39

I have this code in my Web Security Config:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .authorizeRequests()
            .antMatchers("/api/**")
            .hasRole("ADMIN")
            .and()
            .httpBasic().and().csrf().disable();

}

So I added an user with "ADMIN" role in my database and I always get 403 error when I tryed loggin with this user, then I enabled log for spring and I found this line:

2015-10-18 23:13:24.112 DEBUG 4899 --- [nio-8080-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor    : Secure object: FilterInvocation: URL: /api/user/login; Attributes: [hasRole('ROLE_ADMIN')]

Why Spring Security is looking for "ROLE_ADMIN" instead "ADMIN"?

Ahmed Ashour
  • 5,179
  • 10
  • 35
  • 56
Gustavo Rozolin
  • 1,070
  • 2
  • 13
  • 21
  • Possible duplicate of [Spring Security Role Prefix and Custom User Details Service](http://stackoverflow.com/questions/4951832/spring-security-role-prefix-and-custom-user-details-service) – Bruno Oct 19 '15 at 13:03

5 Answers5

36

Spring security adds the prefix "ROLE_" by default.

If you want this removed or changed, take a look at

How to change role from interceptor-url?

EDIT: found this as well: Spring Security remove RoleVoter prefix

Draken
  • 3,134
  • 13
  • 34
  • 54
jmcg
  • 1,547
  • 17
  • 22
  • Just a question, does Spring add ROLE_ by default if I add a role in @Secured annotation? Like If I add @Secured("abc"), will Spring check for ROLE_abc or just abc? – Sajib Acharya May 12 '16 at 13:40
  • @SajibAcharya you can change the default `ROLE_`. please see http://stackoverflow.com/questions/38134121/how-do-i-remove-the-role-prefix-from-spring-security-with-javaconfig/38970309#38970309 – walsh Aug 16 '16 at 08:51
24

In Spring 4, there are two methods hasAuthority() and hasAnyAuthority() defined in org.springframework.security.access.expression.SecurityExpressionRoot class. These two methods checks only your custom role name without adding ROLE_ prefix. Definition as follows:

public final boolean hasAuthority(String authority) {
    return hasAnyAuthority(authority);
}
public final boolean hasAnyAuthority(String... authorities) {
    return hasAnyAuthorityName(null, authorities);
}
private boolean hasAnyAuthorityName(String prefix, String... roles) {
    Set<String> roleSet = getAuthoritySet();

    for (String role : roles) {
        String defaultedRole = getRoleWithDefaultPrefix(prefix, role);
        if (roleSet.contains(defaultedRole)) {
            return true;
        }
    }

    return false;
}
private static String getRoleWithDefaultPrefix(String defaultRolePrefix, String role) {
    if (role == null) {
        return role;
    }
    if (defaultRolePrefix == null || defaultRolePrefix.length() == 0) {
        return role;
    }
    if (role.startsWith(defaultRolePrefix)) {
        return role;
    }
    return defaultRolePrefix + role;
}

Example usage:

<http auto-config="false" use-expressions="true" pattern="/user/**"
      entry-point-ref="loginUrlAuthenticationEntryPoint">
    <!--If we use hasAnyAuthority, we can remove ROLE_ prefix-->
    <intercept-url pattern="/user/home/yoneticiler" access="hasAnyAuthority('FULL_ADMIN','ADMIN')"/>
    <intercept-url pattern="/user/home/addUser" access="hasAnyAuthority('FULL_ADMIN','ADMIN')"/>
    <intercept-url pattern="/user/home/addUserGroup" access="hasAuthority('FULL_ADMIN')"/>
    <intercept-url pattern="/user/home/deleteUserGroup" access="hasAuthority('FULL_ADMIN')"/>
    <intercept-url pattern="/user/home/**" access="hasAnyAuthority('FULL_ADMIN','ADMIN','EDITOR','NORMAL')"/>
    <access-denied-handler error-page="/403"/>
    <custom-filter position="FORM_LOGIN_FILTER" ref="customUsernamePasswordAuthenticationFilter"/>
    <logout logout-url="/user/logout"
            invalidate-session="true"
            logout-success-url="/user/index?logout"/>
    <!-- enable csrf protection -->
    <csrf/>
</http>   <beans:bean id="loginUrlAuthenticationEntryPoint"
            class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
    <beans:constructor-arg value="/user"/>
</beans:bean>
olyanren
  • 1,448
  • 4
  • 24
  • 42
11

As @olyanren said, you can use hasAuthority() method in Spring 4 instead of hasRole(). I am adding JavaConfig example:

@Override
protected void configure(HttpSecurity http) throws Exception {
    .authorizeRequests()
    .antMatchers("/api/**")
    .access("hasAuthority('ADMIN')")
    .and()
    .httpBasic().and().csrf().disable();
}
SmithMart
  • 2,731
  • 18
  • 35
Svitlana Onish
  • 284
  • 3
  • 14
4

You can create a mapper to add ROLE_ at the beginning of all of your roles:

@Bean
public GrantedAuthoritiesMapper authoritiesMapper() {
    SimpleAuthorityMapper mapper = new SimpleAuthorityMapper();
    mapper.setPrefix("ROLE_"); // this line is not required 
    mapper.setConvertToUpperCase(true); // convert your roles to uppercase
    mapper.setDefaultAuthority("USER"); // set a default role

    return mapper;
}

The you should add the mapper to your provider:

@Bean
public DaoAuthenticationProvider authenticationProvider() {
    DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
    // your config ...
    provider.setAuthoritiesMapper(authoritiesMapper());

    return provider;
}
Dónal
  • 185,044
  • 174
  • 569
  • 824
Hamid Mohayeji
  • 3,977
  • 3
  • 43
  • 55
1

_ROLE prefix is used by spring security, to identify that it is as a role. A role has a set of privileges a.k.a Authorities, these authorities define varies permissions for a role. ex:- EDIT_PROFILE, DELETE_PROFILE

You can define both the roles and authorities, if you are defining a role then it must be prefixed with "ROLE_"

In your case you are looking for a role, so by default spring security looks for a string that is prefixed with "ROLE_".

Hashan Mahesh
  • 103
  • 4
  • 12