[Previous] [Contents] [Next] [IONA Technologies]


Chapter 21
Filters


Contents

21.1 Introduction to Per-process Filters
21.2 Introduction to Per-Object Filters
21.3 Per-Process Filters
21.3.1 An Example Per-Process Filter
21.3.2 Installation of Per-Process Filter
21.3.3 Raising an Exception in a Filter
21.3.4 Piggybacking Extra Data to the Request Buffer
21.3.5 Retrieving the Size of a Request Buffer
21.3.6 Defining an Authentication Filter
21.4 Per-Object Filters
21.4.1 IDL Compiler Switch to Enable Object Filtering



OrbixWeb allows a programmer to specify that additional code is to be executed before or after the normal code of an operation or attribute. This support is provided by allowing applications to create filters, which can perform security checks, provide debugging traps or information, maintain an audit trail, and so on.

There are two forms of filters: per-process and per-object filters. Per-process filters see all operation and attribute calls leaving or entering a client's or server's address space, irrespective of the target object. Per-object filters apply to individual objects. Both of these filter types are illustrated in Figure 21.1.


Figure 21.1: Per-process and per-object filtering

Section 21.1 and section 21.2 give a brief introduction to each, and the remainder of the chapter then describes each in detail.

Note that use of the Dynamic Invocation Interface does not by-pass the filtering mechanism: calls made using the DII will result in the use of all appropriate outgoing and incoming filters, except the filter point in reply post marshal. This filter point must be handled explicitly by a DII programmer, as described in section 19.6.

21.1 Introduction to Per-process Filters

Per-process filters monitor all incoming and outgoing operation and attribute requests to and from an address space. Each process can have a chain of such filters, with each element of the chain performing its own actions. A new element can be added to the chain by carrying out the following two steps:

Each filter of the chain can monitor ten individual points during the transmission and reception of an operation or attribute request (see Figure 21.2). The four most commonly used filter points are:

There are four similar monitor points:

Two additional monitor points deal with exceptional conditions:

Once an exception is raised or a filter point uses its return value to indicate that the call should not be processed further, no further monitor points (other than the two failure monitor points) are called. If this occurs in the caller's address space, then in reply failure is called. If it occurs in the target object's address space, then out reply failure and in reply failure are both called (in the target object's and the caller's address spaces respectively).

All monitor points (eight marshalling points and two failure points) are shown in Figure 21.2.


Figure 15.2: Per-process monitor points

A particular filter on the per-process filter chain may perform actions for any number of these filter points, although it is common to handle four filter points, for example:

As well as monitoring incoming and outgoing requests, a filter on the client side and a filter on the server side can co-operate to pass data between them, in addition to the normal parameters of an operation (or attribute) call. For example, the `out' filter points of a filter in the client can be used to insert extra data into the request package (for example, in `out request pre marshal'); and the `in' filter points of a filter in the server can be used to extract this data (for example, in `in request pre marshal').

Each filter point must indicate how the handling of the request should be continued once the filter point itself has completed. In particular, a filter point can determine whether or not OrbixWeb is to continue to process the request or to return an exception to the caller.

Since per-process filters are applied only when an invocation leaves or arrives at an address space, they are not informed of invocations between collocated objects.

Note that a special form of per-process filters can be used to pass authentication information from a client to a server. This type of filter is called an authentication filter, and it supports the verification of the identity of a caller, which is a fundamental requirement for security. Authentication filters are discussed in section 21.3.6.

21.2 Introduction to Per-Object Filters

Per-object filters are associated with a particular object, rather than with all objects in an address space as in per-process filtering. Unlike per-process filters, per-object filters apply even for intra-process operation requests. The following filtering points are supported:

A per-object pre-filter can indicate, by raising an exception, that the actual operation call should not be passed to the target object.

Per-object filters are created by carrying out the following three steps:

It is important to realise that a per-object filter is either a pre-filter or a post-filter. In contrast, a single per-process filter can perform actions for any or all of its eight monitor points.

An object can have a chain of pre-filters and/or a chain of post-filters. For example, a chain of pre-filters can be constructed by attaching a pre-filter to the object, then attaching a pre-filter to that filter, and so on.

Note that per-object filtering can only be used if it was enabled when the corresponding IDL interface was compiled by the IDL compiler (see section 21.4.1).

The parameters to an IDL operation request are readily available for both pre and post per-object filters. Any in and inout parameters are valid for pre filters; in, out and inout parameters and return values are valid for post filters. In contrast, for per-process filters, parameters to the operation request are not in general available.

The per-process `in request' (both pre and post marshal) filters are applied before any per-object pre-filter. The per-object post-filters are applied before any per-process `out reply' (both pre and post marshal) filters.

The remainder of this chapter presents, in turn, the details of per-process and per-object filters.

21.3 Per-Process Filters

A per-process filter is installed by defining a derived class of class Filter, and re-defining one or more of its methods:

outRequestPreMarshal()

Action to carry out in the caller's filter before outgoing requests (before marshalling).

outRequestPostMarshal()

Action to carry out in the caller's filter before outgoing requests (after marshalling).

inRequestPreMarshal()

Action to carry out in the receiver's filter before incoming requests (before marshalling).

inRequestPostMarshal()

Action to carry out in the receiver's filter before incoming requests (after marshalling).

outReplyPreMarshal()

Action to carry out in the receiver's filter before outgoing replies (before marshalling).

outReplyPostMarshal()

Action to carry out in the receiver's filter before outgoing replies (after marshalling).

inReplyPreMarshal()

Action to carry out in the caller's filter before incoming replies (before marshalling).

inReplyPostMarshal()

Action to carry out in the caller's filter before incoming replies (after marshalling).

outReplyFailure()

Action to carry out in the receiver's filter if a preceding filter point raises an exception or indicates that the call should not be processed further or if the target object raises an exception.

inReplyFailure()

Action to carry out in the caller's address space if the target object raises an exception or a preceding filter point raises an exception or indicates that the call should not be processed further.

Each of these methods takes a single parameter; the marshalling methods (the methods not concerned with failure) return a boolean value to indicate whether or not OrbixWeb should continue to make the request. For example

The failure methods, outReplyFailure() and inReplyFailure(), have a void return type.

The details of the request being made can be obtained by calling methods on the Request parameter (class Request is defined in package IE.Iona.Orbix2.CORBA). Examples of this are shown in section 21.3.1.

Full details of these methods are given inPart II, "Class and Interface Reference" of the OrbixWeb Reference Guide.

The constructor of class Filter adds the newly created filter object into the per-process filter chain. Direct instances of Filter cannot be created (the constructor is protected to enforce this). Derived classes of Filter will normally have public constructors.

Note that each method (except the two failure methods) returns a value to indicate how the call should continue. Redefinitions of these methods in a derived class should retain the same semantics for the return value as specified in the relevant entries in the OrbixWeb Reference Guide.

Programmers should define derived classes of Filter and redefine some subset of the filter point methods to carry out the required filtering. If any of the non-failure monitoring methods is not redefined in a derived class of Filter, then the following implementation is inherited in all cases:

The failure filter methods inherit the following implementation:

Note that the two `out reply' marshalling filter points are used only if the operation request is issued to the target object. The two `in reply' marshalling filter points are used only if the operation request is sent out of the caller's address space.

21.3.1 An Example Per-Process Filter

Consider the following simple example of a per-process filter:

Such classes can have any name; but they must inherit from Filter. Filter has a protected default constructor; ProcessFilter is given a default (no parameter) public constructor by Java.

The method target() can be applied to a Request to find the object reference of the target object; and the method _object_to_string() can be applied to an object reference to get a string form of an object reference. The method operation() can be applied to a Request to find the name of the operation being called.

21.3.2 Installation of Per-Process Filter

To install this per-process filter, the programmer need only create an instance of it:

This object will automatically add itself to the per-process filter chain.

21.3.3 Raising an Exception in a Filter

Any of the per-process filter points can raise an exception in the normal manner. For example, the inRequestPostMarshal() filter point can be changed to raise a NO_PERMISSION system exception:

Rules for Raising an Exception

The following rules apply when a filter point raises an exception:

21.3.4 Piggybacking Extra Data to the Request Buffer

One of the outRequest filter points in a client can add extra piggybacked data to an outgoing request buffer–and this data will then be made available to the corresponding inRequest filter point on the server side. In addition, one of the `out reply' marshalling filter points on a server can add data to an outgoing reply–and this data will then be made available to the corresponding inReply filter point on the client-side.

At each of the four `out' marshalling monitor points, data can be added by using an appropriate insert() method for the Request parameter, for example:

This is the same insertion mechanism that is used in the DII (Chapter 19, "Dynamic Invocation Interface").

At each of the `in' marshalling monitor points, data can be extracted using an appropriate extract() method, for example,

Note that this is a subtle difference from the normal use of extract() for the Dynamic Invocation Interface, as described in Chapter 19, "Dynamic Invocation Interface". In the dynamic invocation interface, extract() is only used to determine the return value of an invocation. In particular, inout and out parameters are not obtained using extract(), but their values are instead established using the extractOutParams() method. In contrast here, extract() can be used to extract piggybacked data from an incoming request (or reply).

Care must be taken to correctly match the insertion and extraction points, as follows:

For example, a value inserted by outRequestPreMarshal() must be extracted by inRequestPreMarshal(). Unmatched insertions and extractions will corrupt the request buffer and potentially cause a program crash.

When only one filter is being used, its outRequestPostMarshal() method can add piggybacked data that the corresponding inRequestPostMarshal() method, on the called side, does not remove. However this would cause problems if more that one filter was being used.

Ensuring that Unexpected Extra Data is not Passed

When coding a filter that adds extra data to the request, care should be taken not to include this data when communicating with a server which does not expect it. Frequently, a filter should add extra data only if the target object is in one of an expected set of servers.

For example, it will be necessary to include the following code in outRequestPreMarshal() and outRequestPostMarshal() (assuming the Request parameter is r):

The method _ObjectRef._get_implementation() returns the server name of an object reference (in this case, of the target object).

A programmer should be particularly careful not to add data when communicating with the OrbixWeb daemon, IT_daemon. The OrbixWeb classes may communicate with the daemon process, and programmers of filters should ensure that they do not pass extra data to the daemon.

21.3.5 Retrieving the Size of a Request Buffer

Sometimes, the programmer of a filter may wish to obtain the size of a Request, for example in order to display trace information about traffic between OrbixWeb applications. This information can be obtained by invoking the method getMessageLength() as follows:

21.3.6 Defining an Authentication Filter

Verification of the identity of the caller of an operation is a fundamental component of a protection system. OrbixWeb supports this by installing an authentication filter in every process's filter chain. This default implementation transmits the name of the principal (user name) to the server when the channel between the client and the server is first established (by _bind()) and adds it to all requests at the server side. A server object can obtain the user name of the caller by calling the method:

on the _CORBA.Orbix object. The first parameter, of type _ObjectRef, is not used and may be safely assigned the value null.

The default authentication filter can be overridden by declaring a derived class of AuthenticationFilter and creating an instance of this class. For example, an alternative authentication filter may use a ticket based authentication system rather than passing the caller's user name.

On the client side, a derived AuthenticationFilter class should override the outRequestPreMarshal() filter point. If this filter point alters the default behaviour, then the server-side authentication filter point inRequestPreMarshal() must be appropriately overridden in all servers with which the client communicates.

21.4 Per-Object Filters

A pre and/or a post per-object filter can be attached to an individual object of a given IDL type. Consider the following IDL interface:

This may be implemented as follows:

If we have two objects of this type created, as follows:

then we may wish to have pre and/or post filtering on, for example, the specific object referenced by i1. To achieve this, the programmer must define one or more additional classes and additional TIE classes.

To perform pre-filtering, the programmer could define a class, say FilterPre, to have the same methods and parameters as a normal implementation class of the corresponding IDL type, and which inherits from the generated class of the same name as the IDL type:

Similarly, to perform post-filtering, the programmer could define a class, say FilterPost, as follows:

In the examples shown here, a per-object filter cannot access the object it is filtering. A filter can however do this by having a member variable which points to the object it is filtering–and this member can be set up via a constructor parameter for the filter.

To apply filters to a specific object, the following should be done:

Note that it is not always necessary to attach both a pre and a post-filter to an object.

Attaching a pre-filter to an object which already has a pre-filter causes the old filter to be removed and the new one to be attached. The same applies to a post filter.

The methods _attachPre() and _attachPost() return, respectively, the previous pre-filter and post-filter, if any, attached to the object. The methods _getPre() and _getPost() return an object's pre-filter and post-filter, respectively.

To attach a chain of per-object pre-filters to an object, _attachPre() can be used to attach the first pre-filter, and then it can be used again to attach a pre-filter to the first pre-filter, and so on. The same applies to post-filters.

If a per-object pre-filter raises an exception in the normal way, then the actual operation call will not be made. Normally this exception is returned to the client to indicate the outcome of the invocation. However, if the pre-filter raises the exception FILTER_SUPPRESS then no exception is returned to the caller1–the caller cannot tell that the operation call has not been processed as normal.

In the example above, the same filter objects (those pointed to by serverPre and serverPost) could be used to filter invocations to many objects. Other filters, for example a filter holding a pointer to the object it is filtering, can only be used to filter one object.

21.4.1 IDL Compiler Switch to Enable Object Filtering

Per-object filtering can be applied to an IDL interface only if it has been compiled with the -F switch to the IDL compiler. By default, -F is not set, so object level filtering is not enabled.



1 A FILTER_SUPPRESS exception can be raised as follows:



[Roadmap] [Introduction] [GS: Applications] [GS: Applets]
[IDL] [Mapping] [Programming OrbixWeb] [Publishing Objects] [Retrieving Objects] [IIOP]
[Running Clients] [Running Servers] [Exceptions] [Inheritance] [Callbacks] [Contexts]
[API Configuration] [TypeCode] [Any] [DII] [IR] [Filters] [Smart Proxies] [Loaders] [Locators]
[Index]