How to use failover and distributed Realms in Elytron

In this tutorial we will learn how to create failover and distributed Elytron Realms to add resilience and distribution to your identity lookup.

The option to stack multiple login modules is already available in the legacy Security Model. As the legacy security model is soon going to be deprecated, all the missing features are now available also in Elytron.

The first Realm we will discuss is the Failover Realm which allows to failover the Identity Lookup to another Identity Store in case of failure. Let’s see how this can be configured.

We will be using the following Identity Store set up:

  • LDAP Realm: Base Realm (called “delegate realm” in Elytron)
  • File System Realm: Failover Realm

Let’s start adding the LDAP Realm. Login to the CLI and execute the following commands:

if (outcome != success) of /subsystem=elytron/simple-role-decoder=from-roles-attribute:read-resource
 /subsystem=elytron/simple-role-decoder=from-roles-attribute:add(attribute=Roles) 
end-if

batch

/subsystem=elytron/dir-context=exampleDC:add(url="ldap://localhost:389",principal="cn=admin,dc=wildfly,dc=org",credential-reference={clear-text="secret"})

/subsystem=elytron/ldap-realm=demoLdapRealm: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"}]})

/subsystem=elytron/security-domain=ldapSD:add(realms=[{realm=demoLdapRealm,role-decoder=from-roles-attribute}],default-realm=demoLdapRealm,permission-mapper=default-permission-mapper)

/subsystem=elytron/http-authentication-factory=example-ldap-http-auth:add(http-server-mechanism-factory=global,security-domain=ldapSD,mechanism-configurations=[{mechanism-name=BASIC,mechanism-realm-configurations=[{realm-name=RealmUsersRoles}]}])

run-batch

So the first block of instructions will create an LDAP realm based on the BaseDN “ou=Users,dc=wildfly,dc=org” running on localhost:389. Don’t care about starting up an LDAP Server as this connection is supposed to fail.

Now let’s add a File System Realm which will be our fallback Realm:

batch

/subsystem=elytron/filesystem-realm=demoFsRealm:add(path=demofs-realm-users,relative-to=jboss.server.config.dir)

/subsystem=elytron/filesystem-realm=demoFsRealm:add-identity(identity=frank)
/subsystem=elytron/filesystem-realm=demoFsRealm:set-password(identity=frank,clear={password="password123"})
/subsystem=elytron/filesystem-realm=demoFsRealm:add-identity-attribute(identity=frank,name=Roles, value=["Admin","Guest"])

/subsystem=elytron/security-domain=fsSD:add(realms=[{realm=demoFsRealm,role-decoder=from-roles-attribute}],default-realm=demoFsRealm,permission-mapper=default-permission-mapper)

/subsystem=elytron/http-authentication-factory=example-fs-http-auth:add(http-server-mechanism-factory=global,security-domain=fsSD,mechanism-configurations=[{mechanism-name=BASIC,mechanism-realm-configurations=[{realm-name=RealmUsersRoles}]}])

run-batch

Finally, create the Failover Realm which will be a wrapper around the two base Realms:

# Create a Failover Realm
/subsystem=elytron/failover-realm=failoverRealm:add(delegate-realm=demoLdapRealm,failover-realm=demoFsRealm)

# Create a Security Domain for the Failover Realm
/subsystem=elytron/security-domain=failoverSD:add(default-realm=failoverRealm,permission-mapper=default-permission-mapper,realms=[{realm=failoverRealm,role-decoder="from-roles-attribute"}])

# Add an HTTP Authentication Factory for our Security Domain
/subsystem=elytron/http-authentication-factory=example-failover-http-auth:add(http-server-mechanism-factory="global",mechanism-configurations=[{mechanism-name="BASIC",mechanism-realm-configurations=[{realm-name="RealmUsersRoles"}]}],security-domain=failoverSD)

# Add the Failover Domain to the HTTP Authentication Factory
/subsystem=undertow/application-security-domain=httpLdapSD:add(http-authentication-factory=example-failover-http-auth)
run-batch

We are done with the configuration. Reload for changes to take effect:

reload

The most interesting bit is the failover-realm configuration, which holds a reference to the two wrapped Realms:

 <failover-realm name="failoverRealm" delegate-realm="demoLdapRealm" failover-realm="demoFsRealm"/> 

As a proof of concept, you can deploy the following application: https://github.com/fmarchioni/wildfly-admin-guide/tree/master/chapter15/servlet-security

This application references the Security Domain known to undertow’s Authentication Factory:

<jboss-web>
	<security-domain>httpLdapSD</security-domain>
</jboss-web>

If you try to access the Secured Servlet (http://localhost:8080/demo-security/secure) when the LDAP Server is not available, the failover will happen:

17:32:54,019 WARN  [org.wildfly.security] (default task-1) ELY13001: Realm is failing over.: org.wildfly.security.auth.server.RealmUnavailableException: ELY01125: Ldap-backed realm failed to obtain context
	at [email protected]//org.wildfly.security.auth.realm.ldap.LdapSecurityRealm.obtainContext(LdapSecurityRealm.java:214)
	at [email protected]//org.wildfly.security.auth.realm.ldap.LdapSecurityRealm.access$600(LdapSecurityRealm.java:101)

You can login using the user added in the File System Realm (frank/password123).

Using a Distributed Realm

The other option for configuring Realm redundancy is the Distributed Realm. The Distributed Realm is not about failing over in the event of a Realm being unavailable (although it may be related). This Realm can be rather used when identities are located across multiple stores. Therefore, identity look up will be attempted sequentially across all Realms included in the list, until one succeeds.

You can add a distributed-realm element to your configuration as follows:

<distributed-realm name="distributedRealm" realms="demoLdapRealm demoFsRealm" />

Unlike the Failover Realm, the above configuration requires that the LDAP Server is available, although Identity lookup will be checked on the File System Realm if that failed on LDAP.