瀏覽代碼

Implement MessageSourceAware where missing

Closes gh-8951
Arnaud Mergey 4 年之前
父節點
當前提交
2b9efccc50

+ 14 - 2
core/src/main/java/org/springframework/security/authentication/AbstractUserDetailsReactiveAuthenticationManager.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2019 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -22,6 +22,8 @@ import reactor.core.publisher.Mono;
 import reactor.core.scheduler.Scheduler;
 import reactor.core.scheduler.Schedulers;
 
+import org.springframework.context.MessageSource;
+import org.springframework.context.MessageSourceAware;
 import org.springframework.context.support.MessageSourceAccessor;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.SpringSecurityMessageSource;
@@ -45,7 +47,8 @@ import org.springframework.util.Assert;
  * @author Eddú Meléndez
  * @since 5.2
  */
-public abstract class AbstractUserDetailsReactiveAuthenticationManager implements ReactiveAuthenticationManager {
+public abstract class AbstractUserDetailsReactiveAuthenticationManager
+		implements ReactiveAuthenticationManager, MessageSourceAware {
 
 	protected final Log logger = LogFactory.getLog(getClass());
 
@@ -164,6 +167,15 @@ public abstract class AbstractUserDetailsReactiveAuthenticationManager implement
 		this.postAuthenticationChecks = postAuthenticationChecks;
 	}
 
+	/**
+	 * @since 5.5
+	 */
+	@Override
+	public void setMessageSource(MessageSource messageSource) {
+		Assert.notNull(messageSource, "messageSource cannot be null");
+		this.messages = new MessageSourceAccessor(messageSource);
+	}
+
 	/**
 	 * Allows subclasses to retrieve the <code>UserDetails</code> from an
 	 * implementation-specific location.

+ 18 - 1
core/src/test/java/org/springframework/security/authentication/UserDetailsRepositoryReactiveAuthenticationManagerTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2019 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -25,6 +25,7 @@ import reactor.core.publisher.Mono;
 import reactor.core.scheduler.Scheduler;
 import reactor.core.scheduler.Schedulers;
 
+import org.springframework.context.MessageSource;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.userdetails.ReactiveUserDetailsPasswordService;
 import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
@@ -34,10 +35,12 @@ import org.springframework.security.core.userdetails.UserDetailsChecker;
 import org.springframework.security.crypto.password.PasswordEncoder;
 
 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.ArgumentMatchers.eq;
 import static org.mockito.BDDMockito.given;
 import static org.mockito.BDDMockito.willThrow;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 
@@ -214,4 +217,18 @@ public class UserDetailsRepositoryReactiveAuthenticationManagerTests {
 		assertThatExceptionOfType(DisabledException.class).isThrownBy(() -> this.manager.authenticate(token).block());
 	}
 
+	@Test
+	public void setMessageSourceWhenNullThenThrowsException() {
+		assertThatIllegalArgumentException().isThrownBy(() -> this.manager.setMessageSource(null));
+	}
+
+	@Test
+	public void setMessageSourceWhenNotNullThenCanGet() {
+		MessageSource source = mock(MessageSource.class);
+		this.manager.setMessageSource(source);
+		String code = "code";
+		this.manager.messages.getMessage(code);
+		verify(source).getMessage(eq(code), any(), any());
+	}
+
 }

+ 14 - 3
web/src/main/java/org/springframework/security/web/access/ExceptionTranslationFilter.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2004-2016 the original author or authors.
+ * Copyright 2004-2020 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.
@@ -25,6 +25,8 @@ import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.springframework.context.MessageSource;
+import org.springframework.context.MessageSourceAware;
 import org.springframework.context.support.MessageSourceAccessor;
 import org.springframework.core.log.LogMessage;
 import org.springframework.security.access.AccessDeniedException;
@@ -77,7 +79,7 @@ import org.springframework.web.filter.GenericFilterBean;
  * @author Ben Alex
  * @author colin sampaleanu
  */
-public class ExceptionTranslationFilter extends GenericFilterBean {
+public class ExceptionTranslationFilter extends GenericFilterBean implements MessageSourceAware {
 
 	private AccessDeniedHandler accessDeniedHandler = new AccessDeniedHandlerImpl();
 
@@ -89,7 +91,7 @@ public class ExceptionTranslationFilter extends GenericFilterBean {
 
 	private RequestCache requestCache = new HttpSessionRequestCache();
 
-	private final MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
+	protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
 
 	public ExceptionTranslationFilter(AuthenticationEntryPoint authenticationEntryPoint) {
 		this(authenticationEntryPoint, new HttpSessionRequestCache());
@@ -226,6 +228,15 @@ public class ExceptionTranslationFilter extends GenericFilterBean {
 		this.throwableAnalyzer = throwableAnalyzer;
 	}
 
+	/**
+	 * @since 5.5
+	 */
+	@Override
+	public void setMessageSource(MessageSource messageSource) {
+		Assert.notNull(messageSource, "messageSource cannot be null");
+		this.messages = new MessageSourceAccessor(messageSource);
+	}
+
 	/**
 	 * Default implementation of <code>ThrowableAnalyzer</code> which is capable of also
 	 * unwrapping <code>ServletException</code>s.

+ 8 - 2
web/src/main/java/org/springframework/security/web/authentication/preauth/x509/SubjectDnX509PrincipalExtractor.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2016 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -24,6 +24,7 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
 import org.springframework.context.MessageSource;
+import org.springframework.context.MessageSourceAware;
 import org.springframework.context.support.MessageSourceAccessor;
 import org.springframework.core.log.LogMessage;
 import org.springframework.security.authentication.BadCredentialsException;
@@ -43,7 +44,7 @@ import org.springframework.util.Assert;
  *
  * @author Luke Taylor
  */
-public class SubjectDnX509PrincipalExtractor implements X509PrincipalExtractor {
+public class SubjectDnX509PrincipalExtractor implements X509PrincipalExtractor, MessageSourceAware {
 
 	protected final Log logger = LogFactory.getLog(getClass());
 
@@ -88,7 +89,12 @@ public class SubjectDnX509PrincipalExtractor implements X509PrincipalExtractor {
 		this.subjectDnPattern = Pattern.compile(subjectDnRegex, Pattern.CASE_INSENSITIVE);
 	}
 
+	/**
+	 * @since 5.5
+	 */
+	@Override
 	public void setMessageSource(MessageSource messageSource) {
+		Assert.notNull(messageSource, "messageSource cannot be null");
 		this.messages = new MessageSourceAccessor(messageSource);
 	}
 

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

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2017 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -30,6 +30,8 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
 import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.MessageSource;
+import org.springframework.context.MessageSourceAware;
 import org.springframework.context.support.MessageSourceAccessor;
 import org.springframework.core.log.LogMessage;
 import org.springframework.security.authentication.AccountStatusException;
@@ -59,7 +61,8 @@ import org.springframework.util.StringUtils;
  * @author Onur Kagan Ozcan
  * @since 2.0
  */
-public abstract class AbstractRememberMeServices implements RememberMeServices, InitializingBean, LogoutHandler {
+public abstract class AbstractRememberMeServices
+		implements RememberMeServices, InitializingBean, LogoutHandler, MessageSourceAware {
 
 	public static final String SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY = "remember-me";
 
@@ -71,7 +74,7 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
 
 	protected final Log logger = LogFactory.getLog(getClass());
 
-	protected final MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
+	protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
 
 	private UserDetailsService userDetailsService;
 
@@ -481,4 +484,13 @@ public abstract class AbstractRememberMeServices implements RememberMeServices,
 		this.authoritiesMapper = authoritiesMapper;
 	}
 
+	/**
+	 * @since 5.5
+	 */
+	@Override
+	public void setMessageSource(MessageSource messageSource) {
+		Assert.notNull(messageSource, "messageSource cannot be null");
+		this.messages = new MessageSourceAccessor(messageSource);
+	}
+
 }

+ 20 - 1
web/src/test/java/org/springframework/security/web/access/ExceptionTranslationFilterTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2004-2016 the original author or authors.
+ * Copyright 2004-2020 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.
@@ -29,6 +29,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import org.springframework.context.MessageSource;
 import org.springframework.context.i18n.LocaleContextHolder;
 import org.springframework.mock.web.MockHttpServletRequest;
 import org.springframework.mock.web.MockHttpServletResponse;
@@ -50,8 +51,10 @@ 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.ArgumentMatchers.eq;
 import static org.mockito.BDDMockito.willThrow;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 
 /**
@@ -284,6 +287,22 @@ public class ExceptionTranslationFilterTests {
 		verifyZeroInteractions(this.mockEntryPoint);
 	}
 
+	@Test
+	public void setMessageSourceWhenNullThenThrowsException() {
+		ExceptionTranslationFilter filter = new ExceptionTranslationFilter(this.mockEntryPoint);
+		assertThatIllegalArgumentException().isThrownBy(() -> filter.setMessageSource(null));
+	}
+
+	@Test
+	public void setMessageSourceWhenNotNullThenCanGet() {
+		MessageSource source = mock(MessageSource.class);
+		ExceptionTranslationFilter filter = new ExceptionTranslationFilter(this.mockEntryPoint);
+		filter.setMessageSource(source);
+		String code = "code";
+		filter.messages.getMessage(code);
+		verify(source).getMessage(eq(code), any(), any());
+	}
+
 	private AuthenticationEntryPoint mockEntryPoint = (request, response, authException) -> response
 			.sendRedirect(request.getContextPath() + "/login.jsp");
 

+ 20 - 3
web/src/test/java/org/springframework/security/web/authentication/preauth/x509/SubjectDnX509PrincipalExtractorTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2016 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -19,12 +19,16 @@ package org.springframework.security.web.authentication.preauth.x509;
 import org.junit.Before;
 import org.junit.Test;
 
+import org.springframework.context.MessageSource;
 import org.springframework.security.authentication.BadCredentialsException;
-import org.springframework.security.core.SpringSecurityMessageSource;
 
 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.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 
 /**
  * @author Luke Taylor
@@ -36,7 +40,6 @@ public class SubjectDnX509PrincipalExtractorTests {
 	@Before
 	public void setUp() {
 		this.extractor = new SubjectDnX509PrincipalExtractor();
-		this.extractor.setMessageSource(new SpringSecurityMessageSource());
 	}
 
 	@Test
@@ -71,4 +74,18 @@ public class SubjectDnX509PrincipalExtractorTests {
 		assertThat(principal).isEqualTo("Duke");
 	}
 
+	@Test
+	public void setMessageSourceWhenNullThenThrowsException() {
+		assertThatIllegalArgumentException().isThrownBy(() -> this.extractor.setMessageSource(null));
+	}
+
+	@Test
+	public void setMessageSourceWhenNotNullThenCanGet() {
+		MessageSource source = mock(MessageSource.class);
+		this.extractor.setMessageSource(source);
+		String code = "code";
+		this.extractor.messages.getMessage(code);
+		verify(source).getMessage(eq(code), any(), any());
+	}
+
 }

+ 23 - 1
web/src/test/java/org/springframework/security/web/authentication/rememberme/AbstractRememberMeServicesTests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2017 the original author or authors.
+ * Copyright 2002-2020 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.
@@ -28,6 +28,7 @@ import org.powermock.core.classloader.annotations.PowerMockIgnore;
 import org.powermock.core.classloader.annotations.PrepareOnlyThisForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
 
+import org.springframework.context.MessageSource;
 import org.springframework.mock.web.MockHttpServletRequest;
 import org.springframework.mock.web.MockHttpServletResponse;
 import org.springframework.security.authentication.AccountStatusUserDetailsChecker;
@@ -44,6 +45,11 @@ 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.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 
 /**
  * @author Luke Taylor
@@ -411,6 +417,22 @@ public class AbstractRememberMeServicesTests {
 		assertThat(cookie.getDomain()).isEqualTo("spring.io");
 	}
 
+	@Test
+	public void setMessageSourceWhenNullThenThrowsException() {
+		MockRememberMeServices services = new MockRememberMeServices();
+		assertThatIllegalArgumentException().isThrownBy(() -> services.setMessageSource(null));
+	}
+
+	@Test
+	public void setMessageSourceWhenNotNullThenCanGet() {
+		MessageSource source = mock(MessageSource.class);
+		MockRememberMeServices services = new MockRememberMeServices();
+		services.setMessageSource(source);
+		String code = "code";
+		services.messages.getMessage(code);
+		verify(source).getMessage(eq(code), any(), any());
+	}
+
 	private Cookie[] createLoginCookie(String cookieToken) {
 		MockRememberMeServices services = new MockRememberMeServices(this.uds);
 		Cookie cookie = new Cookie(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY,