spring-projects / spring-security

Spring Security
http://spring.io/projects/spring-security
Apache License 2.0
8.72k stars 5.86k forks source link

AllRolesMode for JEE HttpSecurity configuration #4091

Closed ajmair01 closed 7 years ago

ajmair01 commented 7 years ago

Summary

You can tell tomcat to put any role in the HttpServletRequest rather than only mappable ones specified in your web.xml by adding the allRolesMode attribute to the <Realm> tag in your server.xml. In Spring Security, there is no way to replicate this behavior, since the HttpServletRequest gets wrapped by SecurityContextHolderAwareRequestWrapper, which will only include roles that are specified as mappable when configuring Spring Security.

Actual Behavior

When configuring SpringSecurity in a class that extends WebSecurityConfigurerAdapter, in the configure(HttpSecurity http) { } method, you must specify what roles are mappable to the HttpServletRequest via http.jee().mappableAuthorities(new String[] {"mappable", "roles"}). If you do not specify these mappable authorities/roles, any subsequent call to HttpServletRequest.isUserInRole() will return false.

Expected Behavior

There should be some kind of setting, perhaps invokable via something like http.jee().allRolesMode() that will skip wrapping the HttpServletRequest with SecurityContextHolderAwareRequestWrapper, so that you do not have to specify which roles are mappable, and any role in the original HttpServletRequest will be available throughout the entire life of the application via HttpServletRequest.isUserInRole(). This type of configuration is needed for when roles that are available to the application can be dynamically added, changed or removed throughout the life of an application.

Configuration

As a workaround, I currently pull all available roles from a database, and pass them to mappableAuthorities(), but this is still an issue, because the roles can change throughout the life of the application, and the list of roles will only be pulled at application startup.

@Configuration
@EnableWebSecurity
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@Profile("!dev-embedded")
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);

    private final AuthorizationProperties authorizationProperties;

    private final RoleRepository roleRepository;

    @Inject
    public SecurityConfig(final AuthorizationProperties authorizationProperties, final RoleRepository roleRepository) {
        this.authorizationProperties = authorizationProperties;
        this.roleRepository = roleRepository;
    }

    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        logger.info("Configuring security");
        final Collection<String> allRoles = roleRepository.findAll().stream().map(Role::getName).collect(Collectors.toList());
        logger.info("All roles: " + allRoles.toString());

        http.csrf().disable()
                .jee()
                .mappableAuthorities(allRoles.toArray(new String[allRoles.size()]))
                .and()
                .authorizeRequests()
                .antMatchers(authorizationProperties.getPublicPaths()).permitAll()
                .antMatchers(authorizationProperties.getAuthorizedPaths()).hasAnyRole(authorizationProperties.getAuthorizedRoles())
                .and()
                .logout().disable()
        ;
    }
}

Version

As far as I know, there is no type of "allRolesMode" implemented in any current version of Spring Security.

Stack Overflow Question

http://stackoverflow.com/questions/40028122/spring-security-roles-not-accessible-in-httpservletrequest-unless-specified-vi

rwinch commented 7 years ago

Thanks for reaching out! Can you explain how this would be implemented? Right now J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource needs a list of roles to pass into the HttpServletRequest.isUserInRole(String) method. There is no mechanism on the HttpServletRequest to obtain all the roles.

ajmair01 commented 7 years ago

Perhaps you could still pass "mappable roles" for that to function properly, but if you specify "all roles mode" in your config, just don't wrap the HttpServletRequest with SecurityContextHolderAwareRequestWrapper?

rwinch commented 7 years ago

This won't work. First the Authentication won't be properly populated with the roles. Second if we don't wrap the HttpServletRequest it won't behave properly either.

I'm closing this as I don't see a way to get this to work with the current Servlet APIs.