Oracle8i Enterprise JavaBeans and CORBA Developer's Guide
Release 2 (8.1.6)

A81356-01

Library

Product

Contents

Index

Prev  Chap Top Next

Session Management

In the simple cases, a client starts a new server session implicitly when it activates a server object, such as an EJB or a CORBA server object. But Oracle8i also gives you the ability to control session start-up explicitly, either from the client or from a server object.

Starting a New Session

In general, when you look up a published object using the URL notation and you specify a hostname and port, then the object is activated in a new session. For example when an activated CORBA server object or an EJB looks up a second server object, using the same series of statements as the first client would use:

Hashtable env = new Hashtable();
env.put(Context.URL_PKG_PREFIXES, "oracle.aurora.jndi");
env.put(Context.SECURITY_PRINCIPAL, "scott");
env.put(Context.SECURITY_CREDENTIALS, "tiger");
env.put(Context.SECURITY_AUTHENTICATION, ServiceCtx.NON_SSL_LOGIN);
Context ic = new InitialContext(env);
SomeObject myObj =
   (SomeObject) ic.lookup("sess_iiop://localhost:5521:ORCL/test/someobject");

then the object myObj is activated in a separate session from the session in which the server object that did the lookup is running.

Using thisServer

If the server object must look up and activate a new published object in the same session in which it is running, then the server object should use the thisServer/:thisSession notation in place of the hostname:port:SID in the URL. For example, to look up and activate an object in the same session, do the following:

Hashtable env = new Hashtable();
env.put(Context.URL_PKG_PREFIXES, "oracle.aurora.jndi");
Context ic = new InitialContext(env);
SomeObject myObj =
   (SomeObject) 
ic.lookup("sess_iiop://thisServer/:thisSession/test/someobject");

In this case, myObj is activated in the same session in which the invoking object is running. Note that there is no need to supply login authentication information, as the client (a server object in this case) is already authenticated to Oracle8i.

Realize that objects are not authenticated, instead, clients must be authenticated to a session. However, when a separate session is to be started, then some form of authentication must be done--either login or SSL credential authentication.


Note:

You can only use the thisServer notation on the server side, that is, from server objects. You cannot use it in a client program.  


Starting a Named Session From a Client

In the simple case, you let the JNDI initial context lookup() method also start the session and authenticate the client. The session then becomes the default session (and has the name :default).

If you then create additional objects in the client and activate them, the new objects run in the same session. Even if you create a new JNDI initial context and look up the same or a new object using that context, the object is instantiated in the same session as the first object.

There are cases, however, when a client needs to activate an object in a separate session from any current objects. Do this as follows:

The following is a more detailed code example that demonstrates this technique. The complete example is in "twosessions".

Hashtable env = new Hashtable ();
env.put (Context.URL_PKG_PREFIXES, "oracle.aurora.jndi");
Context ic = new InitialContext (env);

// Get a SessionCtx that represents a database instance
ServiceCtx service = (ServiceCtx) ic.lookup ("sess_iiop://localhost:2481:ORCL");

// Create and authenticate a first session in the instance.  
SessionCtx session1 = (SessionCtx) service.createSubcontext (":session1");

// Authenticate
session1.login("scott", "tiger", null);

// Create and authenticate a second session in the instance.  
SessionCtx session2 = (SessionCtx) service.createSubcontext (":session2");

// Authenticate using a login object (not required, just shown for example).
LoginServer login_server2 = (LoginServer)session2.activate ("etc/login");
Login login2 = new Login (login_server2);
login2.authenticate ("scott", "tiger", null);

// Activate one Hello object in each session
Hello hello1 = (Hello)session1.activate (objectName);
Hello hello2 = (Hello)session2.activate (objectName);

// Verify that the objects are indeed different
hello1.setMessage ("Hello from Session1");
hello2.setMessage ("Hello from Session2");

System.out.println (hello1.helloWorld ());
System.out.println (hello2.helloWorld ());

Closing a Session

You can release objects that you have instantiated in a session by sending a _release() message to them. For example, if you previously activated an object named bank, then invoking bank._release() deactivates the bank object.

When the last object activated in a session is released, the connection is closed.

You can also invoke orb.shutdown() from a client program. This method releases all objects and connections from the client.

Example: Activating Services and Sessions

This section describes in greater detail how you can explicitly activate a session IIOP service and then activate one or more Oracle8i sessions in the context of the service. The simplest way to activate services and sessions is to use the JNDI methods provided in the ServiceCtx and SessionCtx classes.

This section demonstrates service and session activation, as well as explicit login authentication, by way of a useful example: lister.java. This program recursively lists the names of all published objects in the session name space, along with the creation dates and owners.

Unlike most of the other example programs in this guide, the lister program does not start by activating a published object. In the other example programs, the service and session are usually started automatically, as a by-product of the published object look up. In this example the service and session must be specifically activated by the client program.

The example starts by instantiating a new hashtable for the environment properties to be passed to the server:

    Hashtable env = new Hashtable();
    env.put(Context.URL_PKG_PREFIXES, "oracle.aurora.jndi");
Note that only the URL_PKG_PREFIXES Context variable is filled in--the other information will be provided in the login.authenticate() method parameters.

Next, create a new JNDI Context. This is the necessary first step in all programs that will use JNDI methods. Pass in the hashtable, as usual.

    Context ic = new InitialContext(env);
Then use the JNDI lookup() method on the initial context, passing in the service URL, to establish a service context. This example uses a service URL with the service prefix, hostname, listener port, and SID:
    ServiceCtx service =
        (ServiceCtx) ic.lookup("sess_iiop://localhost:2481:ORCL");

The next step is to initiate a session. Do this by invoking the createSubcontext() method on the service context object, as follows:

    SessionCtx session = (SessionCtx) service.createSubcontext(":session1");

Note that you must name a new session when you create it. The session name must start with a colon (:), and cannot contain a slash ('/'), but is not otherwise restricted.

The final step before you can access the published object tables is to authenticate the client program to the database. Do this by calling the login() method on the session context object:

   session.login("scott", "tiger", null);    // role is null

Finally, the example starts listing by calling the listOneDirectory() static method, which recursively lists all directories (PublishingContexts) and leafs (PublishedObjects) in the published names hierarchy:

    listOneDirectory ("/", session);

The complete code for the example is reproduced in the following section. The code includes some minimal formatting to align the printed output. Follow the same procedures as for the sample applications in Appendix A, "Example Code: CORBA" to compile and run this example.

Lister.java

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingEnumeration;
import javax.naming.Binding;
import javax.naming.NamingException;
import javax.naming.CommunicationException;

import oracle.aurora.jndi.sess_iiop.ServiceCtx;
import oracle.aurora.jndi.sess_iiop.SessionCtx;
import oracle.aurora.jndi.sess_iiop.ActivationException;
import oracle.aurora.AuroraServices.PublishedObject;
import oracle.aurora.AuroraServices.objAttribsHolder;
import oracle.aurora.AuroraServices.objAttribs;
import oracle.aurora.AuroraServices.ctxAttribs;
import oracle.aurora.jts.client.AuroraTransactionService;
import oracle.aurora.AuroraServices.LoginServer;
import oracle.aurora.client.Login;

import javax.naming.Context;
import javax.naming.InitialContext;
import java.util.Hashtable;

public class Lister {

  public static void main (String[] args) throws Exception {
    if (args.length != 3) {
      System.out.println("usage: Lister serviceURL user password");
      System.exit(1);
    }
    String serviceURL = args [0];
    String username = args [1];
    String password = args [2];

    // Prepare a simplified Initial Context as we are going to do
    // everything by hand.
    Hashtable env = new Hashtable();
    env.put(Context.URL_PKG_PREFIXES, "oracle.aurora.jndi");
    Context ic = new InitialContext(env);

    // Get a SessionCtx that represents a database instance.
    ServiceCtx service = (ServiceCtx) ic.lookup(serviceURL);

    // Create a session in the instance.
    // The session name must start with a colon(:).
    SessionCtx session = (SessionCtx) service.createSubcontext(":session1");
    session.login(username, password, null);

    // Print a header line.
    System.out.println
      ("\n\nName                          Create Date              Owner");
    listOneDirectory ("/", session);
  }


  public static void listOneDirectory (String name, SessionCtx ctx)
       throws Exception  {
    System.out.print(name);
    for (int i = name.length(); i < 30; i++)
      System.out.print(" ");
    ctxAttribs attribs = null;
    try {
      attribs = ctx.getAttributes();
    } catch (org.omg.CORBA.NO_PERMISSION e) {
      return;
    }

    System.out.print(attribs.creation_ts);
    for (int i = 30 + attribs.creation_ts.length(); i < 55; i++)
      System.out.print(" ");
    System.out.print(attribs.owner);

    /*
     * You could also add output for the access permissions:
     *  attribs.read
     *  attribs.write
     *  attribs.execute
     */

    System.out.println();

    // Show the sub entries
    listEntries(ctx, name);
  }

  public static void listEntries (Context context, String prefix)
       throws Exception  {
    NamingEnumeration bindings = context.list("");
    while (bindings.hasMore()){
      Binding binding = (Binding) bindings.next();
      String name = binding.getName();
      Object object = context.lookup(name);
      if (object instanceof SessionCtx)
        listOneDirectory(prefix + name + "/", (SessionCtx) object);
      else if (object instanceof PublishedObject)
        listOneObject(prefix + name, (PublishedObject) object);
      else
        // We should never get here.
        System.out.println(prefix + name + ": " + object.getClass());
    }
  }


  public static void listOneObject (String name, PublishedObject obj)
       throws Exception  {
    objAttribsHolder holder = new objAttribsHolder();
    try {
      obj.get_attributes(holder);
    } catch (org.omg.CORBA.NO_PERMISSION e) {
      return;
    }

    objAttribs attribs = holder.value;
    System.out.print(name);
    for (int i = name.length(); i < 30; i++)
      System.out.print(" ");

    System.out.print(attribs.creation_ts);
    for (int i = 30 + attribs.creation_ts.length(); i < 55; i++)
      System.out.print(" ");
    System.out.print(attribs.owner);

    /*
     * You could also add output for:
     *  attribs.class_name
     *  attribs.schema
     *  attribs.helper
     * and the access permissions:
     *  attribs.read
     *  attribs.write
     *  attribs.execute
     */

    System.out.println();
  }
}

Starting a New Session From a Server Object

Starting a new session from a CORBA server object or from an EJB is identical to starting a session from an application client. You can start the session implicitly by using lookup() on an initial context to look up and activate another published object, or you can start a new service context, and from that a new session, just as "Starting a Named Session From a Client" shows.

Hashtable env = new Hashtable ();
env.put (Context.URL_PKG_PREFIXES, "oracle.aurora.jndi");
Context ic = new InitialContext (env);
employee =
  (Employee)ic.lookup ("sess_iiop://thisServer/test/myEmployee");

Any new session connection must always authenticate itself to the database server. See "clientserverserver" for an example that starts a new session from a CORBA server object.

If you need to activate a new object in the same session from another server object, use the thisServer indicator. See "Using thisServer" for more information.

Controlling Session Duration

A session normally ends when the last client connection terminates. However, a server object can control the session duration by using the oracle.aurora.net.Presentation.sessionTimeout() method. The method takes one parameter; the session timeout value in seconds. The session timeout clock starts ticking when the last client request completes. For example:

int timeoutValue = 30;
...
// set the timeout to 30 seconds
oracle.aurora.net.Presentation.sessionTimeout(timeoutValue);
...
// set the timeout to a very long time
oracle.aurora.net.Presentation.sessionTimout(Integer.MAX_INT);

See the example "timeout" for an example that sets session timeout on the server side.


Note:

When you use the sessionTimeout() method, you must add $(ORACLE_HOME)/javavm/lib/aurora.zip to your CLASSPATH.  


Ending a Session

To terminate a database session, use the exitSession() method. For example,

oracle.aurora.vm.OracleRuntime.exitSession(1);

The int parameter for exitSession(int x) is an exit value, similar to the value supplied for System.exit().


Note:

System.exit() does not terminate a database session.  


IIOP Security

As discussed in the Oracle8i Java Developer's Guide, there are several security issues you must think about for your application. The Oracle8i Java Developer's Guide divides security into network connection, database contents, and JVM security issues. All these issues are pertain to IIOP. However, IIOP has specific implementation issues for both the networking and the JVM security, as listed below:

This section describes fully the network connection security issues that IIOP applications must consider.

Data Integrity

Do you want your transport line to be encrypted? Do you want data integrity and confidentiality? If you believe that the physical connection can be tampered with, you can consider encrypting all transmissions by using the secure socket layer (SSL) encryption technology. However, because adding encryption to your transmission affects your connection performance, if you do not have any transport security issues, you should transmit unencrypted.

Figure 4-8 Data Integrity Decision Tree


Using the Secure Socket Layer

JServer's CORBA and EJB implementations rely on the Secure Socket Layer (SSL) for data integrity and authentication. SSL is a secure networking protocol, originally defined by Netscape Communications, Inc. Oracle8i JServer supports SSL over the IIOP protocol used for the ORB.

When a connection is requested between a client and the server, the SSL layer within both parties negotiate during the connection handshake to verify if the connection is allowed. The connection is verified at several levels:

  1. The SSL version on both the client and the server must agree for the transport to be guaranteed for data integrity.

  2. If server-side authentication with certificates is requested, the certificates provided by the server are verified by the client at the SSL layer. This means that the server is guaranteed to be itself. That is, it is not a third party pretending to be the server.

  3. If client-side authentication with certificates is requested, the certificates provided by the client are verified at the SSL layer. The server receives the client's certificates for authentication or authorization of the client.


    Note:

    Normally, client-side authentication means only that the server verifies that the client is not an impersonator and is trusted. However, when you specify SSL_CLIENT_AUTH in JServer, you are requesting both server-side and client-side authentication.  


The SSL layer performs authentication between the peers. After the handshake, you can be assured that the peers are authenticated to be who they say they are. You can perform additional tests on their certificate chain to authorize that this user can access your application. See "Authorization" on how to go beyond authentication.


Note:

If you decide to use SSL, your client must import the following JAR files:

  • If your client uses JDK 1.1, import jssl-1_1.jar and javax-ssl-1_1.jar.

  • If your client uses Java 2, import jssl-1_2.jar and javax-ssl-1_2.jar.

 

SSL Version Negotiation

SSL makes sure that both the client and server side agree on an SSL protocol version number. The values that you can specify are as follows:

On the database, the default is "Undetermined". The database does not support 2.0 or 3.0 with 2.0 Hello. Thus, you can use only the Undetermined or 3.0 setting for the client.

Table 4-2 shows which handshakes resolve to depending on SSL version settings on both the client and the server. The star sign "X" indicates cases where the handshake fails. Table 4-2 SSL Version Numbers

  Server Setting  
Client Setting   Undetermined   3.0 W/2.0 Hello (not supported)   3.0   2.0 (not supported)  

Undetermined  

3.0  

X  

X  

X  

3.0 W/2.0 Hello
(not supported)  

X  

X  

X  

X  

3.0  

3.0  

X  

3.0  

X  

2.0 (not supported)  

X  

X  

X  

X  

Authentication

Authentication is the process where one party supplies to a requesting party information that identifies itself. This information guarantees that the originator is not an imposter. In the client/server distributed environment, authentication can be required from the client or the server:

Client-side Authentication

The Oracle data server is a secure server; a client application cannot access data stored in the database without first being authenticated by the database server. Oracle8i CORBA server objects and Enterprise JavaBeans execute in the database server. For a client to activate such an object and invoke methods on it, the client must authenticate itself to the server. The client authenticates itself when a CORBA or EJB object starts a new session. The following are examples of how each IIOP client must authenticate itself to the database:

The client authenticates itself by providing one of the following types:

Authentication type   Definition  

Certificates  

You can provide the user certificate, the Certificate Authority certificate (or a chain that contains both, including other identifying certificates), and a private key.  

Username and
password combination  

You can provide the username and password through either credentials or the login protocol. In addition, you can pass a database role to the server, along with the username and password.  

The type of client-side authentication can be determined by the server's configuration. If, within the SQLNET.ORA file, the SSL_CLIENT_AUTHENTICATION parameter is TRUE, the client must provide certificate-based authentication. If SSL_CLIENT_AUTHENTICATION is FALSE, the client authenticates itself with a username/password combination. If SSL_CLIENT_AUTHENTICATION is TRUE and the client provides a username/password, the connection handshake will fail.

The following table gives a brief overview of the options that the client has for authentication.

As the table demonstrates, most of the authentication options include setting an appropriate value in JNDI properties.

Using JNDI for Authentication

To set up client-side authentication using JNDI, you set the javax.naming.Context.SECURITY_AUTHENTICATION attribute to one of the following values:

Within each of these options, you choose to do one or more of the following:

Client authentication  

  • authenticate itself to the server using login protocol

  • authenticate itself to the server using straight username and password

  • authenticate itself to the server using SSL certificates

 

Server authentication  

  • authenticate itself to the client using SSL certificates

 

For information on how to implement each of these methods for client or server authentication, see the following sections:

Providing Username and Password for Client-Side Authentication

The client authenticates itself to the database server either through a username/password or by supplying appropriate certificates. The username/password can be supplied either through Oracle's login protocol or credentials over the SSL transport connection.

Username Sent by Setting JNDI Properties for the Login Protocol

A client can use the login protocol to authenticate itself to the Oracle8i data server. You can use the login protocol either with or without SSL encryption, because a secure handshaking encryption protocol is built in to the login protocol.

If your application requires an SSL connection for client-server data security, specify the SSL_LOGIN service context value for the SECURITY_AUTHENTICATION property that is passed when the JNDI initial context is obtained. The following example defines the connection to be SSL-enabled for the login protocol. Notice that the username and password are set.


Hashtable env = new Hashtable();
env.put(javax.naming.Context.URL_PKG_PREFIXES, "oracle.aurora.jndi");
env.put(javax.naming.Context.SECURITY_PRINCIPAL, username);
env.put(javax.naming.Context.SECURITY_CREDENTIALS, password);
env.put(javax.naming.Context.SECURITY_AUTHENTICATION, ServiceCtx.SSL_LOGIN);
Context ic = new InitialContext(env);
...

If your application does not use an SSL connection, specify NON_SSL_LOGIN within the SECURITY_AUTHENTICATION parameter as shown below:


Note:

The login handshaking is secured by encryption, but the remainder of the client-server interaction is not secure.  


env.put(javax.naming.Context.SECURITY_AUTHENTICATION, ServiceCtx.NON_SSL_LOGIN);

When you specify values for all four JNDI Context variables--URL_PKG_PREFIXES, SECURITY_PRINCIPAL, SECURITY_CREDENTIALS, and SECURITY_AUTHENTICATION--the first invocation of the Context.lookup()method performs a login automatically.

If the client setting up the connection is not using JNDI look up because it already has an IOR, the user that gave them the IOR for the object should have also passed in a Login object that exists in the same session as the active object. You must provide the username and password in the authenticate method of the Login object, before invoking the methods on the active object.

Username Sent Implicitly by using Credentials

Using the ServiceCtx.SSL_CREDENTIAL authentication type means that the username, password, and, potentially, a role are passed to the server on the first request. Because this information is passed over an SSL connection, the password is encrypted by the transfer protocol, and there is no need for the handshaking that the Login protocol uses. This is slightly more efficient and is recommended for SSL connections.

Username Sent by Explicitly Activating a Login Object

You can explicitly create and populate a Login object for the database login. Typically, you would do this if you wanted to create and use more than a single session from a client. The following example shows a client creating and logging on to two different sessions. To do this, you must perform the following steps:

  1. Create the initial context.

  2. Perform a look up on a URL for the destination database.

  3. On this database service context, create two subcontexts--one for each session.

  4. Login to each session using a Login object, providing a username and password.


    Note:

    The username and password for both sessions are identical because the destination database is the same database. If the client were to connect to two different databases, the username and password may need to be different for logging on.  


    // Prepare a simplified Initial Context as we are going to do
    // everything by hand Hashtable env = new Hashtable (); env.put (Context.URL_PKG_PREFIXES, "oracle.aurora.jndi"); Context ic = new InitialContext (env); // Get a SessionCtx that represents a database instance ServiceCtx service = (ServiceCtx)ic.lookup (serviceURL); // Create and authenticate a first session in the instance. SessionCtx session1 = (SessionCtx)service.createSubcontext (":session1"); LoginServer login_server1 = (LoginServer)session1.activate ("etc/login"); Login login1 = new Login (login_server1); login1.authenticate (user, password, null); // Create and authenticate a second session in the instance. SessionCtx session2 = (SessionCtx)service.createSubcontext (":session2"); LoginServer login_server2 = (LoginServer)session2.activate ("etc/login"); Login login2 = new Login (login_server2); login2.authenticate (user, password, null); // Activate one Hello object in each session Hello hello1 = (Hello)session1.activate (objectName); Hello hello2 = (Hello)session2.activate (objectName);

Using Certificates for Client Authentication

Client authentication through certificates requires the client sending a certificate or certificate chain to the server; the server verifies that the client is truly who the client said it was and that it is trusted.


Note:

All certificates, trustpoints, and the private key should be in base-64 encoded format.  


You set up the client for certificate authentication through one of the following methods:

Specifying Certificates in a File

You can set up a file that contains the user certificate, the issuer certificate, the entire certificate chain, an encrypted private key, and the trustpoints. Once created, you can specify that the client use the file during connection handshake for client authentication.

  1. Create the client certificate file--This file can be created through an export feature in the Wallet Manager. The Oracle Wallet Manager has an option that creates this file. You must populate a wallet using the Wallet Manager before requesting that the file is created.

    After you create a valid wallet, bring up the Wallet Manager and perform the following:

    • From the menu bar pull down, click on Operations > Export Wallet.

    • Within the filename field, enter the name that you want the certificate file known as.

    This creates a base-64 encoded file that contains all certificates, keys, and trustpoints that you added within your wallet. For information on how to create the wallet, see the Oracle Advanced Security Administrator's Guide.

  2. Specify the client certificates file for the connection--Within the client code, set the SECURITY_AUTHENTICATION property to ServiceCtx.SSL_CLIENT_AUTH. Provide the appropriate certificates and trustpoints for the server to authenticate against. Specify the filename and decrypting key in the JNDI properties, as follows:

    Values   Set in JNDI Property  

    Name of the certificate file  

    SECURITY_PRINCIPAL  

    Key for decrypting the private key  

    SECURITY_CREDENTIAL  

    The following code is an example of how to set up the JNDI properties to define the client certificate file:

    
    Hashtable env = new Hashtable();
    env.put(javax.naming.Context.URL_PKG_PREFIXES, "oracle.aurora.jndi");
    env.put(javax.naming.Context.SECURITY_PRINCIPAL, <filename>);
    env.put(javax.naming.Context.SECURITY_CREDENTIAL, <decrypting_key>);
    env.put(javax.naming.Context.SECURITY_AUTHENTICATION, 
    ServiceCtx.SSL_CLIENT_AUTH); Context ic = new InitialContext(env); ...

    For example, if your decrypting key is welcome12 and the certificate file is credsFile, the following two lines would specify these values within the JNDI context:

    env.put(Context.SECURITY_CREDENTIALS, "welcome12");
    env.put(Context.SECURITY_PRINCIPAL, "credsFile");
    
Specifying Certificates in Individual JNDI Properties

You can provide each certificate, private key, and trust point programmatically, by setting each item individually within JNDI properties. Once you populate the JNDI properties with the user certificate, issuer (Certificate Authority) certificate, encrypted private key, and trust points, they are used during connection handshake for authentication. To identify client-side authentication, set the SECURITY_AUTHENTICATION property to serviceCtx.SSL_CLIENT_AUTH.


Note:

Only a single issuer certificate can be set through JNDI properties.  


You can choose any method for setting up your certificates within the JNDI properties. All authorization information values must be set up before initializing the context.

The following example declares the certificates as a static variable. However, this is just one of many options. Your certificate must be base-64 encoded. For example, in the following code, the testCert_base64 is a base-64 encoded client certificate declared as a static variable. The other variables for CA certificate, private key, and so on, are not shown, but they are defined similarly.

final private static String testCert_base64 =
  "MIICejCCAeOgAwIBAgICAmowDQYJKoZIhvcNAQEEBQAwazELMAkGA1UEBhMCVVMx" +
  "DzANBgNVBAoTBk9yYWNsZTEoMCYGA1UECxMfRW50ZXJwcmlzZSBBcHBsaWNhdGlv" +
  "biBTZXJ2aWNlczEhMB8GA1UEAxMYRUFTUUEgQ2VydGlmaWNhdGUgU2VydmVyMB4X" +
  "DTk5MDgxNzE2MjIxMloXDTAwMDIxMzE2MjIxMlowgYUxCzAJBgNVBAYTAlVTMRsw" +
  "GQYDVQQKExJPcmFjbGUgQ29ycG9yYXRpb24xPDA6BgNVBAsUMyoqIFNlY3VyaXR5" +
  "IFRFU1RJTkcgQU5EIEVWQUxVQVRJT04gT05MWSB2ZXJzaW9uMiAqKjEbMBkGA1UE" +
  "AxQSdGVzdEB1cy5vcmFjbGUuY29tMHwwDQYJKoZIhvcNAQEBBQADawAwaAJhANG1" +
  "Kk2K7uOOtI/UBYrmTe89LVRrG83Eb0/wY3xWGelkBeEUTwW57a26u2M9LZAfmT91" +
  "e8Afksqc4qQW23Sjxyo4ObQK3Kth6y1NJgovBgfMu1YGtDHaSn2VEg8p58g+nwID" +
  "AQABozYwNDARBglghkgBhvhCAQEEBAMCAMAwHwYDVR0jBBgwFoAUDCHwEuJfIFXD" +
  "a7tuYNO8bOw1EYwwDQYJKoZIhvcNAQEEBQADgYEARC5rWKge5trqgZ18onldinCg" +
  "Fof6D/qFT9b6Cex5JK3a2dEekg/P/KqDINyifIZL0DV7z/XCK6PQDLwYcVqSSK/m" +
  "487qjdH+zM5X+1DaJ+ROhqOOX54UpiAhAleRMdLT5KuXV6AtAx6Q2mc8k9bzFzwq" +
  "eR3uI+i5Tn0dKgxhCZU=\n";

Hashtable env = new Hashtable();
env.put(Context.URL_PKG_PREFIXES, "oracle.aurora.jndi");
env.put(Context.SECURITY_AUTHENTICATION, ServiceCtx.SSL_CLIENT_AUTH);
//decrypting key
env.put(Context.SECURITY_CREDENTIALS, "welcome12");

// you may also set the certificates individually, as shown bellow.
//User certificate
env.put(ServiceCtx.SECURITY_USER_CERT, testCert_base64);
//Certificate Authority's certificate
env.put(ServiceCtx.SECURITY_CA_CERT, caCert_base64);
//Private key
env.put(ServiceCtx.SECURITY_ENCRYPTED_PKEY, encryptedPrivateKey_base64);
// setup the trust point
env.put(ServiceCtx.SECURITY_TRUSTED_CERT, trustedCert);

Context ic = new InitialContext(env);
Specifying Certificates using AuroraCertificateManager

CORBA clients that do not use JNDI can use AuroraCertificateManager for setting the user and issuer certificates, the encrypted private key, and the trust points.

AuroraCertificateManager maintains certificates for your application. For the certificates to be passed on the SSL handshake for the connection, you must set the certificates before an SSL connection is made. The client sets its certificates through AuroraCertificateManager if client-side authentication is required, and the client does not want to use JNDI properties for setting certificates.

AuroraCertificateManager Class

The methods offered by this object allow you to:

Invoking the ORB.resolve_initial_references method with the parameter SSLCertificateManager will return an object that can be narrowed to a AuroraCertificateManager. Example 4-1 shows a code example of the following methods.

addTrustedCertificate

This method adds the specified certificate as a trusted certificate. The certificate must be in DER encoded format. The client adds trustpoints through this method for server-side authentication.

When your client wants to authenticate a server, the server sends its certificate chain to the client. You might not want to check every certificate in the chain. For example, you have a chain composed of the following certificates: Certificate Authority, enterprise, business unit, a company site, and a user. If you trust the company site, you would check the user's certificate, but you might stop checking the chain when you get to the company site's certificate, because you accept the certificates above the company sites in the hierarchical chain.

Syntax

void addTrustedCertificate(byte[] derCert);

Parameter   Description  

derCert  

The DER encoded byte array containing the certificate.  

requestClientCertificate

This method is invoked by servers that wish to require certificates from client applications. This method is not intended for use by client applications.


Note:

The requestClientCertificate method is not currently required, because the SQLNET.ORA and LISTENER.ORA configuration parameter SSL_CLIENT_AUTHENTICATION performs its function.  


Syntax

void requestClientCertificate(boolean need);

Parameter   Description  

need  

If true, the client must send a certificate for authentication. If false, no certificate is requested from the client.  

setCertificateChain

This method sets the certificate chain for your client application or server object and can be invoked by clients or by servers. The certificate chain always starts with the Certificate Authority certificate. Each subsequent certificate is for the issuer of the preceding certificate. The last certificate in the chain is the certificate for the user or process.

Syntax

void setCertificateChain(byte[][] derCertChain)

Parameter   Description  

derCertChain  

A byte array containing an array of certificates.  

setEncryptedPrivateKey

This method sets the private key for your client application or server object. You must specify the key in PKCS5 or PKCS8 format.

Syntax

void setEncryptedPrivateKey(byte[] key, String password);

Parameter   Description  

key  

The byte array that contains the encrypted private key.  

password  

A string containing a password for decrypting the private key.  

setProtocolVersion

This method sets the SSL protocol version that can be used for the connection. A 2.0 Client trying to establish an SSL connection with a 3.0 Server will fail and the converse. We recommend using Version_Undetermined, because it lets the peers establish an SSL connection whether they are using the same protocol version or not. SSL_Version_Undetermined is the default value.

Syntax

void setProtocolVersion(int protocolVersion);

Parameter   Description  

protocolVersion  

The protocol version being specified. The value you supply is defined in oracle.security.SSL.OracleSSLProtocolVersion. This class defines the following values:

  • SSL_Version_Undetermined: Version is undetermined. This is used to connect to SSL 2.0 and SSL 3.0 peers. This is the default version.

  • SSL_Version_3_0_With_2_0_Hello: Not supported.

  • SSL_Version_3_0: Used to connect to 3.0 peers only.

  • SSL_Version_2_0: Not supported.

 

Example 4-1 Setting SSL Security Information Using AuroraCertificateManager

This example does the following:

  1. Retrieve the AuroraCertificateManager.

  2. Initialize this client's SSL information:

    1. Set the certificate chain through setCertificateChain.

    2. Set the trustpoint through addTrustedCertificate.

    3. Set the private key through setEncryptedPrivateKey.

      // Get the certificate manager
      AuroraCertificateManager cm = AuroraCertificateManagerHelper.narrow(
      	orb.resolve_initial_references("AuroraSSLCertificateManager"));
      
      BASE64Decoder decoder = new BASE64Decoder();
      byte[] userCert = decoder.decodeBuffer(testCert_base64);
      byte[] caCert = decoder.decodeBuffer(caCert_base64);
      
      // Set my certificate chain, ordered from CA to user.
      byte[][] certificates = {
              caCert, userCert
      };
      cm.setCertificateChain(certificates);
      cm.addTrustedCertificate(caCert);
      
      // Set my private key.
      byte[] encryptedPrivateKey =
      decoder.decodeBuffer(encryptedPrivateKey_base64);
      
      cm.setEncryptedPrivateKey(encryptedPrivateKey, "welcome12");
      

Server-Side Authentication

Server-side authentication takes place when the server provides certificates for authentication to the client. When requested, the server will authenticate itself to the client, also known as server-side authentication, by providing certificates to the client. The SSL layer authenticates both peers during the connection handshake. The client requests server-side authentication by setting any of the SSL_* values in the JNDI property. See "Using JNDI for Authentication" for more information on these JNDI values.

For server-side authentication, you must set up a database wallet with the appropriate certificates, using the Wallet Manager. See the Oracle Advanced Security Administrator's Guide for information on how to create a wallet.


Note:

If the client wants to verify the server against trustpoints or authorize the server, it is up to the client to set up its trustpoints and parse the server's certificates for authorization. See "Authorization" for more information.  


Authorization

The SSL layer authenticates the peers during the connect handshake. After the handshake, you can be assured that the peer is authenticated to be who they said they are. In addition, since the server has specified, within an Oracle wallet, its trustpoints, the SSL adapter on the server will authorize the client. However, the client has the option of how much authorization is done against the server.

Setting up Trust Points

The server automatically has trustpoints established through the installed Oracle Wallet. The trustpoints in the wallet are used to verify the client's certificates. However, if the client wants to verify the server's certificates against certain trustpoints, it can set up its these trustpoints, as follows:

If the client does not set up trust points, it does not hinder the authorization. That is, JServer assumes that the client trusts the server.

Example 4-2 Verifying Trustpoints

The following example shows how the client sets up its trustpoints through JNDI. The JNDI SECURITY_TRUSTED_CERT property can take only a single certificate.

// setup the trust point
env.put(ServiceCtx.SECURITY_TRUSTED_CERT, trustedCert);

Parsing through the Server's Certificate Chain

The client retrieves the certificates to perform any authorization checks. In the past, you could retrieve the single issuer certificate. Now, you receive the entire issuer certificate chain. You must parse the certificate chain for the information that you need. You can parse the chain through the AuroraCurrent object.


Note:

You must configure the database and listener to be SSL-enabled, as described in "Configuring CORBA and EJB in JServer".  



Note:

JDK 1.1 certificate classes were contained within javax.security.cert. In JDK 1.2, these classes moved to java.security.cert.  


AuroraCurrent contains three methods for retrieving and managing the certificate chain. For creating and parsing the certificate chain, you can use the X509Cert class methods. For information on this class, see Sun Microsystems's JDK documentation. Note that the X509Cert class manipulates the certificate chain differently in JDK 1.1 than in Java 2.

The AuroraCurrent class methods are as follows:

When the handshake occurs, the protocol version and the type of encryption used is negotiated. The type of encryption can be full or limited encryption, which complies with the United States legal restrictions. After the handshake completes, the AuroraCurrent can retrieve what was resolved in the negotiation.

AuroraCurrent Class

The following describes the methods contained within AuroraCurrent. See Example 4-3 for a code example of these methods.

getNegotiatedCipherSuite

This method obtains the type of encryption negotiated in the handshake with the peer.

Syntax

String getNegotiatedCipherSuite(org.omg.CORBA.Object peer);

Parameter   Description  

peer  

The peer from which you obtain the negotiated cipher.  

Returns

A string one of the following values:

Export ciphers:

Domestic ciphers

getPeerDERCertificateChain

This method obtains the peer's certificate chain. After retrieving the chain, you can parse through the certificates within the chain, to authorize the peer to your application.

Syntax

byte [] [] getPeerDERCertificateChain(org.omg.CORBA.Object peer);

Parameter   Description  

peer  

The peer from which you obtain its certificate chain.  

Returns

A byte array containing an array of certificates.

getNegotiatedProtocolVersion

This method obtains the negotiated SSL protocol version of a peer.

Syntax

String getNegoriatedProtocolVersion(org.omg.CORBA.Object peer);

Parameter   Description  

peer  

The peer from which you obtain the negotiated protocol version.  

Returns

A string with one of the following values:

Example 4-3 Retrieving a Peer's SSL information for Authorization

This example shows how to authorize a peer by retrieving the certificate information using the AuroraCurrent object.

  1. To retrieve an AuroraCurrent object, invoke the ORB.resolve_initial_references method with AuroraSSLCurrent as the argument.

  2. Retrieve the SSL information from the peer through AuroraCurrent methods: getNegotiatedCipherSuite, getNegotiatedProtocolVersion, and getPeerDERCertChain.

  3. Authorize the peer. You can authorize the peer based on its certificate chain.


    Note:

    This example uses the x509Certificate class methods for parsing the certificate chain and is specific to Java 2. If you are using Java 1.1, you must use the x509Certificate class methods specific to Java 1.1.  


    static boolean verifyPeerCert(org.omg.CORBA.Object obj) throws Exception
     {
       org.omg.CORBA.ORB orb = oracle.aurora.jndi.orb_dep.Orb.init();
    
       // Get the SSL current
       AuroraCurrent current = AuroraCurrentHelper.narrow
           (orb.resolve_initial_references("AuroraSSLCurrent"));
    
       // Check the cipher
       System.out.println("Negotiated Cipher:  " +
                          current.getNegotiatedCipherSuite(obj));
       // Check the protocol version
       System.out.println("Protocol Version:   " +
                          current.getNegotiatedProtocolVersion(obj));
       // Check the peer's certificate
       System.out.println("Peer's certificate chain : ");
       byte [] [] certChain = current.getPeerDERCertChain(obj);
    
       //Parse through the certificate chain using the X509Certificate methods
       System.out.println("length : " + certChain.length);
       System.out.println("Certificates: ");
       CertificateFactory cf = CertificateFactory.getInstance("X.509");
    
       //For each certificate in the chain
       for(int i = 0; i < certChain.length; i++) {
         ByteArrayInputStream bais = new ByteArrayInputStream(certChain[i]);
         Certificate  xcert = cf.generateCertificate(bais);
         System.out.println(xcert);
         if(xcert instanceof X509Certificate)
         {
           X509Certificate x509Cert = (X509Certificate)xcert;
           String globalUser = x509Cert.getSubjectDN().getName();
           System.out.println("DN out of the cert : " + globalUser);
         }
       }
    
       return true;
     }
    


    Note:

    The x509Certificate class is a Java 2 class. See Sun Microsystems's documentation for more information. In addition, you can find information in the javadoc for javax.net.ssl.  


Non-JNDI Clients

It is possible for clients to access server objects without using the JNDI classes shown in the other sections of this chapter. These clients can connect to an Oracle server by using straight CosNaming methods. The following example shows how to do this.

import org.omg.CORBA.Object;
import org.omg.CosNaming.*;
import oracle.aurora.AuroraServices.*;
import oracle.aurora.client.Login;

public class Client {

  public static void main(String args[]) throws Exception {
    // Parse the args
    if (args.length != 4) {
      System.out.println("Must supply host/port, username/ password");
      System.exit(1);
    }
    String host = "sess_iiop://localhost:2481:ORCL";
    String port = "2481";
    String username = "scott";
    String password = "tiger";

    // access the Aurora Names Service
    
    Bank.Account account = null;
    Bank.AccountManager manager = null;
  
    try {  
      
      // Get the Name service Object reference (Only ORB specific thing)
      PublishingContext rootCtx = null;
      // See the README file with this demo for more about VisiAurora.
      rootCtx = VisiAurora.getNameService(host, Integer.parseInt(port));
      
      // Get the pre-published login object reference
      PublishedObject loginObj = null;    
      LoginServer   serv = null;
      NameComponent[] name = new NameComponent[2];
      name[0] = new NameComponent("etc", "");
      name[1] = new NameComponent("login", "");

      // look up this object in the name service
      Object lo = rootCtx.resolve(name);

      // Make sure it is a published object
      loginObj = PublishedObjectHelper.narrow(lo);

      // create and activate this object (non- standard call)
      lo = loginObj.activate_no_helper();
      serv = LoginServerHelper.narrow(lo);
      
      // Create a client login proxy object and authenticate to the DB
      Login login = new Login(serv);
      login.authenticate(username, password, null);
      
      // Now create and get the bank object reference
      PublishedObject bankObj = null;    
      name[0] = new NameComponent("test", "");
      name[1] = new NameComponent("bank", "");

      // look up this object in the name service
      Object bo = rootCtx.resolve(name);

      // Make sure it is a published object
      bankObj = PublishedObjectHelper.narrow(bo);

      // create and activate this object (non- standard call)
      bo = bankObj.activate_no_helper();
      manager = Bank.AccountManagerHelper.narrow(bo);
      
      account = manager.open("Jack.B.Quick");
      
      float balance = account.balance();
      System.out.println
          ("The balance in Jack.B.Quick's account is $" + balance);      
    } catch (org.omg.CORBA.SystemException ex) {
      System.out.println("Caught System Ex: " + ex);
      ex.printStackTrace();            
    } catch(java.lang.Exception ex) {
      System.out.println("Caught Unknown Ex: " + ex);
      ex.printStackTrace();            
    }
  }
}

You can obtain documentation and other collateral information about JNDI from the following web site:

http://java.sun.com/products/jndi/index.html




Prev

Top

Next
Oracle
Copyright © 1999 Oracle Corporation.

All Rights Reserved.

Library

Product

Contents

Index