antMatchers Spring Security pattern with changeable URL user ID

51,832

Solution 1

This works for me:

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

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

Solution 2

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"

Share:
51,832
azalut
Author by

azalut

Updated on April 09, 2020

Comments

  • azalut
    azalut about 4 years

    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...
        }
    
  • azalut
    azalut over 9 years
    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?
  • Bohuslav Burghardt
    Bohuslav Burghardt over 9 years
    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.
  • azalut
    azalut over 9 years
    but why should I have added {} brackets to the pattern? because controllers use: {id} pattern to take PathVariable from it?
  • Bohuslav Burghardt
    Bohuslav Burghardt over 9 years
    @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.
  • S_K
    S_K about 5 years
    Note that \d is for a numeric value, I have string parameter in the path. So, I have used \w.