Keycloak adding new authenticator - java

I'd like to add a new auth method in keycloak. To be precise - I'd like the keycloak to ask external API for some specific value. I have read about flows in keycloak but they seem to be poorly documented and I have a feeling that it is not very intuitive.
During login I would like the keycloak to send request to external API and if and only if when specific value is returned allow the user to login. For example I could override some login method and add a few lines of code doing what I want.
Which method in which class is responsible for login?

There are multiple things you need to do to achieve that. I will go over them:
Implement Authenticator and AuthenticatorFactory interfaces.
Copy an existing Authentication Flow
Bind flow
I assume you know how to write and deploy a keycloak extension.
1. Implement Authenticator and AuthenticatorFactory interfaces.
The specific interfaces are those:
org.keycloak.authentication.AuthenticatorFactory
org.keycloak.authentication.Authenticator
A sample implementation:
org.keycloak.authentication.authenticators.browser.UsernamePasswordFormFactory
org.keycloak.authentication.authenticators.browser.UsernamePasswordForm
If you want to externalize your config (So you can add username/password etc. for external api), override getConfigProperties() method in AuthenticatorFactory
2. Copy an existing Authentication Flow.
Login keycloak with admin credentials.
Create a new realm (or use if you have one)
Go to Authentication tab on left.
Copy browser login flow
Add your flows/executions (Your implementation of Authenticator/Factory will be listed under executions)
You can move them up or down. Make them required or alternative etc.
If you override config list it will be shown next to your execution
3. Bind flow.
Bind your flow in the second tab of Authentication page.

Related

Keycloak-6.0.1 Custom Authenticator SPI

I'm trying to implement a custom keycloack Authenticator SPI for authentication purposes against an external Datasource/Rest Service. The plan is to migrate them into keycloak.
Updated the browser flow(copy and created a new flow and bind it).
First time when the user logs in, will display custom theme login screen.
On submit Using Custom SPI authenticate against external service.
On success create users on the keycloak datasource.
Create custom mappers to add extra user attributes on tokens.
I'm following section 8.3 of the official guide https://www.keycloak.org/docs/latest/server_development/index.html#_auth_spi_walkthrough, which is very similar to what I need.
Also, followed examples(https://github.com/keycloak/keycloak/tree/master/examples/providers/authenticator) I think the instructions doesn't map it to the new version.
For example:
In your copy, click the "Actions" menu item and "Add Execution". Pick Secret Question.
In Keycloak-6.0.1, there isn't any such execution as "Pick Secret Question". I really don't need this, but I was atleast trying to set this flow to get hold on how the flow works.
Next you have to register the required action that you created. Click on the Required Actions tab in the Authenticaiton menu. Click on the Register button and choose your new Required Action.
There isn't such Register button on the required action.
Things I have done.
Created new realm
Registered UI client
Created new user in new realm in keycloak tables.
UI on login redirects to Keycloak UI and successfully authenticated and able to retrieve successfully tokens using javascript adapters
componentDidMount = () => {
const keycloak = Keycloak('/keycloak.json');
keycloak.init({onLoad: 'login-required'}).then(authenticated => {
this.setState({ keycloak: keycloak, authenticated: authenticated })
})
}
....
....
if(this.state.keycloak) {
if(this.state.authenticated) return (
<div className="contact-body">
<p>Name: {this.state.name}</p>
<p>Email: {this.state.email}</p>
<p>ID: {this.state.id}</p>
</div>
);
}
}
Would like to use Keycloak Login UI features(like OTP) along with custom authenticator SPI. In the custom authenticator SPI get form fields like username and password and authenticate it using external service. Then create users in Keycloak DB.
Can admin lock/temporarily suspend user within a realm in keycloak?
The other option, I am planning to use is, update login.ftl onsubmit to post username/password to custom service with keycloak url passed as query param.
Will validate it against custom service, create users on keycloak database and redirect to keycloak url which is passed on query param. This doesn't seem like right way.
Any help/thoughts will be highly helpful.
This is the wrong SPI you are implementing.
For external datasource or service integration you must implement a custom User Storage SPI.
You should use "User Storage SPI". It would be the Section 11 on Keycloak Doc
Section 8, is needed if you need extra/custom authentication like secret questions.

Keycloak - how to handle multiple work contexts

I have an application where single user can work in contexts of multiple companies. We call such a connection (user<->company) a permit. Every one of this permits can have different sets of permissions/roles. We want user to login just once and then he can simply change permits within application without need to enter password again.
Till now we had only one application and kept this whole permission model in our own DB. Unfortunately now we have to support second application which should inherit those permits. I was wondering wether is possible to move that model to keycloak so we don't have to replicate it to every single db and keep it in sync manually.
I have searched keycloak documentation regarding this topic but have found no information att all, which seems quite odd, because I don't think we are the first one working with multiple context application.
So now I'm asking is it possible to configure our model in keycloak and if so, how to do it? Eventually are there different options? I guess that I can provided that model as a claim with json structure but that doesn't feel right to me. I was thinking about custom IDP which could provide such claims based on DB so there no spelling errors and less repetition but I feel there should be a better way.
You could try to write your own Keycloak provider (SPI). There is a built in mechanism that allows you to expose REST endpoint on the Keycloak: https://github.com/keycloak/keycloak/tree/master/examples/providers/domain-extension
That REST could be called with authorized context only for example by passing Access-Token (Authorization header with Bearer value). On the provider level (through implementation of: org.keycloak.services.resource.RealmResourceProviderFactory and org.keycloak.services.resource.RealmResourceProvider) you have access to user's Keycloak session and object UserModel like in the following code:
AuthenticationManager.AuthResult authResult = new AppAuthManager().authenticateBearerToken(keycloakSession, keycloakSession.getContext().getRealm());
UserModel userModel = authResult.getUser();
UserModel class has methods for getting and setting attributes, so some information that indicates the current permit/company ID can be stored there. You can use REST methods exposed on the Keycloak to modify the model within the 'session' (represented by Access-Token).
The Github example shows also how to use another Keycloak provider (ex. built-in JPA provider) from you custom provider's level, so using that approach you could try to connect to the database with your permits/company informations. Of course the datasource representing you database should also be registered as Keycloak datasource.

Proper way to enrich Keycloak token via external service

What is the proper way of extending Keycloak -- for example via Service Provider Interface (SPI) -- to enrich the issued JWT token with information fetched from another service but without delegating the user credential check to the other service?
You create - what Keycloak documentation refers to as - a Protocol Mapper. They are various types of them that you can find out by going to the Clients > your_client > Mappers menu and try to create one. Besides, you should see that you can choose which JWT token you want to enrich, ID token or Access token. In your case, you need to customise the mapper's logic enough to fetch info from another service. There are two types of mapper that allow that (at least as far as I know):
The Script mapper: allows you to code a custom mapper in JavaScript, so you can implement the service call and add the result to the token claims in javascript. See the example on Stackoverflow, and source code of the mapper for more info. This has some limitations, e.g. does not support multi-valued claims properly.
Implement the mapper directly in Java: full flexibiliy but more work (implement Java interface AbstractOIDCProtocolMapper). See this Custom Keycloak Protocol Mapper for group membership for instance.

Spring Security: Different authentication methods depending on entity

first post here, hope im doing right.
In a project, we have a scenario where we have a single web application with multiple entities. Currently, the login is managed via default JDBC Spring Security provider, working fine.
For a new requirement, we need that each entity can have their own login method (currently 2 methods would be available, the JDBC one, which is the current one, and the second method would be authentication via SAML, with each entity defining their own IdP, but this is another story)
I need some guidelines on how this can be achieved, I have done some search and I have found providers for different URL's, etc... But not different login methods for the same app and url's depending on the user type or entity.
Is a good approach to have a custom single entry point where we can check the entity user and then use the suitable authentication provider?
Kind regards,
Alex
As each of your users might be using a different IDP you will in any case need to determine the username before proceeding with initialization of the authentication process - but you already know this.
One approach to take (similar to what Microsoft is using with the Office 365 for corporate users) is:
display a login page with fields for standard username + password
once user enters username and blurs the input field, you make an AJAX call (to your custom API made for this purpose) and fetch information about authentication type + IDP to use for this user
in case the type is password you simply let user continue with filling in the password field and POST to the same place as you're used to for processing with the JDBC provider
in case the type is federated authentication you initialize authentication with the correct IDP by redirecting to /saml/login?idp=xyz and continue with the SAML flow
It's possible to avoid any APIs by submitting the form once user enters the username, or let user click a "Continue" button. It would then make sense to use a custom EntryPoint which:
redirects user to the main login page in case it wasn't provided with a username
displays either login page with username/password or redirects to the correct IDP, once username was provided

Seam security with externally-orchestrated SSO

I have an application deployed on WebLogic 10.3.2 (11g), in which the user logs in through SSO. In other words, if the user is not logged in, he is redirected to SSO, where he logs in, and then is redirected back to the application. The whole redirection takes place by an the Oracle HTTP Server (a modified apache), which makes sure that only SSO-authenticated users can see the applciation.
So, when the user finally sees the application, he is already logged in.
Is there a way to use Seam security with this scenario? What I would like is to use the roles of the Subject to restrict access to certain pages and components.
A way I thought of, but for which I am not sure, is to use the subject that is populated by the SSO authentication provider of WebLogic, and use it to populate the Identity component of Seam. That would take place in the authentication method, which will always return true (since the user is already logged in). Inside the method, the credentials and roles of the Subject will be "transfered" inside the Seam identity.
Is this feasible at all?
Cheers!
You could write your own authenticate method, or override the Identity class and the login() method to achieve this. I've done something similar with a reverse proxy that performed our authentication. In the scenario, the proxy sent back the user ID of the authenticated user and all the groups they were a member of as header values. I wrote a filter to intercept the headers and then used my custom Identity class to do the rest.

Categories