spring-security icon indicating copy to clipboard operation
spring-security copied to clipboard

codes in spring security docs fail to work

Open cokeBeer opened this issue 3 years ago • 7 comments
trafficstars

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.

cokeBeer avatar Jun 19 '22 15:06 cokeBeer

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?

marcusdacoregio avatar Jun 22 '22 13:06 marcusdacoregio

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.

cokeBeer avatar Jun 23 '22 03:06 cokeBeer

Great, the ticket is yours. Please base your branch on 5.7.x.

marcusdacoregio avatar Jun 23 '22 11:06 marcusdacoregio

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?

cokeBeer avatar Jun 24 '22 08:06 cokeBeer

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 avatar Jul 08 '22 11:07 marcusdacoregio

@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?

mdeinum avatar Sep 13 '22 05:09 mdeinum

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"));

marcusdacoregio avatar Sep 13 '22 13:09 marcusdacoregio

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)")
        ...
    )

jhyot avatar Nov 21 '22 12:11 jhyot

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?

marcusdacoregio avatar Nov 21 '22 12:11 marcusdacoregio

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.

uniquejava avatar Dec 22 '22 08:12 uniquejava

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)

  1. There is no access(String ...) API.
  2. And there is no class WebExpressionAuthorizationManager

What should I do ?

uniquejava avatar Dec 22 '22 08:12 uniquejava