I have implemented a custom Keycloak UserStorageProvider SPI (following point 11 of official Doc: https://www.keycloak.org/docs/latest/server_development/index.html#_user-storage-spi) which does following:
Authenticate users (not previously existing on the local store) against an
external auth service.
Save the (successfully authenticated against our custom service) user into
the Keycloak local store.
After the users have been imported on keycloak's local store (after users
successfully loged themselves in), the admins are then able to map roles
to those users for resource authorization from keycloak's admin console.
The problem I'm running into is following: Step 1 and 2 work perfectly. And regarding step 3, I can log myself successfully with a user that was saved on the keycloak's local store (after finding it on the external UserProvider), BUT (an here lies the crux of the problem); as soon as I add any role to that imported user, then I can't log myself anymore into that account and the logs show that my custom UserStorageProvider isn't being used anymore from that point onwards when login for that user. Somehow attaching a role to that user makes him invisible to my custom UserStorageProvider (even if I delete the role/(s) again).
In the best case scenario I'm trying to achieve, I'd be able to "log in" with the user (saved locally after authenticated form external SPI), even after assigning roles to him.
Any feedback would be greatly appreciated!!
Thanks in advance for your suggestions.
In the case somebody has this problem in the future, when you implement a provider SPI, you have 2 options as the doc mentions. Federated Store and importing users to the local Keycloak store. If you go with the importing/synching strategy, it is necessary to set federation link to the provider like this:
<UserModel instance>.setFederationLink(<ComponentModel id>);
If you don't do this, then Keycloak can't "remember" that those imported users should be handled by your provider SPI, and in general you won't have the expected behaviour out of your custom Provider SPI.
Related
Requirements:
Given a webapp: 'myapp.com' that is hosted on AWS.
We want 20 unrelated companies to be able to access myapp.com via SSO (SAML)
Each company has its own domain(s) (company1.com, company2.net, and so on).
Each user connects from the office with their computer (Windows).
Each user belongs to the company's AD (could be ADFS, Azure AD or whatever).
What I've tried:
I have been able to understand and test the OneLogin toolkit for one organization but I don't know how to do it when there is more than one organization.
The problem:
Maybe it's a software design or architecture issue but I don't know how to scale the SAML implementations I see online (OneLogin's is an example) for more than one company/organization.
My findings (2 possible options):
First option: Each company has its own IdP in addition to an AD (could be ADFS, Azure AD or whatever)
In authenticindication.com we register the 20 or 40 IdPs and to each IdP we associate the domain of the company.
When the user tries to access authenticindication.com, if there is no open session, the user is asked to enter the email and from there we get the domain.
In case of having an IdP associated with that domain, the user would be redirected.
In case of not having an associated IdP, the user would be asked for a password since it would be considered a local user.
Second option:The companies do not have their own IdP
In this case, we would have to deploy a common IdP and have that IdP connect to their ADs, but that would require those companies to give the IdP machine access/permissions to be able to perform queries to authenticate users.
What I expect:
I would like to know if the approach I am taking is wrong and if the only options are to create an IdP for those companies that do not have their own IdP and for those companies that do have their own IdP to reuse them. Is there a single solution that covers both cases? I was reading in Spring Security but I did not find anything.
If anyone has implemented anything similar, it would also be appreciated if they could share their knowledge.
I am using keycloak as an identity broker to SAML identity provider in order to login to web application.
To get it work I have created new authentication flow which looks like: "Create User If Unique", "Automatically Link Brokered Account".
Keycloak redirects correctly to the identity provider with the login page. After login identity provider redirects as expected to keycloak and then to my web application but keycloak also creates local user.
Is it possible to use external IDP without local users creation?
The problem with local users : I have "custom user federation" implementation which fetch users from my application and if local user created it's not possible login to keycloak using "custom user federation". Keycloak will just try login like with local user.
Unfortunately, it is currently not possible to skip the creation of local user account. According to the Keycloak team, they are deferring the support "as we are planning on some larger work to the storage layer which will make it possible to deliver on this capabiltiy".
See Feature Request https://issues.jboss.org/browse/KEYCLOAK-4429.
I am writing a Spring Boot application where I want to authenticate users against a LDAP server. I have seen solutions and API documentation where an Admin Users credentials are hardcoded in the code.
My question is: Why can't I simply use the credentials for the user that I am trying to authenticate in the first place? If the binding succeeds, I can confirm authentication and get the list of groups they belong to. Is there some good reason why I shouldn't do that?
The reason LDAP examples often include admin users is because LDAP isn't always used for authentication (i.e., to determine if a particular username/password is valid), but sometimes for authorization only (i.e., to retrieve user's assigned groups, to determine if they should have access to the protected resource), when authentication part is done elsewhere (e.g., via Kerberos SSO). If your only use case is bind, then yes, you shouldn't need the admin user.
EDIT: one caveat, though - the LDAP server might have a restriction on binds (see this question, for example), in which case you'll need to have an admin user regardless.
Typically you want to have a service account, specific to the application:
Perform the bind
Lookup user
Return user's group membership
Application authorizes user based on the results
This helps with managing access controls on the authoritative backend because you only have to create ACIs for the service accounts rather than each individual user. It's also more secure because you are granting permissions to a single account, and thus reducing the likelihood of mis-configuring a single user's permissions.
I am trying to use java code mention on link: http://www.nexttutorial.com/faq/azureAD/1/Azure-active-directory-graph-api-user-authentication-in-java - but I get below error:
java.util.concurrent.ExecutionException: com.microsoft.aad.adal4j.AuthenticationException: {"error_description":"AADSTS50055: Force Change Password.\r\nTrace ID: 7596cf92-f3d6-4baf-a0c9-d166a92d1500\r\nCorrelation ID: 8cccb074-4ae4-4c9b-932b-1f4ddcb514cb\r\nTimestamp: 2017-05-05 08:20:28Z","error":"user_password_expired"}
I haven't used the Java APIs, but I can tell you two things that are the core of the problem:
The user's password has expired
You are using Resource Owner Password Grant flow
You need to change the application to instead show a browser window so the user can reset their password. If you just want to test the code as is, you can open a new Incognito/private/InPrivate window and sign in to e.g. portal.azure.com with the user. That will allow you to make sure they have a working password.
But I would advise against using that sign in flow because of potential problems like this one.
The reason you get the error is that the user needs to set a new password, but the flow you are using cannot support that scenario. It also cannot support the scenario where the user account has MFA enabled/is a Microsoft account etc.
And by the way, if this app is intended not to be used by a user, but just run as is, I would suggest making it a daemon with application permissions on the necessary APIs and then use client credentials flow for authentication. No user account needed then, since the app has the needed rights.
I have a WSO2 Identiy server installed and i have written some java code to get user information with oauth 2. For this I am using OLTU. I have connected correctly and after negotiating the access_code, I ask for the userinfo endpoint like this:
https://<serverIP>:9443/oauth2/userinfo?schema=openid
I get user info correctly in JSON format:
{"email":"xxxx#xxx.aa","name":"xxx","family_name":"xx","preferred_username":"xxx","given_name":"xx"}
What I find is that no role information is returned. I have created some custom roles and asigned the users. They don't have any permisions asigned.
Do I have to configure anything in the server? The request has to be made in any other way? What am I doing wrong?
There are two ways to add this claim mapping. It's depends on your requirement.
To get this done has to add a role claim mapping under "http://wso2.org/oidc/claim" claim dialect. This can be done in following ways
Case 1 : For fresh WSO2IS before first startup
Go to <IS_HOME>/repository/conf/claim-config.xml file<br/>
Add following configuration under <Dialect dialectURI="http://wso2.org/oidc/claim"><br/>
<Claim>
<ClaimURI>Roles</ClaimURI>
<DisplayName>Roles</DisplayName>
<AttributeID>role</AttributeID>
<Description>role of the user</Description>
<DisplayOrder>10</DisplayOrder>
<SupportedByDefault />
</Claim>
Case 2: For already running server.
Login to the Identity server management console as admin user.
Click the Configure button to access the Configure menu
Click on http://wso2.org/oidc/claim Dialect.
Click on "Add New Claim Mapping" and set the above details.
(There you will get an error which is known issues. But that value will store. Then again edit it and set Mapped Attribute again)
Then restart the server. Now you can get user info with roles