Keycloak map multiple user attributes - keycloak

I've followed the guide at [1] to map a single user attribute. However, I need to map all attributes to an array, so that every attribute for a particular User shows up in an attribute array of the access token (Or better, restrict attributes to a certain group of attributes, but I guess user attributes are only a flat key/value map).
I tried out setting a wildcard * in the User Attribute field of the client mapper. But no matter what I do, I can ony set one attribute at a time given an actual attribute key of a user's attribute map.
[1] Keycloak retrieve custom attributes to KeycloakPrincipal

I was in trouble with the same problem.
I have tried the following:
Added a key "department" with a single value for example "finance".
Adding a second key "department" with another value "development"
overwrites the initial entry.
I also have tried to put something
like a list into the value column, such as "development, finance" or
"development; finance" but this is treated as a single value too.
If you use "development##finance" in admin console, the user will have "department" attribute with 2 values "development" and "finance".
The "##" seem to be the delimiter to use.
So, if you mark "multivalued" switch in your protocolMapper for "department" attribute, the accessToken will contain list with 2 values "development" and "finance".
"department": [
"development",
"finance"
]
This worked for me.
KeyCloak version 11.0.2

I'm not 100% sure what you're looking for here, but I know this is the first result that came up when I googled what I was looking for, so I'll just post that answer here.
Say you want a multi-valued user attribute set in a JWT in keycloak, but your attributes aren't the same name. E.g. you have something like the following key value set for a user:
Room : Bedrooom
Floor: Tile
Paint: White
Next, you want these values within the JWT
{
"exp": xxxxxxxxxx,
"iat": xxxxxxxxxx,
"jti": "xxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx",
"iss": "xxxxxxxxx",
...
"Room_Info":{
Room : Bedrooom
Floor: Tile
Paint: White
}
...
}
When using you're mapper in keycloak, preappend your Token Claim Name (Room_Info) with a dot.
That should do it.

You can write your own Keycloak extension. One solution would be to write custom Authenticator where you can:
filter user attributes -> join attributes values -> write resulted JSON array as user session note.
Then add Client Mapper which maps this session note into a single claim.

Related

IBM Maximo REST service POST not setting attributes on MBO

I have tried to create a record of my customized object through REST service in IBM Maximo.
The problem is that I created the record but I can't assign values to the attributes.
Next I will show what I did and what happened:
I have an Object Structure called oxidato that represents my customized object.
I did a POST using POSTMAN to this URL:
http://hostname:port/maximo/oslc/os/oxidato?lean=1
In the body section this is the JSON I was trying to send:
{
"attribute1":"205",
"attribute2":"206"
}
The record was created but none of the attributes was filled.
In my opinion, the REST service received the POST but canĀ“t read the body.
What am I missing? I add an image of the POSTMAN as example:
EDIT1: I update the POST in order to use the newest API RES (Thanks Dex!)
EDIT2: I add an image of the header
I have found that Maximo will often ignore incoming attributes that aren't in the Maximo namespace (http://www.ibm.com/maximo). You could go through the trouble of setting up your VALOR1 and VALOR2 attributes to be in that namespace, but it's easier to just tell OSLC to ignore namespaces. You do that by setting the "lean" parameter to "1".
In your case, go to the "Params" tab and add an entry with a name of "lean". Give it a value of "1" and then send your POST again. You should see "?lean=1" appear at the end of the POST URL along the top there, but your body content should remain unchanged.
EDIT:
On the other hand, it looks like (based on your URL) that you aren't actually using the newer JSON/OSLC REST API; It looks like you are using the older REST services. This IBM page gives you a lot of information on the newer JSON REST API, including the correct URLs for it: https://developer.ibm.com/static/site-id/155/maximodev/restguide/Maximo_Nextgen_REST_API.html.
You should change your URL to /maximo/oslc/os/oxidato to use the newer API that naturally supports JSON and the lean parameter described above. This does required Maximo 7.6 to use though.
EDIT 2:
The attributes are often oddly case sensitive, requiring lowercase. Your example in your question of "attribute1" and "attribute2" are properly lowercase, but your screenshot shows uppercase attribute names. Try changing them to "valor1" and "valor2". Also, these are persistent attributes, right?
The response code received back (e.g. 200 - OK) and the response body will detail the record that was created.
I think you are correct in that the body of the post request is being ignored. Provided there are no required fields on the custom MBO your POST is probably creating an empty record with the next value in the sequence for the key field but you should see that in the response.
The following POST should create a record with values provided for attribute1 and attribute2 and provide a response with the record's identifier so that you can look it up in Maximo and show the values that were stored for attribute1 and attribute2:
http://hostname:port/maximo/rest/os/oxidato/?_format=json&_compact=1&attribute1=205&attribute2=206
Response: 200 OK
Reponse Body:
{ "CreateOXIDATOResponse": {
"rsStart": 0,
"rsCount": 1,
"rsTotal": 1,
"OXIDATOSet": {
"OXIDATO": {
"rowstamp": "[0 0 0 0 0 -43 127 13]",
"ATTRIBUTE1": "205",
"ATTRIBUTE2": "206",
"OXIDATOID": 13
}
} } }
You may also want to turn on debug logging for the REST interface in System Configuration -> Platform Configuration -> Logging for additional detail on what's happening in the log file.

User address sub fields not showing in userinfo response

I have added a mapper to my client with a mapper type of 'User Address' and enabled the 'Add to userinfo' option
I have then set an address attribute on my user as follows:
When making a request to the userinfo endpoint I just get back an empty address object:
Have I missed out something here? We are using keycloak 3.2.1 also.
Thanks
Your user's attributes must be passed as single key/value pairs , not as full JSON object.
And the values in the mapper must be filled in as well :

Ordering Server adding sshkeys

I want to order server with sshkeys using the api, but when I use the sshkey property in the structure it returns the result without the keys, I know my code is working fine becausw I orderwd before. I would like to check if my ids are correct, is there any form to check them by using my label names???
this is the structure for ssh keys:
"sshKeys": [
{
"sshKeyIds": [94206]
}
]
You can call http://sldn.softlayer.com/reference/services/SoftLayer_Account/getSshKeys method to get the IDs of your sshs keys and you can use object filters to get the ssks by label this is am example using Rest:
GET https://<USERNAME>:<APIKEY>#api.softlayer.com/rest/v3/SoftLayer_Account/getSshKeys?objectFilter={"sshKeys":{"label":{"operation":"tonny"}}}
here more information about object filters http://sldn.softlayer.com/article/object-filters

REST Resource route naming for get and ResourceByID and ResourceByName

I am trying to write 2 Rest GET methods.
Get user by Id
Get user by userName.
I need to know if there is any resource naming convention for this. Both my id and username are strings.
I came up with:
/api/{v}/users/{userid}
/api/{v}/users/username/{username}
However, 2) doesn't seem correct and if I change 2) to /api/{v}/users/{username}, I am mapping to 1) as both id and username are strings. Or is it considered acceptable to use /api/{v}/userbyName/{username}?
How should I name my resource route in case 2) ?
First of all: https://vimeo.com/17785736 (15 minutes which will solve all your questions)
And what is unique? Is the username unique or only the id or both are unique?
There is a simple rule for all that:
/collection/item
However, 2) doesn't seem correct and if I change 2) to /api/{v}/users/{username}, I am mapping to 1) as both id and username are strings.
If your item can be identified with an id and also with an unique username - it doesn't matter if it's the username or the id - simply look for both (of course your backend needs to handle that) and retrieve it.
According to your needs this would be correct:
/api/{v}/users/{userid}
/api/{v}/users/{username}
but I would choose only to use: /api/{v}/users/{userid} and filter by username only with a query parameter (description for that down there below)
Also will I break any rules if I come up with
/api/{v}/userbyName/{username}
Yes - /api/{v}/userbyName/{username} will break the rule about /collection/item because userByName is clearly not a collection it would be a function - but with a real restful thinking api there is no function in the path.
Another way to get the user by name would be using a filter/query paramter - so the ID will be available for the PathParameter and the username only as filter. which than would look like this:
/api/{v}/users/?username={username}
This also don't break any rules - because the query parameter simply filters the whole collection and retrieves only the one where username = username.
How should I name my resource route in case 2) ?
Your 2) will break a rule - so I can't/won't suggest you a way to do it like this.
Have a look at this: https://vimeo.com/17785736 this simple presentation will help you a lot about understanding rest.
Why would you go this way?
Ever had a look at a javascript framework like - let's say ember. (Ember Rest-Adapter). If you follow the idea described up there and maybe also have a look at the json format used by ember and their rest adapter - you can make your frontend developer speed up their process and save a lot of money + time.
By REST you send back links, which can contain URI templates. For example: /api/{v}/users/{userid} in your case, where v and userid are template variables. Since the URI structure does not matter from a client perspective you can use whatever structure you want. Ofc. it is more convenient to use nice and short URIs, because it is easier to write the routing with them.
According to the URI standard the path contains the hierarchical while the query contains the non-hierarchical part of the URI, but this is just a loose constraint, in practice ppl use both one.
/api/{v}/users/name/{username}
/api/{v}/users/name:{username}
/api/{v}/users?name="{username}"
Ofc. you can use a custom convention, for example I use the following:
I don't use plural resource name by collections
I end collection path with slash
I use slash by reducing a collection to sub-collections or individual items
I don't use slash to give the value of a variable in the path, I use colon instead
I use as few variables and as short URI as I can
I use query by reducing a collection to sub-collections especially by defining complex filters with logical operators
So in you case my solution would be
/api/{v}/user/
/api/{v}/user/name:{username}
/api/{v}/user/{userid}
and
/api/{v}/user/?firstName="John"
/api/{v}/user/?firstName="John|Susan"&birthYear="1980-2005"
or
/api/{v}/user/firstName:John/
/api/{v}/user/firstName:John|Susan/birthYear:1980-2005/
etc...
But that's just my own set of constraints.
Each resource should have a unique URI.
GET /users/7
{
"id": 7,
"username": "jsmith",
"country": "USA"
}
Finding the user(s) that satisfy a certain predicate should be done with query parameters.
GET /users?username=jsmith
[
"/users/7"
]

Play 2.0 password field constructor: no value attrib?

Not sure if this is a security feature, an oversight, or me missing the ocean for the waves, but wondering why there is no value attribute for the password field constructor
This is not an issue for user signup and other form creation events, but becomes a headache when, for example, a user renewal form does not have the password field filled in (and thus fails validation, which is ironic given that they just logged in in order to be able to renew in the first place ;-))
My workaround has been to set the value attrib manually by supplying it as an extra argument:
#inputPassword(
_form("password"), '_label-> "Password*", 'class-> "required",
'value-> _form("password").value map{Some(_)} getOrElse Some("")
)
would prefer the value attribute included by default, however, as with other input elements. Yes, I can override it, but wondering what the dealy-O is regardless
To me, you shouldn't be able to retrieve the user password in any way, since the password should be encrypted before storing it somewhere.