I've got Keycloak setup and running with NodeJS.
I see you can create groups and assign attributes to those groups. Is it possible to access these attributes from the NodeJS application?
I can't even find the groups let alone their attributes.
Yes you can. But there is almost no official documentation on how to achieve this. You can return most keycloak attributes, groups and roles through the client mappers. By default none are configured.
To configure extra mappers: In the administration console, select the client and then the Mappers tab. That should bring you to a list of mappers.
You can add mappers here of different types. Once you add a mapper you can decide which calls to Keycloak from the client return the attribute(s), and what the name of the returned attribute is. The following screenshot includes a mapper that returns a dictionary of groups, with subgroups, separated by forward slashes. Your Node code will need to parse the returned JSON object.
All the information is returned in the keycloak token, which is a Javascript Web Token. In Node you can examine it by printing the token to the log. The keycloak-connect middleware stores tokens etc in an object on the request called kauth. The path to retrieve a list of groups specified by the configuration in the above screenshot is shown below. If you change the token claim name in the configuration, you will need to change the path in your NodeJS code accordingly. You will need to logout from your application and login again for changes to the mapper to work.
router.get('/', async function(req, res){
console.log(req.kauth.grant.access_token.content.groups) ..
}
Related
I'd like to add dedicated scopes to a client so that it can access information from other clients.
Turning full access on works but grants too many permissions.
The scopes are already created with their respective clients. It is “only” a matter of assigning scope from client a to client b. I have a list of names and client ids available locally. How can I efficiently assign them via kcadm.sh?
I already tried with the network tab open but I couldn't wrap my head around what the logic behind assigning scopes is.
E.g., there is a
POST /admin/realms/master/clients/968c7b36-95dd-4121-b92b-37b324298890/scope-mappings/realm with an empty array as payload
POST /admin/realms/master/clients/968c7b36-95dd-4121-b92b-37b324298890/scope-mappings/clients/74cb7b05-34d5-4657-8fe6-bb19a7c8a07f from the APIDOC it just says client. But I don't know what that client should be.
How to reproduce on Keycloak (X) 20.0.3
Login to the Keycloak Admin Console
Click on the client tab
Click createClient
Create client id and click next.
Click save.
On the new client. Click on the upper tab 'Client scopes'.
Click on the first blue item.
Click on the upper tab 'scope' and turn off full scope allowed.
Click assign role and add one of the items.
This is what I want to achieve with the help of the kcadm.sh as clients are added dynamically. You can't even export the client from Actions->Export and Import it again from the UI. Every scope is lost when imported again.
To assign role from client A to client B at the bear minimal you need the following Rest Full API call:
POST /admin/realms/ <REALM NAME> /clients/< ID OF THE CLIENT >/scope-mappings/clients/< ID OF THE CLIENT where the role comes from>
so in your case /admin/realms/ <REALM NAME> /clients/< ID OF CLIENT B >/scope-mappings/clients/ < ID OF CLIENT A>
the payload should be [{"id":"<ID OF ROLE>","name":"<ROLE NAME>"}]
You will need the call to get the id of the client for that you can call:
GET /{realm}/clients
with clientId as query parameter.
And then you will need the call to get the ID of the role, for that you can use:
GET /{realm}/clients/{id}/roles/{role-name}
id is the id of the client.
I have keycloak on docker (v20.0.2) and as you know some versions change some or good part of the UI, so is hard to follow tutorials around the web...
I am trying to follow this particular tuto
https://developers.redhat.com/blog/2020/11/24/authentication-and-authorization-using-the-keycloak-rest-api#keycloak_sso_demo
that seems the more updated. My keycloak is actually behind traeffic and thomseddon/traeffic-fordward-auth with a docker-compose file (but the connection through traeffic is good and I have acces to admin UI)
So on step 10 of the tutorial things change for me, I have to look for that particular view inside:
Click on lateral menu Client Scope
Click on button Create client scope
Give a name to the scope, and click on Tab Mapper
All mappers are predefined... so there is no "New mapper" don't understand this bit
then just follow the tuto
With that series of steps I get an error when retriving the token...
https://keycloak:8443/realms/education/protocol/openid-connect/token
enter image description here
(this are fake local data from the realm I created for testing)
that responds with a or something similar I have also tried to change the grant_type to password, and the same happens can not query the token....
{
"error": "invalid_client",
"error_description": "Invalid client or Invalid client credentials"
}
But if I do not link a user with an scope/role as in the tuto suggest then I get the token, but of course I want to use the role or scope to limit who can see which endpoint and who can not
Any step that I'm missing from this update, do you have the same error?
Thank you in advance
I have tried to run it with different combinations of options to see if there is a toggle that actually allows me to fetch the token
Also with different types of grant_type
I will build an API in Python (I don't know Java and prefer Json instead of XML) that connect to this keycloak to allow users or not based on their scope/role/permission or something
I need to be able to block user so if user Student try to access an url from another Student he get blocked that url. So is based on the role or scope or I don't know which is prefered or easer to accomplish, the mission is to block users or not based on a factor that could be used for this in keycloak.
My requirement is enable 2FA using email in Keycloak.
When enabled, if user tries to login through email & password ,after user is successfully authenticated ,time based token will be sent to email .
User will do this action from custom UI i.e in our product we have UI to enable/disable 2FA for user.
We are using Keycloak & we want to achieve this using Keycloak API.
I am using keycloak-admin-client to interact with Keycloak API but I did not find sufficient resources to achieve this using keycloak-admin-client.
I am looking a way using keycloak-admin-client how to enable 2FA for user.
Any help will be highly appreciated.
Thank You
You should add custom REST endpoints to Keycloak to be able to enable 2FA from your custom UI. We have done this before. It's not that much complicated, but it requires you to have a look at Keycloak source to see what it's doing when OTP gets activated. Some important classes to check/use are TotpBean, OTPCredentialModel and OTPPolicy.
In order to enable the 2FA, we needed to show the QR code image in our custom UI. So we added an endpoint to Keycloak that instantiates an instance of TotpBean. It's the one that gives you access to the QR code image and the secret value that are required to generate the equivalent string representation of the image so that it could be scanned/entered in the 2FA app (e.g. Google Authenticator). Here is an example of how such an endpoint would look like:
#GET
#Produces({MediaType.APPLICATION_JSON})
#Path("/o2p-enable-config/{email}")
#NoCache
public Response fetchOtpEnableConfig(#Email #PathParam("email") String email) {
UserModel user = session.users().getUserByEmail(email, realm);
TotpBean totp = new TotpBean(session, realm, user, session.getContext().getUri().getRequestUriBuilder());
return Response
.ok(new YouOTPResponseClass("data:image/png;base64, " + totp.getTotpSecretQrCode(), totp.getTotpSecret(), totp.getTotpSecretEncoded()))
.build();
}
Then on your own backend, you call this endpoint and send the user's email to it and receive the image and the secret value. You can just display the image as is in your UI and keep the secret value on your backend (e.g. in user's session). When user scans the image using the app and enters the totp value provided by the app in your custom UI, you send the totp value and the secret to another endpoint that you should add to the Keycloak. This second endpoint is the one that does that verification of the value and enables 2FA.
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Path("/enable-2fa/{email}")
#NoCache
public Response enable2Fa(#Email #PathParam("email") String email, OtpDetails optDetails) {
OTPPolicy policy = realm.getOTPPolicy();
String totp = optDetails.getTotp();
UserModel user = session.users().getUserByEmail(email, realm);
OTPCredentialModel credential = OTPCredentialModel.createFromPolicy(realm, optDetails.getSecret(), optDetails.getUserLabel());
if (CredentialValidation.validOTP(totp, credential, policy.getLookAheadWindow())) {
CredentialHelper.createOTPCredential(session, realm, user, totp, credential);
return Response.noContent().status(204).build();
} else {
return Response.status(BAD_REQUEST).build();
}
}
Keycloak supports multiple 2FA for each user. That's why it also has a property named label that allows user to name them so that it would be displayed in the 2FA login scenario with given name. You can also allow user to enter the label value in your custom UI and pass it to the second endpoint (or just pass an empty value to Keycloak if you're not going to allow your users to setup multiple 2FA).
I know it seems complicated, but it's actually not that much. The Keycloak domain model is well designed and when you get familiar with it, you can easily find what you need to do and wrap it in custom APIs. But always ensure that exposing a functionality would not compromise the overall security model of the system.
Take a look at keycloak two factor email authenticator provider
https://github.com/mesutpiskin/keycloak-2fa-email-authenticator
I agree that is necessary to write a custom provider for this use case.
Take a look at https://www.n-k.de/2020/12/keycloak-2fa-sms-authentication.html and https://www.youtube.com/watch?v=GQi19817fFk for a look at how to implement that.
That is an example via SMS, but via e-mail would be very similar, changing just the way of sending the code to the user.
I have a multi-tenant app in which user can select "current company" after they log in.
There is a DB per company but the model is the same, the workflow is the same, and the controller actions are same....The user can switch companies while being logged in and all actions need to be 'directed' to proper DB.
I know it is possible to customize context creation in EFContextProvider<T> by overriding CreateContext() but how do I pass the extra info (parameter, e.g. CompanyId) that would allow me to create context with correct connection string?
Is this possible?
I find the easiest way is to include the tenant id in a custom HTTP header.
Because the tenant id changes during the session, you probably want to create a custom Breeze ajax adapter (wrap the one you're using now) that sets this header dynamically during its implementation of the ajax method.
On the server you fish the header out of the request.
MAKE SURE YOU ARE VALIDATING USER AND HEADER ON THE SERVER
Assume I want to create a very simple todolist RESTful API, where each user owns a list of todos. The user is already authenticated over http BASIC or DIGEST.
At this point I am not sure what the URL scheme should look like.
Would it be:
http://servername/todos/
where my server filters the appropriate todos according to the authentification given to me by the http header.
Or should I include the username in the URI instead:
http://servername/users/username/todos/
On some websites I have even seen that they hand over the user name as a parameter like this:
http://servername/todos?username=babsi
As far as I can tell all three choices are stateless as I always receive the username, but just over different sources. From what I can tell to make sure that the URI is accessed by the proper user I always need to check the http header anyways. So which of the ways would you consider the best URI design in REST or should I do in a different way entirely?
You can use the following:
http://servername/todos/ GET list all todos
http://servername/users/ GET list all users
http://servername/users/{user_id}/ GET list an user
http://servername/users/{user_id}/todos/ GET list all todos for an user
I think the point here is how you want to design the relationships between your resources, if a todo just can exist in the context of an user use a hierarchy like approach as above.
As general rule i usually follow this:
Use path variables to encode hierarchy: /parent/child
Put punctuation characters in path variables to avoid implying hierarchy where
none exists: /parent/child1;child2
Use query variables to imply inputs into an algorithm, for
example: /search?q=jellyfish&start=20
Having the username in the URL depends on what you want to do (if anything at all) when you receive a request where the username in the URL does not match the authentication. If you want to re-authorize the user in this situation then yes - it's OK to have the username in the URL, otherwise it's OK to have it just in your header or other authentication scheme if there is no such need.
One fairly common example of a valid requirement would be if you have to have a main user (or group of such users) that can impersonate other users.
When the user in question is always the user who is holding the authentication token, then use something like "me" in your path.
http://example.com/users/me/<path-to-inner-resource>
Otherwise, user should be treated just like any other resource in your system, in which case the resource identifier for that user becomes a part of the path.
http://example.com/users/<id>/<path-to-inner-resource>
Take a look at Twitter APIs as an example.
https://developer.twitter.com/en/docs/twitter-api/users/follows/quick-start/follows-lookup