So, is this a case issue then? I'm not quite at the liberty to change the case of the roles I'm fetching from LDAP, but I do prefix them all with ROLE_ in the process. But, I have the exact same exception/condition if the authenticated user does not have ALL of the roles specified. My impression (Acegi docbook, Spring In Action) was that a list of roles specified in the objectDefinitionSource for FilterSecurityInterceptor indicate that if the user is an ANY of the roles, then to grant access...
Looking at the source to RoleVoter, it seems to confirm the first role that matches the criteria returns with ACCESS_GRANTED, so I don't know why the user has to be in ALL roles listed.
For example:
Code:
2005-06-07 12:46:37,883 DEBUG [net.sf.acegisecurity.ui.AbstractProcessingFilter] - <Redirecting to target URL from HTTP Session (or default): http://sdmaapp1:8103/pa/secure/index.jsp>
2005-06-07 12:46:37,885 DEBUG [net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter] - <Context stored to HttpSession: 'net.sf.acegisecurity.context.security.SecureContextImpl@ea3932: Authentication: net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken@f70ee1: Username: com.ingenuity.security.dao.IngenuityLegacyLdapUser@1f1e39b; Password: [PROTECTED]; Authenticated: false; Details: net.sf.acegisecurity.ui.WebAuthenticationDetails@1d056de: RemoteIpAddress: 10.32.18.95; SessionId: 583063dc83736948563a; Granted Authorities: ROLE_PAADMIN, ROLE_paumadmin, ROLE_PAUSERTRIAL, ROLE_PAUSERPAID, ROLE_RoleSharingWithMe, ROLE_RoleSharingWithOthers'>
2005-06-07 12:46:37,886 DEBUG [net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter] - <ContextHolder set to null as request processing completed>
2005-06-07 12:46:37,907 DEBUG [net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter] - <Obtained from ACEGI_SECURITY_CONTEXT a valid Context and set to ContextHolder: 'net.sf.acegisecurity.context.security.SecureContextImpl@ea3932: Authentication: net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken@f70ee1: Username: com.ingenuity.security.dao.IngenuityLegacyLdapUser@1f1e39b; Password: [PROTECTED]; Authenticated: false; Details: net.sf.acegisecurity.ui.WebAuthenticationDetails@1d056de: RemoteIpAddress: 10.32.18.95; SessionId: 583063dc83736948563a; Granted Authorities: ROLE_PAADMIN, ROLE_paumadmin, ROLE_PAUSERTRIAL, ROLE_PAUSERPAID, ROLE_RoleSharingWithMe, ROLE_RoleSharingWithOthers'>
2005-06-07 12:46:37,908 DEBUG [net.sf.acegisecurity.intercept.web.PathBasedFilterInvocationDefinitionMap] - <Candidate is: '/secure/index.jsp'; pattern is /secure/admin/**; matched=false>
2005-06-07 12:46:37,908 DEBUG [net.sf.acegisecurity.intercept.web.PathBasedFilterInvocationDefinitionMap] - <Candidate is: '/secure/index.jsp'; pattern is /secure/index.jsp; matched=true>
2005-06-07 12:46:37,908 DEBUG [net.sf.acegisecurity.intercept.AbstractSecurityInterceptor] - <Secure object: FilterInvocation: URL: /secure/index.jsp; ConfigAttributes: [ROLE_PAUSERPAID, ROLE_PAUSERINTERNAL]>
2005-06-07 12:46:37,909 DEBUG [net.sf.acegisecurity.providers.ProviderManager] - <Authentication attempt using net.sf.acegisecurity.providers.dao.PasswordDaoAuthenticationProvider>
2005-06-07 12:46:37,909 DEBUG [com.ingenuity.security.ldap.IngenuityLegacyLdapPasswordAuthenticationDao] - <** email: 'jschmidt@ingenuity.com'>
2005-06-07 12:46:37,910 DEBUG [com.ingenuity.security.ldap.IngenuityLegacyLdapPasswordAuthenticationDao] - <** password: '**'>
2005-06-07 12:46:37,910 DEBUG [com.ingenuity.security.ldap.IngenuityLegacyLdapPasswordAuthenticationDao] - <Attempting to authenticate 'jschmidt@ingenuity.com'>
2005-06-07 12:46:38,054 DEBUG [com.ingenuity.security.dao.IngenuityLegacyLdapUser] - <ILLU, username: jschmidt@ingenuity.com>
2005-06-07 12:46:38,054 DEBUG [com.ingenuity.security.ldap.IngenuityLegacyLdapPasswordAuthenticationDao] - <Added authority: ROLE_PAADMIN>
2005-06-07 12:46:38,055 DEBUG [com.ingenuity.security.ldap.IngenuityLegacyLdapPasswordAuthenticationDao] - <Added authority: ROLE_paumadmin>
2005-06-07 12:46:38,055 DEBUG [com.ingenuity.security.ldap.IngenuityLegacyLdapPasswordAuthenticationDao] - <Added authority: ROLE_PAUSERTRIAL>
2005-06-07 12:46:38,060 DEBUG [com.ingenuity.security.ldap.IngenuityLegacyLdapPasswordAuthenticationDao] - <Added authority: ROLE_PAUSERPAID>
2005-06-07 12:46:38,061 DEBUG [com.ingenuity.security.ldap.IngenuityLegacyLdapPasswordAuthenticationDao] - <Added authority: ROLE_RoleSharingWithMe>
2005-06-07 12:46:38,061 DEBUG [com.ingenuity.security.ldap.IngenuityLegacyLdapPasswordAuthenticationDao] - <Added authority: ROLE_RoleSharingWithOthers>
2005-06-07 12:46:38,062 DEBUG [com.ingenuity.security.ldap.IngenuityLegacyLdapPasswordAuthenticationDao] - <Successfully authenticated 'jschmidt@ingenuity.com'>
2005-06-07 12:46:38,062 DEBUG [org.springframework.web.context.support.XmlWebApplicationContext] - <Publishing event in context [Root WebApplicationContext]: net.sf.acegisecurity.providers.dao.event.AuthenticationSuccessEvent[source=net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken@f70ee1: Username: com.ingenuity.security.dao.IngenuityLegacyLdapUser@1f1e39b; Password: [PROTECTED]; Authenticated: false; Details: net.sf.acegisecurity.ui.WebAuthenticationDetails@1d056de: RemoteIpAddress: 10.32.18.95; SessionId: 583063dc83736948563a; Granted Authorities: ROLE_PAADMIN, ROLE_paumadmin, ROLE_PAUSERTRIAL, ROLE_PAUSERPAID, ROLE_RoleSharingWithMe, ROLE_RoleSharingWithOthers]>
2005-06-07 12:46:38,063 DEBUG [net.sf.acegisecurity.intercept.AbstractSecurityInterceptor] - <Authenticated: net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken@5f1c48: Username: com.ingenuity.security.dao.IngenuityLegacyLdapUser@39ea58; Password: [PROTECTED]; Authenticated: true; Details: net.sf.acegisecurity.ui.WebAuthenticationDetails@1d056de: RemoteIpAddress: 10.32.18.95; SessionId: 583063dc83736948563a; Granted Authorities: ROLE_PAADMIN, ROLE_paumadmin, ROLE_PAUSERTRIAL, ROLE_PAUSERPAID, ROLE_RoleSharingWithMe, ROLE_RoleSharingWithOthers>
2005-06-07 12:46:38,065 DEBUG [org.springframework.web.context.support.XmlWebApplicationContext] - <Publishing event in context [Root WebApplicationContext]: net.sf.acegisecurity.intercept.event.AuthorizationFailureEvent[source=FilterInvocation: URL: /secure/index.jsp]>
2005-06-07 12:46:38,066 DEBUG [net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter] - <Access is denied (user is not anonymous); sending back forbidden response>
net.sf.acegisecurity.AccessDeniedException: Access is denied.
at net.sf.acegisecurity.vote.UnanimousBased.decide(UnanimousBased.java:108)
at net.sf.acegisecurity.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:394)
at net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:81)
at net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter.doFilter(SecurityEnforcementFilter.java:182)
at net.sf.acegisecurity.util.FilterToBeanProxy.doFilter(FilterToBeanProxy.java:125)
at jrun.servlet.FilterChain.doFilter(FilterChain.java:94)
at com.ingenuity.security.ldap.IngenuityLegacyContextHolderAwareRequestFilter.doFilter(IngenuityLegacyContextHolderAwareRequestFilter.java:44)
at net.sf.acegisecurity.util.FilterToBeanProxy.doFilter(FilterToBeanProxy.java:125)
at jrun.servlet.FilterChain.doFilter(FilterChain.java:94)
at net.sf.acegisecurity.ui.AbstractProcessingFilter.doFilter(AbstractProcessingFilter.java:305)
at net.sf.acegisecurity.util.FilterToBeanProxy.doFilter(FilterToBeanProxy.java:125)
at jrun.servlet.FilterChain.doFilter(FilterChain.java:94)
at net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter.doFilter(HttpSessionContextIntegrationFilter.java:225)
at net.sf.acegisecurity.util.FilterToBeanProxy.doFilter(FilterToBeanProxy.java:125)
at jrun.servlet.FilterChain.doFilter(FilterChain.java:94)
at com.ingenuity.security.jrun4.ContextLoaderFilter.doFilter(ContextLoaderFilter.java:59)
at jrun.servlet.FilterChain.doFilter(FilterChain.java:94)
at jrun.servlet.FilterChain.service(FilterChain.java:101)
at jrun.servlet.ServletInvoker.invoke(ServletInvoker.java:91)
at jrun.servlet.JRunInvokerChain.invokeNext(JRunInvokerChain.java:42)
at jrun.servlet.JRunRequestDispatcher.invoke(JRunRequestDispatcher.java:257)
at jrun.servlet.ServletEngineService.dispatch(ServletEngineService.java:541)
at jrun.servlet.http.WebService.invokeRunnable(WebService.java:172)
at jrunx.scheduler.ThreadPool$ThreadThrottle.invokeRunnable(ThreadPool.java:426)
at jrunx.scheduler.WorkerThread.run(WorkerThread.java:66)
2005-06-07 12:46:38,093 DEBUG [net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter] - <Context stored to HttpSession: 'net.sf.acegisecurity.context.security.SecureContextImpl@ea3932: Authentication: net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken@5f1c48: Username: com.ingenuity.security.dao.IngenuityLegacyLdapUser@39ea58; Password: [PROTECTED]; Authenticated: true; Details: net.sf.acegisecurity.ui.WebAuthenticationDetails@1d056de: RemoteIpAddress: 10.32.18.95; SessionId: 583063dc83736948563a; Granted Authorities: ROLE_PAADMIN, ROLE_paumadmin, ROLE_PAUSERTRIAL, ROLE_PAUSERPAID, ROLE_RoleSharingWithMe, ROLE_RoleSharingWithOthers'>
2005-06-07 12:46:38,094 DEBUG [net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter] - <ContextHolder set to null as request processing completed>
Configuration wise, this looks like:
Code:
<bean name="filterSecurityInterceptor"
class="net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager">
<ref bean="authenticationManager"/>
</property>
<property name="accessDecisionManager">
<ref bean="accessDecisionManager"/>
</property>
<property name="objectDefinitionSource">
<!--
Define application URI to role associations here. Configure more specific
patterns above less specific ones, or they may not be discerned.
-->
<value>
CONVERT_URL_TOLOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/secure/admin/**=ROLE_PAADMIN
/secure/**=ROLE_PAUSERPAID,ROLE_PAUSERINTERNAL
</value>
</property>
</bean>
<bean name="authenticationManager"
class="net.sf.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref bean="passwordDaoAuthenticationProvider"/>
</list>
</property>
</bean>
<bean name="passwordDaoAuthenticationProvider"
class="net.sf.acegisecurity.providers.dao.PasswordDaoAuthenticationProvider">
<property name="passwordAuthenticationDao">
<ref bean="ldapPasswordAuthenticationDao"/>
</property>
</bean>
<bean name="ldapPasswordAuthenticationDao"
class="com.ingenuity.security.ldap.IngenuityLegacyLdapPasswordAuthenticationDao">
</bean>
<bean name="accessDecisionManager"
class="net.sf.acegisecurity.vote.UnanimousBased">
<property name="decisionVoters">
<list>
<ref bean="roleVoter"/>
</list>
</property>
<property name="allowIfAllAbstainDecisions">
<value>false</value>
</property>
</bean>
<bean name="roleVoter"
class="net.sf.acegisecurity.vote.RoleVoter">
</bean>
<bean name="requestFilter"
class="com.ingenuity.security.ldap.IngenuityLegacyContextHolderAwareRequestFilter"/>
A question you may have is what are the IngenuityLegacy* classes. Legacy code requires the ability to retrieve a particular implementation of Principal from the HttpServletRequest. The wrapper and associated filter are used so that rather than the Authentication, it returns the Principal within the authentication, which is what the legacy code expects:
Code:
public Principal getUserPrincipal() {
Principal acegiPrincipalToken = super.getUserPrincipal();
if (acegiPrincipalToken != null)
return (Principal)((Authentication)acegiPrincipalToken).getPrincipal();
else
return null;
}
The LDAP based authentication seems to be working as expected, it's just the authorization that is messing me up. The output listed (far) above shows the roles associated with the user, and when accessing /secure/index.jsp, access is denied. The user has the authority ROLE_PAUSERPAID, but not ROLE_PAUSERINTERNAL. If I make the user have both roles, then access is granted. I should not have to do that though, should I?
BTW, this is Acegi 0.8.2 with Spring 1.2.1 on JRun 4. The LDAP code is proprietary at the moment, but I'd like to make use of the Acegi sandbox LDAP in the near future.
Again, this application is just a prototype to see how to get Acegi to play with some legacy issues.
Thanks!
Jeff