In this tutorial we will learn how to configure Authentication with an Elytron LDAP-Based Identity Store on the top of WildFly application Server
Hard requirements
- WildFly 11 or newer
- A LDAP Server or a Docker deamon to start an LDAP Server in a Container
For the sake of simplicity, we will start a Containerised version of OpenLdap, which is available in the DockerHub, using as BASE DN wildfly.org:
$ docker run --env LDAP_ORGANISATION="wildfly" --env LDAP_DOMAIN="wildfly.org" --env LDAP_ADMIN_PASSWORD="admin" --detach osixia/openldap
As an alternative, you can set the BASE DN in your slapf.conf and set the default admin password.
Check your IP Address from your container:
$ docker inspect --format '{{ .NetworkSettings.IPAddress }}' $(docker ps -q) 172.17.0.2
Now verify the connection with any LDAP Browser:
Ok, the connection worked so now upload a sample ldif file which will contain one user named “frank” which is granted the Role “Admin”:
dn: ou=Users,dc=wildfly,dc=org objectClass: organizationalUnit objectClass: top ou: Users dn: uid=frank,ou=Users,dc=wildfly,dc=org objectClass: top objectClass: person objectClass: inetOrgPerson cn: Franky sn: frank uid: frank userPassword: secret123 dn: ou=Roles,dc=wildfly,dc=org objectclass: top objectclass: organizationalUnit ou: Roles dn: cn=Admin,ou=Roles,dc=wildfly,dc=org objectClass: top objectClass: groupOfNames cn: Admin member: uid=frank,ou=Users,dc=wildfly,dc=org
You should be able to see the updated Directory from your LDAP Browser:
Configuring the Elytron LDAP Realm
Firstly, start WildFly and connect to the Command Line Interface.
The first thing we will need to do is configuring a Directory Context with the URL of the LDAP Server and the information related to the Principal:
/subsystem=elytron/dir-context=exampleDC:add(url="ldap://172.17.0.2:389",principal="cn=admin,dc=wildfly,dc=org",credential-reference={clear-text="secret"})
Next, it’s time to create an LDAP Realm which references the Directory Context, specifying the Search Base DN, how and Users are mapped:
/subsystem=elytron/ldap-realm=exampleLR:add(dir-context=exampleDC,identity-mapping={search-base-dn="ou=Users,dc=wildfly,dc=org",rdn-identifier="uid",user-password-mapper={from="userPassword"},attribute-mapping=[{filter-base-dn="ou=Roles,dc=wildfly,dc=org",filter="(&(objectClass=groupOfNames)(member={1}))",from="cn",to="Roles"}]})
Next, you will need creating a Role Decoder which, in its simplest form, takes a single attribute and maps it directly to roles.
/subsystem=elytron/simple-role-decoder=from-roles-attribute:add(attribute=Roles)
Ok, we have the LDAP Realm, the Role Decoder so we will create a Security Domain which uses this information:
/subsystem=elytron/security-domain=exampleLdapSD:add(realms=[{realm=exampleLR,role-decoder=from-roles-attribute}],default-realm=exampleLR,permission-mapper=default-permission-mapper)
As the Security Domain will be used to authenticate users through HTTP, we will need to add an Http Authentication Factory which is configured to use the above defined Security Domain and LDAP Realm:
/subsystem=elytron/http-authentication-factory=example-ldap-http-auth:add(http-server-mechanism-factory=global,security-domain=exampleLdapSD,mechanism-configurations=[{mechanism-name=BASIC,mechanism-realm-configurations=[{realm-name=myApplicationDomain}]}])
We are finished with Elytron. The last piece of the puzzle will be the Http Authentication Factory into Undertow, so that incoming request will be handled by the Security Domain:
/subsystem=undertow/application-security-domain=myApplicationDomain:add(http-authentication-factory=example-ldap-http-auth)
We are done! The above CLI command should reflect in the following server configuration:
<?xml version="1.0" encoding="UTF-8"?> <subsystem xmlns="urn:wildfly:elytron:1.2" final-providers="combined-providers" disallowed-providers="OracleUcrypto"> <security-domains> . . . <security-domain name="exampleLdapSD" default-realm="exampleLR" permission-mapper="default-permission-mapper"> <realm name="exampleLR" role-decoder="from-roles-attribute" /> </security-domain> </security-domains> <security-realms> . . . . . <ldap-realm name="exampleLR" dir-context="exampleDC"> <identity-mapping rdn-identifier="uid" search-base-dn="ou=Users,dc=wildfly,dc=org"> <attribute-mapping> <attribute from="cn" to="Roles" filter="(&(objectClass=groupOfNames)(member={1}))" filter-base-dn="ou=Roles,dc=wildfly,dc=org" /> </attribute-mapping> <user-password-mapper from="userPassword" /> </identity-mapping> </ldap-realm> </security-realms> <mappers> . . . . <simple-role-decoder name="from-roles-attribute" attribute="Roles" /> </mappers> <http> <http-authentication-factory name="management-http-authentication" http-server-mechanism-factory="global" security-domain="ManagementDomain"> . . . . <http-authentication-factory name="example-ldap-http-auth" http-server-mechanism-factory="global" security-domain="exampleLdapSD"> <mechanism-configuration> <mechanism mechanism-name="BASIC"> <mechanism-realm realm-name="exampleApplicationDomain" /> </mechanism> </mechanism-configuration> </http-authentication-factory> <provider-http-server-mechanism-factory name="global" /> </http> <sasl> . . . . </sasl> <dir-contexts> <dir-context name="exampleDC" url="ldap://172.17.0.2:389" principal="cn=admin,dc=wildfly,dc=org"> <credential-reference clear-text="admin" /> </dir-context> </dir-contexts> </subsystem>
Application Configuration
In order to test your application, include the Security bindings in your jboss-web.xml and web.xml.
Here is the jboss-web.xml bit:
<jboss-web> <security-domain>myApplicationDomain</security-domain> </jboss-web>
And this is a sample web.xml:
<web-app> <security-constraint> <web-resource-collection> <web-resource-name>secure</web-resource-name> <url-pattern>/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>Admin</role-name> </auth-constraint> </security-constraint> <security-role> <description>Ldap Secured</description> <role-name>Admin</role-name> </security-role> <login-config> <auth-method>BASIC</auth-method> <realm-name>myApplicationDomain</realm-name> </login-config> </web-app>