Search
  • Daniel Díaz

Security in ADF Essentials


One of the greatest challenge when clients want to apply ADF without license is to secure the application, due to the fact that clients can not use the wizard to secure the apps through ADF Security which is not available in ADF essentials.

It is worthy to mention that the Java EE solution through the implementation of security realm configuration on glassfish does not work because of a bug presented since JDev version 12.2.1, most specific in ADF Essentials version 4.1.

The bug case can be looked at this link:

In this blog we are going to show how to implement log in security through java EE filters of java EE 6 version.

These are the steps:

1. First create the database connection and create a view object based on pl-sql query so it can bring all the users and password to check against the password and user that has been written down.

In a production environment now on days is not safe to store passwords in the database where anyone can see them so in this blog it is going to be done by LDAP configuration, however you can do it by a DB Query to simplify the process "The point is to show how to secure the app access when the user is not authenticated or the session is expired".

2. Then the custom login page form has to be created assuring that is responsive design. It can be creating with the drag and drop functionality of business components to represent user and password data or you can just copy and paste my JSF code and then update it with your BC attributes values.

Here is my JSF Code, feel free to reuse it:

<f:view xmlns:f="http://java.sun.com/jsf/core" xmlns:af="http://xmlns.oracle.com/adf/faces/rich"> <af:document title="Login.jsf" id="d1"> <af:messages id="m1"/> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"/> <af:form id="f1">

<af:resource type="javascript" source="/ESPH/js/LoginFunctions.js"/> <af:panelGroupLayout id="pgl3" layout="vertical"> <af:panelGroupLayout id="pgl1" layout="vertical" styleClass="mainRootContainer"> <af:panelGroupLayout id="pglImagenApp" layout="vertical" styleClass="formTitleContainer"> <af:image source="/ESPH/images/LogoHR.png" id="i1" styleClass="formTitle"/> </af:panelGroupLayout> <af:panelGroupLayout id="pgl4" layout="vertical" styleClass="formRootContainer"> <af:panelGroupLayout id="pgl5" layout="vertical" styleClass="formContainer"> <af:outputText value="Usuario:" id="ot2" styleClass="formLabelText"/> <af:inputText id="it1" simple="true" styleClass="formInputText" placeholder="Ingrese aqui su usuario" binding="#{MBLoginAutenticacion.itUsuario}"/> </af:panelGroupLayout> <af:panelGroupLayout id="panelGroupLayout1" layout="vertical" styleClass="formContainer"> <af:outputText value="Password:" id="outputText1" styleClass="formLabelText"/> <af:inputText id="inputText1" simple="true" styleClass="formInputText" placeholder="Ingrese su password" secret="true" binding="#{MBLoginAutenticacion.itPassword}"/> </af:panelGroupLayout> </af:panelGroupLayout> <af:panelGroupLayout id="pglInfo" styleClass="pglBotonesHorizontales botonMenu" layout="horizontal" shortDesc="Usuario: Daniel Diaz"> <af:outputText id="ot_info" value="Enviar" styleClass="textosBotonesHorizontales"/> <af:link id="lInfo" text="person" styleClass="material-icons botonMenu" actionListener="#{MBLoginAutenticacion.autenticarUsuario}" binding="#{MBLoginAutenticacion.lbotonAPresionar}"/> </af:panelGroupLayout> </af:panelGroupLayout> </af:panelGroupLayout> </af:form> </af:document> </f:view>

Here is the link of the css Style and the javascript needed to some effects in the google drive:

Copy and paste that folder inside ViewController/public_html folder so all the resources will be available including Css, javaScripts and others.

3. Then the method authenticateUser would be like this:

public void authenticateUser (ActionEvent actionEvent) {

//needed import native classes of java to the class for LDAP integration

//import javax.naming.NamingException; //import javax.naming.ldap.LdapContext;

//First it is obtained the name that the user write down

String user = (String) this.getItUsuario().getValue();

//Then the psw that is right down String psw = (String) this.getItPassword().getValue();

// then a validator method that validate against LDAP Directory with the right configuration in glassfish is used.

// you can use a validation against DB or another directory if you want to although is insecure to store pws with a visible role on databases.

HttpSession session = null; //session object declared needed below

FacesContext ctx = FacesContext.getCurrentInstance();

try {

//First it has to be checked if user write the name and the psw required in the //login form.

if (user != null && psw != null) {

//Data configuration that the object LdapContext needs.

LdapContext con = ActiveDirectory.getConnection(user, psw, "esph-sa.com", "esph-cd1");

// method that really does the authentication against LDAP, in case the authentication fails it throws an exception

ActiveDirectory.getUser(user, con);

//In case the authentication success a new session is created.

session = (HttpSession) ctx.getExternalContext().getSession(true);

// The user name authenticated will be store in a session variable

session.setAttribute("username", user);

//Time of the session to get expired

session.setMaxInactiveInterval(500);

} else {

// User or password is missing

JSFUtil.addInfoMessage("Please insert user and password");

}

} catch (NamingException ex) {

//LDAP authentication fails

System.out.println(ex.getMessage());

if (session != null)

session.invalidate(); //invalidates or close any previous session to

// secure the App

Utils.redirectToView("Login"); // Finally redirect to Login Page again

}// end of catch

}// end of method

Here is the method redirectToView that in this case is in a different class to be reuse:

public static void redirectToView(String viewId) { FacesContext fCtx = FacesContext.getCurrentInstance(); ExternalContext eCtx = fCtx.getExternalContext();

String activityUrl = ControllerContext.getInstance().getGlobalViewActivityURL(viewId); try { eCtx.redirect(activityUrl); } catch (IOException e) { e.printStackTrace(); JSFUtil.addFacesErrorMessage("Exception when redirect to " + viewId); } }

3. Now on the filter AplicationFilter.java that was created the method doFilter need to be changed. (This filter method will be called every time the user tries to access the app through any URL Page).

To create the filter a right click on the desired package is needed:

The option "Servlet Filter (Servlets) needs to be created.

Then it has to be specified "Filter Name, Filter Classname, the package location", the "Configuration file (web.xml)" need to be checked.

Then in the "Filter Mapping" it has to be checked the option "Map to URL Pattern" and type down the value "/faces/*".

Then the "Finish" button has to be clicked in the last section.

Once the Filter class is created is going to look like this in the "web.xml" file.

Go to the filter mapping and put the filter-mapping node first because the filters mapping are executed once an application URL is called in the order they are, so if the session authentication is validated first and it results denied the other filters will not execute.

Now the method doFilter of the filter class created is the one that have the logic of authentication:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response;

//The URI is store in a variable String uri = req.getRequestURI();

//ask if the URL that the user is trying to access is the login page if (!uri.endsWith("Login.jsf")) {

//In case is the login page It asks if a session is created and with parameter //false indicate that in case if not then It will not be created thus a null is return. HttpSession session = req.getSession(false); if (session == null) {

// When there is no session object because either the user is not authenticated //or the session has expired the user will be redirect to Login page res.sendRedirect(req.getContextPath() + "/faces/Login.jsf");

//Finish the method return; } else { String user = (String) session.getAttribute("username");

//Ask is there is any user authenticated in the session. if (user == null) {

//In case there is no user store as variable in the session the app

// will redirect to Login page res.sendRedirect(req.getContextPath() + "/faces/Login.jsf");

//Ask is there is any user authenticated in the session. return; }

String idPagARedireccionar=uri.substring(uri.lastIndexOf("/")+1); //If there is a session with the authenticated user registered

//no redirection to login page will be done. session.setAttribute("idPagARedireccionar",idPagARedireccionar); } }

chain.doFilter(request, response); }// end of doFilter method.

Then as soon as it is finished the login form will be ready to be used and secure all the applications by authenticated users and roles in case it is implemented with LDAP directory. It will look like this with a responsive design layout.

Note: Let me know if you need the LDAP configuration steps on glassfish to use it with ADF so I will uploaded later.

#ADFEssentialsSecurity #ADFSecurity #GlassfishSecurity #JSFSecurity #JavaEESecurity

472 views

©2018 by ITEvol7777.