How to enable/disable a required action for a specific client in a realm - single-sign-on

I have a custom required action to authenticate user by using a one time password. I configured this required action in the authentication tab in the admin dashboard and it is applied to the entire realm. How to configure this required action in a way that I can enable/disable it for a specific client (note: a client here is not user/account, it is a client which often represents an application)?

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: Pass custom user attributes on Social Identity Provider Login

On registration, Keycloak provides the ability to add custom user attributes via the Keycloak theme's registration page template via "input" elements that look something like:
<input id="user.attributes.[the_custom_attribute]" name="user.attributes.[the_custom_attribute]" />
However, this only seems to work if the user creates an account and submits the form.
If the user were to login via a Social Identity Provider (google, microsoft, github, etc...) how do we go about adding custom user attributes?
If you are using Social Identity Provider to login into application then the customer_attribute won't be available to you.
But if you still want that attribute to be set for that user before he/she logs in, then you can add custom required action to implement this feature. You can create new RequiredCustomAttribute action and enable it from Admin console.
Implement your own required action, similar to that of org.keycloak.authentication.requiredactions.UpdateProfile class provided by keycloak. You can mark your customer_attribute as required in this new required action flow.
When you do all above things, next time when user logs in using Social Identity Provider, he/she will be asked to enter custom_attribute on next page.

Flask-OIDC | How to call a specific function after the user logged in

I built a login system using Flask OIDC and Keycloak. In my system, there is some endpoints decorated with oidc.require_login() that calls the Keycloak login page.
My goal is, after the user successfully logged in, my system checks if the user name exists in a specific database.
How can I set a function to be called every time someone successfully logged in with Keycloak and do this verification at the database?
According to your needs there are several ways to create the user in the backend.
The easiest way would be to just check the JWT token on every request. OIDC is based on JWT and that token is available on any request (which should already be done to find user roles etc). So your application can check that JWT and extract the username from it (see here for details about the JWT format). With the username you can check your internal database and create the user, if it doesnt exist. But at that time you'll not have access to any user credentials any more. It is just SSO and you need to trust Keycloak and the JWT... Also - you'll never be informed, if the user will be deleted in Keycloak, which could be an issue.
There is a callback API in Keycloak in form of the Admin URL per client. But the documentation is not clear. It says: It’s used by the Keycloak server to send backend requests to the application for various tasks, like logout users or push revocation policies. But I cannot find a complete list of "tasks". I saw only logout events. see Keycloak documentation and the documentation only talks about that. If I add an admin url to a test client, I did not get any requests at login time.
a different but more complicated way would be to create your own UserStorage SPI in Keycloak. It would be Java of course, but only some classes. There is an HTTP example or have a look at the LDAP user storage SPI, which supports registration too. If you choose that for your realm and a user tries to login to Keycloak (Login form), the SPI can call your backend to check the user. It also could be "used" to create the user in the backend by checking the Keycloak local storage and only if there is a local Keycloak user, call the backend. That isn't the reason, why you should implement the UserStorage SPI, but it's possible. If you think, this is a good idea, I would prefer to use your backend storage as the one and only storage or build a different one, that then could call your real backend in case of a new user. I would use this one by not using Keycloak local stored users but, by using your own database.
next (maybe last one). You can write an EventListener SPI to read all events and only filter the login events, see here and here. I think, that would be the easiest one. But be aware. In that case, the HTTP call to your backend coming from the event itself is based on a normal HTTP request (without OIDC at that time).
The last two examples create a JAR (which is explained in the links). That JAR with the SPI must be deployed in keycloaks standalone/deployments folder. The EventListener should be active by default, the UserStorage SPI must be activated per realm.
But - be aware - Keycloak/SSO/JWT - should not be used by creating users in multiple backends. Syncing the users between all backends in a SSO environment is maybe the wrong way. Most information is located in the JWT or can be called by a backend from one central user identity management. Do not store a user more then once. If you need the user reference in your backend - link just to the username or userid (string) instead of a complete entity.
There is no direct way of doing this, other sotfware like Openam, Okta allow you to trigger specific flows in a post-login configuration.
In keycloak, you can try to create your custom authn flow(using Default Identity Provider, its the only option that allow a redirect), and then select this flow in your Identity provider in post login flow.
The idea here is that after login, the user will be redirected to a link ( an api call that will verify his presence on the external database, and sent him back to keycloak once the verification is done.
More info here

Keycloak: Disable username/password login for external IDP

How to disable username/password login for external IDP ?
I know that I can use custom theme to hide http form, but I want to do it properly.
As far as I know I have to create at least custom First Broker Login and Browser authentication flow, right?
After first login from IDP I have to create user in Keycloak, but do not leverage password option.
Also Browser flow must be updated to not show username/password form, right?
Can anyone provide proper example ?
Thanks
You can use a custom authentication provider to achieve your goal.
Instruct Keycloak to assign a specific user attribute to all users arriving from the IDP.
Build an authentication provider which checks for that user attribute and denies access.
Add the authentication provider to the Browser login flow.
Optionally adjust templates files to hide login fields and show a user-friendly error if the user fails step 2.
Further details here: https://groups.google.com/g/keycloak-user/c/N9cuqXIBrSA/m/sycLxTZbCAAJ
May not be 100% suitable to this case, but found next one working fine for our case without need to compile and deploy "custom authentication provider". In our app we suppress keycloak login form and offer own custom user / password form, and for IdP integration we are using kc_hint to redirect directly to IdP login page. Once user login via IdP we want to disable user name / password login using password grant. There is a trick allows to achieve this in keycloak v15. You can assign "Update User Locale" to "Required User Actions" of the user, from that moments, direct password grant wont let user to login returning "requires action" validation error, which is not supported in our UI, while IdP login still works and skip this "required action" nor reset it after login. Of course you may need some scheduled curl script allows to set this for users automatically via users REST API : read users attributes or IdP link integration, if found specific Idp related user attribute or IdP integration link, and "requires action" array is empty, set it to "Update Locale".
Of course this all works as long as you hide keycloak login form and use your own. for all using keycloak login form, login using name / password will work and can bypass "Update locale" requirement (not sure why, perhaps because realm does not have locales configured)
Try this costum Authentication flow
By Automatically linking brokered account, the user won't have to set a password. as for the username it will be automatically imported from the identity provider.

Is it possible to use the install4j HTTP credential dialog for custom actions?

I need to write a custom rest client to be able to handle single-sign-on authentication in some purposes. The client has to decide whether to use sso or basic authentication. For the basic authentication a dialog should appear and the user will be asked for the credentials. In install4j there already exists such a dialog and I wonder whether I can reuse this dialog to get the credentials and set these to the custom rest client?
That information is not saved, so you cannot retrieve it later. Conversely, you could set the system properties "serverAuthUser" and "serverAuthPassword", so install4j would use this for authentication and the password dialog would not be shown.