[keycloak-dev] new credential SPI

Stan Silvert ssilvert at redhat.com
Fri Aug 19 11:55:02 EDT 2016


On 8/19/2016 2:43 AM, Stian Thorgersen wrote:
>
>
> On 18 August 2016 at 21:00, Bill Burke <bburke at redhat.com 
> <mailto:bburke at redhat.com>> wrote:
>
>
>
>     On 8/18/16 5:12 AM, Stian Thorgersen wrote:
>>
>>
>>     On 16 August 2016 at 00:57, Bill Burke <bburke at redhat.com
>>     <mailto:bburke at redhat.com>> wrote:
>>
>>         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 interfaceCredentialInput {
>>              String getType();
>>         }
>>
>>         public interfaceCredentialInputValidator {
>>              booleansupportsCredentialType(String credentialType);
>>              booleanisConfiguredFor(RealmModel realm, UserModel user, String credentialType);
>>              booleanisValid(RealmModel realm, UserModel user, CredentialInput input);
>>
>>         }
>>
>>         public interfaceCredentialInputUpdater {
>>              booleansupportsCredentialType(String credentialType);
>>              Set<String> requiredActionsFor(RealmModel realm, UserModel user, String credentialType);
>>              voidupdateCredential(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.
>>
>>     Extending admin console is fine in community, but would be hard
>>     to support.
>     Generic rendering from a metamodel provided by a REST API is
>     something we can and should support.  It won't be completely
>     pretty, but should work for most things.  If we don't want to
>     support Angular extensions, then the user can just completely punt
>     and have a completely different web app to configure a specific
>     component.
>
>
> I didn't say we shouldn't support extensions to the UI, but we need to 
> consider how to do it. If we tie it to much to Angular 1 specifics 
> than it becomes even harder to migrate to Angular 2.
>
>
>
>>     Especially as we would eventually have to move to AngularJS 2.0,
>>     which drastically changes things.
>
>     Moving to Angular 2 seems daunting.
>
>     https://angular.io/docs/ts/latest/guide/upgrade.html#
>     <https://angular.io/docs/ts/latest/guide/upgrade.html#>
>
>
> Yep, it's a complete rewrite! Sucks.
Bill, you may not be aware that I'm coming to Boston next month to 
attend the Angular conference.  There are sessions on migrating, so at 
least I should be able to get on the right track and make an educated 
assessment of the suckiness.
>
>
>
>
>>     I also wonder if we should provide an higher level extension to
>>     register extensions than having to do $routeProviders etc as that
>>     sounds like a fairly low level approach. Do you have any example?
>>
>
>
>     Look at the old ldap provider for an example of overriding a
>     specific component UI over a fallback generic one.  It just has a
>     more specific route than the generic page.
>
>
>
>>     Account service should be completely scrapped and replaced with
>>     something more modern. The UI needs a complete revamp and it
>>     should also be changed to AngularJS and REST service to make it
>>     more customizable and extensible.
>     Again, we can focus on generic rendering for Account Service. 
>     Then it will translate quite easily to whatever we do here.
>
>
> I don't think generic rendering works for account service as it wants 
> to be more end user friendly. Generic rendering is probably OK for the 
> admin console most of the time, but it's never going to be brilliant 
> for usability.
I've done quite a bit of work with generic rendering.  The richness and 
usability of the resulting UI tends to be a function of the richness of 
the metadata that generates it.  In other words, the more you describe 
what you are rendering the better you can render it.  We'll just have to 
see how much work we want to put into it.
>
>
>
>     Bill
>
>
>
>
> _______________________________________________
> keycloak-dev mailing list
> keycloak-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/keycloak-dev

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


More information about the keycloak-dev mailing list