diff --git a/docs/modules/ROOT/pages/servlet/authentication/rememberme.adoc b/docs/modules/ROOT/pages/servlet/authentication/rememberme.adoc index a0f92dbe1b..97c577da1d 100644 --- a/docs/modules/ROOT/pages/servlet/authentication/rememberme.adoc +++ b/docs/modules/ROOT/pages/servlet/authentication/rememberme.adoc @@ -127,7 +127,7 @@ To do that you can specify your customized `TokenBasedRememberMeServices` as a B @Bean SecurityFilterChain securityFilterChain(HttpSecurity http, RememberMeServices rememberMeServices) throws Exception { http - .authorizeRequests((authorize) -> authorize + .authorizeHttpRequests((authorize) -> authorize .anyRequest().authenticated() ) .rememberMe((remember) -> remember @@ -138,9 +138,9 @@ SecurityFilterChain securityFilterChain(HttpSecurity http, RememberMeServices re @Bean RememberMeServices rememberMeServices(UserDetailsService userDetailsService) { - TokenBasedRememberMeServices rememberMe = new TokenBasedRememberMeServices(myKey, userDetailsService); + RememberMeTokenAlgorithm encodingAlgorithm = RememberMeTokenAlgorithm.SHA256; + TokenBasedRememberMeServices rememberMe = new TokenBasedRememberMeServices(myKey, userDetailsService, encodingAlgorithm); rememberMe.setMatchingAlgorithm(RememberMeTokenAlgorithm.MD5); - rememberMe.setEncodingAlgorithm(RememberMeTokenAlgorithm.SHA256); return rememberMe; } ---- diff --git a/web/src/main/java/org/springframework/security/web/authentication/rememberme/TokenBasedRememberMeServices.java b/web/src/main/java/org/springframework/security/web/authentication/rememberme/TokenBasedRememberMeServices.java index 30d9c3af00..64d4b4c023 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/rememberme/TokenBasedRememberMeServices.java +++ b/web/src/main/java/org/springframework/security/web/authentication/rememberme/TokenBasedRememberMeServices.java @@ -90,6 +90,7 @@ import org.springframework.util.StringUtils; * not be stored when the browser is closed. * * @author Ben Alex + * @author Marcus Da Coregio */ public class TokenBasedRememberMeServices extends AbstractRememberMeServices { @@ -97,12 +98,27 @@ public class TokenBasedRememberMeServices extends AbstractRememberMeServices { private static final RememberMeTokenAlgorithm DEFAULT_ENCODING_ALGORITHM = RememberMeTokenAlgorithm.MD5; + private final RememberMeTokenAlgorithm encodingAlgorithm; + private RememberMeTokenAlgorithm matchingAlgorithm = DEFAULT_MATCHING_ALGORITHM; - private RememberMeTokenAlgorithm encodingAlgorithm = DEFAULT_ENCODING_ALGORITHM; - public TokenBasedRememberMeServices(String key, UserDetailsService userDetailsService) { + this(key, userDetailsService, DEFAULT_ENCODING_ALGORITHM); + } + + /** + * Construct the instance with the parameters provided + * @param key the signature key + * @param userDetailsService the {@link UserDetailsService} + * @param encodingAlgorithm the {@link RememberMeTokenAlgorithm} used to encode the + * signature + * @since 5.8 + */ + public TokenBasedRememberMeServices(String key, UserDetailsService userDetailsService, + RememberMeTokenAlgorithm encodingAlgorithm) { super(key, userDetailsService); + Assert.notNull(encodingAlgorithm, "encodingAlgorithm cannot be null"); + this.encodingAlgorithm = encodingAlgorithm; } @Override @@ -176,6 +192,7 @@ public class TokenBasedRememberMeServices extends AbstractRememberMeServices { /** * Calculates the digital signature to be put in the cookie. + * @since 5.8 */ protected String makeTokenSignature(long tokenExpiryTime, String username, String password, RememberMeTokenAlgorithm algorithm) { @@ -226,18 +243,10 @@ public class TokenBasedRememberMeServices extends AbstractRememberMeServices { } } - /** - * Sets the algorithm to be used to encode the token signature - * @param encodingAlgorithm the encoding algorithm - */ - public void setEncodingAlgorithm(RememberMeTokenAlgorithm encodingAlgorithm) { - Assert.notNull(encodingAlgorithm, "encodingAlgorithm cannot be null"); - this.encodingAlgorithm = encodingAlgorithm; - } - /** * Sets the algorithm to be used to match the token signature * @param matchingAlgorithm the matching algorithm + * @since 5.8 */ public void setMatchingAlgorithm(RememberMeTokenAlgorithm matchingAlgorithm) { Assert.notNull(matchingAlgorithm, "matchingAlgorithm cannot be null"); diff --git a/web/src/test/java/org/springframework/security/web/authentication/rememberme/TokenBasedRememberMeServicesTests.java b/web/src/test/java/org/springframework/security/web/authentication/rememberme/TokenBasedRememberMeServicesTests.java index 1cd1794ad7..22d0607056 100644 --- a/web/src/test/java/org/springframework/security/web/authentication/rememberme/TokenBasedRememberMeServicesTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/rememberme/TokenBasedRememberMeServicesTests.java @@ -33,9 +33,11 @@ import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.test.web.CodecTestUtils; import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices.RememberMeTokenAlgorithm; +import org.springframework.test.util.ReflectionTestUtils; import org.springframework.util.StringUtils; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; @@ -47,6 +49,7 @@ import static org.mockito.Mockito.mock; * . * * @author Ben Alex + * @author Marcus Da Coregio */ public class TokenBasedRememberMeServicesTests { @@ -412,7 +415,7 @@ public class TokenBasedRememberMeServicesTests { MockHttpServletRequest request = new MockHttpServletRequest(); request.addParameter(AbstractRememberMeServices.DEFAULT_PARAMETER, "true"); MockHttpServletResponse response = new MockHttpServletResponse(); - this.services.setEncodingAlgorithm(RememberMeTokenAlgorithm.SHA256); + this.services = new TokenBasedRememberMeServices("key", this.uds, RememberMeTokenAlgorithm.SHA256); this.services.loginSuccess(request, response, new TestingAuthenticationToken("someone", "password", "ROLE_ABC")); Cookie cookie = response.getCookie(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY); @@ -448,4 +451,19 @@ public class TokenBasedRememberMeServicesTests { assertThat(CodecTestUtils.isBase64(cookie.getValue().getBytes())).isTrue(); } + @Test + public void constructorWhenEncodingAlgorithmNullThenException() { + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> new TokenBasedRememberMeServices("key", this.uds, null)) + .withMessage("encodingAlgorithm cannot be null"); + } + + @Test + public void constructorWhenNoEncodingAlgorithmSpecifiedThenMd5() { + TokenBasedRememberMeServices rememberMeServices = new TokenBasedRememberMeServices("key", this.uds); + RememberMeTokenAlgorithm encodingAlgorithm = (RememberMeTokenAlgorithm) ReflectionTestUtils + .getField(rememberMeServices, "encodingAlgorithm"); + assertThat(encodingAlgorithm).isSameAs(RememberMeTokenAlgorithm.MD5); + } + }