Configuring WildFly 27

Learn how to configure WildFly 27 for ISB.

January 13, 2023

Integrated Software for Business uses several important features of the WildFly application server. These features include:

Each one of these steps is configured via the WildFly command line. Let's look at each in turn to configure WildFly for ISB.

User authentication via a configured data source

In order to authenticate users when they log in to the ISB application, we need to set a database and corresponding datasource for WildFly to use in the authentication process. The first step is to create the database. ISB supports two databases: PostgreSQL and IBM i. We will start with a PostgreSQL database and then look at an IBM i database.

We will create a database for PostgreSQL using the following command while logged in as the PostgreSQL administrator account:

createdb -E UTF8 --lc-collate=en_US.UTF8 --lc-ctype=en_US.UTF8 -O wildflyuser -T template0 wildfly "WildFly authentication database"

In this example, wildflyuser is the PostgreSQL role that will own the database. The database will be called wildfly.

Now we will create two tables: users and user_roles. The follow SQL command will create those tables:

create table users (
user_name varchar(100) not null primary key,
user_pass varchar(100) not null,
unique(user_name)
);

create table user_roles (
user_name varchar(100) not null,
role_name varchar(100) not null,
unique(user_name,role_name)
);

Populate the users table like this:

insert into users(user_name,user_pass) values('username','password');

In this example, username is the login name for the user who will be using the ISB application and password should be a secure password.

Populate the user_roles table like this:

insert into user_roles(user_name,role_name) values('username','era');

As in the example above, username is the login name for the user who will be using the ISB application. The role_name is always 'era'.

For IBM i, we create a library using the following command:

CRTLIB LIB(WILDFLY) TEXT('WildFly authentication library')

We can then either run the same SQL commands above to create the tables or use the following DDS:

DDS for file WEBUSERSP:

A                                      UNIQUE
A          R WEBUSERSR                 TEXT('Web users')
A            WUUSER       100A         TEXT('Username')
A                                      COLHDG(' ' ' ' 'Username')
A                                      VARLEN
A                                      ALIAS(USER_NAME)
A            WUPASSWORD   100A         TEXT('Password')
A                                      COLHDG(' ' ' ' 'Password')
A                                      VARLEN
A                                      ALIAS(USER_PASS)
A          K WUUSER

DDS for file WEBROLESP:

A                                      UNIQUE
A          R WEBROLESR                 TEXT('Web roles')
A            WUUSER       100A         TEXT('Username')
A                                      COLHDG(' ' ' ' 'Username')
A                                      VARLEN
A                                      ALIAS(USER_NAME)
A            WUROLE       100A         TEXT('Role')
A                                      COLHDG(' ' ' ' 'Role')
A                                      VARLEN
A                                      ALIAS(ROLE_NAME)
A          K WUUSER
A          K WUROLE

Create these file using the following commands:

CRTPF FILE(WILDFLY/WEBUSERSP)
CRTPF FILE(WILDFLY/WEBROLESP)

These files can be populated using DFU or with the following SQL:

insert into webusersp(user_name,user_pass) values('username','password')

insert into webrolesp(user_name,role_name) values('username','era')

As in the PostgreSQL example, username is the login name for the user who will be using the ISB application and password should be a secure password and the role_name is always 'era'.

With the database created and populated, we are ready to move on the the WildFly configuration. Start the CLI by changing to the WildFly bin directory and running:

./jboss-cli.sh -c

Once in the CLI, deploy the appropriate JDBC driver for your database. For PostgreSQL use:

deploy /home/wildfly/postgresql-42.5.0.jar

where /home/wildfly is replaced with the directory where WildFly lives.

For IBM i use:

deploy /home/wildfly/jt400.jar

Again, /home/wildfly is replaced with the directory where WildFly lives.

With the JDBC driver deployed we are ready to create the data source that WildFly will use for authentication requests. We will call our data source AuthenticationDS. We will use wildflyuser as the username to use to connect to the database with a password of 'password'. Of course you will need to change these appropriately.

For PostgreSQL:

data-source add --name=AuthenticationDS --jndi-name=java:jboss/AuthenticationDS --driver-name=postgresql-42.5.0.jar --connection-url=jdbc:postgresql://localhost/wildfly --user-name=wildflyuser --password=password

For IBM i:

data-source add --name=AuthenticationDS --jndi-name=java:jboss/AuthenticationDS --driver-name=jt400.jar --connection-url=jdbc:as400://your.ibmi.com/wildfly --user-name=wildflyuser --password=password

With the data source created we need to tell WildFly what SQL command to run to retrieve the credentials. This is done as follows:

For PostgreSQL:

/subsystem=elytron/jdbc-realm=AuthenticationRealm:add(principal-query=[{sql="SELECT user_pass,role_name FROM users JOIN user_roles ON users.user_name=user_roles.user_name WHERE users.user_name=?",data-source=AuthenticationDS,clear-password-mapper={password-index=1},attribute-mapping=[{index=2,to=groups}]}])

For IBM i:

/subsystem=elytron/jdbc-realm=AuthenticationRealm:add(principal-query=[{sql="SELECT user_pass,role_name FROM webusersp JOIN webrolesp ON webusersp.user_name=webrolesp.user_name WHERE webusersp.user_name=?",data-source=AuthenticationDS,clear-password-mapper={password-index=1},attribute-mapping=[{index=2,to=groups}]}])

Note that in the above example we are using the clear text password mapper. This means that WildFly expects the passwords to be saved in the database as clear text. This is not desireable for production installations, so a different password mapper the supports encrypted passwords should be used. The full documentation for alternative password mappers for WildFly is very helpful here.

Form based login

To use FORM based login we first need a security domain that ISB will use. This security domain is configured to use the JDBC query we just defined above.

/subsystem=elytron/security-domain=EraSD:add(realms=[{realm=AuthenticationRealm,role-decoder=groups-to-roles}],default-realm=AuthenticationRealm,permission-mapper=default-permission-mapper)

Now we need to create an http based authentication factory that will enable FORM authentication via two commands:

/subsystem=elytron/http-authentication-factory=era-db-http-auth:add(http-server-mechanism-factory=global,security-domain=EraSD,mechanism-configurations=[{mechanism-name=FORM,mechanism-realm-configurations=[{realm-name=EraSD}]}])

/subsystem=undertow/application-security-domain=era:add(http-authentication-factory=era-db-http-auth)

Now we need to tell WildFly to use our security domain by default using two commands:

/subsystem=undertow:write-attribute(name=default-security-domain, value=era)

/subsystem=ejb3/application-security-domain=era:add(security-domain=EraSD)

Named data source for database access

We are now ready to configure the database where the ISB data will live. That is done by creating another data source as follows:

For PostgreSQL:

data-source add --name=EraDB --jndi-name=java:/EraDB --driver-name=postgresql-42.5.0.jar --connection-url=jdbc:postgresql://localhost/era --user-name=wildflyuser --password=password

For IBM i:

data-source add --name=EraDB --jndi-name=java:/EraDB --driver-name=jt400.jar --connection-url=jdbc:as400://your.ibmi.com/era --user-name=wildflyuser --password=password

As always, change the user name, password, and host as appropriate.

Automated emailed logging of critical errors

Now let's configure jakarta.mail so that critical log messages can be automatically emailed. This is also used to enable all email from within ISB.

/subsystem=mail/mail-session=era-mail:add(jndi-name=java:/mail/Session, from=wildflyuser@yourdomain.com

/subsystem=logging/custom-handler=smtp:add(class=org.apache.log4j.net.SMTPAppender, module=org.apache.log4j, named-formatter=PATTERN, level=WARN, properties={SMTPHost="localhost", from="wildflyuser@yourdomain.com", to="recipient@yourdomain.com", bufferSize=1})

/subsystem=logging/logger=com.eaerich:add(level=INFO, handlers=[smtp])

A system property for the location of the scheduled jobs configuration file

ISB uses a crontab-like file for scheduling various tasks. We need to tell WildFly where that file is located. We do that as follows:

/system-property=era.crontab.path:add(value="${jboss.server.config.dir}/era-cron
tab")

Then we can copy the era-crontab file to $WILDFLYHOME/standalone/configuration/era-crontab.

Prevent resubmit of POSTed pages

It is useful to avoid sending a resubmit on POST requests when using the browsers' back button. By default WildFly will cause the browser to resubmit the POSTed data. Change that behavior as follows:

/subsystem=undertow/servlet-container=default:write-attribute(name=disable-caching-for-secured-pages, value=false)

Single-threaded managed executor queues

For some long-running tasks that can be run asynchronously, ISB expects to use a single-threaded queue to avoid a single user consuming all available system resources by submitting many such jobs simultaneously. We need to create a single-threaded queue as follows:

/subsystem=ee/managed-executor-service=single-threaded:add(jndi-name="java:jboss/ee/concurrency/executor/single-threaded", context-service=default, core-threads=1, long-running-tasks=true, max-threads=1, queue-length=100L)

Note that having such a queue has the potential to refuse to run a user's jobs if that queue fills up. If that were to happen, an exception would be thrown and the need to adjust the size of the queue could be adjusted. However, there are very few long running jobs in ISB and a legitimate need to extend the queue is unlikely.

Controlled network access via network interface configuration

Finally, we need to tell WildFly what network address to listen on. By default it only listens on 127.0.0.1 which isn't very useful for users connecting to ISB. So tell WildFly to listen on your LAN address:

/interface=public:write-attribute(name=inet-address, value="192.168.1.1")

WildFly is now configured for ISB. Restart WildFly and deploy the era.war warfile.