Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Springboot Security hasRole not working

I’m unable to use hasRole method in @PreAuthorize annotation. Also request.isUserInRole(“ADMIN”) gives false. What am I missing? Although .hasAuthority(“ADMIN”) works fine.

I am assigning authorities to the users from a database.

like image 576
arvind.mohan Avatar asked Jan 30 '17 22:01

arvind.mohan


2 Answers

You have to name your authority with prefix ROLE_ to use isUserInRole, see Spring Security Reference:

The HttpServletRequest.isUserInRole(String) will determine if SecurityContextHolder.getContext().getAuthentication().getAuthorities() contains a GrantedAuthority with the role passed into isUserInRole(String). Typically users should not pass in the "ROLE_" prefix into this method since it is added automatically. For example, if you want to determine if the current user has the authority "ROLE_ADMIN", you could use the following:

boolean isAdmin = httpServletRequest.isUserInRole("ADMIN");

Same for hasRole (also hasAnyRole), see Spring Security Reference:

Returns true if the current principal has the specified role. By default if the supplied role does not start with 'ROLE_' it will be added. This can be customized by modifying the defaultRolePrefix on DefaultWebSecurityExpressionHandler.

like image 179
dur Avatar answered Oct 18 '22 19:10

dur


I had to improvise a little, maybe there is other ways simpler then mine, but at the time I worked on this I had no other choice but to improvise a bit, after a thorough research came up with this solution. Spring Security has an interface called AccessDecisionManager, you will need to implement it.

@Component
public class RolesAccessDecisionManager implements AccessDecisionManager {
    private final static String AUTHENTICATED = "authenticated";
    private final static String PERMIT_ALL = "permitAll";

    @Override
    public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> collection) throws AccessDeniedException, InsufficientAuthenticationException {
        collection.forEach(configAttribute -> {
            if (!this.supports(configAttribute))
                throw new AccessDeniedException("ACCESS DENIED");
        });
    }

    @Override
    public boolean supports(ConfigAttribute configAttribute) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.isAuthenticated()) {
            String rolesAsString = authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.joining(","));
            if (configAttribute.toString().contains(rolesAsString))
                return true;
            else
                return (configAttribute.toString().contains(PERMIT_ALL) || configAttribute.toString().contains(AUTHENTICATED));
        }
        return true;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return true;
    }
}

Now to support this custom access-decision-manager with your security config do this in the security configuration:

@Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable()
// other configs
    .accessDecisionManager(this.accessDecisionManager)

accessDecisionManager is the autowired bean of the AccessDecisionManager implementation you've created.

like image 24
Omar Ajmi Avatar answered Oct 18 '22 18:10

Omar Ajmi