<html>
  <head>
    <meta content="text/html; charset=windows-1252"
      http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <div class="moz-cite-prefix">Regarding SPNEGO, I remember we
      discussed it on ML few years ago and agreed on doing it at
      UserFederation level. However that was before we had
      Authentication SPI <span class="moz-smiley-s1"><span> :-) </span></span><br>
      <br>
      So yes, maybe we can refactor now? <br>
      <br>
      What we can do is:<br>
      - Add keytab, kerberos principal and "debug" as properties of
      SPNEGOAuthenticator. <br>
      - If user is successfuly authenticated by SPNEGOAuthenticator, he
      will be lookup by UserFederationStorage. If found, then
      authentication finished with success (so the case when user is in
      LDAP is still supported). If he is not found, then he is lazily
      created (typically the usecase for SPNEGO/Kerberos not backed by
      LDAP)<br>
      <br>
      This shouldn't be too hard to do though.<br>
      <br>
      Regarding multiple handshakes, this is still valid requirement
      IMO? There are authentication mechanisms like SASL, which count
      with multiple handshakes. The Keycloak is currently around
      passwords and OTP, but people may want to add their own credential
      types or in the future we can add more mechanisms, which can
      require multiple handshakes? <br>
      <br>
      Marek<br>
       <br>
      <br>
      On 23/08/16 14:47, Bill Burke wrote:<br>
    </div>
    <blockquote
      cite="mid:44df3c3e-0d25-1ba0-182f-dd3ad04b8b5e@redhat.com"
      type="cite">
      <meta content="text/html; charset=windows-1252"
        http-equiv="Content-Type">
      <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>
    </blockquote>
    <br>
  </body>
</html>