Showing posts with label ldap. Show all posts
Showing posts with label ldap. Show all posts

May 14, 2013

LDAP support enhanced for CXF STS 2.7.5

I described in a previous blog how to configure the CXF STS for an LDAP directory for authentication and to retrieve user claims (attributes). The new release 2.7.5 of CXF provides extended support for roles managed in a LDAP directory. In previous versions, the LdapClaimsHandler added groups as roles if the groups were assigned to a multi-value attribute of the user. The new release provides an LdapGroupClaimsHandler which supports the case where an attribute of the groups lists the users who belong to this group. Further, it introduces the semantic of an application role. A user might have the role "User" for application X and role "Manager" and "User" for application Y.

The STS provides the semantic of an application with the AppliesTo parameter which is a URI. If you request a SAML token which includes the roles for a specific application (ex. MyApp), you get User and Manager back. A mapping is required in the STS to map the AppliesTo URI (URL or URN) to a String value like MyApp.

The sub-project Fediz provides in 1.1 (not released yet) a Maven profile to build the STS with an LDAP backend (instead of managing users/claims in a file). You can have a look at the ldap.xmlhere. The following configuration configures the LdapClaimsHandler and LdapGroupClaimsHandler. There is nothing special for the LdapClaimsHandler. The LdapGroupClaimsHandler also uses the Spring LdapContextSource and LdapTemplate.

    <util:list id="claimHandlerList">
        <ref bean="userClaimsHandler" />
        <ref bean="groupClaimsHandler" />
    </util:list>

    <bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource">
        <property name="url" value="ldap://localhost:389/" />
        <property name="userDn" value="uid=admin,ou=system" />
        <property name="password" value="secret" />
    </bean>

    <bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
        <constructor-arg ref="contextSource" />
    </bean>

    <util:map id="claimsToLdapAttributeMapping">
        <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"
            value="givenName" />
        <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"
            value="sn" />
        <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"
            value="mail" />
        <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/country"
            value="c" />
        <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/postalcode"
            value="postalCode" />
        <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/streetaddress"
            value="postalAddress" />                        
        <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/locality"
            value="town" />
        <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/stateorprovince"
            value="st" />
        <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/gender"
            value="gender" />
        <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/dateofbirth"
            value="dateofbirth" />                                                
        <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role"
            value="member" />
    </util:map>

    <bean id="userClaimsHandler" class="org.apache.cxf.sts.claims.LdapClaimsHandler">
        <property name="ldapTemplate" ref="ldapTemplate" />
        <property name="claimsLdapAttributeMapping" ref="claimsToLdapAttributeMapping" />
        <property name="userBaseDN" value="ou=users,dc=fediz,dc=org" />
        <property name="userNameAttribute" value="uid" />
    </bean>
    
    <util:map id="appliesToScopeMapping">
        <entry key="urn:org:apache:cxf:fediz:fedizhelloworld"
            value="Example" />
    </util:map>
    
    <bean id="groupClaimsHandler" class="org.apache.cxf.sts.claims.LdapGroupClaimsHandler">
        <property name="ldapTemplate" ref="ldapTemplate" />
        <property name="userBaseDN" value="ou=users,dc=fediz,dc=org" />
        <property name="userNameAttribute" value="uid" />
        <property name="groupBaseDN" value="ou=groups,dc=fediz,dc=org" />
        <property name="appliesToScopeMapping" ref="appliesToScopeMapping" />
    </bean>
    
    <jaxws:endpoint id="transportSTS1" implementor="#transportSTSProviderBean"
        address="/STSService" wsdlLocation="/WEB-INF/wsdl/ws-trust-1.4-service.wsdl"
        xmlns:ns1="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
        serviceName="ns1:SecurityTokenService" endpointName="ns1:TransportUT_Port">
        <jaxws:properties>
            <entry key="ws-security.ut.validator">
                <bean class="org.apache.ws.security.validate.JAASUsernameTokenValidator">
                    <property name="contextName" value="LDAP" />
                </bean>
            </entry>
        </jaxws:properties>
    </jaxws:endpoint>
I've highlighted the important beans to support the mapping of groups to (application) roles. The bean LdapGroupClaimsHandler has got the following attributes:

NameMandatoryDefaultDescription
ldapTemplateYesN.A.The Spring LDAP template
groupBaseDNYesN.A.The base group context where the search starts
groupObjectClassNogroupOfNamesObject class for groups. Used for search filter.
groupMemeberAttributeNomemberThe group attribute where the list of users are stored
groupURINohttp://schemas.xmlsoap.org/ws/2005/05/identity/claims/roleThe SAML attribute name where the roles should be stored
groupNameGlobalFilterNoROLEDefault uses the CN of the group as role name
groupNameScopedFilterNoSCOPE_ROLEDefault cuts the SCOPE and the underscore of the CN of the group
appliesToScopeMappingNoN.A.The mapping is required if application specific roles must be supported
userNameAttributeNocnUser id attribute. Only required if LDAP is not used for authentication and thus the DN of the user must be resolved first. Used for search filter.
userObjectClassNopersonObject class for users. Only required if LDAP is not used for authentication and thus the DN of the user must be resolved first. Used for search filter.

The bean appliesToScopeMapping defines the mapping of the URI in the AppliesTo variable to a Name as URI's are not valid within a CN of an LDAP group.

One example for the usage of groupNameScopedFilter. One more example. Let's assume you use the same LDAP directory for the application environemnt development and pre-production and defines the following naming convention for application roles:
DEV_<Application>_<ROLE>_Group and UAT_<Application>_<ROLE>_Group The groupNameScopedFilter will look like this DEV_SCOPE_ROLE_Group (assumption: Different STS instances are deployed for development and pre-production).

The following table lists a few group examples and how the role value will look like in the SAML attribute. The assumption is that the AppliesTo element is urn:org:apache:cxf:fediz:fedizhelloworld which maps to the scope Example (see configuration example above) and the groupNameScopedFilter is configured like DEV_SCOPE_ROLE_Group:

Group CNRole name
DEV_Example_User_GroupUser
DEV_Example_Admin_GroupAdmin
DEV_Example2_User_Groupignored
UAT_Example_User_Groupignored
INFR_Citrix_Accessignored

Last but not least I'd like to comment the default value of userNameAttribute which is CN. As per recommendation (5.4) the CN is typically the person's fullname and therefore doesn't fit for the user id (login name). Due to the reason that the LdapClaimsHandler had the cn as default value I wanted to keep that in sync and change it in the next non-patch release of CXF.

If you face issues or like more functionality send a message to the CXF mailing list or open a JIRA issue.

October 18, 2011

Configure LDAP directory for CXF STS

I explained in my previous blog how to set up the CXF STS where you manage your users and claims in a file.This blog explains the required changes to integrate the CXF STS with a LDAP directory.

You can attach an LDAP directory either for username/password validation or for retrieving the claims data or both.

1. Username and password authentication

WSS4j supports username/password authentication against a JAAS based backend since version 1.6.3.

The JDK provides a JAAS LoginModule for LDAP which can be configured as illustrated here in a sample jaas configuration (jaas.config):
  
myldap {
 com.sun.security.auth.module.LdapLoginModule REQUIRED
 userProvider=ldap://ldap.mycompany.org:389/OU=Users,DC=mycompany,DC=org"
 authIdentity="cn={USERNAME},OU=Users,DC=mycompany,DC=org"
 useSSL=false
 debug=true;
};

You can get more information about this LoginModule here.

In this example, all the users are stored in the organization unit Users within mycompany.org. The configuration filename can be chosen, i.e. jaas.config. The filename must be configured as a JVM argument. I recommend to set JVM related configurations for Tomcat in the setenv.sh/bat file located in tomcat/bin directory. This script is called by catalina.bat/sh implicitly and might look like this for UNIX:

#!/bin/sh 
JAVA_OPTS="-Djava.security.auth.login.config=/opt/tomcat/conf/jaas.config"
export JAVA_OPTS

Now, the LDAP LoginModule is configured. Next we have to configure the JAASUsernameTokenValidator for the STS endpoint.

<bean
  class="org.apache.ws.security.validate.JAASUsernameTokenValidator"
      id="jaasUTValidator">
   <property name="contextName" value="myldap"/>
</bean>

<jaxws:endpoint id="transportSTSUT"
  endpointName="ns1:TransportUT_Port"
  serviceName="ns1:SecurityTokenService"
  xmlns:ns1=http://docs.oasis-open.org/ws-sx/ws-trust/200512/
  wsdlLocation="/WEB-INF/wsdl/ws-trust-1.4-service.wsdl"
  address="/STSServiceTransportUT"
  implementor="#transportSTSProviderBean">

  <jaxws:properties>
    <entry key="ws-security.ut.validator"
         value-ref="jaasUTValidator"/>
  </jaxws:properties>
</jaxws:endpoint>


The property contextName must match with the context name defined in the JAAS configuration file which is "myldap" in this example.
<
 2. Claims management

When a STS client requests a claim, the ClaimsManager in the STS checks every registered ClaimsHandler who can provide the data of the requested claim.  The CXF STS provides a claims handler implementation which allows to add claims which are stored as user attributes in a LDAP directory. You can configure which claim URI maps to which LDAP user attribute. The implementation uses the spring ldap module (LdapTemplate).

<util:list id="claimHandlerList">
  <ref bean="ldapClaimsHandler" />
</util:list>

<bean id="contextSource"
   class="org.springframework.ldap.core.support.LdapContextSource">
  <property name="url" value="ldap://ldap.mycompany.org:389" />
  <property name="userDn"
    value="CN=techUser,OU=Users,DC=mycompany,DC=org" />
  <property name="password" value="mypassword" />
</bean>

<bean id="ldapTemplate"
   class="org.springframework.ldap.core.LdapTemplate">
  <constructor-arg ref="contextSource" />
</bean>

<util:map id="claimsToLdapAttributeMapping">
  <entry
key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"
value="givenName" />
  <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"
value="sn" />
  <entry
key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"
value="mail" />
  <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/country"
value="c" />
</util:map>

<bean id="ldapClaimsHandler"
    class="org.apache.cxf.sts.claims.LdapClaimsHandler">
  <property name="ldapTemplate" ref="ldapTemplate" />
  <property name="claimsLdapAttributeMapping"
            ref="claimsToLdapAttributeMapping" />
  <property name="userBaseDN"
      value="OU=Users,DC=mycompany,DC=org" />
</bean>


The claim id's are configured according to chapter 7.5 in the specification Identity Metasystem Interoperability. You can add as many entries in the map claimsToLdapAttributeMapping as you want. Thus you can add any user attribute from your LDAP directory to the issued SAML token.