Creating a JAAS JDBC Authentication Realm in Glassfish

01 April 2014

Why JAAS

The objective of using JAAS is to separate the concerns of user authentication so that they may be managed independently. You can let your Application Server handle the authentication logic using JAAS JDBC based authentication in order to keep your business domain related code isolated from the authentication layer mechanism.

The examples of this post explain how to create a JDBC Authentication realm for Oracle and PostgreSQL in Linux and Windows, using MD5 algorithm to store the users passwords encrypted in the DB.



Setup DATABASE

ORACLE

Open ORACLE SQLPlus:

CREATE TABLESPACE testapp DATAFILE 'testapp.dbf' SIZE 40M ONLINE;

CREATE USER testapp IDENTIFIED BY testapp DEFAULT TABLESPACE testapp TEMPORARY TABLESPACE temp;

GRANT CONNECT TO testapp; GRANT DBA TO testapp; -- * For testing purposes only!


POSTGRESQL

LINUX

.Create data base

sudo -u postgres createdb testapp

.Start data base

sudo /etc/init.d/postgresql start

.Login to your database

psql -d testapp -U testapp

. to examine the database

    \l :List databases
    \c database-name :List databases
    \d :List tables in database
    \d table-name :Describe table
    \q : quit


WINDOWS

Open command line, in your POSGRESQL bin folder:

initdb -U postgres -A password -E utf8 -W -D POSTGRESQL_ROOT\data
postgres -D %PGSQL_HOME%\data



Build Database Model

 CREATE TABLE TB_USER
 (
      ID_USER varchar(64) NOT NULL CONSTRAINT USER_PK PRIMARY KEY,
      PASSWORD varchar(64) NOT NULL,
      ACTIVE CHAR(1)
 );

CREATE TABLE TB_USER_GROUP ( ID_GROUP VARCHAR(32) PRIMARY KEY NOT NULL, DESCRIPTION varchar(128) );

CREATE TABLE TB_USER_GROUP_USER ( ID_USER varchar(64) NOT NULL, ID_GROUP varchar(64) NOT NULL, CONSTRAINT USER_GROUP_USER_PK PRIMARY KEY(ID_USER, ID_GROUP), CONSTRAINT USER_GROUP_USER_USER_FK FOREIGN KEY (ID_USER) REFERENCES TB_USER(ID_USER), CONSTRAINT USER_GROUP_USER_GROUP_FK FOREIGN KEY(ID_GROUP) REFERENCES TB_USER_GROUP(ID_GROUP) ON DELETE CASCADE );



Configure Glassfish

Create DATASOURCE in Glassfish

First copy JDBC libs to glassfish/lib, or make sure you have Oracle or PostgreSQL jdbc .jar file(s) in the Classpath for Glassfish.

Create JDBC connection pool using asadmin Tool under glassfish\bin:


ORACLE

asadmin > create-jdbc-connection-pool --restype=javax.sql.DataSource
--datasourceclassname=oracle.jdbc.pool.OracleDataSource
--property=user=testapp:password=testapp1:url=jdbc\:oracle\:thin\:@localhost\:1521\:XE oracleJDBCPool

asadmin > create-jdbc-resource --connectionpoolid oracleJDBCPool oracleJDBCResource


POSTGRESQL

asadmin > create-jdbc-connection-pool --restype=javax.sql.DataSource
--datasourceclassname=org.postgresql.ds.PGSimpleDataSource
--property=user=postgres:password=testapp1:serverName=localhost:portNumber=5432:databaseName=testapp postgreSQLJDBCPool

asadmin > create-jdbc-resource --connectionpoolid postgreSQLJDBCPool postgreSQLJDBCResource



CREATE AUTHENTICATION REALM in Glassfish

Here we specify several parameters for the authentication realm we're creating, including a DIGEST algorithm to store the user's password encrypted, In this example we're going to use MD5.


ORACLE

create-auth-realm --classname com.sun.enterprise.security.ee.auth.realm.jdbc.JDBCRealm
--property jaas-context=jdbcRealm:datasource-jndi=oracleJDBCResource:user-table=TB_USER:
user-name-column=ID_USER:password-column=PASSWORD:group-table=TB_USER_GROUP_USER:
group-name-column=ID_GROUP:group_table_user-name-column=ID_GROUP:digest-algorithm=MD5 userauth


POSTGRESQL

create-auth-realm --classname com.sun.enterprise.security.ee.auth.realm.jdbc.JDBCRealm
--property jaas-context=jdbcRealm:datasource-jndi=postgreSQLJDBCResource:user-table=TB_USER:
user-name-column=ID_USER:password-column=PASSWORD:group-table=TB_USER_GROUP_USER:
group-name-column=ID_GROUP:group_table_user-name-column=ID_GROUP:digest-algorithm=MD5 userauth



Configure your web.xml

<login-config>
    <auth-method>FORM</auth-method>
    <realm-name>userauth</realm-name>
    <form-login-config>
        <form-login-page>/login.xhtml</form-login-page>
        <form-error-page>/loginError.xhtml</form-error-page>
    </form-login-config>
</login-config>

<security-constraint> <display-name>ConstraintSSL</display-name> <web-resource-collection> <web-resource-name>common</web-resource-name> <description /> <url-pattern>/login/</url-pattern> <url-pattern>/products/</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> <http-method>HEAD</http-method> <http-method>PUT</http-method> <http-method>OPTIONS</http-method> <http-method>TRACE</http-method> <http-method>DELETE</http-method> </web-resource-collection> <auth-constraint> <description /> <role-name>USERS</role-name> <role-name>ADMINISTRATORS</role-name> </auth-constraint> <user-data-constraint> <description>Development mode</description> <transport-guarantee>NONE</transport-guarantee> </user-data-constraint> </security-constraint> <security-constraint> <display-name>ConstraintUser</display-name> <web-resource-collection> <web-resource-name>protected</web-resource-name> <description /> <url-pattern>/account/*</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> <http-method>HEAD</http-method> <http-method>PUT</http-method> <http-method>OPTIONS</http-method> <http-method>TRACE</http-method> <http-method>DELETE</http-method> </web-resource-collection> <auth-constraint> <description /> <role-name>ADMINISTRATORS</role-name> </auth-constraint> <user-data-constraint> <description>SSL not required for Development</description> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint>

<security-role> <description /> <role-name>USERS</role-name> </security-role> <security-role> <description /> <role-name>ADMINISTRATORS</role-name> </security-role>

notice the url-pattern tag, this defines the actual resources that this group of users can access.



Create your authentication form

In your Login page, place a form that will trigger the login flow:

 <form method="post" action="j_security_check" >
  <label>User</label>
  <input type="text" name="j_username" />

<label>Password</label> <input type="password" name="j_password" />

<input name="login" type="submit" value="Login" /> <input name="reset" type="reset" value="Reset" /> </form>



Load some sample data and test

Create 2 different USER Groups one for common Users and other for Admins:

--------------------------------- USERS AND GROUPS -----------------------------------------------------
insert into TB_USER_GROUP values('USERS', 'common USERS');
insert into TB_USER_GROUP values('ADMINISTRATORS', 'privileged ADMIN GROUP');

After that create sample users on each group, common users should only be able to access resources under /products/ and /login/, while admin users should be able to access these URLs and also "protected" URLs which are under /account/*.

You can customize your login and error pages accordingly.



Additional links:

JAAS

comments powered by Disqus