SEC-1303: Added internal Hex and Base64 classes, and moved commons-codec dependency to test scope
This commit is contained in:
+8
-3
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user