Class ScramScheme

  • All Implemented Interfaces:
    AuthScheme

    @Contract(threading=UNSAFE)
    @Experimental
    public final class ScramScheme
    extends java.lang.Object
    implements AuthScheme
    Strict HTTP SCRAM client implementing SCRAM-SHA-256 per RFC 7804 with SCRAM core per RFC 5802/7677.

    HTTP SCRAM uses no channel binding (GS2 header "n,,"; c=biws).

    Experimental: This API is work in progress and may change without notice in a future release.

    Since:
    5.6
    • Constructor Summary

      Constructors 
      Constructor Description
      ScramScheme()
      Default policy: warn if i < 4096, no hard enforcement; SHA-256 only.
      ScramScheme​(int warnMinIterations, int minIterationsRequired, int maxIterationsAllowed, java.security.SecureRandom rnd)
      Constructor with custom iteration policy.
      ScramScheme​(int warnMinIterations, int minIterationsRequired, java.security.SecureRandom rnd)
      Constructor with custom iteration policy.
    • Method Summary

      All Methods Static Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      private static java.lang.String b64ToString​(java.lang.String b64)  
      private java.lang.String buildClientFinalAndExpectV()  
      private java.lang.String buildClientFirst()  
      private static java.lang.String escapeUser​(java.lang.String user)  
      java.lang.String generateAuthResponse​(org.apache.hc.core5.http.HttpHost host, org.apache.hc.core5.http.HttpRequest request, org.apache.hc.core5.http.protocol.HttpContext context)
      Generates an authorization response based on the current state.
      private java.lang.String genNonce()  
      java.lang.String getName()
      Returns textual designation of the scheme.
      java.security.Principal getPrincipal()
      Returns Principal whose credentials are used.
      java.lang.String getRealm()
      Returns authentication realm.
      private static byte[] hiPBKDF2​(char[] password, byte[] salt, int iterations, int dkLen)  
      private static byte[] hmac​(byte[] key, java.lang.String msg)  
      boolean isChallengeComplete()
      Authentication process may involve a series of challenge-response exchanges.
      boolean isChallengeExpected()
      SCRAM must inspect final responses to verify v= in Authentication-Info.
      boolean isConnectionBased()
      SCRAM is per-request (no connection binding).
      boolean isResponseReady​(org.apache.hc.core5.http.HttpHost host, CredentialsProvider credentialsProvider, org.apache.hc.core5.http.protocol.HttpContext context)
      Allow response when: - INIT (preemptive client-first) — only if creds have been prepared - ANNOUNCED (401 without data) - SERVER_FIRST_RCVD (ready to send client-final)
      private static java.util.Map<java.lang.String,​java.lang.String> parseAttrs​(java.lang.String s)  
      void processChallenge​(AuthChallenge authChallenge, org.apache.hc.core5.http.protocol.HttpContext context)
      void processChallenge​(org.apache.hc.core5.http.HttpHost host, boolean challenged, AuthChallenge authChallenge, org.apache.hc.core5.http.protocol.HttpContext context)
      Handles 401 challenges (with/without data) and final responses carrying Authentication-Info (any status code).
      private static java.lang.String quoteParam​(java.lang.String v)  
      private static byte[] sha256​(byte[] in)  
      private static java.lang.String stringToB64​(java.lang.String s)  
      private static java.util.Map<java.lang.String,​java.lang.String> toParamMap​(java.util.List<org.apache.hc.core5.http.NameValuePair> pairs)  
      private static byte[] xor​(byte[] a, byte[] b)  
      private static void zero​(byte[] a)  
      private void zeroAndClearExpectedV()  
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Field Detail

      • LOG

        private static final org.slf4j.Logger LOG
      • DEFAULT_WARN_MIN_ITERATIONS

        private static final int DEFAULT_WARN_MIN_ITERATIONS
        See Also:
        Constant Field Values
      • DEFAULT_MAX_ITERATIONS_ALLOWED

        private static final int DEFAULT_MAX_ITERATIONS_ALLOWED
        See Also:
        Constant Field Values
      • B64

        private static final java.util.Base64.Encoder B64
      • B64D

        private static final java.util.Base64.Decoder B64D
      • secureRandom

        private final java.security.SecureRandom secureRandom
      • warnMinIterations

        private final int warnMinIterations
      • minIterationsRequired

        private final int minIterationsRequired
      • maxIterationsAllowed

        private final int maxIterationsAllowed
      • complete

        private boolean complete
      • realm

        private java.lang.String realm
      • sid

        private java.lang.String sid
      • username

        private java.lang.String username
      • password

        private char[] password
      • principal

        private java.security.Principal principal
      • clientNonce

        private java.lang.String clientNonce
      • clientFirstBare

        private java.lang.String clientFirstBare
      • serverFirstRaw

        private java.lang.String serverFirstRaw
      • serverNonce

        private java.lang.String serverNonce
      • salt

        private byte[] salt
      • iterations

        private int iterations
      • expectedV

        private byte[] expectedV
    • Constructor Detail

      • ScramScheme

        public ScramScheme()
        Default policy: warn if i < 4096, no hard enforcement; SHA-256 only.
        Since:
        5.6
      • ScramScheme

        public ScramScheme​(int warnMinIterations,
                           int minIterationsRequired,
                           java.security.SecureRandom rnd)
        Constructor with custom iteration policy.
        Parameters:
        warnMinIterations - warn if iteration count is lower than this (0 disables warnings)
        minIterationsRequired - fail if iteration count is lower than this (0 disables enforcement)
        rnd - optional secure random source (null uses system default)
        Since:
        5.6
      • ScramScheme

        public ScramScheme​(int warnMinIterations,
                           int minIterationsRequired,
                           int maxIterationsAllowed,
                           java.security.SecureRandom rnd)
        Constructor with custom iteration policy.
        Parameters:
        warnMinIterations - warn if iteration count is lower than this (0 disables warnings)
        minIterationsRequired - fail if iteration count is lower than this (0 disables enforcement)
        maxIterationsAllowed - fail if iteration count is greater than this (must be positive)
        rnd - optional secure random source (null uses system default)
        Since:
        5.6
    • Method Detail

      • getName

        public java.lang.String getName()
        Returns textual designation of the scheme.
        Specified by:
        getName in interface AuthScheme
        Returns:
        the name of the given authentication scheme
        Since:
        5.6
      • isConnectionBased

        public boolean isConnectionBased()
        SCRAM is per-request (no connection binding).
        Specified by:
        isConnectionBased in interface AuthScheme
        Returns:
        true if the scheme is connection based, false if the scheme is request based.
        Since:
        5.6
      • isChallengeExpected

        public boolean isChallengeExpected()
        SCRAM must inspect final responses to verify v= in Authentication-Info.
        Specified by:
        isChallengeExpected in interface AuthScheme
        Returns:
        true if responses with non 401/407 response codes must be processed by the scheme.
        Since:
        5.6
      • processChallenge

        public void processChallenge​(org.apache.hc.core5.http.HttpHost host,
                                     boolean challenged,
                                     AuthChallenge authChallenge,
                                     org.apache.hc.core5.http.protocol.HttpContext context)
                              throws MalformedChallengeException,
                                     AuthenticationException
        Handles 401 challenges (with/without data) and final responses carrying Authentication-Info (any status code).
        Specified by:
        processChallenge in interface AuthScheme
        Parameters:
        host - HTTP host
        challenged - true if the response was unauthorised (401/407)
        authChallenge - the auth challenge or null if no challenge was received
        context - HTTP context
        Throws:
        MalformedChallengeException - in case the auth challenge is incomplete,
        AuthenticationException - in case the authentication process is unsuccessful.
        Since:
        5.6
      • isChallengeComplete

        public boolean isChallengeComplete()
        Description copied from interface: AuthScheme
        Authentication process may involve a series of challenge-response exchanges. This method tests if the authorization process has been fully completed (either successfully or unsuccessfully), that is, all the required authorization challenges have been processed in their entirety.

        Please note if the scheme returns true from this method in response to a challenge, it effectively implies a failure to respond to this challenge and termination of the authentication process.

        Specified by:
        isChallengeComplete in interface AuthScheme
        Returns:
        true if the authentication process has been completed, false otherwise.
        Since:
        5.6
      • getRealm

        public java.lang.String getRealm()
        Description copied from interface: AuthScheme
        Returns authentication realm. If the concept of an authentication realm is not applicable to the given authentication scheme, returns null.
        Specified by:
        getRealm in interface AuthScheme
        Returns:
        the authentication realm
        Since:
        5.6
      • isResponseReady

        public boolean isResponseReady​(org.apache.hc.core5.http.HttpHost host,
                                       CredentialsProvider credentialsProvider,
                                       org.apache.hc.core5.http.protocol.HttpContext context)
                                throws AuthenticationException
        Allow response when: - INIT (preemptive client-first) — only if creds have been prepared - ANNOUNCED (401 without data) - SERVER_FIRST_RCVD (ready to send client-final)
        Specified by:
        isResponseReady in interface AuthScheme
        credentialsProvider - The credentials to be used for authentication
        context - HTTP context
        Returns:
        true if an authorization response can be generated and the authentication handshake can proceed, false otherwise.
        Throws:
        AuthenticationException - if authorization string cannot be generated due to an authentication failure
        Since:
        5.6
      • generateAuthResponse

        public java.lang.String generateAuthResponse​(org.apache.hc.core5.http.HttpHost host,
                                                     org.apache.hc.core5.http.HttpRequest request,
                                                     org.apache.hc.core5.http.protocol.HttpContext context)
                                              throws AuthenticationException
        Description copied from interface: AuthScheme
        Generates an authorization response based on the current state. Some authentication schemes may need to load user credentials required to generate an authorization response from a CredentialsProvider prior to this method call.
        Specified by:
        generateAuthResponse in interface AuthScheme
        request - The request being authenticated
        context - HTTP context
        Returns:
        authorization header
        Throws:
        AuthenticationException - if authorization string cannot be generated due to an authentication failure
        Since:
        5.6
        See Also:
        AuthScheme.isResponseReady(HttpHost, CredentialsProvider, HttpContext)
      • buildClientFirst

        private java.lang.String buildClientFirst()
      • zero

        private static void zero​(byte[] a)
      • zeroAndClearExpectedV

        private void zeroAndClearExpectedV()
      • toParamMap

        private static java.util.Map<java.lang.String,​java.lang.String> toParamMap​(java.util.List<org.apache.hc.core5.http.NameValuePair> pairs)
      • genNonce

        private java.lang.String genNonce()
      • escapeUser

        private static java.lang.String escapeUser​(java.lang.String user)
      • quoteParam

        private static java.lang.String quoteParam​(java.lang.String v)
      • hiPBKDF2

        private static byte[] hiPBKDF2​(char[] password,
                                       byte[] salt,
                                       int iterations,
                                       int dkLen)
                                throws java.security.GeneralSecurityException
        Throws:
        java.security.GeneralSecurityException
      • hmac

        private static byte[] hmac​(byte[] key,
                                   java.lang.String msg)
                            throws java.security.GeneralSecurityException
        Throws:
        java.security.GeneralSecurityException
      • sha256

        private static byte[] sha256​(byte[] in)
                              throws java.security.GeneralSecurityException
        Throws:
        java.security.GeneralSecurityException
      • xor

        private static byte[] xor​(byte[] a,
                                  byte[] b)
      • stringToB64

        private static java.lang.String stringToB64​(java.lang.String s)