Class DelegatingPasswordEncoder

  • All Implemented Interfaces:
    PasswordEncoder

    public class DelegatingPasswordEncoder
    extends java.lang.Object
    implements PasswordEncoder
    A password encoder that delegates to another PasswordEncoder based upon a prefixed identifier.

    Constructing an instance

    You can easily construct an instance using PasswordEncoderFactories. Alternatively, you may create your own custom instance. For example:
     String idForEncode = "bcrypt";
     Map<String,PasswordEncoder> encoders = new HashMap<>();
     encoders.put(idForEncode, new BCryptPasswordEncoder());
     encoders.put("noop", NoOpPasswordEncoder.getInstance());
     encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
     encoders.put("scrypt", new SCryptPasswordEncoder());
     encoders.put("sha256", new StandardPasswordEncoder());
    
     PasswordEncoder passwordEncoder = new DelegatingPasswordEncoder(idForEncode, encoders);
     

    Password Storage Format

    The general format for a password is:
     {id}encodedPassword
     
    Such that "id" is an identifier used to look up which PasswordEncoder should be used and "encodedPassword" is the original encoded password for the selected PasswordEncoder. The "id" must be at the beginning of the password, start with "{" and end with "}". If the "id" cannot be found, the "id" will be null. For example, the following might be a list of passwords encoded using different "id". All of the original passwords are "password".
     {bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG
     {noop}password
     {pbkdf2}5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc
     {scrypt}$e0801$8bWJaSu2IKSn9Z9kM+TPXfOc/9bdYSrN1oD9qfVThWEwdRTnO7re7Ei+fUZRJ68k9lTyuTeUp4of4g24hHnazw==$OAOec05+bXxvuu/1qZ6NUR+xQYvYv7BeL1QxwRpY5Pc=
     {sha256}97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0
     
    For the DelegatingPasswordEncoder that we constructed above:
    1. The first password would have a PasswordEncoder id of "bcrypt" and encodedPassword of "$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG". When matching it would delegate to BCryptPasswordEncoder
    2. The second password would have a PasswordEncoder id of "noop" and encodedPassword of "password". When matching it would delegate to NoOpPasswordEncoder
    3. The third password would have a PasswordEncoder id of "pbkdf2" and encodedPassword of "5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc". When matching it would delegate to Pbkdf2PasswordEncoder
    4. The fourth password would have a PasswordEncoder id of "scrypt" and encodedPassword of "$e0801$8bWJaSu2IKSn9Z9kM+TPXfOc/9bdYSrN1oD9qfVThWEwdRTnO7re7Ei+fUZRJ68k9lTyuTeUp4of4g24hHnazw==$OAOec05+bXxvuu/1qZ6NUR+xQYvYv7BeL1QxwRpY5Pc=" When matching it would delegate to SCryptPasswordEncoder
    5. The final password would have a PasswordEncoder id of "sha256" and encodedPassword of "97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0". When matching it would delegate to StandardPasswordEncoder

    Password Encoding

    The idForEncode passed into the constructor determines which PasswordEncoder will be used for encoding passwords. In the DelegatingPasswordEncoder we constructed above, that means that the result of encoding "password" would be delegated to BCryptPasswordEncoder and be prefixed with "{bcrypt}". The end result would look like:
     {bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG
     

    Password Matching

    Matching is done based upon the "id" and the mapping of the "id" to the PasswordEncoder provided in the constructor. Our example in "Password Storage Format" provides a working example of how this is done. By default the result of invoking matches(CharSequence, String) with a password with an "id" that is not mapped (including a null id) will result in an IllegalArgumentException. This behavior can be customized using setDefaultPasswordEncoderForMatches(PasswordEncoder).
    Since:
    5.0
    See Also:
    PasswordEncoderFactories
    • Constructor Summary

      Constructors 
      Constructor Description
      DelegatingPasswordEncoder​(java.lang.String idForEncode, java.util.Map<java.lang.String,​PasswordEncoder> idToPasswordEncoder)
      Creates a new instance
    • Method Summary

      All Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      java.lang.String encode​(java.lang.CharSequence rawPassword)
      Encode the raw password.
      boolean matches​(java.lang.CharSequence rawPassword, java.lang.String prefixEncodedPassword)
      Verify the encoded password obtained from storage matches the submitted raw password after it too is encoded.
      void setDefaultPasswordEncoderForMatches​(PasswordEncoder defaultPasswordEncoderForMatches)
      Sets the PasswordEncoder to delegate to for matches(CharSequence, String) if the id is not mapped to a PasswordEncoder.
      boolean upgradeEncoding​(java.lang.String prefixEncodedPassword)
      Returns true if the encoded password should be encoded again for better security, else false.
      • Methods inherited from class java.lang.Object

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

      • setDefaultPasswordEncoderForMatches

        public void setDefaultPasswordEncoderForMatches​(PasswordEncoder defaultPasswordEncoderForMatches)
        Sets the PasswordEncoder to delegate to for matches(CharSequence, String) if the id is not mapped to a PasswordEncoder.

        The encodedPassword provided will be the full password passed in including the {"id"} portion.* For example, if the password of "{notmapped}foobar" was used, the "id" would be "notmapped" and the encodedPassword passed into the PasswordEncoder would be "{notmapped}foobar".

        Parameters:
        defaultPasswordEncoderForMatches - the encoder to use. The default is to throw an IllegalArgumentException
      • encode

        public java.lang.String encode​(java.lang.CharSequence rawPassword)
        Description copied from interface: PasswordEncoder
        Encode the raw password. Generally, a good encoding algorithm applies a SHA-1 or greater hash combined with an 8-byte or greater randomly generated salt.
        Specified by:
        encode in interface PasswordEncoder
      • matches

        public boolean matches​(java.lang.CharSequence rawPassword,
                               java.lang.String prefixEncodedPassword)
        Description copied from interface: PasswordEncoder
        Verify the encoded password obtained from storage matches the submitted raw password after it too is encoded. Returns true if the passwords match, false if they do not. The stored password itself is never decoded.
        Specified by:
        matches in interface PasswordEncoder
        Parameters:
        rawPassword - the raw password to encode and match
        prefixEncodedPassword - the encoded password from storage to compare with
        Returns:
        true if the raw password, after encoding, matches the encoded password from storage
      • upgradeEncoding

        public boolean upgradeEncoding​(java.lang.String prefixEncodedPassword)
        Description copied from interface: PasswordEncoder
        Returns true if the encoded password should be encoded again for better security, else false. The default implementation always returns false.
        Specified by:
        upgradeEncoding in interface PasswordEncoder
        Parameters:
        prefixEncodedPassword - the encoded password to check
        Returns:
        true if the encoded password should be encoded again for better security, else false.