BEA Logo BEA WebLogic Enterprise Release 5.0

  Corporate Info  |  News  |  Solutions  |  Products  |  Partners  |  Services  |  Events  |  Download  |  How To Buy

 

   WLE Doc Home   |   CORBA Programming & Related Topics   |   Previous   |   Next   |   Contents   |   Index

InterceptorSec Sample Interceptors

This chapter discusses the following topics:

Before trying out the steps described in this chapter, make sure you have completed all the steps described in PersonQuery Sample Application.

Note: The WLE software provides C++ versions of both the client and target InterceptorSec sample interceptors. However, only the target-side InterceptorSec sample interceptor is provided in Java; there is no Java version of the client-side InterceptorSec sample interceptor.

How the PersonQuery Sample Interceptors Work

The InterceptorSec sample interceptors show a simple client/server interceptor pair that implement a basic security model. The InterceptorSec client-side interceptor simply logs each client request that is handled by the ORB. The InterceptorSec target-side interceptor implements a simple security mechanism that checks to see whether the user of the client application is authorized to perform the operation in the request.

The C++ InterceptorSec sample interceptors show the client and target interceptor pair initialized through a single initialization function and implemented in a single library. Since a single initialization function is called, the interceptor registration command registers one initialization function and one implementation library.

(The Java InterceptorSec sample interceptor is implemented on the target-side only.)

How the InterceptorSec Target-side Interceptor Works

When the target-side ORB receives a request, the ORB calls the InterceptorSec target-side interceptor and passes the RequestContext and DataInputStream objects from the client request.

The target-side interceptor then does the following to authorize the user of the client application for the operation contained in the request:

  1. Checks to see if the request is an invocation on the PersonQuery interface. If it is not, the interceptor returns a INVOKE_NO_EXCEPTION .

  2. If the operation contained in the request is an invocation on the PersonQuery interface, the interceptor:

    1. Obtains a reference to the SecurityCurrent object, which the interceptor then narrows

    2. Invokes the SecurityContext object, requesting the attribute list for the user of the client application

    3. Walks through the attribute list to obtain two attributes:

      PrimaryGroupId

      Identifies the client name of the user of the client application. In this interceptor, the client name must contain either the character r or a NULL string.

      AccessId

      Identifies the user of the client application. In this interceptor, the user name must have the characters R , P , or N (either upper- or lowercase).

    4. Matches the user against the PrimaryGroupId and the AccessId . If the user successfully matches the criteria for these two attributes, the interceptor returns INVOKE_NO_EXCEPTION .

    5. If no match is found, the interceptor returns REPLY_EXCEPTION , which prevents the request from being sent to the target object. Instead, the ORB returns an exception to the client application.

The sections that immediately follow discuss interceptor security topics and show code fragments of interest from both the C++ and Java versions of the InterceptorSec target-side interceptor.

Using the SecurityCurrent Object

Interceptors obtain the SecurityCurrent object from the ORB, not from the Bootstrap object. The SecurityCurrent object available from the ORB has the API that interceptors need for obtaining information about the client.

To obtain the SecurityCurrent object, your interceptors can invoke the resolve_initial_references("SecurityCurrent") operation on the ORB. The interceptor can then narrow the SecurityCurrent reference to a SecurityCurrentLevel1 current.

Obtaining the SecurityCurrent Object

The current JavaServer ORB provides equivalent functionality to the C++ ORB with regards to a proprietary SecurityCurrent object in the server process. The SecurityCurrent object is available only through the ORB, and this object's primary functionality is to provide server applications access to attributes related to the client invocation.

The ORB's resolve_initial_references("SecurityCurrent") method provides the interceptor a reference to a SecurityCurrent object from which the interceptor is provided with Level 1 Security functionality. The interceptor can obtain the attributes of the client invocation via the get_attributes method on the SecurityCurrent object, which returns an attribute list to the interceptor. The attribute list contains the attributes that pertain to the user of the client application that performed the invocation being intercepted. The behavior of any and all methods from the CORBA security service is still the same, with the exceptions noted above.

The following code fragments show obtaining the SecurityCurrent object.

C++

try
{
sec_current = m_orb->resolve_initial_references("SecurityCurrent");
}
catch (...)
{
*m_outfile <<
"ERROR: ORB::resolve_initial_references threw exception"
<< endl << endl << flush;
excep_val = new CORBA::UNKNOWN();
return Interceptors::REPLY_EXCEPTION;
}
if (CORBA::is_nil(sec_current.in()))
{
*m_outfile << "ERROR: No SecurityCurrent present"
<< endl << endl << flush;
excep_val = new CORBA::NO_PERMISSION();
return Interceptors::REPLY_EXCEPTION;
}

m_security_current = SecurityLevel1::Current::_narrow(sec_current.in());
if (!m_security_current)
{
*m_outfile << "ERROR: Couldn't narrow security
current to SecurityLevel1::Current"
<< endl << endl << flush;
excep_val = new CORBA::NO_PERMISSION();
return Interceptors::REPLY_EXCEPTION;
}

Java

try
{
org.omg.CORBA.Object secCurObjRef =
theOrb.resolve_initial_references("SecurityCurrent");
if(secCurObjRef == null)
{
TP.userlog("ERROR: No SecurityCurrent present");
excep_val.value = new NO_PERMISSION();
return InvokeReturnStatus.REPLY_EXCEPTION;
}
securityCurrent =
org.omg.SecurityLevel1.CurrentHelper.narrow(secCurObjRef);
}
catch(Exception ex)
{
TP.userlog("ERROR: ORB.resolve_initial_references
threw exception");
excep_val.value = new UNKNOWN();
return InvokeReturnStatus.REPLY_EXCEPTION;
}

Creating the List of User Attributes

The code fragments in this section show how the InterceptorSec target-side interceptor creates a list of user attributes and then walks through this list to determine if the user matches the authorization criteria.

C++

In the C++ version of the InterceptorSec sample, creating the list of attributes, then walking through them are done in separate steps. Note that if you specify a client attribute list length of zero (0) to be returned, the SecurityCurrent object returns all the attributes for the client.

// Get the attributes that correspond to the information that we need to
// do an authorization check:
// PrimaryGroupId (clientname of the logged in client)
// AccessId (username of the logged in client)
Security::AttributeList_var client_attr = 0;
try
{
client_attr = m_security_current->get_attributes(*m_attributes_to_get);

The following fragment shows creating the list.

Security::AttributeTypeList_var attr = new Security::AttributeTypeList(2);
if (!attr.ptr())
{
cout <<
"ERROR: can't allocation security list: Out of memory"
<< endl << endl << flush;
return;
}
attr.inout().length(2);
attr[(CORBA::ULong)0].attribute_family.family_definer = 0;
attr[(CORBA::ULong)0].attribute_family.family = 1;
attr[(CORBA::ULong)0].attribute_type = Security::PrimaryGroupId;
attr[(CORBA::ULong)1].attribute_family.family_definer = 0;
attr[(CORBA::ULong)1].attribute_family.family = 1;
attr[(CORBA::ULong)1].attribute_type = Security::AccessId;
m_attributes_to_get = attr._retn();
return;

The following fragment shows walking through the attribute list to check whether the user matches the authorization criteria:

if (client_attr[i].attribute_type.attribute_type == Security::PrimaryGroupId)
{
//
// This attribute is the client name.
// Compare to some client name value.
// For this example, we're going to accept anything with
// an 'r' in it, or a NULL string. You will want to compare
// the client name to some set of values you have authorized.
//
if ((strlen(value_buffer) == 0) ||
(strchr(value_buffer, 'r') != 0))
{
*m_outfile << " INFO: Valid client name found: "
<< value_buffer << endl;
clientname_ok = 1;
}
else
{
*m_outfile << " ERROR: Invalid client name found: "
<< value_buffer << endl;
}
}
else if (client_attr[i].attribute_type.attribute_type == Security::AccessId)
{
// This attribute is the user name. We're arbitrarily
// choosing to authorize anyone who has an 'r', 'n', or 'p'
// in their user id. You will likely want to choose
// some other criteria for authorization.
//
if ((strchr(value_buffer, 'r') != 0) ||
(strchr(value_buffer, 'R') != 0) ||
(strchr(value_buffer, 'P') != 0) ||
(strchr(value_buffer, 'p') != 0) ||
(strchr(value_buffer, 'N') != 0) ||
(strchr(value_buffer, 'n') != 0))
{
*m_outfile << " INFO: Valid username found: "
<< value_buffer << endl;
username_ok = 1;
}

Java

In Java version of this sample, creating the attribute list and then verifying its contents is done in a single step, as in the following code fragment. Note that if you specify a null argument in the invocation to the get_attributes method, the SecurityCurrent returns all the attributes for the client.

org.omg.Security.SecAttribute clientAttributes[];
try
{
clientAttributes = securityCurrent.get_attributes(null);
}
.
.
.
if((clientAttributes == null ) || (clientAttributes.length == 0))
{
// This condition short-circuits the invocation, because it
// returns an exception on the reply.
TP.userlog("ERROR: Security attributes not retrieved");
excep_val.value = new NO_PERMISSION();
return InvokeReturnStatus.REPLY_EXCEPTION;
}

boolean groupFlag = false;
for(int i = 0; i < clientAttributes.length; i++)
{
/**
* The verification depends upon what type of attribute this
* element contains.
*/
if(clientAttributes[i].attribute_type.attribute_type ==
org.omg.Security.PrimaryGroupId.value)

{

/**
* This attribute is the client name.
* Compare to some client name value.
* For this example, we're going to accept anything with
* an 'r' in it, or a NULL string. You will want to compare
* the client name to some set of values you have authorized.
*/
for(int j = 0; j < clientAttributes[i].value.length; j++)
{
char ch = (char) clientAttributes[i].value[j];
TP.userlog("Client name value[" + j + "] = " + ch);
if((ch == 'r') || (ch == 'R') ||
(ch == 'p') || (ch == 'P'))
{
groupFlag = true;
TP.userlog("INFO: Valid Client Name Found");
}
}
if(!groupFlag)
TP.userlog("INFO: No Valid Client Name Found");
}
else if(clientAttributes[i].attribute_type.attribute_type ==
org.omg.Security.AccessId.value)
{
/**
* This attribute is the user name. We're arbitrarily
* choosing to authorize anyone who has an 'r', 'n', or 'p'
* in their user id. You will likely want to choose
* some other criteria for authorization.
*/
for(int j = 0; j < clientAttributes[i].value.length; j++)
{
char ch = (char) clientAttributes[i].value[j];
TP.userlog("Access Id value[" + j + "] = " + ch);
if((ch == 'r') || (ch == 'R') ||
(ch == 'p') || (ch == 'P') ||
(ch == 'n') || (ch == 'N'))
{
userFlag = true;
TP.userlog("INFO: Valid User Id Found");
}
}
if(!userFlag)
TP.userlog("INFO: No Valid User Id Found");
}
}

Registering and Running the PersonQuery Interceptors

When you run the makefile that builds the PersonQuery sample application in PersonQuery Sample Application, the entire set of sample interceptors are built as well, including the InterceptorSec interceptor. This section describes how to register the InterceptorSec interceptor so that it works with PersonQuery application at run time.

This section is presented in two parts: one for C++, and one for Java.

Registering and Running the C++ Interceptors

To register and run the C++ InterceptorSec client and server interceptors:

  1. Change directory to the InterceptorSec sample directory, where workdirectory represents the name of the directory into which you copied the interceptor sample applications in PersonQuery Sample Application:

    Windows NT

    > cd <workdirectory>\cxx\security_cxx

    UNIX

    $ cd <workdirectory>/cxx/security_cxx

  2. Register the interceptor:

    Windows NT

    > nmake -f makefile.nt config

    UNIX

    $ make -f makefile.mk config

  3. Boot the server and run the client:

    Windows NT

    > cd <workdirectory>\cxx\app_cxx
    > tmboot -y
    > PersonQueryClient

    UNIX

    > cd <workdirectory>/cxx/app_cxx
    > tmboot -y
    > PersonQueryClient

  4. Perform any number of invocations using the PersonQuery client application, using the command syntax described in PersonQuery Sample Application.

  5. Stop the PersonQuery application:

    > tmshutdown -y

Registering and Running the Java Interceptors

To register the Java InterceptorSec server interceptor:

  1. Change directory to the one into which you copied the Java interceptor sample applications in PersonQuery Sample Application:

    Windows NT:

    > cd <workdirectory>\java

    UNIX:

    $ cd <workdirectory>/java

  2. Register the interceptor:

    Windows NT:

    > .\registerAll.cmd

    UNIX:

    $ chmod u+x registerAll.ksh
    $ ./registerAll.ksh

  3. Boot the server and run the C++ client:

    Windows NT:

    > tmboot -y
    > cd <workdirectory>\cxx\app_cxx
    > PersonQueryClient

    UNIX:

    > tmboot -y
    > cd <workdirectory>/cxx/app_cxx
    > PersonQueryClient

  4. Perform any number of invocations using the PersonQuery client application, using the command syntax described in PersonQuery Sample Application.

  5. Stop the PersonQuery application:

    > tmshutdown -y

Examining the Interceptor Output

Because of the way in which the sample interceptors were implemented, the location and format of the interceptor output is different between the C++ and Java interceptors.

For C++:

The C++ InterceptorSec client and target interceptors log their output to the files named, respectively, InterceptorSecClient xxx.out and InterceptorSecTarget xxx.out . These files contain debugging output from the interceptors that is automatically loaded and executed by the ORB for the PersonQuery application.

For Java:

The Java InterceptorSec target-side interceptor sends its output to the ULOG file, as in the following example:

134040.ICEAXE!JavaServer.221: main: InterceptorSecurity0,
InterceptorSecurity.target_invoke
134040.ICEAXE!JavaServer.221: main: Group Id value[0] = I
134040.ICEAXE!JavaServer.221: main: Group Id value[1] = I
134040.ICEAXE!JavaServer.221: main: Group Id value[2] = O
134040.ICEAXE!JavaServer.221: main: Group Id value[3] = P
134040.ICEAXE!JavaServer.221: main: INFO: Valid Group Id Found
134040.ICEAXE!JavaServer.221: main: Group Id value[4] =
134040.ICEAXE!JavaServer.221: main: Group Id value[5] = c
134040.ICEAXE!JavaServer.221: main: Group Id value[6] = l
134040.ICEAXE!JavaServer.221: main: Group Id value[7] = i
134040.ICEAXE!JavaServer.221: main: Group Id value[8] = e
134040.ICEAXE!JavaServer.221: main: Group Id value[9] = n
134040.ICEAXE!JavaServer.221: main: Group Id value[10] = t
134040.ICEAXE!JavaServer.221: main: Access Id value[0] = I
134040.ICEAXE!JavaServer.221: main: Access Id value[1] = I
134040.ICEAXE!JavaServer.221: main: Access Id value[2] = O
134040.ICEAXE!JavaServer.221: main: Access Id value[3] = P
134040.ICEAXE!JavaServer.221: main: INFO: Valid User Id Found
134040.ICEAXE!JavaServer.221: main: Access Id value[4] =
134040.ICEAXE!JavaServer.221: main: Access Id value[5] = c
134040.ICEAXE!JavaServer.221: main: Access Id value[6] = l
134040.ICEAXE!JavaServer.221: main: Access Id value[7] = i
134040.ICEAXE!JavaServer.221: main: Access Id value[8] = e
134040.ICEAXE!JavaServer.221: main: Access Id value[9] = n
134040.ICEAXE!JavaServer.221: main: INFO: Valid User Id Found
134040.ICEAXE!JavaServer.221: main: Access Id value[10] = t

Unregistering the Interceptors

After you have run the PersonQuery sample application with the InterceptorSec sample interceptors, you can unregister those interceptors using the following steps:

  1. Shut down all running WLE applications by entering the following command:

    > tmshutdown -y

  2. Unregister the interceptors as described in the language-specific sections that follow.

Unregistering the C++ Interceptors

To unregister the C++ InterceptorSec client and server interceptors:

  1. Change directory to the InterceptorSec sample directory, where workdirectory represents the name of the directory into which you copied the interceptor sample applications in PersonQuery Sample Application:

    Windows NT:

    > cd <workdirectory >\cxx\security_cxx

    UNIX:

    $ cd <workdirectory >/cxx/security_cxx

  2. Unregister the interceptors:

    Windows NT:

    > nmake -f makefile.nt unconfig

    UNIX:

    $ make -f makefile.mk unconfig

Unregistering the Java Interceptors

To unregister the Java InterceptorSec server interceptor:

  1. Change directory to the one into which you copied the Java interceptor sample applications in PersonQuery Sample Application:

    Windows NT:

    > cd <workdirectory >\java

    UNIX:

    $ cd <workdirectory >/java

  2. Unregister the interceptor:

    Windows NT:

    > .\unregisterAll.cmd

    UNIX:

    $ chmod u+x unregisterAll.ksh
    $ ./unregisterAll.ksh