Reputation: 1159
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
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
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