[keycloak-dev] How would you handle an external user store?

Marek Posolda mposolda at redhat.com
Wed Jul 9 03:02:14 EDT 2014


On 9.7.2014 01:10, Bill Burke wrote:
>
>
> On 7/8/2014 4:06 PM, Marek Posolda wrote:
>> On 8.7.2014 18:50, Bill Burke wrote:
>>>> AuthProvider is trying to achieve something different than storing
>>>> users, and the combination of the two is quite flexible.
>>> They serve different purposes? And yet AuthProvider stores users:
>>>
>>> AuthProvider.registerUser()
>>>
>>> and retrieves them:
>>>
>>> AuthProvider.getUser()
>>>
>>> Then you have AuthenticationManager which creates a UserModel, sets up
>>> an AuthenticationLink.  So a developer has to implement registerUser()
>>> as well as the create interfaces of UserProvider.
>> IMO the difference is:
>> - UserProvider is used to implement whole storage SPI and store *all*
>> informations needed for user (roles, socialLinks, requiredRoles etc...)
>>
>> - AuthenticationProvider is used just for password based authentication
>> and hence need just very small subset of UserProvider methods. Note that
>> methods "registerUser" and "updatePassword" are not mandatory to
>> implement if you set "passwordUpdateSupported" for particular
>> AuthenticationProvider to false. Method "registerUser" is used just to
>> send "some" data of UserModel to the Auth store, but it doesn't need to
>> be all (For example with LDAP you store just username, firstName,
>> lastName, email ).
>>
>
> I was under the impression that LDAP schemas often store more than 
> username, first, last, and email. i.e. address, phone number, really 
> any number of claims.  They also can store role mappings as well, 
> correct? 
Yeah, they can store phone, address and also role mappings etc. But they 
can't easily store generic attributes, requiredActions etc.
> So if a user has all those things in LDAP *AND* they want to 
> authenticate through LDAP, what do they do?
I think that's the idea behind Sync SPI, which doesn't yet exist, but is 
planned for next version. This will allow one-way or two-way sync of all 
the possible stuff including roles between Keycloak and external store 
like LDAP. More info in JIRA https://issues.jboss.org/browse/KEYCLOAK-373
>
> The same could be said of RDBMS too.
>
>> The point is, that AuthenticationProvider is really easy to implement as
>> it doesn't need to store all Keycloak data related to user.
>
> But that is not currently how you use AuthenticationProvider.
>
> If the user is not already stored in a Keycloak UserModel, then 
> AuthenticationProvider.getUser() must be implemented.  Otherwise 
> INVALID_USER is returned.
>
>
> Besides.  UserProvider is just as easy to implement.
>
>> See
>> PropertiesAuthenticationProvider from our examples. And note that we
>> already have community members, who implement their own Authentication
>> providers. IMO LDAP, Properties file, or legacy database are classic
>> example, which suits much better as AuthenticationProvider than
>> UserProvider.
>>
>
> I really don't care if users are already implementing SPIs for a beta 
> project.  The time to fix the SPIs is *NOW* not after 1.0 Final 
> release.  Once the APIs/SPIs go final, we are stuck with them.
>
>
>> I am not sure if Federation based on metadata on UserModel is good idea.
>> I think we already discussed Federation approach and the decision was to
>> avoid it due to many reasons. I believe that Authentication SPI and Sync
>> SPI were introduced mainly to avoid federation approach...
>>
>
> What Sync SPI are you talking about?  We don't have a Sync SPI. We 
> only have a one-way half-baked sync from 
> AuthenticationProvider.AuthUser -> UserModel.
>
>>   I am happy with AuthUserProvider
>
> Drawing 3 boxes with lines between them does not an SPI make.
>
> , which delegates "store" to other
>> underlying UserProvider, but authentication to one or more
>> AuthenticationProviders. This might help to remove the "authentication"
>> related code from AuthenticationManager. So something like:
>>
>>                                           +--------------------+
>>                             Store         |                    |
>>                              +------------> JpaUserProvider   |
>>                              |            |                    |
>>                              |            +--------------------+
>>           +------------------+
>>           |                  |
>>           | AuthUserProvider |            +--------------------+
>>           |                  |            |                    |
>>           +------------------+            | 
>> LDAPAuthenticationProvider  |
>> +------------>                    |
>>                             Authenticate  +--------------------+
>>
>>
>>
>> LDAPUserProvider or PropertiesFileUserProvider doesn't make much sense
>> to me as implementors would need to leave almost all methods empty or
>> "throw new NotImplementedException()"
>>
>
> They wouldn't leave these methods empty.  Take a look at the 
> UserProvider methods.  For example
>
>     User getUserById(String id, String realm);
>     User getUserByUsername(String username, String realm);
>     User getUserByEmail(String email, String realm);
>     User getUserByAttribute(String name, String value, String realm);
>
>
> Would not an LDAPUserProvider do an LDAP query to see if the user 
> exists, then import the user into local UserProvider storage, then 
> return that object?
>
> UserProvider.verifyCredentials(User user, Credentials... credentials)
AFAIR many SSO servers like CAS allow easy way for users to plug their 
authentication mechanism. If only way to do this in Keycloak is to 
implement whole UserProvider interface, it looks a bit like overhead to 
me. For authentication purposes only, people need just to implement 
"getUserByUsername" and eventually "getUserByEmail", but for example 
they don't need "getUserById"or "getUserBytAttribute"
>
> If LDAP only verifies password, then do an LDAP query, otherwise 
> delegate to the local UserProvider.
>
> If the local User is modified, then wouldn't it be prudent for the 
> LDAPUserProvider to wrap return User instances so that it could 
> register sync events?  Sync events that would trigger the update to 
> get back to the LDAP server eventually?
>
> IMO, UserProvider is the *perfect* place to implement a Sync API. Out 
> of the box, we would have an LDAPUserProvider which you could 
> configure in the admin console.  i.e. specify connection parameters 
> and attribute mappings.  Anything beyond that common use case would 
> have to be written by the user.
I agree that UserProvider is good place to call authentication or 
register sync events. Just not sure if it's good to mandate people to 
implement whole UserProvider interface if they want just subset of it 
(like only authentication related methods)...
>
>> As I said LDAPUserProvider doesn't make much sense to me, so it's not
>> needed to configure in 2 places. AFAIK in next KC version, the plan for
>> stuff like SMTP and LDAP is to remove it from realm configuration and
>> move it to keycloak-server.json . And also the possibility to configure
>> stuff from keycloak-server.json in admin console UI.
>>
>
> If you move LDAP config to keycloak-server.json then you remove the 
> notion of Keycloak being able to have multiple and distinct realms. 
> Same goes with SMTP.  You might want to use different email/password 
> for email login for different realms.
>
I think the plan here is to have something like "datasources" . 
Basically you can have configurations like "LDAPConfig1" or 
"SMTPConfig1" at keycloak-server.json level and then each realm can 
point just to this name. This will allow that 2 realms can share same 
SMTP/LDAP configuration without repeating stuff, but also it will still 
be possibility to use different configuration by each realm if they want to.

Marek


More information about the keycloak-dev mailing list