How to use two providers with same username in a realm/client in keycloak - keycloak

I have keycloak instance (version 16) with one realm and two different clients.
The first client works with Open ID Connect Identity provider. It also works with public Access Type and with SSO and 2FA.
The second client works with a Custom module added from User Federation where 2FA is not possible to be used because the calls for authentication are mainly programmatically. Also, this client works with confidential Access Type.
The problem is that each client has a different external database with users, but the usernames in these databases are not unique.
And if I try to log in with the second client it works but after that, if I try to log in with the first client I can't, and vice versa. (in both clients username "notUniqueUser#email.com" is used)
The error message in this case is:
User with username notUniqueUser#email.com already exists. How do you want to continue?
“Review profile”
“Add to existing account”
Is it possible for these two clients to work both properly at the same time, when I do not have unique usernames and how should I configure it? (I find that is possible to have same email addresses but I can't find anything for usernames)
Maybe some kind of force authentication will be OK, and when the user "notUniqueUser#email.com" is already logged with the first client and I try to log in with the second, the session from the first one to be deleted and vice versa.

Depending on how your IDPs are configured you can try the following:
go to your realm
then to the IDP configuration in question
switch to Mappers
Click on Create
As a mapper type select Username teamplate Importer
in the template field and something that will make the username unique for example ${CLAIM.preferred_username}_<The Name of the IDP>
For example, if a username named 'user' logins from both 'IDP1' and 'IDP2' it will be imported into the Keycloak DB as 'user_IDP1' and 'user_IDP2', respectively.

Related

Provide "Forgot Password" feature in Keycloak to certain users only

We're using Keycloak 12 for authentication in our portal and there are two different types of users:
Internal users (read from our internal LDAP)
External users (stored in Keycloak but without being synced with the LDAP)
We'd now like to use the "Forget Password" feature provided by Keycloak. After having configured the feature and the mail server, this works fine out-of-the-box.
However we'd like to restrict the "Forget Password" feature to all users which belong to (2), i.e. the internal users. These users are not allowed updating their password via Keycloak as this is done by another mechanism.
I couldn't find any information in the documentation so far if this is possible at all?
The Keycloak Forgot Password feature is applied at the Realm level, hence applied to all the users belonging to the Realm. For Keycloak, the LDAP is just an external storage with users to authenticate against. Consequently, out of the box, there is no way (as far as I know) for the Forgot Password to only be enabled to certain users within the Realm.
Even if it would be possible IMO it would not be a very user-friendly feature, since when one activates such a feature a new link will be shown to the users on the login page in case they have forgotten their passwords. So if a user from the LDAP would click on it, it would display an error or something?!
Alternatively, you can configure the LDAP of the so-called internal users in another Realm than the one with the Forgot Password enabled. And then configure the newly created realm to be an external Identity Provider, which the users could explicitly authenticate against it. So in practice, the users would lend in the normal login page, the external users could login normally, and would have the Forgot Password option enabled. The internal users would explicitly click on the external IDP to authenticate themselves. Log in using the external IDP would be a similar user-experience as log in to the normal login page, however, the Forgot Password option would not be shown.
You can see an example such configuration here.

SAML 2.0 best practices for custom user fields

We have an existing web application which works with its own users, stored in a local SQL server database and each user has specific rights to access specific content.
A new customer is interested in using this application, but their requirement was that it should have SAML 2.0 integrated.
Now, I'm new to SSO, but I assume they want this so all user management is done at their place and that their users can log on at any of their services, using the same credentials.
The user rights defined at our web application however, are application specific; they have no meaning outside our application. So I assume these fields should remain stored and managed at our end, instead of managed at the identity provider?
But what would be the best way initiate this? I could create an empty user record locally whenever the user logons for first time, but he would literally not be able to do anything without proper rights. I could give him default right settings, but there should be at least 1 administrator to distribute the rights of the remaining users. Is it common to ask additional fields at the identity provider to initiate users for a specific service?
This can be done using entitlements sent in a SAML2 attribute. e.g. if you have a normal user profile for your application, you can ask the IdP to release an attribute such as eduPersonEntitlement or urn:oid:1.3.6.1.4.1.5923.1.1.1.7 as it's known in SAML2. If the IdP owner agrees to release this attribute you can agree a controlled vocabulary with them for the value of the attribute.
So when a normal user logs in to your application using SAML2 and their attributes arrive in an AttributeStatement with a collection of SAML2 Attribute instances you can look for urn:oid:1.3.6.1.4.1.5923.1.1.1.7. If it has a value of, perhaps, https://yourapp.com/entitlement/user you can set them up with a normal user account. If they have a value of, perhaps, https://yourapp.com/entitlement/admin, you can set them up with admin rights.
Just be careful to compare what they already have (if anything) with their incoming SAML2 entitlement, in case they longer are an admin. The IdP decides who is a normal user and who is an admin but that's up to them to work that out. All you care about is the value of urn:oid:1.3.6.1.4.1.5923.1.1.1.7
The full set of eduPerson attributes is here

keycloak - realm resolution based on username (email address)

I'm working on a multi tenant project where usernames are actually their email addresses and the domain of the email serves as a tenant identifier.
Now in keycloak I'll have different realms per tenant, but I want to have a single login page for all tenants and the actual realm that will do the authentication to be somehow resolved by the username (email address).
How do I go about doing that?
I found a thread on the mailing list (that I cant find now...) that discussed the same problem. It was something along the lines of - create a main realm that will "proxy" to the others, but I'm not quite sure how to do that.
I think Michał Łazowik's answer is on the right track, but for Single-Sign-On to work, it needs to be extended a little.
Keep in mind that because of KEYCLOAK-4593 if we have > 100 realms we may have to have multiple Keycloak servers also.
We'll need:
A separate HTTP server specifically for this purpose, auth-redirector.example.com.
An algorithm to determine the Keycloak server and realm from a username (email address).
Here would be the entire OAuth2 Authorization Code Flow:
An application discovers the user wants to log in. Before multiple realms, the realm's name would be a constant, so the application would redirect to:
https://keycloak.example.com/auth/realms/realname/protocol/openid-connect/auth?$get_params
Instead, it redirects to
https://auth-redirector.example.com/?$get_params
auth-redirector determines if it itself has a valid access token for this session, perhaps having to refresh the access token first from the Keycloak server that issued it (the user could have logged out and is trying to login as a different user that is served by a different realm).
If it has an valid access token we can determine the Keycloak server and realm from the username or email address in the access token and redirect to:
https://$keycloak_server/auth/$realm/realname/protocol/openid-connect/auth?$get_params
from here, the OAuth2 Authorization Code Flow proceeds as usual.
Else if it doesn't have a a valid access token, the auth-redirector stores the original app's $get_params as session data. It presents a form to the user asking for a username. When the user submits that, we can determine the Keycloak server and realm to use and then auth-redirector itself logs in to the Keycloak server using its own $get_params. Once the auth-redirector gets a call-back, it retrieves the access+refresh token from the Keycloak server and stores them in session data. It then, finally, redirects back to that same keycloak server and realm with the callers original $get_params (from session data). And the OAuth2 Authorization Code Flow proceeds as usual.
This is definitely a hack! But I think it could work. I'd love to try it out some day, time permitting.
Other hacks/solutions are needed for other OAuth2 flows...
The idea from the mailing list is to write a service (let's say auth-redirector.example.com) that has a single input field for email, finds realm based on domain and redirects to that realm's keycloak endpoint (e.g. auth.example.com/auth/realms/realm-name/etc…) while keeping all GET params.
You can find examples of direct login/registration URLs here: https://lists.jboss.org/pipermail/keycloak-user/2016-July/007045.html
One usability problem is that users would have to provide their email twice, I have not yet found a way to pass the username via the login URL.

How should mapping of service provider users to identity provider users work?

I'm working on setting up a service provider that supports SAML. I've added two identity providers - one custom one that I built from SimpleSAMLphp and then ssocircle. So I log in to the selected identity provider, and then it returns to my service provider and I inspect the attributes of the SAML Auth object. The identity provider I built returns whatever I want it to (obviously). The ssocircle one only returns e-mail, first, and last names.
So now to map this to the user of the service provider, I have to use some value the identity provider provides. So this led me to wonder how it should be done. Since ssocircle only gives me e-mail as a useful value, do I just use the e-mail to map to the SP user?
Let's pretend for a second that ssocircle doesn't validate e-mail addresses. So now if I create a second account at ssocircle with the same e-mail, I can log in as my coworker who I know has admin privileges.
So my question is, do I handle this? Or is the onus on the admin who set up the identity provider and say "well you shouldn't have used an identity provider that doesn't validate e-mail addresses!" or something of that nature? Or should I only allow identity providers that pass a certain value, like userid or 0.9.2342.19200300.100.1.1? Is there something that identity providers commonly use?
Well, you said it, two different identity providers. They both should be passing not only the email but different entity ids and certificates.
In multi-tenant applications that would mean two different applications, but if you plan to allow multiple IDPs to point to a single app you will need to ensure that same email but different entityID create two different users and or throw an error after the first was created that the second cannot be provision nor access.
Interesting question. These days people think always of auto federation of users by some attribute. In early SAML federation days federating two unrelated users was a manual step in which a user logs in at the IDP and logs in to the SP providing both sets of credentials and then manually federated these two user accounts. The process guarantees that only the user who has access to the accounts at the IDP and SP controls the linkage between the two. It also allows anonymous naming identifiers (SAML persistent NameIDFormat) which protects privacy because even the IDP does not know the user name at the SP and vice versa.
Unfortunately the process was to complicated for users and with the success of OpenID the aspect was getting less and less important.
To answer your question: What you describe happens in the real world -see Office 365 authentication bypass
You need to check that the IDP is authoritative to send a specific attribute and attribute scope in case of two IDPs.
In case of one IDP the attribute must be verified (SSOCircle verifies email address) and it should better be unique (For example SSOCircle userId) to avoid that two users with the same attribute are mapped to a single user at the SP.
If the userid's are not the same (e.g. you use a simple user ID at the IDP and email address format at the SP) you can still add a correlation attribute at the SP (e.g. an attribute named ssocircle-userid) and use that to link the user accounts.

Multiple Client Types

I have a web application that I would like to use authenticate using MembershipReboot for a subset of users but internally I would also like to use Active Directory.
What's the best practice of authenticating a single web application with two different authentication models? Any code samples would be great.
For this scenario you'll need a UserService for Membership Reboot. This will mean when users log in to Identity Server using the local username & password fields they will use Membership Reebot. You can find this UserService here.
To also use Active Directory you need to configure it as an external identity provider. This will then provide users with the option to log in using their AD credentials.
If you want to specify in your requests which provider to log the user into, check out the acr_values parameter of the Authorization endpoint or the IdentityProviderRestrictions property of the Client class.