Skip Headers
Oracle® Application Development Framework Developer's Guide
10g Release 3 (10.1.3.0)

Part Number B28967-02
Go to Documentation Home
Home
Go to Table of Contents
Contents
Go to Index
Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

18 Adding Security to an Application

This chapter describes how to use Oracle ADF Security in your web application to handle authentication and authorization on the Oracle Application Server. It also describes how to bypass Oracle ADF Security when you want to work strictly with container-managed security.

This chapter includes the following sections:

18.1 Introduction to Security in Oracle ADF Web Applications

Web application security can be provided by Oracle ADF Security. The Oracle ADF Security implementation is built upon a pluggable architecture that implements the Oracle Application Server Java Authentication and Authorization (JAAS) Provider for authentication and authorization:

First, you must configure the application to use a resource provider. The user data against which the login and passwords are authenticated is stored within a resource provider, such as a database or LDAP director. By editing the jazn.xml file, you choose an identity management provider for the OracleAS JAAS Provider. Read the following section to understand editing the jazn.xml file:

Then, you can configure the application's container to use Oracle ADF Security. This will allow you to use Oracle ADF Security for authentication and authorization. Alternatively, you can bypass Oracle ADF Security and use container-managed security.

Read the following sections to understand how to configure authentication and create login and logout pages:

When you want to assign resources to particular users, you can work with Oracle ADF Model layer to enable authorization. If you choose not to use ADF authorization, you can still work with ADF authentication. Alternatively, you can integrate standard J2EE authorization with the Oracle ADF Model layer to restrict resources. The SRDemo application uses the latter approach. Read the following section to understand both approaches to implementing authorization:

Note:

When you want to understand the security features of OC4J, see the Oracle Containers for J2EE Security Guide in the Oracle Application Server documentation library. For example, the "Standard Security Concepts" chapter provides a useful overview of the JAAS security model.

18.2 Specifying the JAZN Resource Provider

If you wish to use the JAZN realm from either the lightweight XML resource provider (system-jazn-data.xml) or through the Oracle Internet Directory, you need to edit the jazn.xml file to select one of those providers.

Note: If you are working with another JAAS-compliant security provider, see your security provider's documentation.

18.2.1 How To Specify the Resource Provider

To use the JAZN realm from either the lightweight XML resource provider (system-jazn-data.xml) or through the Oracle Internet Directory (LDAP provider), you need to specify which provider you want your application to work with.

To specify the resource provider, you edit the provider environment descriptor in jazn.xml, located in the following directories.

  • For JDeveloper's embedded OC4J:

    <JDEV_HOME>/jdev/system/oracle.j2ee.10.1.3/embedded-oc4j/config directory

  • For JDeveloper's standalone OC4J:

    <JDEV_HOME>/j2ee/home/config directory

  • For Oracle Application Server:

    <OC4J_HOME>/j2ee/<instance_name>/config directory

To work with the XML-based provider, comment out the environment descriptor for LDAP:

<jazn xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:noNamespaceSchemaLocation=
         "http://xmlns.oracle.com/oracleas/schema/jazn-10_0.xsd"
   schema-major-version="10"
   schema-minor-version="0"
   provider="XML" 
   location="./system-jazn-data.xml" 
   default-realm="jazn.com"
/>

<!--
<jazn 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   xsi:noNamespaceSchemaLocation=
         "http://xmlns.oracle.com/oracleas/schema/jazn-10_0.xsd"
   schema-major-version="10"
   schema-minor-version="0"
   provider="LDAP" 
   location="ldap://myoid.us.oracle.com:389"
/>
-->

To work with the LDAP provider, comment out the environment descriptor for XML:

<!--
<jazn 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:noNamespaceSchemaLocation=
         "http://xmlns.oracle.com/oracleas/schema/jazn-10_0.xsd"
   schema-major-version="10"
   schema-minor-version="0"
   provider="XML" 
   location="./system-jazn-data.xml" 
   default-realm="jazn.com"
/>
-->

<jazn 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   xsi:noNamespaceSchemaLocation=
         "http://xmlns.oracle.com/oracleas/schema/jazn-10_0.xsd"
   schema-major-version="10"
   schema-minor-version="0"
   provider="LDAP" 
   location="ldap://myoid.us.oracle.com:389"
/>

18.2.2 What You May Need to Know About Oracle ADF Security and Resource Providers

Because Oracle ADF Security uses OracleAS JAAS, it relies on the LoginContext to provide the basic methods for authentication. LoginContext uses Login Modules, which are pluggable bits of code that handle the actual authentication. Oracle ADF Security also uses OracleAS JAAS Provider RealmLoginModule login module to perform standard user name/password type of authentication.

Oracle ADF Security can authenticate users against a given resource provider. The resource provider, such as a database or LDAP directory, contains the data against which the login and passwords are authenticated.

Specifically, Oracle ADF Security supports the use of Oracle Single Sign-On and Oracle Internet Directory (OID) to provide authentication. You should use OID (the LDAP-based provider) to provide identity management in production environments where scalability and manageability are important. In this case, you will need to administer the users through the LDAP administration tools provided with Oracle Containers for J2EE.

For more information on using OID, see the Oracle Identify Management Guide to Delegated Administration from the Oracle Application Server documentation library.

In addition, JDeveloper provides an XML-based resource provider (system-jazn-data.xml) that can be used for small scale applications or for development and testing purposes. This provider contains user, role, grant, and login module configurations.

18.3 Configuring Authentication Within the web.xml File

In many web-based applications, there may be a link to "protected" areas of the site that require knowing who the originator of the request is; in other words, access to the linked area requires an authenticated user. This can be accomplished dynamically with the adfAuthentication servlet or without ADF, using only J2EE container-managed authentication provided by OC4J. Either way, by configuring the container with security constraints, you prevent access to the server without an authenticated session.

Note:

The SRDemo application currently does not demonstrate Oracle ADF Security at the ADF Model layer. To understand how the SRDemo application handles authentication, see Section 18.3.1, "How to Enable J2EE Container-Managed Authentication".

Once the user is authenticated, the application can determine whether that user has privileges to access the resource as defined by any authorization constraint. You configure this constraint and set up users or roles for you application to recognize in the web.xml file.

For example, in the SRDemo application, three roles determine who gets access to perform what type of functions. Each user must be classified with one of the three roles: user, technician or manager. All of these criterion are implemented using container managed Form-based authentication supported by Oracle Application Server.

18.3.1 How to Enable J2EE Container-Managed Authentication

If your application contains pages that require a user to be authenticated against a data store in order to be accessed, you must declare the following in the web.xml configuration file:

  • <security-role> defines valid roles in the security context.

  • <login-config> defines the protocol for authentication, for example form-based or HTTPS.

  • <security-constraint> defines the resources specified by URL patterns and HTTP methods that can be accessed only by authorized users or roles.

  • <servlet> defines the servlet that provides authentication.

  • <servlet-mapping> maps the servlet to a URL pattern. The

  • <filter> defines the filter used to transform the content of the authentication request.

  • <filter-mapping> maps the filter to the file extensions used by the application. For details about the ADF binding filter, see Configuring the ADF Binding Filter.

Note:

When you insert an ADF Faces component into a JSF page for the first time, JDeveloper updates the web.xml file to define the ADF Faces servlet filter and ADF Faces resources servlet. For more details about the these servlet settings, see What Happens When You First Insert an ADF Faces Component.

The security roles that you define in the web.xml file identify the logical names of groups of users that your application recognizes. You will create security constraints in order to restrict access to particular web pages based on whether the authenticated user belongs to the authorized role or not.

To specify security roles for J2EE container-managed security:

  1. In the Navigator, expand your JSP project, right-click the web.xml file and choose Properties. The web.xml file resides in the WEB-INF folder of your project.

  2. To add the security role definition, select Security Roles on the left panel of the Web Application Deployment Descriptor editor and click Add.

    The roles you enter here must match roles from your data store. For example, if you are using the XML-based provider (as defined with system-jazn-data.xml), you would enter the value of <name> for any of the defined <roles> that need to be authenticated. Additionally, if you configure OC4J to use security role mapping, the role names must also match the roles defined in the <security-role-mapping> element of the orion-web.xml configuration file.

  3. Save all changes and proceed to create the login configuration, as described below.

Figure 18-1 shows the web.xml editor with the Security Roles definition displayed. In the SRDemo application, three security roles are defined.

Figure 18-1 Web Application Deployment Descriptor Dialog, Security Roles Panel

Security roles in Deployment Descriptor editor.

Before configuring the login configuration, you should already have created a login web page and the optional login error page. For details, see Section 18.4, "Creating a Login Page".

To create a login configuration for J2EE container-managed security:

  1. In the Navigator, expand your JSP project, right-click the web.xml file and choose Properties. The web.xml file resides in the WEB-INF folder of your project.

  2. To create a login configuration, select Login Configuration on the left panel of the editor. For example, to use form-based authentication, you would select Form-Based Authentication, and enter the name of the file used to render the login and login error page, for example login.jspx and loginerror.jspx. For further details, see Section 18.4.1, "Wiring the Login and Error Pages".

  3. Save all changes and close the Web Application Deployment Descriptor editor.

Figure 18-2 shows the web.xml editor with the Login Configuration definition displayed.

Figure 18-2 Web Application Deployment Descriptor Dialog, Login Configuration Panel

Login configuration in Deployment Descriptor editor.

To create security constraints for J2EE container-managed security:

  1. In the Navigator, expand your JSP project, right-click the web.xml file and choose Properties. The web.xml file resides in the WEB-INF folder of your project.

  2. To add the security constraint definition, select Security Constraints on the left panel of the editor, and at the bottom of the panel click New.

  3. To add a new Web Resource, on the Constraints page, click Add.

    Tip: Because the security constraint is specified as a URL, the web resource name you supply can be based on your application's database connection name. For example, if your database connection is MyConnection, then you might type jdbc/MyConnection for the web resource name.

  4. To specify the URL pattern of your client requests, click the web resource name you just specified, select URL Patterns, and click Add. Type a forward slash (/) to reference a JSP login page located at the top level relative to the web application folder.

  5. To specify authorized security roles, select the Authorization tab. Select the security roles that require authentication. The roles available are the roles you configured in step 2.

  6. To specify transport guarantee, select the User Data tab. Select the type of guarantee to use.

  7. Save all changes and close the Web Application Deployment Descriptor editor.

Figure 18-3 shows the web.xml editor with a Security Constraint definition displayed.

Figure 18-3 Web Application Deployment Descriptor Dialog, Security Constraints Panel

Security contraints in Deployment Descriptor editor.

18.3.2 What Happens When You Use Security Constraints without Oracle ADF Security

Example 18-1 shows sample definitions similar to the ones that your web.xml file should contain when you have finished configuring J2EE container-managed security.

Example 18-1 J2EE Security Enabled in the SRDemo Application web.xml File

<security-constraint>
    <web-resource-collection>
      <web-resource-name>ALL Manager</web-resource-name>
      <url-pattern>faces/app/management/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>manager</role-name>
    </auth-constraint>
</security-constraint>
<security-constraint>
    <web-resource-collection>
      <web-resource-name>AllStaff</web-resource-name>
      <url-pattern>faces/app/staff/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>technician</role-name>
      <role-name>manager</role-name>
    </auth-constraint>
</security-constraint>
<security-constraint>
    <web-resource-collection>
      <web-resource-name>SRDemo Sample</web-resource-name>
      <url-pattern>faces/app/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
       <role-name>user</role-name>
          <role-name>technician</role-name>
          <role-name>manager</role-name>
       </auth-constraint>
  </security-constraint>
  <login-config>
     <auth-method>FORM</auth-method>
     <form-login-config>
        <form-login-page>infrastructure/SRLogin.jspx</form-login-page>
        <form-error-page>infrastructure/SRLogin.jspx</form-error-page>
     </form-login-config>
  </login-config>
  <security-role>
     <description>Customers of ACME corp</description>
     <role-name>user</role-name>
  </security-role>
  <security-role>
     <description>Employees of ACME corp</description>
     <role-name>technician</role-name>
  </security-role>
  <security-role>
     <description>The boss</description>
     <role-name>manager</role-name>
  </security-role>

When the user clicks a link to a protected page, if they are not authenticated (that is, the authenticated user principal is not currently in SecurityContext), the OC4J security servlet is called and the web container invokes the login page defined by the deployment descriptor <form-login-config> element.

Once a user submits their user name and password, that data is compared against the data in a resource provider where user information is stored, and if a match is found, the originator of the request (the user) is authenticated. The user name is then stored in SecurityContext, where it can be accessed to obtain other security related information (such as the group the user belongs to) in order to determine authorization rights.

The web.xml deployment descriptor supports declarative security through <security-constraints> that specify the resources available to the authenticated users of the application. Whether or not the user is permitted to access a web page depends on its membership in a role identified in the <auth_constraint> element. The application calls the servlet method isUserInRole() to determine if a particular user is in a given security role. The <security-role> element defines a logical name of the roles based on the same names defined by the JAZN realm in the system-jazn-data.xml file.

18.3.3 How to Enable Oracle ADF Authentication

For web-based applications, you can configure a security constraint against the adfAuthentication servlet within the web.xml file. This constraint prevents access to the servlet without an authenticated session. As long as the link to the protected area contains the URL pattern defined in the constraint, the web container will invoke the login page if the user is not authenticated.

Note:

The adfAuthentication servlet is optional and allows dynamic authentication, that is, if the user has not yet logged in and the page being accessed needs authorization, then the user will be prompted to log in. The servlet take an optional parameter success_url. If success_url is specified, then after successfully logging in, the user is directed to the requested page. If success_url is not specified, then after successful login, the servlet directs the user back to the page from which the login was initiated.

To configure web.xml for Oracle ADF Security:

  1. In the Navigator, expand your JSP project, right-click the web.xml file and choose Properties. The web.xml file resides in the WEB-INF folder of your project.

  2. Define Security Roles, Login Configuration, and Security Constraints as you normally would. (See above procedures.)

  3. To create the <servlet> element for the ADF authentication servlet, select Servlets/JSP on the left panel of the editor and click New. Enter the following:

    Servlet Name: adfAuthentication

    Servlet Class: oracle.adf.share.security.authentication.AuthenticationServlet

    To add an initialization parameter that contains the URL for the resulting page if authentication succeeds, select Initialization Parameters and click Add. If you do not enter a URL, the user will return to the current page.

  4. To create a servlet mapping, select Servlet Mapping on the left panel of the editor, and click Add. Enter the following:

    URL Pattern: /adfAuthentication/*

    Servlet Name: adfAuthentication

  5. Save all changes and close the Web Application Deployment Descriptor editor.

Figure 18-4 shows the web.xml editor with the Servlet Mapping definition displayed for the adfAuthentication servlet.

Figure 18-4 Web Application Deployment Descriptor Dialog, Servlet Mapping Panel

ADF servlet mapping in the Deployment Descriptor editor.

18.3.4 What Happens When You Use Security Constraints with Oracle ADF

Example 18-2 shows sample definitions similar to the ones that your web.xml file should contain.

Example 18-2 Oracle ADF Security Enabled in a Sample web.xml File

<servlet>
  <servlet-name>adfAuthentication</servlet-name> <servlet-class>oracle.adf.share.security.authentication.                              AuthenticationServlet</servlet-class>
  <init-param>
    <param-name>sucess_url</param-name>
    <param-value>inputForm.jsp</param-value>
  </init-param>
</servlet>
<servlet-mapping>
  <servlet-name>adfAuthentication</servlet-name>
  <url-pattern>/adfAuthentication/*</url-pattern>
</servlet-mapping>
<security-constraint>
  <web-resource-collection>
    <web-resource-name>adfAuthentication</web-resource-name>
    <url-pattern>/adfAuthentication</url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <role-name>user</role-name>
  </auth-constraint>
</security-constraint>
<login-config>
  <auth-method>FORM</auth-method>
  <form-login-config>
    <form-login-page>login.jspx</form-login-page>
    <form-error-page>login.jspx</form-error-page>
  </form-login-config>
</login-config>
<security-role>
  <role-name>user</role-name>
</security-role>

When the user clicks a link to a protected page, if they are not authenticated (that is, the authenticated user principal is not currently in SecurityContext), the Oracle ADF Security Login Servlet is called and the web container invokes the login page.

Once a user submits their user name and password, that data is compared against the data in a resource provider where user information is stored, and if a match is found, the originator of the request (the user) is authenticated. The user name is then stored in SecurityContext, where it can be accessed to obtain other security related information (such as the group the user belongs to) in order to determine authorization rights.

Because Oracle ADF Security implements OracleAS JAAS, authentication also results in the creation of a JAAS Subject, which also represents the originator of the request.

18.4 Creating a Login Page

The login page for a web application should use the J2EE security container login method j_security_check as a method that the form posts. Figure 18-5 shows a sample login page from the SRDemo application.

Figure 18-5 Sample Login Page from the SRDemo Application

Sample login page from the SRDemo application.

CAUTION:

When you create the login page, you may use JSP elements and JSTL tags. Your page can be formatted as a JSFX document, but due to a limitation in relation to JSF and container security, JSF components cannot be used.

To create a web page for the login form:

  1. With the user interface project selected, open the New Gallery and select JSP from the Web Tier - JSP category. Do NOT select the Web Tier - JSF category to create a JSPX document as a login form.

  2. In the Create JSP wizard, choose JSPX Document type for the JSP file type. The wizard lets you create a JSPX document without using managed beans.

  3. On the Tag Libraries page of the wizard, select All Libraries and add JSTL Format 1.1 and JSTL Core 1.1 to the Selected Libraries list.

  4. Click Finish to complete the wizard and add the JSPX file to the user interface project.

  5. In the Component Palette, select the JSTL 1.1 FMT page, and drag SetBundle into the Structure window for the JSPX document so it appears above the title element.

  6. In the Insert SetBundle dialog, set BaseName to the package that contains the resource bundle for the page. For example, in the SRDemo application, it is oracle.srdemo.view.resources.UIResources.

  7. Optionally, drag Message onto the title element displayed in the Structure window. Double-click the Message element and set the key property to the resource bundle's page title key. For example, in the SRDemo application, the key is srlogin.pageTitle. Delete the string title leftover from the page creation.

  8. In the Component Palette, select the HTML Forms page and drag Form inside the page body. In the Insert Form dialog, set the action to j_security_check and set the method to post.

  9. Drag Text Field for the user name into the form and set the name to j_username.

  10. Drag Password Field into the form and name it j_password.

  11. Drag Submit Button into the form with label set to Sign On.

  12. In the Component Palette, again select the JSTL 1.1 FMT page, and drag two Message tags into the form so they appear beside the input fields. Set their key properties. For example, in the SRDemo application, the resource keys are srlogin.password and srlogin.username.

Example 18-3 shows the source code from the SRDemo application's login page. This JSPX document uses only HTML elements and JSTL tags to avoid conflicts with the security container when working with JSF components. The security check method appears on the <form> element and the form contains input fields to accept the user name and password. These fields assign the values to the container's login bean attributes j_username and j_password, respectively.

Example 18-3 Sample Source from SRLogin.jspx

<html>
    <head>
      <meta http-equiv="Content-Type"
            content="text/html; charset=windows-1252"/>
      <fmt:setBundle basename="oracle.srdemo.view.resources.UIResources"/>
      <title>
        <fmt:message key="srdemo.login"/>
      </title>
    </head>
    <body>
        ... omitting the "number of attempts" checking logic ... 
        <form action="j_security_check" method="post">
          <table cellspacing="3" cellpadding="2" border="0" width="100%">
            <tr>
              <td colspan="3">
                <img height="69" width="340"
                     src="/SRDemo/faces/images/SRBranding.gif"
                     alt="SRDemo Logo"/>
                <hr/>
              </td>
            </tr>
            <tr>
              <td colspan="3">
                <h1>
                  <fmt:message key="srlogin.pageTitle"/>
                </h1>
              </td>
            </tr>
            <tr>
              <td colspan="3">
                <c:if test="${sessionScope.loginAttempts >0}">
                  <h3><fmt:message key="srdemo.badLogin"/></h3>
                </c:if>
              </td>
            </tr>
            <tr>
              <td>&amp;nbsp;</td>
              <td> </td>
              <td rowspan="7">
                <table border="1" cellpadding="5">
                  <tr>
                    <td>
                      <fmt:message key="srlogin.info"/>
                    </td>
                  </tr>
                </table>
              </td>
            </tr>
            <tr>
              <td>&amp;nbsp;</td>
            </tr>
            <tr>
              <td width="120">
                <b><fmt:message key="srlogin.username"/></b>
              </td>
              <td>
                <input type="text" name="j_username"/>
              </td>
            </tr>
            <tr>
              <td width="120">
                <b><fmt:message key="srlogin.password"/></b>
              </td>
              <td>
                <input type="password" name="j_password"/
              </td>
            </tr>
            <tr>
              <td> </td>
              <td>
                <input type="submit" name="logon" value="Sign On"/>
              </td>
            </tr>
            <tr>
            </tr>
              <td>&amp;nbsp;</td>
            <tr>
              <td>&amp;nbsp;</td>
            </tr>
            <tr>
              <td>&amp;nbsp;</td>
            </tr>
            <tr>
              <td colspan="3">
                <hr/>
              </td>
            </tr>
          </table>
        </form>
      </c:if>
    </body>
</html>

18.4.1 Wiring the Login and Error Pages

To allow the web container to perform authentication, the web.xml file must contain the login configuration information that specifies the page to display for log in and another page to display when log in fails because the user could not be authenticated.

To configure how login is to be handled:

  1. In the Application Navigator, locate web.xml in the WEB-INF folder.

  2. Right-click web.xml and choose Properties.

  3. In the Web Application Deployment Descriptor dialog, select Login Configuration.

  4. Choose Form-Based Authentication and enter the path name for both the login and error page. The path specified for the login page and error page is relative to the document root that will be used to authenticate the user. For example, in the SRDemo application, the path infrastructure/SRLogin.jspx is used for both the login and error page.

Figure 18-6 shows the web.xml editor with the Login Configuration definition displayed.

Figure 18-6 Web Application Deployment Descriptor Dialog, Login Configuration Panel

Login configuration in the Deployment Descriptor editor.

18.4.2 What Happens When You Wire the Login and Error Pages

When you define the web.xml login configuration information, JDeveloper creates these definitions:

<login-config>
    <auth-method>FORM</auth-method>
    <form-login-config>
      <form-login-page>infrastructure/SRLogin.jspx</form-login-page>
      <form-error-page>infrastructure/SRLogin.jspx</form-error-page>
    </form-login-config>
  </login-config>

Because you selected Form-based authentication, to specify user-written HTML Form for authentication, the page servlet will look for the JSP page you specified to authenticate the user. The JSP page must return an HTML page containing a Form that conforms to a specific naming convention. Similarly, when authentication fails, the servlet will look for a page to display. In the SRDemo application, the same page appears for both cases, though you could have defined different pages.

Example 18-3 shows the conventions of that permit the HTML Form to invoke the authentication servlet. Specifically, the form must specify three pieces of information:

  1. <form action="j_security_check" method="post"> to invoke the security check method j_security_check on the container's login bean.

  2. <input type="text" name="j_username"/> to assign the username value to the container's login bean attribute j_username.

  3. <input type="password" name="j_password"/> to assign the password value to the container's login bean attribute j_password.

Please note that the value of the login bean attributes must be retuned by the HTML Form with the exact names shown. In a JSF JSP page, a JSF form does not guarantee this. Therefore, Oracle recommends that you use a JSP document page in order to use the HTML Form to preserve the login bean attribute names.

18.5 Creating a Logout Page

The logout page may be called from the global logout button that appears on any page that includes the global menu page. The purpose of the logout page is to provide a prompt for the user to confirm that they want to quit. If the user chooses to log out, their session is invalidated and then they are redirected back to the application's welcome page. They will have to log in again to continue the application. Figure 18-7 shows the logout page from the SRDemo application.

Figure 18-7 Sample Logout Page from SRDemo Application

Navigator showing basic model project.

To create the logout page:

  1. With the user interface project selected, open the New Gallery and select JSF JSP from the Web Tier - JSF category. In this case, it is acceptable to use JSF components.

  2. In the Create JSF JSP wizard, choose JSP Document type for the JSF JSP file type. In this case, you want to create a JSPX document that will use JSF components.

  3. On the Component Binding page, do not create a managed bean.

  4. On the Tag Libraries page of the wizard, add ADF Faces Components and ADF Faces HTML to the Selected Libraries list.

  5. Click Finish to complete the wizard and add the JSPX file to the user interface project.

  6. In the Component Palette, select the ADF Faces Core page, and drag the components Document, Form, and PanelPage so that PanelPage appears nested inside Form, and Form appears nested inside Document.

  7. Next construct the PanelPage container for the command buttons by dragging the components PanelBox, PanelHeader, PanelButtonBar so that PanelButtonBar appears nested inside PanelHeader, and PanelHeader appears nested inside PanelBox. All should be nested inside PanelPage.

  8. To create the buttons that give the user the choice whether to logout or not, drag two CommandButton components inside the PanelButtonBar.

  9. The first button should provide the logout function. You can wire it separately by creating a managed bean. For details, see Section 18.5.1, "Wiring the Logout Action".

  10. The second button should invoke an action GlobalHome to direct the user to the desired page. This action will be defined in the faces-config.xml file with a navigation rule.

Example 18-4 shows the source code from the SRDemo application's logout page. This JSPX document has no restriction on using JSF components because the page has no interaction with the security container. The action to invoke the logout function appears on the <af:commandButton> with the logout label.

Example 18-4 Sample Source from SRLogout.jspx

<af:form>
      <af:panelPage title="#{res['srlogout.pageTitle']}">
        <!--Page Content Start-->
        <af:panelBox>
          <af:panelHeader text="#{res['srlogout.subTitle']}"
                          messageType="warning">
            <af:outputText value="#{res['srlogout.text']}"/>
            <af:panelButtonBar>
              <af:commandButton text="#{res['srlogout.logout.label']}"
                                action="#{backing_SRLogout.logoutButton_action}"/>
              <af:commandButton text="#{res['srlogout.goBack.label']}"
                                action="GlobalHome"/>
            </af:panelButtonBar>
          </af:panelHeader>
        </af:panelBox>
        <!-- Page Content End -->
        ... omitting facets related to the visual design of the page ...
      </af:panelPage>
</af:form>

18.5.1 Wiring the Logout Action

To handle the logout action, the JSPX document can use a managed bean with properties that correspond to the logout page's logout command button.

To handle the logout action:

  1. In the open logout page, double-click the command button that you reserved for the logout action.

  2. In the Action property dialog, leave Method Binding selected and click New to define the Managed Bean class.

  3. In the Create Managed Bean dialog, specify the new class file name for the managed bean and enter the name of the managed bean to register with the faces-config.xml file.

  4. In the Action property dialog, click New to name the method that you will implement in the managed bean class to return a string that sets the component's outcome value.

    Figure 18-8 shows the Action property dialog with the managed bean backing_SRLogout and the method logoutButton_action() entered.

  5. Figure 18-8 Action Binding Dialog for Logout CommandButton

    Backing bean method definition in Action dialog.
  6. In the generated .java file, implement the method handler for the command button that will redirect the user back to an appropriate page. See Example 18-5 for a sample.

Warning:

If your application calls the invalidate() method on the HTTP Session to terminate the current session at logoff time, you must use a "Redirect" to navigate back to a home page to require accessing an ADF Model binding container. The redirect to a databound page ensures that the ADF Binding Context gets created again after invalidating the HTTP Session.

Example 18-5 shows the method handler from the SRDemo application logout page's managed bean. The logoutButton_action() method invalidates the session and redirects to the home page. The security container will prompt the user to reauthenticate automatically.

Example 18-5 Sample Source from SRLogout.java

public String logoutButton_action() throws IOException{
    ExternalContext ectx = FacesContext.getCurrentInstance().getExternalContext();
    HttpServletResponse response = (HttpServletResponse)ectx.getResponse();
    HttpSession session = (HttpSession)ectx.getSession(false);
    session.invalidate();
    
    response.sendRedirect("SRWelcome.jspx");
    return null;
  }

18.5.2 What Happens When You Wire the Logout Action

When you define the action property for the command button, JDeveloper updates the Logout.jspx page source code with the name of the managed bean and bean method to invoke:

<af:commandButton text="#{res['srlogout.logout.label']}"
               action="#{backing_SRLogout.logoutButton_action}"/>

and, JDeveloper updates the faces-config.xml file to define the managed bean:

<managed-bean>
     <managed-bean-name>backing_SRLogout</managed-bean-name>
     <managed-bean-class>oracle.srdemo.view.backing.SRLogout</managed-bean-class>
     <managed-bean-scope>request</managed-bean-scope>
</managed-bean>

Once a user clicks the logout button, the JSF controller identifies the corresponding class file from the Faces configuration file and passes the name of the action handler method to the managed bean. In turn, the action handler, shown previously in Example 18-5, invalidates the session and redirects to the home page.

18.6 Implementing Authorization Using Oracle ADF Security

Authorization provides a way to restrict access to a resource based on the user attempting access. Oracle ADF Security implements OracleAS JAAS for authorization of security-aware resources.

Oracle ADF Security provides another level of granularity, allowing object instance access control based on Java Permissions using JAAS. Specifically, certain Oracle ADF Model layer objects are "security-aware," meaning that there are pre-defined component-specific permissions that a developer can grant for a given resource.

Note:

The SRDemo application currently does not demonstrate Oracle ADF Security at the ADF Model layer. To understand how the SRDemo application handles authorization, see Section 18.7, "Implementing Authorization Programmatically".

The following Oracle ADF objects are security-aware as defined by the page definition file associated with each databound web page:

You set grants on these objects by defining which authenticated users or roles have permission to perform a given action on the object (called a resource). Grantees, which are roles, users, or groups defined as principals are mapped to permissions. Permissions are permission to execute a specific action against a resource, as defined by Oracle ADF Security classes (see the Oracle ADF Javadoc for details). Grants are aggregated. That is if a group's role is granted permissions, and a user is a member of that group, then the user also has those permissions. If no grant is made, then access by the role, user, or group is denied.

Table 18-1 shows permissions you can grant on binding containers, iterator bindings, attribute-level bindings (for example, table, list, boolean, and attribute-value bindings), and method bindings. You use the Authorization Editor to grant permissions for users on the Oracle ADF objects created at runtime from the page definition file.

Table 18-1 Oracle ADF Security Authorization Permissions

ADF Model Object Defined Actions Affect on Components in the User Interface

Binding Container for a web page

grant - can administer the permissions on the page

On pages that allow runtime customization, any link or button configured to set access controls will be disabled for users not granted this permission.

 

edit - can edit content on the page

If a user is granted permission for the view action, but not for the edit action, then any data in input text boxes will display as read only.

 

personalize - allows the user customization of the page

On pages that allow runtime customization, any link or button configured to put the page into personalization mode will be disabled for users not granted this permission.

 

view - can view the page

A user not granted this permission will be shown an authorization error.

Iterator Binding

read - can read the returned rows

All rows of data will be returned. However, you can limit what can be displayed or updated by placing grants on the individual attribute bindings.

 

update - can update data in a row

If the Commit operation is dropped as a command button from the Data Control Palette, the button will be disabled for users who were not granted this permission. Instead of limiting updates to an entire row, you can instead limit the ability to update individual attributes.

 

create - can create a new row

If the Create operation is dropped as a command button from the Data Control Palette, the button will be disabled for any users that were not granted this permission.

 

delete - can delete a row

If the Delete operation is dropped as a command button from the Data Control Palette, the button will be disabled for any users that were not granted this permission.

Method Action Binding

invoke - the method can execute

If the method is bound to a command button, that button will be disabled for any users that were not granted this permission. If the method is invoked implicitly, the method will only execute for users granted this permission.

Attribute-level Bindings

read - can read the attribute's value

The value for the attributes will be displayed.

 

update - can update the attribute 's value

Any data in input text boxes will display as read only for users who were not granted this permission.


Before you can implement Oracle ADF authorization, you must first:

18.6.1 Configuring the Application to Use Oracle ADF Security Authorization

You must first configure the application to use Oracle ADF Security before you can work with ADF authorization in your application.

18.6.1.1 How to Configure Oracle ADF Security Authorization

To enable Oracle ADF Security authorization, you create a configuration file named adf-config.xml that sets the application's container to use Oracle ADF Security. The file initializes the ADFContext and SecurityContext.

To configure an application to use Oracle ADF Security:

  1. Right-click on the project for which security is needed and choose New.

  2. In the New Gallery, select the XML category.

    If XML is not displayed, use the Filter By list at the top to select All Technologies.

  3. In the Items list, select XML Document and click OK.

  4. Name the file adf-config.xml, save it in the <application_name>/.adf/META-INF directory, and click OK.

    The file opens in the source editor.

  5. Replace the generated code with the following:

    <?xml version="1.0" encoding="windows-1252" ?> 
    <adf-config xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance " 
        xsi:schemaLocation=" http://xmlns.oracle.com/adf/config 
        ../../../../../bc4jrt/src/oracle/adf/share/config/schema/config.xsd" 
        xmlns=" http://xmlns.oracle.com/adf/config " 
        xmlns:sec=" http://xmlns.oracle.com/adf/security/config ">
       <sec:adf-config-child xmlns=" http://xmlns.oracle.com/adf/security/config "> 
         <JaasSecurityContext
            initialContextFactoryClass="oracle.adf.share.security.
                 JAASInitialContextFactory" 
            authorizationEnforce="true" 
            jaasProviderClass="oracle.adf.share.security.providers.jazn.
                 JAZNSecurity Context" > 
        </JaasSecurityContext>
       </sec:adf-config-child>
    </adf-config>
    
  6. Save and close the file.

18.6.1.2 What Happens When You Configure An Application to Use Oracle ADF Security

The authorizationEnforce parameter in the <JaasSecurityContext> element set to true will allow the authenticated user principals to be placed into ADF SecurityContext once the user is authenticated.

Tip:

If you want to run the application without using Oracle ADF Security, simply set the authorizationEnforce parameter to false.

18.6.1.3 What You May Need to Know About the Authorization Property

Because security can be turned on and off, it is recommended that an application should determine this property setting before invoking an authorization check. The application can check if Oracle ADF Security is enabled by checking the authorization property setting. This is exposed through the isAuthorizationEnabled() method of the SecurityContext under the ADFContext. For example:

if (ADFContext.getCurrent().getSecurityContext().isAuthorizationEnabled()) 
  {
    Permission p = new RegionPermission("view.pageDefs.page1PageDef", "Edit");
    AccessController.checkPermission(p);
    // do the protected action
  } catch (AccessControlException ace) {
    // do whatever's appropriate on an access denied
}

18.6.2 Setting Authorization on ADF Binding Containers

You use the Authorization Editor to grant permissions for users on the binding container as it is defined by the entire page definition. See Table 18-1 for details about available Oracle ADF permissions.

To grant permissions on the binding container using the Authorization Editor:

  1. Create your web page. From the Visual Editor, right-click the page and choose Go to Page Definition.

  2. In the Structure window, right-click the root node, PageDef, and choose Edit Authorization.

  3. The Authorization Editor shows the pre-defined permissions for the binding container, along with the principals (roles and users) as defined by your resource provider.

    Click Help or press F1 for more help on using this dialog.

18.6.3 Setting Authorization on ADF Iterator Bindings

You use the Authorization Editor to grant permissions for users on iterator bindings. See Table 18-1 for details about available Oracle ADF permissions.

To grant permissions on iterators using the Authorization Editor:

  1. Create your web page. From the Visual Editor, right-click the page and choose Go to Page Definition.

  2. In the Structure window, expand the executables node.

  3. Right-click on the iterator you wish to grant a permission for and choose Edit Authorization.

  4. The Authorization Editor shows the pre-defined permissions for the iterator, along with the principals (roles and users) as defined by your resource provider.

    Click Help or press F1 for more help on using this dialog.

18.6.4 Setting Authorization on ADF Attribute and MethodAction Bindings

You use the Authorization Editor to grant permissions for users on attribute and method action bindings.

Note that permissions granted on an attribute reflect the ability to execute operations such as Create, Delete, and Commit. Therefore, do not set authorization on the operations, but instead on the attribute or iterator. See Table 18-1 for details about Oracle ADF permissions.

To grant permissions on attribute and method bindings using the Authorization Editor:

  1. Create your web page. From the Visual Editor, right-click the page and choose Go to Page Definition.

  2. In the Structure window, expand the bindings node.

  3. Right-click on the attribute or method action binding you wish to grant a permission for and choose Edit Authorization.

  4. The Authorization Editor shows the pre-defined permissions for the attribute or method action binding, along with the principals (roles and users) as defined by your resource provider.

    Click Help or press F1 for more help on using this dialog.

18.6.5 What Happens When Oracle ADF Security Handles Authorization

When a user attempts to execute an action against a resource which has a defined grant, Oracle ADF Security checks to see if the user is a principal defined in the grant. If the user is not yet authenticated, the application displays the login page or form. If the user has been authenticated, and does not have permission, a security error is displayed.

Example 18-6 shows grants for the attribute binding and method binding if you are using the Oracle JAZN lightweight XML provider, these grants are written in the system-jazn-data.xml file. Note that in these grants, the role users has been granted a MethodPermission to invoke the deleteDepartments() method, and also an AttributePermission to read the DepartmentID attribute value.

Example 18-6 Sample system-jazn-data.xml File Oracle ADF Permissions

<grant>
  <grantee>
    <principals>
      <principal>
        <realm-name>jazn.com</realm-name>
        <type>role</type>
        <class>oracle.security.jazn.spi.xml.XMLRealmRole</class>
        <name>jazn.com/users</name>
      </principal>
    </principals>
  </grantee>
  <permissions>
    <permission>
      <class>oracle.adf.share.security.authorization.MethodPermission</class>
      <name>SessionEJB.dataProvider.deleteDepartments</name>
      <actions>invoke</actions>
    </permission>
    <permission>
      <class>oracle.adf.share.security.authorization.AttributePermission</class>
      <name>EmployeesView1.DepartmentId</name>
      <actions>read</actions>
    </permission>
  </permissions>
</grant>

Users or roles are those already defined in your resource provider.

18.7 Implementing Authorization Programmatically

You can set authorization policies against resources and users. For example, you can allow only certain groups of users the ability to view, create, or change certain data or invoke certain methods. Or, you can prevent components from rendering based on the group a user belongs to. Because the user has been authenticated, the application can determine whether or not to allow that user access to any object that has an authorization restraint configured against it.

The application can reference roles programmatically to determine whether a specific user belongs to a role. In the SRDemo application this is accomplished using the method isUserInRole() defined by the FacesContext interface (and also available from the HttpServletRequest interface).

The SRDemo application uses three core roles to determine who will have access to perform specific functions. Each user is classified with by the roles: user, technician, or manager. The remoteUser value (obtained from the Faces Context through the userid property) matches the email address in the SRDemo application's USERS table. These criteria are implemented using container-managed, Form-based authentication provided by Oracle Application Server as described in Section 18.3.1, "How to Enable J2EE Container-Managed Authentication".

18.7.1 Making User Information EL Accessible

Once the security container is set up, performing authorization is a task of:

  • Reading the container security attributes the first time the application references it

  • Making the key security information available in a form that can be accessed through the expression language

To accomplish this, the JSF web application can make use of a managed bean that is registered with session scope. The managed beans are Java classes that you register with the application using the faces-config.xml file. When the application starts, it parses this configuration file and the beans are made available and can be referenced in an EL expression, allowing access by the web pages to the bean's content.

For detailed information about working with managed beans, see Section 10.2, "Using a Managed Bean to Store Information".

This sample from SRList.jspx controls whether the web page will display a button that the manager uses to display an edit page.

<af:commandButton text="#{res['srlist.buttonbar.edit']}"
           action="#{backing_SRList.editButton_action}"
           rendered="#{userInfo.manager}"/>

This sample from SRCreateConfirm.jspx controls whether the web page will display a user name based on the user's authentication status.

<f:facet name="infoUser">
     <!-- Show the Logged in user -->
     <h:outputFormat value="#{res['srdemo.connectedUser']}"
                     rendered="#{userInfo.authenticated}" escape="false">
            <f:param value="#{userInfo.userName}"/>
     </h:outputFormat>
</f:facet>

18.7.1.1 Creating a Class to Manage Roles

The managed bean's properties allow you to invoke methods in a class that contains the code needed to validate users and to determine the available roles. This class should be created before you create the managed bean so you know the property names to use when you define the managed bean.

To create the Java class:

  1. In the New Gallery select the General category and the Java Class item.

  2. In the Create Java Class dialog, enter the name of the class and accept the defaults to create a public class with a default constructor.

Example 18-7 shows the key methods that the SRDemo application implements:

Example 18-7 SRDemo Application UserInfo.java Sample

/**
 * Constructor
 */
public UserInfo() {

        FacesContext ctx = FacesContext.getCurrentInstance();
        ExternalContext ectx = ctx.getExternalContext();
 
        //Only allow Development mode functions if security is not active        _devMode = (ectx.getAuthType() == null);
 
        //Ask the container who the user logged in as
        _userName = ectx.getRemoteUser();
 
        //Default the value if not authenticated
        if (_userName == null || _userName.length()==0) {
            _userName = "Not Authenticated";
        }        //Set the user role flag...
        //Watch out for a tricky bug here:
        //We have to evaluate the roles Most > Least restrictive 
        //because the manager role is assigned to the technician and user roles 
        //thus checking if a manager is in "user" will succeed and we'll stop 
        //there at the lower level of priviledge
        for (int i=(ROLE_NAMES.length-1);i>0;i--)  {
            if (ectx.isUserInRole(ROLE_NAMES[i])){
                _userRole = i;
                break;
            }
        }
    }    /*
     * Function to take the login name from the container and match that
     * against the email id in the USERs table.
     * Note this is NOT an authentication step, the user is already
     * authenticated at this stage by container security. The binding 
     * container is injected from faces-config.xml and refers to a special
     * pageDef "headless_UserInfoPageDef.xml" which only contains the definition     * of this method call,
     */
    private Integer lookupUserId(String userName) {
        if (getBindings() != null) {
            OperationBinding oper =
           (OperationBinding)getBindings().getOperationBinding("findUserByEmail");
            //now set the argument to the function with the username we want
            Map params = oper.getParamsMap();
            params.put("emailParam",userName);
            // And execute
            User user = (User)oper.execute();
            setUserobject(user);
            //It is possible that the data in the database has changed and             //there is no match in the table for this ID - return an appropriate            //Error in that case
            if (user != null){
                return user.getUserId();    
            }
            else{
                FacesContext ctx = FacesContext.getCurrentInstance();
                ctx.addMessage(null,JSFUtils.getMessageFromBundle
                 ("srdemo.dataError.userEmailMatch",FacesMessage.SEVERITY_FATAL));
                return -1;
            }
        }
        else {
            //This can happen if the ADF filter is missing from the web.xml
            FacesContext ctx = FacesContext.getCurrentInstance();
            ctx.addMessage(null,JSFUtils.getMessageFromBundle
               ("srdemo.setupError.missingFilter",FacesMessage.SEVERITY_FATAL));
            return -1;
        }
    }    /**
     * @return the String role name
     */
    public String getUserRole() {
        return ROLE_NAMES[_userRole];
    }    /**
     * Get the security container user name of the current user.
     * As an additional precaution make it clear when we are running in     * Dev mode
     * @return users login name which in this case is also their email id     */
    public String getUserName() {
      StringBuffer name = new StringBuffer(_userName);
      if (_devMode) {
        name.append(" (Development Mode)");
      }
      return name.toString();
    }    /**
     * Function designed to be used from Expression Language
     * for swiching UI Features based on role.
     * @return boolean
     */
    public boolean isCustomer() {
        return (_userRole==USER_ROLE);
    }    /**
     * Function designed to be used from Expression Language
     * for switching UI Features based on role.
     * @return boolean
     */
    public boolean isTechnician() {
        return (_userRole==TECHNICIAN_ROLE);
    }    /**
     * Function designed to be used from Expression Language
     * for switching UI Features based on role.
     * @return boolean
     */
    public boolean isManager() {
        return (_userRole==MANAGER_ROLE);
    }    /**
     * Function designed to be used from Expression Language
     * for switching UI Features based on role.
     * This particular function indicates if the user is either
     * a technician or manager
     * @return boolean
     */
    public boolean isStaff() {
        return (_userRole>USER_ROLE);
    }    /**
     * Function designed to be used from Expression Language
     * for switching UI Features based on role.
     * This particular function indicates if the session is actually authenticated
     * @return boolean
     */
    public boolean isAuthenticated() {
        return (_userRole>NOT_AUTHENTICATED);
    }
}

18.7.1.2 Creating a Managed Bean for the Security Information

The UserInfo bean is registered as a managed bean named userInfo in the JSF faces-config.xml file. The managed bean uses expressions for managed properties which the UserInfo.java class implements.

For example, in the SRDemo application the following expressions appear in the UserInfo managed bean:

  • #{userInfo.userName} either returns the login Id or the String "Not Authenticated"

  • #{userInfo.userRole} returns the current user's role in its String value, for example, manager

  • #{userInfo.staff} returns true if the user is a technician or manager

  • #{userInfo.customer} returns true if the user belongs to the role user

  • #{userInfo.manager} returns true if the user is a manager

To define the managed bean properties and expressions:

  1. In the Application Navigator, open the faces-config.xml file in the user interface WEB-INF folder.

  2. In the window, select the Overview tab.

  3. In the element list on the left, select Managed Beans and click New.

  4. In the Create Managed Bean dialog specify the class information for the managed bean. If you have not created the class, see Section 18.7.1.1, "Creating a Class to Manage Roles".

  5. To permit the security information defined by the managed bean to accessible by multiple web pages, set Scope to Session. For example, the SRDemo application defines the managed bean name userInfo, corresponding to the UserInfo.java class.

  6. In the Overview window, click the arrow to the left of the Managed Properties bar (appears below the managed bean list) to display properties of the bean.

  7. Click New to create a unique managed bean property bindings with the value #{data.<ManagedBeanName+PageDefID}. In the Oracle ADF model, the variable bindings makes the binding objects accessible to EL expressions. In the SRDemo application defines the bindings property as UserInfoPageDef. The importance of this expression is described in Section 18.7.2.3, "Create a Page Definition to Make the Method an EL Accessible Object".

  8. Optionally, click New to create the security properties that your application will access. For example, the SRDemo application defines the userName and userRole properties as Strings. Figure 18-9 shows the managed bean overview created for the SRDemo application.

    Figure 18-9 Overview of userInfo Managed Bean in the Faces Configuration File

    Navigator showing basic model project.

Example 18-8 shows the portion of the faces-config.xml file that defines the managed bean userInfo to hold security information for the SRDemo application. Note that the managed bean also defines the managed property bindings. Note that the values shown for managed property userName and userRole are ignored by the SRDemo application and were included for test purposes only.

Example 18-8 Managed Beans in the SRDemo faces-config.xml File

<!-- The managed bean used to hold security information -->
  <managed-bean>
    <managed-bean-name>userInfo</managed-bean-name>
    <managed-bean-class>oracle.srdemo.view.UserInfo</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
    <managed-property>
      <property-name>bindings</property-name>
      <value>#{data.UserInfoPageDef}</value>
    </managed-property>
    <!-- Test Data ignored if real security is in use-->
    <managed-property>
      <property-name>userName</property-name>
      <property-class>java.lang.String</property-class>
      <value>sking</value>
    </managed-property>
    <managed-property>
      <property-name>userRole</property-name>
      <property-class>java.lang.String</property-class>
      <value>manager</value>
    </managed-property>
  <!-- End Test Data -->
</managed-bean>

18.7.2 Integrating the Managed Bean with Oracle ADF Model

The managed bean does have some interaction with the Oracle ADF Model layer. Once the user logs in and the logon ID is obtained, the application needs to translate the login ID into the unique userid that permits the application to identify the user. This information can then be used throughout the application to determine what menus and functionality to display. For instance, in the SRDemo application, the SRList page will only display the Edit button when the user logged in belongs to the manager role. The same authorization restraints is applied to the SRCreate page.

To obtain a unique userid that databound web pages can use to perform authorization:

  • Create a TopLink named query that will return a user object for a particular id (which is the value obtained from the container security).

  • Create a method on the session bean facade that wraps this lookup method up.

  • Create an ADF page definition file for the managed bean to describe its use of this lookup method on the session bean.

  • Inject the binding information into the UserInfo bean to provide access to the ADF Model layer to invoke the method on the session bean.

  • Execute the custom method from the UserInfo bean the first time the particular id is required for authorization.

18.7.2.1 Creating a TopLink Named Query To Return a User Object

You can identify the user who logs into the application through a named query. This query will return a user object for a unique identifier, such as a particular email id, received from the container security. The query is read-only and takes a String parameter containing the identifier.

To create a named query, use the descriptor of the TopLink SRMap file that corresponds to the USERS table. The query in SRDemo application is based on the email id and receives its value from the security container.

For more information about TopLink named queries, see Section 3.8, "Creating and Modifying Objects with a Unit of Work".

To create a named query for the User entity:

  1. In the Application Navigator, expand the data model project and open SRMap to display the Mapping editor.

  2. In the Structure window, expand the entities package.

  3. In the Mapping editor, select the descriptor User and click Add to define a new TopLink named query. For example, SRDemo application uses findUserByEmail.

  4. Use the General panel to add a parameter that identifies the unique attribute. For example, the SRDemo application uses emailParam of type java.lang.String.

  5. Use the Format panel to define an expression for the named query. For example, the SRDemo application uses email EQUAL emailParam.

  6. Save the query.

18.7.2.2 Create a Session Facade Method to Wrap the Named Query

Oracle recommends that you use a session facade to access entities and methods in order to expose services to clients. The session bean that implements the session facade design pattern, becomes your application's entry point for the Oracle ADF data control. Chapter three describes how to expose services with ADF data controls. Like other methods to be invoked at application runtime, the finder method for the named query must be registered with the Oracle ADF EJB data control in your project. This step begins the process of allowing the ADF Model layer to access the user security information for a uniquely identified user.

If you have not already created a session facade to wrap the TopLink queries, see Section 3, "Building and Using Application Services".

To add a finder method to an existing the session facade:

  1. Expand the data model package that contains the session bean for which you created the ADF EJB data control.

  2. Double-click the session bean .java file to open it in the source editor.

  3. Add the new method. Example 18-9 shows the session facade finder method implemented in the SRDemo application.

  4. In the Application Navigator, right-click the session bean and choose Edit Session Facade.

  5. In the Application Navigator, add the new method to the remote interface.

  6. Save the .java file and recompile.

  7. In the Application Navigator, right-click the session bean and choose Create Data Control. The new method will appear on the Data Control Palette.

Example 18-9 SRDemo SRPublicFacadeBean.java Finder Method to Expose Unique ID

public User findUserByEmail(String emailParam) {    Session session = getSessionFactory().acquireSession();
    Vector params = new Vector(1);
    params.add(emailParam);
    User result = 
      (User)session.executeQuery("findUserByEmail", User.class, params);
    session.release();

    return result;
}

18.7.2.3 Create a Page Definition to Make the Method an EL Accessible Object

After the finder method used to return a unique id for the user has been registered with the ADF data control, the next step in exposing the finder methods to the Oracle ADF Model layer is to provide a page definition description, where it will be defined as a method action binding. Once the binding is exposed by the Oracle ADF Model, it can be used throughout the application pages.

Typically, each web page maps to a single page definition file. However, when the action binding is to be accessible throughout the application, the binding definition must belong to its own page definition—one that is "headless"—without a corresponding web page.

To create a headless page definition file for the user interface project:

  1. In the Application Navigator, expand the user interface package that contains the page definition files.

  2. Right-click the pageDefs package node and choose New.

  3. In the New Gallery, create an XML document from the General - XML category.

  4. In the Create XML File dialog, name the file for the managed bean that defines the security properties and append PageDef. For example, in the SRDemo application, the headless page definition is named headless_UserInfoPageDef.xml.

  5. Open the XML file in the source editor and add the method binding definition. Example 18-10 shows the binding definition created for the SRDemo application.

  6. Save the file.

The value 999 (or CUSTOM) set on the action property of the methodBinding specifies the method to be invoked is a custom method defined by the application service.

Example 18-10 SRDemo headless_UserInfoPageDef.xml Page Definition File

<?xml version="1.0" encoding="UTF-8" ?>
<pageDefinition xmlns="http://xmlns.oracle.com/adfm/uimodel"
                version="10.1.3.35.65" id="UserInfoPageDef"
                Package="oracle.srdemo.view.pageDefs">
  <bindings>
    <methodAction id="findUserByEmail"
                  InstanceName="SRPublicFacade.dataProvider"
                  DataControl="SRPublicFacade"
                  MethodName="findUserByEmail" RequiresUpdateModel="true"
                  Action="999"
                  ReturnName="SRPublicFacade.methodResults.
                        SRPublicFacade_dataProvider_findUserByEmail_result">
      <NamedData NDName="emailParam" NDType="java.lang.String"/>
    </methodAction>
  </bindings>
</pageDefinition>

The ADF Model layer loads the page definition from the path reference that appears in the DataBinding.cpx file. The new page definition file needs to have this reference to id "UserInfoPageDef" within DataBindings.cpx. This can be done from the Structure window for the CPX file.

To create a headless page definition file for the user interface project:

  1. In the Application Navigator, expand the root user interface package and locate the DataBindings.cpx file. The packages appear in the Application Sources folder.

  2. Double-click DataBindings.cpx and open the Structure window.

  3. In the Structure window, select the pageDefinitionUsages node and choose Insert Inside pageDefinitionUsages > page.

  4. Set Id to the name you specified for your headless page definition file (contains the single methodAction binding). For example, the SRDemo application uses UserInfoPageDef.

  5. Set path to package that where you added the page definition file. For example, in the SRDemo application, the path is oracle.srdemo.view.pageDefs.userInfo.

At runtime, a reference to data.<Headless_PageDefID> will now resolve to this binding definition. Example 18-11 shows the id specified for the headless page definition file in the SRDemo application.

Example 18-11 SRDemo DataBindings.cpx Page Definition Reference

<?xml version="1.0" encoding="UTF-8" ?>
<Application xmlns="http://xmlns.oracle.com/adfm/application" ...
  <pageDefinitionUsages>
    <page id="SRListPageDef"
          path="oracle.srdemo.view.pageDefs.app_SRListPageDef"/>
    <page id="UserInfoPageDef"
          path="oracle.srdemo.view.pageDefs.headless_UserInfoPageDef"/>
     ...
</Application>

18.7.2.4 Executing the Session Facade Method from the UserInfo Bean

In the managed bean definition userInfo, you may have already defined a managed property bindings that has the value #{data.UserInfoPageDef}. For details, see Section 18.7.1.2, "Creating a Managed Bean for the Security Information".

To compliment the expression, the class that implements the security methods (UseInfo.java) requires a corresponding getter and setter method for the bindings property:

public void setBindings(BindingContainer bindings) {
   this._bindings = bindings;
 } 
public BindingContainer getBindings() {    return _bindings;
} 

The first time the application requires the UserId, the session bean method is called. This is done using the getUserId() method in UserInfo.java. The getUserId() method checks to see if the UserId is currently populated. If not, it makes a call to a private method lookupUserId() that actually calls the session facade method:

public Integer getUserId() {
   if (_userId == null){
    _userId = lookupUserId(_userName);
   }
   return _userId;
}

The lookupUserId() method is responsible for invoking the methodAction binding which calls the session facade method defined to get the user ID:

private Integer lookupUserId(String userName) {
        if (getBindings() != null) {
            OperationBinding oper = (OperationBinding)getBindings().
                                 getOperationBinding("findUserByEmail");
            //now set the argument to the function with the username we
            //are interested in
            Map params = oper.getParamsMap();
            params.put("emailParam",userName);
            // And execute
            User user = (User)oper.execute();
            setUserobject(user);
            return user.getUserId();
        }
}

The method uses getBindings() to get the injected binding container from the Faces configuration. Once the binding container is obtained, the method looks up the methodAction binding responsible for coordinating with the session facade method. For details about the session facade method, see Section 18.7.2.4, "Executing the Session Facade Method from the UserInfo Bean".