Friday, March 7, 2014

Web authentication with MySQL in WildFly8

Developer who want to migrate web application from Apache Tomcat to WildFly 8 , application server from JBoss,  may wonder how to setup their WildFly application server to support existing web applications which has been deployed on Apache Tomcat.

This article shows setting up WildFly application server to provide authentication using credential stored in MySQL database with MD5 hashing password.

Installing MySQL driver for WildFly application server.
Although MySQL driver can be installed by placing in deployments directory of server, In this blog I will install MySQL driver as core module by using the following steps.

Prepare module directory.
# cd wildfly8-Final/modules
# cd mkdir com
# cd com
# mkdir mysql
# cd mysql
# mkdir main

Then copy MySQL connector/J jar file (downloaded from mysql.com) into "main" directory.
# cd main
# cp ~/Downloads/mysql-connector-java-5.1.29-bin.jar .

Create module.xml in the "main" directory and add the following file contents.

<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="com.mysql">
    <resources>
        <resource-root path="mysql-connector-java-5.1.29-bin.jar"/>
    </resources>
    <dependencies>
<module name="javax.api"/>
    </dependencies>
</module>

In the file standalone.xml, find <drivers> section then add driver configuration.

<drivers>
     <driver name="mysql" module="com.mysql"/>
</drivers>

Try to start WildFly then see the log file, message should show driver deployment and service status.

......Deploying non-JDBC-compliant driver class com.mysql.jdbc.Driver (version 5.1)
......Started Driver service with driver-name = mysql

Creating authentication database with users and roles information.

CREATE DATABASE authen_db;
USE authen_db;

CREATE TABLE `users` (
  `user_name` varchar(50) NOT NULL,
  `user_pass` varchar(50) DEFAULT NULL,
  `user_full_name` varchar(100)  DEFAULT NULL,
  PRIMARY KEY (`user_name`)
);

CREATE TABLE `user_roles` (
  `user_name` varchar(50)  NOT NULL,
  `role_name` varchar(50)  NOT NULL,
  PRIMARY KEY (`user_name`,`role_name`)
);

Add some user information for testing.

insert into users values('administrator', md5('admpass'), 'administrator');
insert into users values('john', md5('smtpwd'), 'John smith');
insert into users values('linda', md5('linpwd'), 'Linda smith');

insert into user_roles('administrator', 'admin');
insert into user_roles('john', 'admin');
insert into user_roles('john', 'callcenter');
insert into user_roles('linda', 'accounting');

Creating data source using by security sub system.

Creating data source is an easy task when using management web provided by WildFly.
Editing configuration file directly give the same working result. Here is what to be add into standalone.xml in standalone/configuration directory.

<subsystem xmlns="urn:jboss:domain:datasources:2.0">
      .
      .
      .
      <datasources>
                <datasource jndi-name="java:jboss/datasources/authenDb" pool-name="authenDb" enabled="true" use-java-context="true">
                    <connection-url>jdbc:mysql://authen-db-server:3306/authen_db</connection-url>
                    <driver>mysql</driver>
                    <pool>
                        <min-pool-size>1</min-pool-size>
                        <max-pool-size>5</max-pool-size>
                        <flush-strategy>IdleConnections</flush-strategy>
                    </pool>
                    <security>
                        <user-name>dbuser</user-name>
                        <password>dbpass</password>
                    </security>
                    <statement>
                        <track-statements>nowarn</track-statements>
                    </statement>
                </datasource>
      </datasources>
</subsystem>

Configuring security subsystem to apply MySQL database authentication.

In standalone.xml, add new security-domain into security subsystem. Parameter "principalsQuery" and "rolesQuery" is depend on your database schema.

<subsystem xmlns="urn:jboss:domain:security:1.2">
            <security-domains>
                 .
                 .
                 .
                 <security-domain name="webapp-authentication" cache-type="default">
                    <authentication>
                        <login-module code="Database" flag="required">
                            <module-option name="dsJndiName" value="java:jboss/datasources/authenDb"/>
                            <module-option name="principalsQuery" value="select user_pass from users where user_name=?"/>
                            <module-option name="rolesQuery" value="select role_name, 'Roles' from user_roles where user_name=?"/>
                            <module-option name="hashAlgorithm" value="MD5"/>
                            <module-option name="hashEncoding" value="hex"/>
                        </login-module>
                    </authentication>
                </security-domain>
            </security-domains>
</subsystem>

Defining security domain in jboss-web.xml

Create jboss-web.xml in WEB-INF directory with this content.

<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
<security-domain>webapp-authentication</security-domain>
</jboss-web>


Configuring web application.

If you used standard login mechanism of Java EE when deploy in Tomcat, nothing have to be changed.

Sample authentication part of web.xml

  <login-config>
  <auth-method>BASIC</auth-method>
  </login-config>
  <security-constraint>
  <display-name>demo realm</display-name>
  <web-resource-collection>
  <web-resource-name>demo realm</web-resource-name>
  <url-pattern>/*</url-pattern>
  <http-method>GET</http-method>
  <http-method>POST</http-method>
 
  </web-resource-collection>
  <auth-constraint>
  <role-name>*</role-name>
  </auth-constraint>
  </security-constraint>
  <security-role>
  <role-name>*</role-name>
  </security-role>