I am using CAS authentication for my application. I store my user details in LDAP Active Directory. I use spring security and JSF in my web application. I find difficulty in getting the LDAP attributes like country, country code to the managed bean. I am able to retrieve the roles, username, password from SecurityContext but I am not able to get the country details of the logged in user from the ldap.
I beleive there must be a way after the CAS authentication, I can retrieve the ldap attributes to JSF managed bean through CAS. I tried the below link but i couldnt get the details to the managed bean.
My CAS does get roles from LDAP, but I don't want my web app to talk to LDAP.
Can spring security + CAS be configured to get the ldap attributes ?
can someone help me in getting the ldap attributes like country after the CAS authentication ?
Get LDAP user attributes from CAS
I have attached my CAS deployerConfigContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="authenticationManager" class="xxx.cas.authentication.XXXOTPPolicyBasedAuthenticationManager">
<constructor-arg index="0">
<list value-type="org.jasig.cas.authentication.AuthenticationHandler" >
<ref local="ldapAuthenticationHandler"/>
<ref local="radiusAuthenticationHandler"/>
</list>
</constructor-arg>
<property name="authenticationPolicy">
<bean class="xxx.cas.authentication.XXXAllAuthenticationPolicy" />
</property>
</bean>
<!-- Required for proxy ticket mechanism. -->
<bean id="proxyAuthenticationHandler"
class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"
p:httpClient-ref="httpClient" p:requireSecure="false" />
<!--
| Change principalIdAttribute to use another directory attribute,
| e.g. userPrincipalName, for the NetID
-->
<bean id="ldapAuthenticationHandler"
class="org.jasig.cas.authentication.LdapAuthenticationHandler"
p:principalIdAttribute="sAMAccountName"
c:authenticator-ref="authenticator">
<property name="principalAttributeMap">
<map>
<!--
| This map provides a simple attribute resolution mechanism.
| Keys are LDAP attribute names, values are CAS attribute names.
| Use this facility instead of a PrincipalResolver if LDAP is
| the only attribute source
-->
<entry key="displayName" value="displayName" />
<entry key="facsimileTelephoneNumber" value="facsimileTelephoneNumber" />
<entry key="memberOf" value="memberOf" />
<entry key="co" value="co" />
<entry key="c" value="c" />
<entry key="mail" value="mail" />
<entry key="description" value="role" />
</map>
</property>
</bean>
<!-- Required for proxy ticket mechanism -->
<bean id="proxyPrincipalResolver"
class="org.jasig.cas.authentication.principal.BasicPrincipalResolver" />
<!-- Radius authentication -->
<bean id="radiusClientFactory"
class="org.jasig.cas.adaptors.radius.RadiusClientFactory"
p:inetAddress="${fourtress.server}"
p:sharedSecret="${fourtress.ss}" />
<bean id="radiusServer"
class="org.jasig.cas.adaptors.radius.JRadiusServerImpl"
c:protocol="PAP"
c:clientFactory-ref="radiusClientFactory" />
<bean id="radiusAuthenticationHandler"
class="xxx.cas.authentication.XXXRadiusAuthenticationHandler">
<property name="servers">
<list>
<ref local="radiusServer" />
</list>
</property>
</bean>
<bean id="attributeRepository"
class="org.jasig.cas.persondir.LdapPersonAttributeDao"
p:connectionFactory-ref="pooledLdapConnectionFactory"
p:baseDN="ou=users,ou=egate,dc=egate-t,dc=local" p:searchControls-ref="searchControls" p:searchFilter="sAMAccountName={0}">
<property name="requireAllQueryAttributes" value="true"/>
<property name="queryAttributeMapping">
<map>
<!-- Attribute mapping between principal (key) and LDAP (value) names used to perform the LDAP search -->
<entry key="username" value="sAMAccountName" />
</map>
</property>
<property name="resultAttributeMapping">
<map>
<!-- Mapping between LDAP entry attributes (key) and Principal's (value) -->
<entry key="memberOf" value="memberOf" />
<entry key="mail" value="mail" />
<entry key="cn" value="FullName" />
<entry key="sn" value="LastName" />
<entry key="displayName" value="displayName" />
<entry key="description" value="role" />
<entry key="facsimileTelephoneNumber" value="facsimileTelephoneNumber" />
<entry key="co" value="country" />
<entry key="c" value="countryCode" />
</map>
</property>
</bean>
<bean id="searchControls"
class="javax.naming.directory.SearchControls"
p:searchScope="2"
p:countLimit="0" p:timeLimit="0" />
<!--
Sample, in-memory data store for the ServiceRegistry. A real implementation
would probably want to replace this with the JPA-backed ServiceRegistry DAO
The name of this bean should remain "serviceRegistryDao".
+-->
<bean id="serviceRegistryDao" class="org.jasig.cas.services.InMemoryServiceRegistryDaoImpl"
p:registeredServices-ref="registeredServicesList" />
<util:list id="registeredServicesList">
<bean class="org.jasig.cas.services.RegexRegisteredService">
<property name="id" value="1" />
<property name="name" value="cassimple" />
<property name="description" value="cassimple application 1" />
<property name="serviceId" value="^(http?|https?|imaps?)://localhost:7002/cassimple/.*" />
<property name="evaluationOrder" value="10000001" />
</bean>
<bean class="org.jasig.cas.services.RegexRegisteredService">
<property name="id" value="2" />
<property name="name" value="casldap" />
<property name="description" value="casldap application 2" />
<property name="serviceId" value="^(http?|https?|imaps?)://localhost:7002/casldap/.*" />
<property name="evaluationOrder" value="10000002" />
<property name="allowedAttributes">
<list>
<value>memberOf</value>
<value>LastName</value>
<value>FullName</value>
<value>displayName</value>
<value>role</value>
</list>
</property>
</bean>
<bean class="org.jasig.cas.services.RegexRegisteredService">
<property name="id" value="3" />
<property name="name" value="cascir" />
<property name="description" value="cas cir application 3" />
<property name="serviceId" value="^(http?|https?|imaps?)://localhost:7002/cascir/.*" />
<property name="evaluationOrder" value="10000003" />
<property name="allowedAttributes">
<list>
<value>role</value>
<value>FullName</value>
<value>displayName</value>
<value>LastName</value>
<value>memberOf</value>
</list>
</property>
</bean>
<bean class="org.jasig.cas.services.RegexRegisteredService">
<property name="id" value="4" />
<property name="name" value="egate" />
<property name="description" value="cas egate application 4" />
<property name="serviceId" value="^(http?|https?|imaps?)://localhost:7002/egate/.*" />
<property name="evaluationOrder" value="10000004" />
<property name="allowedAttributes">
<list>
<value>role</value>
<value>FullName</value>
<value>displayName</value>
<value>LastName</value>
<value>memberOf</value>
</list>
</property>
</bean>
<bean class="org.jasig.cas.services.RegexRegisteredService">
<property name="id" value="5" />
<property name="name" value="cir" />
<property name="description" value="cas cir application 5" />
<property name="serviceId" value="^(http?|https?|imaps?)://localhost:7002/cir/.*" />
<property name="evaluationOrder" value="10000005" />
<property name="allowedAttributes">
<list>
<value>role</value>
<value>FullName</value>
<value>displayName</value>
<value>LastName</value>
<value>memberOf</value>
<value>country</value>
<value>countryCode</value>
</list>
</property>
</bean>
</util:list>
<bean id="auditTrailManager" class="com.github.inspektr.audit.support.Slf4jLoggingAuditTrailManager" />
<bean id="healthCheckMonitor" class="org.jasig.cas.monitor.HealthCheckMonitor" p:monitors-ref="monitorsList" />
<util:list id="monitorsList">
<bean class="org.jasig.cas.monitor.MemoryMonitor" p:freeMemoryWarnThreshold="10" />
<!--
NOTE
The following ticket registries support SessionMonitor:
* DefaultTicketRegistry
* JpaTicketRegistry
Remove this monitor if you use an unsupported registry.
-->
<bean class="org.jasig.cas.monitor.SessionMonitor"
p:ticketRegistry-ref="ticketRegistry"
p:serviceTicketCountWarnThreshold="5000"
p:sessionCountWarnThreshold="100000" />
</util:list>
<bean id="authenticator" class="org.ldaptive.auth.Authenticator"
c:resolver-ref="dnResolver"
c:handler-ref="authHandler"
p:entryResolver-ref="entryResolver" />
<!-- Active Directory UPN format. -->
<bean id="dnResolver"
class="org.ldaptive.auth.FormatDnResolver"
c:format="${ldap.authn.format}" />
<bean id="authHandler" class="org.ldaptive.auth.PooledBindAuthenticationHandler"
p:connectionFactory-ref="pooledLdapConnectionFactory" />
<bean id="pooledLdapConnectionFactory"
class="org.ldaptive.pool.PooledConnectionFactory"
p:connectionPool-ref="connectionPool" />
<bean id="connectionPool"
class="org.ldaptive.pool.BlockingConnectionPool"
init-method="initialize"
p:poolConfig-ref="ldapPoolConfig"
p:blockWaitTime="${ldap.pool.blockWaitTime}"
p:validator-ref="searchValidator"
p:pruneStrategy-ref="pruneStrategy"
p:connectionFactory-ref="connectionFactory" />
<bean id="ldapPoolConfig" class="org.ldaptive.pool.PoolConfig"
p:minPoolSize="${ldap.pool.minSize}"
p:maxPoolSize="${ldap.pool.maxSize}"
p:validateOnCheckOut="${ldap.pool.validateOnCheckout}"
p:validatePeriodically="${ldap.pool.validatePeriodically}"
p:validatePeriod="${ldap.pool.validatePeriod}" />
<bean id="connectionFactory" class="org.ldaptive.DefaultConnectionFactory"
p:connectionConfig-ref="connectionConfig" />
<bean id="connectionConfig" class="org.ldaptive.ConnectionConfig"
p:ldapUrl="${ldap.url}"
p:connectTimeout="${ldap.connectTimeout}"
p:useStartTLS="${ldap.useStartTLS}"
p:sslConfig-ref="sslConfig"/>
<bean id="sslConfig" class="org.ldaptive.ssl.SslConfig">
<property name="credentialConfig">
<bean class="org.ldaptive.ssl.X509CredentialConfig"
p:trustCertificates="classpath:${ldap.trustedCert}" />
</property>
</bean>
<bean id="pruneStrategy" class="org.ldaptive.pool.IdlePruneStrategy"
p:prunePeriod="${ldap.pool.prunePeriod}"
p:idleTime="${ldap.pool.idleTime}" />
<bean id="searchValidator" class="org.ldaptive.pool.SearchValidator" />
<bean id="entryResolver"
class="org.jasig.cas.authentication.support.UpnSearchEntryResolver"
p:baseDn="${ldap.baseDn}" />
</beans>
My spring security.xml
<beans:beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
<debug />
<global-method-security secured-annotations="enabled" />
<http auto-config="false" use-expressions="true"
entry-point-ref="casAuthenticationEntryPoint">
<custom-filter position="CAS_FILTER" ref="casAuthenticationFilter" />
<intercept-url pattern="/faces/disclaimer**" access="permitAll" />
<intercept-url pattern="/faces/searchCreditInstitution**"
access="permitAll" />
<intercept-url pattern="/faces/searchParentInstitution**"
access="hasAnyRole('ROLE_CIR_EDITOR','ROLE_CIR_AUTHORISER')" />
<intercept-url pattern="/faces/createCreditInstitution**"
access="hasAuthority('ROLE_CIR_EDITOR')" />
<intercept-url pattern="/faces/authorisation**"
access="hasAuthority('ROLE_CIR_AUTHORISER')" />
<intercept-url pattern="/faces/rejected**" access="hasAuthority('ROLE_CIR_EDITOR')" />
<intercept-url pattern="/faces/pendingApproval**"
access="hasAuthority('ROLE_CIR_EDITOR')" />
<intercept-url pattern="/faces/auditLog**"
access="hasAuthority('ROLE_CIR_AUTHORISER')" />
<intercept-url pattern="/faces/enquiry**"
access="hasAnyRole('ROLE_CIR_EDITOR','ROLE_CIR_AUTHORISER','ROLE_CIR_XXXOPS')" />
<intercept-url pattern="/faces/changePassword**"
access="hasAnyRole('ROLE_CIR_EDITOR','ROLE_CIR_AUTHORISER','ROLE_CIR_XXXOPS')" />
<intercept-url pattern="/faces/dashboard**" access="ROLE_CIR_XXXOPS" />
<intercept-url pattern="/resources**" access="permitAll" />
<intercept-url pattern="/faces/javax.faces.resource**" access="permitAll" />
<logout logout-url="/logout" logout-success-url="https://localhost:7002/cas/logout" />
</http>
<beans:bean id="serviceProperties"
class="org.springframework.security.cas.ServiceProperties">
<beans:property name="service"
value="https://localhost:7002/cir/j_spring_cas_security_check" />
<beans:property name="sendRenew" value="false" />
</beans:bean>
<beans:bean id="casAuthenticationEntryPoint"
class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
<beans:property name="loginUrl" value="https://localhost:7002/cas/login" />
<beans:property name="serviceProperties" ref="serviceProperties" />
</beans:bean>
<beans:bean id="casAuthenticationFilter"
class="org.springframework.security.cas.web.CasAuthenticationFilter">
<beans:property name="authenticationManager" ref="casAuthenticationManager" />
</beans:bean>
<authentication-manager alias="casAuthenticationManager">
<authentication-provider ref="casAuthenticationProvider" />
</authentication-manager>
<beans:bean id="casAuthenticationProvider"
class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<beans:property name="serviceProperties" ref="serviceProperties" />
<beans:property name="ticketValidator" ref="ticketValidator" />
<beans:property name="authenticationUserDetailsService"
ref="authenticationUserDetailsService" />
<beans:property name="key" value="cir" />
</beans:bean>
<beans:bean id="ticketValidator"
class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
<beans:constructor-arg index="0"
value="https://localhost:7002/cas">
</beans:constructor-arg>
</beans:bean>
<beans:bean id="authenticationUserDetailsService"
class="XXX.cir.cas.authentication.XXXCasAuthenticationUserDetailsService" />
</beans:beans>
I am able to get the Ldap roles, username in JSF managed bean by this way but not country
SecurityContext ctx = SecurityContextHolder.getContext();
UserDetails userDetails = (UserDetails)ctx.getAuthentication().getPrincipal();
System.out.println("Role of the ldaper : " + ctx.getAuthentication().getAuthorities());
String userRole = ctx.getAuthentication().getAuthorities();