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.