Remove dependency on commons-codec by using java.util.Base64

Closes gh-11318
This commit is contained in:
j3graham 2022-06-01 14:32:55 -04:00 committed by Josh Cummings
parent d1cb236df5
commit f3c96fa9cd
11 changed files with 156 additions and 54 deletions

View File

@ -105,12 +105,6 @@ updateDependenciesSettings {
alphaBetaVersions()
snapshotVersions()
addRule { components ->
components.withModule("commons-codec:commons-codec") { selection ->
ModuleComponentIdentifier candidate = selection.getCandidate();
if (!candidate.getVersion().equals(selection.getCurrentVersion())) {
selection.reject("commons-codec updates break saml tests");
}
}
components.withModule("org.python:jython") { selection ->
ModuleComponentIdentifier candidate = selection.getCandidate();
if (!candidate.getVersion().equals(selection.getCurrentVersion())) {

View File

@ -23,7 +23,6 @@ dependencies {
api "com.squareup.okhttp3:mockwebserver:3.14.9"
api "com.squareup.okhttp3:okhttp:3.14.9"
api "com.unboundid:unboundid-ldapsdk:4.0.14"
api "commons-codec:commons-codec:1.15"
api "commons-collections:commons-collections:3.2.2"
api "io.mockk:mockk:1.12.4"
api "jakarta.annotation:jakarta.annotation-api:2.1.0"

View File

@ -15,7 +15,6 @@ dependencies {
optional 'jakarta.servlet:jakarta.servlet-api'
testImplementation project(path: ':spring-security-core', configuration: 'tests')
testImplementation 'commons-codec:commons-codec'
testImplementation "org.assertj:assertj-core"
testImplementation "org.junit.jupiter:junit-jupiter-api"
testImplementation "org.junit.jupiter:junit-jupiter-params"

View File

@ -18,13 +18,13 @@ package org.springframework.security.saml2.provider.service.web;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
import java.util.function.Function;
import java.util.zip.Inflater;
import java.util.zip.InflaterOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.codec.CodecPolicy;
import org.apache.commons.codec.binary.Base64;
import org.springframework.http.HttpMethod;
import org.springframework.security.saml2.core.Saml2Error;
@ -47,7 +47,11 @@ import org.springframework.util.Assert;
*/
public final class Saml2AuthenticationTokenConverter implements AuthenticationConverter {
private static Base64 BASE64 = new Base64(0, new byte[] { '\n' }, false, CodecPolicy.STRICT);
// MimeDecoder allows extra line-breaks as well as other non-alphabet values.
// This matches the behaviour of the commons-codec decoder.
private static final Base64.Decoder BASE64 = Base64.getMimeDecoder();
private static final Base64Checker BASE_64_CHECKER = new Base64Checker();
private final RelyingPartyRegistrationResolver relyingPartyRegistrationResolver;
@ -110,6 +114,7 @@ public final class Saml2AuthenticationTokenConverter implements AuthenticationCo
private byte[] samlDecode(String base64EncodedPayload) {
try {
BASE_64_CHECKER.checkAcceptable(base64EncodedPayload);
return BASE64.decode(base64EncodedPayload);
}
catch (Exception ex) {
@ -132,4 +137,58 @@ public final class Saml2AuthenticationTokenConverter implements AuthenticationCo
}
}
static class Base64Checker {
private static final int[] values = genValueMapping();
Base64Checker() {
}
private static int[] genValueMapping() {
byte[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
.getBytes(StandardCharsets.ISO_8859_1);
int[] values = new int[256];
Arrays.fill(values, -1);
for (int i = 0; i < alphabet.length; i++) {
values[alphabet[i] & 0xff] = i;
}
return values;
}
boolean isAcceptable(String s) {
int goodChars = 0;
int lastGoodCharVal = -1;
// count number of characters from Base64 alphabet
for (int i = 0; i < s.length(); i++) {
int val = values[0xff & s.charAt(i)];
if (val != -1) {
lastGoodCharVal = val;
goodChars++;
}
}
// in cases of an incomplete final chunk, ensure the unused bits are zero
switch (goodChars % 4) {
case 0:
return true;
case 2:
return (lastGoodCharVal & 0b1111) == 0;
case 3:
return (lastGoodCharVal & 0b11) == 0;
default:
return false;
}
}
void checkAcceptable(String ins) {
if (!isAcceptable(ins)) {
throw new IllegalArgumentException("Unaccepted Encoding");
}
}
}
}

View File

@ -20,7 +20,6 @@ dependencies {
provided 'jakarta.servlet:jakarta.servlet-api'
testImplementation project(path: ':spring-security-core', configuration: 'tests')
testImplementation 'commons-codec:commons-codec'
testImplementation 'io.projectreactor:reactor-test'
testImplementation 'jakarta.xml.bind:jakarta.xml.bind-api'
testImplementation 'org.hamcrest:hamcrest'

View File

@ -0,0 +1,55 @@
/*
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.test.web;
import java.util.Base64;
import org.springframework.util.DigestUtils;
public final class CodecTestUtils {
private CodecTestUtils() {
}
public static String encodeBase64(String unencoded) {
return Base64.getEncoder().encodeToString(unencoded.getBytes());
}
public static String encodeBase64(byte[] unencoded) {
return Base64.getEncoder().encodeToString(unencoded);
}
public static String decodeBase64(String encoded) {
return new String(Base64.getDecoder().decode(encoded));
}
public static boolean isBase64(byte[] arrayOctet) {
try {
Base64.getMimeDecoder().decode(arrayOctet);
return true;
}
catch (Exception ex) {
return false;
}
}
public static String md5Hex(String data) {
return DigestUtils.md5DigestAsHex(data.getBytes());
}
}

View File

@ -19,8 +19,6 @@ package org.springframework.security.web.authentication.rememberme;
import java.util.Date;
import jakarta.servlet.http.Cookie;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -33,6 +31,7 @@ import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.test.web.CodecTestUtils;
import org.springframework.util.StringUtils;
import static org.assertj.core.api.Assertions.assertThat;
@ -76,7 +75,7 @@ public class TokenBasedRememberMeServicesTests {
}
private long determineExpiryTimeFromBased64EncodedToken(String validToken) {
String cookieAsPlainText = new String(Base64.decodeBase64(validToken.getBytes()));
String cookieAsPlainText = CodecTestUtils.decodeBase64(validToken);
String[] cookieTokens = StringUtils.delimitedListToStringArray(cookieAsPlainText, ":");
if (cookieTokens.length == 3) {
try {
@ -92,9 +91,9 @@ public class TokenBasedRememberMeServicesTests {
// format is:
// username + ":" + expiryTime + ":" + Md5Hex(username + ":" + expiryTime + ":" +
// password + ":" + key)
String signatureValue = DigestUtils.md5Hex(username + ":" + expiryTime + ":" + password + ":" + key);
String signatureValue = CodecTestUtils.md5Hex(username + ":" + expiryTime + ":" + password + ":" + key);
String tokenValue = username + ":" + expiryTime + ":" + signatureValue;
return new String(Base64.encodeBase64(tokenValue.getBytes()));
return CodecTestUtils.encodeBase64(tokenValue);
}
@Test
@ -134,7 +133,7 @@ public class TokenBasedRememberMeServicesTests {
@Test
public void autoLoginReturnsNullAndClearsCookieIfMissingThreeTokensInCookieValue() {
Cookie cookie = new Cookie(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY,
new String(Base64.encodeBase64("x".getBytes())));
CodecTestUtils.encodeBase64("x"));
MockHttpServletRequest request = new MockHttpServletRequest();
request.setCookies(cookie);
MockHttpServletResponse response = new MockHttpServletResponse();
@ -175,7 +174,7 @@ public class TokenBasedRememberMeServicesTests {
@Test
public void autoLoginClearsCookieIfTokenDoesNotContainANumberInCookieValue() {
Cookie cookie = new Cookie(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY,
new String(Base64.encodeBase64("username:NOT_A_NUMBER:signature".getBytes())));
CodecTestUtils.encodeBase64("username:NOT_A_NUMBER:signature"));
MockHttpServletRequest request = new MockHttpServletRequest();
request.setCookies(cookie);
MockHttpServletResponse response = new MockHttpServletResponse();
@ -275,7 +274,7 @@ public class TokenBasedRememberMeServicesTests {
assertThat(Long.parseLong(expiryTime) > expectedExpiryTime - 10000).isTrue();
assertThat(cookie).isNotNull();
assertThat(cookie.getMaxAge()).isEqualTo(this.services.getTokenValiditySeconds());
assertThat(Base64.isArrayByteBase64(cookie.getValue().getBytes())).isTrue();
assertThat(CodecTestUtils.isBase64(cookie.getValue().getBytes())).isTrue();
assertThat(new Date().before(new Date(determineExpiryTimeFromBased64EncodedToken(cookie.getValue())))).isTrue();
}
@ -289,7 +288,7 @@ public class TokenBasedRememberMeServicesTests {
Cookie cookie = response.getCookie(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY);
assertThat(cookie).isNotNull();
assertThat(cookie.getMaxAge()).isEqualTo(this.services.getTokenValiditySeconds());
assertThat(Base64.isArrayByteBase64(cookie.getValue().getBytes())).isTrue();
assertThat(CodecTestUtils.isBase64(cookie.getValue().getBytes())).isTrue();
assertThat(new Date().before(new Date(determineExpiryTimeFromBased64EncodedToken(cookie.getValue())))).isTrue();
}
@ -315,7 +314,7 @@ public class TokenBasedRememberMeServicesTests {
assertThat(determineExpiryTimeFromBased64EncodedToken(cookie.getValue())
- System.currentTimeMillis() > AbstractRememberMeServices.TWO_WEEKS_S - 50).isTrue();
assertThat(cookie.getMaxAge()).isEqualTo(-1);
assertThat(Base64.isArrayByteBase64(cookie.getValue().getBytes())).isTrue();
assertThat(CodecTestUtils.isBase64(cookie.getValue().getBytes())).isTrue();
}
}

View File

@ -17,7 +17,6 @@
package org.springframework.security.web.authentication.www;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.codec.binary.Base64;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@ -28,6 +27,7 @@ import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.test.web.CodecTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@ -56,7 +56,7 @@ public class BasicAuthenticationConverterTests {
public void testNormalOperation() {
String token = "rod:koala";
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization", "Basic " + new String(Base64.encodeBase64(token.getBytes())));
request.addHeader("Authorization", "Basic " + CodecTestUtils.encodeBase64(token));
UsernamePasswordAuthenticationToken authentication = this.converter.convert(request);
verify(this.authenticationDetailsSource).buildDetails(any());
assertThat(authentication).isNotNull();
@ -67,7 +67,7 @@ public class BasicAuthenticationConverterTests {
public void requestWhenAuthorizationSchemeInMixedCaseThenAuthenticates() {
String token = "rod:koala";
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization", "BaSiC " + new String(Base64.encodeBase64(token.getBytes())));
request.addHeader("Authorization", "BaSiC " + CodecTestUtils.encodeBase64(token));
UsernamePasswordAuthenticationToken authentication = this.converter.convert(request);
verify(this.authenticationDetailsSource).buildDetails(any());
assertThat(authentication).isNotNull();
@ -87,7 +87,7 @@ public class BasicAuthenticationConverterTests {
public void testWhenInvalidBasicAuthorizationTokenThenError() {
String token = "NOT_A_VALID_TOKEN_AS_MISSING_COLON";
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization", "Basic " + new String(Base64.encodeBase64(token.getBytes())));
request.addHeader("Authorization", "Basic " + CodecTestUtils.encodeBase64(token));
assertThatExceptionOfType(BadCredentialsException.class).isThrownBy(() -> this.converter.convert(request));
}
@ -102,7 +102,7 @@ public class BasicAuthenticationConverterTests {
public void convertWhenEmptyPassword() {
String token = "rod:";
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization", "Basic " + new String(Base64.encodeBase64(token.getBytes())));
request.addHeader("Authorization", "Basic " + CodecTestUtils.encodeBase64(token));
UsernamePasswordAuthenticationToken authentication = this.converter.convert(request);
verify(this.authenticationDetailsSource).buildDetails(any());
assertThat(authentication).isNotNull();

View File

@ -22,7 +22,6 @@ import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.codec.binary.Base64;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -38,6 +37,7 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.test.web.CodecTestUtils;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.web.util.WebUtils;
@ -104,7 +104,7 @@ public class BasicAuthenticationFilterTests {
public void testInvalidBasicAuthorizationTokenIsIgnored() throws Exception {
String token = "NOT_A_VALID_TOKEN_AS_MISSING_COLON";
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization", "Basic " + new String(Base64.encodeBase64(token.getBytes())));
request.addHeader("Authorization", "Basic " + CodecTestUtils.encodeBase64(token));
request.setServletPath("/some_file.html");
request.setSession(new MockHttpSession());
final MockHttpServletResponse response = new MockHttpServletResponse();
@ -134,7 +134,7 @@ public class BasicAuthenticationFilterTests {
public void testNormalOperation() throws Exception {
String token = "rod:koala";
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization", "Basic " + new String(Base64.encodeBase64(token.getBytes())));
request.addHeader("Authorization", "Basic " + CodecTestUtils.encodeBase64(token));
request.setServletPath("/some_file.html");
// Test
assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull();
@ -150,7 +150,7 @@ public class BasicAuthenticationFilterTests {
public void doFilterWhenSchemeLowercaseThenCaseInsensitveMatchWorks() throws Exception {
String token = "rod:koala";
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization", "basic " + new String(Base64.encodeBase64(token.getBytes())));
request.addHeader("Authorization", "basic " + CodecTestUtils.encodeBase64(token));
request.setServletPath("/some_file.html");
// Test
assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull();
@ -165,7 +165,7 @@ public class BasicAuthenticationFilterTests {
public void doFilterWhenSchemeMixedCaseThenCaseInsensitiveMatchWorks() throws Exception {
String token = "rod:koala";
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization", "BaSiC " + new String(Base64.encodeBase64(token.getBytes())));
request.addHeader("Authorization", "BaSiC " + CodecTestUtils.encodeBase64(token));
request.setServletPath("/some_file.html");
assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull();
FilterChain chain = mock(FilterChain.class);
@ -200,7 +200,7 @@ public class BasicAuthenticationFilterTests {
public void testSuccessLoginThenFailureLoginResultsInSessionLosingToken() throws Exception {
String token = "rod:koala";
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization", "Basic " + new String(Base64.encodeBase64(token.getBytes())));
request.addHeader("Authorization", "Basic " + CodecTestUtils.encodeBase64(token));
request.setServletPath("/some_file.html");
final MockHttpServletResponse response1 = new MockHttpServletResponse();
FilterChain chain = mock(FilterChain.class);
@ -212,7 +212,7 @@ public class BasicAuthenticationFilterTests {
// NOW PERFORM FAILED AUTHENTICATION
token = "otherUser:WRONG_PASSWORD";
request = new MockHttpServletRequest();
request.addHeader("Authorization", "Basic " + new String(Base64.encodeBase64(token.getBytes())));
request.addHeader("Authorization", "Basic " + CodecTestUtils.encodeBase64(token));
final MockHttpServletResponse response2 = new MockHttpServletResponse();
chain = mock(FilterChain.class);
this.filter.doFilter(request, response2, chain);
@ -228,7 +228,7 @@ public class BasicAuthenticationFilterTests {
public void testWrongPasswordContinuesFilterChainIfIgnoreFailureIsTrue() throws Exception {
String token = "rod:WRONG_PASSWORD";
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization", "Basic " + new String(Base64.encodeBase64(token.getBytes())));
request.addHeader("Authorization", "Basic " + CodecTestUtils.encodeBase64(token));
request.setServletPath("/some_file.html");
request.setSession(new MockHttpSession());
this.filter = new BasicAuthenticationFilter(this.manager);
@ -244,7 +244,7 @@ public class BasicAuthenticationFilterTests {
public void testWrongPasswordReturnsForbiddenIfIgnoreFailureIsFalse() throws Exception {
String token = "rod:WRONG_PASSWORD";
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization", "Basic " + new String(Base64.encodeBase64(token.getBytes())));
request.addHeader("Authorization", "Basic " + CodecTestUtils.encodeBase64(token));
request.setServletPath("/some_file.html");
request.setSession(new MockHttpSession());
assertThat(this.filter.isIgnoreFailure()).isFalse();
@ -262,7 +262,7 @@ public class BasicAuthenticationFilterTests {
public void skippedOnErrorDispatch() throws Exception {
String token = "bad:credentials";
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization", "Basic " + new String(Base64.encodeBase64(token.getBytes())));
request.addHeader("Authorization", "Basic " + CodecTestUtils.encodeBase64(token));
request.setServletPath("/some_file.html");
request.setAttribute(WebUtils.ERROR_REQUEST_URI_ATTRIBUTE, "/error");
MockHttpServletResponse response = new MockHttpServletResponse();
@ -286,7 +286,7 @@ public class BasicAuthenticationFilterTests {
String token = "rod:äöü";
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization",
"Basic " + new String(Base64.encodeBase64(token.getBytes(StandardCharsets.UTF_8))));
"Basic " + CodecTestUtils.encodeBase64(token.getBytes(StandardCharsets.UTF_8)));
request.setServletPath("/some_file.html");
MockHttpServletResponse response = new MockHttpServletResponse();
// Test
@ -315,7 +315,7 @@ public class BasicAuthenticationFilterTests {
String token = "rod:äöü";
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization",
"Basic " + new String(Base64.encodeBase64(token.getBytes(StandardCharsets.ISO_8859_1))));
"Basic " + CodecTestUtils.encodeBase64(token.getBytes(StandardCharsets.ISO_8859_1)));
request.setServletPath("/some_file.html");
MockHttpServletResponse response = new MockHttpServletResponse();
// Test
@ -344,7 +344,7 @@ public class BasicAuthenticationFilterTests {
String token = "rod:äöü";
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization",
"Basic " + new String(Base64.encodeBase64(token.getBytes(StandardCharsets.UTF_8))));
"Basic " + CodecTestUtils.encodeBase64(token.getBytes(StandardCharsets.UTF_8)));
request.setServletPath("/some_file.html");
MockHttpServletResponse response = new MockHttpServletResponse();
// Test
@ -377,7 +377,7 @@ public class BasicAuthenticationFilterTests {
this.filter.setSecurityContextRepository(securityContextRepository);
String token = "rod:koala";
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization", "Basic " + new String(Base64.encodeBase64(token.getBytes())));
request.addHeader("Authorization", "Basic " + CodecTestUtils.encodeBase64(token));
request.setServletPath("/some_file.html");
MockHttpServletResponse response = new MockHttpServletResponse();
// Test

View File

@ -18,13 +18,12 @@ package org.springframework.security.web.authentication.www;
import java.util.Map;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.test.web.CodecTestUtils;
import org.springframework.util.StringUtils;
import static org.assertj.core.api.Assertions.assertThat;
@ -41,11 +40,11 @@ public class DigestAuthenticationEntryPointTests {
// Check the nonce seems to be generated correctly
// format of nonce is:
// base64(expirationTime + ":" + md5Hex(expirationTime + ":" + key))
assertThat(Base64.isArrayByteBase64(nonce.getBytes())).isTrue();
String decodedNonce = new String(Base64.decodeBase64(nonce.getBytes()));
assertThat(CodecTestUtils.isBase64(nonce.getBytes())).isTrue();
String decodedNonce = CodecTestUtils.decodeBase64(nonce);
String[] nonceTokens = StringUtils.delimitedListToStringArray(decodedNonce, ":");
assertThat(nonceTokens).hasSize(2);
String expectedNonceSignature = DigestUtils.md5Hex(nonceTokens[0] + ":" + "key");
String expectedNonceSignature = CodecTestUtils.md5Hex(nonceTokens[0] + ":" + "key");
assertThat(nonceTokens[1]).isEqualTo(expectedNonceSignature);
}

View File

@ -23,8 +23,6 @@ import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -40,6 +38,7 @@ import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.cache.NullUserCache;
import org.springframework.security.test.web.CodecTestUtils;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.util.StringUtils;
@ -105,9 +104,9 @@ public class DigestAuthenticationFilterTests {
private static String generateNonce(int validitySeconds, String key) {
long expiryTime = System.currentTimeMillis() + (validitySeconds * 1000);
String signatureValue = DigestUtils.md5Hex(expiryTime + ":" + key);
String signatureValue = CodecTestUtils.md5Hex(expiryTime + ":" + key);
String nonceValue = expiryTime + ":" + signatureValue;
return new String(Base64.encodeBase64(nonceValue.getBytes()));
return CodecTestUtils.encodeBase64(nonceValue);
}
@AfterEach
@ -182,7 +181,7 @@ public class DigestAuthenticationFilterTests {
@Test
public void testInvalidDigestAuthorizationTokenGeneratesError() throws Exception {
String token = "NOT_A_VALID_TOKEN_AS_MISSING_COLON";
this.request.addHeader("Authorization", "Digest " + new String(Base64.encodeBase64(token.getBytes())));
this.request.addHeader("Authorization", "Digest " + CodecTestUtils.encodeBase64(token));
MockHttpServletResponse response = executeFilterInContainerSimulator(this.filter, this.request, false);
assertThat(response.getStatus()).isEqualTo(401);
assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull();
@ -210,7 +209,7 @@ public class DigestAuthenticationFilterTests {
@Test
public void testNonceWithIncorrectSignatureForNumericFieldReturnsForbidden() throws Exception {
String nonce = new String(Base64.encodeBase64("123456:incorrectStringPassword".getBytes()));
String nonce = CodecTestUtils.encodeBase64("123456:incorrectStringPassword");
String responseDigest = DigestAuthUtils.generateDigest(false, USERNAME, REALM, PASSWORD, "GET", REQUEST_URI,
QOP, nonce, NC, CNONCE);
this.request.addHeader("Authorization",
@ -222,7 +221,7 @@ public class DigestAuthenticationFilterTests {
@Test
public void testNonceWithNonNumericFirstElementReturnsForbidden() throws Exception {
String nonce = new String(Base64.encodeBase64("hello:ignoredSecondElement".getBytes()));
String nonce = CodecTestUtils.encodeBase64("hello:ignoredSecondElement");
String responseDigest = DigestAuthUtils.generateDigest(false, USERNAME, REALM, PASSWORD, "GET", REQUEST_URI,
QOP, nonce, NC, CNONCE);
this.request.addHeader("Authorization",
@ -234,7 +233,7 @@ public class DigestAuthenticationFilterTests {
@Test
public void testNonceWithoutTwoColonSeparatedElementsReturnsForbidden() throws Exception {
String nonce = new String(Base64.encodeBase64("a base 64 string without a colon".getBytes()));
String nonce = CodecTestUtils.encodeBase64("a base 64 string without a colon");
String responseDigest = DigestAuthUtils.generateDigest(false, USERNAME, REALM, PASSWORD, "GET", REQUEST_URI,
QOP, nonce, NC, CNONCE);
this.request.addHeader("Authorization",