I am trying to enable role hierarchy voting in Spring Security when authenticating using Waffle NTML but having some unknown issues in that the inherited roles do not appear as authorities on the principal as expected preventing hasRole expressions in both the intercept urls and using the authorize jsp taglibs.
I have been integrating waffle based on the following guide: https://github.com/dblock/waffle/blob/master/Docs/spring/SpringSecuritySingleSignOnFilter.md
This works within the application as expected on its own using the standard RoleVoter but the problem starts when I try to customise it to use the RoleHierarchyVoter which I have also tested on its own (using an LDAP Authentication Provider) and the role hierarchies work exactly as expected.
The config for the combined Waffle and RoleHierarchyVoter approach is as follows:
Waffle Specfic Config
<!-- windows authentication provider -->
<bean id="waffleWindowsAuthProvider" class="waffle.windows.auth.impl.WindowsAuthProviderImpl" />
<!-- collection of security filters -->
<bean id="negotiateSecurityFilterProvider" class="waffle.servlet.spi.NegotiateSecurityFilterProvider">
<constructor-arg ref="waffleWindowsAuthProvider" />
</bean>
<bean id="basicSecurityFilterProvider" class="waffle.servlet.spi.BasicSecurityFilterProvider">
<constructor-arg ref="waffleWindowsAuthProvider" />
</bean>
<bean id="waffleSecurityFilterProviderCollection" class="waffle.servlet.spi.SecurityFilterProviderCollection">
<constructor-arg>
<list>
<ref bean="negotiateSecurityFilterProvider" />
<ref bean="basicSecurityFilterProvider" />
</list>
</constructor-arg>
</bean>
<bean id="negotiateSecurityFilterEntryPoint" class="waffle.spring.NegotiateSecurityFilterEntryPoint">
<property name="Provider" ref="waffleSecurityFilterProviderCollection" />
</bean>
<!-- spring security filter -->
<bean id="waffleNegotiateSecurityFilter" class="waffle.spring.NegotiateSecurityFilter">
<property name="Provider" ref="waffleSecurityFilterProviderCollection" />
<property name="AllowGuestLogin" value="false" />
<property name="PrincipalFormat" value="fqn" />
<property name="RoleFormat" value="fqn" />
<property name="GrantedAuthorityFactory" ref="simpleGrantedAuthorityFactory" />
<!-- set the default granted authority to null as we don't need to assign a default role of ROLE_USER -->
<property name="defaultGrantedAuthority"><null/></property>
</bean>
<!-- custom granted authority factory so the roles created are based on the name rather than the fqn-->
<bean id="simpleGrantedAuthorityFactory" class="xx.yy.zz.SimpleGrantedAuthorityFactory">
<constructor-arg name="prefix" value="ROLE_"/>
<constructor-arg name="convertToUpperCase" value="true"/>
</bean>
Familiar Spring Security Config
<!-- declare the entry point ref as the waffle defined entry point -->
<sec:http use-expressions="true"
disable-url-rewriting="true"
access-decision-manager-ref="accessDecisionManager"
entry-point-ref="negotiateSecurityFilterEntryPoint" >
<sec:intercept-url pattern="/**" access="isAuthenticated()" requires-channel="any"/>
.
. access denied handlers, concurrency control, port mappings etc
.
<sec:custom-filter ref="waffleNegotiateSecurityFilter" position="BASIC_AUTH_FILTER" />
</sec:http>
<!-- spring authentication provider -->
<sec:authentication-manager alias="authenticationProvider" />
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<property name="decisionVoters">
<list>
<ref bean="roleHierarchyVoter" />
<bean class="org.springframework.security.web.access.expression.WebExpressionVoter">
<property name="expressionHandler">
<bean class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler">
<property name="roleHierarchy" ref="roleHierarchy"/>
</bean>
</property>
</bean>
</list>
</property>
</bean>
<bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<property name="hierarchy">
<value>
ROLE_TEST_1 > ROLE_TEST_2
ROLE_TEST_2 > ROLE_TEST_3
ROLE_TEST_3 > ROLE_TEST_4
</value>
</property>
</bean>
<bean id="roleHierarchyVoter"
class="org.springframework.security.access.vote.RoleHierarchyVoter">
<constructor-arg ref="roleHierarchy"/>
</bean>