43

I was looking for the answer for a long time but couldnt find anything productive

In my rest service I keep some functionality under: /account/{id}/download and I would like to set the acces ROLE in SecurityConfig java file, that only ROLE_TOKENSAVED users can access this url

How should the pattern look like, when {id} is changeable?

I tried some regexp patterns, but nothing worked as I wanted, here are some of my attempts:

1. antMatchers("account/**/download").access(somerolehere)
2. antMatchers("account/\\d/download").access(somerolehere)
3. antMatchers("account/[\\d]/download").access(somerolehere)

thanks in advance for your anserwers :)

edit:

    @Override
    protected void configure(HttpSecurity http) throws Exception {            
        http.authorizeRequests()
                .antMatchers("/admin**").access("hasRole('ROLE_ADMIN')")
                .antMatchers("/account*//**").access("hasRole('ROLE_USER') or hasRole('ROLE_ADMIN')")
                .antMatchers("/account/\\d+/download").access("hasRole('ROLE_TOKENSAVED')")
                .antMatchers("/user**").permitAll()
                //othercode...
    }
Bohuslav Burghardt
  • 33,626
  • 7
  • 114
  • 109
azalut
  • 4,094
  • 7
  • 33
  • 46

3 Answers3

48

This works for me:

antMatchers("/account/{\\d+}/download").access("hasAnyAuthority('ROLE_TOKENSAVED')")

Notice the curly braces around the path variable representing the ID.

Bohuslav Burghardt
  • 33,626
  • 7
  • 114
  • 109
  • yup it worked, but only when I comment .antMatchers("/account*//**").access("hasRole('ROLE_USER') or hasRole('ROLE_ADMIN')") pattern, how to reconcile these two patterns? – azalut Dec 25 '14 at 18:55
  • 2
    Because that matcher is more general. Matchers must be ordered from most specific to least specific. So put the `/account/{\\d+}/download` matcher before it. – Bohuslav Burghardt Dec 25 '14 at 18:58
  • but why should I have added {} brackets to the pattern? because controllers use: {id} pattern to take PathVariable from it? – azalut Dec 25 '14 at 19:02
  • 1
    @azalut When you look at the `AntPathMatcher` JavaDoc it says this: "URI template variables are expressed through curly brackets ('{' and '}')". So this is just specific syntax for Ant matchers. – Bohuslav Burghardt Dec 25 '14 at 19:06
  • 2
    Note that `\d` is for a numeric value, I have string parameter in the path. So, I have used `\w`. – S_K Apr 30 '19 at 04:58
17

Though what Bohuslav suggest works, it is not complete. According to the documentation for AntPathMarcher: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/util/AntPathMatcher.html

You need to specify the path variable with the regex:

{spring:[a-z]+} matches the regexp [a-z]+ as a path variable named "spring"

If you don't, you may expose other routes. For example:

    .authorizeRequests()
        .antMatchers(HttpMethod.GET, "/users/{^[\\d]$}").authenticated()
        .antMatchers("/users/**").hasAuthority("admin")

and these methods on a UserController:

@ResponseBody
@RequestMapping(value = "/users/{userId}", method = RequestMethod.GET)
public User getUser(@PathVariable("userId") Object id) {
    return userService.getUserById(userId);
}

@ResponseBody
@RequestMapping(value = "/users/roles", method = RequestMethod.GET)
public List<String> getAllRoles() {
    return userService.getAllRoles();
}

Because you didn't specify path variable, userId, users will be able to do a GET request on "/users/roles" without having the admin authority. Also other futures routes like "/users/test" will also be exposed even if admin authorization is required. To prevent that:

antMatchers("/account/{accountId:\\d+}/download")
       .access("hasAnyAuthority('ROLE_TOKENSAVED')")

if your path variable's name was "accountId"

Boni2k
  • 3,255
  • 3
  • 23
  • 27
LethalLima
  • 211
  • 3
  • 6
0

I think i had a similar problem and in ma case something like antMatchers("/items/{\d+}) didn't work. But if i read antMatchers("/items/{d+}) (without //) is working.

llsnpy
  • 1
  • 1
  • 2