Previous     Contents     DocHome     Index     Next     
iPlanet Trustbase Transaction Manager 3.0.1 Beta Developer Guide



Chapter 10   Message Handler Example



Introduction

To explain the scope and function of the Standard Message Path features of iTTM, the following sections define all of the requirements and restrictions placed upon users of the Standard Message Path functionality. A number of common questions are answered below.


What is the iTTM Standard Message Path ?

The Standard Message Path is the name given to a class of XML application messaging protocols which conform to the restrictions laid out below. The iTTM product implements a default set of iTTM processing pipeline components which provide a basic level of service to all compliant XML messages. A tool for generating XML message parsing classes and an outline message processing service for deployment in the iTTM platform.


What needs to be in place before the Standard Message Path may be used ?

The most important components which must be in place before starting to produce a Standard Message Path service are the XML messaging protocol and its associated DTD. It is important to have both the message structure definitions (i.e. DTD) and the messaging protocol (i.e. what actions and response messages are provoked by a given request message) defined before trying to create a Standard Message Path service to process the messaging protocol.


What restrictions does the Standard Message Path place on messaging protocols ?

The messaging is defined by DTD's, the Standard Message Path messaging does not prescribe a specific DTD or XML Schema for messages, instead it makes a number of features mandatory for third parties when they are defining their own message structures. Taking this approach allows the consumers of Standard Message Path maximum flexibility in the design of their messaging protocols. The full restrictions are defined below, but can be summarised as:

    •    The messages must contain a transaction identifier' which relates all requests and responses in a messaging exchange.

    •    There must exist an XML DSIG signature as an immediate child of the document rood element. This signature must sign at least one of the messaging elements.

    •    The use of the XML `ID ` attribute type is mandatory for all elements which may need to be inculded in the creation of a signature. The values of these ID attributes take a prescribed format.

    •    All DTD's must be assigned a public identifier, this identifier is unique for each version of the messaging. i.e. revision 2 of a given DTD must have a different identifier to revision 1. This allows multiple versions of messaging to be simultaneously supported.

    •    The mime type of all Standard Message Path compliant messages must adhere to the structure defined below.


What basic functions does the default implementation of the Standard Message Path provide ?

The default iTTM message pipeline components that implement the default Standard Message Path processing behaviour provide the following services to all compliant messages:

   XML Parsing and structural check

   XML message validation against the DTD which defines them, ensuring grammatical correctness

   Logging into a database of the `Raw' XML bytes

   Message signature checking of the mandatory message signature

   Use of the certificate which validates the mandatory signature to establish an authentication level which is then used by the iTTM authorisation component to gate access to the processing service to legitimate requestors only.

The idea of the default components are that they provide enough basic service and message processing semantics that the user need only concentrate on the implementation of the message `payload' processing, leaving the administrative processing to iTTM Standard Message Path components.

  • Which tools are required to create a Standard Message Path service ?

There are a minimum number of tools required to create a Standard Message Path service, these a listed below:

    •    JDK v1.2.x or greater, this contains a Java compiler and the JAR tool for creating the final deliverable.

    •    JAXHIT class generation tool, which is provided by the iTTM installation

    •    An editor for writing Java source code

  • Can the default implementation of the Standard Message Path be changed ?

    The default implementation is designed to produce useful basic set of functions, but sometimes these will need to be augmented for specific application needs. Each of the iTTM Standard Message Path components has been designed to allow for sub-classing which allows specific areas of function to be added, augmented or removed. This includes the basic error handling framework provided by each of the components.


Development Life Cycle

This section defines the development lifecycle of Standard Message Path service, this lifecycle utilises tools that allow basic services to be deployed and tested very quickly. The basic lifecycle is shown below and each stage is further detailed in the following sections.

  1. Design Messaging

  2. Generate Classes and Service descriptor with JAXHIT

  3. Write service Java code

  4. Compile

  5. Make JAR file

  6. Deploy into iTTM

  7. Test service


Design Messaging Structures and Protocols



The most important input to the lifecycle is the design of the messaging structures and protocols. The messaging protocol defines which requests will result in which actions and responses etc. The messaging protocol will be implemented by the `service' Java code written by the developer. The message structures are defined in DTD's which are used as input to the next stage of the lifecycle. This section concentrates on the design of the messaging structures, the protocols are not restrained by the Standard Message Path.

The iTTM Standard Message Path does not prescribe a specific DTD or XML Schema for messages, instead it makes a number of features mandatory for third parties when they are defining their own message structures. Taking this approach allows the consumers of iTTM the maximum flexibility in the design of their messaging protocols, including extending or wrapping existing XML messages in a Standard Message Path compatible form.

The following terms are used in the definition of the messaging rules:

  •    Level 1 element.
    This is used to refer to the top level, or root, XML tag defined for the message.

  •    Level n element.
    This is used to refer to an XML tag that is the child of a level n-1 XML tag, where level 1 represents the top level element.

The following points are all mandatory for any XML message to be deemed iTTM Standard Message Path compliant:

  •    Somewhere in the message structure there must exist a message identifier whose life is as long as the transaction and is globally unique. This message identifier is used by iTTM to relate all the messages in a transaction. If this identifier is not present then the Standard Message Path components will allocate and identifier whose life will be a single request/response message pair. i.e. multi-request transactions will not resume their messaging context.

  •    There must exist an XML DSIG <Signature> element as a level 2 element, this Signature element must comply with the following:

  •    All of the certificates required to verify the signature must be included as children of the signature in the standard DSIG manner. This includes the entire certificate chain from child to root.

  •    The signature must sign at least one element.

  •    The signature must only refer to elements within the current message. e.g. `detached' external document signatures are not allowed.

  •    Must be defined by the DTD included with the iTTM distribution, it has the revision URL of http://www.w3.org/2000/09/xmldsig#. For the purposes of entity inclusion in the application messaging DTD's its public identifier must be: http://www.w3.org/2000/09/xmldsig#. E.g. to include the XML DSIG DTD inside a messaging DTD add the following lines to the top of the messaging DTD and place the XML DSIG DTD supplied in the iTTM distribution in the same directory as the messaging DTD(s):

    <!ENTITY % XMLDSIG.dtd PUBLIC "http://www.w3.org/2000/09/xmldsig#" "./xmldsig.dtd">

    %XMLDSIG.dtd;

  •    Whitespace processing for the purposes of signature generation/validation must be defined by canonicalisation algorithm used in the DSIG signature. Where this algorithm is not prescriptive enough (e.g. DOMHASH), in order to remove ambiguity created by whitespace characters contained between nodes, all non-significant whitespace should be removed prior to signature generation or validation.

  •    Where a messaging protocol contains base 64 encoded elements, the line breaking in the base 64 representation is not prescribed - but for the purposes of signature calculation all whitespace in the encoding is considered significant.

  •    The use of XML ID attributes is mandatory for any element which needs to be signed, the generation of these ID values is critical because the following must be true:

    •    Each ID is unique within a single document

    •    Once a block is signed, the ID may not be changed without invalidating the signature. This is significant if blocks are to be copied from one document to another along with their associated signature.

  • In order to allow all iTTM messages to interoperate and to remove the burden of ID generation from the developer, the following scheme will be used for the generation of ID values when signing a message. This scheme is not mandatory, but any elements that do not have an ID value already assigned before an attempt to generate a signature is made will be completed using this scheme. It would be advisable for all users of iTTM Standard Message Path messaging to adopt this scheme. Each ID value will be constructed from the 3 following elements, in the following order, separated by underscore (`_') characters.

  •    Element Name

  •    A 20 byte securely generated random number, represented as a hexadecimal string, where the most significant byte of the number is the first character, all letters in the number will be uppercase.

  •    To guarantee uniqueness of the ID within the message, a further integer is added as the final component of the ID. The first occurrence of an ElementName will have a value of 1, all subsequent occurrences will be incremented by one. The integer is not mandatory if there is only one occurrence of an element name within a message. If the integer is not present then the final underscore separator is also omitted.

An example for the PingRequest element:

PingRequest_0102030405060708090A0B0C0D0E0F10111213_1 or
PingRequest_0102030405060708090A0B0C0D0E0F10111213

  • All DTD's must be assigned a public identifier, this identifier must identify a particular version of a message definition. i.e. each version of each DTD must be assigned a different public identifier. This ensures that iTTM can easily distinguish different message versions and support multiple message versions simultaneously. The structure for a public identifier is defined to be:
    -//organisation//description//language
    The public identifier is case sensitive and is typically defined all in upper case. There must always be a system identifier defined for a DTD, this must be a valid URL from which the DTD can be fetched. As a further constraint, when a request/response message protocol is defined, the DTD that defines the top-level request element must be the same as the DTD that defines the appropriate response element. Entity inclusion may be used to `import' other DTDs that define sub-ordinate elements.

  •    When sending a message to iTTM, it must have the following mime-type "application/ittm-doctype" where doctype is the XML DOCTYPE of the message in lowercase. That is the element name of the level 1 element in the message. e.g. application/ittm-pingrequest. This mime-type will ensure that the default protocol handler, message reader and message writer process the message along the iTTM Standard Message Path pipeline. If a different mime-type is required then customers will need to override each of the processing pipeline elements to implement their specific mime-type.


Generate Classes and Service descriptor with JAXHIT

The use of this tool is defined in "The JAXHIT Class Generation Tool" of the appendix at the end of this document, the tool can be started with a script called jaxhit which is found in the ...../Trustbase/Scripts directory of the distribution. An example configuration file is described in the Appendix and another example is used in the sample Credit Check application supplied with the distributions and described in a later section of this document.

When using the jaxhit tool, all Standard Message Path messages must have a standard class as their <ElementBase> and must also define a <ServiceConfig>. The example JAXHIT configuration file for the sample CreditCheck application is described below:

<Config

srcDir="src"

basePackage="com.iplanet.trustbase.generated"

build="false">

The first lines define the location of the generated classes and their base Java package root, the build flag is set to flase to stop the JAXHIT tool from trying to compile the generated classes.

<DTDFile file="creditcheck.dtd" publicId="-//IPLANET//ITTM CREDIT CHECK//EN"/>

This next line defines the base DTD files to have classes generated, if a DTD is entity included by a DTD named in a <DTDFile> element, then it will have its classes generated as the tool recurses through all included DTD files. The classpath that is defined when the JAXHIT tool is run is very important, before a class is generated, the classpath is checked to see if a class already exists. This feature allows for library DTD's such as XMLDSIG to be generated just once and then used by many application DTD's. This behaviour can be overridden by using the `force="true"' attribute on the <Config> element. See "The JAXHIT Class Generation Tool" of the appendix at the end of this document.

<DefaultElementBase/>

<ElementBase name="CreditCheckRequest">

<ExtendsClass name="com.iplanet.trustbase.standardpath.message.ITTMMessage"/>

</ElementBase>

<ElementBase name="CreditCheckResponse">

<ExtendsClass name="com.iplanet.trustbase.standardpath.message.ITTMMessage"/>

</ElementBase>

<ElementBase name="CreditCheckError">

<ExtendsClass name="com.iplanet.trustbase.standardpath.message.ITTMMessage"/>

</ElementBase>

The lines above define the three allowable Document Root Elements, it tells JAXHIT that each of the Java classes should extend the existing "com.iplanet.trustbase.standardpath.message.ITTMMessage" class which is delivered as part of the iTTM distribution. If the behaviour of the ITTMMessage class has been overridden by a sub-class (see the `Changing Standard Message Path Default Implementation' section later in this document) then the sub-class should be used in the ExtendsClass attribute. ONLY sub-classes of ITTMMessage are valid in Standard Message Path elements.

<ServiceConfig name="CreditCheckService"

className="com.iplanet.trustbase.standardpath.sample.creditcheck.Cr editCheckService">

<RootElement name="CreditCheckRequest"/>

<RootElement name="CreditCheckResponse"/>

<RootElement name="CreditCheckError"/>

</ServiceConfig>

</Config>

The final lines define the contents of the Standard Message Path service descriptor file, The name of the service is used for authorisation once the service is deployed into iTTM, the class name defines the class that will be executed by iTTM to process the message `payload'. This must implement the `uk.co.jcp.tbase.service.Service' interface (see the next section). Each of the acceptable document root elements is enumerated as a <RootElement>, each of these entries will result in an iTTM routing rule which routes messages with that document type to the named service.

The result of using the jaxhit tool are the following items:

  •    Java Classes
    These classes represent the XML elements defined by the messaging DTD, and are capable of parsing the appropriate message elements (by being called by a SAX parser) and are also capable of validating the parsed elements against their DTD definition.

  •    Service Descriptor
    A properties file that defines the name of the service, the main class that implements the service and the list of XML document types that the service will process.


Write service Java code

This is the Java code which acts upon the incoming message, processes the content and generates the `payload' for the response message. The service class must implement the `uk.co.jcp.tbase.service.Service' interface. A skeleton service class is shown below and a small but complete service is provided with the credit check sample in the distribution.

package com.test.package;

import uk.co.jcp.tbase.service.Service;

import uk.co.jcp.tbase.service.ServiceException;

import uk.co.jcp.tbase.environment.Message;

import com.iplanet.trustbase.standardpath.message.ITTMMessage;

import com.iplanet.trustbase.standardpath.util.ITTMUtil;

import com.iplanet.trustbase.standardpath.util.ITTMConstants;

import uk.co.jcp.tbase.environment.attribute.Attribute;

import uk.co.jcp.tbase.environment.attribute.AttributeList;

import uk.co.jcp.tbase.environment.attribute.AttributeConstants;

import com.iplanet.trustbase.xml.message.TbaseIdentifiedElement;

import com.iplanet.trustbase.xml.message.TbaseElement;

import com.iplanet.trustbase.xml.message.TbaseElementException;

import uk.co.jcp.tbaseimpl.log.error.ErrorLog;

import uk.co.jcp.tbaseimpl.log.error.ErrorObject;

import java.rmi.RemoteException;

import java.io.IOException;

public class A_Service implements Service

{

   /** See parent class

*/

public Message process( String serviceName, Message message )

throws ServiceException, RemoteException

{

      // Get the content and de-serialize it

      ITTMMessage request = null;

ITTMMessage response = null;

      try

      { request = (ITTMMessage)ITTMUtil.deserializeMessageContent( message );   }

      catch ( IOException iox )

      {

ErrorObject error = new ErrorObject( "AAA0001",iox );

         ErrorLog.log( error );

      }

      catch ( ClassNotFoundException cnfx )

      { ErrorObject error = new ErrorObject ( "AAA0002", cnfx );

         ErrorLog.log( error ); }

      catch (ClassCastException ccx)

      { ErrorObject error = new ErrorObject ( "AAA0003", ccx);

         ErrorLog.log( error ); }

      response = processITTMMessage(request);

// Set the ReturnToUser attribute to signal to the router that the

// message is to be sent back to the user

message.getAttributes().addAttribute(new Attribute("ReturnToUser", "true", null));

// Remove he Request message DOC_TYPE attribute and replace it with

// the correct Response message DOC_TYPE

message.getAttributes().removeAttributes( ITTMConstants.DOC_TYPE );

message.getAttributes().addAttribute(new Attribute( ITTMConstants.DOC_TYPE,( (TbaseElement) response ).elementName(), null ) );

// Serialize the content into the TBASE message

ITTMUtil.serializeMessageContent( message, response );   return message;}

}:

The above skeleton service implementation provides for a call to `processITTMMessage(....)' which takes the Java object tree that represents the request and processes it to produce a response message. Reading the Java API documentation for ITTMMessage and its associated classes will provide an insight into what sort of operations can be performed on the request. It must also be remembered that `request' can be cast down into the actual message type class e.g. CreditCheckRequest, there are a number of different abstractions that may apply to a given generated class. Generating Java API documentation for the generated classes will help to provide a better understanding of the make up of each message class.


Compile



Any Java compiler is acceptable for the generation of Standard Message Path classes, it is recommended that the chosen compiler be 1.2.x compliant, all examples in this document assume that the JDK from JavaSoft is being used.


Make JAR file



Any Java compliant JAR tool is acceptable, all examples in this document assume that the JDK from JavaSoft is being used.


Deploy into iTTM



Deploying a the new service into iTTM is as simple as copying the final JAR file into the /opt/ittm/current/deploy directory and then logging on to iTTM as administrator and use the <Services> <Deployment> menu option. If the service already exists then uninstall the old version before installing the new version. If the new service is not visible, then the service JAR file is probably incorrectly constructed.


Changing the Standard Message Path Default Implementation



The basic ITTMProtocolHandler, ITTMMessageReader and ITTMMessageWriter provide a default implementation that will be adequate for most purposes, but each of these classes has been designed to allow partial or total rewrite of their functionality via sub-classing. The following sections define the control flows and methods which may be overridden to change the behaviour of the standard pipeline for specific message types.


Base Message Class ITTMMessage

The base com.iplanet.trustbase.standardpath.message.ITTMMessage class must be the base class of all root document elements in a messaging DTD, it implements all of the generic message signature creation and validation function. A message may be signed and verified as an opaque entity (i.e. without a semantic understanding of its `payload'). If this class is sub-classed and the sub-class is used as the base class for root document elements then the basic signature and verification behaviour may be affected.

  1. Overridable Methods

  2.    getElementsToSign()
    This method returns the elements of the XML message which must be signed in the signature.

  3.    getMessageRootElementName()
    Gets the name of the XML root element of this iTTM message

  4.    getSigningCertificate()
    Get the child certificate which validates the message signature

  5.    getSigningChains()
    Get all of the signing chains that validate the message signature - normally this will only be a single chain, but in a cross-signed PKI it may be multiple chains

  6.    getValidatingTokenKeyStore()
    Establish which TokenKeyStore a.k.a. Trust Domain

  7.    getXmlSignature()
    Get the mandatory level 2 DSIG signature

  8.    setXmlSignature(...)
    Set the signature on the message, this will overwrite any signature that may currently be associated with the message

  9.    signMessage(...)
    Create the mandatory level 2 signature and set it into the message.

  10.    traverseTreeAndSetIds(...)
    Traverse the XML message tree and set all ID attributes in elements to a value if they are not already set.

  11.    validateSignature(java.util.Date atDate)
    Validate the mandatory level 2 signature, using the appropriate trust domain.


Protocol Handler

The protocol handler (com.iplanet.trustbase.standardpath.protocol.ITTMProtocolHandler) is the first component in the incoming messaging pipeline and it can be sub-classed to change its behaviour. The control flow sections defines which methods are called in which order, allowing scope for changing the specific methods whilst leaving the control flow untouched.


Control Flow

The basic ITTM message processing pipeline provides an implementation of a protocol handler that accepts wild card mime types beginning with application/ittm-. This default handler performs the following functions in the following order, method names for each function are specified:

  •    readRawXML(...) - Read the Raw XML from the stream into an array.

  •    checkInputLength(...) - Check input length read in against the content specified length.

  •    preProcessXML(...) - Call a raw bytes pre-processing function. The default implementation performs no function here, it is an override point.

  •    getXMLEncodingIdentifier(...) - Extract the XML character encoding identifier from the raw bytes. The default implementation performs no function here, it is an override point.

  •    parseXmlMessage(...) - Use the class generator message factory to XML parse the message and create the internal object tree representation of the message which is made up of classes created by the Class Generator tool. Apart from structural XML encoding, no validation of the message occurs at this point.

  •    validateXmlMessage(...) - Validate the message, this validation checks that the message is structurally compliant with the DTD that describes it.

  •    rawLog(...) - Raw log the complete message string, this will result in a unique raw log identifier being returned to the protocol handler. This unique identifier is added as a iTTM attribute ITTMConstants.RAW_LOG_ID to the message, this enables other stages of message processing to relate their storage back to the original raw log record for the message.

  •    setContextId(...) - Extract a unique identifier from the message for use as an TTM external context identifier this identifier is very important in multiple request message protocols, it allows a context to be stored in TTM which lives longer than just the first request/response pair. It is a requirement of a compliant iTTM message that this identifier is present in all messages, although its form and location are not specified. The default implementation of this will generate a random identifier whose life will be one request/response pair, thus precluding any multiple message protocols.

  •    setDocType(...) - Set the ITTMConstants.DOC_TYPE attribute in the iTTM message with the DOCTYPE of the XML message.

  •    Set the iTTM message type to be IITMConstants.ITTM_MESSAGE_TYPE.


Overridable Methods

  •    checkInputLength(...)
    Check that the input length of the raw XML message matches the expected message content length

  •    getContentTypes()
    Get content types recognized by the ProtocolHandler.

  •    getRawLogStoreName()
    This returns the name of the raw log that will be used to store the message, by default this is the 'identrus' raw log

  •    getXMLBytes(...)
    To allow i18n, convert a Unicode string into raw XML bytes in a known character encoding

  •    getXMLEncodingIdentifier(...)
    Returns a java character encoding string for the message

  •    getXMLString(...)
    To allow i18n, convert raw XML bytes in a known character encoding into a Unicode string

  •    handle(...)
    Extract the Message type, determine response content type, and create an execution environment for the Message

  •    parseXmlMessage(...)
    Parse the XML message into the Java object tree and checks that the message is XML compliant structurally.

  •    preProcessXML(...)
    Before the XML is parsed this method is called to allow any pre-processing of the raw message bytes.

  •    processParsingException(...)
    An exception occurred whilst reading/parsing the XML, this does not include DTD validation

  •    processProcessingException(...)
    An exception has ocurred in the general processing of the XML message, e.g.

  •    processRawLoggingException(...)
    An exception occurred whilst trying to Raw log the XML

  •    processUnspecifiedException(...)
    An general exception has occurred

  •    processValidationException(...)
    An exception occurred whilst validating the incoming XML message against its DTD

  •    rawLog(...)
    Log the content of the TbaseElement into the database.

  •    readRawXML(...)
    Read raw XML message from the InputStream into the byte array.

  •    setContextId(...)
    This method sets the context id of the message.

  •    setDoctype(...)
    Set the DOCTYPE attribute in the iTTM message based on the DOCTYPE of the Xml message

  •    validateXmlMessage(...)
    Validate the message against its original DTD.


Error Handling

All errors in the main control flow are caught, error logged and then one of the process....(...) methods is called, to allow a point where error handling behaviour may be changed by sub-classing. There is an example of this sub-classing in the Credit Check Sample that is supplied with the distribution.

The protocol handler error processing methods need to return a ProtocolHandlerException, if this exception has been constructed with a response message bytes and response mime-type, then the response message is returned to the user without further processing. If no response message bytes are provided then an HTTP level error is returned on the connection e.g. FileNotFound.


Message Reader

The message reader (com.iplanet.trustbase.standardpath.message.ITTMMessageReader) is the final component in the incoming messaging pipeline and it can be sub-classed to change its behaviour. The control flow sections defines which methods are called in which order, allowing scope for changing the specific methods whilst leaving the control flow untouched.


Control Flow

A MessageReader parses the content of a Message from an InputStream. MessageReader may be a part of an application, and have specific knowledge of Message types, or they may be general purpose and have general knowledge of Message formats.

The basic ITTM message processing pipeline provides an implementation of a message reader that accepts wild card mime types beginning with application/ittm- and a message type of ITTMConstants.ITTM_MESSAGE_TYPE. This default handler performs the following functions in the following order, method names for each function are specified:

  •    Default implementation accepts wild card mime types beginning with 'application/ittm-' and a message type of ITTM_MESSAGE (defined by ITTMConstants.ITTM_MESSAGE_TYPE)

  •    Deserialise the XML message structure from the iTTM message

  •    Set the 'security.role' attribute to be 'unset'

  •    checkXMLSignature(...) - Check the mandatory iTTM message signature applied to the message, this includes certificate chain checks at the current date and that the root of the chain is trusted in a single domain.

  •    processSignature(...) - This is a hook to allow further signature processing to be added in a child class. The default implementation does nothing in this method.

  •    setTrustDomain(...) - This sets the ITTMConstants.PKI_IDENTIFIER attribute to be the name of the trust domain into which the message validated. This sets a trust domain context for all further crytographic operations on this message, including the signing of the response.

  •    setSecurityContext(...) - This method sets the message attributes which allow the authorisation component of iTTM to determine the authentication level of the message. This adds a number of attributes to the message, two for each certificate in the validating certificate chain. These are an attribute named SecurityContext.CERTIFICATE_DN+"."+counter, whose value is set to the issuer dn of the certificate at position 'counter' in the chain. 'counter' is 1 based, child certificate first. For each of these attributes there is also an attribute named SecurityContext.CERTIFICATE_SN+"."+counter, whose value is the serial number of the certificate at position 'counter' in the chain.

  •    doBilling(...) - This method provides a hook point for child classes to implement a billing stage in the message processing. The default method implementation does nothing.

  •    Serialise the XML message structure into the iTTM message ready to be routed to a service.


Overridable Methods

  •    checkXMLSignature(...)
    This method checks the mandatory level 2 XML signature on the message, including checking the certificate chain is valid at todays date and that its root certificate exists in one and only one trust domain.

  •    doBilling(...)
    Provide access the billing system to perfrom billing for the processed message.

  •    getTypeAndFormats()
    get a list of the Message types and formats supported by this MessageReader.

  •    processIncompleteCertChain(...)
    The certificate chain for validating the message signature was not supplied and could not be re-created from the certificates in the TokenKeyStore

  •    processInvalidCertChain(...)
    The certificate chain used to validate the message is invalid, signatures maybe corrupt or certificates may be out of the valid date range

  •    processInvalidSignature(...)
    Called if the mandatory level 2 signature check fails, this indicates that the message or signature has been tampered with.

  •    processProcessingException(...)
    An exception occurred during the processing of the mandatory level 2 signature

  •    processSignature(...)
    Allow further processing of the message signature such as the OCSP check, the default implementation of this method does nothing.

  •    processSignatureTrustFailure(...)
    Called if the root certificate in the mandatory level 2 signature certificate chain doesn't exist in any trust domain or if it exists in more than one domain.

  •    processUnspecifiedException(...) A general exception occurred during the processing of the message

  •    read(...)
    parse the content of a Message from the InputStream

  •    setSecurityContext(...)
    Set certificate chain attributes on the iTTM message, in preparation for the authorisation stage to check the authentication level of the message.

  •    setTrustDomain(...)
    Set the private key identifier to the ITTMConstants.PKI_IDENTIFIER message attribute.


Error Handling

All errors in the main control flow are caught, error logged and then one of the process....(...) methods is called, to allow a point where error handling behaviour may be changed by sub-classing. There is an example of this sub-classing in the Credit Check Sample that is supplied with the distribution.

The message reader error processing methods need to return a MessageReaderException, if this exception has been constructed with a response message, then the response message is returned to the user via the appropriate (based on the value of the message type and mime-type) message writer. If no response message is provided then an HTTP level error is returned on the connection e.g. FileNotFound.


Message Writer

The message writer (com.iplanet.trustbase.standardpath.message.ITTMMessageWriter) is the only component in the outbound messaging pipeline and it can be sub-classed to change its behaviour. The control flow sections defines which methods are called in which order, allowing scope for changing the specific methods whilst leaving the control flow untouched.

The ITTMMessageWriter component implements the DirectionalMessageWriter interface which is derived from the more generic MessageWriter interface. The ITTMMessageWriter component handles messages with mime types beginning with 'application/ittm-' ie ITTMMessages. It specifically handles messages whose type is either: ITTMConstants.ITTM_MESSAGE_TYPE or ITTMConstants.ITTM_AUTH_ERROR_MESSAGE_TYPE. The ITTMMessageWriter signs the outbound XML message using the XML DSIG profile specified for ITTMMessage, it then does an XML validation of the message, logs it and writes it to the client stream.

  •    Default implementation accepts wild card mime types beginning with 'application/ittm-'

  •    Check to see if the message is an authorisation failure, i.e. if its message type is set to ITTMConstants.ITTM_AUTH_ERROR_MESSAGE_TYPE - if so then call processAuthorisationError(...)

  •    Deserialise the XML message structure from the iTTM message

  •    checkDoNotSignAttribute(...) - Check for the existence of the ITTMConstants.ITTM_DO_NOT_SIGN message attribute, if this is present then don't sign the message. It must be noted that if the attribute is present but no signature element is on the message then it will fail XML validation before it is sent out.

  •    getSigningChain(...) & getSigningKey(...) - Create a message signature structure and add it to the message, always overwrite any existing structure in the default implementation. The XML DSIG profile used by the default implementation will use reference objects for all level 2 elements except the signature - these references will be bare-name x-pointers. Select a private key which has an attribute of ITTMConstants.ITTM_SIGNING_KEY associated with, or if the iTTM message attribute ITTM_SIGNING_KEY_ATTRIBUTE is present then select a private key with the named attribute. Use the iTTM message attribute ITTMConstants.PKI_IDENTIFIER to retrieve the trust domain name for the signing key to be used.

  •    Call an XML validation on the outbound message - check that it complies with its DTD.

  •    getXMLEncodingIdentifier(...) - Get the XML encoding identifier

  •    addDocType(...) - Set the DOCTYPE of the message, along with its system identifier (which can be extracted from XML_SYSID iTTM message attribute).

  •    rawLog(...) - Raw log the response message - passing in the original request raw log identifier (iTTM Message attribute RAW_LOG_IDENTIFIER). Using the message attribute will allow multiple message protocols to have all of their message related back to the original request - except in the case where no implementation has been provided for extracting an external context identifier.

  •    Set the mime-type of the response message.

  •    getXMLBytes(...) - Get the XML bytes and write to client stream.


Overridable Methods

  •    addDocType(...)
    Add tag to the message, identifying the public and system identifiers of the document.

  •    checkDoNotSignAttribute(...)
    Checks for existence of ITTMConstants.ITTM_DO_NOT_SIGN message attribute

  •    getContentType(...)
    Gets the actual mime-type to assign to data to a Message to be translated to an OutputStream by a call to write().

  •    getRawLogStoreName()
    This returns the name of the raw log that will be used to store the message, by default this is the 'identrus' raw log

  •    getSigningChain(...)
    Retrieve the chain to be used for validation of the XML signature which will be added to the document.

  •    getSigningKey(...)
    Retrieve the private key to be used for signing the XML document

  •    getTypeAndFormats()
    Gets a list of the Message types and formats supported by ITTMMessageWriter.

  •    getXMLBytes(...)
    To allow i18n, convert a Unicode string into raw XML bytes in a known character encoding

  •    getXMLEncodingIdentifier(...)
    Returns a java character encoding string for the message

  •    getXMLString(...)
    To allow i18n, convert raw XML bytes in a known character encoding into a Unicode string

  •    processAuthorisationFailureException(...)
    Called if there was an authorisation failure in the router whilst attempting to process the original request.

  •    processKeyStoreException(...)
    Called if there is a problem recovering the signing key or certificate chains from the stores

  •    processProcessingException(...)
    Called if there is a problem in the general processing of the response message

  •    processRawLoggingException(...)
    Called if there is a problem writing the response message to the raw log

  •    processSignatureCreateException(...)
    Called if there is a problem generating the mandatory level 2 signature structure for the response message

  •    processUnspecifiedException(...)
    A general exception occurred during the processing of the message

  •    rawLog(...)
    Raw Logs the response XML bytes into the Database

  •    write(...)
    Translates a Message to an external format, and write to an OutputStream


Error Handling

All errors in the main control flow are caught, error logged and then one of the process....(...) methods is called, to allow a point where error handling behaviour may be changed by sub-classing. There is an example of this sub-classing in the Credit Check Sample that is supplied with the distribution.

The message writer error processing methods need to set the content of the iTTM message to be the message to be returned. This message content is then written directly to the return stream by the error processing method. If no response message is written to the output stream and instead a MessageWriterException is thrown, then an HTTP level error is returned on the connection e.g. FileNotFound


Example Application




The Example Credit Check Messaging Protocol

The example messaging protocol will implement a very simple credit check function between a merchant and his bank, regarding the customer. The messaging will be supported by a very simple PKI that can be easily extended to interoperate with another bank.


Public Key Infrastructure

The standard 3 party transaction need only have the following very simple PKI:

This PKI has certificates for the following specific uses:

  1. Bank 1 Root is only for issuing other certificates, this certificate is available to all customers and merchants.

  2. Customer 1 of Bank 1 certificate is used to verify all signatures made by that customer, the private key remains in the possession of the customer, who signs requests and presents this certificate for the recipient to validate the requests.

  3. Merchant 1 of Bank 1 certificate is used to verify all signatures made by that merchant. The merchant only ever sends requests to his associated bank, all of these requests must be signed by the merchant's private key.

  4. Bank 1 Bank certificate is used when bank 1 contacts any other bank or any of its merchants.


Message Protocol

The basic 3 party model is described below




Three Party Variant

The three party variant of the transaction is defined by the following sequence of messages and occurs when the customer in the transaction is a customer of Bank 1 (i.e. it has a certificate issued by Bank 1).

  1.    This message would normally be a set of request parameters together with a PKCS#7 signature, generated by a smartcard signing plug-in. The request parameters are signed using the C1B1 private key and the C1B1 certificate and B1Root certificate are included in the PKCS#7 and the whole lot is sent to the merchant web-server.

  2.    This message would be generated by the merchant once the merchant has examined the request parameters and verified the PKCS#7 signature. The merchant would then generate a CreditCheckRequest message to be sent to Bank 1, asking for a credit rating for customer C1B1. This message contains the C1B1 certificate and is signed by the M1B1 private key.

  3.    This message would be generated by the bank once the bank has done the following:

    1.    Verify the signature of M1B1 on the CreditCheckRequest. If the signature check fails then a CreditCheckError message is returned with the status of `signature_fail'.

    2.    Verify the certificate status of M1B1 certificate with its local OCSP responder. If the certificate is revoked or its status is unknown then a CreditCheckError message is returned with a status of `certificate_invalid'.

    3.    Check that M1B1 is authorised to make CreditCheckRequests. If the merchant is not authorised to make a CreditCheckRequest then a CreditCheckError message is returned with the status of `unauthorised'

    4.    The Customer Certificate contained in the CreditCheckRequest is extracted and examined. If this certificate was issued by this bank then a local OCSP responder check is made to establish if the certificate is still valid. If the certificate status is revoked or unknown then a CreditCheckResponse message is returned with a CreditRating of `Unknown'.

    5.    Once this has passed then a call to an external credit reference database is made to establish the rating of the customer. The credit rating is returned in a CreditCheckResponse Message containing the appropriate CreditRating.

    6. The returned message (CreditCheckError or CreditCheckResponse) is always signed with the BB1 private key.

  4. This message is merchant specific and is based on the credit rating received by the merchant from his bank. This message is only sent once the merchant has verified the bank signature on the response message and is satisfied that the message can be traced back to the B1Root certificate that the merchant implicitly trusts.


Message Definition

This section contains the DTD's that describe the credit check messaging. These DTD's may be used by the iTTM Class Generator to create the message parsing classes for the implementation.

The construction of the messages should be self-explanatory if the DTD is read in conjunction with message protocol definition, but a few extra notes about message construction:

  •    The txid attribute in the TxBlock of the message should be the same for all messages associated with a given transaction. This txid would be generated by the merchant and would remain with all messages. This txid can also be used by iTTM as an external context identifier. Although, this message protocol does not require the use of contexts within iTTM that last longer than a single request/response pair.

  •    The ClientCertificate is optional is the CreditCheckResponse, it may be useful to return this so that credit ratings can be easily cached against certificates. It may also be useful if a CreditCheckResponse is being contained within another protocol that may require access to the certificate that was used to get the credit rating.

  •    The ClientCertficate element contains a base 64 encoded X.509 certificate.

  •    The construction of the signature element can be done in any number of ways providing it adheres to the basic requirements of iTTM standard messaging.

  • The vendorcode attribute of the ErrorInfo element is there to allow a vendor to attach a specific reason code to a failure.

The Following is the full DTD for this example

<!--PUBLIC ID for this DTD is: "-//IPLANET//ITTM CREDIT CHECK//EN"-->

<!ENTITY % XMLDSIG.dtd PUBLIC "http://www.w3.org/2000/09/xmldsig#" "./xmldsig.dtd">

%XMLDSIG.dtd;

<!ELEMENT CreditCheckRequest ( TxBlock, Signature, ClientCertificate )>

<!ATTLIST CreditCheckRequest

   id ID #REQUIRED>

<!ELEMENT CreditCheckResponse ( TxBlock, Signature, CreditRating, ClientCertificate? )>

<!ATTLIST CreditCheckResponse

   id ID #REQUIRED>

<!ELEMENT CreditCheckError (TxBlock, Signature, ErrorInfo )>

<!ATTLIST CreditCheckError

   id ID #REQUIRED>

<!ELEMENT TxBlock EMPTY>

<!ATTLIST TxBlock

   id ID #REQUIRED

   txid CDATA #REQUIRED

   txtime CDATA #REQUIRED>

<!ELEMENT ClientCertificate (#PCDATA)>

<!ELEMENT CreditRating EMPTY>

<!ATTLIST CreditRating

   id ID #REQUIRED

   rating ( AAA | AA | A | B | C | D | Unknown ) #REQUIRED>

<!ELEMENT ErrorInfo EMPTY>

<!ATTLIST ErrorInfo id ID #REQUIRED

   errorCode ( unparsable_content | unknown_dtd | signature_fail | certificate_invalid | unauthorized | unspecified_error ) #REQUIRED

   vendorcode CDATA #IMPLIED>


Building & Installing the Example

The following instructions assume that you are using a Bourne Shell or derivative, and that you have a JDK (at least v1.2.2) installed.

  1.    From the Trustbase installation directory change into the Scripts sub-directory:

    cd Scripts

  2.    Set the shell CLASSPATH environment variable to include all of the iTTM libraries

    . ./setcp

  3.    Change directory into the Credit Check Sample resource directory

    cd ../samples/creditcheck/resources

  4.    Generate the classes from the creditcheck.dtd file, using the JAXHIT tool

    ../../../Scripts/jaxhit -config CreditCheckExample.xml -y

  5.    Change directory to the parent directory and compile the generated classes

    cd ..

    javac -d build src/com/iplanet/trustbase/generated/IPLANET/ITTM_CREDIT_CHECK/*.jav a

  6.    Compile the credit check sample classes

    javac -d build -classpath $CLASSPATH:build src/com/iplanet/trustbase/standardpath/sample/creditcheck/*.java

  7.    Build all of the classes and the service descriptor file (build/config/tbasesvc.properties) into a JAR file which can be deployed into iTTM.

    jar -cvf creditchecksample.jar -C build com -C build config

  8.    Make the new service JAR file available for deployment in iTTM

    cp creditchecksample.jar ../../current/deploy

  9.    Install the additional error codes that the sample uses into the iTTM error database. This is done by executing the SQL script resources/credit_check_error_codes.sql against the database and user that iTTM uses.

  10.    Log on to iTTM as administrator and use the service deployment tool to deploy the service, using the <Services ><Deployment> menu option.

  11.    Change directory to the directory which contains the iTTM scripts, redefine the CLASSPATH environment variable to include the newly added creditcheck JAR using the setcp script.

    cd ../../Scripts

    . ./setcp

  12.    Stop iTTM

    ./stopias

  13.    Use the token key tool to mark one of the existing private keys as suitable for use by the Standard Message Path components to use to sign outbound messages.

    ./runtokenkeytool

    > listkeys

    > addalias -newalias ITTM_SIGNING_KEY -issuer "...issuer_dn..." -serial serial_number

    > quit

  14.    Start iTTM

    ./startias

  15.    Execute the test client which will submit a valid credit check request message to iTTM, the command line below assumes that you are running on a machine called foo.bar.com and that you have a key store password of `a_password'. The java code for this client is available in the ../samples/creditcheck/src tree. This will result in an error, because the certificate used to sign the message is not one of those authorised to use the new Credit Check Service - no authorisation entries have been made yet.

    java com.iplanet.trustbase.standardpath.sample.creditcheck.CreditCheckCl ient -url http://foo.bar.com/NASApp/NASAdapter/TbaseNASAdapter -domainuri file:../foo -password a_password -trustdomain identrus

  16.    The result of the previous step is an HTTP level error (FileNotFound), this is the behaviour of the default Standard Message Path Components. This HTTP level error is not normally acceptable for a messaging protocol, most protocols will define an error message which provides the client with a more acceptable response. As part of the CreditCheck sample messaging, a response message type of CreditCheckError is supposed to be returned under error conditions. In order to meet this requirement a new protocol handler, message reader and message writer will need to be installed to override the error handling behaviour of the default standard message path equivalents. Implementations of these can be found in ../samples/creditcheck/src, they are installed by logging on to iTTM as administrator and selecting the <Parser> <Configuration> menu option. Add the following entries in the three sub sections of the configuration screen:

    1. Message Readers, add an entry in Name: CreditCheckMessageReader, add entry in class: com.iplanet.trustbase.standardpath.sample.creditcheck.CreditCheckMessageReader, press the Add button.

    2. Message Writers, add an entry in Name: CreditCheckMessageWriter, add entry in class: com.iplanet.trustbase.standardpath.sample.creditcheck.CreditCheckMessageWriter, press the Add button.

    3. Protocol Handlers, add an entry in Name: CreditCheckProtocolHandler, add entry in class: com.iplanet.trustbase.standardpath.sample.creditcheck.CreditCheckProtocolHandler, press the Add button.

    Press the Submit button to commit all of the changes to iTTM.

  17.    Restart iTTM to apply the configuration changes

    ./stopias

    ./startias

  18.    Re-run the client tool as described in step 15. This time a properly formed, XML DSIG signed CreditCheckError message is returned and displayed on the screen.

  19.    The final stage is to add an authorisation for the message, so that it can be legitimately routed to the CreditCheckService that has been written. In order to authorise the message, three configurations need to be added. This configuration is done by logging on to iTTM as administrator.

A role into which credit check requests may be authenticated, select <Authorisation> <Add Role> menu option and add a new role, with a description, leaving the Active checkbox ticked.


A service authorisation entry which maps access to the CreditCheckService to any client that authenticates into the newly defined role, select <Authorisation> <Add Service> menu option. complete the form, it is important to make sure that the service name is exactly right, the service name can be discovered by looking at the `Service' entry shown on the Services Deployment screen, for the example this is CreditCheckService (case is important).

A certificate authentication entry, which maps any client whose XML DSIG signature can be verified by the named certificate into the newly defined role, select <Authorisation> <Add Certificate>. Entries made on this form describe a certificate in the PKI from which this authentication will occur, this may be an individual child certificate or at the other end of the scale it may be a root certificate. The Issuer DN is an RFC2253 formatted name string and the serial number is a decimal version of the certificate serial number. These two pieces of information can be displayed about any certificate in the PKI using the tokenkeytool (see step 13). The maximum depth indicates the number of child levels below the described certificate that will be authenticated by this entry, this allows a root certificate to be entered and then restrict the depth of allowable child certificates. For the example, an entry for the root certificate can be made with the correct depth to include the certificate which signs the request message (The one marked with the ITTM_SIGNING_KEY alias in step 13). The role must be set to the newly defined role, and the access checkbox should be left checked. Press the Add button and then press the Submit button.

  1.    Restart iTTM to apply the configuration changes

    ./stopias

    ./startias

  2.    Re-run the client tool as described in step 15. This time a properly formed, XML DSIG signed CreditCheckResponse message is returned and displayed on the screen.


Previous     Contents     DocHome     Index     Next     
Copyright © 2001 Sun Microsystems, Inc. Some preexisting portions Copyright © 2001 Netscape Communications Corp. All rights reserved.

Last Updated October 31, 2002