Oracle ADF Basics
Monday, April 22, 2019
Monday, July 27, 2015
How to enable Prime Faces latest community edition in Oracle ADF essentials version-12c?
Recently faced a requirement from client that existing ADF
essentials application need to run on Stand Alone Kiosk which did not have
keyboard support. Since Oracle’s ADF components do not come with in-built virtual keyboard had to search a lot and came to a conclusion that we have.
Following best ways of implemting desired functionality
1. Custom JavaScript driven keyboard.
2. JQuery virtual keyboard.
3. Prime faces Keyboard component.
Since prime faces is also JSF based component suite I decided
to give it a try and following steps helped me actually in integrating both
component suites.
1. Download primefaces-5.2.jar community edition from prime
faces download site http://primefaces.org/downloads
2. Copy downloaded file to your project’s WEB-INF\lib
directory
3. Add this downloaded jar file to project properties using Jdeveloper.
4. Once you do this you will see the Prime faces library
listed in component window.
5. You can now drag drop components in source mode of your
JSF page.
You can have look at the below code for reference
primedemo.jsf
<af:document title="primedemo.jsf"
id="d1">
<af:form
id="f1">
<af:panelStretchLayout id="psl1"
inlineStyle="width:inherit;">
<f:facet name="bottom"/>
<f:facet name="center">
<af:panelGroupLayout id="pgl1" layout="scroll"
inlineStyle="width:inherit;">
<primefaces-p:keyboard id="k1"
binding="#{backingBeanScope.primedemo_backing.keyboardvalue}"/>
<af:button text="Show" id="b1"
actionListener="#{backingBeanScope.primedemo_backing.buttonActionListener}"/>
</af:panelGroupLayout>
</f:facet>
<f:facet name="start"/>
<f:facet name="end"/>
<f:facet name="top"/>
</af:panelStretchLayout>
</af:form>
</af:document>
primedemo_backing.java
package view;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import org.primefaces.component.keyboard.Keyboard;
public class primedemo_backing {
private Keyboard
keyboardvalue;
public
primedemo_backing() {
}
public void
setKeyboardvalue(Keyboard keyboardvalue) {
this.keyboardvalue = keyboardvalue;
}
public Keyboard
getKeyboardvalue() {
return
keyboardvalue;
}
public void
buttonActionListener(ActionEvent actionEvent) {
// Add event code here...
FacesMessage
Message = new FacesMessage(String.valueOf(keyboardvalue.getValue()));
Message.setSeverity(FacesMessage.SEVERITY_INFO);
FacesContext fc = FacesContext.getCurrentInstance();
fc.addMessage(null, Message);
}
}
Versions Used
1.Oracle Jdeveloper 12.1.3
2.PrimeFaces community edition version primefaces-5.2.jar
Cheers
Thursday, January 2, 2014
Integrate Apache SHIRO With ADF 11g (RichClient/Trinidad)
Apache Shiro basics
Shiro is a project with a long history—it
started life as JSecurity back in 2003 when there were really few options for
Java security. It provides four main pieces of functionality:
• Authentication
• Authorization
• Cryptography
• Session management
We'll be using the authentication part
(determining who the user is) and the authorization part (determining what the
user can do). We will not be using the cryptography (encrypting and decrypting
data)
or the session management (we rely on standard
JSF and ADF functionality for
our session data).
Getting the software
You can download the Shiro software from
http://shiro.apache.org. You'll want the Latest Stable Release, Binary
Distribution. Download the shiro-core and shiro-web JAR files. Because you
don't want your application to depend on a directory outside the application
structure, create a directory called extjars in the application directory and
place your JAR files there. The Shiro code uses Simple Logging Façade for Java
(SLF4J), so you also need to download SLF4J from http://www.slf4j.org. Download
the ZIP file, unpack it somewhere, and copy the slf4j-api-1.7.5.jar and
slf4j-simple-1.7.5.jar files to the same directory. If a newer version than
1.7.5 is available by the time you read this, use that instead.
Installing the packages in your application
To use Shiro security in your application, you
need to include the JAR files in your project. To do this, choose Project
Properties for your View project and then Libraries and Classpath. Click on Add
Library and then New. Give your library the name Shiro and choose Location as
Project. Then select the Class Path node in the tree, click on Add Entry, and
add the four JAR files. Remember to check the Deployed by Default checkbox
The Deployed by Default checkbox indicates that
these libraries should be deployed with the application. If you don't select
this box, your application EAR file gets smaller, but you have to ensure that
the libraries are available on each server you deploy it to.
Click on OK several times to return to the
application.
Now we have the JAR files ready for use in our application,
but we also need to actually configure the application to use them. So, we add
a servlet filter so that every request for a page of our application is passed
through Shiro. This allows Shiro to perform security evaluation before the page
is shown to the user.
To add this filter, we change the web.xml file.
You can find this file in your View project under Web Content | WEB-INF. When
you double-click on the file, JDeveloper opens it in a specialized editor that
allows you to change all settings through user-friendly dialog boxes. In this
case, however, we will use the Source view to work directly with the file.
Click on the Source tab at the bottom of the web.xml window and insert the
following code:
<context-param>
<param-name>shiroConfigLocations</param-name>
<param-value>/WEB-INF/shiro.ini</param-value>
</context-param>
<listener>
<listener-class>
org.apache.shiro.web.env.EnvironmentLoaderListener
</listener-class>
</listener>
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.ShiroFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
The <listener> element goes with the
other <listener> elements, and the filter/ filter-mapping block goes
between the last existing <filter> and the first existing <filter-mapping>.
By placing your Shiro filter mapping first in
the file, this filter is applied first at runtime. There is no need to apply
the other filters if Shiro figures out that the user doesn't have access anyway
Configuring your application for Shiro
Shiro is configured through the use of a Shiro
INI configuration file. Create a new file (item type File in the New dialog),
call it shiro.ini, and place it in the /WEB-INF directory of the view project
Contents of shiro.ini (For rich client application)
[main]
user = sbaf.view.rc.shirofilter.FacesAjaxAwareUserFilter
shiro.loginUrl = /faces/infrastructure/SLogin.jsf
user.loginUrl =
/faces/infrastructure/SLogin.jsf
# DataSource config
ds = org.apache.shiro.jndi.JndiObjectFactory
ds.requiredType = javax.sql.DataSource
ds.resourceName = jdbc/PWCMMISDS
# JDBC realm config
jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.permissionsLookupEnabled = true
# Configure JDBC realm SQL queries.
jdbcRealm.authenticationQuery = SELECT ADUM_PASSWORD FROM ad_user_mst
WHERE ADUM_USER_ID = ?
jdbcRealm.userRolesQuery = SELECT ADUR_ROLE_ID FROM
ad_user_roles WHERE ADUR_USER_ID =?
jdbcRealm.permissionsQuery = SELECT 1 FROM dual
jdbcRealm.dataSource = $ds
[urls]
/faces/infrastructure/SLogin.jsf = user
/faces/common/welcome.jspx = user
/faces/** = user
Contents of shiro.ini for Trinidad Application
[main]
user = sbafuserinterfaces.FacesAjaxAwareUserFilter
shiro.loginUrl = /faces/infrastructure/SLogin.jspx
user.loginUrl =
/faces/infrastructure/SLogin.jspx
# DataSource config
ds = org.apache.shiro.jndi.JndiObjectFactory
ds.requiredType = javax.sql.DataSource
ds.resourceName = jdbc/cgmandiDS
# JDBC realm config
jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.permissionsLookupEnabled = true
# Configure JDBC realm SQL queries.
jdbcRealm.authenticationQuery = SELECT ADUM_PASSWORD FROM
ad_user_mst WHERE ADUM_USER_ID = ?
jdbcRealm.userRolesQuery = SELECT ADUR_ROLE_ID FROM
ad_user_roles WHERE ADUR_USER_ID =?
jdbcRealm.permissionsQuery = SELECT 1 FROM dual
jdbcRealm.dataSource = $ds
[urls]
/faces/infrastructure/SLogin.jspx = user
/faces/common/welcome.jspx = user
/faces/** = user
Note:- Datasource Name
can vary with respect to what you configure in your application
Form-based authentication
If we want our own login page, we need to build
it. In other contexts, it is possible to use a simple HTML-based login page
with Shiro, but for an ADF application where we use JSF, we need to create a
JSF login page and a backing bean to perform the actual login operations
The login bean
Create a new java class “SecurityHandlerBean”
and place that under the package sbafuserinterfaces. If this is rich client
application configure this bean using adfc-config.xml. If you are using
Trinidad then configure this bean in faces-config.xml
Source code of the class:-
package sbafuserinterfaces;
import java.io.IOException;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.ArrayList;
import javax.faces.application.FacesMessage;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;
import javax.servlet.http.HttpServletRequest;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.web.util.SavedRequest;
import org.apache.shiro.web.util.WebUtils;
import sun.misc.BASE64Encoder;
public class SecurityHandlerBean {
private String
userName;
private String
password;
private String
encpassword;
private
ArrayList<String> languageList=new ArrayList<String>();
private String
selectedLanguage="en";
private boolean
remember;
public static
final String HOME_URL = "/faces/common/welcome.jspx";
public static
final String LOGIN_URL = "Slogin.jsf";
public
SecurityHandlerBean() {
}
public boolean
isUserAllowedToSeeAddress() {
return
SecurityUtils.getSubject().isPermitted("ViewAddress");
}
public String
login() {
try {
encpassword=getKeyDigestString(password,null);
System.out.println(encpassword);
SecurityUtils.getSubject().login(new UsernamePasswordToken(userName,
encpassword, remember));
HttpServletRequest request =
(HttpServletRequest)(FacesContext.getCurrentInstance().getExternalContext().getRequest());
SavedRequest savedRequest = WebUtils.getAndClearSavedRequest(request);
ExternalContext externalContext =
FacesContext.getCurrentInstance().getExternalContext();
if
(savedRequest != null) {
System.out.println("SavedRequest URL:" +
savedRequest.getRequestUrl());
}
// externalContext.redirect(savedRequest != null
? savedRequest.getRequestUrl() : HOME_URL);
externalContext.redirect( request.getContextPath()+HOME_URL);
} catch
(Exception e) {
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR,"Sorry,
failed to validate you. Please try again", "");
FacesContext.getCurrentInstance().addMessage(null, msg);
e.printStackTrace(); // TODO: logger.
}
return
"";
}
String
getAbsoluteApplicationUrl() throws Exception {
ExternalContext externalContext =
FacesContext.getCurrentInstance().getExternalContext();
HttpServletRequest request =
(HttpServletRequest)externalContext.getRequest();
URL url = new
URL(request.getRequestURL().toString());
URL newUrl =
new URL(url.getProtocol(), url.getHost(), url.getPort(),
request.getContextPath());
return
newUrl.toString();
}
public String
logout() throws IOException {
SecurityUtils.getSubject().logout();
ExternalContext
externalContext = FacesContext.getCurrentInstance().getExternalContext();
externalContext.invalidateSession();
//
externalContext.redirect(LOGIN_URL);
return
"logout";
}
public void
setUserName(String userName) {
this.userName
= userName;
}
public String
getUserName() {
return
userName;
}
public void
setPassword(String password) {
this.password
= password;
}
public String
getPassword() {
return
password;
}
public void
setRemember(boolean remember) {
this.remember
= remember;
}
public boolean
isRemember() {
return
remember;
}
public String
getKeyDigestString(String message, String key) throws NoSuchProviderException {
try {
String
pwCompareStr = "";
byte[]
messageByte = message.getBytes();
// if no
key is provided, the message string gets encrypted with itself
byte[]
keyByte = (key != null && key.length() > 0) ? key.getBytes() :
message.getBytes();
// get
SHA1 instance
MessageDigest sha1 = MessageDigest.getInstance("SHA-1",
"SUN");
sha1.update(messageByte);
//byte[]
digestByte = sha1.digest(keyByte);
byte[]
digestByte = sha1.digest();
// base 64
encoding
BASE64Encoder b64Encoder = new BASE64Encoder();
pwCompareStr = (b64Encoder.encode(digestByte));
pwCompareStr = new StringBuilder("{SHA-1}").append(pwCompareStr).toString();
return
pwCompareStr;
} catch
(NoSuchAlgorithmException e) {
}
return null;
}
public void
languageChangeEvent(ValueChangeEvent valueChangeEvent){
}
public void setLanguageList(ArrayList<String>
languageList) {
this.languageList = languageList;
}
public
ArrayList<String> getLanguageList() {
return
languageList;
}
public void
setSelectedLanguage(String selectedLanguage) {
this.selectedLanguage
= selectedLanguage;
}
public String
getSelectedLanguage() {
return
selectedLanguage;
}
}
Ensure that the user id and password fields value property
is bind to the configured LoginBean corresponding property.
The login page
Create new page as per the technology stack
(Richclient/Trinidad) and place that in
Sample Login page
(Trinidad)
<?xml version='1.0' encoding='UTF-8'?>
<jsp:root
xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:trh="http://myfaces.apache.org/trinidad/html"
xmlns:tr="http://myfaces.apache.org/trinidad">
<jsp:output
omit-xml-declaration="true" doctype-root-element="HTML"
doctype-system="http://www.w3.org/TR/html4/loose.dtd"
doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"/>
<jsp:directive.page
contentType="text/html;charset=UTF-8"/>
<f:view>
<trh:html>
<trh:head>
<meta http-equiv="Content-Type" content="text/html;
charset=UTF-8"/>
</trh:head>
<trh:body>
<h:form>
<tr:panelFormLayout maxColumns="1" rows="3">
<tr:inputText label="UserId"
value="#{LoginBean.userName}" autoSubmit="true"/>
<tr:inputText label="Password" secret="true"
value="#{LoginBean.password}" autoSubmit="true"/>
<tr:commandButton text="Login" action="#{LoginBean.login}"/>
<f:facet name="footer"/>
</tr:panelFormLayout>
</h:form>
</trh:body>
</trh:html>
</f:view>
</jsp:root>
Sample Login page (RichClient)
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<f:view xmlns:f="http://java.sun.com/jsf/core"
xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
<af:document
title="Login" id="d1">
<af:form
id="f1">
<af:panelStretchLayout id="psl1"
dimensionsFrom="auto">
<f:facet name="bottom"/>
<f:facet name="center">
<af:panelGroupLayout id="pgl2" layout="vertical"
valign="middle" halign="center">
<af:spacer width="10" height="150"/>
<af:panelBox text="" id="pb1"
showDisclosure="false" inlineStyle="width:300px;
height:250.0px;"
rendered="true">
<af:panelFormLayout
id="pfl1">
<af:inputText label="User Name" id="it1"
autoSubmit="true"
value="#{SLoginbean.userName}"
partialTriggers="cb1 cb2"/>
<af:spacer
width="10" height="10"/>
<af:inputText label="Password" id="it2"
secret="true" autoSubmit="true"
value="#{SLoginbean.password}"
partialTriggers="cb1
cb2"/>
<af:spacer width="10" height="10"/>
<af:selectOneChoice label="Language"
value="#{SLoginbean.selectedLanguage}"
valueChangeListener="#{SLoginbean.languageChangeEvent}"
id="soc1" autoSubmit="true">
<af:selectItem label="Arabic" value="ar"
id="si3"/>
<af:selectItem label="Hindi" value="hi"
id="si2"/>
<af:selectItem label="English" value="en"
id="si1"/>
</af:selectOneChoice>
<af:spacer width="10" height="10"/>
<f:facet
name="footer">
<af:panelGroupLayout id="pgl12" layout="vertical"
halign="center">
<af:spacer width="10" height="10"/>
<af:panelGroupLayout id="pgl1" layout="horizontal"
halign="center">
<af:commandButton text="Login" id="cb1"
partialSubmit="true"
action="#{SLoginbean.login}">
</af:commandButton>
<af:spacer width="10" height="10"/>
<af:commandButton text="Cancel" id="cb2"
rendered="false"/>
</af:panelGroupLayout>
</af:panelGroupLayout>
</f:facet>
</af:panelFormLayout>
</af:panelBox>
</af:panelGroupLayout>
</f:facet>
<f:facet name="start"/>
<f:facet name="end"/>
<f:facet name="top"/>
</af:panelStretchLayout>
</af:form>
</af:document>
</f:view>
The user filter
Because
Shiro was born in the classic HTML and JSP world, it doesn't really understand
all the asynchronous JavaScript used in a modern JSF application. This means
that we cannot use a plain Shiro UserFilter filter to redirect to the login
page, but we instead need to build our own. Fortunately, JEE developer Bauke Scholtz
has already figured out how to build such a filter, and he has documented it on
his blog http://balusc.blogspot.sg/2013/01/apache-shiro-is-it-readyfor-java-ee-6.html).
The
following filter is verbatim the one he developed. Create a Java class called
FacesAjaxAwareUserFilter in a new sbafuserinterfaces Java package under your
application base package with content as follows:
package sbafuserinterfaces;
import java.io.IOException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.apache.shiro.web.filter.authc.UserFilter;
public class FacesAjaxAwareUserFilter extends UserFilter {
private static
final String FACES_REDIRECT_XML =
"<?xml
version=\"1.0\" encoding=\"UTF-8\"?>" +
"<partial-response><redirect
url=\"%s\"></redirect></partial-response>";
@Override
protected void
redirectToLogin(ServletRequest req, ServletResponse res) throws IOException {
HttpServletRequest request = (HttpServletRequest)req;
if
("partial/ajax".equals(request.getHeader("Faces-Request")))
{
res.setContentType("text/xml");
res.setCharacterEncoding("UTF-8");
res.getWriter().printf(FACES_REDIRECT_XML, request.getContextPath() +
getLoginUrl());
} else {
super.redirectToLogin(req, res);
}
}
}
The logout Method
This logout method needs to be changed to the following
piece of code so as to ensure that the shiro logout is invoked.
public String
logout_action()throws IOException {
MpUsageLogView
v_mplog = new MpUsageLogView();
v_mplog.logUsage("Logout", "", "");
SecurityUtils.getSubject().logout();
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
HttpServletResponse response =
(HttpServletResponse)externalContext.getResponse();
HttpServletRequest req =
(HttpServletRequest)externalContext.getRequest();
externalContext.invalidateSession();
try {
response.sendRedirect((new
StringBuilder()).append(req.getContextPath()).append("/faces/common/welcome.jspx").toString());
FacesContext.getCurrentInstance().responseComplete();
} catch (IOException
e) {
}
return null;
}
The Weblogic.xml
Changes
We need to comment out everything in Weblogic.xml. You will
find below entries there. Comment them out
<security-role-assignment>
<role-name>1</role-name>
<principal-name>1</principal-name>
</security-role-assignment>
<security-role-assignment>
<role-name>2</role-name>
<principal-name>2</principal-name>
</security-role-assignment>
<security-role-assignment>
<role-name>4</role-name>
<principal-name>4</principal-name>
</security-role-assignment>
<security-role-assignment>
<role-name>5</role-name>
<principal-name>5</principal-name>
</security-role-assignment>
Change Web.xml
In web.xml we need to comment out the traditional security
constraints
<!--<security-constraint>
<web-resource-collection>
<web-resource-name>sbaf</web-resource-name>
<url-pattern>/faces/common/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>5</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/faces/infrastructure/LoginNew.jspx</form-login-page>
<form-error-page>/faces/infrastructure/LoginNew.jspx</form-error-page>
</form-login-config>
</login-config>
<security-role>
<role-name>1</role-name>
</security-role>
<security-role>
<role-name>2</role-name>
</security-role>
<security-role>
<description>4</description>
<role-name>4</role-name>
</security-role>
<security-role>
<description>CREATE_SESSION</description>
<role-name>5</role-name>
</security-role>
<security-role>
<role-name>valid-users</role-name>
</security-role>-->
· http://www.jobinesh.com/2013/02/securing-your-adf-applications-using.html (by Jobinesh Purushothaman)
· Developing Web Applications with Oracle ADF Essentials by Sten E. Vesterli
Subscribe to:
Comments (Atom)
