By: Nick Chandler user 04 Jun 2018 at 4:05 p.m. CDT

3 Responses
Nick Chandler gravatar
We have some custom attributes that are multivalued. The format of the text in each of these is JSON, although it is text in Gluu. For example, we might have an entry: "{'id': 1, 'name': 'Test 1'}". When we query the userinfo endpoint, we get a list of strings currently. I would like to, instead, return a JSON representation of the object. So, for example, instead of: ``` "custom_attribute": [ "{'id': 1, 'name': 'Test 1'}", "{'id': 2, 'name': 'Test 2'}" ] ``` ... I would like: ``` "custom_attribute": [ {'id': 1, 'name': 'Test 1'}, {'id': 2, 'name': 'Test 2'} ] ``` Unfortunately, even using a custom script to set my attributes to a list of dictionaries, dictionaries are still presented as strings. Is there any way around this? I would prefer the Client not have to parse a string as JSON if it could just have a JSON object to begin with.

By Aliaksandr Samuseu staff 04 Jun 2018 at 4:44 p.m. CDT

Aliaksandr Samuseu gravatar
Hi, Nick. I believe that at least with dynamic scope scripts it's possible to have a proper enclosed JSON object in the response's JSON, if you use the right approach. Regarding your case, do you see this behaviour only when claims derived from your custom attributes are involved, or with any claims (even those which are derived from built-in multi-valued attributes)?

By Nick Chandler user 05 Jun 2018 at 10:17 a.m. CDT

Nick Chandler gravatar
Hi, Aliaksandr. Thank you for the quick reply! I tested using the built-in user permissions attribute this morning, and I see similar behavior with them, as well. For reference, the code I currently have looks similar to the following: ``` def update(self, dynamicScopeContext, configurationAttributes): """Updates OIDC scopes returned when queried.""" print "Retrieving dynamic scopes" dynamicScopes = dynamicScopeContext.getDynamicScopes() user = dynamicScopeContext.getUser() jsonToken = dynamicScopeContext.getJsonWebResponse() claims = jsonToken.getClaims() # Iterate through list of dynamic scopes in order to add custom scopes if needed for dynamicScope in dynamicScopes: if (StringHelper.equalsIgnoreCase(dynamicScope, "custom_attribute")): my_attributes = user.getAttributeValues("my_attributes") attribute_return = [] for attribute in my_attributes: try: attribute_dict = eval(attribute) attribute_return.append(attribute_dict) except Exception as exc: print exc attribute_return.append(attribute) claims.setClaim("custom_attribute", attribute_return) ``` I don't love having an "eval" there, but I understand that the attributes must be stored as text on the backend, so I had hoped that this would allow conversion to a dict within the Jython script. However, each "attribute_dict" still seems to be wrapped as a string in the userinfo response.

By Aliaksandr Samuseu staff 13 Jun 2018 at 6:39 p.m. CDT

Aliaksandr Samuseu gravatar
Hi, Nick. Though I can confirm it indeed behaves like this, I can't consider it's a bug, more like a design limitation. When you store some JSON data value in an attribute using web UI, it makes it to LDAP storage unchanged. It seems the problem here is that we don't have a specific attribute type for storing JSON values, the closest type atm is "Text", hence the result. oxAuth honours types set in each attribute's metadata and encodes them correspondingly. I've created [enhancement proposal](https://github.com/GluuFederation/oxAuth/issues/822) for a new type to handle JSON more gracefully, but no ETA can be given atm. As a temporary workaround, you still can add claims containing enclosed JSON object to userinfo's response via dynamic scope script. Here is example which works for me (assuming "json_attr" LDAP attribute contains a single value which is a JSON object): ``` from org.codehaus.jettison.json import JSONObject ... jsonWebResponse = dynamicScopeContext.getJsonWebResponse() claims = jsonWebResponse.getClaims() ... json_from_attr = userService.getCustomAttribute(user, "json_attr") jobj = JSONObject(json_from_attr.getValue()) claims.setClaim("test_dyn_claim_inline_obj", jobj) ``` I'm closing the ticket now, you can track its progress on github.