24 Configuring Java SE Applications to Use OPSS

This chapter describes how to use OPSS to implement authentication, authorization, and audit in Java SE applications.

This chapter includes in the following topics:

Using OPSS in Java SE Applications

To use OPSS in a Java SE application:

  • Place the jps-manifest.jar file in the class path.

  • Call the JpsStartup.start method at initialization.

  • Set the following properties:

    • oracle.security.jps.config, the file path to the jps-config-jse.xml file.

    • common.components.home, the path to the oracle_common directory.

    • java.security.policy, the path to the file java.policy.

    • opss.audit.logDirectory, the path to a writable directory where audit writes records for the application.

  • Set -Djava.security.policy to the location of the Oracle WebLogic Server weblogic.policy policy file (located in the wl_home/server/lib directory).

  • Use the OPSS AppSecurityContext class and note the required associated grant:

    String appID = AppSecurityContext.getApplicationID();
           try {
                setApplicationID(appName);
    	            .....
            } finally {
                setApplicationID(appID );
            }
        }
        private static void setApplicationID(final String applicationID) {
                    AccessController.doPrivileged(new PrivilegedAction() {
                public Object run() {
                    AppSecurityContext.setApplicationID(applicationID);
                    return null;
                }
            });
        } 
    

    The call AppSecurityContext.setApplicationID requires that you include in your jps-config-jse.xml a codesource permission like the following:

    <grant>
        <grantee>
            <codesource>
              <url>myJavaSEapp/-</url>
            </codesource>
        </grantee>
        <permissions>
            <permission>
                <class>oracle.security.jps.JpsPermission</class>
                <name>AppSecurityContext.setApplicationID.myAppStripeID</name>
            </permission>
        </permissions>
    </grant>

The JpsStartup Class

The following sections describe the states, runtime options, and examples of use of the JpsStartup class:

JpsStartup.start States

The transition states of the JpsStartup.start method are defined by the following constants:

  • UNINITIALIZED - The state before a call to JpsStartup.start.

  • INITIALIZING - The state to which it transitions after calling JpsStartup.start.

  • FAILURE - The state to which it transitions if the INITIALIZING state run into any errors.

  • ACTIVE - The state to which it transitions if the INITIALIZING state completed successfully.

  • INACTIVE - The state to which it transitions after calling the JpsStatup.stop method.

The JpsStartup.getState method returns the current OPSS state.

JpsStartup Constructor

The class includes the following constructor:

JpsStatup(java.lang.String platformType,
          java.util.Map<java.lang.String,ContextConfiguration>  ctxtCfgs, 
          java.util.Map<java.lang.String,?> options)

Call this constructor when you want to start OPSS with additional context details and options.

The ctxCfgs argument holds the details of the context specified in the jps-config-jse.xml file. To start contexts other than the default context, pass multiple context information. To start a context other than the default context, pass the context name. If unspecified, then it uses the default context.

The options argument groups specific OPSS startup values. For information about runtime options, see Table 24-1.

JpsStartup runtime Options

The following table describes the options you use with the jpsStartup method:

Table 24-1 JpsStartup Runtime Options

Option Values Default Description

ACTIVE_CONTEXT

The name of an active context.

default

Use the specified context. Otherwise, use the default context.

ENABLE_JAVA_POLICY_PROVIDER

true or false

true

Set to true to use the policy provider. Otherwise, set to false.

ENABLE_AUDIT_SERVICE_EXT

true or false

true

Set to true to start audit monitoring and the audit loader when the service is started. Otherwise, set to false.

ENABLE_POLICY_STORE_SERVICE_EXT

true or false

true

Set to true to start the Policy Distribution Point (PDP) with a policy change. Otherwise, set to false.

ENABLE_DEPLOYMENT_HANDLING

true or false

true

Set to true to create deployment handlers. Otherwise, set to false.

RUNTIME_MODE

DEFAULT or

SCRIPT

DEFAULT

Set to SCRIPT to have the following options set to false:

  • ENABLE_JAVA_POLICY_PROVIDER

  • ENABLE_AUDIT_SERVICE_EXT

  • ENABLE_POLICY_STORE_SERVICE_EXT

  • ENABLE_DEPLOYMENT_HANDLING

Otherwise set to DEFAULT.

JPS_CONFIG

The path to jps.config-jse.xml specified by oracle.security.jps.config

Use the specified path. Otherwise, use the default path.

OPSS Starting Examples

This section illustrates the use of the JpsStartup class in typical scenarios.

Example 1

The following example illustrates how to start OPSS with no explicit parameters.

JpsStartup jpsStartUp = new JpsStartup();
jpsStartUp.start();
jpsStartUp.getState();   
jpsStartUp.stop();

Example 2

The following example illustrates how to start OPSS with specific configuration values. Note that:

  • default1 is the default context passed as part of the contextConfig map.

  • To disable audit, set ENABLE_AUDIT_SERVICE_EXT to false. By default, it is enabled.

  • To disable runtime services set ENABLE_POLICY_STORE_SERVICE_EXT to false. By default, it is enabled.

ConfigurationServiceProvider prov = ConfigurationServiceProvider.newInstance();
ConfigurationService configService = prov.getConfigurationService();
ContextConfiguration configuration = configService.getContextConfiguration("default1");
Map<String, ContextConfiguration> contextConfig = new HashMap<String, ContextConfiguration>();
contextConfig.put(JpsConstants.DEFAULT_CONTEXT_KEY, configuration);

Map<String, Object> option = new HashMap<String, Object>();
option.put(JpsConstants.ENABLE_AUDIT_SERVICE_EXT, "FALSE");
option.put(JpsConstants.ENABLE_POLICY_STORE_SERVICE_EXT, "FALSE");

JpsStartup  jpsStartUp = new JpsStartup("JSE", contextConfig, option);
jpsStartUp.start();
jpsStartUp.stop();

Example 3

The following example illustrates how to start OPSS with an additional context:

Map<String, Object> startupOption = new HashMap<String, Object>();
        
ConfigurationServiceProvider prov = ConfigurationServiceProvider.newInstance();
ConfigurationService configService = prov.getConfigurationService();
ContextConfiguration configuration = configService.getContextConfiguration("default1");

Map<String, ContextConfiguration> contextConfig = new HashMap<String, ContextConfiguration>();
contextConfig.put(JpsConstants.DEFAULT_CONTEXT_KEY, configuration);
 
JpsStartup jpsStartUp = new JpsStartup("JSE", contextConfig, startupOption);
jpsStartUp.start();
jpsStartUp.stop();

Example 4

The following example illustrates how to start OPSS with multiple contexts. It assumes that the jps.config-jse.xml file includes the contexts:

<jpsContexts default="default">
 <jpsContext name="default">
  <serviceInstanceRef ref="credstore"/> ...
 </jpsContext>

 <jpsContext name="default1">
  <serviceInstanceRef ref="idstore.loginmodule"/> ...
 </jpsContext>

 <jpsContext name="default2">
  <serviceInstanceRef ref="keystore"/> ...
 </jpsContext>

 <jpsContext name="default3">
  <serviceInstanceRef ref="policystore "/> ...
 </jpsContext>

 <jpsContext name="bootstrap_credstore_context">
  <serviceInstanceRef ref="bootstrap.credstore"/>
 </jpsContext>
</jpsContexts>

ConfigurationServiceProvider prov = ConfigurationServiceProvider.newInstance();
ConfigurationService configService = prov.getConfigurationService();
ContextConfiguration configuration1 = configService.getContextConfiguration("default1");
ContextConfiguration configuration2 = configService.getContextConfiguration("default2");
ContextConfiguration configuration3 = configService.getContextConfiguration("default3");
 
Map<String, ContextConfiguration> contextConfig = new HashMap<String, ContextConfiguration>();
 
contextConfig.put(JpsConstants.DEFAULT_CONTEXT_KEY, configuration);
contextConfig.put(("default1", configuration1);
contextConfig.put(("default2", configuration2);
contextConfig.put(("default3", configuration3);
 
Map<String, Object> startupOption = new HashMap<String, Object>();
startupOption.put(JpsConstants.ACTIVE_CONTEXT, "default");
 
JpsStartup jpsStartUp = new JpsStartup("JSE", contextConfig, startupOption);
jpsStartUp.start();
jpsStartUp.stop();

The ACTIVE_CONTEXT parameter specifies the context to use as default. If DEFAULT_CONTEXT_KEY is not passed as part of map, then the default context is started provided there is no ACTIVE_CONTEXT key passed as part of startupOption map.

Example 5

The following example illustrates how to start OPSS in the SCRIPT mode. This mode is used when you do not want runtime services started.

Map<String, Object> startupOption = new HashMap<String, Object>();
startupOption.put(JpsConstants.RUNTIME_MODE, "SCRIPT");        
 
JpsStartup jpsStartUp = new JpsStartup("JSE", startupOption);
jpsStartUp.start();
jpsStartUp.stop();

Authentication in Java SE Applications

The following sections explain the identity store support in Java SE applications:

Configuring the LDAP Identity Store in Java SE Applications

A Java SE application can use an LDAP identity store configured in the jps-config-jse.xml file with the serviceProvider, serviceInstance, and jpsContext elements:

<serviceProviders>
  <serviceProvider type="IDENTITY_STORE" name="idstore.ldap.provider" class="oracle.security.jps.internal.idstore.ldap.LdapIdentityStoreProvider">
    <description>Prototype LDAP ID store</description>
  </serviceProvider>
</serviceProviders>

<serviceInstances>
 <serviceInstance name="idstore.ldap" provider="idstore.ldap.provider">
   <property name="idstore.type" value="OID"/>
   <property name="max.search.filter.length" value="500"/>
   <extendedProperty>
     <name>user.search.bases</name>
     <values>
       <value>cn=users,dc=us,dc=oracle,dc=com</value>
     </values>
   </extendedProperty>
   <extendedProperty>
     <name>group.search.bases</name>
     <values>
       <value>cn=groups,dc=us,dc=oracle,dc=com</value>
      </values>
   </extendedProperty>
 </serviceInstance>
</serviceInstances>

<jpsContexts default="ldap_idstore">
  <jpsContext name="ldap_idstore">
    <serviceInstanceRef ref="idstore.ldap"/>
  </jpsContext>

  <jpsContext name="bootstrap_credstore_context">
     <serviceInstanceRef ref="bootstrap.cred"/>  
   </jpsContext>
</jpsContexts>

Note the following points:

  • The name of the serviceInstance (idstore.ldap in the example) must match the instance referenced in serviceInstanceRef.

  • The name of the serviceProvider (idstore.ldap.provider in the example) must match the provider specified in serviceInstance.

Using Login Modules in Java Applications

Unless otherwise stated the information in this section applies to both Java EE and SE applications, and the API you use to call login modules is common to both kinds of applications.

A login module is a component that authenticates users and populates a subject with principals. The login module authenticates a user after requesting a name and a password or some other data. If the authentication succeeds, then the module assigns the relevant principals to the subject.

In any of the supported login modules, set the following properties:

enable.anonymous (default: false)
remove.anonymous.role (default: true)
add.application.roles (default: true)
add.authenticated.role (default: true)

The supported login modules are:

In Java SE applications, the default identity store service supports the User Authentication and the User Assertion login modules.

The User Authentication Login Module

Use the User Authentication login module in both Java EE or SE applications to authenticate a user with a given user name and password. The configuration of this login module is available ready-to-use, and it authenticates against the domain identity store.

The following example illustrates the use of this module for programmatic authentication:

import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
public class MyCallbackHandler  extends CallbackHandler {
        private String name = null;
        private char[] password = null;
 
        public MyCallbackHandler(String name, char[] password) {
          this.name = name;
          this.password = password;
        }
 
        public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
            for (Callback callback : callbacks) {
                if (callback instanceof NameCallback) {
                    NameCallback ncb  = (NameCallback) callback;
                    ncb.setName(name);
                }
                else if (callback instanceof PasswordCallback) {
                    PasswordCallback pcb  = (PasswordCallback) callback;
                    pcb.setPassword(password);
                }
                else {
                    throw UnsupportedCallbackException(callback);
                }
            }
        }
}
 
JpsLoginModuleFactory factory = JpsLoginModuleFactory.getLoginModuleFactory();
CallbackHandler cbh = new  MyCallbackHandler("name", "password".toCharArray());
LoginContext ctx = factory.getLoginContext(JpsLoginModuleType.USER_AUTHENTICATION, null, cbh);
ctx.login();
Subject s = ctx.getSubject();
The User Assertion Login Module

Use the User Authentication login module in both Java EE and SE applications to assert a user identity in the identity store. This requires provisioning an oracle.security.jps.JpsPermission permission and implementing the oracle.security.jps.callback.IdentityCallback callback, as described in the following sections:

Provisioning the jpsPermission

The following example illustrates a grant allowing the jdoe principal permission to execute the User Assertion login module:

<grant>
  <grantee>
    <principals>
      <principal>
        <class>weblogic.security.principal.WLSUserImpl</class>
        <name>jdoe</name>
      </principal>
    </principals>
  </grantee>
  <permissions>
    <permission>
      <class>oracle.security.jps.JpsPermission</class>
      <name>IdentityAssertion</name>
      <action>execute</action>
    </permission>
  </permissions>
</grant>

Implementing the CallbackHandler

The following example illustrates an implementation of the callback handler:

import oracle.security.jps.callback.IdentityCallback;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import java.io.IOException;
    public class AssertCallbackHandler implements CallbackHandler {
        private String name = null;
        public AssertCallbackHandler(String name) {
            this.name = name;
        }
        public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
            for (Callback callback : callbacks) {
                if (callback instanceof IdentityCallback) {
                    IdentityCallback nc = (IdentityCallback) callback;
                    nc.setIdentity(name);
                }
                else {
                    throw new UnsupportedCallbackException(callback);
                }
            }
        }
    }

Implementing the Programmatic Assertion

The following example illustrates how to assert a user:

import oracle.security.jps.callback.IdentityCallback;
import oracle.security.jps.internal.api.jaas.module.JpsLoginModuleFactory;
import oracle.security.jps.internal.api.jaas.module.JpsLoginModuleType;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginContext;
import java.io.IOException;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
        Subject subject = AccessController.doPrivileged(new PrivilegedExceptionAction<Subject>() {
            public Subject run() throws Exception {
                JpsLoginModuleFactory f = JpsLoginModuleFactory.getLoginModuleFactory();
                CallbackHandler cbh = new AssertCallbackHandler(name);
                LoginContext c = f.getLoginContext(JpsLoginModuleType.USER_ASSERTION, null, cbh);
                c.login();
                return c.getSubject();
            }
        });
The Identity Store Login Module

A Java SE application can use a stack of login modules to authenticate its users. Each module performs its own computations independently from the others in the stack, and they are specified in the jps-config-jse.xml file.

The sequence in which a context lists the login modules in a stack is significant because the authentication algorithm takes this order into account in its computation. Ready-to-use, the identity store service is specified in the system-jazn-data.xml file. The service can be reconfigured to use an LDAP store.

OPSS APIs includes the oracle.security.jps.service.login.LoginService interface that allows a Java SE application to call not just all the login modules in a stack, but a subset of them in a prescribed order. The context passed to LoginContext in this interface determines the stack of login modules that your application uses.

The class associated with Identity Store login module is the oracle.security.jps.internal.jaas.module.idstore.IdStoreLoginModule class.

Properties specific to this login module include remove.anononymous.role and add.application.role.

You configure an instance of this module in the jps-config-jse.xml file:

<serviceInstance name="idstore.loginmodule" provider="jaas.login.provider">
  <description>Identity Store Login Module</description>
  <property name="loginModuleClassName" value="oracle.security.jps.internal.jaas.module.idstore.IdStoreLoginModule"/>
  <property name="jaas.login.controlFlag" value="REQUIRED"/>
</serviceInstance>

The following sections explain the use of this module in Java SE applications:

Using the Identity Store Login Module for Authentication

This section describes the use of the Identity Store login module for basic user name and password authentication.

The following example illustrates how to configure the appName context:

<jpsContext name="appName">
   <serviceInstanceRef ref="jaaslm.idstore1"/>
</jpsContext>

<serviceProvider type="JAAS_LM" name="jaaslm.idstore" 
      class="oracle.security.jps.internal.jaas.module.idstore.IdStoreLoginModule">
   <description>Identity Store-based LoginModule
   </description>
</serviceProvider>

<serviceInstance name="jaaslm.idstore1" provider="jaaslm.idstore">
   <property name="jaas.login.controlFlag" value="REQUIRED"/>
   <property name="debug" value="true"/>
   <property name="addAllRoles" value="true"/>
</serviceInstance>

The following example illustrates a callback that handles the name and password:

import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.callback.*;
import java.io.IOException; 
Subject sub = new Subject();
CallbackHandler cbh = new YourCallbackHandler();
LoginContext context = new LoginContext(appName, subject,  cbh);
context.login();
public class SampleCallbackHandler implements CallbackHandler {
//For name/password callbacks
private String name = null;private char[] password = null; 
public SampleCallbackHandler(String name, char[] pwd) { 
   if (name == null || name.length() == 0 )         
      throw new IllegalArgumentException("Invalid name ");
   else 
      this.name = name; 
   if (pwd == null || pwd.length == 0)
      throw new IllegalArgumentException("Invalid password ");
   else
      this.password = pwd;
}
public String getName() {
   return name;
   } public char[] getPassword()  {
   return password;
 }    
public void handle(Callback[] callbacks) 
   throws IOException, UnsupportedCallbackException {
   if (callbacks != null && callbacks.length > 0) {
      for (Callback c : callbacks) {
      if (c instanceof NameCallback) {
            ((NameCallback) c).setName(name);
            } 
   else 
      if (c instanceof PasswordCallback) {
         ((PasswordCallback) c).setPassword(password);
              }           
   else {
      throw new UnsupportedCallbackException(c);
 }
          }
      }
  }
}

Using the Identity Store Login Module for Assertion

To use the Identity Store login module for assertion, provide a permission to execute the protected setIdentity method, and implement the callback handler that uses the oracle.security.jps.callback.IdentityCallback class.

The following example illustrates a configuration that allows the MyApp application permission to execute protected methods in the assertion login module:

<grant>
  <grantee>
    <codesource>
      <url>file:${soa.oracle.home}/application/myApp.ear</url>
		      <--! soa.oracle.home is a system property set when 
      the server JVM is started -->
    </codesource>
  </grantee>
  <permissions>
    <permission>
      <class>oracle.security.jps.JpsPermission</class>
      <name>IdentityAssertion</name>
    </permission>t
  </permissions>
</grant>

The following example illustrates the configuration that allows the jdoe user permission to execute the assertion login module:

<grant>
  <grantee>
    <principals>
      <principal>
        <class>weblogic.security.principal.WLSUserImpl</class>
        <name>jdoe</name>
      </principal>
    </principals>
  </grantee>
  <permissions>
    <permission>
      <class>oracle.security.jps.JpsPermission</class>
      <name>IdentityAssertion</name>
    </permission>
  </permissions>
</grant>

The following example illustrates an implementation of the callback handler:

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import oracle.security.jps.callback.IdentityCallback;
public class CustomCallbackHandler implements CallbackHandler {
    private String name = null;
    private char[] password;
    public CustomCallbackHandler(String name) {
        this.name = name;
    }
    public CustomCallbackHandler(String name, char[] password) {
      this.name  = name;
      this.password = password;
    }
    public void handle(Callback[] callbacks) throws IOException,
                                                    UnsupportedCallbackException {
        for (Callback callback : callbacks) {
            if (callback instanceof NameCallback) {
              NameCallback nc = (NameCallback) callback;
              nc.setName(name);
            }
            else if (callback instanceof PasswordCallback) {
              PasswordCallback pc = (PasswordCallback) callback;
              pc.setPassword(password);
            }
            else if (callback instanceof IdentityCallback) {
                IdentityCallback idcb = (IdentityCallback)callback;
                idcb.setIdentity(name);
                idcb.setIdentityAsserted(true);
                idcb.setAuthenticationType("CUSTOM");
            } else {
                //throw exception
                throw new UnsupportedCallbackException(callback);
            }
        }
    }
}

The following example illustrates the implementation of a login module:

import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginContext;
 
import oracle.security.jps.service.JpsServiceLocator;
import oracle.security.jps.service.login.LoginService;
 
public class LoginModuleExample {
    private static final String CONTEXT_NAME = "JSE_UserAuthnAssertion";
 
    public LoginModuleExample() {
        super();
    }
 
    public Subject assertUser(final String username) throws Exception {
        CallbackHandler cbh =
            AccessController.doPrivileged(new PrivilegedExceptionAction<CallbackHandler>() {
                public CallbackHandler run() throws Exception {
                    return new CustomCallbackHandler(username);
                }
            });
        Subject sub = new Subject();
        LoginService ls =
            JpsServiceLocator.getServiceLocator().lookup(LoginService.class);
        LoginContext context = ls.getLoginContext(sub, cbh);
 
        context.login();
        Subject s = context.getSubject();
 
        return s;
    }
 
    public Subject authenticate(final String username, final char[] password) throws Exception {
        CallbackHandler cbh = new CustomCallbackHandler(username, password);
        Subject sub = new Subject();
        LoginService ls =
            JpsServiceLocator.getServiceLocator().lookup(LoginService.class);
        LoginContext context = ls.getLoginContext(sub, cbh);
 
        context.login();
        Subject s = context.getSubject();
 
        return s;
    }
 
    public static void main(String[] args) {
        LoginModuleExample loginModuleExample = new LoginModuleExample();
        try {
            System.out.println("authenticated user subject = " + 
                               loginModuleExample.authenticate("testUser", 
 "password".toCharArray()));
            System.out.println("asserted user subject = " +
                               loginModuleExample.assertUser("testUser"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
The Asserted User

Applications often must execute actions as run-as operations. OPSS allows you to use the subjects of an asserted user to execute application logic as if it were executed by that user.

The following sections explains how to use the OPSS SubjectSecurity class to implement run-as operations:

The SubjectSecurity Class

Here are several scenarios where you use this class:

  • UC1 - A scheduler allows submitting and executing jobs. These jobs are submitted at one time and executed at some future time, therefore the need to assert the user's identity and execute the scheduled job in the user's context.

  • UC2 - A scheduled job is executed by an entity bean that calls other entity beans to complete the job, and all the code to complete the job must execute in the user's context. Therefore this context must be propagated through the call path, across entity beans.

  • UC3 - The permissions to execute a scheduled job are based on the user's application roles. In this case, the user's context must be aware of the application roles granted to the user regardless of the code path across entity beans.

  • UC4 - When an unauthenticated user submits a job, the job metadata must persist the anonymous user. Eventually, the job must be executed by the anonymous user.

  • UC5 - An MBean running in an application is called from a UI via an MBean server. The MBean operation call a series of diagnostic tests that must be run as a particular user.

  • UC6 - An identity has been asserted and the assertion has produced a user context that can be used to run operations as that user.

Programming Guidelines and Recommendations

The SubjectSecurity class allows you to execute code either when a precomputed subject is available, or when the user must first be asserted. If the application context has not been set, then before you use the SubjectSecurity class, set its ID:

AppSecurityContext.setApplicationID(applicationID)

If you have set the application context, then the call to setApplicationID is optional.

When programming with the SubjectSecurity class:

  • Use SubjectSecurity.getActionExecutor(subject) if you have already obtained a subject and want to execute some operation with it.

    • If you obtained the subject with the SubjectUtil.getCurrentSubject method, then that subject works with the container security and OPSS, and application roles are considered.

    • If you obtained the subject programmatically using the JpsLoginModuleFactory class, then that subject works with the container security and OPSS.

  • Use SubjectSecurity.getActionExecutor(userName) if just the user name is available and want to execute some operation as that user. To use this method, provide a codesource permission like the following:

    <grant>
        <grantee>
            <codesource>
               <url>file:${domain.home}/servers/${weblogic.Name}/myApp.ear/-</url>
            </codesource>
        </grantee>
        <permissions>
            <permission>
                <class>oracle.security.jps.JpsPermission</class>
                <name>IdentityAssertion</name>
                <actions>execute</actions>
            </permission>
        </permissions>
    </grant>
    

    where url specifies the location of the code where the method is called.

  • Note that ActionExecutor.execute(PrivilegedAction) calls Subject.doAs with the subject and the application's PrivilegedAction.

  • Use SubjectSecurity.executeAs(Subject subject, PrivilegedAction<T> action) to execute the action immediately.

  • Use SubjectSecurity.executeAs(Subject subject, PrivilegedExceptionAction<T> action) to execute the action immediately. This method obtains the action executor using the getActionExecutor method, and executes the action.

For information about the oracle.security.jps.runtime.SubjectSecurity class and the oracle.security.jps.runtime.ActionExecutor interface, see Java API Reference for Oracle Platform Security Services.

Using SubjectSecurity

The following example illustrates how to use the SubjectSecurity class to run as the asserted jdoe user:

// get a SubjectSecurity instance
        final SubjectSecurity subjectSecurity = SubjectSecurity.getInstance();
        String username = "jdoe";
// create ActionExecutor with subjectSecurity getActionExecutor(String username)
        ActionExecutor executor =
        AccessController.doPrivileged(new PrivilegedExceptionAction<ActionExecutor>() {
            public ActionExecutor run() throws AssertionException {
                    return subjectSecurity.getActionExecutor(username);
            }
        }, null);
// When OPSS subjects are available,
// create ActionExecutor with SubjectSecurity getActionExecutor(Subject subject)
        Subject opssSubject = SubjectUtil.getCurrentSubject();
        ActionExecutor ececutor = subjectSecurity.getActionExecutor(opssSubject);
 //run privilegedAction
        PrivilegedAction action = new MyPrivilegedAction();
        executor.execute(action);
 //run PrivilegedExceptionAction
        PrivilegedExceptionAction exceptionAction = new MyPrivilegedExceptionAction();
        try {
            executor.execute(exceptionAction);
        } catch (PrivilegedActionException e) {
            // handle PrivilegedActionException
        }

Using the Login Modules in Java SE Applications

To call a login module in Java SE applications, use the getLoginContext method of the oracle.security.jps.service.login.LoginService interface.

Similar to the LoginContext method in the standard Java Authorization and Authentication Services (JAAS) API, the getLoginContext method returns a LoginContext object instance that you use to authenticate a user, but, more generally, it allows you to use any number of login modules and in any order. Authentication is performed on just those login modules and in the order you passed them.

The following example illustrates user authentication against a subset of login modules with the getLoginContext method:

import oracle.security.jps.service.ServiceLocator;
import oracle.security.jps.service.JpsServiceLocator;
import oracle.security.jps.service.login.LoginService;

//Obtain the login service
ServiceLocator locator = JpsServiceLocator.getServiceLocator();
LoginService loginService = locator.lookup(LoginService.class);

//Create the handler for given name and password
CallbackHandler cbh = new MyCallbackHandler("name", "password".toCharArray());

//Invoke login modules selectively in a given order
selectiveModules = new String[]{"lmName1", "lmName2", "lmName3"};
LoginContext ctx = loginService.getLoginContext(new Subject(), cbh, selectiveModules);
ctx.login();
Subject s = ctx.getSubject();

selectiveModules is an array of login module names, and the authentication uses these login modules in the order listed in the array. Each login module in the array is listed in the default context in the jps-config-jse.xml file.

The following example illustrates the configuration of a stack of two login modules:

<serviceProvider type="LOGIN" name="jaas.login.provider" class="oracle.security.jps.internal.login.jaas.JaasLoginServiceProvider">
   <description>Common definition for any login module instances</description>
</serviceProvider>

<serviceInstance name="auth.loginmodule" provider="jaas.login.provider">
   <description>User Authentication Login Module</description>
   <property name="loginModuleClassName" value="oracle.security.jps.internal.jaas.module.authentication.JpsUserAuthenticationLoginModule"/>
   <property name="jaas.login.controlFlag" value="REQUIRED"/>
</serviceInstance>
 
<serviceInstance name="custom.loginmodule" provider="jaas.login.provider">
   <description>My Custom Login Module</description>
   <property name="loginModuleClassName" value="my.custom.MyLoginModuleClass"/>
   <property name="jaas.login.controlFlag" value="REQUIRED"/>
</serviceInstance>
 
<jpsContexts default="aJpsContext">
   <jpsContext name="aJpsContext">
     <serviceInstanceRef ref="auth.loginmodule"/>
     <serviceInstanceRef ref="custom.loginmodule"/>
   </jpsContext>
</jpsContexts>

Authorization in Java SE Applications

Use a file, LDAP, or database-based security store in your Java SE applications and configure all services in the jps-config-jse.xml file. In this file, you also set system properties appropriate to your applications.

The following sections describe the configuration of policy and credential stores:

Configuring Policy and Credential File Stores

A file policy store is specified in the system-jazn-data.xml file. A file credential store is specified in the cwallet.sso file.

The following example illustrates policy and credential configurations:

<serviceProviders>
  <serviceProvider type="CREDENTIAL_STORE" name="credstoressp"
  	class="oracle.security.jps.internal.credstore.ssp.SspCredentialStoreProvider">
    <description>SecretStore-based CSF Provider</description>
  </serviceProvider>
  <serviceProvider type="POLICY_STORE" name="policystore.xml.provider"
	class="oracle.security.jps.internal.policystore.xml.XmlPolicyStoreProvider">
  <description>XML-based PolicyStore Provider</description>
  </serviceProvider>
</serviceProviders>

<serviceInstances>
  <serviceInstance name="credstore" provider="credstoressp" location="./">
    <description>File Credential Store Instance</description>
  </serviceInstance>
 
  <serviceInstance name="policystore.xml" provider="policystore.xml.provider" location="./system-jazn-data.xml">
   <description>File Policy Store Service Instance</description>
   <property name="oracle.security.jps.policy.principal.cache.key" value="false"/>
  </serviceInstance>
</serviceInstances>

<jpsContexts default="TestJSE">
  <jpsContext name="TestJSE">
	    <serviceInstanceRef ref="credstore"/>
	    <serviceInstanceRef ref="policystore.xml"/>
    ...
  </jpsContext>
</jpsContexts>

Note that setting the oracle.security.jps.policy.principal.cache.key property to false in the policy store instance is required.

See also:

Using File Credential Stores

modifyBootStrapCredential and addBootStrapCredential in WLST Command Reference for Infrastructure Security

Configuring Policy and Credential LDAP Stores

The examples in this section assume that the domain uses an LDAP store.

The following example illustrate the configurations of providers, instances, and context for a Java SE application:

<serviceProviders
  <serviceProvider type="POLICY_STORE" mame="ldap.policystore.provider"
 class=oracle.security.jps.internal.policystore.ldap.LdapPolicyStoreProvider"/>
  <serviceProvider type="CREDENTIAL_STORE" mame="ldap.credential.provider"
 class=oracle.security.jps.internal.credstore.ldap.LdapCredentialStoreProvider"/>
</serviceProviders>

<serviceInstances>
 <serviceInstance provider="ldap.policystore.provider" name="policystore.ldap">
  <property value="OID" name="policystore.type"/>
  <property value="bootstrap" name="bootstrap.security.principal.key"/>
  <property value="cn=PS1domainRC3" name="oracle.security.jps.farm.name"/>
  <property value="cn=myTestNode" name="oracle.security.jps.ldap.root.name"/>
  <property value="ldap://myComp.com:1234" name="ldap.url"/>
 </serviceInstance>

 <serviceInstance provider="ldap.credential.provider" name="credstore.ldap">
  <property value="bootstrap" name="bootstrap.security.principal.key"/>
  <property value="cn=PS1domainRC3" name="oracle.security.jps.farm.name"/>
  <property value="cn=myTestNode" name="oracle.security.jps.ldap.root.name"/>
  <property value="ldap://myComp.com:1234" name="ldap.url"/>
 </serviceInstance>
</serviceInstances>
<serviceInstance location="./bootstrap" provider="credstoressp" name="bootstrap.cred">
  <property value="./bootstrap" name="location"/>
</serviceInstance>
<jpsContexts default="TestJSE">
  <jpsContext name="TestJSE">
    <serviceInstanceRef ref="policystore.ldap"/>
    <serviceInstanceRef ref="credstore.ldap"/>
  </jpsContext>
  <jpsContext name="bootstrap_credstore_context">
    <serviceInstanceRef ref="bootstrap.cred"/>  
  </jpsContext>
</jpsContexts>

The following example illustrates how to obtain programmatically a reference to the security store and assumes that you have set the oracle.security.jps.config system property to the location of the jps-config-jse.xml file:

String contextName="TestJSE";
public static PolicyStore getPolicyStore(String contextName) {
      try-block    
            JpsContextFactory ctxFact;  
            ctxFact = JpsContextFactory.getContextFactory();   
            JpsContext ctx = ctxFact.getContext(contextName);  
            return ctx.getServiceInstance(PolicyStore.class);      
      catch-block ...

Configuring Database-Based Security Stores

This sections presents configuration examples of database-based policy, credential, and keystores in the jps-config-jse.xml file. Note the points about the following example:

  • The value of the jdbc.url property should be identical to the name of the Java Database Connectivity (JDBC) data source entered when you created the data source.

  • The values of the bootstrap credentials (map and key) must match those you passed to the addBootStrapCredential WebLogic Scripting Tool (WLST) command when you created the bootstrap credential.

<jpsConfig  …>
  <propertySets>
   <propertySet name="props.db.1">
    <property value="cn=myDomain" name="oracle.security.jps.farm.name"/>
    <property value="DB_ORACLE" name="server.type"/>
    <property value="cn=myRoot" name="oracle.security.jps.ldap.root.name"/>
    <property name="jdbc.url" value="jdbc:oracle:thin:@myhost.com:1521/srv_name"/>
    <property name="jdbc.driver" value="oracle.jdbc.driver.OracleDriver"/>
    <property name="bootstrap.security.principal.key" value="myKeyName" />
    <property name="bootstrap.security.principal.map" value="myMapName" />
   </propertySet> 
  </propertySets>

  <serviceProviders>
    <serviceProvider class="oracle.security.jps.internal.policystore.OPSSPolicyStoreProvider"
           type="POLICY_STORE" name="policy.rdbms">
      <description>DBMS based PolicyStore</description>
    </serviceProvider>
    <serviceProvider class="oracle.security.jps.internal.credstore.rdbms.DbmsCredentialStoreProvider"
               type="CREDENTIAL_STORE" name="db.credentialstore.provider" >
  <serviceProvider class="oracle.security.jps.internal.keystore.KeyStoreProvider" 
               type="KEY_STORE" name="keystore.provider" >
    <property name="provider.property.name" value="owsm"/>
  </serviceProvider>
 </serviceProviders>
 
 <serviceInstances>
   <serviceInstance name="policystore.rdbms" provider="db.policystore.provider">  
    <propertySetRef ref = "props.db.1"/>
    <property name="policystore.type"  value="DB_ORACLE"/>
   </serviceInstance>
   <serviceInstance name="credstore.rdbms" provider="db.credstore.provider">
    <propertySetRef ref = "props.db.1"/>  
   </serviceInstance>
   <serviceInstance name="keystore.rdbms" provider="db.keystore.provider">  
    <propertySetRef ref = "props.db.1"/> 
    <property name="keystore.provider.type"  value="db"/>
   </serviceInstance>
  </serviceInstances>
 
  <jpsContexts default="default">
    <jpsContext name="default">
      <serviceInstanceRef ref="policystore.rdbms"/>      
      <serviceInstanceRef ref="credstore.rdbms"/>
      <serviceInstanceRef ref="keystore.rdbms"/>
    </jpsContext>
  </jpsContexts>
</jpsConfig>

File Store Unsupported Methods

The file store does not support methods that involve cascading deletions. It supports only simple queries.

The following example illustrates a simple query that returns of all permissions with a display name matching MyDisplayName:

PermissionSetSearchQuery query = new PermissionSetSearchQuery();
query.addQuery(PermissionSetSearchQuery.SEARCH_PROPERTY.DISPLAY_NAME,
               false,
               ComparatorType.EQUALITY,
               "MyDisplayName",
               BaseSearchQuery.MATCHER.EXACT);
getPermissionSets(query);

Cascading deletions relates to any method whose signature includes the Boolean cascadeDelete argument. The only value allowed in case of a file store is false.

Audit in Java SE Applications

The following sections explain how to use Oracle Platform Security Services Common Audit Framework to audit events in Java SE applications and some common audit usage scenarios:

About Audit in Java SE Applications

In Java SE applications, the audit configuration is specified in the jps-config-jse.xml file:

<serviceInstance provider="audit.provider" name="audit">
 <property value="Medium" name="audit.filterPreset"/>
 <property value="0" name="audit.maxDirSize"/>
 <property value="104857600" name="audit.maxFileSize"/>
 <property value="" name="audit.specialUsers"/>
 <property value="" name="audit.customEvents"/>
 <property value="Db" name="audit.loader.repositoryType"/>
 <property value="file" name="auditstore.type"/>
</serviceInstance>

Audit lets your application capture specific runtime events that are recorded in bus-stop files. The audit loader periodically moves data from bus-stop files to the audit store.

Configuring the Audit Bus-Stop Directory

The bus-stop file names follow the format host_pid_audit_major_minor.log, as in sample.myhost.com_12345_audit_1_0.log. Note that the host name, the process ID, and the version number are embedded in the file name.

Your Java SE application must use a writable directory to which the service writes audit bus-stop files. To specify this location, set the audit.logDirectory property with the setAuditRepository WLST command, or set the opss.audit.logDirectory system property. If the runtime process is unable to determine a writable directory, then audit may not work.

Java SE applications can share the bus-stop directory if you set it with the audit.logDirectory property and all the Java SE applications in the environment use the same jps-config-jse.xml file, or the same value is passed as a system property to all Java SE applications.

See also:

setAuditRepository in WLST Command Reference for Infrastructure Security

Configuring Audit Loaders

The audit loader is a process that moves audit data from bus-stop files to a database. The audit.loader.repositoryType system property must be set in Java EE and SE applications. By default, it is set to database.

Java SE applications can use two kinds of loaders:

  • The audit loader, a thread started by runtime audit. Ready-to-use, the audit loader is disabled; to enable it, set audit.loader.enable=true.

  • The standalone audit loader for Java SE applications, which Oracle recommends, especially if you are using a shared directory.

Common Audit Scenarios in Java SE Applications

The following sections describe common scenarios that implement audit in Java SE applications. We consider environments with and without a collocated WebLogic Server. A collocated environment is a WebLogic Server domain where Java Required Files (JRF) are installed.

Configuring Audit with a Collocated WebLogic Server

To set audit in your the domain:

  1. Set up the audit loader repository with Fusion Middleware Control or use the setAuditRepository WLST command:
    # logDirectory is the location of the audit log directory   
    # jdbcSring is the connect string
    # user and pass refer to the IAU append schema user and password  
    # (These get stored in bootstrap credential store)
     
    setAuditRepository(switchToDB = "true",dataSourceName = "jdbc/AuditDB",interval = "20", timezone="utc", logDirectory="/foo/bar", jdbcString="jdbc:oracle:thin:@host:1521:sid", dbUser="test_iau_append", dbPassword="password");
    

    The command updates the jps-config.xml and jps-config-jse.xml files. A standalone audit loader is not needed if the writable audit directory for Java SE applications is the same directory as the log directory for WebLogic Server.

  2. If you choose to have a separate writable audit directory for Java SE applications, then start the standalone audit loader and use a system properties, such as oracle.instance, to set the value of the bus-stop directory:
    $JAVA_HOME/bin/java 
    -classpath $COMMON_COMPONENTS_HOME/modules/oracle.jps_12.2.1/jps-manifest.jar:
    $COMMON_COMPONENTS_HOME/modules/oracle.jdbc_12.2.1/ojdbc6dms.jar:
    $COMMON_COMPONENTS_HOME/modules/oracle.iau_12.2.1./jps-manifest.jar
    -Doracle.instance=$ORACLE_INST 
    -Doracle.security.jps.config=path_to_jps-config-jse.xml
    oracle.security.audit.ajl.loader.StandaloneAuditLoader
Configuring Audit Without a Collocated WebLogic Server

The following task assumes that a middleware home is available but no WebLogic Server is running, so neither Fusion Middleware Control nor the setAuditRepository WLST command is available.

To set up audit in this case:

  1. Specify the bus-stop directory with the opss.audit.logDirectory or oracle.instance system properties. Ready-to-use, audit is enabled in Java SE applications if you provide a writable directory to the Java Virtual Machine (JVM).
  2. Use the addBootStrapCredential WLST command to add the bootstrap credential to the bootstrap credential store:
    addBootStrapCredential(jpsConfigFile='../../../user_projects/domains/base_domain/config/fmwconfig/jps-config-jse.xml', map='AuditDbPrincipalMap', key='AuditDbPrincipalMap', username='TEST_IAU_APPEND', password='password')
    
  3. Add the audit.loader.jdbcString property to the audit configuration in the jps-config-jse.xml file with a value such as audit.loader.jdbcString=jdbc:oracle:thin:@host:1521:sid
  4. If several Java SE applications share an audit directory, then start the standalone audit loader to move records to the database.
  5. If every Java SE application writes to its own audit directory, then enable the runtime service's audit loader by specifying audit.loader.enable=true.

    Otherwise, if the audit directory is shared, then start the standalone audit loader.