I am using CAS with JDBC Authentication handler and was wondering is it possible to get the other attributes of principal object (for e.g. firstname, lastname) not just the username from CAS after successful authentication?
In the casServiceValidationSuccess.jsp, I add like below:
<cas:attributes>
<c:forEach var="attr" items="${assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes}">
**<cas:${fn:escapeXml(attr.key)}>${fn:escapeXml(attr.value)}</cas:${fn:escapeXml(attr.key)}>**
</c:forEach>
</cas:attributes>
In the deployerConfigContent.xml, I add like below:
<bean class="org.jasig.cas.authentication.principal.UsernamePasswordCredentialsToPrincipalResolver" >
**<property name="attributeRepository">
<ref bean="attributeRepository" />
</property>**
</bean>
<bean id="attributeRepository" class="org.jasig.services.persondir.support.jdbc.SingleRowJdbcPersonAttributeDao">
<constructor-arg index="0" ref="dataSource"/>
<constructor-arg index="1" value="select * from bbs_members where {0}" />
<property name="queryAttributeMapping">
<map>
<entry key="username" value="username" />
</map>
</property>
<property name="resultAttributeMapping">
<map>
<entry key="uid" value="uid"/>
<entry key="email" value="email"/>
<entry key="password" value="password"/>
</map>
</property>
</bean>
It works.
I came across this problem during the debug, please close the browser if you change this JSP or XML files, otherwise the changes won't work. Be careful.
To get any user attributes from DB I did the following: use PersonDirectoryPrincipalResolver
in deployerConfigContext.xml:
<bean id="primaryPrincipalResolver"
class="org.jasig.cas.authentication.principal.PersonDirectoryPrincipalResolver" >
<property name="attributeRepository" ref="singleRowJdbcPersonMultiplyAttributeDao" />
</bean>
instead of using standard SingleRowJdbcPersonAttributeDao class create your own implementation which returns not only one row from a query result but aggregated data from all returned rows:
copy all code from SingleRowJdbcPersonAttributeDao
and change only one method parseAttributeMapFromResults
.
you will have something like that:
public class SingleRowJdbcPersonMultiplyAttributeDao extends AbstractJdbcPersonAttributeDao<Map<String, Object>> {
...
@Override
protected List<IPersonAttributes> parseAttributeMapFromResults(final List<Map<String, Object>> queryResults, final String queryUserName) {
final List<IPersonAttributes> peopleAttributes = new ArrayList<IPersonAttributes>(queryResults.size());
Map<String, List<Object>> attributes = new HashMap<String, List<Object>>();
for (final Map<String, Object> queryResult : queryResults) {
for (final Map.Entry<String, Object> seedEntry : queryResult.entrySet()) {
final String seedName = seedEntry.getKey();
final Object seedValue = seedEntry.getValue();
if (attributes.get(seedName) != null && !attributes.get(seedName).get(0).equals(seedValue)) {
attributes.get(seedName).add(seedValue);
} else {
List<Object> list = new ArrayList<Object>();
list.add(seedValue);
attributes.put(seedName, list);
}
}
}
final IPersonAttributes person;
final String userNameAttribute = this.getConfiguredUserNameAttribute();
if (this.isUserNameAttributeConfigured() && attributes.containsKey(userNameAttribute)) {
// Option #1: An attribute is named explicitly in the config,
// and that attribute is present in the results from LDAP; use it
person = new CaseInsensitiveAttributeNamedPersonImpl(userNameAttribute, attributes);
} else if (queryUserName != null) {
// Option #2: Use the userName attribute provided in the query
// parameters. (NB: I'm not entirely sure this choice is
// preferable to Option #3. Keeping it because it most closely
// matches the legacy behavior there the new option -- Option #1
// -- doesn't apply. ~drewwills)
person = new CaseInsensitiveNamedPersonImpl(queryUserName, attributes);
} else {
// Option #3: Create the IPersonAttributes doing a best-guess
// at a userName attribute
person = new CaseInsensitiveAttributeNamedPersonImpl(userNameAttribute, attributes);
}
peopleAttributes.add(person);
return peopleAttributes;
}
...
}
and in deployerConfigContext.xml:
<bean id="singleRowJdbcPersonMultiplyAttributeDao"
class="com.scentbird.SingleRowJdbcPersonMultiplyAttributeDao">
<constructor-arg index="0" ref="dataSource" />
<constructor-arg index="1" value="SELECT attributes_table1.*, attributes_table2.attr1, attributes_table2.roles AS roles FROM user_table ut LEFT JOIN roles_table rt ON <condition> LEFT JOIN another_table at ON <condition> WHERE {0}" />
<property name="queryAttributeMapping">
<map>
<entry key="username" value="username" />
</map>
</property>
</bean>
Also in my case I used SAML protocol.
As a result you will get on the client all attributes which your select returns. For example, if user have many roles you could have on the client:
User: username, firstname, lastname, email, ... , [ROLE_1, ROLE_2, ROLE_3]
My case works with Spring Security and Grails.
I'm not sure this is 100% Feng Shui solution :) as it's fast cooked but it works in our case.
Hope it helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With