Creating an Elytron Security Realm for WildFly

Elytron is WildFly’s security framework which has replaced the PicketBox legacy security system. In this tutorial we will have an overview of it and learn how to create a sample Elytron File System Realm to secure applications. Next, we will learn how to encrypt the content of Identities in the File System.

Overview of Elytron Realms

Firstly, one of the main advantages of Elytron is that it provides an unified security solution across the application server. Elytron key points are also the following ones:

  • Secure server-side authentication mechanisms based on HTTP, SASL,and TLS, as well as supporting other authentication protocols in the future
  • Support for password credential types using the standard Java cryptography extension structure (such as DES, MD5, SHA, bcrypt, and so on)

The following picture shows Elytron building blocks:

elytron wildfly tutorial

An elytron Security Realm encapsulates and integrates the application server with an identity store or repository (such as an LDAP server or a database). Hence, they are mainly responsible for obtaining or verifying credentials, obtaining the attributes associated with a given identity and last, but also important, creating an internal representation based on this information that a Security Domain uses to authenticate and perform role and permission mappings for a given principal.

Built-in Elytron Realms

By default, elytron provides some built-in implementations of security realms that are capable of managing your identities. Here are some examples:

  • FileSystem Security Realm : The class org.wildfly.security.auth.realm.FileSystemSecurityRealm provides an implementation for a security realm which uses a FileSystem to store identities
  • JDBC Security realm : The class org.wildfly.security.auth.realm.jdbc.JdbcSecurityRealm provides a security realm implementation backed by a database. (Learn more here: How to configure an Elytron JDBC Realm on WildFly )
  • LDAP security realm : The class org.wildfly.security.auth.realm.ldap.LdapSecurityRealm is a security realm implementation backed by LDAP  (Learn more here: How to configure an Elytron LDAP Realm on WildFly )
  • Property security realm: The class org.wildfly.security.auth.realm.LegacyPropertiesSecurityRealm is an implementation that makes use of the legacy property files
  • Java KeyStores security realm: The class org.wildfly.security.auth.realm.KeyStoreBackedSecurityRealm is a Keystore-backed security realm
  • Token security realm: The class org.wildfly.security.auth.realm.token.TokenSecurityRealm is a security realm capable of building identities based on different security token formats based on a TokenValidator
  • JAAS security realm: which uses a LoginContext initialized from a JAAS configuration file to authenticate and authorize users with custom Login Modules. (Learn more here: How to configure an Elytron JAAS Security Realm )

The other key block of elytron is the security domain which is the entry point to all security operations available in your server infrastructure. It contains a high-level view of security policies and resources associated with your IT domain.

Don’t confuse the term domain with an Internet Protocol (IP) resource. An elytron domain can be composed of a single application or multiple applications which share the same security policies.

Finally, In terms of responsibilities, a security domain is in charge of:

  • Mapping a principal to its corresponding identity on a specific security realm
  • Permission mapping
  • Role mapping
  • Obtain the current and authorized identity and all information associated with it, such as roles, permissions, and attributes

Creating an Elytron FileSystem Realm

The most basic example of a security realm is the FileSystem Realm, which stores the identity information on a filesystem, by paging each identity in an XML file containing credentials and Roles.

Start the application server and connect to it from a CLI.

First of all, before starting the FileSystem Realm batch, we need to add a Simple Role Decoder which maps the application Roles from the attribute Roles in the File system. It’s recommended to use a conditional execution of this statement, in case the Role Decoder has been already created:

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

Now let’s define a new filesystem-realm named fsRealm and its respective path on the file system:

batch

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

Next, we will be adding some identities to the Realm:

/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"])

Done with that, we will then create a new Security Domain which maps our Realm:

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

Now we have both a Realm and a Security Domain available and correctly mapped. As we will test our Realm with a Web application, we need an Http Authentication Factory which references our Security Domain:

/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}]}])

Finally, a Security Domain in the undertow’s subsystem will be associated with our Http Authentication Factory:

/subsystem=undertow/application-security-domain=httpFsSD:add(http-authentication-factory=example-fs-http-auth)

Run the above batch and check that it executes successfully.

run-batch

Testing the Elytron Security Realm

The above example uses an HTTP Authentication Factory to reference the Security Domain of Elytron. Therefore, in order to test our File System Realm we will be using a simple Web Application which contains a secured Servlet.

Using a Declarative approach to define the Roles Allowed to the Servlet, we will restrict access only to users belonging to the “Admin” Role:

@WebServlet("/secure")
@ServletSecurity(@HttpConstraint(rolesAllowed = { "Admin" }))
public class SecuredServlet extends HttpServlet {
. . .
}

Finally, we will link the Web application to our Security Domain by setting the security-domain attribute in jboss-web.xml:

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

As a result, when you access the Web application, you will receive a BASIC HTTP Authentication challenge:

elytron wildfly tutorial

Encrypting the Security Realm

If you are running WildFly 26.1 or newer you can also encrypt the files where elytron stores the Identities. We will show how to do that from the Command Line Interface.

Firstly, configure the credential store (secret.cs) that will contain the SecretKey to encrypt and decrypt the filesystem realm:

/subsystem=elytron/secret-key-credential-store=credstore:add(path=secret.cs, relative-to=jboss.server.config.dir, create=true, populate=true)

The following batch script, configures a file system realm which uses the above Credential Store that contains the Secret:

# Start batching commands
batch

# Configure a filesystem realm with a single identity
/subsystem=elytron/filesystem-realm=encFsRealm:add(path=fs-realm,relative-to=jboss.server.config.dir, credential-store=credstore, secret-key=key)
/subsystem=elytron/filesystem-realm=encFsRealm:add-identity(identity=quickstartUser)
/subsystem=elytron/filesystem-realm=encFsRealm:set-password(digest={algorithm=digest-md5, realm=encFsRealm, password=password123!}, identity=quickstartUser)
/subsystem=elytron/filesystem-realm=encFsRealm:add-identity-attribute(identity=quickstartUser, name=Roles, value=["Admin", "Guest"])

# Add a simple role decoder
/subsystem=elytron/simple-role-decoder=from-roles-attribute:add(attribute=Roles)

# Configure a new security domain to use our filesystem realm and role decoder
/subsystem=elytron/security-domain=fsDomain:add(realms=[{realm=encFsRealm, role-decoder=from-roles-attribute}], default-realm=encFsRealm,permission-mapper=default-permission-mapper)

# Add the case security domain mapping in the Undertow subsystem
/subsystem=undertow/application-security-domain=other:write-attribute(name=security-domain, value=fsDomain)

# Run the batch commands
run-batch

# Reload the server configuration
reload

In the above example, the Identity “quickstartUser” with password “password123!” is granted the Roles “Admin” and “Guest”.

After running the above script, you will see the configuration folder includes an entry for our Identity:

fs-realm/
└── O
    └── F
        └── OF2WSY3LON2GC4TUKVZWK4Q.xml

If you look inside the XML file, you will see that the content is now encrypted:

<identity xmlns="urn:elytron:identity:1.1">
    <credentials>
        <password algorithm="digest-md5" format="enc_base64">RUxZAUMQbA5Xc/tzwgo8JM5qxR8VzycNrk9xAr9RNjNwddVWJYOoS+4wItUT/qEEpN2eo6ggZLp8LtERkMLSTgX5icrVzA==</password>
    </credentials>
    <attributes>
        <attribute name="RUxZAUMQub8SjOoKpYYCVtmuPSlzkQlnYZpIpvBi81ym43E6zhs=" value="RUxZAUMQjqbHdKkaanOhYpwe5u2EtJhfBcFnRVd6473khj449Qk="></attribute>
        <attribute name="RUxZAUMQLflIQShDR88XnuJsjICuU6l2k2dTbTOFrExi8STCXQw=" value="RUxZAUMQdTixB+GmrplQ0/1Ri8bLrafhvc2MNAnYwqr2Wm8BuFk="></attribute>
    </attributes>
</identity>

That’s all for now. In the next tutorial we will show some more examples of Elytron Security realms. Stay tuned!

Found the article helpful? if so please follow us on Socials