Spring security - 403 bei Role Access Regel

8u3631984

Bekanntes Mitglied
Hallo.
ich möchte meine App mit verschiedenen Endpunkten absichern : Hier mein Controller :
Java:
@Controller
@Log4j2
public class CalendarUserController {

    @Autowired
    private CalendarUserFactory calendarUserFactory;

    @PostMapping(value = "/api/v1/calendarUser/add", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public CalendarUser createCalendarUser(@RequestBody UserData userData) {
        log.info("/api/v1/calendarUser/add");
        log.info("userData : {}", userData);
        return calendarUserFactory.buildAndSave(userData);
    }

    @DeleteMapping(value = "/api/v1/calendarUser/delete")
    public void deleteCalendarUser(@RequestBody Long id) {
        log.info("/api/v1/calendarUser/delete");
        // TODO let factory delete item
        //samsCalendarFactory.delete(id);
    }

    @GetMapping(value = "/api/v1/calendarUser/getAll")
    public List<CalendarUser> getAllCalendarUser() {
        log.info("/api/v1/calendarUser/getAll");
        return calendarUserFactory.getAll();
    }
}

Ich möchte nun,dass alle Aufrufe für den /api/v1/calendarUser/ Endpunkt nur von einem Administrator User aufgerufen werden können :

dazu habe ich eine SecurityConfig Klasse angelegt :
Java:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails adminUserDetails = User.withDefaultPasswordEncoder()
                .username("admin")
                .password("admin")
                .roles("ADMIN")
                .build();

        UserDetails importUserDetails = User.withDefaultPasswordEncoder()
                .username("importer")
                .password("importer")
                .roles("IMPORTER")
                .build();

        UserDetails defaulUserDetails = User.withDefaultPasswordEncoder()
                .username("user")
                .password("user")
                .roles("USER")
                .build();

        return new InMemoryUserDetailsManager(adminUserDetails, importUserDetails, defaulUserDetails);
    }

    //
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/").permitAll()
                .antMatchers("/api/v1/calendarUser/getAll").hasRole("ADMIN")
                .anyRequest().authenticated();
    }
}
}

Geprüft habe ich das mit dem Postman Tool : Dort habe ich einen Get Request auf den Endpunkt : http://localhost:8080/api/v1/calendarUser/getAll mit und ohne Authenfication (basic Auth) gemacht.
Als Ergebnis bekomme ich immer :
Java:
{
    "timestamp": "2021-08-31T10:02:21.743+00:00",
    "status": 403,
    "error": "Forbidden",
    "message": "",
    "path": "/api/v1/calendarUser/getAll"
}

Hat jemand eine Idee wo der Fehler liegt ?
Vielen Dank
 
Danke für deine Hilfe.
Noch eine Anmerkung zu meiner Anforderungen. Ich will per HttPClient auf die Schnittstelle zurgreifen :
Java:
        HttpClient httpClient = HttpClient.newBuilder()
                .version(HttpClient.Version.HTTP_2)
                .connectTimeout(Duration.ofSeconds(10))
                .authenticator(new Authenticator() {
                    @Override
                    protected PasswordAuthentication getPasswordAuthentication() {
                        return new PasswordAuthentication("admin", "admin".toCharArray());
                    }
                })
                .build();

        String url = "http://localhost:8080/api/v1/calendarUser/getAll";
        log.info("send request : {}", url);
        HttpRequest httpRequest = HttpRequest.newBuilder()
                .GET()
//                .header("Authorization", basicAuth("admin", "admin"))
                .uri(URI.create(url))
                .build();
        HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
        log.info("status code : {}",httpResponse.statusCode());
        log.info("body  : {}",httpResponse.body());

Wenn ich in der Config Methode :
Java:
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/").permitAll()
                .antMatchers("/api/v1/calendarUser/getAll").hasRole("ADMIN")
                //.and().formLogin();
    }
die formLogin zeile aukommentiere bekomme ich verschiede Status Code : 302
 
Habe meine Config Klasse noch einmal angepasst :
Java:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final PasswordEncoder passwordEncoder;

    @Autowired
    public SecurityConfig(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }

    @Override
    @Bean
    protected UserDetailsService userDetailsService() {
        UserDetails adminUserDetails = User.builder()
                .username("admin")
                .password(passwordEncoder.encode("admin"))
                .roles("ADMIN") // ROLE_ADMIN
                .build();

        UserDetails importerUserDetails = User.builder()
                .username("importer")
                .password(passwordEncoder.encode("importer"))
                .roles("IMPORTER") // ROLE_IMPORTER
                .build();

        return new InMemoryUserDetailsManager(
                adminUserDetails, importerUserDetails);

    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/api/v1/calendarUser/**").hasRole("ADMIN")
                .antMatchers(HttpMethod.POST, "/api/v1/calendarUser/add").hasRole("ADMIN")
                .anyRequest()
                .authenticated()
                .and()
                .httpBasic();
    }
}

Was geht nun (/)
wenn ich als admin User den Get Request aufrufe : http://localhost:8080/api/v1/calendarUser/getAll bekomme ich eine Antwort : status 200
Rufe ich den gleichen Get request mit dem improter User auf bekomme einen 403 zurücke. Alles so wie es sein soll.

Nun möchte ich das auch für einen Post request : http://localhost:8080/api/v1/calendarUser/add bekomme ich immer den Status 403 zurück.

HAt jemand eine Idee wo der Fehler in der Config ist.
 
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter
probiere
Java:
@Configuration 
@EnableWebSecurity 
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
 
@bueges Welche Route soll jetzt mit welcher Methode für welchen User welchen Status zurückgeben?

probiere
Java:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
@EnableGlobalMethodSecurity braucht man nur, wenn man @PreAuthorize und @Secured nutzt, was hier nicht gemacht wird.
 
Also ich schicke hier mal einen Link zu einem Youtube Spring Boot Security Kurs - will keine Werbung machen. Aber dort wurde mir viele Sachen klarer :

Zu meinem Problem :
Java:
        http
                .csrf().disable()

Hier werde wohl Post, Delete request von Hause verboten. Erst wenn man csrf disabled funktioniert es. Eine Alternative ist wohl einen Token mitzuschicken. Muss ich mich wohl noch mal mit beschäftigen.

Aber zu deiner Frage @mrBrown :
Ich möchte dass alle Anfrage unter /api/v1/calendarUser/ nur von Nutzer mit der Rolle Admin zugänglich gemacht werden.
Java:
.antMatchers("/api/v1/calendarUser/**").hasRole("ADMIN")
 

Zurück
Oben