spring-security
spring-security copied to clipboard
codes in spring security docs fail to work
Describe the bug I tried all codes in https://docs.spring.io/spring-security/reference/servlet/authorization/authorize-http-requests.html, but they all failed to work
To Reproduce configure codes in a SecurityConfig.java file in my springboot, which is migrated from hello-security project downloaded from spring security docs. They have all kinds of errors like typo or even no match method in source file.
Expected behavior example code should work
Sample For example, what is HttpRequestServlet in this code?
@Bean
AuthorizationManager<RequestAuthorizationContext> requestMatcherAuthorizationManager(HandlerMappingIntrospector introspector) {
RequestMatcher permitAll =
new AndRequestMatcher(
new MvcRequestMatcher(introspector, "/resources/**"),
new MvcRequestMatcher(introspector, "/signup"),
new MvcRequestMatcher(introspector, "/about"));
RequestMatcher admin = new MvcRequestMatcher(introspector, "/admin/**");
RequestMatcher db = new MvcRequestMatcher(introspector, "/db/**");
RequestMatcher any = AnyRequestMatcher.INSTANCE;
AuthorizationManager<HttpRequestServlet> manager = RequestMatcherDelegatingAuthorizationManager.builder()
.add(permitAll, (context) -> new AuthorizationDecision(true))
.add(admin, AuthorityAuthorizationManager.hasRole("ADMIN"))
.add(db, AuthorityAuthorizationManager.hasRole("DBA"))
.add(any, new AuthenticatedAuthorizationManager())
.build();
return (context) -> manager.check(context.getRequest());
}
besides, is there a method named access which receives a String parameter? I can only find this in source code
/**
* Allows specifying a custom {@link AuthorizationManager}.
* @param manager the {@link AuthorizationManager} to use
* @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
* customizations
*/
public AuthorizationManagerRequestMatcherRegistry access(
AuthorizationManager<RequestAuthorizationContext> manager) {
Assert.notNull(manager, "manager cannot be null");
return AuthorizeHttpRequestsConfigurer.this.addMapping(this.matchers, manager);
}
Please give me some code that really work, or an example project which already has some configurations.
Hi @cokeBeer, which version of Spring Security/Spring Boot are you using?
I don't see too many errors when trying in my IDE. Can you point out which specific errors you are seeing?
For example, what is HttpRequestServlet in this code?
It should be HttpServletRequest, do you want to contribute with the fix to this mistype?
Spring Boot 2.7.0, Spring Security 5.7.1. Besides the typo, the method named access which receives a String parameter in code below(which is example2 in https://docs.spring.io/spring-security/reference/5.7.1/servlet/authorization/authorize-requests.html) does not exist.
@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
http
// ...
.authorizeHttpRequests(authorize -> authorize
.mvcMatchers("/resources/**", "/signup", "/about").permitAll()
.mvcMatchers("/admin/**").hasRole("ADMIN")
.mvcMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
.anyRequest().denyAll()
);
return http.build();
}
I would like to give them a fix.
Great, the ticket is yours. Please base your branch on 5.7.x.
So can you explain why there is not a method named access which receives a String parameter but do presented in example code in my previous comment? Does it exist in some history versions?
I'm sorry for the delay in responding @cokeBeer.
Yes, the method exists in the authorizeRequests DSL, and it accepts an arbitrary expression to secure the URLs, i.e access("hasRole('USER')).
You can still do that with authorizeHttpRequests#access, but instead of an expression you pass the AuthorizationManager, the example above would be access(AuthorityAuthorizationManager.hasRole('USER')).
@marcusdacoregio I don't see an easy way with the new API to rewrite .access("hasRole('ADMIN') and hasRole('DBA')") to something with the AuthorityAuthorizationManager as there is no way to construct a flexible expression as was with the string based one. Feels like a step back instead of a step forward?
Hello @mdeinum.
You would have to create an AuthorizationManager that combines other AuthorizationManagers.
There is already a PR to simplify the AuthorizationManager composition, see https://github.com/spring-projects/spring-security/pull/11756.
With that PR merged, you could do something like AuthorizationManagers.allOf(AuthorityAuthorizationManager.hasRole("USER"), AuthorityAuthorizationManager.hasRole("ADMIN"));
Can anybody (@marcusdacoregio?) post an example how the correct way would be to write the Example 1 in https://docs.spring.io/spring-security/reference/6.0/servlet/authorization/expression-based.html#el-access-web-beans ?
Currently it is invalid:
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/user/**").access("@webSecurity.check(authentication,request)")
...
)
Hi @jhyot, did you try using the WebExpressionAuthorizationManager? It would look something like:
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/user/**").access(new WebExpressionAuthorizationManager("@webSecurity.check(authentication,request)"))
...
)
Are you interested in submitting a PR that fixes the doc?
so hard to find here, the examples around the world all use something like access("#u == authentication.name"). however I found this popular way of doing things not exist any more and don't know how to rewrite, glad I found here.
We still based on jdk11 and I created new spring starter project and chose latest spring boot 2.7.6 (I dig into the pom and found it includes spring security 5.7.5)
- There is no
access(String ...)API. - And there is no class WebExpressionAuthorizationManager
What should I do ?