SEC-1303: Added internal Hex and Base64 classes, and moved commons-codec dependency to test scope
This commit is contained in:
parent
cd6711d21a
commit
69699431b1
|
@ -59,6 +59,7 @@
|
|||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
//
|
||||
// }
|
||||
}
|
|
@ -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)
|
||||
*/
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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: "
|
||||
|
|
|
@ -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) {
|
||||
|
|
5
pom.xml
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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 " +
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 = "";
|
||||
|
|
|
@ -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())));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue