Hatik
Hatik

Reputation: 1159

Spring Security Limiting URL access by roles

I am trying to implement SpringSecurity mechanism on this little project, that will limit interactions with the URL of the request by roles.

I have two roles USER and ADMIN, USER can see the items, but not add or delete them, while ADMIN can do both.

Now the problem, the requests from USER role and even unauthenticated users to create/delete/read an item are allowed somehow. It seems to me that my application is not configured correctly somewhere.

SecurityConfig:

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


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("user").password("{noop}12345").roles("USER").and()
                .withUser("admin").password("{noop}12345").roles("ADMIN");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.httpBasic().and().authorizeRequests()
                .antMatchers("api/**").hasRole("ADMIN")
                .antMatchers("api/items", "api/items/").hasRole("USER")
                .anyRequest().authenticated()
                .and().csrf().disable().headers().frameOptions().disable();
    }

}

Controller:

@RestController
public class ItemController {

    @Autowired
    private ItemService itemService;

    @GetMapping("/api/items")
    public List<Item> getItems() {
        return itemService.getAllItems();
    }

    @PostMapping(value = "/api/addItem",consumes = {"application/json"},produces = {"application/json"})
    @ResponseBody
    public Item addItem(@RequestBody Item item) {
        itemService.addItem(item);
        return item;
    }

    @DeleteMapping(value = "api/deleteItem/{id}")
    @ResponseBody
    public String deleteItem(@PathVariable int id) {
        itemService.deleteItem(id);
        return "Deleted";
    }
}

I am sending requests to the following URL's:

http://localhost:8080/api/items        // GET
http://localhost:8080/api/addItem      // POST
http://localhost:8080/api/deleteItem/4 // DELETE

Upvotes: 0

Views: 1879

Answers (2)

LynAs
LynAs

Reputation: 6567

On top of @GetMapping or @PostMapping you can add following annotation to manage Role based access

@PreAuthorize("hasAnyRole('ROLE_ADMIN')")
@PostMapping(value = "/api/addItem",consumes = {"application/json"},produces = {"application/json"})
@ResponseBody
public Item addItem(@RequestBody Item item) {
    itemService.addItem(item);
    return item;
}

Upvotes: 1

Michiel
Michiel

Reputation: 3500

Have you tried adding slashes to your antmatcher patterns, such as:

antMatchers("/api/**").hasRole("ADMIN")

The Spring documentation mentions:

Note: a pattern and a path must both be absolute or must both be relative in order for the two to match. Therefore it is recommended that users of this implementation to sanitize patterns in order to prefix them with "/" as it makes sense in the context in which they're used.

Furthermore, Spring security uses the first match of all the matching rules expressed. I would recommend reordering the matchers from most-specific to less-specific as otherwise a call to api/items will be matched by the api/** matcher instead of being matched by the api/items matcher.

.antMatchers("/api/items", "api/items/").hasRole("USER")
.antMatchers("/api/**").hasRole("ADMIN")

Upvotes: 3

Related Questions