Skip to content

Commit d6f5c6e

Browse files
committed
Add remaining methods from ExpressionUrlAuthorizationConfigurer to AuthorizeHttpRequestsConfigurer
- Added fullyAuthenticated - Added rememberMe - Added anonymous Closes gh-11360
1 parent ce67fb0 commit d6f5c6e

File tree

4 files changed

+346
-10
lines changed

4 files changed

+346
-10
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurer.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,39 @@ public AuthorizationManagerRequestMatcherRegistry authenticated() {
318318
return access(AuthenticatedAuthorizationManager.authenticated());
319319
}
320320

321+
/**
322+
* Specify that URLs are allowed by users who have authenticated and were not
323+
* "remembered".
324+
* @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
325+
* customization
326+
* @since 5.8
327+
* @see RememberMeConfigurer
328+
*/
329+
public AuthorizationManagerRequestMatcherRegistry fullyAuthenticated() {
330+
return access(AuthenticatedAuthorizationManager.fullyAuthenticated());
331+
}
332+
333+
/**
334+
* Specify that URLs are allowed by users that have been remembered.
335+
* @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
336+
* customization
337+
* @since 5.8
338+
* @see RememberMeConfigurer
339+
*/
340+
public AuthorizationManagerRequestMatcherRegistry rememberMe() {
341+
return access(AuthenticatedAuthorizationManager.rememberMe());
342+
}
343+
344+
/**
345+
* Specify that URLs are allowed by anonymous users.
346+
* @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
347+
* customization
348+
* @since 5.8
349+
*/
350+
public AuthorizationManagerRequestMatcherRegistry anonymous() {
351+
return access(AuthenticatedAuthorizationManager.anonymous());
352+
}
353+
321354
/**
322355
* Allows specifying a custom {@link AuthorizationManager}.
323356
* @param manager the {@link AuthorizationManager} to use

config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
import org.springframework.beans.factory.annotation.Autowired;
2828
import org.springframework.context.annotation.Bean;
2929
import org.springframework.context.annotation.Configuration;
30+
import org.springframework.security.authentication.RememberMeAuthenticationToken;
31+
import org.springframework.security.authentication.TestAuthentication;
3032
import org.springframework.security.authorization.AuthorizationDecision;
3133
import org.springframework.security.authorization.AuthorizationEventPublisher;
3234
import org.springframework.security.authorization.AuthorizationManager;
@@ -36,7 +38,10 @@
3638
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
3739
import org.springframework.security.config.test.SpringTestContext;
3840
import org.springframework.security.config.test.SpringTestContextExtension;
41+
import org.springframework.security.core.authority.AuthorityUtils;
3942
import org.springframework.security.core.authority.SimpleGrantedAuthority;
43+
import org.springframework.security.core.userdetails.UserDetailsService;
44+
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
4045
import org.springframework.security.web.SecurityFilterChain;
4146
import org.springframework.security.web.access.expression.WebExpressionAuthorizationManager;
4247
import org.springframework.security.web.access.intercept.AuthorizationFilter;
@@ -58,6 +63,7 @@
5863
import static org.mockito.Mockito.spy;
5964
import static org.mockito.Mockito.verify;
6065
import static org.springframework.security.config.Customizer.withDefaults;
66+
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
6167
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
6268
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
6369
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@@ -493,6 +499,50 @@ private static RequestPostProcessor remoteAddress(String remoteAddress) {
493499
};
494500
}
495501

502+
@Test
503+
public void getWhenFullyAuthenticatedConfiguredAndRememberMeTokenThenRespondsWithUnauthorized() throws Exception {
504+
this.spring.register(FullyAuthenticatedConfig.class, BasicController.class).autowire();
505+
RememberMeAuthenticationToken rememberMe = new RememberMeAuthenticationToken("key", "user",
506+
AuthorityUtils.createAuthorityList("ROLE_USER"));
507+
MockHttpServletRequestBuilder requestWithRememberMe = get("/").with(authentication(rememberMe));
508+
this.mvc.perform(requestWithRememberMe).andExpect(status().isUnauthorized());
509+
}
510+
511+
@Test
512+
public void getWhenFullyAuthenticatedConfiguredAndUserThenRespondsWithOk() throws Exception {
513+
this.spring.register(FullyAuthenticatedConfig.class, BasicController.class).autowire();
514+
MockHttpServletRequestBuilder requestWithUser = get("/").with(user("user").roles("USER"));
515+
this.mvc.perform(requestWithUser).andExpect(status().isOk());
516+
}
517+
518+
@Test
519+
public void getWhenRememberMeConfiguredAndNoUserThenRespondsWithUnauthorized() throws Exception {
520+
this.spring.register(RememberMeConfig.class, BasicController.class).autowire();
521+
this.mvc.perform(get("/")).andExpect(status().isUnauthorized());
522+
}
523+
524+
@Test
525+
public void getWhenRememberMeConfiguredAndRememberMeTokenThenRespondsWithOk() throws Exception {
526+
this.spring.register(RememberMeConfig.class, BasicController.class).autowire();
527+
RememberMeAuthenticationToken rememberMe = new RememberMeAuthenticationToken("key", "user",
528+
AuthorityUtils.createAuthorityList("ROLE_USER"));
529+
MockHttpServletRequestBuilder requestWithRememberMe = get("/").with(authentication(rememberMe));
530+
this.mvc.perform(requestWithRememberMe).andExpect(status().isOk());
531+
}
532+
533+
@Test
534+
public void getWhenAnonymousConfiguredAndAnonymousUserThenRespondsWithOk() throws Exception {
535+
this.spring.register(AnonymousConfig.class, BasicController.class).autowire();
536+
this.mvc.perform(get("/")).andExpect(status().isOk());
537+
}
538+
539+
@Test
540+
public void getWhenAnonymousConfiguredAndLoggedInUserThenRespondsWithForbidden() throws Exception {
541+
this.spring.register(AnonymousConfig.class, BasicController.class).autowire();
542+
MockHttpServletRequestBuilder requestWithUser = get("/").with(user("user"));
543+
this.mvc.perform(requestWithUser).andExpect(status().isForbidden());
544+
}
545+
496546
@EnableWebSecurity
497547
static class NoRequestsConfig {
498548

@@ -888,6 +938,74 @@ String path(@PathVariable("username") String username) {
888938

889939
}
890940

941+
@EnableWebSecurity
942+
static class FullyAuthenticatedConfig {
943+
944+
@Bean
945+
SecurityFilterChain chain(HttpSecurity http) throws Exception {
946+
// @formatter:off
947+
http
948+
.httpBasic()
949+
.and()
950+
.rememberMe()
951+
.and()
952+
.authorizeHttpRequests((requests) -> requests
953+
.anyRequest().fullyAuthenticated()
954+
);
955+
// @formatter:on
956+
return http.build();
957+
}
958+
959+
@Bean
960+
UserDetailsService userDetailsService() {
961+
return new InMemoryUserDetailsManager(TestAuthentication.user());
962+
}
963+
964+
}
965+
966+
@EnableWebSecurity
967+
static class RememberMeConfig {
968+
969+
@Bean
970+
SecurityFilterChain chain(HttpSecurity http) throws Exception {
971+
// @formatter:off
972+
http
973+
.httpBasic()
974+
.and()
975+
.rememberMe()
976+
.and()
977+
.authorizeHttpRequests((requests) -> requests
978+
.anyRequest().rememberMe()
979+
);
980+
// @formatter:on
981+
return http.build();
982+
}
983+
984+
@Bean
985+
UserDetailsService userDetailsService() {
986+
return new InMemoryUserDetailsManager(TestAuthentication.user());
987+
}
988+
989+
}
990+
991+
@EnableWebSecurity
992+
static class AnonymousConfig {
993+
994+
@Bean
995+
SecurityFilterChain chain(HttpSecurity http) throws Exception {
996+
// @formatter:off
997+
http
998+
.httpBasic()
999+
.and()
1000+
.authorizeHttpRequests((requests) -> requests
1001+
.anyRequest().anonymous()
1002+
);
1003+
// @formatter:on
1004+
return http.build();
1005+
}
1006+
1007+
}
1008+
8911009
@Configuration
8921010
static class AuthorizationEventPublisherConfig {
8931011

core/src/main/java/org/springframework/security/authorization/AuthenticatedAuthorizationManager.java

Lines changed: 112 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
2121
import org.springframework.security.authentication.AuthenticationTrustResolver;
2222
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
2323
import org.springframework.security.core.Authentication;
24+
import org.springframework.util.Assert;
2425

2526
/**
2627
* An {@link AuthorizationManager} that determines if the current user is authenticated.
@@ -31,7 +32,35 @@
3132
*/
3233
public final class AuthenticatedAuthorizationManager<T> implements AuthorizationManager<T> {
3334

34-
private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
35+
private final AbstractAuthorizationStrategy authorizationStrategy;
36+
37+
/**
38+
* Creates an instance that determines if the current user is authenticated, this is
39+
* the same as calling {@link #authenticated()} factory method.
40+
*
41+
* @since 5.8
42+
* @see #authenticated()
43+
* @see #fullyAuthenticated()
44+
* @see #rememberMe()
45+
* @see #anonymous()
46+
*/
47+
public AuthenticatedAuthorizationManager() {
48+
this(new AuthenticatedAuthorizationStrategy());
49+
}
50+
51+
private AuthenticatedAuthorizationManager(AbstractAuthorizationStrategy authorizationStrategy) {
52+
this.authorizationStrategy = authorizationStrategy;
53+
}
54+
55+
/**
56+
* Sets the {@link AuthenticationTrustResolver} to be used. Default is
57+
* {@link AuthenticationTrustResolverImpl}. Cannot be null.
58+
* @param trustResolver the {@link AuthenticationTrustResolver} to use
59+
* @since 5.8
60+
*/
61+
public void setTrustResolver(AuthenticationTrustResolver trustResolver) {
62+
this.authorizationStrategy.setTrustResolver(trustResolver);
63+
}
3564

3665
/**
3766
* Creates an instance of {@link AuthenticatedAuthorizationManager}.
@@ -43,24 +72,98 @@ public static <T> AuthenticatedAuthorizationManager<T> authenticated() {
4372
}
4473

4574
/**
46-
* Determines if the current user is authorized by evaluating if the
47-
* {@link Authentication} is not anonymous and authenticated.
75+
* Creates an instance of {@link AuthenticatedAuthorizationManager} that determines if
76+
* the {@link Authentication} is authenticated without using remember me.
77+
* @param <T> the type of object being authorized
78+
* @return the new instance
79+
* @since 5.8
80+
*/
81+
public static <T> AuthenticatedAuthorizationManager<T> fullyAuthenticated() {
82+
return new AuthenticatedAuthorizationManager<>(new FullyAuthenticatedAuthorizationStrategy());
83+
}
84+
85+
/**
86+
* Creates an instance of {@link AuthenticatedAuthorizationManager} that determines if
87+
* the {@link Authentication} is authenticated using remember me.
88+
* @param <T> the type of object being authorized
89+
* @return the new instance
90+
* @since 5.8
91+
*/
92+
public static <T> AuthenticatedAuthorizationManager<T> rememberMe() {
93+
return new AuthenticatedAuthorizationManager<>(new RememberMeAuthorizationStrategy());
94+
}
95+
96+
/**
97+
* Creates an instance of {@link AuthenticatedAuthorizationManager} that determines if
98+
* the {@link Authentication} is anonymous.
99+
* @param <T> the type of object being authorized
100+
* @return the new instance
101+
* @since 5.8
102+
*/
103+
public static <T> AuthenticatedAuthorizationManager<T> anonymous() {
104+
return new AuthenticatedAuthorizationManager<>(new AnonymousAuthorizationStrategy());
105+
}
106+
107+
/**
108+
* Determines if the current user is authorized according to the given strategy.
48109
* @param authentication the {@link Supplier} of the {@link Authentication} to check
49110
* @param object the {@link T} object to check
50111
* @return an {@link AuthorizationDecision}
51112
*/
52113
@Override
53114
public AuthorizationDecision check(Supplier<Authentication> authentication, T object) {
54-
boolean granted = isGranted(authentication.get());
115+
boolean granted = this.authorizationStrategy.isGranted(authentication.get());
55116
return new AuthorizationDecision(granted);
56117
}
57118

58-
private boolean isGranted(Authentication authentication) {
59-
return authentication != null && isNotAnonymous(authentication) && authentication.isAuthenticated();
119+
private abstract static class AbstractAuthorizationStrategy {
120+
121+
AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
122+
123+
private void setTrustResolver(AuthenticationTrustResolver trustResolver) {
124+
Assert.notNull(trustResolver, "trustResolver cannot be null");
125+
this.trustResolver = trustResolver;
126+
}
127+
128+
abstract boolean isGranted(Authentication authentication);
129+
60130
}
61131

62-
private boolean isNotAnonymous(Authentication authentication) {
63-
return !this.trustResolver.isAnonymous(authentication);
132+
private static class AuthenticatedAuthorizationStrategy extends AbstractAuthorizationStrategy {
133+
134+
@Override
135+
boolean isGranted(Authentication authentication) {
136+
return authentication != null && !this.trustResolver.isAnonymous(authentication)
137+
&& authentication.isAuthenticated();
138+
}
139+
140+
}
141+
142+
private static final class FullyAuthenticatedAuthorizationStrategy extends AuthenticatedAuthorizationStrategy {
143+
144+
@Override
145+
boolean isGranted(Authentication authentication) {
146+
return super.isGranted(authentication) && !this.trustResolver.isRememberMe(authentication);
147+
}
148+
149+
}
150+
151+
private static final class AnonymousAuthorizationStrategy extends AbstractAuthorizationStrategy {
152+
153+
@Override
154+
boolean isGranted(Authentication authentication) {
155+
return this.trustResolver.isAnonymous(authentication);
156+
}
157+
158+
}
159+
160+
private static final class RememberMeAuthorizationStrategy extends AbstractAuthorizationStrategy {
161+
162+
@Override
163+
boolean isGranted(Authentication authentication) {
164+
return this.trustResolver.isRememberMe(authentication);
165+
}
166+
64167
}
65168

66169
}

0 commit comments

Comments
 (0)