Wildfly – Elytron – LDAP SecurityDomains for Active Directory

In one of my last blog posts I explained how to setup a Security Domain in Wildfy Elytron – the new security module. In this blog post I explain how to setup a LDAP security domain for the Active Directory:

The ldap-realm

As explained in my last blog you have to define a security-domain and a security-realm in two separate sections. The following example shows the LDAP configuration to resolve users and roles form an Active Directory. I have reduced the non relevant parts:

       <subsystem xmlns="urn:wildfly:elytron:14.0" final-providers="combined-providers" disallowed-providers="OracleUcrypto">
            .....
            <security-domains>
                .....                
              	<!-- My LDAP domain   -->
		<security-domain name="mydomain" default-realm="cached-ldap" permission-mapper="default-permission-mapper">
		   <realm name="cached-ldap"/>
		</security-domain>				                
            </security-domains>
            <security-realms>
                .....                
                <!-- my LDAP realm -->
		<ldap-realm name="ldap-realm" dir-context="ldap-connection" direct-verification="true">
			<identity-mapping rdn-identifier="sAMAccountName" use-recursive-search="false" search-base-dn="CN=users,DC=intern,DC=foo,DC=de" >
			  <attribute-mapping>
			   <attribute from="CN" to="Roles" filter="(member={1})" filter-base-dn="CN=users,DC=intern,DC=foo,DC=de"/>
			  </attribute-mapping>
			</identity-mapping>
		</ldap-realm>
		<caching-realm  name="cached-ldap" realm="ldap-realm"/>			    
            </security-realms>
            
            <!-- LDAP Dir Contexts -->
            <dir-contexts>
		<dir-context name="ldap-connection" url="ldap://my-ldap:389" principal="CN=bind_user,CN=users,DC=intern,DC=foo,DC=de">
		     <credential-reference clear-text="YOUR-PASSWORD"/>
		</dir-context>
    	    </dir-contexts>
.....
       

You have to tweak the dir-context and the base-dn in the example above to your LDAP settings. The setup searches for the sAMAccountName as the UserID and searches the roles in the ‘members’ attribute of the user entry.

The cached-ldap

The important part is the ‘cached-ldap‘ security realm. In older versions of Wildfly the ldap realm uses a cache per default. In the new version you need to define a cache by yourself. This is what the cached-ldap is good for. Your security domain points to the cached-ldap and the cached-ldap points to the ldap realm. If you don’t use this, you will see a lot of ldap requests against your directory.

You can also add attributes to setup the default caching like:

<caching-realm name="cached-ldap" realm="ldap-realm" maximum-age="300000" />

Find details here.

Logging

For debugging it is helpful if you change the loglevel for org.wildfly.security. For this you simply add the following logger into the subsystem logging:

        <logger category="org.wildfly.security">
	    <level name="DEBUG"/>
	</logger>

And also set the log level from “INFO” to “DEBUG” for your console handler. This setting will give you more insights of what is happening in the background.

From a server bash you can ‘tail’ the security messages like this:

$ tail -f /opt/jboss/wildfly/standalone/log/server.log  | grep "security"

Role Mapping

In some cases it maybe necessary to map LDAP Group names to specific role names within your application. There for you can use the mappers. See the following example which maps the LDAP Group name ‘imixs_users’ to the application role ‘org.imixs.ACCESSLEVEL.AUTHORACCESS’:

            <security-domains>
               ....
		<security-domain name="imixsrealm" default-realm="cached-ldap" permission-mapper="default-permission-mapper">
		 <realm name="cached-ldap" role-mapper="imixs-user-rolemapper" />
		</security-domain>	                
            </security-domains>
.....
            <mappers>
                .....              
                <regex-role-mapper name="imixs-user-rolemapper" pattern="imixs_user" replacement="org.imixs.ACCESSLEVEL.AUTHORACCESS" keep-non-mapped="true"/>
            </mappers>
....

The mapper is referred in the security-domain. I am using a regex role mapper to replace the role name. You will find more background about this role mapping here.