diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurer.java index 7937143b31..82b2d32994 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurer.java @@ -17,6 +17,7 @@ package org.springframework.security.config.annotation.web.configurers; import java.util.List; +import java.util.function.Function; import java.util.function.Supplier; import io.micrometer.observation.ObservationRegistry; @@ -37,6 +38,7 @@ import org.springframework.security.config.annotation.ObjectPostProcessor; import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.core.GrantedAuthorityDefaults; +import org.springframework.security.core.Authentication; import org.springframework.security.web.access.intercept.AuthorizationFilter; import org.springframework.security.web.access.intercept.RequestAuthorizationContext; import org.springframework.security.web.access.intercept.RequestMatcherDelegatingAuthorizationManager; @@ -387,6 +389,21 @@ public final class AuthorizeHttpRequestsConfigurer + * For example,
+		 * requestMatchers("/user/{username}").hasVariable("username").equalTo(Authentication::getName)
+		 * 
+ * @param variable the variable in URL template to compare. + * @return {@link AuthorizedUrlVariable} for further customization. + * @since 6.3 + */ + public AuthorizedUrlVariable hasVariable(String variable) { + return new AuthorizedUrlVariable(variable); + } + /** * Allows specifying a custom {@link AuthorizationManager}. * @param manager the {@link AuthorizationManager} to use @@ -401,6 +418,41 @@ public final class AuthorizeHttpRequestsConfigurer + * For example,
+			 * requestMatchers("/user/{username}").hasVariable("username").equalTo(Authentication::getName));
+			 * 
+ * @param function a function to get value from {@link Authentication}. + * @return the {@link AuthorizationManagerRequestMatcherRegistry} for further + * customization. + */ + public AuthorizationManagerRequestMatcherRegistry equalTo(Function function) { + return access((auth, requestContext) -> { + String value = requestContext.getVariables().get(this.variable); + return new AuthorizationDecision(function.apply(auth.get()).equals(value)); + }); + } + + } + } } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java index 5f220a7a17..0aad4d777c 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java @@ -40,8 +40,10 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe import org.springframework.security.config.core.GrantedAuthorityDefaults; import org.springframework.security.config.test.SpringTestContext; import org.springframework.security.config.test.SpringTestContextExtension; +import org.springframework.security.core.Authentication; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.SecurityFilterChain; @@ -543,6 +545,17 @@ public class AuthorizeHttpRequestsConfigurerTests { this.mvc.perform(request).andExpect(status().isOk()); request = get("/user/deny"); this.mvc.perform(request).andExpect(status().isUnauthorized()); + + UserDetails user = TestAuthentication.withUsername("taehong").build(); + Authentication authentication = TestAuthentication.authenticated(user); + request = get("/v2/user/{username}", user.getUsername()).with(authentication(authentication)); + this.mvc.perform(request).andExpect(status().isOk()); + + request = get("/v2/user/{username}", "withNoAuthentication"); + this.mvc.perform(request).andExpect(status().isUnauthorized()); + + request = get("/v2/user/{username}", "another").with(authentication(authentication)); + this.mvc.perform(request).andExpect(status().isForbidden()); } private static RequestPostProcessor remoteAddress(String remoteAddress) { @@ -1067,6 +1080,7 @@ public class AuthorizeHttpRequestsConfigurerTests { .httpBasic(withDefaults()) .authorizeHttpRequests((requests) -> requests .requestMatchers("/user/{username}").access(new WebExpressionAuthorizationManager("#username == 'user'")) + .requestMatchers("/v2/user/{username}").hasVariable("username").equalTo(Authentication::getName) ); // @formatter:on return http.build(); @@ -1080,6 +1094,11 @@ public class AuthorizeHttpRequestsConfigurerTests { return username; } + @RequestMapping("/v2/user/{username}") + String pathV2(@PathVariable("username") String username) { + return username; + } + } } diff --git a/core/src/test/java/org/springframework/security/authentication/TestAuthentication.java b/core/src/test/java/org/springframework/security/authentication/TestAuthentication.java index a0faebee71..51c81e9626 100644 --- a/core/src/test/java/org/springframework/security/authentication/TestAuthentication.java +++ b/core/src/test/java/org/springframework/security/authentication/TestAuthentication.java @@ -35,14 +35,14 @@ public class TestAuthentication extends PasswordEncodedUser { AuthorityUtils.createAuthorityList("ROLE_USER")); public static Authentication authenticatedAdmin() { - return autheticated(admin()); + return authenticated(admin()); } public static Authentication authenticatedUser() { - return autheticated(user()); + return authenticated(user()); } - public static Authentication autheticated(UserDetails user) { + public static Authentication authenticated(UserDetails user) { return UsernamePasswordAuthenticationToken.authenticated(user, null, user.getAuthorities()); }