Home > database >  Spring Secutirty hasRole Always Return 403
Spring Secutirty hasRole Always Return 403

Time:04-12

I'm trying to restrict access to an endpoint based on roles. I searched here on stackoverflow for a solution and tried a few but was not successful in solving my problem. I tried to make the restriction both in the global configuration (WebSecurityConfig) and also with PreAuthorize Annotation, both returned 403 when called. My test user has the SYS_ADMIN role, I have already validated this flow and it actually has the role. Below are my sources.

Global WebSecurityConfig

@Configuration
@EnableWebSecurity
@EnableAutoConfiguration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

    @Autowired
    private UserDetailsService jwtUserDetailsService;

    @Autowired
    private JwtRequestFilter jwtRequestFilter;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
    }

    @Override
    @Bean
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.headers().frameOptions().disable();

        httpSecurity.cors().and()
                .csrf().disable()
                .authorizeRequests()
                    .antMatchers("/spring-security-rest/**").permitAll().and()
                .authorizeRequests()
                    .antMatchers(HttpMethod.POST, "/api/authentication/**").permitAll()
                    .antMatchers(HttpMethod.POST, "/api/persons/**").hasRole("SYS_ADMIN")
                    .antMatchers(HttpMethod.GET, "/api/roles/**").permitAll()
                    .anyRequest().authenticated().and()
                .headers().frameOptions().sameOrigin().and()
                .exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().mvcMatchers(HttpMethod.OPTIONS, "/**");
        web.ignoring().mvcMatchers("/swagger-ui.html/**", "/configuration/**", "/swagger-resources/**", "/v2/api-docs",
                "/webjars/**");
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();

        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

Person Controller

package br.com.aquamain.backend.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import br.com.aquamain.backend.exception.InvalidPersonException;
import br.com.aquamain.backend.model.CustomPage;
import br.com.aquamain.backend.model.Person;
import br.com.aquamain.backend.service.PersonService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

@RestController
@RequestMapping("/api/persons")
@Api(tags = "Persons")
public class PersonController {

    @Autowired
    private PersonService personService;
    
    ...

    @PostMapping(path = "new", consumes = "application/json")
    @ApiOperation(value = "Create a new person.")
    public ResponseEntity<?> save(@RequestBody Person person) {
        try {
            CustomPage<Person> persons = this.personService.save(person);
            return new ResponseEntity<CustomPage<Person>>(persons, HttpStatus.CREATED);         
        } catch (InvalidPersonException error) {
            return new ResponseEntity<String>(error.getMessage(), HttpStatus.BAD_REQUEST);
        }
    }
    
    ...
}

Role Model

package br.com.aquamain.backend.model;

import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;

@Entity
@JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
@Table(name = "AQUARIUM_MAINTANCE_MONITOR_ROLE")
public class Role {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID_ROLE", nullable = false, precision = 9, scale = 0)
    private Integer id;
    
    @JsonIgnoreProperties(value = {"roles"})
    @ManyToMany(fetch = FetchType.LAZY, mappedBy = "roles")
    @JsonInclude(Include.NON_NULL)
    private List<User> users;
    
    @Column(name = "CODE_ROLE", nullable = true, length = 255)
    private String code;
    
    @Column(name = "DESCRIPTION_ROLE", nullable = true, length = 255)
    private String description;
    
    @Column(name = "NAME_ROLE", nullable = true, length = 255)
    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }   
}

CodePudding user response:

The role permissions on your control are correct.

@Secured( {"ROLE_myAuthority"} )

You had, in fact, given the proper approval.

new SimpleGrantedAuthority("ROLE_myAuthority");

The UsernamePasswordAuthenticationToken object really grants authority.

Filter is been injected correctly

Authentication auth = new UsernamePasswordAuthenticationToken(username, authentication.getCredentials(), authorities); 

Collection<? extends GrantedAuthority> auths = auth.getAuthorities();`

Iterator authsIterator = auths.iterator();

while (authsIterator.hasNext()) {
     SimpleGrantedAuthority sga =  (SimpleGrantedAuthority) authsIterator.next();
        sga.getAuthority();
    // ... 
}

CodePudding user response:

Your are using .hasRole("SYS_ADMIN") instead of this try .hasAnyAuthority("SYS_ADMIN") this worked for me and also give @EnableWebMvc annotation in config class.

Also check pom.xml file for below dependency.

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <version>2.6.6</version>
        </dependency>
  • Related