Browse Source

Add AuthenticationTrustResolver.isAuthenticated

Rob Winch 1 năm trước cách đây
mục cha
commit
750cb30ce4
16 tập tin đã thay đổi với 123 bổ sung26 xóa
  1. 5 3
      cas/src/main/java/org/springframework/security/cas/web/CasAuthenticationFilter.java
  2. 4 1
      config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java
  3. 4 3
      config/src/test/kotlin/org/springframework/security/config/annotation/web/SessionManagementDslTests.kt
  4. 1 1
      core/src/main/java/org/springframework/security/access/expression/SecurityExpressionRoot.java
  5. 16 4
      core/src/main/java/org/springframework/security/authentication/AuthenticationTrustResolver.java
  6. 2 3
      core/src/main/java/org/springframework/security/authorization/AuthenticatedAuthorizationManager.java
  7. 24 0
      core/src/test/java/org/springframework/security/access/expression/SecurityExpressionRootTests.java
  8. 53 0
      core/src/test/java/org/springframework/security/authentication/AuthenticationTrustResolverImplTests.java
  9. 2 1
      messaging/src/test/java/org/springframework/security/messaging/access/expression/DefaultMessageSecurityExpressionHandlerTests.java
  10. 1 2
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/AuthenticatedPrincipalOAuth2AuthorizedClientRepository.java
  11. 1 2
      oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/server/AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository.java
  12. 1 1
      web/src/main/java/org/springframework/security/web/server/authorization/ExceptionTranslationWebFilter.java
  13. 1 1
      web/src/main/java/org/springframework/security/web/servletapi/SecurityContextHolderAwareRequestWrapper.java
  14. 1 1
      web/src/main/java/org/springframework/security/web/session/SessionManagementFilter.java
  15. 1 1
      web/src/test/java/org/springframework/security/web/servletapi/SecurityContextHolderAwareRequestWrapperTests.java
  16. 6 2
      web/src/test/java/org/springframework/security/web/session/SessionManagementFilterTests.java

+ 5 - 3
cas/src/main/java/org/springframework/security/cas/web/CasAuthenticationFilter.java

@@ -27,8 +27,9 @@ import org.apereo.cas.client.util.WebUtils;
 import org.apereo.cas.client.validation.TicketValidator;
 
 import org.springframework.core.log.LogMessage;
-import org.springframework.security.authentication.AnonymousAuthenticationToken;
 import org.springframework.security.authentication.AuthenticationDetailsSource;
+import org.springframework.security.authentication.AuthenticationTrustResolver;
+import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
 import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
 import org.springframework.security.cas.ServiceProperties;
 import org.springframework.security.cas.authentication.CasServiceTicketAuthenticationToken;
@@ -195,6 +196,8 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
 
 	private SecurityContextRepository securityContextRepository = new HttpSessionSecurityContextRepository();
 
+	private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
+
 	public CasAuthenticationFilter() {
 		super("/login/cas");
 		setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler());
@@ -337,8 +340,7 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
 	 */
 	private boolean authenticated() {
 		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
-		return authentication != null && authentication.isAuthenticated()
-				&& !(authentication instanceof AnonymousAuthenticationToken);
+		return this.trustResolver.isAuthenticated(authentication);
 	}
 
 	/**

+ 4 - 1
config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java

@@ -29,6 +29,7 @@ import jakarta.servlet.http.HttpServletResponse;
 import jakarta.servlet.http.HttpSession;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Answers;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
@@ -82,6 +83,7 @@ import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.withSettings;
 import static org.springframework.security.config.Customizer.withDefaults;
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
@@ -304,7 +306,8 @@ public class SessionManagementConfigurerTests {
 	@Test
 	public void getWhenAnonymousRequestAndTrustResolverSharedObjectReturnsAnonymousFalseThenSessionIsSaved()
 			throws Exception {
-		SharedTrustResolverConfig.TR = mock(AuthenticationTrustResolver.class);
+		SharedTrustResolverConfig.TR = mock(AuthenticationTrustResolver.class,
+				withSettings().defaultAnswer(Answers.CALLS_REAL_METHODS));
 		given(SharedTrustResolverConfig.TR.isAnonymous(any())).willReturn(false);
 		this.spring.register(SharedTrustResolverConfig.class).autowire();
 		MvcResult mvcResult = this.mvc.perform(get("/")).andReturn();

+ 4 - 3
config/src/test/kotlin/org/springframework/security/config/annotation/web/SessionManagementDslTests.kt

@@ -28,6 +28,7 @@ import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.context.annotation.Bean
 import org.springframework.context.annotation.Configuration
 import org.springframework.mock.web.MockHttpSession
+import org.springframework.security.authentication.TestingAuthenticationToken
 import org.springframework.security.config.annotation.web.builders.HttpSecurity
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
 import org.springframework.security.config.http.SessionCreationPolicy
@@ -118,7 +119,7 @@ class SessionManagementDslTests {
     @Test
     fun `session management when session authentication error url then redirected to url`() {
         this.spring.register(SessionAuthenticationErrorUrlConfig::class.java).autowire()
-        val authentication: Authentication = mockk()
+        val authentication: Authentication = TestingAuthenticationToken("user", "password", "ROLE_USER")
         val session: MockHttpSession = mockk(relaxed = true)
         every { session.changeSessionId() } throws SessionAuthenticationException("any SessionAuthenticationException")
         every<Any?> { session.getAttribute(any()) } returns null
@@ -150,7 +151,7 @@ class SessionManagementDslTests {
     @Test
     fun `session management when session authentication failure handler then handler used`() {
         this.spring.register(SessionAuthenticationFailureHandlerConfig::class.java).autowire()
-        val authentication: Authentication = mockk()
+        val authentication: Authentication = TestingAuthenticationToken("user", "password", "ROLE_USER")
         val session: MockHttpSession = mockk(relaxed = true)
         every { session.changeSessionId() } throws SessionAuthenticationException("any SessionAuthenticationException")
         every<Any?> { session.getAttribute(any()) } returns null
@@ -210,7 +211,7 @@ class SessionManagementDslTests {
     fun `session management when session authentication strategy then strategy used`() {
         this.spring.register(SessionAuthenticationStrategyConfig::class.java).autowire()
         mockkObject(SessionAuthenticationStrategyConfig.STRATEGY)
-        val authentication: Authentication = mockk(relaxed = true)
+        val authentication: Authentication = TestingAuthenticationToken("user", "password", "ROLE_USER")
         val session: MockHttpSession = mockk(relaxed = true)
         every { session.changeSessionId() } throws SessionAuthenticationException("any SessionAuthenticationException")
         every<Any?> { session.getAttribute(any()) } returns null

+ 1 - 1
core/src/main/java/org/springframework/security/access/expression/SecurityExpressionRoot.java

@@ -147,7 +147,7 @@ public abstract class SecurityExpressionRoot implements SecurityExpressionOperat
 
 	@Override
 	public final boolean isAuthenticated() {
-		return !isAnonymous();
+		return this.trustResolver.isAuthenticated(getAuthentication());
 	}
 
 	@Override

+ 16 - 4
core/src/main/java/org/springframework/security/authentication/AuthenticationTrustResolver.java

@@ -61,13 +61,25 @@ public interface AuthenticationTrustResolver {
 	 * <p>
 	 * @param authentication to test (may be <code>null</code> in which case the method
 	 * will always return <code>false</code>)
-	 * @return <code>true</code> the passed authentication token represented an anonymous
-	 * principal and is authenticated using a remember-me token, <code>false</code>
-	 * otherwise
+	 * @return <code>true</code> the passed authentication token represented an
+	 * authenticated user ({@link #isAuthenticated(Authentication)} and not
+	 * {@link #isRememberMe(Authentication)}, <code>false</code> otherwise
 	 * @since 6.1
 	 */
 	default boolean isFullyAuthenticated(Authentication authentication) {
-		return !isAnonymous(authentication) && !isRememberMe(authentication);
+		return isAuthenticated(authentication) && !isRememberMe(authentication);
+	}
+
+	/**
+	 * Checks if the {@link Authentication} is not null, authenticated, and not anonymous.
+	 * @param authentication the {@link Authentication} to check.
+	 * @return true if the {@link Authentication} is not null,
+	 * {@link #isAnonymous(Authentication)} returns false, &
+	 * {@link Authentication#isAuthenticated()} is true.
+	 * @since 6.1.7
+	 */
+	default boolean isAuthenticated(Authentication authentication) {
+		return authentication != null && authentication.isAuthenticated() && !isAnonymous(authentication);
 	}
 
 }

+ 2 - 3
core/src/main/java/org/springframework/security/authorization/AuthenticatedAuthorizationManager.java

@@ -133,8 +133,7 @@ public final class AuthenticatedAuthorizationManager<T> implements Authorization
 
 		@Override
 		boolean isGranted(Authentication authentication) {
-			return authentication != null && !this.trustResolver.isAnonymous(authentication)
-					&& authentication.isAuthenticated();
+			return this.trustResolver.isAuthenticated(authentication);
 		}
 
 	}
@@ -143,7 +142,7 @@ public final class AuthenticatedAuthorizationManager<T> implements Authorization
 
 		@Override
 		boolean isGranted(Authentication authentication) {
-			return authentication != null && this.trustResolver.isFullyAuthenticated(authentication);
+			return this.trustResolver.isFullyAuthenticated(authentication);
 		}
 
 	}

+ 24 - 0
core/src/test/java/org/springframework/security/access/expression/SecurityExpressionRootTests.java

@@ -25,6 +25,7 @@ import org.springframework.security.core.Authentication;
 import org.springframework.security.core.authority.AuthorityUtils;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
 import static org.mockito.BDDMockito.given;
 import static org.mockito.Mockito.mock;
 
@@ -134,4 +135,27 @@ public class SecurityExpressionRootTests {
 		assertThat(this.root.hasAnyAuthority("ROLE_A", "NOT")).isTrue();
 	}
 
+	@Test
+	void isAuthenticatedWhenAuthenticatedNullThenException() {
+		this.root = new SecurityExpressionRoot((Authentication) null) {
+		};
+		assertThatIllegalArgumentException().isThrownBy(() -> this.root.isAuthenticated());
+	}
+
+	@Test
+	void isAuthenticatedWhenTrustResolverFalseThenFalse() {
+		AuthenticationTrustResolver atr = mock(AuthenticationTrustResolver.class);
+		given(atr.isAuthenticated(JOE)).willReturn(false);
+		this.root.setTrustResolver(atr);
+		assertThat(this.root.isAuthenticated()).isFalse();
+	}
+
+	@Test
+	void isAuthenticatedWhenTrustResolverTrueThenTrue() {
+		AuthenticationTrustResolver atr = mock(AuthenticationTrustResolver.class);
+		given(atr.isAuthenticated(JOE)).willReturn(true);
+		this.root.setTrustResolver(atr);
+		assertThat(this.root.isAuthenticated()).isTrue();
+	}
+
 }

+ 53 - 0
core/src/test/java/org/springframework/security/authentication/AuthenticationTrustResolverImplTests.java

@@ -18,6 +18,7 @@ package org.springframework.security.authentication;
 
 import org.junit.jupiter.api.Test;
 
+import org.springframework.security.core.Authentication;
 import org.springframework.security.core.authority.AuthorityUtils;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -63,4 +64,56 @@ public class AuthenticationTrustResolverImplTests {
 		assertThat(trustResolver.getRememberMeClass()).isEqualTo(TestingAuthenticationToken.class);
 	}
 
+	@Test
+	void isAuthenticatedWhenAuthenticationNullThenFalse() {
+		AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
+		Authentication authentication = null;
+		assertThat(trustResolver.isAuthenticated(authentication)).isFalse();
+	}
+
+	@Test
+	void isAuthenticatedWhenAuthenticationNotAuthenticatedThenFalse() {
+		AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
+		TestingAuthenticationToken authentication = new TestingAuthenticationToken("user", "password");
+		assertThat(trustResolver.isAuthenticated(authentication)).isFalse();
+	}
+
+	@Test
+	void isAuthenticatedWhenAnonymousThenFalse() {
+		AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
+		AnonymousAuthenticationToken authentication = new AnonymousAuthenticationToken("key", "principal",
+				AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));
+		assertThat(trustResolver.isAuthenticated(authentication)).isFalse();
+	}
+
+	@Test
+	void isFullyAuthenticatedWhenAuthenticationNullThenFalse() {
+		AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
+		Authentication authentication = null;
+		assertThat(trustResolver.isFullyAuthenticated(authentication)).isFalse();
+	}
+
+	@Test
+	void isFullyAuthenticatedWhenAuthenticationNotAuthenticatedThenFalse() {
+		AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
+		TestingAuthenticationToken authentication = new TestingAuthenticationToken("user", "password");
+		assertThat(trustResolver.isFullyAuthenticated(authentication)).isFalse();
+	}
+
+	@Test
+	void isFullyAuthenticatedWhenAnonymousThenFalse() {
+		AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
+		AnonymousAuthenticationToken authentication = new AnonymousAuthenticationToken("key", "principal",
+				AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));
+		assertThat(trustResolver.isFullyAuthenticated(authentication)).isFalse();
+	}
+
+	@Test
+	void isFullyAuthenticatedWhenRememberMeThenFalse() {
+		AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
+		RememberMeAuthenticationToken authentication = new RememberMeAuthenticationToken("key", "user",
+				AuthorityUtils.createAuthorityList("ROLE_USER"));
+		assertThat(trustResolver.isFullyAuthenticated(authentication)).isFalse();
+	}
+
 }

+ 2 - 1
messaging/src/test/java/org/springframework/security/messaging/access/expression/DefaultMessageSecurityExpressionHandlerTests.java

@@ -22,6 +22,7 @@ import org.assertj.core.api.InstanceOfAssertFactories;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
 
@@ -50,7 +51,7 @@ import static org.mockito.Mockito.verifyNoInteractions;
 @ExtendWith(MockitoExtension.class)
 public class DefaultMessageSecurityExpressionHandlerTests {
 
-	@Mock
+	@Mock(answer = Answers.CALLS_REAL_METHODS)
 	AuthenticationTrustResolver trustResolver;
 
 	@Mock

+ 1 - 2
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/AuthenticatedPrincipalOAuth2AuthorizedClientRepository.java

@@ -107,8 +107,7 @@ public final class AuthenticatedPrincipalOAuth2AuthorizedClientRepository implem
 	}
 
 	private boolean isPrincipalAuthenticated(Authentication authentication) {
-		return authentication != null && !this.authenticationTrustResolver.isAnonymous(authentication)
-				&& authentication.isAuthenticated();
+		return this.authenticationTrustResolver.isAuthenticated(authentication);
 	}
 
 }

+ 1 - 2
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/server/AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository.java

@@ -106,8 +106,7 @@ public final class AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository
 	}
 
 	private boolean isPrincipalAuthenticated(Authentication authentication) {
-		return authentication != null && !this.authenticationTrustResolver.isAnonymous(authentication)
-				&& authentication.isAuthenticated();
+		return this.authenticationTrustResolver.isAuthenticated(authentication);
 	}
 
 }

+ 1 - 1
web/src/main/java/org/springframework/security/web/server/authorization/ExceptionTranslationWebFilter.java

@@ -52,7 +52,7 @@ public class ExceptionTranslationWebFilter implements WebFilter {
 		return chain.filter(exchange)
 			.onErrorResume(AccessDeniedException.class, (denied) -> exchange.getPrincipal()
 				.filter((principal) -> (!(principal instanceof Authentication) || (principal instanceof Authentication
-						&& !(this.authenticationTrustResolver.isAnonymous((Authentication) principal)))))
+						&& (this.authenticationTrustResolver.isAuthenticated((Authentication) principal)))))
 				.switchIfEmpty(commenceAuthentication(exchange,
 						new InsufficientAuthenticationException(
 								"Full authentication is required to access this resource")))

+ 1 - 1
web/src/main/java/org/springframework/security/web/servletapi/SecurityContextHolderAwareRequestWrapper.java

@@ -93,7 +93,7 @@ public class SecurityContextHolderAwareRequestWrapper extends HttpServletRequest
 	 */
 	private Authentication getAuthentication() {
 		Authentication auth = this.securityContextHolderStrategy.getContext().getAuthentication();
-		return (!this.trustResolver.isAnonymous(auth)) ? auth : null;
+		return (this.trustResolver.isAuthenticated(auth)) ? auth : null;
 	}
 
 	/**

+ 1 - 1
web/src/main/java/org/springframework/security/web/session/SessionManagementFilter.java

@@ -94,7 +94,7 @@ public class SessionManagementFilter extends GenericFilterBean {
 		request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
 		if (!this.securityContextRepository.containsContext(request)) {
 			Authentication authentication = this.securityContextHolderStrategy.getContext().getAuthentication();
-			if (authentication != null && !this.trustResolver.isAnonymous(authentication)) {
+			if (this.trustResolver.isAuthenticated(authentication)) {
 				// The user has been authenticated during the current request, so call the
 				// session strategy
 				try {

+ 1 - 1
web/src/test/java/org/springframework/security/web/servletapi/SecurityContextHolderAwareRequestWrapperTests.java

@@ -140,7 +140,7 @@ public class SecurityContextHolderAwareRequestWrapperTests {
 		String username = "authPrincipalUsername";
 		AuthenticatedPrincipal principal = mock(AuthenticatedPrincipal.class);
 		given(principal.getName()).willReturn(username);
-		Authentication auth = new TestingAuthenticationToken(principal, "user");
+		Authentication auth = new TestingAuthenticationToken(principal, "user", "ROLE_USER");
 		SecurityContextHolder.getContext().setAuthentication(auth);
 		MockHttpServletRequest request = new MockHttpServletRequest();
 		request.setRequestURI("/");

+ 6 - 2
web/src/test/java/org/springframework/security/web/session/SessionManagementFilterTests.java

@@ -21,6 +21,7 @@ import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Test;
+import org.mockito.Answers;
 
 import org.springframework.mock.web.MockFilterChain;
 import org.springframework.mock.web.MockHttpServletRequest;
@@ -42,6 +43,7 @@ import static org.mockito.BDDMockito.willThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.withSettings;
 
 /**
  * @author Luke Taylor
@@ -176,7 +178,8 @@ public class SessionManagementFilterTests {
 
 	@Test
 	public void customAuthenticationTrustResolver() throws Exception {
-		AuthenticationTrustResolver trustResolver = mock(AuthenticationTrustResolver.class);
+		AuthenticationTrustResolver trustResolver = mock(AuthenticationTrustResolver.class,
+				withSettings().defaultAnswer(Answers.CALLS_REAL_METHODS));
 		SecurityContextRepository repo = mock(SecurityContextRepository.class);
 		SessionManagementFilter filter = new SessionManagementFilter(repo);
 		filter.setTrustResolver(trustResolver);
@@ -194,7 +197,8 @@ public class SessionManagementFilterTests {
 	}
 
 	private void authenticateUser() {
-		SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "pass"));
+		SecurityContextHolder.getContext()
+			.setAuthentication(new TestingAuthenticationToken("user", "pass", "ROLE_USER"));
 	}
 
 }