Order of Keycloak authenicators and required actions - keycloak

Should Keycloak display a required action for an authenticator before moving to another authenticator in my flow? Let's say I have authenticator A and authenticator B. They are in the flow after the password form. All are set to required. Here's what happens:
Authenticator A returns false for isConfiguredFor(). Keycloak then calls A.getRequiredActions() followed by A.setRequiredActions(). That makes sense.
Next the A.authenticate() is called. Shouldn't that not be called yet because the required action hasn't executed? I am calling context.success() in A.authenticate() because I there is nothing to authenticate. A is really just a placeholder to cause the required action to occur.
The next thing that happens is authenticator B is called. B.authenticate calls context.challenge() and then B.action is called and if the user enters the right code, the authentication completes.
Now, after authenticator B is complete, the required action from A is finally displayed. How do I get the required action displayed in the right place?
I have run and built the "secret question" example and based my code on that. It seems to work as I expected - the action to set up the question is displayed and authenticate is never called.
Here's my flow as described in this question. I intend to add another auth check into the flow on the same level as SMS. Either SMS or OTP will be presented to the user based on his or her choice from the "Select 2FA Authentication Type" authenticator.

Related

How do we detect if a user has ever visited a particular client

In every realm in Keycloak, there is client which often represent the application the user is about to access which is represented as client_id in the url, such as
${keycloak_root_url}/auth/realms/${realm_name}/protocol/openid-connect/auth?response_type=code&client_id=${client_id}&redirect_uri=${redirect_uri}
How do we detect if a user has ever successfully logged in into a particular client at least once?
Out-of-the-box and depending on the type of use-case and client flow used you could either:
Enable the admin events, in particular the Event Type : LOGIN and then query those events for the clientID and id of the user;
If the client in question is using either Browser Flow or Direct Grant Flow then you can (under the Authentication tab) copy and create your own version of one of the flows accordingly. Then add a sub-flow that forces the user to perform an action only during the first login (e.g., accept the 'Terms and Conditions'). Afterwards, under Authentication Flow Overrides (of the client) override the flow with your customized flow, accordingly. Finally, query the user for the first login action required by the client in question.
DISCLAIMER: I am not claiming that those are either the best solutions for this use case or that they are bulletproof.

Keycloak user chooses OTP or SMS

I want to add a question into the Keycloak auth flow after the user’s name and pw have been authenticated to ask what type of two factor authentication they prefer. The choices are OTP or SMS. If the user has already made the choice before, I will skip the question and continue to either OTP or SMS authenticators. Need some advice on how to implement this.
I have created an authenticator class that shows a template. Is that right? I have seen examples of creating a required action.
How do I skip the question if the user has already made his choice? I tried using returning false from configuredFor() but that just halts the flow with an error since my authenticator is set as required.
I plan on storing the user’s choice in a user attribute or possibly a cookie. Any thought on which is better?
As always, thanks.
You can use a Conditional authenticator to check the condition, there is an example of this in the server developer documentation: https://www.keycloak.org/docs/latest/server_development/#algorithm-overview

Keycloak token doesn't include mapped user session note on first login

I have created a custom IDP and whenever I login I need to set a User Session Note which is mapped in Keycloak and then added to the access token. The problem I am facing is that this User Session Note is not saved the first time a user logs in. It works the second time, and third and so on, but on the first login the user does not simply get the key/value added to the token.
The login succeeds every time, however it is missing the user session note that I wanted to be mapped on the token.
I'm not sure what the problem is. The IDP is set up to have a custom "First Login Flow" which has Create User If Unique (alternative) and Automatically Set Existing User (alternative). Maybe there is something here that I need to change so that it also includes User Session Notes on token for the first login?
I found that you need to implement the importNewUser() method in your extension of AbstractIdentityProviderMapper and set your notes on the authenticationSessionModel there.
Inside of the authenticated method, where preprocessFederatedIdentity() is called, Keycloak checks if federatedUser == null. At this point, you are in the state of preprocessing the federated user; it does not yet exist. Keycloak then calls resetFlow() within this if block where it then clears auth notes from the authenticationSessionModel.
Hopefully someone finds a more delicate solution than I did, but I managed to solve this by a little hack.
I noticed that in the provider I could override the method "preprocessFederatedIdentity" and when listing the User Session Notes there I saw that they do in fact exist on the session. However, when reaching the method "authenticationFinished" (also overridden) they have been cleared from the session (the clearing seems to happen right before method "updateBrokeredUser" is reached). This odd behaviour only happens on the first login.
What I then noticed is that User Attributes stored on the context however are not cleared. They persist, and this was key to my solution. Then what I did was simply to loop through all of the User Session Notes in the method "preprocessFederatedIdentity" and store them as User Attributes (with the key prefixed with "UserSessionNote:"), and in the latter step "authenticationFinished" I add them to User Session Notes again. I also stored all of the keys of the User Session Notes in a User Attribute called "UserSessionNotesKeys" as a comma separated string so that I could simply split that string and loop through the attributes in the "authenticationFinished" method and then add them to User Session Notes.
This basically solved my issue in a generic way, and also made sure it would work if future User Session Notes were added.

Remove linked account/token programmatically

I created a project and enabled account linking (using authorisation code) against my oauth2 provider.
Linking an account works fine and next times Google Assistant calls my fulfilment webhook, accessToken gets passed along other user data.
However, if this token gets invalidated in my system, Google does not know about it. When this situation arises (i.e. my webhook receives a token which is now invalid) I would like to notify Google (so that it can get rid of this invalid link) and/or re-send a prompt to link your account.
I tried calling the sign-in helper (as below) but that did not work.
app.askForSignIn();
Any ideas on how to solve this?

IdentityServer3 - Contacting IdP after user is authenticated

We have SPA, IdSvr3, and a third party IdP(AAD B2C).
The user authenticates successfully. When the user clicks an edit profile link in the SPA, they are directed to IdSvr using the authorization_endpoint. I pass in an acr_value called "profile."
I believe this is the same problem as this gentleman- https://github.com/IdentityServer/IdentityServer3/issues/2816#issuecomment-217161898
I've tried a few things:
Implemented ICustomRequestValidator.ValidateAuthorizeRequestAsync.- In this method, I retrieve the acr_values. There doesn't appear to be a good way to direct the user from here. There is the RedirectUrl on the ValidatedAuthorizeRequest that does redirect the user, but all the information on that object is from the client request to IdSvr and is not relevant to the IdP.
Perhaps there is a setting on the ValidatedRequest that could be tweaked to force IdSvr to direct over to the identity provider(in this case the IdP is - Microsoft.Owin.Security.OpenIdConnect.OpenIdConnectAuthentication)
Implemented a UserService. If the user is logged in, the events trigger IsActiveAsync and GetProfileDataAsync. In IsActiveAsync I can get the acr value from the HTTP context, and set IsActive to false, forcing IdSvr to go back to the IdP. I can't access the context from OpenIdConnectAuthenticationNotifications.RedirectToIdentityProvider, so I haven't found a way to access the acr value there. Is there a way to pass something into here to check if this should be an edit profile?
Similar to the UserService I've implemented IsAuthenticationSessionValidAsync to invalidate the session and force the idsvr to direct to the Idp. This has the same issue of not being able to access the acr value.
PartialLogin doesn't appear to be the right strategy for this either because it appears to only be triggered from a user who isn't authenticated yet. Perhaps if we force the user to log-out, this could be used to direct them to the IdP? https://identityserver.github.io/Documentation/docsv2/advanced/userService.html
Logging the user out feels like the wrong approach to begin with, but it seems like it could be made to work.
Is there a standard way of intercepting a request and directing it over to the IdP based on something in the request?