简体   繁体   中英

Why is the Auth0 not throwing 403 with spring-boot-starter-oauth2-resource-server when filtering by scope?

I have the following...

@RestController
@RequestMapping(path="/person", produces = MediaType.APPLICATION_JSON_VALUE)
public class AuthController {
  @GetMapping("")
    @ResponseBody
    public String getPersonFromEmail(@RequestParam(name = "email") String email){ ... }
}
@EnableWebSecurity
public class SecurityConfig {
    ...
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests()
                .requestMatchers("/person").hasAuthority("SCOPE_blahablah")
                .anyRequest().authenticated()
                .and().cors()
                .and().oauth2ResourceServer().jwt();
        return http.build();
    }
}

When I run but pass no token I get a 401. However, when I pass a token that doesn't have the proper scope I get a 200. I would expect to also get a 403. What am I missing?

With a little more digging it looks like the problem is the query params. Not sure how to acoomadate those...

~/tmp/user-profile >curl -v http://localhost:8080/person
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /person HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.85.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 403 
< Set-Cookie: JSESSIONID=EFD9C400D91760FE8FA2119AC2EB382B; Path=/; HttpOnly
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 0
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Length: 0
< Date: Wed, 11 Jan 2023 21:45:16 GMT
< 
* Connection #0 to host localhost left intact
~/tmp/user-profile >curl -v http://localhost:8080/person?email=...
zsh: no matches found: http://localhost:8080/person?email=... <-- This means it worked without checking

What you should expect is actually a 403 (forbidden which mean that authentication is valid but access was denied) and not a 401 (unauthorized which means that authentication is missing or invalid).

Have you checked that your SecurityConfig is correctly loaded with a breakpoint or log line? It Seams that @Configuration is missing and my bet is that your resource-server is actually secured with spring-boot default SecurityFilterChain which only applies anyRequest().authenticated() .

You could also disable sessions (and CSRF protection). Access could be denied because of CSRF protection which is useless when sessions are disabled and sessions are rarely needed with access-tokens. It would also ease scaling and fault tolerance.

You could have a look at my tutorials for resource-server configuration and access-control tests.

Edit: complete sample

package com.c4soft.dumb;

import java.util.Arrays;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

@SpringBootApplication
public class DumbApplication {

    public static void main(String[] args) {
        SpringApplication.run(DumbApplication.class, args);
    }

    @RestController
    @RequestMapping(path = "/dumb")
    public class AuthController {
        @GetMapping("/public")
        public String getPublic() {
            return "Hello!";
        }

        @GetMapping("/person")
        public String getPersonFromEmail(@RequestParam(name = "email") String email) {
            return email;
        }

        @GetMapping("/name")
        public String getName(Authentication auth) {
            return auth.getName();
        }
    }

    @Configuration
    @EnableWebSecurity
    public class SecurityConfig {
        @Bean
        public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
            http.oauth2ResourceServer().jwt();

            http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().csrf().disable();

            // @formatter:off
            http.authorizeHttpRequests()
                .requestMatchers("/dumb/public").permitAll()
                .requestMatchers("/dumb/person").hasAuthority("SCOPE_email")
                .anyRequest().authenticated();
            // @formatter:on

            http.cors().configurationSource(corsConfigurationSource());
            
            return http.build();
        }

        private CorsConfigurationSource corsConfigurationSource() {
            final var configuration = new CorsConfiguration();
            configuration.setAllowedOrigins(Arrays.asList("*"));
            configuration.setAllowedMethods(Arrays.asList("*"));
            configuration.setAllowedHeaders(Arrays.asList("*"));
            configuration.setExposedHeaders(Arrays.asList("*"));

            final var source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/dumb/**", configuration);

            return source;
        }
    }
}
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://dev-ch4mpy.eu.auth0.com/

Queries with Postman work exactly as expected:

  • http://localhost:8080/dumb/public is accessible without any authentication
  • http://localhost:8080/dumb/name return
    • 401 if access token is missing or invalid (wrong issuer, expired, ...)
    • access-token sub claim value if access token is valid
  • http://localhost:8080/dumb/person?email=dumb@truc.com returns
    • 401 if access token is missing or invalid (wrong issuer, expired, ...)
    • 403 if client did not request email scope
    • dumb@truc.com if access-token is valid and has email scope

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM