mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-07-06 18:52:13 +00:00
Add Request Path Extraction Support
Closes gh-13256
This commit is contained in:
parent
b82bd471bd
commit
ec02c22459
@ -17,6 +17,7 @@
|
|||||||
package org.springframework.security.config.annotation.web.configurers;
|
package org.springframework.security.config.annotation.web.configurers;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import io.micrometer.observation.ObservationRegistry;
|
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.AbstractRequestMatcherRegistry;
|
||||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||||
import org.springframework.security.config.core.GrantedAuthorityDefaults;
|
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.AuthorizationFilter;
|
||||||
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
|
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
|
||||||
import org.springframework.security.web.access.intercept.RequestMatcherDelegatingAuthorizationManager;
|
import org.springframework.security.web.access.intercept.RequestMatcherDelegatingAuthorizationManager;
|
||||||
@ -387,6 +389,21 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
|||||||
return access(AuthenticatedAuthorizationManager.anonymous());
|
return access(AuthenticatedAuthorizationManager.anonymous());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify that a path variable in URL to be compared.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* For example, <pre>
|
||||||
|
* requestMatchers("/user/{username}").hasVariable("username").equalTo(Authentication::getName)
|
||||||
|
* </pre>
|
||||||
|
* @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}.
|
* Allows specifying a custom {@link AuthorizationManager}.
|
||||||
* @param manager the {@link AuthorizationManager} to use
|
* @param manager the {@link AuthorizationManager} to use
|
||||||
@ -401,6 +418,41 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
|||||||
: AuthorizeHttpRequestsConfigurer.this.addMapping(this.matchers, manager);
|
: AuthorizeHttpRequestsConfigurer.this.addMapping(this.matchers, manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object that allows configuring {@link RequestMatcher}s with URI path
|
||||||
|
* variables
|
||||||
|
*
|
||||||
|
* @author Taehong Kim
|
||||||
|
* @since 6.3
|
||||||
|
*/
|
||||||
|
public final class AuthorizedUrlVariable {
|
||||||
|
|
||||||
|
private final String variable;
|
||||||
|
|
||||||
|
private AuthorizedUrlVariable(String variable) {
|
||||||
|
this.variable = variable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares the value of a path variable in the URI with an `Authentication`
|
||||||
|
* attribute
|
||||||
|
* <p>
|
||||||
|
* For example, <pre>
|
||||||
|
* requestMatchers("/user/{username}").hasVariable("username").equalTo(Authentication::getName));
|
||||||
|
* </pre>
|
||||||
|
* @param function a function to get value from {@link Authentication}.
|
||||||
|
* @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
|
||||||
|
* customization.
|
||||||
|
*/
|
||||||
|
public AuthorizationManagerRequestMatcherRegistry equalTo(Function<Authentication, String> function) {
|
||||||
|
return access((auth, requestContext) -> {
|
||||||
|
String value = requestContext.getVariables().get(this.variable);
|
||||||
|
return new AuthorizationDecision(function.apply(auth.get()).equals(value));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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.core.GrantedAuthorityDefaults;
|
||||||
import org.springframework.security.config.test.SpringTestContext;
|
import org.springframework.security.config.test.SpringTestContext;
|
||||||
import org.springframework.security.config.test.SpringTestContextExtension;
|
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.AuthorityUtils;
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
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.core.userdetails.UserDetailsService;
|
||||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
@ -543,6 +545,17 @@ public class AuthorizeHttpRequestsConfigurerTests {
|
|||||||
this.mvc.perform(request).andExpect(status().isOk());
|
this.mvc.perform(request).andExpect(status().isOk());
|
||||||
request = get("/user/deny");
|
request = get("/user/deny");
|
||||||
this.mvc.perform(request).andExpect(status().isUnauthorized());
|
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) {
|
private static RequestPostProcessor remoteAddress(String remoteAddress) {
|
||||||
@ -1067,6 +1080,7 @@ public class AuthorizeHttpRequestsConfigurerTests {
|
|||||||
.httpBasic(withDefaults())
|
.httpBasic(withDefaults())
|
||||||
.authorizeHttpRequests((requests) -> requests
|
.authorizeHttpRequests((requests) -> requests
|
||||||
.requestMatchers("/user/{username}").access(new WebExpressionAuthorizationManager("#username == 'user'"))
|
.requestMatchers("/user/{username}").access(new WebExpressionAuthorizationManager("#username == 'user'"))
|
||||||
|
.requestMatchers("/v2/user/{username}").hasVariable("username").equalTo(Authentication::getName)
|
||||||
);
|
);
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
return http.build();
|
return http.build();
|
||||||
@ -1080,6 +1094,11 @@ public class AuthorizeHttpRequestsConfigurerTests {
|
|||||||
return username;
|
return username;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequestMapping("/v2/user/{username}")
|
||||||
|
String pathV2(@PathVariable("username") String username) {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -35,14 +35,14 @@ public class TestAuthentication extends PasswordEncodedUser {
|
|||||||
AuthorityUtils.createAuthorityList("ROLE_USER"));
|
AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||||
|
|
||||||
public static Authentication authenticatedAdmin() {
|
public static Authentication authenticatedAdmin() {
|
||||||
return autheticated(admin());
|
return authenticated(admin());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Authentication authenticatedUser() {
|
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());
|
return UsernamePasswordAuthenticationToken.authenticated(user, null, user.getAuthorities());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user