[keycloak-dev] new credential SPI

Bill Burke bburke at redhat.com
Mon Aug 15 18:57:46 EDT 2016


I'm currently working on a new credential SPI that will replace existing 
methods on UserProvider and UserModel, as well as replacing 
UserCredentialModel, etc.  This is a work in progress where we may see 
multiple iterations in master.  I hope to remain backward compatible, 
but can't guarentee I won't break existing User Federation Providers.  
Here's an initial writeup to explain things. Credentials revolve around 
these 4 events that are initiated by authentication flows, the admin 
console, and the account service.

* Is the user configured for a specific credential type

* Is a credential valid

* What required actions must be taken for an unconfigured credential type

* update a credential

How each of these events is resolved will depend on the configuration of 
the system and these interfaces:

public interface CredentialInput {
     String getType();
}

public interface CredentialInputValidator {
     boolean supportsCredentialType(String credentialType);
     boolean isConfiguredFor(RealmModel realm, UserModel user, String credentialType);
     boolean isValid(RealmModel realm, UserModel user, CredentialInput input);

}

public interface CredentialInputUpdater {
     boolean supportsCredentialType(String credentialType);
     Set<String> requiredActionsFor(RealmModel realm, UserModel user, String credentialType);
     void updateCredential(RealmModel realm, UserModel user, CredentialInput input);
}

Two different types of components will be able to implement these 
interfaces.  UserStorageProviders (user federation) and 
CredentialProviders.  CredentialProviders are components configured at 
the realm level.  CredentialProviders are responsible for managing one 
or more types of credential types and are the bridge between 
CredentialInput and where the credential is stored.  UserStorageProvider 
is always asked first whether it can complete the requested action, then 
CredentialProviders are queried in order of their priority.

Each UserStorageProvider and/or CredentialProvider can implement the 
OnUserCache callback interface discussed in my previous custom caching 
email.  This allows each credential type to decide whether it will be 
cached or not along with the user.  For example, HOTP cannot be cached.

So, for example, there will be a KeycloakMobileOTPProvider.  This deals 
with Google Authenticator and FreeOTP as well as storing these things 
within Keycloak storage, it also looks at the OTP policy of the realm to 
determine how to update and store the OTP secret and stuff.  There is 
also a KeycloakPasswordProvider which hooks into Keycloak storage and 
the PasswordPolicies set up by the realm.  When a user is cached, the 
KeycloakPasswordProvider will add the hashed password to the user cache, 
the KeycloakMobileOTPProvider will add the OTP secret to cache if its 
not HOTP and needs to maintain a counter.

Let's walk through an authentication flow, specificaly for OTP.

1. Authenticator calls KeycloakSession.users().isConfiguredFor(realm, 
user, "OTP").  If the user was loaded by a UserStorageProvider and that 
provider implements the CredentialInputValidator interface, 
isConfiguredFor() is called on that.  If that returns false, each 
CredentialProvider is iterated on to call isConfiguredFor().

2. If OTP is required and not configured for the user, the Authenticator 
then calls KeycloakSession.users().requiredActionsFor(...).  Again, 
UserStorageProvider is queried first, then the CredneitalProviders.  The 
first provider that returns a non-empty set will end the query and the 
set of required actions will be returned.

3a. Let's say that in this particular example, the generic OTP Requried 
Action screen is invoked.  In that case, this required action provider 
callsKeycloakSession.users().updateCredential. The first 
UserStorageProvider or CredentialProvider that can handle this 
credential type will save the credential.

3b. If OTP is configured for user, the OTP is obtained by the 
Authenticator and KeycloakSession.users().isValid() method is called.   
Again, UserStorageProvider first, then each CredentialProvider.  Each 
provider is queried until one returns true or the list is exhausted.  
FYI, This algorithm allows for multiple OTP authenticators per user.

** Admin console and Account Service UIs **

Like we do for other components, the UserStorageProvider or 
CredentialProvider can optionally provide a list of 
ProviderConfigProperties for the admin console and/or account serviceso 
that it can create a credential for a specific user. There will be 
separate property lists for admin console and account service.  If a 
specific custom screen is desired, I'm pretty sure we can just allow the 
develoepr to plug in their own $routeProvider for the admin console.  We 
don't have a pluggable mechanism for the account service yet (or a way 
to generic render either).  This will need to be developed eventually.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/keycloak-dev/attachments/20160815/99c95996/attachment-0001.html 


More information about the keycloak-dev mailing list