
EJB is used to create business logic in Java EE application. Setting up authorization to limit the access to your business execution base on the role. In the enterprise level, security concern is very crucial to ensure the authorized user shall be the only on who those business logic is available to. EJB provide two types of methodologies for securing business logic for instance, declarative and programmatic.
Declarative security - it is preferable methodology to secured EJB. It is provided in the container like Wildfly, etc. For this method, security can be defined through deploy descriptor or annotation.
Programmatic security - security is required to put in the code directly.
In this post, I have deployed application as below scheme.
In our set up, we authenticate and authorize user by using JDBC Realm. To enable
Create User Schema in PostgreSQL
First, we need to create user schema in database as following.
From above schema, we create SQL script for user and role table as following.
CREATE TABLE IF NOT EXISTS USERTBL_01(
userid serial PRIMARY
KEY,
username
VARCHAR(255),
passwd VARCHAR(255),
firstname VARCHAR(255),
lastname
VARCHAR(255),
status VARCHAR(1) NOT NULL
DEFAULT 'N',
CREATEDATE TIMESTAMP DEFAULT
NOW()::TIMESTAMP
);
CREATE TABLE IF NOT EXISTS ROLETBL_01(
ROLEID serial PRIMARY
KEY,
ROLENAME VARCHAR(255),
ROLEDESC VARCHAR(255),
STATUS VARCHAR(1) NOT NULL
DEFAULT 'N',
CREATEDATE TIMESTAMP DEFAULT
NOW()::TIMESTAMP
);
CREATE TABLE IF NOT EXISTS USR_ROLE_TBL_01(
USERID INTEGER,
ROLEID INTEGER,
PRIMARY KEY
(USERID,ROLEID),
CONSTRAINT fk_USER
FOREIGN KEY(USERID)
REFERENCES
USERTBL_01(USERID) ON DELETE CASCADE,
CONSTRAINT fk_ROLE
FOREIGN KEY(ROLEID)
REFERENCES
ROLETBL_01(ROLEID) ON DELETE CASCADE
);
After creating user and role table, we will insert data to table. But before we insert user and role information to user and role table, we need to encrypt password. For our setup, we use SHA-256 method to encrypt password. Fortunately, we could utilize sha-256 encryption package in WILDFLY as below.
$java -cp $JBOSS_HOME/modules/system/layers/base/org/picketbox/main/picketbox-4.9.6.Final.jar org.jboss.security.Base64Encoder password SHA-256
[L1yCd6L0X8BZ8WJuP4P1xW+r6s6Sj1hNJmhBEMUZL48=]
Now, we will use password we have encrypted and create insert script to insert user and role information as below.
INSERT INTO usertbl_01 (username,passwd,firstname, lastname)
VALUES
('user01','L1yCd6L0X8BZ8WJuP4P1xW+r6s6Sj1hNJmhBEMUZL48=','firstname','lastname'),
('user02','L1yCd6L0X8BZ8WJuP4P1xW+r6s6Sj1hNJmhBEMUZL48=','firstname','lastname'),
('user03','L1yCd6L0X8BZ8WJuP4P1xW+r6s6Sj1hNJmhBEMUZL48=','firstname','lastname'),
('user04','L1yCd6L0X8BZ8WJuP4P1xW+r6s6Sj1hNJmhBEMUZL48=','firstname','lastname'),
('user05','L1yCd6L0X8BZ8WJuP4P1xW+r6s6Sj1hNJmhBEMUZL48=','firstname','lastname');
INSERT INTO roletbl_01 (ROLENAME,ROLEDESC) VALUES
('Administrator','Administrator Role'),
('Super','Super Role'),
('Operator','Operator Role');
INSERT INTO usr_role_tbl_01 (USERID,ROLEID) VALUES
(1,1),
(1,2),
(1,3),
(2,1),
(2,2),
(3,3);
Enable JDBC Realm Security Domain in Wildfly
To enable JDBC Realm Security domain in wildfly, First, we need to create datasource in Wildfly to connect to database. After creating datasource to connection database, we need to edit standalone.xml. And inside security-domain tag, we will add as below.
<security-domain name="JDBCAuth" cache-type="default">
<authentication>
<login-module code="Database"
flag="required">
<module-option name="dsJndiName" value="java:/sampledbs"/>
<module-option name="principalsQuery" value="select passwd from usertbl_01 where username=?"/>
<module-option name="rolesQuery" value="select r.role,
'Roles' from roletbl_01 r inner join usr_role_tbl_01 ur on r.roleid=ur.roleid inner join usertbl_01 u on
ur.userid = u.userid where u.username=?"/>
<module-option name="hashAlgorithm"
value="SHA-256"/>
<module-option name="hashEncoding"
value="base64"/>
</login-module>
</authentication>
</security-domain>
After editing standalone.xml, restart the server
Create EJB Project
Now, we start to create business logic by creating EJB project. In the application, I have set 3 level of authorization.
- Administrator - role for administrator staff for administrator to execute business logic.
- Operator - this is role for operator staff to execute the business logic.
- Anonymous -this is role for any user can use the logical business.
For Administrator and Operator role, we need to maintain in role table which we can see in the insert script. Next step is to creat EJP project and business logic by EJB. For the business logic I have created interface and EJB class as below.
First we create interface for EJB class as following.
package pro.itstikk.ejb.secure;
import javax.ejb.Local;
@Local
public interface SecuredWorkEjb {
public String
doWorkSuper();
public String
doWorkAdmin();
public String
doWorkStaff();
public String
doWorkAny();
}
And for the interface implemented class, we have created as below code.
package pro.itstikk.ejb.secure;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ejb.Stateless;
/**
* Session Bean implementation class SecuredWorkEjbImp
*/
@Stateless(mappedName = "securedWorkEjb")
@DeclareRoles({"Super","Administrator","Operator"})
public class SecuredWorkEjbImp implements SecuredWorkEjb {
/**
* Default constructor.
*/
public SecuredWorkEjbImp() {
super();
}
@RolesAllowed({"Super"})
@Override
public String doWorkSuper()
{
return "do super work";
}
@RolesAllowed({"Administrator"})
@Override
public String doWorkAdmin()
{
return "do admin work";
}
@RolesAllowed({"Operator"})
@Override
public String doWorkStaff()
{
return "do staff work";
}
@PermitAll
@Override
public String doWorkAny() {
return "do anonymous work";
}
}
Create Dynamic Web Project
Next is to create web application (we need to include our EJB project in web application project) and set up authentication. First we create bean
package pro.itstikk.ee.web.bean;
import javax.ejb.EJB;import javax.enterprise.context.RequestScoped;import javax.inject.Named;
import pro.itstikk.ejb.secure.SecuredWorkEjb;
@Named("workBean")@RequestScopedpublic class WorkBean { @EJB private SecuredWorkEjb securedWorkEjb; private String result; public String getResult() { return result; } public void setResult(String result) { this.result = result; } public String doWorkAdmin() { result = securedWorkEjb.doWorkAdmin(); return "result.xhtml"; } public String doWorkOperator() { result = securedWorkEjb.doWorkStaff(); return "result.xhtml"; } public String doWorkAny() { result = securedWorkEjb.doWorkAny(); return "result.xhtml"; }}
After create manage bean, create login.xhtml page under secure folder as below
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:rich="http://richfaces.org/rich" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:a4j="http://richfaces.org/a4j" xmlns:h="http://java.sun.com/jsf/html">
<h:head> <title>Wildfly 10 Application</title></h:head> <body> <rich:panel> <f:facet name="header"> Write your own custom rich components with built-in AJAX </f:facet> <div> <h2>Login Form</h2> <form name="loginForm" action="j_security_check" method="post"> <p> <label for="j_username"><strong>User Name: </strong></label> <input name="j_username" type="text"/> </p> <p> <label for="j_password"><strong>Password: </strong></label> <input name="j_password" type="password"/> </p> <p> <input type="submit" value="Login"/> <input type="reset" value="Reset"/> </p> </form> </div> </rich:panel></body> </html>
Next is to create login-error.xhtml for error login.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:rich="http://richfaces.org/rich" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:a4j="http://richfaces.org/a4j" xmlns:h="http://java.sun.com/jsf/html">
<h:head></h:head> <body> <rich:panel> <f:facet name="header"> Write your own custom rich components with built-in AJAX support </f:facet> <h2>Login Error</h2> <a href="/java-ee-05-web-secure">Back</a> </rich:panel></body> </html>
After preparing login.xhtml and login-error.xhtml for authentication form, we need to create secure resource under secure folder as below.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:rich="http://richfaces.org/rich" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:a4j="http://richfaces.org/a4j" xmlns:h="http://java.sun.com/jsf/html">
<h:head> <title>EJB Security</title> <style> li { margin:10px 5px 10px 5px;} </style></h:head> <body> <rich:panel> <f:facet name="header"> Write your own custom rich components with built-in AJAX support </f:facet> <h:outputText value="Panel Body" /> <div> <ol> <li> <h:form> <h:commandButton action="#{workBean.doWorkAdmin()}" value="administrator" title="administrator action"/> </h:form> </li> <li> <h:form> <h:commandButton action="#{workBean.doWorkOperator()}" value="operator" title="operator action"/> </h:form> </li> <li> <h:form> <h:commandButton action="#{workBean.doWorkAny()}" value="anonymous" title="anynomous action"/> </h:form> </li> </ol> </div> </rich:panel></body> </html>
To handle error that occur we create error.xhtml under secure foloder.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:rich="http://richfaces.org/rich" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:a4j="http://richfaces.org/a4j" xmlns:h="http://java.sun.com/jsf/html">
<h:head></h:head> <body> <rich:panel> <f:facet name="header"> Error </f:facet> <h:outputText value="Error ocurred due to operation is not allowed.!" style="color:red;weight:bold;"/> </rich:panel></body> </html>
Next is to configure web.xml to setup security.
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <display-name>java-ee-05-web-secure</display-name> <welcome-file-list> <welcome-file>secure/index.xhtml</welcome-file> </welcome-file-list> <!-- Richfaces --> <context-param> <param-name>javax.faces.PROJECT_STAGE</param-name> <param-value>Development</param-value> </context-param> <context-param> <param-name>org.richfaces.skin</param-name> <param-value>blueSky</param-value> </context-param> <!-- Faces Servlet --> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <!-- Faces Servlet Mapping --> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.xhtml</url-pattern> </servlet-mapping> <!-- security configure --> <security-constraint> <web-resource-collection> <web-resource-name>SecurityFilter</web-resource-name> <description>Application Security Constraints</description> <url-pattern>/secure/*</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection> <auth-constraint> <description>Roles collection</description> <role-name>Administrator</role-name> <role-name>Operator</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>FORM</auth-method> <realm-name>JDBC Authentication Realm</realm-name> <form-login-config> <form-login-page>/login.xhtml</form-login-page> <form-error-page>/login-error.xhtml</form-error-page> </form-login-config> </login-config> <security-role> <description>The Role for Administrator</description> <role-name>Administrator</role-name> </security-role> <security-role> <description>The Role for Operator</description> <role-name>Operator</role-name> </security-role> <error-page> <exception-type>java.lang.Throwable</exception-type> <location>/secure/error.xhtml</location> </error-page> </web-app>
Finally, now to enable JDBC Realm we have configure in standalone.xml, we create jboss-web.xml
<?xml version="1.0" encoding="UTF-8"?><jboss-web> <security-domain>java:/jaas/JDBCAuth</security-domain></jboss-web>
To deploy EJB and Web Project, we create Enterprise Application Project. We pack EJB and Web Project in Enterprise Application Project and package as EAR package to deploy.
Testing Secured EJB
After we deployed the package, we could test the authentication and authorization of the application. For our setup, we create user as below.
- admin01 - administrator role which could execute administration operation.
- operator01 - operator role which could execute operator operation.
After run the test, we have received result as following.
Fig 04 Login |
Fig 05 Admin user login |
Fig 06 Login page |
Fig 05 Execute Admin Operation Result |
Fig 07 Execute Operator Operation Result |
Fig 07 Execute Anonymous Operation Result |
Fig 08 Execute Admin Operation by operator user Result |
Fig 09 Execute Operator operation Result |
Fig 10 Execute Anonymous Operation Result |
No comments:
Post a Comment