Chapter 1. Configuring identity stores 1.1. Creating an aggregate realm 1.1.1. Aggregate realm in Elytron With an aggregate realm, aggregate-realm , you can use one security realm for authentication and another security realm, or an aggregation of multiple security realms, for authorization in Elytron. For example, you can configure an aggregate-realm to use an ldap-realm for authentication and aggregation of a filesystem-realm and an ldap-realm for authorization. An identity is created in an aggregate realm configured with multiple authorization realms as follows: Attribute values from each authorization realm are loaded. If an attribute is defined in more than one authorization realm, the value of the first occurrence of the attribute is used. The following example illustrates how identity is created when multiple authorization realms contain definitions for the same identity attribute. Example aggregate realm configuration In the example, the configured aggregate-realm references two existing security realms: "exampleLDAPRealm", which is an LDAP realm, and "exampleFilesystemRealm", which is a filesystem realm. Attribute values obtained from the LDAP realm: Attribute values obtained from the filesystem realm: Resulting identity obtained from the aggregate realm: The example aggregate-realm uses the value for the attribute mail defined in the LDAP realm because the LDAP realm is referenced before the filesystem realm. Additional resources Creating an aggregate-realm in Elytron 1.1.2. Examples of creating security realms required for an aggregate realm The following examples illustrate creating ldap-realm and filesystem-realm . You can reference these security realms in an aggregate-realm . 1.1.2.1. Creating an ldap-realm in Elytron example Create an Elytron security realm backed by a Lightweight Directory Access Protocol (LDAP) identity store to secure the JBoss EAP server interfaces or the applications deployed on the server. For the examples in this procedure, the following LDAP Data Interchange Format (LDIF) is used: The LDAP connection parameters used for the example are as follows: LDAP URL: ldap://10.88.0.2 LDAP admin password: secret You need this for Elytron to connect with the LDAP server. LDAP admin Distinguished Name (DN): (cn=admin,dc=wildfly,dc=org) LDAP organization: wildfly If no organization name is specified, it defaults to Example Inc . LDAP domain: wildfly.org This is the name that is matched when the platform receives an LDAP search reference. Prerequisites You have configured an LDAP identity store. JBoss EAP is running. Procedure Configure a directory context that provides the URL and the principal used to connect to the LDAP server. Example Create an LDAP realm that references the directory context. Specify the Search Base DN and how users are mapped. Syntax Example You can now use this realm to create a security domain or to combine with another realm in failover-realm , distributed-realm , or aggregate-realm . 1.1.2.2. Creating a filesystem-realm in Elytron example Create an Elytron security realm backed by a file system-based identity store to secure the JBoss EAP server interfaces or the applications deployed on the server. Prerequisites JBoss EAP is running. Procedure Create a filesystem-realm in Elytron. Syntax Example Add a user to the realm and configure the user's role. Add a user. Syntax Example Set roles for the user. Syntax Example Set attributes for the user. Syntax Example You can now use this realm to create a security domain or to combine with another realm in failover-realm , distributed-realm , or aggregate-realm . 1.1.3. Creating an aggregate-realm in Elytron Create an aggregate-realm in Elytron that uses one security realm for authentication and aggregation of multiple security realms for authorization. Use the aggregate-realm to create a security domain to add authentication and authorization to management interfaces and deployed applications. Prerequisites JBoss EAP is running. You have created the realms to reference from the aggregate realm. Procedure Create an aggregate-realm from existing security realms. Syntax Example Create a role decoder to map attributes to roles. Syntax Example Create a security domain that references the aggregate-realm and the role decoder. Syntax Example You now can use the created security domain to add authentication and authorization to management interfaces and applications. For more information, see Securing management interfaces and applications . Additional resources aggregate-realm attributes security-domain attributes simple-role-decoder attributes 1.2. Creating a caching realm 1.2.1. Caching realm in Elytron Elytron provides caching-realm to cache the results of a credential lookup from a security realm. The caching-realm caches the PasswordCredential credential using a LRU or Least Recently Used caching strategy, in which the least accessed entries are discarded when maximum number of entries is reached. You can use a caching-realm with the following security realms: filesystem-realm jdbc-realm ldap-realm a custom security realm If you make changes to your credential source outside of JBoss EAP, those changes are only propagated to a JBoss EAP caching realm if the underlying security realm supports listening. Only ldap-realm supports listening. However, filtered attributes, such as roles , inside the ldap-realm do not support listening. To ensure that your caching realm has a correct cache of user data, ensure the following: Clear the caching-realm cache after you modify the user attributes at your credential source. Modify your user attributes through the caching realm rather than at your credential source. Important Making user changes through a caching realm is provided as Technology Preview only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs), might not be functionally complete, and Red Hat does not recommend to use them for production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process. See Technology Preview Features Support Scope on the Red Hat Customer Portal for information about the support scope for Technology Preview features. Additional resources Creating a caching-realm in Elytron caching-realm attributes Clearing the caching-realm cache 1.2.2. Creating a caching-realm in Elytron Create a caching-realm and a security domain that references the realm to secure the JBoss EAP server interfaces or the applications deployed on the server. Note An ldap-realm configured as caching realm does not support Active Directory. For more information, see Changing LDAP/AD User Password via JBossEAP CLI for Elytron . Prerequisites You have configured the security realm to cache. Procedure Create a caching-realm that references the security realm to cache. Syntax Example Create a security domain that references the caching-realm . Syntax Example Verification To verify that Elytron can load data from the security realm referenced in the caching-realm into the caching-realm , use the following command: Syntax Example You now can use the created security domain to add authentication and authorization to management interfaces and applications. For more information, see Securing management interfaces and applications . Additional resources caching-realm attributes Clearing the caching-realm cache security-domain attributes 1.2.3. Clearing the caching-realm cache Clearing a caching-realm cache forces Elytron to re-populate the cache by using the latest data from the security realm, which Elytron is configured to cache. Prerequisites A caching-realm is configured. Procedure Clear the caching-realm cache. Syntax Example Additional resources caching-realm attributes 1.3. Creating a distributed realm 1.3.1. Distributed realm in Elytron With a distributed realm, you can search across different identity stores by referencing existing security realms. The identity obtained is used for both authentication and authorization. Elytron invokes the security realms in a distributed realm in the order that you define them in the distributed-realm resource. Example distributed-realm configuration In the example, the configured distributed-realm references two existing security realms: "exampleLDAPRealm", which is an LDAP realm, and "exampleFilesystemRealm", which is a filesystem realm. Elytron searches the referenced security realms sequentially as follows: Elytron first searches the LDAP realm for a matching identity. If Elytron finds a match, the authentication succeeds. If Elytron does not find a match, it searches the filesystem realm. By default, in case the connection to any identity store fails before an identity is matched, the authentication fails with an exception RealmUnavailableException and no more realms are searched. You can change this behavior by setting the attribute ignore-unavailable-realms to true . If the connection to an identity store fails when ignore-unavailable-realms is set to true , Elytron continues to search the remaining realms. When ignore-unavailable-realms is set to true , emit-events is by default set to true , so a SecurityEvent is emitted in case any of the queried realms is unavailable. You can turn this off by setting emit-events to false . Additional resources Creating a distributed-realm in Elytron 1.3.2. Examples of creating security realms required for a distributed realm The following examples illustrate creating ldap-realm and filesystem-realm . You can reference these security realms in a distributed-realm . 1.3.2.1. Creating an ldap-realm in Elytron example Create an Elytron security realm backed by a Lightweight Directory Access Protocol (LDAP) identity store to secure the JBoss EAP server interfaces or the applications deployed on the server. For the examples in this procedure, the following LDAP Data Interchange Format (LDIF) is used: The LDAP connection parameters used for the example are as follows: LDAP URL: ldap://10.88.0.2 LDAP admin password: secret You need this for Elytron to connect with the LDAP server. LDAP admin Distinguished Name (DN): (cn=admin,dc=wildfly,dc=org) LDAP organization: wildfly If no organization name is specified, it defaults to Example Inc . LDAP domain: wildfly.org This is the name that is matched when the platform receives an LDAP search reference. Prerequisites You have configured an LDAP identity store. JBoss EAP is running. Procedure Configure a directory context that provides the URL and the principal used to connect to the LDAP server. Example Create an LDAP realm that references the directory context. Specify the Search Base DN and how users are mapped. Syntax Example You can now use this realm to create a security domain or to combine with another realm in failover-realm , distributed-realm or aggregate-realm . You can also configure a caching-realm for the ldap-realm to cache the result of lookup and improve performance. 1.3.2.2. Creating a filesystem-realm in Elytron example Create an Elytron security realm backed by a file system-based identity store to secure the JBoss EAP server interfaces or the applications deployed on the server. Prerequisites JBoss EAP is running. Procedure Create a filesystem-realm in Elytron. Syntax Example Add a user to the realm and configure the user's role. Add a user. Syntax Example Set a password for the user. Syntax Example Set roles for the user. Syntax Example You can now use this realm to create a security domain or to combine with another realm in failover-realm , distributed-realm , or aggregate-realm . 1.3.3. Creating a distributed-realm in Elytron Create a distributed-realm in Elytron that references existing security realms to search for an identity. Use the distributed-realm to create a security domain to add authentication and authorization to management interfaces or the applications deployed on the server. Prerequisites JBoss EAP is running. You have created the realms to reference in the distributed-realm . Procedure Create a distributed-realm referencing existing security realms. Syntax Example Create a role decoder to map attributes to roles. Syntax Example Create a security domain that references the distributed-realm and the role decoder. Syntax Example You now can use the created security domain to add authentication and authorization to management interfaces and applications. For more information, see Securing management interfaces and applications . Additional resources distributed-realm attributes security-domain attributes simple-role-decoder attributes 1.4. Creating a failover realm 1.4.1. Failover realm in Elytron You can configure a failover security realm, failover-realm , in Elytron that references two existing security realms so that in case one security realm fails, Elytron uses the other as a backup. A failover-realm in Elytron references two security realms: delegate-realm : The primary security realm to use. failover-realm : The security realm to use as the backup. Example failover-realm configuration In the example, exampleLDAPRealm , which is an ldap-realm , is used as the delegate realm and exampleFileSystemRealm , which is a filesystem-realm is used as the failover-realm . In the case that the ldap-realm fails, Elytron will use the filesystem-realm for authentication and authorization. Note In a failover-realm , the failover-realm is invoked only when the delegate-realm fails. The fail-over realm is not invoked if the connection to the delegate-realm succeeds but the required identity is not found. To search for identity across multiple security realms, use the distributed-realm . 1.4.2. Examples of creating security realms required for a failover realm The following examples illustrate creating ldap-realm and filesystem-realm . You can reference these security realms in a failover-realm . 1.4.2.1. Creating an ldap-realm in Elytron example Create an Elytron security realm backed by a Lightweight Directory Access Protocol (LDAP) identity store to secure the JBoss EAP server interfaces or the applications deployed on the server. For the examples in this procedure, the following LDAP Data Interchange Format (LDIF) is used: The LDAP connection parameters used for the example are as follows: LDAP URL: ldap://10.88.0.2 LDAP admin password: secret You need this for Elytron to connect with the LDAP server. LDAP admin Distinguished Name (DN): (cn=admin,dc=wildfly,dc=org) LDAP organization: wildfly If no organization name is specified, it defaults to Example Inc . LDAP domain: wildfly.org This is the name that is matched when the platform receives an LDAP search reference. Prerequisites You have configured an LDAP identity store. JBoss EAP is running. Procedure Configure a directory context that provides the URL and the principal used to connect to the LDAP server. Example Create an LDAP realm that references the directory context. Specify the Search Base DN and how users are mapped. Syntax Example You can now use this realm to create a security domain or to combine with another realm in failover-realm , distributed-realm or aggregate-realm . You can also configure a caching-realm for the ldap-realm to cache the result of lookup and improve performance. 1.4.2.2. Creating a filesystem-realm in Elytron example Create an Elytron security realm backed by a file system-based identity store to secure the JBoss EAP server interfaces or the applications deployed on the server. Prerequisites JBoss EAP is running. Procedure Create a filesystem-realm in Elytron. Syntax Example Add a user to the realm and configure the user's role. Add a user. Syntax Example Set a password for the user. Syntax Example Set roles for the user. Syntax Example You can now use this realm to create a security domain or to combine with another realm in failover-realm , distributed-realm , or aggregate-realm . 1.4.3. Creating a failover-realm in Elytron Create a failover security realm in Elytron that references existing security realms as a delegate realm, the default realm to use, and a failover realm. Elytron uses the configured failover realm in case the delegate realm fails. Use the security realm to create a security domain to add authentication and authorization to management interfaces or the applications deployed on the server. Prerequisites JBoss EAP is running. You have created the realms to use as the delegate and failover realm. Procedure Create a failover-realm from existing security realms. Syntax Example Create a role decoder to map attributes to roles. Syntax Example Create a security domain that references the failover-realm and the role decoder. Syntax Example You now can use the created security domain to add authentication and authorization to management interfaces and applications. For more information, see Securing management interfaces and applications . Additional resources failover-realm attributes security-domain attributes simple-role-decoder attributes 1.5. Creating a JAAS realm 1.5.1. JAAS realm in Elytron The Java Authentication and Authorization Service (JAAS) realm, jaas-realm , is a security realm that you can use to configure custom login modules in the elytron subsystem for credential verification of users and assigning users roles. You can use jaas-realm for securing both JBoss EAP management interfaces and the deployed applications. The JAAS realm verifies user credentials by initializing a javax.security.auth.login.LoginContext , which uses login modules specified in the JAAS configuration file. A login module is an implementation of javax.security.auth.login.LoginContext.LoginModule interface. Add these implementations as a JBoss EAP module to your server and specify them in the JAAS configuration file. Example of JAAS configuration file 1 Name of the entry that you use when configuring the jaas-realm . 2 Login module with its optional flags. You can use all the flags defined by JAAS. For more information, see JAAS Login Configuration File in the Oracle Java SE documentation. 3 Login module with its optional flags and options. Subject's principals to attributes mapping and roles association in login modules You can add attributes to identities obtained from login modules by utilizing a subject 's principals. A subject is the user being authenticated and principals are identifiers, such as the user name, contained within a subject. Elytron obtains and maps identities as follows: Login modules use javax.security.auth.Subject to represent the user, subject , being authenticated. A subject can have multiple instances of java.security.Principal , principal , associated with it. Elytron uses org.wildfly.security.auth.server.SecurityIdentity to represent authenticated users. Elytron maps subject to SecurityIdentity . A subject's principal s are mapped to security identity's attributes with the following rule: The key of the attribute is principal 's simple class name, obtained by principal.getClass().getSimpleName() call. The value is the principal 's name, obtained by principal.getName() call. For principal s of the same type, the values are appended to the collection under the attribute key. Additional resources Developing custom JAAS login modules Creating a jaas-realm in Elytron Subject class Javadocs Principal class Javadocs 1.5.2. Developing custom JAAS login modules You can create custom Java Authentication and Authorization Service (JAAS) login modules to implement custom authentication and authorization functionality. You can use the custom JAAS login modules through the jaas-realm in the Elytron subsystem to secure JBoss EAP management interfaces and deployed applications. The login modules are not part of a deployment, you include them as JBoss EAP modules. Note The following procedures are provided as an example only. If you already have an application that you want to secure, you can skip these and go directly to Adding authentication and authorization to applications . 1.5.2.1. Creating a Maven project for JAAS login module development For creating custom Java Authentication and Authorization Service (JAAS) login modules, create a Maven project with the required dependencies and directory structure. Prerequisites You have installed Maven. For more information, see Downloading Apache Maven . Procedure Use the mvn command in the CLI to set up a Maven project. This command creates the directory structure for the project and the pom.xml configuration file. Syntax Example Navigate to the application root directory. Syntax Example Replace the content of the generated pom.xml file with the following text: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>custom.loginmodules</groupId> <artifactId>custom-login-modules</artifactId> <version>1.0</version> <dependencies> <dependency> <groupId>org.wildfly.security</groupId> <artifactId>wildfly-elytron</artifactId> <version>1.17.2.Final</version> </dependency> <dependency> <groupId>jakarta.security.enterprise</groupId> <artifactId>jakarta.security.enterprise-api</artifactId> <version>3.0.0</version> </dependency> </dependencies> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties> </project> Remove the directories site and test because they are not required for this example. Verification In the application root directory, enter the following command: You get an output similar to the following: You can now create custom JAAS login modules. 1.5.2.2. Creating custom JAAS login modules Create a custom Java Authentication and Authorization Service (JAAS) login module by creating a class that implements the javax.security.auth.spi.LoginModule interface. Additionally, create JAAS configuration file with flags and options for the custom login module. In this procedure, <application_home> refers to the directory that contains the pom.xml configuration file for the application. Prerequisites You have created a Maven project. For more information, see Creating a Maven project for JAAS login module development . Procedure Create a directory to store the Java files. Syntax Example Navigate to the directory containing the source files. Syntax Example Delete the generated file App.java . Create a file ExampleCustomLoginModule.java for custom login module source. package com.example.loginmodule; import org.wildfly.security.auth.principal.NamePrincipal; import javax.security.auth.Subject; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.auth.login.LoginException; import javax.security.auth.spi.LoginModule; import java.io.IOException; import java.security.Principal; import java.util.Arrays; import java.util.HashMap; import java.util.Map; public class ExampleCustomLoginModule implements LoginModule { private final Map<String, char[]> usersMap = new HashMap<String, char[]>(); private Principal principal; private Subject subject; private CallbackHandler handler; /** * In this example, identities are created as fixed Strings. * * The identities are: * user1 has the password passwordUser1 * user2 has the password passwordUser2 * * Use these credentials when you secure management interfaces * or applications with this login module. * * In a production login module, you would get the identities * from a data source. * */ @Override public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) { this.subject = subject; this.handler = callbackHandler; this.usersMap.put("user1", "passwordUser1".toCharArray()); this.usersMap.put("user2", "passwordUser2".toCharArray()); } @Override public boolean login() throws LoginException { // obtain the incoming username and password from the callback handler NameCallback nameCallback = new NameCallback("Username"); PasswordCallback passwordCallback = new PasswordCallback("Password", false); Callback[] callbacks = new Callback[]{nameCallback, passwordCallback}; try { this.handler.handle(callbacks); } catch (UnsupportedCallbackException | IOException e) { throw new LoginException("Error handling callback: " + e.getMessage()); } final String username = nameCallback.getName(); this.principal = new NamePrincipal(username); final char[] password = passwordCallback.getPassword(); char[] storedPassword = this.usersMap.get(username); if (!Arrays.equals(storedPassword, password)) { throw new LoginException("Invalid password"); } else { return true; } } /** * user1 is assigned the roles Admin, User and Guest. * In a production login module, you would get the identities * from a data source. * */ @Override public boolean commit() throws LoginException { if (this.principal.getName().equals("user1")) { this.subject.getPrincipals().add(new Roles("Admin")); this.subject.getPrincipals().add(new Roles("User")); this.subject.getPrincipals().add(new Roles("Guest")); } return true; } @Override public boolean abort() throws LoginException { return true; } @Override public boolean logout() throws LoginException { this.subject.getPrincipals().clear(); return true; } /** * Principal with simple classname 'Roles' will be mapped to the identity's attribute with name 'Roles'. */ private static class Roles implements Principal { private final String name; Roles(final String name) { this.name = name; } /** * @return name of the principal. This will be added as a value to the identity's attribute which has a name equal to the simple name of this class. In this example, this value will be added to the attribute with a name 'Roles'. */ public String getName() { return this.name; } } } In the <application_home> directory, create JAAS configuration file JAAS-login-modules.conf . exampleConfiguration is the Entry name. com.example.loginmodule.ExampleCustomLoginModule is the login module. optional is the flag. Compile the login module. You can now use the login module to secure JBoss EAP management interfaces and deployed applications. 1.5.3. Creating a jaas-realm in Elytron Create an Elytron security realm backed by Java Authentication and Authorization Service (JAAS)-compatible custom login module to secure JBoss EAP server interfaces or deployed applications. Use the security realm to create a security domain. Prerequisites You have packaged custom login modules as JAR. For an example login module, see Developing custom JAAS login modules . JBoss EAP is running. Procedure Add the login module JAR to JBoss EAP as a module using the management CLI. Syntax Example Create jaas-realm from the login module and the JAAS login configuration file. Syntax Example Create a security domain that references the jaas-realm . Syntax Example You now can use the created security domain to add authentication and authorization to management interfaces and applications. For more information, see Securing management interfaces and applications . Additional resources module command arguments jaas-realm attributes security-domain attributes

Commands:
/subsystem=elytron/aggregate-realm=exampleSecurityRealm:add(authentication-realm=exampleLDAPRealm,authorization-realms=[exampleLDAPRealm,exampleFileSystemRealm])
mail: administrator@example.com telephoneNumber: 0000 0000
mail: user@example.com website: http://www.example.com/
mail: administrator@example.com telephoneNumber: 0000 0000 website: http://www.example.com/
dn: ou=Users,dc=wildfly,dc=org objectClass: organizationalUnit objectClass: top ou: Users dn: uid=user1,ou=Users,dc=wildfly,dc=org objectClass: top objectClass: person objectClass: inetOrgPerson cn: user1 sn: user1 uid: user1 userPassword: passwordUser1 mail: administrator@example.com telephoneNumber: 0000 0000 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=user1,ou=Users,dc=wildfly,dc=org
/subsystem=elytron/dir-context= <dir_context_name> :add(url=" <LDAP_URL> ",principal=" <principal_distinguished_name> ",credential-reference= <credential_reference> )
/subsystem=elytron/dir-context=exampleDirContext:add(url="ldap://10.88.0.2",principal="cn=admin,dc=wildfly,dc=org",credential-reference={clear-text="secret"}) {"outcome" => "success"}
/subsystem=elytron/ldap-realm= <ldap_realm_name> add:(dir-context= <dir_context_name> ,identity-mapping=search-base-dn="ou= <organization_unit> ,dc= <domain_component> ",rdn-identifier=" <relative_distinguished_name_identifier> ",user-password-mapper={from= <password_attribute_name> },attribute-mapping=[{filter-base-dn="ou= <organization_unit> ,dc= <domain_component> ",filter=" <ldap_filter> ",from=" <ldap_attribute_name> ",to=" <identity_attribute_name> "}]})
/subsystem=elytron/ldap-realm=exampleLDAPRealm:add(dir-context=exampleDirContext,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"},{from="mail",to="mail"},{from="telephoneNumber",to="telephoneNumber"}]}) {"outcome" => "success"}
/subsystem=elytron/filesystem-realm= <filesystem_realm_name> :add(path= <file_path> )
/subsystem=elytron/filesystem-realm=exampleFileSystemRealm:add(path=fs-realm-users,relative-to=jboss.server.config.dir) {"outcome" => "success"}
/subsystem=elytron/filesystem-realm= <filesystem_realm_name> :add-identity(identity= <user_name> )
/subsystem=elytron/filesystem-realm=exampleFileSystemRealm:add-identity(identity=user1) {"outcome" => "success"}
/subsystem=elytron/filesystem-realm= <filesystem_realm_name> :add-identity-attribute(identity= <user_name> ,name= <roles_attribute_name> , value=[ <role_1> , <role_N> ])
/subsystem=elytron/filesystem-realm=exampleFileSystemRealm:add-identity-attribute(identity=user1, name=Roles, value=["Admin","Guest"]) {"outcome" => "success"}
/subsystem=elytron/filesystem-realm= <filesystem_realm_name> :add-identity-attribute(identity= <user_name> ,name= <attribute_name> , value=[ <attribute_value> ])
/subsystem=elytron/filesystem-realm=exampleFileSystemRealm:add-identity-attribute(identity=user1, name=mail, value=["user@example.com"]) /subsystem=elytron/filesystem-realm=exampleFileSystemRealm:add-identity-attribute(identity=user1, name=website, value=["http://www.example.com/"])
/subsystem=elytron/aggregate-realm= <aggregate_realm_name> :add(authentication-realm= <security_realm_for_authentication> , authorization-realms=[ <security_realm_for_authorization_1> , <security_realm_for_authorization_2> ,..., <security_realm_for_authorization_N> ])
/subsystem=elytron/aggregate-realm=exampleSecurityRealm:add(authentication-realm=exampleLDAPRealm,authorization-realms=[exampleLDAPRealm,exampleFileSystemRealm]) {"outcome" => "success"}
/subsystem=elytron/simple-role-decoder= <role_decoder_name> :add(attribute= <attribute> )
/subsystem=elytron/simple-role-decoder=from-roles-attribute:add(attribute=Roles) {"outcome" => "success"}
/subsystem=elytron/security-domain= <security_domain_name> :add(default-realm= <aggregate_realm_name> ,permission-mapper=default-permission-mapper,realms=[{realm= <aggregate_realm_name> ,role-decoder=" <role_decoder_name> "}])
/subsystem=elytron/security-domain=exampleSecurityDomain:add(default-realm=exampleSecurityRealm,permission-mapper=default-permission-mapper,realms=[{realm=exampleSecurityRealm,role-decoder="from-roles-attribute"}]) {"outcome" => "success"}
/subsystem=elytron/caching-realm= <caching_realm_name> :add(realm= <realm_to_cache> )
/subsystem=elytron/caching-realm=exampleSecurityRealm:add(realm=exampleLDAPRealm)
/subsystem=elytron/security-domain= <security_domain_name> :add(default-realm= <caching_realm_name> ,permission-mapper=default-permission-mapper,realms=[{realm= <caching_realm_name> ,role-decoder=" <role_decoder_name> "}])
/subsystem=elytron/security-domain=exampleSecurityDomain:add(default-realm=exampleSecurityRealm,permission-mapper=default-permission-mapper,realms=[{realm=exampleSecurityRealm}]) {"outcome" => "success"}
/subsystem=elytron/security-domain= <security_domain_name> :read-identity(name= <username> )
/subsystem=elytron/security-domain=exampleSecurityDomain:read-identity(name=user1) { "outcome" => "success", "result" => { "name" => "user1", "attributes" => {"Roles" => ["Admin"]}, "roles" => ["Admin"] } }
/subsystem=elytron/caching-realm= <caching_realm_name> :clear-cache
/subsystem=elytron/caching-realm=exampleSecurityRealm:clear-cache
/subsystem=elytron/distributed-realm=exampleSecurityRealm:add(realms=[exampleLDAPRealm,exampleFilesystemRealm])
dn: ou=Users,dc=wildfly,dc=org objectClass: organizationalUnit objectClass: top ou: Users dn: uid=user1,ou=Users,dc=wildfly,dc=org objectClass: top objectClass: person objectClass: inetOrgPerson cn: user1 sn: user1 uid: user1 userPassword: userPassword1 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=user1,ou=Users,dc=wildfly,dc=org
/subsystem=elytron/dir-context= <dir_context_name> :add(url=" <LDAP_URL> ",principal=" <principal_distinguished_name> ",credential-reference= <credential_reference> )
/subsystem=elytron/dir-context=exampleDirContext:add(url="ldap://10.88.0.2",principal="cn=admin,dc=wildfly,dc=org",credential-reference={clear-text="secret"}) {"outcome" => "success"}
/subsystem=elytron/ldap-realm= <ldap_realm_name> add:(dir-context= <dir_context_name> ,identity-mapping=search-base-dn="ou= <organization_unit> ,dc= <domain_component> ",rdn-identifier=" <relative_distinguished_name_identifier> ",user-password-mapper={from= <password_attribute_name> },attribute-mapping=[{filter-base-dn="ou= <organization_unit> ,dc= <domain_component> ",filter=" <ldap_filter> ",from=" <ldap_attribute_name> ",to=" <identity_attribute_name> "}]})
/subsystem=elytron/ldap-realm=exampleLDAPRealm:add(dir-context=exampleDirContext,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"}]}) {"outcome" => "success"}
/subsystem=elytron/filesystem-realm= <filesystem_realm_name> :add(path= <file_path> )
/subsystem=elytron/filesystem-realm=exampleFileSystemRealm:add(path=fs-realm-users,relative-to=jboss.server.config.dir) {"outcome" => "success"}
/subsystem=elytron/filesystem-realm= <filesystem_realm_name> :add-identity(identity= <user_name> )
/subsystem=elytron/filesystem-realm=exampleFileSystemRealm:add-identity(identity=user2) {"outcome" => "success"}
/subsystem=elytron/filesystem-realm= <filesystem_realm_name> :set-password(identity= <user_name> , clear={password= <password> })
/subsystem=elytron/filesystem-realm=exampleFileSystemRealm:set-password(identity=user2, clear={password="passwordUser2"}) {"outcome" => "success"}
/subsystem=elytron/filesystem-realm= <filesystem_realm_name> :add-identity-attribute(identity= <user_name> , name= <roles_attribute_name> , value=[ <role_1> , <role_N> ])
/subsystem=elytron/filesystem-realm=exampleFileSystemRealm:add-identity-attribute(identity=user2, name=Roles, value=["Admin","Guest"]) {"outcome" => "success"}
/subsystem=elytron/distributed-realm= <distributed_realm_name> :add(realms=[ <security_realm_1> , <security_realm_2> , ..., <security_realm_N> ])
/subsystem=elytron/distributed-realm=exampleSecurityRealm:add(realms=[exampleLDAPRealm, exampleFileSystemRealm]) {"outcome" => "success"}
/subsystem=elytron/simple-role-decoder= <role_decoder_name> :add(attribute= <attribute> )
/subsystem=elytron/simple-role-decoder=from-roles-attribute:add(attribute=Roles) {"outcome" => "success"}
/subsystem=elytron/security-domain= <security_domain_name> :add(realms=[{realm= <distributed_realm_name> ,role-decoder= <role_decoder_name> }],default-realm= <ldap_realm_name> ,permission-mapper= <permission_mapper> )
/subsystem=elytron/security-domain=exampleSecurityDomain:add(default-realm=exampleSecurityRealm,permission-mapper=default-permission-mapper,realms=[{realm=exampleSecurityRealm,role-decoder="from-roles-attribute"}]) {"outcome" => "success"}
/subsystem=elytron/failover-realm=exampleSecurityRealm:add(delegate-realm=exampleLDAPRealm,failover-realm=exampleFileSystemRealm)
dn: ou=Users,dc=wildfly,dc=org objectClass: organizationalUnit objectClass: top ou: Users dn: uid=user1,ou=Users,dc=wildfly,dc=org objectClass: top objectClass: person objectClass: inetOrgPerson cn: user1 sn: user1 uid: user1 userPassword: userPassword1 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=user1,ou=Users,dc=wildfly,dc=org
/subsystem=elytron/dir-context= <dir_context_name> :add(url=" <LDAP_URL> ",principal=" <principal_distinguished_name> ",credential-reference= <credential_reference> )
/subsystem=elytron/dir-context=exampleDirContext:add(url="ldap://10.88.0.2",principal="cn=admin,dc=wildfly,dc=org",credential-reference={clear-text="secret"}) {"outcome" => "success"}
/subsystem=elytron/ldap-realm= <ldap_realm_name> add:(dir-context= <dir_context_name> ,identity-mapping=search-base-dn="ou= <organization_unit> ,dc= <domain_component> ",rdn-identifier=" <relative_distinguished_name_identifier> ",user-password-mapper={from= <password_attribute_name> },attribute-mapping=[{filter-base-dn="ou= <organization_unit> ,dc= <domain_component> ",filter=" <ldap_filter> ",from=" <ldap_attribute_name> ",to=" <identity_attribute_name> "}]})
/subsystem=elytron/ldap-realm=exampleLDAPRealm:add(dir-context=exampleDirContext,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"}]}) {"outcome" => "success"}
/subsystem=elytron/filesystem-realm= <filesystem_realm_name> :add(path= <file_path> )
/subsystem=elytron/filesystem-realm=exampleFileSystemRealm:add(path=fs-realm-users,relative-to=jboss.server.config.dir) {"outcome" => "success"}
/subsystem=elytron/filesystem-realm= <filesystem_realm_name> :add-identity(identity= <user_name> )
/subsystem=elytron/filesystem-realm=exampleFileSystemRealm:add-identity(identity=user1) {"outcome" => "success"}
/subsystem=elytron/filesystem-realm= <filesystem_realm_name> :set-password(identity= <user_name> , clear={password= <password> })
/subsystem=elytron/filesystem-realm=exampleFileSystemRealm:set-password(identity=user1, clear={password="passwordUser1"}) {"outcome" => "success"}
/subsystem=elytron/filesystem-realm= <filesystem_realm_name> :add-identity-attribute(identity= <user_name> ,name= <roles_attribute_name> , value=[ <role_1> , <role_N> ])
/subsystem=elytron/filesystem-realm=exampleFileSystemRealm:add-identity-attribute(identity=user1, name=Roles, value=["Admin","Guest"]) {"outcome" => "success"}
/subsystem=elytron/failover-realm= <failover_realm_name> :add(delegate-realm= <realm_to_use_by_default> ,failover-realm= <realm_to_use_as_backup> )
/subsystem=elytron/failover-realm=exampleSecurityRealm:add(delegate-realm=exampleLDAPRealm,failover-realm=exampleFileSystemRealm) {"outcome" => "success"}
/subsystem=elytron/simple-role-decoder= <role_decoder_name> :add(attribute= <attribute> )
/subsystem=elytron/simple-role-decoder=from-roles-attribute:add(attribute=Roles) {"outcome" => "success"}
/subsystem=elytron/security-domain= <security_domain_name> :add(default-realm= <failover_realm_name> ,permission-mapper=default-permission-mapper,realms=[{realm= <failover_realm_name> ,role-decoder=" <role_decoder_name> "}])
/subsystem=elytron/security-domain=exampleSecurityDomain:add(default-realm=exampleSecurityRealm,permission-mapper=default-permission-mapper,realms=[{realm=exampleSecurityRealm,role-decoder="from-roles-attribute"}]) {"outcome" => "success"}
test { 1 loginmodules.CustomLoginModule1 optional; 2 loginmodules.CustomLoginModule2 optional myOption1=true myOption2=exampleOption; 3 };
mvn archetype:generate -DgroupId= <group-to-which-your-application-belongs> -DartifactId= <name-of-your-application> -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-simple -DinteractiveMode=false
mvn archetype:generate -DgroupId=com.example.loginmodule -DartifactId=example-custom-login-module -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-simple -DinteractiveMode=false
cd <name-of-your-application>
cd example-custom-login-module
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>custom.loginmodules</groupId> <artifactId>custom-login-modules</artifactId> <version>1.0</version> <dependencies> <dependency> <groupId>org.wildfly.security</groupId> <artifactId>wildfly-elytron</artifactId> <version>1.17.2.Final</version> </dependency> <dependency> <groupId>jakarta.security.enterprise</groupId> <artifactId>jakarta.security.enterprise-api</artifactId> <version>3.0.0</version> </dependency> </dependencies> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties> </project>
rm -rf src/site/ rm -rf src/test/
mvn install
[INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1.404 s [INFO] Finished at: 2022-04-28T13:55:18+05:30 [INFO] ------------------------------------------------------------------------
mkdir -p src/main/java/<path_based_on_artifactID>
mkdir -p src/main/java/com/example/loginmodule
cd src/main/java/<path_based_on_groupID>
cd src/main/java/com/example/loginmodule
rm App.java
package com.example.loginmodule; import org.wildfly.security.auth.principal.NamePrincipal; import javax.security.auth.Subject; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.auth.login.LoginException; import javax.security.auth.spi.LoginModule; import java.io.IOException; import java.security.Principal; import java.util.Arrays; import java.util.HashMap; import java.util.Map; public class ExampleCustomLoginModule implements LoginModule { private final Map<String, char[]> usersMap = new HashMap<String, char[]>(); private Principal principal; private Subject subject; private CallbackHandler handler; /** * In this example, identities are created as fixed Strings. * * The identities are: * user1 has the password passwordUser1 * user2 has the password passwordUser2 * * Use these credentials when you secure management interfaces * or applications with this login module. * * In a production login module, you would get the identities * from a data source. * */ @Override public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) { this.subject = subject; this.handler = callbackHandler; this.usersMap.put("user1", "passwordUser1".toCharArray()); this.usersMap.put("user2", "passwordUser2".toCharArray()); } @Override public boolean login() throws LoginException { // obtain the incoming username and password from the callback handler NameCallback nameCallback = new NameCallback("Username"); PasswordCallback passwordCallback = new PasswordCallback("Password", false); Callback[] callbacks = new Callback[]{nameCallback, passwordCallback}; try { this.handler.handle(callbacks); } catch (UnsupportedCallbackException | IOException e) { throw new LoginException("Error handling callback: " + e.getMessage()); } final String username = nameCallback.getName(); this.principal = new NamePrincipal(username); final char[] password = passwordCallback.getPassword(); char[] storedPassword = this.usersMap.get(username); if (!Arrays.equals(storedPassword, password)) { throw new LoginException("Invalid password"); } else { return true; } } /** * user1 is assigned the roles Admin, User and Guest. * In a production login module, you would get the identities * from a data source. * */ @Override public boolean commit() throws LoginException { if (this.principal.getName().equals("user1")) { this.subject.getPrincipals().add(new Roles("Admin")); this.subject.getPrincipals().add(new Roles("User")); this.subject.getPrincipals().add(new Roles("Guest")); } return true; } @Override public boolean abort() throws LoginException { return true; } @Override public boolean logout() throws LoginException { this.subject.getPrincipals().clear(); return true; } /** * Principal with simple classname 'Roles' will be mapped to the identity's attribute with name 'Roles'. */ private static class Roles implements Principal { private final String name; Roles(final String name) { this.name = name; } /** * @return name of the principal. This will be added as a value to the identity's attribute which has a name equal to the simple name of this class. In this example, this value will be added to the attribute with a name 'Roles'. */ public String getName() { return this.name; } } }
exampleConfiguration { com.example.loginmodule.ExampleCustomLoginModule optional; };
mvn package [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1.321 s [INFO] Finished at: 2022-04-28T14:16:03+05:30 [INFO] ------------------------------------------------------------------------
module add --name= <name_of_the_login_moudle> --resources= <path_to_the_login_module_jar> --dependencies=org.wildfly.security.elytron
module add --name=exampleLoginModule --resources= <path_to_login_module> /custom-login-modules-1.0.jar --dependencies=org.wildfly.security.elytron
/subsystem=elytron/jaas-realm= <jaas_realm_name> :add(entry= <entry-name> ,path= <path_to_module_config_file> ,module= <name_of_the_login_module> ,callback-handler= <name_of_the_optional_callback_handler> )
/subsystem=elytron/jaas-realm=exampleSecurityRealm:add(entry=exampleConfiguration,path= <path_to_login_module> /JAAS-login-modules.conf,module=exampleLoginModule)
/subsystem=elytron/security-domain= <security_domain_name> :add(default-realm= <jaas_realm_name> ,realms=[{realm= <jaas_realm_name> }],permission-mapper=default-permission-mapper)
/subsystem=elytron/security-domain=exampleSecurityDomain:add(default-realm=exampleSecurityRealm,realms=[{realm=exampleSecurityRealm}],permission-mapper=default-permission-mapper) {"outcome" => "success"}