Forráskód Böngészése

SEC-1303: Added internal Hex and Base64 classes, and moved commons-codec dependency to test scope

Luke Taylor 15 éve
szülő
commit
69699431b1
21 módosított fájl, 832 hozzáadás és 127 törlés
  1. 1 0
      config/pom.xml
  2. 0 4
      core/pom.xml
  3. 5 6
      core/src/main/java/org/springframework/security/authentication/encoding/LdapShaPasswordEncoder.java
  4. 8 8
      core/src/main/java/org/springframework/security/authentication/encoding/Md4PasswordEncoder.java
  5. 6 6
      core/src/main/java/org/springframework/security/authentication/encoding/MessageDigestPasswordEncoder.java
  6. 649 0
      core/src/main/java/org/springframework/security/core/codec/Base64.java
  7. 37 0
      core/src/main/java/org/springframework/security/core/codec/Hex.java
  8. 25 25
      core/src/main/java/org/springframework/security/core/token/KeyBasedPersistenceTokenService.java
  9. 7 7
      core/src/main/java/org/springframework/security/core/token/Sha512DigestUtils.java
  10. 6 9
      core/src/main/java/org/springframework/security/remoting/httpinvoker/AuthenticationSimpleHttpInvokerRequestExecutor.java
  11. 5 5
      core/src/main/java/org/springframework/security/util/EncryptionUtils.java
  12. 0 5
      pom.xml
  13. 6 0
      web/pom.xml
  14. 8 3
      web/src/main/java/org/springframework/security/web/access/expression/WebSecurityExpressionRoot.java
  15. 8 8
      web/src/main/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServices.java
  16. 3 3
      web/src/main/java/org/springframework/security/web/authentication/rememberme/PersistentTokenBasedRememberMeServices.java
  17. 13 3
      web/src/main/java/org/springframework/security/web/authentication/rememberme/TokenBasedRememberMeServices.java
  18. 2 2
      web/src/main/java/org/springframework/security/web/authentication/www/BasicAuthenticationFilter.java
  19. 23 11
      web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthUtils.java
  20. 5 6
      web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthenticationEntryPoint.java
  21. 15 16
      web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthenticationFilter.java

+ 1 - 0
config/pom.xml

@@ -59,6 +59,7 @@
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-web</artifactId>
+            <optional>true</optional>
         </dependency>
         <dependency>
             <groupId>org.apache.directory.server</groupId>

+ 0 - 4
core/pom.xml

@@ -69,10 +69,6 @@
             <groupId>commons-logging</groupId>
             <artifactId>commons-logging</artifactId>
         </dependency>
-        <dependency>
-            <groupId>commons-codec</groupId>
-            <artifactId>commons-codec</artifactId>
-        </dependency>
         <dependency>
             <groupId>commons-collections</groupId>
             <artifactId>commons-collections</artifactId>

+ 5 - 6
core/src/main/java/org/springframework/security/authentication/encoding/LdapShaPasswordEncoder.java

@@ -16,13 +16,12 @@
 package org.springframework.security.authentication.encoding;
 
 
-import org.apache.commons.codec.binary.Base64;
-
-import org.springframework.util.Assert;
-
 import java.io.UnsupportedEncodingException;
 import java.security.MessageDigest;
 
+import org.springframework.security.core.codec.Base64;
+import org.springframework.util.Assert;
+
 
 /**
  * A version of {@link ShaPasswordEncoder} which supports Ldap SHA and SSHA (salted-SHA) encodings. The values are
@@ -103,13 +102,13 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
             prefix = forceLowerCasePrefix ? SSHA_PREFIX_LC : SSHA_PREFIX;
         }
 
-        return prefix + new String(Base64.encodeBase64(hash));
+        return prefix + new String(Base64.encode(hash));
     }
 
     private byte[] extractSalt(String encPass) {
         String encPassNoLabel = encPass.substring(6);
 
-        byte[] hashAndSalt = Base64.decodeBase64(encPassNoLabel.getBytes());
+        byte[] hashAndSalt = Base64.decode(encPassNoLabel.getBytes());
         int saltLength = hashAndSalt.length - SHA_LENGTH;
         byte[] salt = new byte[saltLength];
         System.arraycopy(hashAndSalt, SHA_LENGTH, salt, 0, saltLength);

+ 8 - 8
core/src/main/java/org/springframework/security/authentication/encoding/Md4PasswordEncoder.java

@@ -16,8 +16,8 @@ package org.springframework.security.authentication.encoding;
 
 import java.io.UnsupportedEncodingException;
 
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.codec.binary.Hex;
+import org.springframework.security.core.codec.Base64;
+import org.springframework.security.core.codec.Hex;
 
 /**
  * MD4 implementation of PasswordEncoder.
@@ -45,7 +45,7 @@ public class Md4PasswordEncoder extends BaseDigestPasswordEncoder {
      */
     public String encodePassword(String rawPass, Object salt) {
         String saltedPass = mergePasswordAndSalt(rawPass, salt, false);
-        
+
         byte[] passBytes;
 
         try {
@@ -53,16 +53,16 @@ public class Md4PasswordEncoder extends BaseDigestPasswordEncoder {
         } catch (UnsupportedEncodingException e) {
             throw new IllegalStateException("UTF-8 not supported!");
         }
-        
+
         Md4 md4 = new Md4();
         md4.update(passBytes, 0, passBytes.length);
-        
+
         byte[] resBuf = md4.digest();
 
         if (getEncodeHashAsBase64()) {
-            return new String(Base64.encodeBase64(resBuf));
+            return new String(Base64.encode(resBuf));
         } else {
-            return new String(Hex.encodeHex(resBuf));
+            return new String(Hex.encode(resBuf));
         }
     }
 
@@ -84,4 +84,4 @@ public class Md4PasswordEncoder extends BaseDigestPasswordEncoder {
     public String getAlgorithm() {
         return "MD4";
     }
-}
+}

+ 6 - 6
core/src/main/java/org/springframework/security/authentication/encoding/MessageDigestPasswordEncoder.java

@@ -1,12 +1,12 @@
 package org.springframework.security.authentication.encoding;
 
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.codec.binary.Hex;
-
 import java.io.UnsupportedEncodingException;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 
+import org.springframework.security.core.codec.Base64;
+import org.springframework.security.core.codec.Hex;
+
 /**
  * Base for digest password encoders.
  * <p>This class can be used stand-alone, or one of the subclasses can be used for compatiblity and convenience.
@@ -74,7 +74,7 @@ public class MessageDigestPasswordEncoder extends BaseDigestPasswordEncoder {
         MessageDigest messageDigest = getMessageDigest();
 
         byte[] digest;
-        
+
         try {
             digest = messageDigest.digest(saltedPass.getBytes("UTF-8"));
         } catch (UnsupportedEncodingException e) {
@@ -82,9 +82,9 @@ public class MessageDigestPasswordEncoder extends BaseDigestPasswordEncoder {
         }
 
         if (getEncodeHashAsBase64()) {
-            return new String(Base64.encodeBase64(digest));
+            return new String(Base64.encode(digest));
         } else {
-            return new String(Hex.encodeHex(digest));
+            return new String(Hex.encode(digest));
         }
     }
 

+ 649 - 0
core/src/main/java/org/springframework/security/core/codec/Base64.java

@@ -0,0 +1,649 @@
+package org.springframework.security.core.codec;
+
+
+/**
+ * Base64 encoder which is a reduced version of Robert Harder's public domain implementation.
+ * See <a href="http://iharder.net/base64">http://iharder.net/base64</a> for more information.
+ * <p>
+ * For internal use only.
+ *
+ * @author Luke Taylor
+ * @version $Id$
+ * @since 3.0
+ */
+public final class Base64 {
+
+    /** No options specified. Value is zero. */
+    public final static int NO_OPTIONS = 0;
+
+    /** Specify encoding in first bit. Value is one. */
+    public final static int ENCODE = 1;
+
+
+    /** Specify decoding in first bit. Value is zero. */
+    public final static int DECODE = 0;
+
+    /** Do break lines when encoding. Value is 8. */
+    public final static int DO_BREAK_LINES = 8;
+
+    /**
+     * Encode using Base64-like encoding that is URL- and Filename-safe as described
+     * in Section 4 of RFC3548:
+     * <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
+     * It is important to note that data encoded this way is <em>not</em> officially valid Base64,
+     * or at the very least should not be called Base64 without also specifying that is
+     * was encoded using the URL- and Filename-safe dialect.
+     */
+     public final static int URL_SAFE = 16;
+
+
+     /**
+      * Encode using the special "ordered" dialect of Base64 described here:
+      * <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.
+      */
+     public final static int ORDERED = 32;
+
+
+    /** Maximum line length (76) of Base64 output. */
+    private final static int MAX_LINE_LENGTH = 76;
+
+
+    /** The equals sign (=) as a byte. */
+    private final static byte EQUALS_SIGN = (byte)'=';
+
+
+    /** The new line character (\n) as a byte. */
+    private final static byte NEW_LINE = (byte)'\n';
+
+    private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding
+    private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding
+
+
+/* ********  S T A N D A R D   B A S E 6 4   A L P H A B E T  ******** */
+
+    /** The 64 valid Base64 values. */
+    /* Host platform me be something funny like EBCDIC, so we hardcode these values. */
+    private final static byte[] _STANDARD_ALPHABET = {
+        (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
+        (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
+        (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
+        (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
+        (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
+        (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
+        (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
+        (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z',
+        (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5',
+        (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/'
+    };
+
+
+    /**
+     * Translates a Base64 value to either its 6-bit reconstruction value
+     * or a negative number indicating some other meaning.
+     **/
+    private final static byte[] _STANDARD_DECODABET = {
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,                 // Decimal  0 -  8
+        -5,-5,                                      // Whitespace: Tab and Linefeed
+        -9,-9,                                      // Decimal 11 - 12
+        -5,                                         // Whitespace: Carriage Return
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 14 - 26
+        -9,-9,-9,-9,-9,                             // Decimal 27 - 31
+        -5,                                         // Whitespace: Space
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,              // Decimal 33 - 42
+        62,                                         // Plus sign at decimal 43
+        -9,-9,-9,                                   // Decimal 44 - 46
+        63,                                         // Slash at decimal 47
+        52,53,54,55,56,57,58,59,60,61,              // Numbers zero through nine
+        -9,-9,-9,                                   // Decimal 58 - 60
+        -1,                                         // Equals sign at decimal 61
+        -9,-9,-9,                                      // Decimal 62 - 64
+        0,1,2,3,4,5,6,7,8,9,10,11,12,13,            // Letters 'A' through 'N'
+        14,15,16,17,18,19,20,21,22,23,24,25,        // Letters 'O' through 'Z'
+        -9,-9,-9,-9,-9,-9,                          // Decimal 91 - 96
+        26,27,28,29,30,31,32,33,34,35,36,37,38,     // Letters 'a' through 'm'
+        39,40,41,42,43,44,45,46,47,48,49,50,51,     // Letters 'n' through 'z'
+        -9,-9,-9,-9                                 // Decimal 123 - 126
+        /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 127 - 139
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 140 - 152
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 153 - 165
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 166 - 178
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 179 - 191
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 192 - 204
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 205 - 217
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 218 - 230
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 231 - 243
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9         // Decimal 244 - 255 */
+    };
+
+
+/* ********  U R L   S A F E   B A S E 6 4   A L P H A B E T  ******** */
+
+    /**
+     * Used in the URL- and Filename-safe dialect described in Section 4 of RFC3548:
+     * <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
+     * Notice that the last two bytes become "hyphen" and "underscore" instead of "plus" and "slash."
+     */
+    private final static byte[] _URL_SAFE_ALPHABET = {
+      (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
+      (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
+      (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
+      (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
+      (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
+      (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
+      (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
+      (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z',
+      (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5',
+      (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'-', (byte)'_'
+    };
+
+    /**
+     * Used in decoding URL- and Filename-safe dialects of Base64.
+     */
+    private final static byte[] _URL_SAFE_DECODABET = {
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,                 // Decimal  0 -  8
+      -5,-5,                                      // Whitespace: Tab and Linefeed
+      -9,-9,                                      // Decimal 11 - 12
+      -5,                                         // Whitespace: Carriage Return
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 14 - 26
+      -9,-9,-9,-9,-9,                             // Decimal 27 - 31
+      -5,                                         // Whitespace: Space
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,              // Decimal 33 - 42
+      -9,                                         // Plus sign at decimal 43
+      -9,                                         // Decimal 44
+      62,                                         // Minus sign at decimal 45
+      -9,                                         // Decimal 46
+      -9,                                         // Slash at decimal 47
+      52,53,54,55,56,57,58,59,60,61,              // Numbers zero through nine
+      -9,-9,-9,                                   // Decimal 58 - 60
+      -1,                                         // Equals sign at decimal 61
+      -9,-9,-9,                                   // Decimal 62 - 64
+      0,1,2,3,4,5,6,7,8,9,10,11,12,13,            // Letters 'A' through 'N'
+      14,15,16,17,18,19,20,21,22,23,24,25,        // Letters 'O' through 'Z'
+      -9,-9,-9,-9,                                // Decimal 91 - 94
+      63,                                         // Underscore at decimal 95
+      -9,                                         // Decimal 96
+      26,27,28,29,30,31,32,33,34,35,36,37,38,     // Letters 'a' through 'm'
+      39,40,41,42,43,44,45,46,47,48,49,50,51,     // Letters 'n' through 'z'
+      -9,-9,-9,-9                                 // Decimal 123 - 126
+      /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 127 - 139
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 140 - 152
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 153 - 165
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 166 - 178
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 179 - 191
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 192 - 204
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 205 - 217
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 218 - 230
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 231 - 243
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9         // Decimal 244 - 255 */
+    };
+
+
+
+/* ********  O R D E R E D   B A S E 6 4   A L P H A B E T  ******** */
+
+    /**
+     * I don't get the point of this technique, but someone requested it,
+     * and it is described here:
+     * <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.
+     */
+    private final static byte[] _ORDERED_ALPHABET = {
+      (byte)'-',
+      (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4',
+      (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9',
+      (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
+      (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
+      (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
+      (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
+      (byte)'_',
+      (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
+      (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
+      (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
+      (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z'
+    };
+
+    /**
+     * Used in decoding the "ordered" dialect of Base64.
+     */
+    private final static byte[] _ORDERED_DECODABET = {
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,                 // Decimal  0 -  8
+      -5,-5,                                      // Whitespace: Tab and Linefeed
+      -9,-9,                                      // Decimal 11 - 12
+      -5,                                         // Whitespace: Carriage Return
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 14 - 26
+      -9,-9,-9,-9,-9,                             // Decimal 27 - 31
+      -5,                                         // Whitespace: Space
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,              // Decimal 33 - 42
+      -9,                                         // Plus sign at decimal 43
+      -9,                                         // Decimal 44
+      0,                                          // Minus sign at decimal 45
+      -9,                                         // Decimal 46
+      -9,                                         // Slash at decimal 47
+      1,2,3,4,5,6,7,8,9,10,                       // Numbers zero through nine
+      -9,-9,-9,                                   // Decimal 58 - 60
+      -1,                                         // Equals sign at decimal 61
+      -9,-9,-9,                                   // Decimal 62 - 64
+      11,12,13,14,15,16,17,18,19,20,21,22,23,     // Letters 'A' through 'M'
+      24,25,26,27,28,29,30,31,32,33,34,35,36,     // Letters 'N' through 'Z'
+      -9,-9,-9,-9,                                // Decimal 91 - 94
+      37,                                         // Underscore at decimal 95
+      -9,                                         // Decimal 96
+      38,39,40,41,42,43,44,45,46,47,48,49,50,     // Letters 'a' through 'm'
+      51,52,53,54,55,56,57,58,59,60,61,62,63,     // Letters 'n' through 'z'
+      -9,-9,-9,-9                                 // Decimal 123 - 126
+      /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 127 - 139
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 140 - 152
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 153 - 165
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 166 - 178
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 179 - 191
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 192 - 204
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 205 - 217
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 218 - 230
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 231 - 243
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9         // Decimal 244 - 255 */
+    };
+
+
+    public static byte[] decode(byte[] bytes) {
+        return decode(bytes, 0, bytes.length, NO_OPTIONS);
+    }
+
+    public static byte[] encode(byte[] bytes) {
+        return encodeBytesToBytes(bytes, 0, bytes.length, NO_OPTIONS);
+    }
+
+    public static boolean isBase64(byte[] bytes) {
+        try {
+            decode(bytes);
+        } catch (InvalidBase64CharacterException e) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Returns one of the _SOMETHING_ALPHABET byte arrays depending on
+     * the options specified.
+     * It's possible, though silly, to specify ORDERED <b>and</b> URLSAFE
+     * in which case one of them will be picked, though there is
+     * no guarantee as to which one will be picked.
+     */
+    private final static byte[] getAlphabet( int options ) {
+        if ((options & URL_SAFE) == URL_SAFE) {
+            return _URL_SAFE_ALPHABET;
+        } else if ((options & ORDERED) == ORDERED) {
+            return _ORDERED_ALPHABET;
+        } else {
+            return _STANDARD_ALPHABET;
+        }
+    }
+
+    /**
+     * Returns one of the _SOMETHING_DECODABET byte arrays depending on
+     * the options specified.
+     * It's possible, though silly, to specify ORDERED and URL_SAFE
+     * in which case one of them will be picked, though there is
+     * no guarantee as to which one will be picked.
+     */
+    private final static byte[] getDecodabet( int options ) {
+        if( (options & URL_SAFE) == URL_SAFE) {
+            return _URL_SAFE_DECODABET;
+        } else if ((options & ORDERED) == ORDERED) {
+            return _ORDERED_DECODABET;
+        } else {
+            return _STANDARD_DECODABET;
+        }
+    }
+
+
+/* ********  E N C O D I N G   M E T H O D S  ******** */
+
+    /**
+     * <p>Encodes up to three bytes of the array <var>source</var>
+     * and writes the resulting four Base64 bytes to <var>destination</var>.
+     * The source and destination arrays can be manipulated
+     * anywhere along their length by specifying
+     * <var>srcOffset</var> and <var>destOffset</var>.
+     * This method does not check to make sure your arrays
+     * are large enough to accomodate <var>srcOffset</var> + 3 for
+     * the <var>source</var> array or <var>destOffset</var> + 4 for
+     * the <var>destination</var> array.
+     * The actual number of significant bytes in your array is
+     * given by <var>numSigBytes</var>.</p>
+     * <p>This is the lowest level of the encoding methods with
+     * all possible parameters.</p>
+     *
+     * @param source the array to convert
+     * @param srcOffset the index where conversion begins
+     * @param numSigBytes the number of significant bytes in your array
+     * @param destination the array to hold the conversion
+     * @param destOffset the index where output will be put
+     * @return the <var>destination</var> array
+     * @since 1.3
+     */
+    private static byte[] encode3to4(
+    byte[] source, int srcOffset, int numSigBytes,
+    byte[] destination, int destOffset, int options ) {
+
+    byte[] ALPHABET = getAlphabet( options );
+
+        //           1         2         3
+        // 01234567890123456789012345678901 Bit position
+        // --------000000001111111122222222 Array position from threeBytes
+        // --------|    ||    ||    ||    | Six bit groups to index ALPHABET
+        //          >>18  >>12  >> 6  >> 0  Right shift necessary
+        //                0x3f  0x3f  0x3f  Additional AND
+
+        // Create buffer with zero-padding if there are only one or two
+        // significant bytes passed in the array.
+        // We have to shift left 24 in order to flush out the 1's that appear
+        // when Java treats a value as negative that is cast from a byte to an int.
+        int inBuff =   ( numSigBytes > 0 ? ((source[ srcOffset     ] << 24) >>>  8) : 0 )
+                     | ( numSigBytes > 1 ? ((source[ srcOffset + 1 ] << 24) >>> 16) : 0 )
+                     | ( numSigBytes > 2 ? ((source[ srcOffset + 2 ] << 24) >>> 24) : 0 );
+
+        switch( numSigBytes )
+        {
+            case 3:
+                destination[ destOffset     ] = ALPHABET[ (inBuff >>> 18)        ];
+                destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
+                destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>>  6) & 0x3f ];
+                destination[ destOffset + 3 ] = ALPHABET[ (inBuff       ) & 0x3f ];
+                return destination;
+
+            case 2:
+                destination[ destOffset     ] = ALPHABET[ (inBuff >>> 18)        ];
+                destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
+                destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>>  6) & 0x3f ];
+                destination[ destOffset + 3 ] = EQUALS_SIGN;
+                return destination;
+
+            case 1:
+                destination[ destOffset     ] = ALPHABET[ (inBuff >>> 18)        ];
+                destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
+                destination[ destOffset + 2 ] = EQUALS_SIGN;
+                destination[ destOffset + 3 ] = EQUALS_SIGN;
+                return destination;
+
+            default:
+                return destination;
+        }
+    }
+
+
+    /**
+     * Similar to {@link #encodeBytes(byte[], int, int, int)} but returns
+     * a byte array instead of instantiating a String. This is more efficient
+     * if you're working with I/O streams and have large data sets to encode.
+     *
+     *
+     * @param source The data to convert
+     * @param off Offset in array where conversion should begin
+     * @param len Length of data to convert
+     * @param options Specified options
+     * @return The Base64-encoded data as a String
+     * @see Base64#DO_BREAK_LINES
+     * @throws java.io.IOException if there is an error
+     * @throws NullPointerException if source array is null
+     * @throws IllegalArgumentException if source array, offset, or length are invalid
+     * @since 2.3.1
+     */
+    private static byte[] encodeBytesToBytes( byte[] source, int off, int len, int options ) {
+
+        if( source == null ){
+            throw new NullPointerException( "Cannot serialize a null array." );
+        }   // end if: null
+
+        if( off < 0 ){
+            throw new IllegalArgumentException( "Cannot have negative offset: " + off );
+        }   // end if: off < 0
+
+        if( len < 0 ){
+            throw new IllegalArgumentException( "Cannot have length offset: " + len );
+        }   // end if: len < 0
+
+        if( off + len > source.length  ){
+            throw new IllegalArgumentException(
+            String.format( "Cannot have offset of %d and length of %d with array of length %d", off,len,source.length));
+        }   // end if: off < 0
+
+        boolean breakLines = (options & DO_BREAK_LINES) > 0;
+
+        //int    len43   = len * 4 / 3;
+        //byte[] outBuff = new byte[   ( len43 )                      // Main 4:3
+        //                           + ( (len % 3) > 0 ? 4 : 0 )      // Account for padding
+        //                           + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines
+        // Try to determine more precisely how big the array needs to be.
+        // If we get it right, we don't have to do an array copy, and
+        // we save a bunch of memory.
+        int encLen = ( len / 3 ) * 4 + ( len % 3 > 0 ? 4 : 0 ); // Bytes needed for actual encoding
+        if( breakLines ){
+            encLen += encLen / MAX_LINE_LENGTH; // Plus extra newline characters
+        }
+        byte[] outBuff = new byte[ encLen ];
+
+
+        int d = 0;
+        int e = 0;
+        int len2 = len - 2;
+        int lineLength = 0;
+        for( ; d < len2; d+=3, e+=4 ) {
+            encode3to4( source, d+off, 3, outBuff, e, options );
+
+            lineLength += 4;
+            if( breakLines && lineLength >= MAX_LINE_LENGTH )
+            {
+                outBuff[e+4] = NEW_LINE;
+                e++;
+                lineLength = 0;
+            }   // end if: end of line
+        }   // en dfor: each piece of array
+
+        if( d < len ) {
+            encode3to4( source, d+off, len - d, outBuff, e, options );
+            e += 4;
+        }   // end if: some padding needed
+
+
+        // Only resize array if we didn't guess it right.
+        if( e < outBuff.length - 1 ){
+            byte[] finalOut = new byte[e];
+            System.arraycopy(outBuff,0, finalOut,0,e);
+            //System.err.println("Having to resize array from " + outBuff.length + " to " + e );
+            return finalOut;
+        } else {
+            //System.err.println("No need to resize array.");
+            return outBuff;
+        }
+    }
+
+
+/* ********  D E C O D I N G   M E T H O D S  ******** */
+
+
+    /**
+     * Decodes four bytes from array <var>source</var>
+     * and writes the resulting bytes (up to three of them)
+     * to <var>destination</var>.
+     * The source and destination arrays can be manipulated
+     * anywhere along their length by specifying
+     * <var>srcOffset</var> and <var>destOffset</var>.
+     * This method does not check to make sure your arrays
+     * are large enough to accomodate <var>srcOffset</var> + 4 for
+     * the <var>source</var> array or <var>destOffset</var> + 3 for
+     * the <var>destination</var> array.
+     * This method returns the actual number of bytes that
+     * were converted from the Base64 encoding.
+     * <p>This is the lowest level of the decoding methods with
+     * all possible parameters.</p>
+     *
+     *
+     * @param source the array to convert
+     * @param srcOffset the index where conversion begins
+     * @param destination the array to hold the conversion
+     * @param destOffset the index where output will be put
+     * @param options alphabet type is pulled from this (standard, url-safe, ordered)
+     * @return the number of decoded bytes converted
+     * @throws NullPointerException if source or destination arrays are null
+     * @throws IllegalArgumentException if srcOffset or destOffset are invalid
+     *         or there is not enough room in the array.
+     * @since 1.3
+     */
+    private static int decode4to3(
+    byte[] source, int srcOffset,
+    byte[] destination, int destOffset, int options ) {
+
+        // Lots of error checking and exception throwing
+        if( source == null ){
+            throw new NullPointerException( "Source array was null." );
+        }   // end if
+        if( destination == null ){
+            throw new NullPointerException( "Destination array was null." );
+        }   // end if
+        if( srcOffset < 0 || srcOffset + 3 >= source.length ){
+            throw new IllegalArgumentException( String.format(
+            "Source array with length %d cannot have offset of %d and still process four bytes.", source.length, srcOffset ) );
+        }   // end if
+        if( destOffset < 0 || destOffset +2 >= destination.length ){
+            throw new IllegalArgumentException( String.format(
+            "Destination array with length %d cannot have offset of %d and still store three bytes.", destination.length, destOffset ) );
+        }   // end if
+
+
+        byte[] DECODABET = getDecodabet( options );
+
+        // Example: Dk==
+        if( source[ srcOffset + 2] == EQUALS_SIGN ) {
+            // Two ways to do the same thing. Don't know which way I like best.
+          //int outBuff =   ( ( DECODABET[ source[ srcOffset    ] ] << 24 ) >>>  6 )
+          //              | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 );
+            int outBuff =   ( ( DECODABET[ source[ srcOffset    ] ] & 0xFF ) << 18 )
+                          | ( ( DECODABET[ source[ srcOffset + 1] ] & 0xFF ) << 12 );
+
+            destination[ destOffset ] = (byte)( outBuff >>> 16 );
+            return 1;
+        }
+
+        // Example: DkL=
+        else if( source[ srcOffset + 3 ] == EQUALS_SIGN ) {
+            // Two ways to do the same thing. Don't know which way I like best.
+          //int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] << 24 ) >>>  6 )
+          //              | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
+          //              | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 );
+            int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] & 0xFF ) << 18 )
+                          | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )
+                          | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) <<  6 );
+
+            destination[ destOffset     ] = (byte)( outBuff >>> 16 );
+            destination[ destOffset + 1 ] = (byte)( outBuff >>>  8 );
+            return 2;
+        }
+
+        // Example: DkLE
+        else {
+            // Two ways to do the same thing. Don't know which way I like best.
+          //int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] << 24 ) >>>  6 )
+          //              | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
+          //              | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 )
+          //              | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 );
+            int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] & 0xFF ) << 18 )
+                          | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )
+                          | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) <<  6)
+                          | ( ( DECODABET[ source[ srcOffset + 3 ] ] & 0xFF )      );
+
+
+            destination[ destOffset     ] = (byte)( outBuff >> 16 );
+            destination[ destOffset + 1 ] = (byte)( outBuff >>  8 );
+            destination[ destOffset + 2 ] = (byte)( outBuff       );
+
+            return 3;
+        }
+    }
+
+    /**
+     * Low-level access to decoding ASCII characters in
+     * the form of a byte array. <strong>Ignores GUNZIP option, if
+     * it's set.</strong> This is not generally a recommended method,
+     * although it is used internally as part of the decoding process.
+     * Special case: if len = 0, an empty array is returned. Still,
+     * if you need more speed and reduced memory footprint (and aren't
+     * gzipping), consider this method.
+     *
+     * @param source The Base64 encoded data
+     * @param off    The offset of where to begin decoding
+     * @param len    The length of characters to decode
+     * @param options Can specify options such as alphabet type to use
+     * @return decoded data
+     * @throws IllegalArgumentException If bogus characters exist in source data
+     */
+    private static byte[] decode( byte[] source, int off, int len, int options ) {
+
+        // Lots of error checking and exception throwing
+        if( source == null ){
+            throw new NullPointerException( "Cannot decode null source array." );
+        }   // end if
+        if( off < 0 || off + len > source.length ){
+            throw new IllegalArgumentException( String.format(
+            "Source array with length %d cannot have offset of %d and process %d bytes.", source.length, off, len ) );
+        }   // end if
+
+        if( len == 0 ){
+            return new byte[0];
+        }else if( len < 4 ){
+            throw new IllegalArgumentException(
+            "Base64-encoded string must have at least four characters, but length specified was " + len );
+        }   // end if
+
+        byte[] DECODABET = getDecodabet( options );
+
+        int    len34   = len * 3 / 4;       // Estimate on array size
+        byte[] outBuff = new byte[ len34 ]; // Upper limit on size of output
+        int    outBuffPosn = 0;             // Keep track of where we're writing
+
+        byte[] b4        = new byte[4];     // Four byte buffer from source, eliminating white space
+        int    b4Posn    = 0;               // Keep track of four byte input buffer
+        int    i         = 0;               // Source array counter
+        byte   sbiCrop   = 0;               // Low seven bits (ASCII) of input
+        byte   sbiDecode = 0;               // Special value from DECODABET
+
+        for( i = off; i < off+len; i++ ) {  // Loop through source
+
+            sbiCrop = (byte)(source[i] & 0x7f); // Only the low seven bits
+            sbiDecode = DECODABET[ sbiCrop ];   // Special value
+
+            // White space, Equals sign, or legit Base64 character
+            // Note the values such as -5 and -9 in the
+            // DECODABETs at the top of the file.
+            if( sbiDecode >= WHITE_SPACE_ENC )  {
+                if( sbiDecode >= EQUALS_SIGN_ENC ) {
+                    b4[ b4Posn++ ] = sbiCrop;           // Save non-whitespace
+                    if( b4Posn > 3 ) {                  // Time to decode?
+                        outBuffPosn += decode4to3( b4, 0, outBuff, outBuffPosn, options );
+                        b4Posn = 0;
+
+                        // If that was the equals sign, break out of 'for' loop
+                        if( sbiCrop == EQUALS_SIGN ) {
+                            break;
+                        }
+                    }
+                }
+            }
+            else {
+                // There's a bad input character in the Base64 stream.
+                throw new InvalidBase64CharacterException( String.format(
+                "Bad Base64 input character '%c' in array position %d", source[i], i ) );
+            }
+        }
+
+        byte[] out = new byte[ outBuffPosn ];
+        System.arraycopy( outBuff, 0, out, 0, outBuffPosn );
+        return out;
+    }
+}
+
+
+class InvalidBase64CharacterException extends IllegalArgumentException {
+
+    InvalidBase64CharacterException(String message) {
+        super(message);
+    }
+}

+ 37 - 0
core/src/main/java/org/springframework/security/core/codec/Hex.java

@@ -0,0 +1,37 @@
+package org.springframework.security.core.codec;
+
+/**
+ * Hex data encoder. Converts byte arrays (such as those obtained from message digests)
+ * into hexadecimal string representation.
+ * <p>
+ * For internal use only.
+ *
+ * @author Luke Taylor
+ * @version $Id$
+ * @since 3.0
+ */
+public final class Hex {
+
+    private static final char[] HEX = {
+        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+    };
+
+    public static char[] encode(byte[] bytes) {
+        final int nBytes = bytes.length;
+        char[] result = new char[2*nBytes];
+
+        int j = 0;
+        for (int i=0; i < nBytes; i++) {
+            // Char for top 4 bits
+            result[j++] = HEX[(0xF0 & bytes[i]) >>> 4 ];
+            // Bottom 4
+            result[j++] = HEX[(0x0F & bytes[i])];
+        }
+
+        return result;
+    }
+
+//    public static byte[] decode(char[] hex) {
+//
+//    }
+}

+ 25 - 25
core/src/main/java/org/springframework/security/core/token/KeyBasedPersistenceTokenService.java

@@ -4,31 +4,31 @@ import java.io.UnsupportedEncodingException;
 import java.security.SecureRandom;
 import java.util.Date;
 
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.codec.binary.Hex;
 import org.springframework.beans.factory.InitializingBean;
+import org.springframework.security.core.codec.Base64;
+import org.springframework.security.core.codec.Hex;
 import org.springframework.util.Assert;
 import org.springframework.util.StringUtils;
 
 /**
  * Basic implementation of {@link TokenService} that is compatible with clusters and across machine restarts,
  * without requiring database persistence.
- * 
+ *
  * <p>
  * Keys are produced in the format:
  * </p>
- * 
+ *
  * <p>
  * Base64(creationTime + ":" + hex(pseudoRandomNumber) + ":" + extendedInformation + ":" +
  * Sha512Hex(creationTime + ":" + hex(pseudoRandomNumber) + ":" + extendedInformation + ":" + serverSecret) )
  * </p>
- * 
+ *
  * <p>
  * In the above, <code>creationTime</code>, <code>tokenKey</code> and <code>extendedInformation</code>
  * are equal to that stored in {@link Token}. The <code>Sha512Hex</code> includes the same payload,
  * plus a <code>serverSecret</code>.
  * </p>
- * 
+ *
  * <p>
  * The <code>serverSecret</code> varies every millisecond. It relies on two static server-side secrets. The first
  * is a password, and the second is a server integer. Both of these must remain the same for any issued keys
@@ -39,7 +39,7 @@ import org.springframework.util.StringUtils;
  * to the computed hash). Recall that framework features depending on token services should reject tokens
  * that are relatively old in any event.
  * </p>
- * 
+ *
  * <p>
  * A further consideration of this class is the requirement for cryptographically strong pseudo-random numbers.
  * To this end, the use of {@link SecureRandomFactoryBean} is recommended to inject the property.
@@ -48,7 +48,7 @@ import org.springframework.util.StringUtils;
  * <p>
  * This implementation uses UTF-8 encoding internally for string manipulation.
  * </p>
- * 
+ *
  * @author Ben Alex
  *
  */
@@ -57,7 +57,7 @@ public class KeyBasedPersistenceTokenService implements TokenService, Initializi
     private String serverSecret;
     private Integer serverInteger;
     private SecureRandom secureRandom;
-    
+
     public Token allocateToken(String extendedInformation) {
         Assert.notNull(extendedInformation, "Must provided non-null extendedInformation (but it can be empty)");
         long creationTime = new Date().getTime();
@@ -68,8 +68,8 @@ public class KeyBasedPersistenceTokenService implements TokenService, Initializi
         // Compute key
         String sha512Hex = Sha512DigestUtils.shaHex(content + ":" + serverSecret);
         String keyPayload = content + ":" + sha512Hex;
-        String key = convertToString(Base64.encodeBase64(convertToBytes(keyPayload)));
-        
+        String key = convertToString(Base64.encode(convertToBytes(keyPayload)));
+
         return new DefaultToken(key, creationTime, extendedInformation);
     }
 
@@ -77,19 +77,19 @@ public class KeyBasedPersistenceTokenService implements TokenService, Initializi
         if (key == null || "".equals(key)) {
             return null;
         }
-        String[] tokens = StringUtils.delimitedListToStringArray(convertToString(Base64.decodeBase64(convertToBytes(key))), ":");
+        String[] tokens = StringUtils.delimitedListToStringArray(convertToString(Base64.decode(convertToBytes(key))), ":");
         Assert.isTrue(tokens.length >= 4, "Expected 4 or more tokens but found " + tokens.length);
-        
+
         long creationTime;
         try {
             creationTime = Long.decode(tokens[0]).longValue();
         } catch (NumberFormatException nfe) {
             throw new IllegalArgumentException("Expected number but found " + tokens[0]);
         }
-        
+
         String serverSecret = computeServerSecretApplicableAt(creationTime);
         String pseudoRandomNumber = tokens[1];
-        
+
         // Permit extendedInfo to itself contain ":" characters
         StringBuffer extendedInfo = new StringBuffer();
         for (int i = 2; i < tokens.length-1; i++) {
@@ -98,17 +98,17 @@ public class KeyBasedPersistenceTokenService implements TokenService, Initializi
             }
             extendedInfo.append(tokens[i]);
         }
-        
+
         String sha1Hex = tokens[tokens.length-1];
-        
+
         // Verification
         String content = new Long(creationTime).toString() + ":" + pseudoRandomNumber + ":" + extendedInfo.toString();
         String expectedSha512Hex = Sha512DigestUtils.shaHex(content + ":" + serverSecret);
         Assert.isTrue(expectedSha512Hex.equals(sha1Hex), "Key verification failure");
-        
+
         return new DefaultToken(key, creationTime, extendedInfo.toString());
     }
-    
+
     private byte[] convertToBytes(String input) {
         try {
             return input.getBytes("UTF-8");
@@ -116,7 +116,7 @@ public class KeyBasedPersistenceTokenService implements TokenService, Initializi
             throw new RuntimeException(e);
         }
     }
-    
+
     private String convertToString(byte[] bytes) {
         try {
             return new String(bytes, "UTF-8");
@@ -124,16 +124,16 @@ public class KeyBasedPersistenceTokenService implements TokenService, Initializi
             throw new RuntimeException(e);
         }
     }
-    
+
     /**
      * @return a pseduo random number (hex encoded)
      */
     private String generatePseudoRandomNumber() {
         byte[] randomizedBits = new byte[pseudoRandomNumberBits];
         secureRandom.nextBytes(randomizedBits);
-        return new String(Hex.encodeHex(randomizedBits));
+        return new String(Hex.encode(randomizedBits));
     }
-    
+
     private String computeServerSecretApplicableAt(long time) {
         return serverSecret + ":" + new Long(time % serverInteger.intValue()).intValue();
     }
@@ -144,11 +144,11 @@ public class KeyBasedPersistenceTokenService implements TokenService, Initializi
     public void setServerSecret(String serverSecret) {
         this.serverSecret = serverSecret;
     }
-    
+
     public void setSecureRandom(SecureRandom secureRandom) {
         this.secureRandom = secureRandom;
     }
-    
+
     /**
      * @param pseudoRandomNumberBits changes the number of bits issued (must be >= 0; defaults to 256)
      */

+ 7 - 7
core/src/main/java/org/springframework/security/core/token/Sha512DigestUtils.java

@@ -3,15 +3,15 @@ package org.springframework.security.core.token;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 
-import org.apache.commons.codec.binary.Hex;
+import org.springframework.security.core.codec.Hex;
 
 /**
  * Provides SHA512 digest methods.
- * 
+ *
  * <p>
  * Based on Commons Codec, which does not presently provide SHA512 support.
  * </p>
- * 
+ *
  * @author Ben Alex
  * @since 2.0.1
  *
@@ -43,7 +43,7 @@ public abstract class Sha512DigestUtils  {
     }
 
     /**
-     * Calculates the SHA digest and returns the value as a 
+     * Calculates the SHA digest and returns the value as a
      * <code>byte[]</code>.
      *
      * @param data Data to digest
@@ -54,7 +54,7 @@ public abstract class Sha512DigestUtils  {
     }
 
     /**
-     * Calculates the SHA digest and returns the value as a 
+     * Calculates the SHA digest and returns the value as a
      * <code>byte[]</code>.
      *
      * @param data Data to digest
@@ -71,7 +71,7 @@ public abstract class Sha512DigestUtils  {
      * @return SHA digest as a hex string
      */
     public static String shaHex(byte[] data) {
-        return new String(Hex.encodeHex(sha(data)));
+        return new String(Hex.encode(sha(data)));
     }
 
     /**
@@ -81,7 +81,7 @@ public abstract class Sha512DigestUtils  {
      * @return SHA digest as a hex string
      */
     public static String shaHex(String data) {
-        return new String(Hex.encodeHex(sha(data)));
+        return new String(Hex.encode(sha(data)));
     }
 
 }

+ 6 - 9
core/src/main/java/org/springframework/security/remoting/httpinvoker/AuthenticationSimpleHttpInvokerRequestExecutor.java

@@ -15,18 +15,15 @@
 
 package org.springframework.security.remoting.httpinvoker;
 
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContextHolder;
+import java.io.IOException;
+import java.net.HttpURLConnection;
 
-import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-
 import org.springframework.remoting.httpinvoker.SimpleHttpInvokerRequestExecutor;
-
-import java.io.IOException;
-
-import java.net.HttpURLConnection;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.codec.Base64;
+import org.springframework.security.core.context.SecurityContextHolder;
 
 
 /**
@@ -71,7 +68,7 @@ public class AuthenticationSimpleHttpInvokerRequestExecutor extends SimpleHttpIn
 
         if ((auth != null) && (auth.getName() != null) && (auth.getCredentials() != null)) {
             String base64 = auth.getName() + ":" + auth.getCredentials().toString();
-            con.setRequestProperty("Authorization", "Basic " + new String(Base64.encodeBase64(base64.getBytes())));
+            con.setRequestProperty("Authorization", "Basic " + new String(Base64.encode(base64.getBytes())));
 
             if (logger.isDebugEnabled()) {
                 logger.debug("HttpInvocation now presenting via BASIC authentication SecurityContextHolder-derived: "

+ 5 - 5
core/src/main/java/org/springframework/security/util/EncryptionUtils.java

@@ -23,8 +23,8 @@ import javax.crypto.SecretKey;
 import javax.crypto.SecretKeyFactory;
 import javax.crypto.spec.DESedeKeySpec;
 
-import org.apache.commons.codec.binary.Base64;
 import org.springframework.core.NestedRuntimeException;
+import org.springframework.security.core.codec.Base64;
 import org.springframework.util.Assert;
 
 /**
@@ -102,7 +102,7 @@ public final class EncryptionUtils {
     public static String encrypt(String key, String inputString) throws EncryptionException {
         isValidKey(key);
         final byte[] cipherText = cipher(key, stringToByteArray(inputString), Cipher.ENCRYPT_MODE);
-        return byteArrayToString(Base64.encodeBase64(cipherText));
+        return byteArrayToString(Base64.encode(cipherText));
     }
 
     /**
@@ -115,7 +115,7 @@ public final class EncryptionUtils {
      */
     public static byte[] encrypt(String key, byte[] inputBytes) throws EncryptionException {
         isValidKey(key);
-        return Base64.encodeBase64(cipher(key, inputBytes, Cipher.ENCRYPT_MODE));
+        return Base64.encode(cipher(key, inputBytes, Cipher.ENCRYPT_MODE));
     }
 
     /**
@@ -128,7 +128,7 @@ public final class EncryptionUtils {
      */
     public static String decrypt(String key, String inputString) throws EncryptionException {
         Assert.hasText(key, "A key is required to attempt decryption");
-        final byte[] cipherText = cipher(key, Base64.decodeBase64(stringToByteArray(inputString)), Cipher.DECRYPT_MODE);
+        final byte[] cipherText = cipher(key, Base64.decode(stringToByteArray(inputString)), Cipher.DECRYPT_MODE);
         return byteArrayToString(cipherText);
     }
 
@@ -142,7 +142,7 @@ public final class EncryptionUtils {
      */
     public static byte[] decrypt(String key, byte[] inputBytes) throws EncryptionException {
         Assert.hasText(key, "A key is required to attempt decryption");
-        return cipher(key, Base64.decodeBase64(inputBytes), Cipher.DECRYPT_MODE);
+        return cipher(key, Base64.decode(inputBytes), Cipher.DECRYPT_MODE);
     }
 
     private static void isValidKey(String key) {

+ 0 - 5
pom.xml

@@ -702,11 +702,6 @@
                 <version>1.1.1</version>
                 <optional>true</optional>
             </dependency>
-            <dependency>
-                <groupId>commons-codec</groupId>
-                <artifactId>commons-codec</artifactId>
-                <version>1.3</version>
-            </dependency>
             <dependency>
                 <groupId>javax.servlet</groupId>
                 <artifactId>servlet-api</artifactId>

+ 6 - 0
web/pom.xml

@@ -30,6 +30,12 @@
             <artifactId>spring-test</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+            <version>1.3</version>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>jaxen</groupId>
             <artifactId>jaxen</artifactId>

+ 8 - 3
web/src/main/java/org/springframework/security/web/access/expression/WebSecurityExpressionRoot.java

@@ -4,6 +4,8 @@ import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.Arrays;
 
+import javax.servlet.http.HttpServletRequest;
+
 import org.springframework.security.access.expression.SecurityExpressionRoot;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.web.FilterInvocation;
@@ -16,11 +18,14 @@ import org.springframework.util.StringUtils;
  * @since 3.0
  */
 public class WebSecurityExpressionRoot extends SecurityExpressionRoot {
-    private FilterInvocation filterInvocation;
+    //private FilterInvocation filterInvocation;
+    /** Allows direct access to the request object */
+    public final HttpServletRequest request;
 
     public WebSecurityExpressionRoot(Authentication a, FilterInvocation fi) {
         super(a);
-        this.filterInvocation = fi;
+        //this.filterInvocation = fi;
+        this.request = fi.getRequest();
     }
 
     /**
@@ -39,7 +44,7 @@ public class WebSecurityExpressionRoot extends SecurityExpressionRoot {
         }
 
         InetAddress requiredAddress = parseAddress(ipAddress);
-        InetAddress remoteAddress = parseAddress(filterInvocation.getHttpRequest().getRemoteAddr());
+        InetAddress remoteAddress = parseAddress(request.getRemoteAddr());
 
         if (!requiredAddress.getClass().equals(remoteAddress.getClass())) {
             throw new IllegalArgumentException("IP Address in expression must be the same type as " +

+ 8 - 8
web/src/main/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServices.java

@@ -1,6 +1,9 @@
 package org.springframework.security.web.authentication.rememberme;
 
-import org.apache.commons.codec.binary.Base64;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.springframework.beans.factory.InitializingBean;
@@ -11,6 +14,7 @@ import org.springframework.security.authentication.AuthenticationDetailsSource;
 import org.springframework.security.authentication.RememberMeAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.SpringSecurityMessageSource;
+import org.springframework.security.core.codec.Base64;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.core.userdetails.UserDetailsChecker;
 import org.springframework.security.core.userdetails.UserDetailsService;
@@ -21,10 +25,6 @@ import org.springframework.security.web.authentication.logout.LogoutHandler;
 import org.springframework.util.Assert;
 import org.springframework.util.StringUtils;
 
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 /**
  * Base class for RememberMeServices implementations.
  *
@@ -160,11 +160,11 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
             cookieValue = cookieValue + "=";
         }
 
-        if (!Base64.isArrayByteBase64(cookieValue.getBytes())) {
+        if (!Base64.isBase64(cookieValue.getBytes())) {
             throw new InvalidCookieException( "Cookie token was not Base64 encoded; value was '" + cookieValue + "'");
         }
 
-        String cookieAsPlainText = new String(Base64.decodeBase64(cookieValue.getBytes()));
+        String cookieAsPlainText = new String(Base64.decode(cookieValue.getBytes()));
 
         return StringUtils.delimitedListToStringArray(cookieAsPlainText, DELIMITER);
     }
@@ -187,7 +187,7 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
 
         String value = sb.toString();
 
-        sb = new StringBuffer(new String(Base64.encodeBase64(value.getBytes())));
+        sb = new StringBuffer(new String(Base64.encode(value.getBytes())));
 
         while (sb.charAt(sb.length() - 1) == '=') {
             sb.deleteCharAt(sb.length() - 1);

+ 3 - 3
web/src/main/java/org/springframework/security/web/authentication/rememberme/PersistentTokenBasedRememberMeServices.java

@@ -7,9 +7,9 @@ import java.util.Date;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.apache.commons.codec.binary.Base64;
 import org.springframework.dao.DataAccessException;
 import org.springframework.security.core.Authentication;
+import org.springframework.security.core.codec.Base64;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.web.authentication.RememberMeServices;
 import org.springframework.util.Assert;
@@ -151,13 +151,13 @@ public class PersistentTokenBasedRememberMeServices extends AbstractRememberMeSe
     protected String generateSeriesData() {
         byte[] newSeries = new byte[seriesLength];
         random.nextBytes(newSeries);
-        return new String(Base64.encodeBase64(newSeries));
+        return new String(Base64.encode(newSeries));
     }
 
     protected String generateTokenData() {
         byte[] newToken = new byte[tokenLength];
         random.nextBytes(newToken);
-        return new String(Base64.encodeBase64(newToken));
+        return new String(Base64.encode(newToken));
     }
 
     private void addCookie(PersistentRememberMeToken token, HttpServletRequest request, HttpServletResponse response) {

+ 13 - 3
web/src/main/java/org/springframework/security/web/authentication/rememberme/TokenBasedRememberMeServices.java

@@ -16,13 +16,15 @@
 package org.springframework.security.web.authentication.rememberme;
 
 import org.springframework.security.core.Authentication;
+import org.springframework.security.core.codec.Hex;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.util.StringUtils;
 
-import org.apache.commons.codec.digest.DigestUtils;
-
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.util.Arrays;
 import java.util.Date;
 
@@ -129,7 +131,15 @@ public class TokenBasedRememberMeServices extends AbstractRememberMeServices {
      * MD5 ("username:tokenExpiryTime:password:key")
      */
     protected String makeTokenSignature(long tokenExpiryTime, String username, String password) {
-        return DigestUtils.md5Hex(username + ":" + tokenExpiryTime + ":" + password + ":" + getKey());
+        String data = username + ":" + tokenExpiryTime + ":" + password + ":" + getKey();
+        MessageDigest digest;
+        try {
+            digest = MessageDigest.getInstance("MD5");
+        } catch (NoSuchAlgorithmException e) {
+            throw new IllegalStateException("No MD5 algorithm available!");
+        }
+
+        return new String(Hex.encode(digest.digest(data.getBytes())));
     }
 
     protected boolean isTokenExpired(long tokenExpiryTime) {

+ 2 - 2
web/src/main/java/org/springframework/security/web/authentication/www/BasicAuthenticationFilter.java

@@ -24,13 +24,13 @@ import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.apache.commons.codec.binary.Base64;
 import org.springframework.security.authentication.AnonymousAuthenticationToken;
 import org.springframework.security.authentication.AuthenticationDetailsSource;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.codec.Base64;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.web.AuthenticationEntryPoint;
 import org.springframework.security.web.authentication.NullRememberMeServices;
@@ -117,7 +117,7 @@ public class BasicAuthenticationFilter extends GenericFilterBean {
 
         if ((header != null) && header.startsWith("Basic ")) {
             byte[] base64Token = header.substring(6).getBytes("UTF-8");
-            String token = new String(Base64.decodeBase64(base64Token), getCredentialsCharset(request));
+            String token = new String(Base64.decode(base64Token), getCredentialsCharset(request));
 
             String username = "";
             String password = "";

+ 23 - 11
web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthUtils.java

@@ -1,27 +1,28 @@
 package org.springframework.security.web.authentication.www;
 
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.commons.codec.digest.DigestUtils;
+import org.springframework.security.core.codec.Hex;
 import org.springframework.util.Assert;
 import org.springframework.util.StringUtils;
 
-abstract class DigestAuthUtils {
+final class DigestAuthUtils {
 
     private static final String[] EMPTY_STRING_ARRAY = new String[0];
 
-    public final static String encodePasswordInA1Format(String username, String realm, String password) {
+    static String encodePasswordInA1Format(String username, String realm, String password) {
         String a1 = username + ":" + realm + ":" + password;
-        String a1Md5 = new String(DigestUtils.md5Hex(a1));
+        String a1Md5 = md5Hex(a1);
 
         return a1Md5;
     }
 
-
-    final static String[] splitIgnoringQuotes(String str, char separatorChar) {
+    static String[] splitIgnoringQuotes(String str, char separatorChar) {
         if (str == null) {
             return null;
         }
@@ -87,12 +88,12 @@ abstract class DigestAuthUtils {
      * @return the MD5 of the digest authentication response, encoded in hex
      * @throws IllegalArgumentException if the supplied qop value is unsupported.
      */
-    final static String generateDigest(boolean passwordAlreadyEncoded, String username, String realm, String password,
+    static String generateDigest(boolean passwordAlreadyEncoded, String username, String realm, String password,
                                         String httpMethod, String uri, String qop, String nonce, String nc, String cnonce)
             throws IllegalArgumentException {
         String a1Md5 = null;
         String a2 = httpMethod + ":" + uri;
-        String a2Md5 = new String(DigestUtils.md5Hex(a2));
+        String a2Md5 = md5Hex(a2);
 
         if (passwordAlreadyEncoded) {
             a1Md5 = password;
@@ -112,7 +113,7 @@ abstract class DigestAuthUtils {
             throw new IllegalArgumentException("This method does not support a qop: '" + qop + "'");
         }
 
-        String digestMd5 = new String(DigestUtils.md5Hex(digest));
+        String digestMd5 = new String(md5Hex(digest));
 
         return digestMd5;
     }
@@ -130,7 +131,7 @@ abstract class DigestAuthUtils {
      * @return a <code>Map</code> representing the array contents, or <code>null</code> if the array to process was
      *         null or empty
      */
-    final static Map<String, String> splitEachArrayElementAndCreateMap(String[] array, String delimiter, String removeCharacters) {
+    static Map<String, String> splitEachArrayElementAndCreateMap(String[] array, String delimiter, String removeCharacters) {
         if ((array == null) || (array.length == 0)) {
             return null;
         }
@@ -169,7 +170,7 @@ abstract class DigestAuthUtils {
      *         (neither element includes the delimiter)
      * @throws IllegalArgumentException if an argument was invalid
      */
-    final static String[] split(String toSplit, String delimiter) {
+    static String[] split(String toSplit, String delimiter) {
         Assert.hasLength(toSplit, "Cannot split a null or empty string");
         Assert.hasLength(delimiter, "Cannot use a null or empty delimiter to split a string");
 
@@ -188,4 +189,15 @@ abstract class DigestAuthUtils {
 
         return new String[]{beforeDelimiter, afterDelimiter};
     }
+
+    static String md5Hex(String data) {
+        MessageDigest digest;
+        try {
+            digest = MessageDigest.getInstance("MD5");
+        } catch (NoSuchAlgorithmException e) {
+            throw new IllegalStateException("No MD5 algorithm available!");
+        }
+
+        return new String(Hex.encode(digest.digest(data.getBytes())));
+    }
 }

+ 5 - 6
web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthenticationEntryPoint.java

@@ -21,14 +21,13 @@ import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.web.AuthenticationEntryPoint;
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.core.Ordered;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.codec.Base64;
+import org.springframework.security.web.AuthenticationEntryPoint;
 
 
 /**
@@ -82,9 +81,9 @@ public class DigestAuthenticationEntryPoint implements AuthenticationEntryPoint,
         // format of nonce is:
         //   base64(expirationTime + ":" + md5Hex(expirationTime + ":" + key))
         long expiryTime = System.currentTimeMillis() + (nonceValiditySeconds * 1000);
-        String signatureValue = new String(DigestUtils.md5Hex(expiryTime + ":" + key));
+        String signatureValue = new String(DigestAuthUtils.md5Hex(expiryTime + ":" + key));
         String nonceValue = expiryTime + ":" + signatureValue;
-        String nonceValueBase64 = new String(Base64.encodeBase64(nonceValue.getBytes()));
+        String nonceValueBase64 = new String(Base64.encode(nonceValue.getBytes()));
 
         // qop is quality of protection, as defined by RFC 2617.
         // we do not use opaque due to IE violation of RFC 2617 in not

+ 15 - 16
web/src/main/java/org/springframework/security/web/authentication/www/DigestAuthenticationFilter.java

@@ -25,8 +25,6 @@ import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.springframework.context.MessageSource;
@@ -38,6 +36,7 @@ import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.core.SpringSecurityMessageSource;
+import org.springframework.security.core.codec.Base64;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.core.userdetails.UserCache;
 import org.springframework.security.core.userdetails.UserDetails;
@@ -96,7 +95,7 @@ public class DigestAuthenticationFilter extends GenericFilterBean implements Mes
 
 
 
-	@Override
+    @Override
     public void afterPropertiesSet() {
         Assert.notNull(userDetailsService, "A UserDetailsService is required");
         Assert.notNull(authenticationEntryPoint, "A DigestAuthenticationEntryPoint is required");
@@ -168,7 +167,7 @@ public class DigestAuthenticationFilter extends GenericFilterBean implements Mes
             }
 
             // Check nonce was a Base64 encoded (as sent by DigestAuthenticationEntryPoint)
-            if (!Base64.isArrayByteBase64(nonce.getBytes())) {
+            if (!Base64.isBase64(nonce.getBytes())) {
                 fail(request, response,
                         new BadCredentialsException(messages.getMessage("DigestAuthenticationFilter.nonceEncoding",
                                 new Object[]{nonce}, "Nonce is not encoded in Base64; received nonce {0}")));
@@ -179,7 +178,7 @@ public class DigestAuthenticationFilter extends GenericFilterBean implements Mes
             // Decode nonce from Base64
             // format of nonce is:
             //   base64(expirationTime + ":" + md5Hex(expirationTime + ":" + key))
-            String nonceAsPlainText = new String(Base64.decodeBase64(nonce.getBytes()));
+            String nonceAsPlainText = new String(Base64.decode(nonce.getBytes()));
             String[] nonceTokens = StringUtils.delimitedListToStringArray(nonceAsPlainText, ":");
 
             if (nonceTokens.length != 2) {
@@ -205,7 +204,7 @@ public class DigestAuthenticationFilter extends GenericFilterBean implements Mes
             }
 
             // Check signature of nonce matches this expiry time
-            String expectedNonceSignature = DigestUtils.md5Hex(nonceExpiryTime + ":"
+            String expectedNonceSignature = DigestAuthUtils.md5Hex(nonceExpiryTime + ":"
                     + this.getAuthenticationEntryPoint().getKey());
 
             if (!expectedNonceSignature.equals(nonceTokens[1])) {
@@ -305,11 +304,11 @@ public class DigestAuthenticationFilter extends GenericFilterBean implements Mes
 
             UsernamePasswordAuthenticationToken authRequest;
             if (createAuthenticatedToken) {
-            	   authRequest = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
+                   authRequest = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
             }
             else
             {
-            	authRequest = new UsernamePasswordAuthenticationToken(user, user.getPassword());
+                authRequest = new UsernamePasswordAuthenticationToken(user, user.getPassword());
             }
 
             authRequest.setDetails(authenticationDetailsSource.buildDetails((HttpServletRequest) request));
@@ -367,23 +366,23 @@ public class DigestAuthenticationFilter extends GenericFilterBean implements Mes
     public void setUserDetailsService(UserDetailsService userDetailsService) {
         this.userDetailsService = userDetailsService;
     }
-    
-    
-    /** 
+
+
+    /**
      * If you set this property, the Authentication object, which is
      * created after the successful digest authentication will be marked
-     * as <b>authenticated</b> and filled with the authorities loaded by 
+     * as <b>authenticated</b> and filled with the authorities loaded by
      * the UserDetailsService. It therefore will not be re-authenticated
      * by your AuthenticationProvider. This means, that only the password
      * of the user is checked, but not the flags like isEnabled() or
-     * isAccountNonExpired(). You will save some time by enabling this flag, 
+     * isAccountNonExpired(). You will save some time by enabling this flag,
      * as otherwise your UserDetailsService will be called twice. A more secure
      * option would be to introduce a cache around your UserDetailsService, but
      * if you don't use these flags, you can also safely enable this option.
-     * 
+     *
      * @param createAuthenticatedToken default is false
      */
     public void setCreateAuthenticatedToken(boolean createAuthenticatedToken) {
-		this.createAuthenticatedToken = createAuthenticatedToken;
-	}
+        this.createAuthenticatedToken = createAuthenticatedToken;
+    }
 }