Update Keycloak user data based on data present in Identity Provider token - keycloak

I am running Keycloak as an Identity Broker, with one Identity Provider configured.
When a user with a valid token from my IdP accesses my application for the first time, that user is created in Keycloak with information from the token. This includes email, username, firstName and lastName. Keycloak then issues its token with that user information.
When the same user logs in subsequently, the Keycloak token is crafted from the user information in the Keycloak database.
My question is this: if a user changes his lastName at the IdP, how can I configure Keycloak to automatically update its records to match the information on the IdP token?

You don't need to implement your own IdentityProvider to achieve that. Instead just add a mapper of type Attribute Importer to the identity provider. For the case of taking the last name, you can get the the attribute value out of the profile client scope that an OpenID provider should provide. Just set Claim to given_name and User Attribute Name to firstName as shown in this screenshot. Each new login with the brokered account will then cause Keycloak to update the account. (tested on Keycloak 7.0.1)

Configure your realm's 'Sync mode' to force and the Attribute Import mappers of your IdP's 'Sync Mode Override' to force/inherit. During each authentication if there is a change at IdP end, the data will be updated at KeyCloak end
The sync mode determines when user data will be synced using the mappers. 'force' to always update the user during every login with this identity provider.

The solution we came up with was to implement our own IdentityProvider that extends Keycloak's OIDCIdentityProvider to override the updateBrokeredUser method. In this overridden method, we set the userModel's lastName to that from the BrokeredIdentityContext (which came from the token from the IdP). Like this:
#Override
public void updateBrokeredUser(KeycloakSession session, RealmModel realm,
UserModel user, BrokeredIdentityContext context) {
user.setFirstName(context.getFirstName());
user.setLastName(context.getLastName());
// etc for other user attributes
}
The default implementation of this updateBrokeredUser method is a no-op, so it's pretty clear to me that Keycloak intended for this to be overridden to do things like this.
Our custom identity provider class gets wired in via the usual way using the provider / provider factory mechanism.

Related

Enable sid claim in the Keyclaok id token

I'm currently working on configuring Keycloak as a federated identity provider to test the OIDC back-channel logout flow.
In both id token and the logout token, they don't include the sid claim by default since it is an optional claim. But in the client's configuration, there's a config to enable the session identifier in the back-channel logout token. Config to enable 'sid' claim. If this is enabled, the logout token will have an sid claim, but the id token won't.
OIDC Specification section 2.1,
backchannel_logout_session_supported:
OPTIONAL. Boolean value specifying whether the OP can pass a sid (session ID) Claim in the Logout Token to identify the RP session with the OP. If supported, the sid Claim is also included in ID Tokens issued by the OP. If omitted, the default value is false.
According to this, if the sid claim is included in the logout token, id token should also have the sid claim
Is there a way to include sid claim in the id token as well ?.
If not, what's the purpose of having an sid claim only in the logout token and not in the id token ?
I'm not familiar with the back-channel flows, but in general you want to use KeyCloak's concept of "Mappers" to add claims into tokens. Both Identity Providers and Clients can have Mappers, depending on where you need to add data.
Clients and IdP configs will have different 'Mapper Types' available. The 'Mapper Type' field is the most important field when configuring the Mapper - it determines where the data is coming from (some session value, some user attribute, etc). We often have to write small custom implementations for new mapper types to pull some data out of the Java layer so we can put it into a token.

Keycloak: How can user be filtered for a specific OIDC client by role?

We have one realm with many users and multiple OIDC clients configured. We would like to connect another application (OIDC Client) to the realm. Unfortunately, the client cannot check for any attributes or roles to be present.
How can I configure Keycloak to authenticate with a specific OIDC-client but return failing authentication if users have not a specific role?
Generally this type of option will not work, since authorization redirects occur before you know who the user is, and therefore before you know which roles are involved.
WHAT I WOULD DO
Make an authorization redirect perform only the following job:
Signing in the user and returning the user id (sub claim), along with perhaps a couple of scopes
Then manage roles within your app - the second app should call a Web API that does this:
Get claims from the access token, and also from other sources, then use them for identification and authorization
If a user authenticates but is not entitled to use a particular app, detect this via an API call, then present an Access Denied page in the app after login.
To reach this you should implement the AuthenticatorFactory and Authenticator interfaces of Keycloak. Look here for more infos.
In the authenticate() method you will write something similar to this:
If(client == yourClient){
// Check for roles
}
Otherwise, expected behaviour in case of failure.

Cognito User Pool custom attributes do not show up in the ID token if user pool is configured with a SAML identity provider

According to the documentation, the ID token (a JWT token) created by Cognito upon user authentication is also supposed to contain the custom attributes defined for the user's User Pool.
It seems that when the User Pool is configured with a SAML identity provider, the ID token does not contain those custom attributes of the user pool, but only the Cognito attributes which are mapped from the SAML token.
Note: the custom attribute is already configured when the user pool is created, therefore it does not make sense to set it up again in the SAML token, for example by configuring the remote AD FS attributes.
Is there any way to preserve a User Pool custom attribute in the ID token, in this case of using a federated identity provider?
Or be able to hook into the authentication process to insert a custom attribute into the token?
Thanks for the help!

How can I add claims to the context for GetProfileDataAsync & IsActiveAsync for a custom user service?

I am implementing a user service that is storing user info in Azure Table storage. I would like to use a value for tenant ID as part of my partition key, but, the claims available in GetProfileDataAsync and IsActiveAsync are just 5 built in claims (sub, name, amr, idp, auth_time).
I get tenant ID from my identity provider and it's included as a claim in both my access token & identity token. How can I make it available to those methods?
When the AuthenticateLocal is invoke, you return an AuthenticateResult to indicate the authentication outcome. If it's successful you use the ctor overload that accepts the subject and name values. There's also an optional claims collection. If you pass values for claims then you are adding your own custom claims to the authentication cookie at IdentityServer. Those claims are then part of the Subject for the GetProfile API (assuming the requests into those APIs are being done via the browser such as from the authorization request). You can then inspect those claims and use them in any way you want.
If the request is not via the browser, then the only claim you have on the Subject is the user's unique id (which is the sub claims).

Persist claims added after user is authenticated by Identity Server

Is there a way I can persist my application specific claims added to the identity after it gets authenticated by Identity Server. I don't want to load the claims from database for the user and add everytime I want to access my API.
The best practice for these cases is Claims transformation.
You can add more claims to token after user authenticated with IdentityServer and redirected to you client.