Oracle® Fusion Middleware Application Security Guide 11g Release 1 (11.1.1) Part Number E10043-10 |
|
|
PDF · Mobi · ePub |
This chapter describes a number of security-related use cases and the typical life cycle of an ADF application security. It also lists code and configuration samples presented elsewhere in this Guide.
This chapter contains the following sections:
The audience for the material presented in this chapter are developers, security architects, and security administrators. The presentation is not feature-driven, as in most topics in this Guide, but use case-driven: a number of use cases that solve typical application security challenges are introduced as a departing point to solve particular application security requirements. Some of the use cases describe a declarative approach (and do not require changes in application code); others provide a programmatic approach; and others require both approaches.
The top security issues that security architects and developers face include managing users, user passwords, and access to resources. OPSS is a suite of security services that provides solutions to these challenges by supporting:
Externalizing security artifacts and the security logic from the application
A declarative approach to security
A complete user identity life cycle
Policy-driven access controls
Figure 19-1 illustrates how applications access the security stores and the tools to manage those stores.
Links to Related Documentation
Topics explained elsewhere include the following:
The OPSS Security Architecture - see Section 1.2, "OPSS Architecture Overview."
Single Sign On - see Part IV.
ADF applications - see Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
Oracle Development Tools - see Oracle Fusion Middleware Reference for Oracle Security Developer Tools.
For the list of OPSS APIs, see Appendix H, "References."
This section introduces a number of use cases categorized according to a main security feature or security artifact, in the following sections:
Each use case contains a brief description of the problem it attempts to solve, the security artifacts required, the features involved, and links to details solving the stated problem. Unless otherwise stated, all the descriptions apply to the Oracle WebLogic Application Server and to the WebSphere Application Server.
The authentication use cases are the following:
Java EE Application Requiring Authenticated Users - Users must be authenticated in order to access a Java EE application.
Java EE Application Requiring Programmatic Authentication - Java EE application requires authenticating a user programmatically.
Java SE Application Requiring Authentication - Java SE application requires authenticating against a domain identity store.
In order to access a Java EE application, users must be authenticated against the identity store in cases where the identity store is any of the following:
Single LDAP-based store
Several LDAP-based stores of the same kind (such as all OID, for example)
Several LDAP-based stores of different kinds; in particular two LDAP-based stores: one AD LDAP and a second one OID LDAP
Single DB-based store
Several LDAP- and DB-based stores
This use case requires:
Allowing access to the application to only authenticated users
Not modifying the application code, even when customers have user identities in different repositories
This use case features:
Deploying an application to a WebLogic container
Configuring the appropriate authenticators according to the particular set of user repositories
Configuring the OVD authenticator in case of a mixed LDAP types or mixed LDAP and DB types
According to the repository used, the details of this use case are split into the following scenarios:
Single user repository - Configure the appropriate authenticator with the WebLogic console
Multiple user repositories (or split profiles across LDAP of the same of different kinds) - Configure the OVD authenticator
DB-based repositories - Configure the OVD authenticator
For details, see Section 3.1.2, "Oracle WebLogic Authenticators."
A Java EE application, not using deployment descriptors, must authenticate the user programmatically against the configured identity store(s); it applies only to Java EE applications deployed to the Oracle WebLogic Application Server.
This use case requires using the OPSS public API to authenticate a user, and it features:
Configuring authenticators for a Java EE container
Using the LoginService API to authenticate the user
For details about this use case, see Section 22.1, "Links to Authentication Topics for Java EE Applications."
A Java SE application must authenticate users against the LDAP identity store in use in a domain; the application code requesting authentication must be same regardless of the specifics of the domain's identity store.
This use case requires configuring the identity store(s) against which the authentication should take place and using the LoginService; note that a Java SE application can use only one id login module.
For details about this use case, see Section 22.2.4, "Using the OPSS API LoginService in Java SE Applications."
The identity use cases are the following:
Application Running in Two Environments - Application, running in two different environments, needs to access user profile information in an LDAP-based store.
Application Accessing User Profiles in Multiple Stores - Application needs to access user profile information stored in multiple LDAP-based stores.
An application, which runs in two different environments, needs to access user profile information, such as a user's email address, stored in an LDAP-based store; the LDAP server can be of any of the supported types and that type may differ with the environment. For details on supported types, see Section 4.1, "Supported LDAP-, DB-, and File-Based Services."
More specifically, this use case assumes that:
The application uses the method UserProfile.getEmail()
.
In one environment, there is an AD LDAP configured as follows:
mail.attr = msad_email
In the second environment, there is an OID LDAP configured as follows:
mail.attr = mail
In order for the application to retrieve the correct information without modifying the code and regardless of the environment (first or second) in which it runs, the identity store provider must be configured with the correct property in each of those two environments.
In the first environment (AD LDAP), the identity store provider is set to have the following property:
<property name="mail.attr" value="msad_mail">
In the second one (OID LDAP), the identity store provider is set to have the following property:
<property name="mail.attr" value="mail"
For details about this use case, see Section 7.2, "Configuring the Identity Store Provider."
An application needs access to user profile information located in more than one LDAP-based stores.
This use case requires configuring the environment for multiple LDAP-based stores.
For details about:
Configuring multiple LDAPs, see Section 7.3.2.6, "Examples of the Configuration File"
Configuring the identity store service, see Section 7.3, "Configuring the Identity Store Service"
The authorization use cases are the following:
Java EE Application Accessible by Specific Roles - Java EE application accessible only by users configured in web descriptors.
ADF Application Requiring Fine-Grained Authorization - ADF application requires fine-grained authorization.
Web Application Securing Web Services - Web services application requires securing web services.
Java EE Application Requiring Codebase Permissions - Java EE application requires codebase permissions.
Non-ADF Application Requiring Fine-Grained Authorization - Non-ADF application requires fine-grained authorization.
A Java EE application needs to be accessible only by users that had been assigned specific roles in web descriptors; the group-to-role assignment must be configurable at deployment based on the customer's environment.
For details about this use case, see sections Using Declarative Security with Web Applications and Using Declarative Security with EJBs in Oracle Fusion Middleware Programming Security for Oracle WebLogic Server.
An ADF application in container requires fine-grained authorization at the level of individual controls on the pages in the web application; while the application initiates the authorization check, the policies need to be externalized and customizable per customer post application deployment.
For details on how to develop and secure Oracle ADF applications, see chapter 30, Enabling ADF Security in a Fusion Web Application, in Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
For general information about ADF applications, see Section 1.5.2, "Scenario 2: Securing an Oracle ADF Application."
For details about the life cycle of an ADF application, see Appendix - Security Life Cycle of an ADF Application.
A web application requires securing web services with fine grained policies.
For details about web services security administration, see Oracle Fusion Middleware Security and Administrator's Guide for Web Services.
A Java EE application requires codebase permissions to perform specific actions; typical examples are reading a credential from the credential store or looking up policies in the policy store.
For details about creating codebase policies with Fusion Middleware Control, see Section 9.2.3, "Managing System Policies."
A non-ADF application needs to be secured with fine-grained authorization checks.
This use case requires:
Placing checks in the application code at the appropriate places
Configuring the appropriate policies
For details see Section 20.3, "The JAAS/OPSS Authorization Model."
The credential use case is the following:
Application Requiring Credentials to Access System - Application requires credentials to access a back-end system.
An application requires a credential to connect to a back-end system, such as a database or an LDAP server. The application code should reference this credential in such a way that the specifics of the credential can be changed per customer post deployment without modifying the application code. Furthermore, this use case also requires specifying who can access the credential store and what operations an authorized user can perform on credential data.
This use case features:
Using the credential store to persist credentials
Fetching credentials at runtime with the CSF API in application code
Defining and enforcing system policies on codebase
For details about:
Configuration and code examples, see Section 24.3, "Setting the Java Security Policy Permissions," and Section 24.7, "Examples"
Credential management, see Section 10.3, "Managing the Credential Store"
Packaging, see Section 21.3.2, "Packaging Credentials with Application."
The audit use cases are the following:
Auditing Security-Related Activity - An application requires recording security-related activity.
Auditing Business-Related Activity - An application requires recording business activity in the context of a flow.
An application needs to record security-related activity in several security areas; specifically, the application requires logging the following information:
Changes to a policy: what and when
The policies that were evaluated in a particular time interval
Changes to credentials or keys: what and when
The settings explained in this use case apply to all applications and components in a domain.
This use case requires that auditable applications:
Integrate with the Common Audit Framework (CAF)
Have built-in capabilities to log security activities
Set the proper audit filter level to capture activities in specific security areas
This use case features:
Integrating with the Common Audit Framework
Allowing applications to define their own audit categories and events in security areas, and making the application audit-aware
Allowing applications to set the appropriate filter level
For details about:
Integrating with CAF, see Section 28.4, "Integrating the Application with the Audit Framework."
Registering applications, see Section 28.6, "Register Application with the Registration Service."
Log audit events, see Section 28.7, "Add Application Code to Log Audit Events."
An application needs to record business-related activity in the context of a functional flow; specifically, the application requires logging the users and the business actions performed by them in a particular time interval.
The settings explained in this use case apply to all applications and components in a domain.
This use case requires that applications:
Create their own audit events based on their business needs
Be able to log business activities with runtime attributes to audit data repository
Generate audit reports from audit events
Manage runtime audit policies
Modify audit event definitions, if necessary
This use case features:
Allowing applications to define business functional areas (as audit categories), business activities (as audit events in categories), and attributes in each category.
Registering applications at deployment; updating audit definitions; deregistering applications after deployment.
Managing audit artifacts with Fusion Middleware Control or WSLT scripts.
For details about:
Integrating with CAF, see Section 28.4, "Integrating the Application with the Audit Framework."
Registering applications, see Section 28.6, "Register Application with the Registration Service."
Log audit events, see Section 28.7, "Add Application Code to Log Audit Events."
A sample component_events.xml
file, see Section 28.5, "Create Audit Definition Files."
Managing audit policies, seeSection 13.3, "Managing Audit Policies."
The identity propagation use cases are the following:
Propagating the Executing User Identity - Propagating the executing user identity to a web service over SOAP.
Propagating a User Identity - Propagating a user identity to a web service over SOAP.
Propagating Identities Across Domains - Propagating a user identity across WebLogic domains.
Propagating Identities over HTTP - Propagating a user identity over HTTP.
A client application in container needs to propagate the executing user identity to a web service over SOAP; the web service can be running on a different managed server, in the same domain, or in a different domain.
This use case requires that the current executing user identity be propagated to a web service over SOAP.
The features that facilitate this use case are primarily those of Oracle Web Services Manager (OWSM).
For details about OWSM, see chapter 4, Examining the Rearchitecture of Oracle Web Services Manager in Oracle Fusion Middleware, in Oracle Fusion Middleware Security and Administrator's Guide for Web Services.
For details about propagating identities over SOAP, see chapter 11, Configuring Policies, in Oracle Fusion Middleware Security and Administrator's Guide for Web Services.
A client application in container needs to propagate a user identity (which is not the executing user identity) to a web service over SOAP; the identity to be propagated is stored in the OPSS security store.
This use case requires that an identity of a user, distinct from the current executing user, be propagated to a web service over SOAP.
This use case features:
The OPSS security store, where credentials are stored, from where the application gets the specific identity that needs to be propagated as a PasswordCredential.
Oracle Web Services Manager ability to fetch and propagate the identity to a remote web service.
For details about this use case, see chapter 9, Creating and Managing Policies Sets, in Oracle Fusion Middleware Security and Administrator's Guide for Web Services.
A client application in container in a WebLogic domain needs to propagate a user identity (stored in the OPSS security store) to a different WebLogic domain over RMI.
For details about this use case, see section Enabling Trust Between WebLogic Server Domains in shar.
A client application in container (in a WebLogic domain or a WAS cell) needs to propagate identities over HTTP.
For requirements and details about this use case, see Propagating Identities over HTTP.
The administration use cases are the following:
Application Requiring a Central Store - Application requires a central repository of security artifacts where those artifacts are managed.
Application Requiring Custom Management Tool - Application requires a custom tool to manage a central repository of externalized security artifacts.
Application Running in a Multiple Server Environment - Application requires modifying security artifacts in a multiple node server environment.
An application requires a central repository of policies, credentials, audit configuration, trusts, and keys, and a set of tools to manage that central repository, which is the OPSS security store.
This use case features:
The OPSS security store
Managing security artifacts with Fusion Middleware Control
Managing security artifacts with WLST scripts
For details about:
The OPSS security store, see Section 8.1, "Introduction to the OPSS Security Store."
Managing security artifacts, see:
An application requires a custom tool to manage externalized security artifacts in a context that is meaningful to the application's business.
This use case requires building a custom graphical user interface with calls to OPSS APIs to display and manage security artifacts in the OPSS security store in a context that is meaningful to the application.
This use case features:
Managing security artifacts with OPSS API
For details about:
Code sample illustrating the use of the OPSS API to implement some of the operations needed to manage security artifacts, see A Custom Graphical User Interface.
The list of OPSS APIs, see Appendix H, "References."
Application running in a WebLogic domain where several server instances are distributed across multiple machines requires modifying security artifacts; changes must take effect in all components of the application regardless of where they are running.
This use case features:
Propagating changes to security artifacts whenever those changes are initiated on the administration server; data on managed server nodes is refreshed based on caching policies.
Using the MBeans API or Management API to modify security artifacts.
For details about:
Multiple server nodes, see Section 8.2.1, "Multiple-Node Server Environments"
OPSS services and MBeans, see Appendix E, "Configuring OPSS Services with MBeans"
The integration use case is the following:
Application Running in Multiple Domains - Several WebLogic domains sharing a single repository of security artifacts.
A product requires multiple WebLogic domains to run and those domains share a single central OPSS security store.
This use case features:
OPSS support for several domains to share a security store
For details about:
Domains sharing a credential store, see Section 10.2, "Encrypting Credentials"
Using reassociateSecurityStore
to join to an existing OPSS security store, see Section 9.3.29, "reassociateSecurityStore"
This section describes the following use cases in some detail:
This section explains how an identity can be propagated across containers and domains using the OPSS trust service and the HTTP protocol.
The OPSS trust service allows the propagation of identities across HTTP-enabled applications by providing and validating tokens. The OPSS trust service uses an asserter that is available only on the following platforms:
Oracle WebLogic Application Server - the Identity Asserter
IBM WebSphere Application Server - the Trust Asserter Interceptor (TAI)
Even though the scenarios in this section are illustrated with applications running on WebLogic domains, they also apply to applications running on WebSphere cells; except for the asserter configuration, all other configurations and samples are identical on both platforms. For configuration properties, see Section F.2.6, "Trust Service Properties."
There is one asserter per WebLogic domain or WebSphere cell; the keystore stores digital certificates, private keys, and trusted CA certificates; the storage service used by the keystore is JKS.
Identity propagation using HTTP calls typically runs as follows (see Figure 19-2):
A client application in Domain1 requests a token for an authenticated user from Domain1's OPSS trust service instance.
The trust service accesses Domain1's keystore and issues a token to the client application.
The client application encodes the token in an HTML header and dispatches an HTTP request to a servlet application in Domain2. Domain 2's asserter intercepts the request and extracts the token.
The asserter requests a validation of that token from Domain2's OPSS trust service instance.
The trust service accesses Domain2's keystore to validate the token and returns a response.
Assuming that the validation is successful, the asserter sends the request to the servlet application using the asserted identity.
The servlet application sends an HTTP response to the client application request.
The remainder of this section explains and illustrates the configuration required for the above scenario to work, in the following sections:
In this scenario, the client and the servlet applications use the same trust service instance to issue and validate tokens. The following code and configuration samples illustrate a sample client and a servlet applications running in the same domain.
Client Application Code Sample
The following sample illustrates a client application; note that the file jps-api.jar
must be included the class path for the code to compile.
// Authentication type name public static final String AUTH_TYPE_NAME = "OIT"; // The authenticated username String user = "weblogic"; // URL of the target application URL url = "http://host:port/destinationApp"; //----------------------------------------- JpsContextFactory ctxFactory = JpsContextFactory.getContextFactory(); JpsContext jpsCtx = ctxFactory.getContext(); final TrustService trustService = jpsCtx.getServiceInstance(TrustService.class); final TokenManager tokenMgr = trustService.getTokenManager(); final TokenContext ctx = tokenMgr.createTokenContext( TokenConfiguration.PROTOCOL_EMBEDDED); UsernameToken ut = WSSTokenUtils.createUsernameToken("wsuid", user); GenericToken gtok = new GenericToken(ut); ctx.setSecurityToken(gtok); ctx.setTokenType(SAML2URI.ns_saml); Map<String, Object> ctxProperties = ctx.getOtherProperties(); ctxProperties.put(TokenConstants.CONFIRMATION_METHOD, SAML2URI.confirmation_method_bearer); AccessController.doPrivileged(new PrivilegedAction<String>() { public String run() { try { tokenMgr.issueToken(ctx); } catch (Exception e) { e.printStackTrace(); } return null; } }); Token token = ctx.getSecurityToken(); String b64Tok = TokenUtil.encodeToken(token); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setDoOutput(true); connection.setReadTimeout(10000); connection.setRequestProperty("Authorization", AUTH_TYPE_NAME + " " + b64Tok); connection.connect(); BufferedReader rd = new BufferedReader(new InputStreamReader( connection.getInputStream())); StringBuilder sb = new StringBuilder(); String line = null; while ((line = rd.readLine()) != null) { sb.append(line); } connection.disconnect(); System.out.println(sb.toString());
Keystore Service Configuration
Assuming that the domain name is jrfServer_admin
, the following command illustrates the creation of the domain keystore, represented by the generated file default-keystore.jks
:
JAVA_HOME/bin/keytool -genkeypair -alias jrfServer_admin -keypass welcome -keyalg RSA -dname "CN=jrfServer_admin,O=Oracle,C=US" -keystore default-keystore.jks -storepass password cp default-keystore.jks ${domain.home}/config/fmwconfig
Make sure that the keystore service configured in the file jps-config.xml
points to the generated default-keystore.jks
; the following sample illustrates a keystore service configuration:
<!-- KeyStore Service Instance --> <serviceInstance name="keystore" provider="keystore.provider" location="./default-keystore.jks"> <description>Default JPS Keystore Service</description> <property name="keystore.provider.type" value="file"/> <property name="keystore.file.path" value="./"/> <property name="keystore.type" value="JKS"/> <property name="keystore.csf.map" value="oracle.wsm.security"/> <property name="keystore.pass.csf.key" value="keystore-csf-key"/> <property name="keystore.sig.csf.key" value="sign-csf-key"/> <property name="keystore.enc.csf.key" value="enc-csf-key"/> </serviceInstance >
CSF Configuration
Create a map/key pair used to open the keystore and another map/key pair used to issue tokens. The following commands illustrate these operations using the OPSS script createCred
:
// JKS keystore opening password createCred(map="oracle.wsm.security", key="keystore-csf-key", user="keystore", password="password") // Private key password to issue tokens createCred(map="oracle.wsm.security", key="sign-csf-key", user="orakey", password="password")
For details about the OPSS script createCred
, see Section 10.5, "Managing Credentials with OPSS Scripts."
Grant Configuration
Add a grant like the following to the policy store, which allows the client application to use the trust service API:
<grant> <grantee> <codesource> <url>file:${oracle.deployed.app.dir}/<MyApp>${oracle.deployed.app.ext}</url> </codesource> </grantee> <permissions> <permission> <class>oracle.security.jps.service.trust.TrustServiceAccessPermission</class> <name>appId=*</name> <actions>issue</actions> </permission> </permissions> </grant>
The Oracle WebLogic Server must be stopped and re-started for the above grant to take effect.
Servlet Code
The following sample illustrates how a servlet can obtain an asserted user name:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getRemoteUser(); ServletOutputStream out = response.getOutputStream(); out.print("Asserted username: " + username); out.close(); }
web.xml Configuration
Set the appropriate login method in the file web.xml
, as illustrated in the following snippet:
<web-app id="WebApp_ID" … <login-config> <auth-method>CLIENT-CERT</auth-method> <realm-name>Identity Assertion</realm-name> </login-config> … </web-app>
WebLogic Asserter and Trust Service Configuration
To configure the WebLogic asserter, proceed as follows:
Copy the WebLogic identity asserter JAR jps-wls-trustprovider.jar
to the location ${domain.home}/lib/mbeantypes
, as illustrated by the following command, and then restart the WebLogic Server:
cp ${common.components.home}/modules/oracle.jps_11.1.1/jps-wls-trustprovider.jar ${domain.home}/lib/mbeantypes
Use WebLogic Console to configure the asserter, as follows:
Login to the console as an administrator.
Navigate to Security Settings > Security Realms > myrealm > Providers Tab > Authentication, and click New to open the Create a New Authentication Provider dialog.
In that dialog, enter TrustServiceIdentityAsserter
in the name box, and select TrustServiceIdentityAsserter
from the pull-down in the type box; then click OK.
Verify that a grant like the following is present in the policy store; this grant is required for the asserter to use the OPSS trust service API; if necessary, use WSLT scripts to specify the grant:
<grant> <grantee> <codesource> <url>file:${domain.home}/lib/mbeantypes/jps-wls-trustprovider.jar</url> </codesource> </grantee> <permissions> <permission> <class>oracle.security.jps.service.trust.TrustServiceAccessPermission</class> <name>appId=*</name> <actions>validate</actions> </permission> </permissions> </grant>
Any changes to the file jps-config.xml
) requires the server to be re-started before updates take effect.
WebSphere Trust Asserter Interceptor Configuration
For details on this topic, see section Configuring the Trust Association Interceptor in Oracle Fusion Middleware Third-Party Application Server Guide.
In this scenario there are two different domains: Domain1 and Domain2. The client application is running in Domain1; the servlet application is running in Domain2. It is assumed that each of these two domains have each a trust store service and keystore properly configured as explained under the heading WebLogic Asserter and Trust Store Configuration in the Single Domain Scenario. In this scenario, the client application uses Domain1's trust service for token generation, and the servlet application uses Domain2's trust service for token validation.
In Domain1, the client sample code and the following configurations are identical to those described in the Single Domain Scenario:
the client application is illustrated by the code under the heading Client Application Code Sample.
the configuration of the keystore is illustrated under the heading Keystore Service Configuration.
the CSF configuration is illustrated under the heading CSF Configuration.
the grant configuration is illustrated under the heading Grant Configuration.
In Domain 2, the servlet sample code and web.xml
configuration are identical to those described in the Single Domain Scenario, but there is some extra setup required:
The servlet application code is illustrated by the code under the heading Servlet Code in the Single Domain Scenario.
The configuration of the file web.xml
is illustrated under the heading web.xml Configuration in the Single Domain Scenario.
The client certificate that is used to sign the token in Domain1 must be present in Domain2's keystore; therefore, the administrator proceeds as follows:
Exports the certificate from Domain 1's keystore, as illustrated by the following command:
JAVA_HOME/bin/keytool -export -alias jrfServer_admin.cer -keystore default-keystore.jks -storepass password
Imports the certificate into Domain 2's keystore as illustrated by the command below. Note that the alias passed must be the same as the alias used in step 1 for the export; if you overwrite the issuer name in the client side then that issuer name should be used as the alias.
JAVA_HOME/bin/keytool -importcert -alias jrfServer_admin -keypass welcome -keyalg RSA -dname "CN=jrfServer_admin,O=Oracle,C=US" -keystore default-keystore.jks -storepass password
Sets the Domain2's keystore password in the (Domain2's) credential store using the OPSS script createCred
as follows:
createCred(map="oracle.wsm.security", key="keystore-csf-key", user="keystore", password="password")
In this scenario, applications use either the HTTP protocol or the SOAP protocol, and not all applications in the domain use the same protocol. In such scenario, the keystore can be shared by the trust service used by the HTTP protocol and the SOAP service used by Oracle Web Services Manager. But in order for the trust service to work in this case, some special configurations in the file jps-config.xml
are required as explained in the following sections:
In this scenario, there is one keystore. The following snippet illustrates the configuration required for a certificate with alias orakey
:
<propertySet name="trust.provider.embedded"> <property name="trust.provider.className" value="oracle.security.jps.internal.trust.provider.embedded.EmbeddedProviderImpl"/> <property name="trust.clockSkew" value="60"/> <property name="trust.token.validityPeriod" value="1800"/> <property name="trust.token.includeCertificate" value="false"/> <!-- The alias used to get the signing certificate from JKS --> <property name="trust.aliasName" value="orakey"/> <!-- The issuer name to be added in the token used by the destination trust service instance as an alias to pick up the corresponding certificate to validate the token signature --> <property name="trust.issuerName" value="orakey"/> </propertySet>
In this scenario, there are two domains and two keystores. The following snippet illustrates the configuration required in the domain that is issuing tokens for a certificate with alias orakey
:
<!-- issuer domain trust store must have a signing certif. w. alias orakey --> <propertySet name="trust.provider.embedded"> <property name="trust.provider.className" value="oracle.security.jps.internal.trust.provider.embedded.EmbeddedProviderImpl"/> <property name="trust.clockSkew" value="60"/> <property name="trust.token.validityPeriod" value="1800"/> <property name="trust.token.includeCertificate" value="false"/> <!-- the signing certificate alias in local JKS --> <property name="trust.aliasName" value="orakey"/> <!-- the token issuer's name --> <property name="trust.issuerName" value="domain1"/> </propertySet>
The following snippet illustrates the configuration required in the domain that is receiving tokens for a certificate with alias orakey
:
<!- important: recipient domain must have a token validation certificate for domain1, which is the one was used to sign the token with alias "domain1" --> <propertySet name="trust.provider.embedded"> <property name="trust.provider.className" value="oracle.security.jps.internal.trust.provider.embedded.EmbeddedProviderImpl"/> <property name="trust.clockSkew" value="60"/> <property name="trust.token.validityPeriod" value="1800"/> <property name="trust.token.includeCertificate" value="false"/> <!-- the signing certificate alias in local JKS --> <property name="trust.aliasName" value="orakey"/> <!-- the token issuer's name --> <property name="trust.issuerName" value="domain2"/> </propertySet>
This use case illustrates some of the operations needed, for example, when implementing a custom graphic UI to manage policies. The samples presented use the OPSS APIs and demonstrate the following operations:
Querying users in the identity store.
Querying application roles in the policy store.
Querying the mapping of users and groups to application roles; specifically, given a user identify all the application roles mapped to that user (Recall that the mapping of users and groups to application roles is a many-to-many relationship).
Creating, reading, updating, and deleting the mapping of users and groups to application roles.
This use case assumes that:
The identity store is an OID LDAP-based store.
The policy store is an OID LDAP-based store.
The identity store contains the following hierarchy of users and groups (enterprise roles):
The users Mary, John, Tom, and Helen.
The groups IT, Training, and Development.
The groups Training and Development are members of the group IT.
The user Mary is a member of the group Training.
The users Tom and John are members of the group Development.
The policy store contains the following application policies and hierarchy of application roles:
The application policies ApplicationPolicy1 and ApplicationPolicy2.
The roles System Manager, System Developer, and System Analyst are application roles referenced in the policy ApplicationPolicy1; the System Manager role is a member of the System Developer role; the System Developer role is a member of the System Analyst role.
The roles Director, Instructor, and Lecturer are application roles referenced in the application policy ApplicationPolicy2; the Director role is a member of the Instructor role; the Instructor role is member of the Lecturer role.
The mapping of application roles to users and groups is as follows:
The role System Manager is mapped to the user Helen.
The role System Developer is mapped to the group Development.
The role Director is mapped to the user Tom.
The role Instructor is mapped to the groups Training and Development.
Figure 19-3 illustrates the hierarchy of application roles, the users and groups, and the mapping of application roles to users and groups, as assumed in this use case.
Note that the above role hierarchy implies, for instance, that a user in the System Manager role is also in the System Developer role, and similarly with the other roles. Therefore the role membership for each of the four users is as follows:
User Tom is a member of the following application roles: System Developer, System Analyst, Director, Instructor, and Lecturer.
User Helen is a member of the following application roles: System Manager, System Developer, and System Analyst.
User Mary is a member of the following application roles: Instructor and Lecturer.
User John is a member of the following application roles: System Developer, System Analyst, Instructor, and Lecturer.
The code samples are detailed in the following sections:
Imports Assumed - List of imports
Code Sample 1 - Querying the identity store.
Code Sample 2 - Creating application roles and assigning members to a role.
Code Sample 3 - Querying application roles.
Code Sample 4 - Mapping application roles to users and groups.
Code Sample 5 - Getting all the roles that have a given user as a member.
Code Sample 6 - Removing the mapping of an application role to a group.
The sample codes in this use case assume the following import statements:
import java.security.AccessController; import java.security.Policy; import java.security.Principal; import java.security.PrivilegedExceptionAction; import java.security.Security; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.security.auth.Subject; import oracle.security.idm.Identity; import oracle.security.idm.IdentityStore; import oracle.security.idm.ObjectNotFoundException; import oracle.security.idm.Role; import oracle.security.idm.RoleManager; import oracle.security.idm.SearchParameters; import oracle.security.idm.SearchResponse; import oracle.security.idm.SimpleSearchFilter; import oracle.security.idm.User; import oracle.security.idm.UserProfile; import oracle.security.jps.ContextFactory; import oracle.security.jps.JpsContext; import oracle.security.jps.JpsContextFactory; import oracle.security.jps.principals.JpsApplicationRole; import oracle.security.jps.service.idstore.IdentityStoreService; import oracle.security.jps.service.policystore.ApplicationPolicy; import oracle.security.jps.service.policystore.PolicyObjectNotFoundException; import oracle.security.jps.service.policystore.PolicyStore; import oracle.security.jps.service.policystore.PolicyStoreException; import oracle.security.jps.service.policystore.entitymanager.AppRoleManager; import oracle.security.jps.service.policystore.info.AppRoleEntry; import oracle.security.jps.service.policystore.search.AppRoleSearchQuery; import oracle.security.jps.service.policystore.search.ComparatorType; import oracle.security.jps.util.JpsAuth; import weblogic.security.principal.PrincipalFactory;
The following sample code illustrates two queries to users in the identity store:
private void queryUsers() throws Exception { // Using IDM U/R to query ID store IdentityStore idmStore = idStore.getIdmStore(); // Query an individual user by name User employee = idmStore.searchUser(USER_TOM); log("----------------------------------------------------------"); log("### Query individual user (Tom) from ID store ###"); log(USER_TOM + ": " + employee.getName() + " GUID: " + employee.getGUID()); log(); // Get all users whose name is not "Paul" SimpleSearchFilter filter = idmStore.getSimpleSearchFilter(UserProfile.NAME, SimpleSearchFilter.TYPE_NOTEQUAL, "Paul"); SearchParameters sps = new SearchParameters(filter, SearchParameters.SEARCH_USERS_ONLY); SearchResponse result = idmStore.searchUsers(sps); log("----------------------------------------------------------"); log("### Query all users (whose name is not Paul) from ID store ###"); log("Found the following users:"); while (result.hasNext()) { Identity user = result.next(); log("\t user: " + user.getName() + ", GUID: " + user.getGUID()); } log(); }
The following sample code illustrates how to create an application role and how to make a role a member of another role:
private void createAppRoles1() throws Exception { AppRoleManager arm1 = ap1.getAppRoleManager(); log("----------------------------------------------------------"); log("### Creating app roles in app policy1 with hierachy ###"); AppRoleEntry sysAnalystRole = arm1.createAppRole(APP_ROLE_SYS_ANALYST, APP_ROLE_SYS_ANALYST, APP_ROLE_SYS_ANALYST); AppRoleEntry sysDeveloperRole = arm1.createAppRole(APP_ROLE_SYS_DEVELOPER, APP_ROLE_SYS_DEVELOPER, APP_ROLE_SYS_DEVELOPER); AppRoleEntry sysManagerRole = arm1.createAppRole(APP_ROLE_SYS_MANAGER, APP_ROLE_SYS_MANAGER, APP_ROLE_SYS_MANAGER); ap1.addPrincipalToAppRole(sysManagerRole, APP_ROLE_SYS_DEVELOPER); ap1.addPrincipalToAppRole(sysDeveloperRole, APP_ROLE_SYS_ANALYST); log("### App roles in app policy #1 have been created ###"); log(); }
The following code sample illustrates several ways to query application roles:
private void queryAppRolesInApplicationPolicy1() throws Exception { AppRoleManager arm1 = ap1.getAppRoleManager(); // Get role that matches a name AppRoleEntry are = arm1.getAppRole(APP_ROLE_SYS_MANAGER); log("----------------------------------------------------------"); log("### Query app roles in application policy #1, by name ###"); log("Found " + are.getName() + " by app role name."); log(); // Get the role that matches a name exactly AppRoleSearchQuery q = new AppRoleSearchQuery(AppRoleSearchQuery.SEARCH_PROPERTY.NAME, false, ComparatorType.EQUALITY, APP_ROLE_SYS_ANALYST, AppRoleSearchQuery.MATCHER.EXACT); List<AppRoleEntry> arel = arm1.getAppRoles(q); log("### Query app roles in application policy #1, by exact query ###"); log("Found " + arel.get(0).getName() + " by exact query."); log(); // Get roles with names that begin with a given string q = new AppRoleSearchQuery(AppRoleSearchQuery.SEARCH_PROPERTY.NAME, false, ComparatorType.EQUALITY, APP_ROLE_SYS_DEVELOPER.subSequence(0, 7), AppRoleSearchQuery.MATCHER.BEGINS_WITH); arel = arm1.getAppRoles(q); log("### Query app roles in app policy #1, by begins_with query ###"); log("Found " + arel.get(0).getName() + " by begins_with query."); log(); // Get roles with names that contain a given substring q = new AppRoleSearchQuery(AppRoleSearchQuery.SEARCH_PROPERTY.NAME, false, ComparatorType.EQUALITY, "dummy", AppRoleSearchQuery.MATCHER.ANY); arel = arm1.getAppRoles(q); log("### Query app roles in app policy #1, by matcher any ###"); log("Found " + arel.size() + " app roles by matcher any."); for (AppRoleEntry ar : arel) { log("\t" + ar.getName()); } log(); }
The following sample illustrates how to map application roles to users and groups:
private void assignAppRoleToUsersAndGroups() throws Exception { // Obtain the user/group principals IdentityStore idmStore = idStore.getIdmStore(); User tom = idmStore.searchUser(USER_TOM); User helen = idmStore.searchUser(USER_HELEN); Role trainingRole = idmStore.searchRole(IdentityStore.SEARCH_BY_NAME, GROUP_TRAINING); Role devRole = idmStore.searchRole(IdentityStore.SEARCH_BY_NAME, GROUP_DEV); Principal tomPrincipal = PrincipalFactory.getInstance().createWLSUser(tom.getName(), tom.getGUID(), tom.getUniqueName()); Principal helenPrincipal = PrincipalFactory.getInstance().createWLSUser(helen.getName(), helen.getGUID(), helen.getUniqueName()); Principal trainingPrincipal = PrincipalFactory.getInstance().createWLSGroup(trainingRole.getName(), trainingRole.getGUID(), trainingRole.getUniqueName()); Principal devPrincipal = PrincipalFactory.getInstance().createWLSGroup(devRole.getName(), devRole.getGUID(), devRole.getUniqueName()); // Application policy #1 log("----------------------------------------------------------"); log("### Assigning appl roles to users and groups, app policy #1 ###"); ap1.addPrincipalToAppRole(helenPrincipal, APP_ROLE_SYS_MANAGER); ap1.addPrincipalToAppRole(devPrincipal, APP_ROLE_SYS_DEVELOPER); // Application policy #2 log("### Assigning app roles to users and groups, app policy #2 ###"); ap2.addPrincipalToAppRole(tomPrincipal, APP_ROLE_DIRECTOR); ap2.addPrincipalToAppRole(devPrincipal, APP_ROLE_INSTRUCTOR); ap2.addPrincipalToAppRole(trainingPrincipal, APP_ROLE_INSTRUCTOR); log("### App roles have been assigned to users and groups ###"); log(); }
The following code sample illustrates how to get all the roles that have a given user as a member:
private void showAppRoles() throws Exception { Subject tomSubject = getUserSubject(USER_TOM); Subject helenSubject = getUserSubject(USER_HELEN); Subject johnSubject = getUserSubject(USER_JOHN); Subject marySubject = getUserSubject(USER_MARY); Set<String> applications = new HashSet<String>(); applications.add(APPLICATION_NAME1); applications.add(APPLICATION_NAME2); log("----------------------------------------------------------"); log("### Query application roles for Tom ###"); showAppRoles(applications, USER_TOM, tomSubject); log(); log("### Query application roles for Helen ###"); showAppRoles(applications, USER_HELEN, helenSubject); log(); log("### Query application roles for John ###"); showAppRoles(applications, USER_JOHN, johnSubject); log(); log("### Query application roles for Mary ###"); showAppRoles(applications, USER_MARY, marySubject); log(); } private Subject getUserSubject(String userName) throws Exception { Subject subject = new Subject(); // Query users from ID store using user/role API,for user principal IdentityStore idmStore = idStore.getIdmStore(); User user = idmStore.searchUser(userName); Principal userPrincipal = PrincipalFactory.getInstance().createWLSUser(user.getName(), user.getGUID(), user.getUniqueName()); subject.getPrincipals().add(userPrincipal); // Query users from ID store using user/role API, for enterprise roles RoleManager rm = idmStore.getRoleManager(); SearchResponse result = null; try { result = rm.getGrantedRoles(user.getPrincipal(), false); } catch (ObjectNotFoundException onfe) { // ignore } // Add group principals to the subject while (result != null && result.hasNext()) { Identity role = result.next(); Principal groupPrincipal = PrincipalFactory.getInstance().createWLSGroup(role.getName(), role.getGUID(), role.getUniqueName()); subject.getPrincipals().add(groupPrincipal); } // The subject now contains both user and group principals. // In the WebLogic Server, this setting is done by a login module return subject; } private void showAppRoles(Set<String> applications, String user, Subject subject) { // Get all granted application roles for this subject Set<JpsApplicationRole> result = null; try { result = JpsAuth.getAllGrantedAppRoles(subject, applications); } catch (PolicyStoreException pse) { log(pse.toString()); } if (result.size() <= 1) { log(user + " has " + result.size() + " application role."); if (result.size() == 1) { for (JpsApplicationRole ar : result) { log("\tApplication role: " + ar.getName()); } } } else { System.out.println(user + " has " + result.size() + " application roles."); for (JpsApplicationRole ar : result) { log("\tApplication role: " + ar.getAppID() + "/" + ar.getName()); } } }
The following sample code illustrates how to remove the mapping of an application role to a group:
private void removeAppRoleForUserDirector() throws Exception { // Remove instructor role from Dev group log("----------------------------------------------------------"); log("### Removing Instructor application role from Dev group ###"); IdentityStore idmStore = idStore.getIdmStore(); Role devRole = idmStore.searchRole(IdentityStore.SEARCH_BY_NAME, GROUP_DEV); Principal devPrincipal = PrincipalFactory.getInstance().createWLSGroup(devRole.getName(), devRole.getGUID(), devRole.getUniqueName()); ap2.removePrincipalFromAppRole(devPrincipal, APP_ROLE_INSTRUCTOR); log("### Instructor app role has been removed from Dev group ###"); log(); log("----------------------------------------------------------"); log("### Now query application roles for user John, again ###"); Set<String> applications = new HashSet<String>(); applications.add(APPLICATION_NAME1); applications.add(APPLICATION_NAME2); Subject johnSubject = getUserSubject(USER_JOHN); showAppRoles(applications, USER_JOHN, johnSubject); log(); }
This section explains the phases that the security of an application goes through. It is assumed that the application uses ADF and that it is developed in the Oracle JDeveloper environment.
The phases of the security life cycle of an application are the development phase, the deployment phase, and the management phase. The participants are the product manager or application architect, application developers, and application security administrators. For a summary of tasks, see Summary of Tasks per Participant per Phase.
In the development phase developers design the application to work with the full range of security options available in Oracle Fusion Middleware. Developers have access to a rich set of security services exposed by Oracle JDeveloper, the built-in ADF framework, and the Oracle WebLogic Server. All these components are based on OPSS, which ensures a consistent approach to security throughout the application's life span.
Typically, a developer uses the ADF Security Wizard (an authorization editor) and an expression language editor, all within Oracle JDeveloper; additionally and optionally, he may use OPSS APIs to implement more complex security tasks. Thus, some parts of the application use declarative security, others use programmatic security, and they both rely on security features available in the development and run-time environment.
Application developers also define a number of application entitlements and roles (policy seed data) required to secure the application. This policy seed data is kept in a source control system together with the application source code.
Once developed, the application is typically tested in a staging environment before being deployed to a production environment. In a production environment, both the application and the run-time services are integrated with other security components, such as user directories, single sign-on systems, user provisioning systems, and auditing. The security services usually change with the phase: for example, during development, a developer relies on a file or Oracle Wallet to store user credentials, but, in a production environment, credentials are stored in an LDAP directory (the OPSS security store).
In the deployment phase, typically, an administrator migrates the policy seed data to the production policy store (the OPSS security store), and maps application roles to enterprise groups to effect application security policies.
The management phase starts once an application has been deployed to a production environment. In this phase, application administrators or enterprise security administrators manage day-to-day security tasks, such as granting users access to application resources, reviewing audit logs, responding to security incidents, and applying security patches.
The following tables summarize the major responsibilities per participant in each of the security life cycle phases and Figure 19-4 illustrates the basic flow.
Table 19-1 Security Tasks for the Application Architect
Phase | Task |
---|---|
Development |
Defines high-level application roles based on functional security and data security requirements. Populates the initial file-based application policy store ( |
Deployment |
Defines real-world customer scenarios to be tested by the QA team. |
Management |
Understands and identifies the requirements to customize application policies. Considers defining templates for vertical industries. |
Table 19-2 Security Tasks for the Application Developer
Phase | Task |
---|---|
Development |
Uses tools and processes, specifically Oracle JDeveloper, to build the application and to create security artifacts, such as application roles and permissions. Uses FND Grants to specify data-level security. Tests the application using a local policy store with sample users and roles. |
Deployment |
Assists the QA team to troubleshoot and resolve runtime issues. |
Table 19-3 Security Tasks for the Application Security Administrator
Phase | Task |
---|---|
Deployment |
Uses deployment services to migrate security seed data in Maps application roles to enterprise groups so that security policies can be enforced. |
Management |
Applies patches and upgrades software, as necessary. Manages users and roles, as enterprise users and the application role hierarchy changes overtime. Manages policies packed with the application and creates new ones. Integrates with and manages the IAM infrastructure. |
This section lists most of the code and configuration samples found elsewhere in this Guide, and a fully-written code example.
The following list includes typical security-related programming tasks and links to sample code illustrating implementations:
Querying an LDAP identity store - See Section 7.4, "Querying the Identity Store Programmatically."
Querying application roles and the mapping of users and groups to application roles - See A Custom Graphical User Interface.
Invoking the method isUserInRole
- See Section 20.2.2.2, "Programmatic Authorization."
Managing policies - See Section 20.3.2, "Managing Policies."
Checking policies - See Section 20.3.3, "Checking Policies."
Using the class ResourcePermission
- See Section 20.3.4, "The Class ResourcePermission."
Using the Identity Store Login Module for authentication in Java SE applications - See Section 22.2.3.2, "Using the Identity Store Login Module for Authentication."
Using the Identity Store Login Module for assertion in Java SE applications - See Section 22.2.3.3, "Using the Identity Login Module for Assertion."
The following list includes typical security-related configuration tasks and links to sample configuration:
Configuring an OAM SSO provider - See Section 8.7.3.3, "OAM Configuration Example."
Configuring resource permissions - See Section 20.3.4, "The Class ResourcePermission."
Configuring the servlet filter and the EJB interceptor - See Section 21.1, "Configuring the Servlet Filter and the EJB Interceptor."
Configurations involved with migrateSecurityStore
- See Section 6.5.2.1, "Migrating Policies Manually," and Section 6.5.2.2, "Migrating Credentials Manually."
Configuring an LDAP identity store - See Section 7.3.2.6, "Examples of the Configuration File," and Section 22.2.2, "Configuring an LDAP Identity Store in Java SE Applications."
Configuring the policy and credential stores in Java SE applications - See Section 23.1, "Configuring Policy and Credential Stores in Java SE Applications."
ezshare
is a full example of a Java EE application whose security has been integrated with OPSS that uses permission-based grants and available at the Oracle Network. To locate the example, search for the keyword ezshare.