<html>
  <head>
    <meta content="text/html; charset=windows-1252"
      http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <p>I never understood why all this is done at the UserFederationSPI
      level.  Why isn't it done at the authenticator level?  Its all
      protocol stuff.  Would you do the same for bearer tokens if we had
      to?  I don't think so.  UserStorageSPI is supposed to be an
      abstraction for storage, not a protocol abstraction.<br>
    </p>
    <br>
    <div class="moz-cite-prefix">On 8/23/16 3:23 AM, Marek Posolda
      wrote:<br>
    </div>
    <blockquote cite="mid:57BBF9DE.7030703@redhat.com" type="cite">
      <meta content="text/html; charset=windows-1252"
        http-equiv="Content-Type">
      <div class="moz-cite-prefix">Few additional things, which applies
        for credentials like SPNEGO/Kerberos tokens, however I think
        they might be required for other credential types too.<br>
        <br>
        - Authentication of unknown user : For example in case of
        SPNEGO, you have just the token, but you don't know which user
        are you authenticating. User is "recognized" later once the
        SPNEGO token is successfully validated<br>
        <br>
        - More handshakes for credential validation : This is again
        related to SPNEGO, but I am sure it applies for some other
        credential types too. Instead of true/false we may need
        something like : SUCCESS, FAILED, CONTINUE. <br>
        Also the possibility to send some context info back to the
        client, so client can continue with the handshake. For the old
        federationProvider we had:<br>
        <br>
        <meta http-equiv="content-type" content="text/html;
          charset=windows-1252">
        <pre style="background-color:#ffffff;color:#000000;font-family:'DejaVu Sans Mono';font-size:9.0pt;">CredentialValidationOutput validCredentials(RealmModel realm, UserCredentialModel credential);

</pre>
        I guess we need something similar for the new SPI too? Also for
        "isValid" method, I would rather return
        CredentialValidationOutput instead of just true/false.
        True/false is good for passwords/OTP, which are most widely used
        credential types in Keycloak, but may not be sufficient for
        other custom credential types.<br>
        <br>
        Marek<br>
        <br>
        On 16/08/16 00:57, Bill Burke wrote:<br>
      </div>
      <blockquote
        cite="mid:a59cd47b-6d17-0997-76f8-7dc62b08da0b@redhat.com"
        type="cite">
        <meta http-equiv="content-type" content="text/html;
          charset=windows-1252">
        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.
        <p>* Is the user configured for a specific credential type</p>
        <p>* Is a credential valid</p>
        <p>* What required actions must be taken for an unconfigured
          credential type</p>
        <p>* update a credential</p>
        <p>How each of these events is resolved will depend on the
          configuration of the system and these interfaces:</p>
        <p>
          <meta http-equiv="content-type" content="text/html;
            charset=windows-1252">
        </p>
        <pre style="background-color:#ffffff;color:#000000;font-family:'Menlo';font-size:9.0pt;"><span style="color:#000080;font-weight:bold;">public interface </span>CredentialInput {
    String getType();
}
</pre>
        <p>
          <meta http-equiv="content-type" content="text/html;
            charset=windows-1252">
        </p>
        <p>
          <meta http-equiv="content-type" content="text/html;
            charset=windows-1252">
        </p>
        <pre style="background-color:#ffffff;color:#000000;font-family:'Menlo';font-size:9.0pt;"><span style="color:#000080;font-weight:bold;">public interface </span>CredentialInputValidator {
    <span style="color:#000080;font-weight:bold;">boolean </span>supportsCredentialType(String credentialType);
    <span style="color:#000080;font-weight:bold;">boolean </span>isConfiguredFor(RealmModel realm, UserModel user, String credentialType);
    <span style="color:#000080;font-weight:bold;">boolean </span>isValid(RealmModel realm, UserModel user, CredentialInput input);

}
</pre>
        <p>
          <meta http-equiv="content-type" content="text/html;
            charset=windows-1252">
        </p>
        <pre style="background-color:#ffffff;color:#000000;font-family:'Menlo';font-size:9.0pt;"><span style="color:#000080;font-weight:bold;">public interface </span>CredentialInputUpdater {
    <span style="color:#000080;font-weight:bold;">boolean </span>supportsCredentialType(String credentialType);
    Set&lt;String&gt; requiredActionsFor(RealmModel realm, UserModel user, String credentialType);
    <span style="color:#000080;font-weight:bold;">void </span>updateCredential(RealmModel realm, UserModel user, CredentialInput input);
}

</pre>
        <p>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.</p>
        <p>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.</p>
        <p>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.</p>
        <p>Let's walk through an authentication flow, specificaly for
          OTP.</p>
        <p>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().</p>
        <p>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.</p>
        <p>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.<br>
        </p>
        <p>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.</p>
        <p>** Admin console and Account Service UIs **</p>
        <p>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.<br>
        </p>
        <p><br>
        </p>
        <br>
        <fieldset class="mimeAttachmentHeader"></fieldset>
        <br>
        <pre wrap="">_______________________________________________
keycloak-dev mailing list
<a moz-do-not-send="true" class="moz-txt-link-abbreviated" href="mailto:keycloak-dev@lists.jboss.org">keycloak-dev@lists.jboss.org</a>
<a moz-do-not-send="true" class="moz-txt-link-freetext" href="https://lists.jboss.org/mailman/listinfo/keycloak-dev">https://lists.jboss.org/mailman/listinfo/keycloak-dev</a></pre>
      </blockquote>
      <br>
    </blockquote>
    <br>
  </body>
</html>