Wednesday, 13 April 2016

Implement Security in Oracle ADF 12C

Requirement: I have three pages login.jspx, error.jspx and home.jspx page. 

In login.jspx page I have two af:inputText to enter UserName and Password. The af:inputText for the Password should be secret that is whatever User types should be secret. Also in login.jspx I will have a Login button.

Once the User type UserName and Password and click on Login button, if the credentials are correct then it should navigate to the home.jspx page. Else it should display a popup error message.

In home.jspx I will have a banner “Welcome to the Home Page“, the loggedin UserName ansd the Logout link. 

On click of the Logout link in the home.jspx page it should redirect back to the login.jspx page

Solution: For solution to the above requirement follow the steps as shown below:

Step 1: Create an Oracle ADF Fusion Web Application and name the application as ADFSecurityDemo.

Step 2: Create two pages: home.jspx and login.jspx.

Step 3: Open login.jspx. Drag and drop two af:inputText from the component palette on the login.jspx page. Set the Label of the two af:inputText as UserName and Password.

Drag and drop two af:button from the component palette on the login.jspx page. Set the Text of the Login button as text="Login" and action="#{LoginBean.doLogin}". The scope of the LoginBean is of requestScope.

Step 4: Open LoginBean.java. Create two String varaibles: uname and pwd and generate the accessors for these two varibles as shown below:

Write the code for the doLogin method in the LoginBean.java. 

Also we need to add one Library in the ViewController project of our application. To do this follow the steps as shown below:
  1. Double click ViewController project of our application.
  2. Go to Libraries and Classpath.
  3. Click Add Library.
  4. Select WebLogic 12.1 Remote-Client under Extension.
  5. Click OK
  6. Click OK and Save the application
Thus the complete doLogin method and its related methods are shown below:

Step 5: Open login.jxpx. Set value="#{LoginBean.uname}" for the first af:inputText. Set value="#{LoginBean.pwd}" secret="true" for the second af:inputText. Thus the complete login.jspx is shown below:

Step 6: Open home.jxpx.

Drag and drop af:outputText from the component palette in the home.jspx page. Set the value as value="Welcome to the Home Page".

Drag and drop af:spacer from the component palette in the home.jspx page. Set width="500" height="10".

Drag and drop af:outputLabel from the component palette in the home.jspx page. Set value="UserName".

Drag and drop af:outputLabel from the component palette in the home.jspx page. Set value="Susanto". In the later steps we will set the value from the SecurityContext. That is the username value will be same as that of the Loggedin username.

Drag and drop af:spacer from the component palette in the home.jspx page. Set width="100" height="10".

Drag and drop af:link from the component palette in the home.jspx page. Set text="Logout" and action="#{LoginBean.onLogout}".

Thus, the home.jspx page code is shown below:

Step 7: Open LoginBean.java and the write the code for the onLogout method as shown below:
 
Thus the complete LoginBean.java is shown below:
package com.susanto.beans;

import java.io.IOException;

import javax.faces.application.FacesMessage;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;

import javax.security.auth.Subject;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;

import weblogic.security.services.Authentication;
import weblogic.security.URLCallbackHandler;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

public class LoginBean {
       private String uname;
       private String pwd;

       public void setUname(String uname) {
             this.uname = uname;
       }

       public String getUname() {
             return uname;
       }

       public void setPwd(String pwd) {
             this.pwd = pwd;
       }

       public String getPwd() {
             return pwd;
       }

       public LoginBean() {
       }

       public String doLogin() {
             String un = uname;
             byte[] pw = pwd.getBytes();
             FacesContext ctx = FacesContext.getCurrentInstance();
             HttpServletRequest request = (HttpServletRequest) ctx.getExternalContext().getRequest();
             try {
                    Subject subject = Authentication.login(new URLCallbackHandler(un, pw));
                    weblogic.servlet.security.ServletAuthentication.runAs(subject, request);
                    String loginUrl = "/adfAuthentication?success_url=/faces/home.jspx";

                    HttpServletResponse response = (HttpServletResponse) ctx.getExternalContext().getResponse();
                    sendForward(request, response, loginUrl);
             } catch (FailedLoginException fle) {
                    FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Incorrect Username or Password",
                                 "An incorrect Username or Password was specified");
                    ctx.addMessage(null, msg);
             } catch (LoginException le) {
                    reportUnexpectedLoginError("LoginException", le);
             }
             return null;
       }

       private void sendForward(HttpServletRequest request, HttpServletResponse response, String forwardUrl) {
             FacesContext ctx = FacesContext.getCurrentInstance();
             RequestDispatcher dispatcher = request.getRequestDispatcher(forwardUrl);
             try {
                    dispatcher.forward(request, response);
             } catch (ServletException se) {
                    reportUnexpectedLoginError("ServletException", se);
             } catch (IOException ie) {
                    reportUnexpectedLoginError("IOException", ie);
             }
             ctx.responseComplete();
       }

       private void reportUnexpectedLoginError(String errType, Exception e) {
             FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Unexpected error during login",
                           "Unexpected error during login (" + errType + "), please consult logs for detail");
             FacesContext.getCurrentInstance().addMessage(null, msg);
             e.printStackTrace();
       }

       public String onLogout() {
             FacesContext facesContext = FacesContext.getCurrentInstance();
             ExternalContext externalContext = facesContext.getExternalContext();
             String url = externalContext.getRequestContextPath()
                           + "/adfAuthentication?logout=true&end_url=/faces/login.jspx";
             try {
                    externalContext.redirect(url);
             } catch (IOException e) {
                    e.printStackTrace();
             }
             facesContext.getResponseComplete();
             return null;
       }
}

Step 8: Now we will configure ADF Security to our application.

Click Application à Secure à Configure ADF Security as shown below:

On click of Configure ADF Security we will get the "Configure ADF Security - Step 1 of 5" popup as shown below:

Select Security Model as "ADF Authentication and Authorization". Click Next. Thus we will get the below popup.

Select Authentication Type as Form-Based Authentication. Browse and set the Login Page as /faces/login.jspx and Error page as /faces/error.jspx. as shown below:

Click Next. Thus we will get the below popup.

Select Enable automatic policy grants as  No Automatic Grants. Click Next. Thus we will get the below popup.

Check Redirect Upon Successful Authentication. Browser the Welcome Page as  /faces/home.jspx as shown below and click Next.

Click the Finish button of the below popup

Step 9: Expand Application Resources à Descriptors à META-INF à Open jazn-data.xml file as shown below:

Step 10: In jazn-data.xml, select Test Users & Roles and create First User as shown below: Set Name as Susanto, Password as welcome1, Display Name as Susanto, Description as Susanto Description.

Similarly create Second User: Set Name as Moumita, Password as welcome1, Display Name as Moumita, Description as Moumita Description.

Step 11: In jazn-data.xml, select Test Users & Roles, click Enterprise Roles: Set Name as EnterpriseAdminRole, Display Name as EnterpriseAdminRole, Description as EnterpriseAdminRole Description, Member as Susanto

Similarly create one more Enterprise Roles and Set Name as EnterpriseUserRole, Display Name as EnterpriseUserRole, Description as EnterpriseUserRole Description, Member as Moumita

Step 12: In jazn-data.xml, select Application Roles. Set Name as ApplicationAdminRole, Display Name as ApplicationAdminRole, Description as ApplicationAdminRole Description, Mapping as EnterpriseAdminRole

Similarly create ApplicationUserRole and set Set Name as ApplicationUserRole, Display Name as ApplicationUserRole, Description as ApplicationUserRole  Description, Mapping as EnterpriseUserRole

Step 13: In jazn-data.xml, select Resource Grants. Select the Resource Type as Web Page. Source Project as ViewController

Now, click the green (+) icon of the Granted To and click Add Enterprise Role.

Add EnterpriseAdminRole, EnterpriseUserRole to grant access.

Check only view under action as shown below. Please note before that we have to create a page definition file (homePageDef.xml) for the home.jspx.

Step 14: Now open home.jspx page and set the value of the af:outputText in line 11 as value="#{securityContext.userName}". This will display the UserName as the LoggedIn UserName. Thus the complete home.jpsx is shown below:

Step 15: Save all and run the login.jspx page. Thus the ran application is shown below:

Give UserName as Susanto and Password as welcome1 ad click on Login button. Thus we get home.jpsx page on successfull login.

We can see that the UserName Susanto is displayed beside Logout link. This is the same User who loggedin.

Click on Logout link and we get back into the login.jpsx page again.

Give UserName as ghgh and Password as 123 ad click on Login button.

Thus on wrong credentials we et the below error popup

Now give UserName as Moumita and Password as welcome1 ad click on Login button. Thus we get the below home.jspx page with UserName as Moumita

Hence the solution to our requirement.


Thanks & Regards,
Susanto Paul