3 Stepping Through Sample Custom Assertions

This chapter describes sample custom assertions. It includes the following sections:

3.1 Overview

This chapter describes some sample custom assertions and provides sample code for each custom assertion. Each sample also includes a section that describes the key features that are implemented in the sample.

3.2 IP Address Validation Custom Assertion Sample

The IP Validation Custom Assertion sample validates whether a request that is made to the Web service is from a set of valid IP addresses. In the custom policy assertion you can include the valid IP addresses as a comma-separated list of values. Any request coming from any other IP address results in a FAILED_CHECK response.

The following sections provide samples that demonstrate how to code the custom assertion:

3.2.1 Code Samples

This section includes the following sample codes to create and implement the custom assertion:

Sample Custom Assertion Executor

Example 3-1 provides a sample custom assertion executor that you can use to validate the IP address.

Example 3-1 Sample Custom Assertion Executor

package sampleassertion;
 
import oracle.wsm.common.sdk.IContext;
import oracle.wsm.common.sdk.IMessageContext;
import oracle.wsm.common.sdk.IResult;
import oracle.wsm.common.sdk.Result;
import oracle.wsm.common.sdk.WSMException;
import oracle.wsm.policy.model.IAssertionBindings;
import oracle.wsm.policy.model.IConfig;
import oracle.wsm.policy.model.IPropertySet;
import oracle.wsm.policy.model.ISimpleOracleAssertion;
import oracle.wsm.policy.model.impl.SimpleAssertion;
import oracle.wsm.policyengine.impl.AssertionExecutor;
 
public class IpAssertionExecutor extends AssertionExecutor {
 
    public IpAssertionExecutor() {
    }
 
    public void destroy() {
    }
 
    public void init(oracle.wsm.policy.model.IAssertion assertion,
                     oracle.wsm.policyengine.IExecutionContext econtext,
                     oracle.wsm.common.sdk.IContext context) {
        this.assertion = assertion;
        this.econtext = econtext;
    }
 
    public oracle.wsm.policyengine.IExecutionContext getExecutionContext() {
        return this.econtext;
    }
 
    public boolean isAssertionEnabled() {
        return ((ISimpleOracleAssertion)this.assertion).isEnforced();
    }
 
    public String getAssertionName() {
        return this.assertion.getQName().toString();
    }
 
    /**
     * @param context
     * @return
     */
    public IResult execute(IContext context) throws WSMException {
        try {
         oracle.wsm.common.sdk.IMessageContext.STAGE stage =
 ((oracle.wsm.common.sdk.IMessageContext)context).getStage();
 
            if (stage  == IMessageContext.STAGE.request)  {    
 

               IAssertionBindings bindings =
 ((SimpleAssertion)(this.assertion)).getBindings();
               IConfig config = bindings.getConfigs().get(0);
               IPropertySet propertyset = config.getPropertySets().get(0);
               String valid_ips = propertyset.getPropertyByName("valid_
ips").getValue();
               String ipAddr = ((IMessageContext)context).getRemoteAddr();
               IResult result = new Result();
 
               if (valid_ips != null && valid_ips.trim().length() > 0) {
                    String[] valid_ips_array = valid_ips.split(",");
                    boolean isPresent = false;
                    for (String valid_ip : valid_ips_array) {
                      if (ipAddr.equals(valid_ip.trim())) {
                          isPresent = true;
                      }
                    }
                    if (isPresent) {
                       result.setStatus(IResult.SUCCEEDED);
                    } else {
                       result.setStatus(IResult.FAILED);
                       result.setFault(new WSMException(WSMException.FAULT_FAILED
_CHECK));
                    }
               } else {
                result.setStatus(IResult.SUCCEEDED);
               }
               return result;
          }
        } catch (Exception e) {
            throw new WSMException(WSMException.FAULT_FAILED_CHECK, e);
        }
    }
 
    public oracle.wsm.common.sdk.IResult
 postExecute(oracle.wsm.common.sdk.IContext p1) {
        IResult result = new Result();
        result.setStatus(IResult.SUCCEEDED);
        return result;
    }
}

Sample Policy File

Example 3-2 describes a sample policy file.

Example 3-2 Sample Policy File

<?xml version = '1.0' encoding = 'UTF-8'?>
<wsp:Policy xmlns="http://schemas.xmlsoap.org/ws/2004/09/policy"
 xmlns:orasp="http://schemas.oracle.com/ws/2006/01/securitypolicy"
orawsp:status="enabled"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-uti
lity-1.0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" orawsp:category="security"
 orawsp:attachTo="binding.server" wsu:Id="ip_assertion_policy"
xmlns:orawsp="http://schemas.oracle.com/ws/2006/01/policy"
 xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
wsp:Name="oracle/ip_assertion_policy">
           <orasp:ipAssertion orawsp:Silent="true" orawsp:Enforced="true"
 orawsp:name="WSSecurity IpAsertion validator"
 orawsp:category="security/authentication">
               <orawsp:bindings>
                    <orawsp:Config orawsp:name="ipassertion"
 orawsp:configType="declarative">
                         <orawsp:PropertySet orawsp:name="valid_ips">
                               <orawsp:Property orawsp:name="valid_ips"
 orawsp:type="string" orawsp:contentType="constant">
                                    <orawsp:Value>140.87.6.143,10.178.93.107</orawsp:Value>
                                </orawsp:Property>
                         </orawsp:PropertySet>
                     </orawsp:Config>
               </orawsp:bindings>
            </orasp:ipAssertion>
</wsp:Policy>

Sample policy-config.xml

Example 3-3 demonstrates how to use the policy-config.xml file to specify the custom assertion executor. You can also use the custom policy to specify the custom policy executor, as described in Section 2.2.3, "Step 3: Specify the Custom Assertion Executor".

Example 3-3 Sample policy-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<policy-config>
    <policy-model-config>
      <entry>
        <key namespace="http://schemas.oracle.com/ws/2006/01/securitypolicy"
 element-name="ipAssertion"/>
        <executor-classname>sampleassertion.IpAssertionExecutor</executor-classname>
      </entry>
    </policy-model-config>
</policy-config>

Sample Web Service

Example 3-4 describes a sample Web service. You can attach the custom assertion to Web service as described in Section 2.2.7, "Step 7: Attach the Custom Policy to a Web Service".

Example 3-4 Sample Web Service

package project1; 
import javax.jws.WebService;
import weblogic.wsee.jws.jaxws.owsm.SecurityPolicies;
@WebService
@SecurityPolicy(uri="policy:oracle/ip_assertion_policy")
public class Class1 {
    public Class1() {
        super();
    }
 
    public String echo1() {
        return "one";
    }
}

Sample JSE Client

Example 3-5 is a sample of a JSE client generated from the Web service in Example 3-4.

Example 3-5 Sample JSE Client

package project1;
import javax.xml.ws.WebServiceRef;
 
public class Class1PortClient
{
  @WebServiceRef
  private static Class1Service class1Service;
  public static void main(String [] args)
  {
    class1Service = new Class1Service();
    Class1 port = class1Service.getClass1Port();
    // Add your code to call the desired methods.
 
    System.out.println(port.echo1());
  }
}

3.2.2 Running This Sample

To use the IP Validation custom assertion sample, perform the following steps:

  1. Create the custom assertion and custom assertion executor with the sample codes as described in Section 3.2.1, "Code Samples". These samples demonstrate the following key features:

  2. Create the JAR file as described in Section 2.2.4, "Step 4: Create the JAR File".

  3. Add the custom policy to the policy store as described in Section 2.2.5, "Step 5: Add the Custom Policy to the Policy Store".

  4. Update the classpath as described in Section 2.2.6, "Step 6: Deploy the Custom Assertion".

  5. Attach the custom policy to the Web service by any one of the methods described in Section 2.2.7, "Step 7: Attach the Custom Policy to a Web Service".

  6. Test the Web service by creating a JSE client as shown in Example 3-5.

3.3 Encryption and Decryption Custom Assertion Sample

In this sample, a set of custom assertions are used to encrypt data from an inbound message, making it unreadable from consoles, audit trail, or logs. The encrypted data is decrypted for outbound messages for downstream services that require access to the data.

The following sections provide samples that demonstrate how to code the custom assertion and describe the sample in detail:

3.3.1 Code Samples

This section includes the following sample codes to create and implement the custom assertion:

Sample Custom Assertion Executor

Example 3-6 describes a sample custom assertion executor used for encryption and decryption of data. For more information on the implementation, see Section 3.3.2, "Running the Sample".

Example 3-6 Sample Custom Assertion Executor

package owsm.custom.soa;
 
import java.util.HashMap;
import java.util.Iterator;
 
import javax.xml.namespace.NamespaceContext;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
 
import oracle.wsm.common.sdk.IContext;
import oracle.wsm.policy.model.IAssertion;
import oracle.wsm.policyengine.IExecutionContext;
import oracle.wsm.policyengine.impl.AssertionExecutor;
 
import org.w3c.dom.Element;
import org.w3c.dom.Node;
 
/**
 * A base class for OWSM custom assertions that specific classes can extend. It
 * contains common code and variables used accross all custom assertions.
 * 
 * All custom assertions must extend the AssertionExecutor class.
 */
public abstract class CustomAssertion
  extends AssertionExecutor
{
 
 
  protected final static String PROP_DEBUG = "debugFlag";
  
  protected final static String DEBUG_START =
 "===========================================================>>>";
  protected final static String DEBUG_END =
 "<<<===========================================================";
 
  protected IAssertion mAssertion = null;
  protected IExecutionContext mEcontext = null;
  protected oracle.wsm.common.sdk.IContext mIcontext = null;
  
  /**
   * A tag or text to display when printing debug information to identify the
   * content.
   */
  protected String mTag;
 
  /**
   * Constructor
   */
  public CustomAssertion(String tag)
  {
    super();
    mTag = tag;
  } // CustomAssertion()
 
  /**
   * Implemented from parent class
   */
  public void init(IAssertion iAssertion,
                      IExecutionContext iExecutionContext,
                      IContext iContext)
  {
    mAssertion = iAssertion;
    mEcontext = iExecutionContext;
    mIcontext = iContext;
    //IAssertionBindings bindings = ((SimpleAssertion)

 (mAssertion)).getBindings();
  } // init()
  /**
   * Implemented from parent class
   */
  public void destroy()
  {
    // Nothing to do.
  } // destroy()
  
  /**
   * A utility method for extracting the node specified by <code>xpathStr</code>
   * (with namespaces defined by <code>namespaces</code>) from  
 *<code>payload</code>
   * 
   * This method will print an stack trace if their is an exception. If you want
 *to
   * return the exception instead then modify the method appropriately.
   * 
   * @param payload the payload
   * @param namespaces the namespaces referenced by <code>xpathStr</code>
   * @param xpathStr an XPath query defining how to extract a node from
 *<code>payload</code>
   * @return
   */
  public static Node getDataNode(Element payload, final HashMap<String, String>

 namespaces, String xpathStr)
  {
    Node node = null;
    
    try
    {
      // Create a namespace context based on the namespaces passed in.
      //
      NamespaceContext ctx = new NamespaceContext()
      {
        public String getNamespaceURI(String prefix)
        {
          return namespaces.get(prefix);
        }
        // Dummy implementation - not used
        public Iterator getPrefixes(String val)
        {
          return null;
        }
        // Dummy implemenation - not used
        public String getPrefix(String uri)
        {
          return null;
        }
      };
      XPathFactory xpathFact = XPathFactory.newInstance();
      XPath xpath = xpathFact.newXPath();
      xpath.setNamespaceContext(ctx);
            node = (Node)xpath.evaluate(xpathStr, payload, XPathConstants.NODE);
    }
    catch (XPathExpressionException ex)
    {
      ex.printStackTrace();
      return null;
    }
    
    return node;
  } // getDataNode()
  
} 

Sample Inbound Encryption Class

Example 3-7 provides a sample custom assertion executor for encrypting an element of an inbound message.

Example 3-7 Sample Inbound Encryption Class

package owsm.custom.soa;
 
import java.util.HashMap;
 
import javax.xml.soap.SOAPBody;
 
import oracle.wsm.common.sdk.IContext;
import oracle.wsm.common.sdk.IMessageContext;
import oracle.wsm.common.sdk.IResult;
import oracle.wsm.common.sdk.Result;
import oracle.wsm.common.sdk.SOAPBindingMessageContext;
import oracle.wsm.common.sdk.WSMException;
import oracle.wsm.policy.model.IAssertionBindings;
import oracle.wsm.policy.model.IConfig;
import oracle.wsm.policy.model.IProperty;
import oracle.wsm.policy.model.IPropertySet;
import oracle.wsm.policy.model.impl.SimpleAssertion;
 
import oracle.xml.parser.v2.XMLElement;
 
import org.w3c.dom.Node;
 
 
/**
 * A custom assertion class for encrypting an element of an inbound message.
 */
public class InboundEncryptor
  extends CustomAssertion
{
  /**
   * Constructor
   */
  public InboundEncryptor()
  {
    super("[InboundEncryptor] ");
  } // InboundEncryptor()
 

 
  /**
   * Process an inbound message for the given invocation context
   *
   * @param iContext the invocation context for a specific message
   * @return the result of any actions taken. It can return a success message or
   *         a fault with an exception message
   */
  public IResult execute(IContext iContext)
  {
    // Create the result that's going be populate with success or failure
    // depending on what happens.
    //
    IResult result = new Result();
    
    // Specify whether we are in debug mode or not. If true then debug statements
    // will be printed to the log file.
    // This can be set to true in the OWSM policy assertion.
    //
    boolean debug = false;
 
    try
    {
      // Get the property set which contains properties defined in the OWSM
      // policy assertion.
      //
      IAssertionBindings bindings = ((SimpleAssertion)
 (mAssertion)).getBindings();
      IConfig config = bindings.getConfigs().get(0);
      IPropertySet propertyset = config.getPropertySets().get(0);
 
      // Now that we have the property set, let's check it for the specific
      // properties we care about.
      //
      
      // Check for the debug flag property.
      //
      IProperty debugProp = propertyset.getPropertyByName(PROP_DEBUG);
      if (debugProp != null)
      {
        String debugStr = debugProp.getValue();
        debug = Boolean.valueOf(debugStr).booleanValue();
      }
      if (debug)
      {
        System.out.println(mTag+DEBUG_START);
        System.out.println(mTag+this.getClass().getSimpleName()+".execute()
 Starting...");
        System.out.println(mTag+"In debug mode");
      }
      
      // Check for the stage. We only care about the request stage for this
      // implementation.
      //
      IMessageContext.STAGE stage = ((IMessageContext) iContext).getStage();
      if (debug) System.out.println(mTag+"stage="+stage);
      if (stage != IMessageContext.STAGE.request)
      {
        result.setStatus(IResult.SUCCEEDED);
        if (debug)
        {
          System.out.println(mTag+"Nothing to process in this stage. Returning");
          System.out.println(mTag+DEBUG_END);
        }
        return result;
      }
      // Get the encryption key, which is a property on the assertion.
      //
      String key = propertyset.getPropertyByName("encryption_key").getValue();
      if (debug) System.out.println(mTag+"key=[" + key + "]");
      if (key == null || key.trim().length() == 0)
      {
        result.setStatus(IResult.FAILED);
        result.setFault(new WSMException("Invalid key"));
        if (debug)
        {
          System.out.println(mTag+"Invalid key");
          System.out.println(mTag+DEBUG_END);
        }
        return result;
      }
      // As as point of interest, you can get the service URL. This could be used
      // by this class to know which service this message is bound for, and
 //therefore
      // which XPath expression to use.
      // In this example no such logic is needed as we only have one servcie
      // to worry about.
      //
      if (debug)
      {
        String serviceURL = ((IMessageContext) iContext).getServiceURL();
        System.out.println(mTag+"serviceURL=[" + serviceURL+"]");
      }
      // Get the message.
      //
      SOAPBindingMessageContext soapbindingmessagecontext =
 (SOAPBindingMessageContext) iContext;
      javax.xml.soap.SOAPMessage soapMessage =
 soapbindingmessagecontext.getRequestMessage();
      SOAPBody soapElem = soapMessage.getSOAPBody();
      if (debug)
      {
        System.out.println(mTag+"----- Start ORIGINAL inbound message -----");
        ((XMLElement) soapElem).print(System.out);
        System.out.println(mTag+"-----  End ORIGINAL inbound message  -----");
      }
      // Create the XPath to reference the element which is to be encrypted.
      //
      String xpathStr =
 "/soap:Envelope/soap:Body/ns1:process/ns1:order/ns1:ccNum";
      // Build up a namespace list for any namespaces referenced by the
      // XPath expression. This will be the basis for a namespace context
      // created later.
      //
      final HashMap<String, String> namespaces = new HashMap<String, String>();
      namespaces.put("soap", "http://schemas.xmlsoap.org/soap/envelope/");
      namespaces.put("ns1", "http://xmlns.oracle.com/CustomEncryption
_jws/CustomEncryptionComposite/ProcessCustomer");
     
      // Extract the node that should be encrypted.
      //
      Node inputNode = getDataNode(soapElem, namespaces, xpathStr);
      if (inputNode == null)
      {
        // Something went wrong, but getDataNode() would've printed out a
 //stacktrace
        // so print out a debug statement and exit.
        //
        result.setStatus(IResult.FAILED);
        result.setFault(new WSMException("Cannot find node with XPath expression:
 "+xpathStr));
        if (debug)
        {
          System.out.println(mTag+"Cannot find node with XPath expression:
 "+xpathStr);
          System.out.println(mTag+DEBUG_END);
        }
        return result;
      }
  
      // Extract the string value of the element to be encrypted.
      //
      String inputValue = inputNode.getTextContent();
  
      // Get an instance of EncDec and perform the actual encryption.
      //
      EncDec ed = EncDec.getInstance();
      String encryptedInput = ed.encryptStrToStr(inputValue, key);
      if (debug) System.out.println(mTag+"result of encryption=[" + encryptedInput
 + "]");
      // Replace the value of the node with the encrypted value.
      //
      try
      {
        inputNode.setTextContent(encryptedInput);
      }
      catch (Exception ex)
      {
        ex.printStackTrace();
      }
      if (debug)
      {
        System.out.println(mTag+"----- Start MODIFIED inbound message -----");
        ((XMLElement) soapElem).print(System.out);
        System.out.println(mTag+"-----  End MODIFIED inbound message  -----");
      }
      // Set a happy result.
      //
      result.setStatus(IResult.SUCCEEDED);
    }
    catch (Exception e)
    {
      // This is a general or catchall handler.
      //
      result.setStatus(IResult.FAILED);
      result.setFault(new WSMException(WSMException.FAULTCODE_QNAME_FAILED_CHECK,
 e));
      if (debug) System.out.println(this.getClass().getName()+": ERROR: Got an
 exception somewhere...");
    }
    
    if (debug) System.out.println(mTag+DEBUG_END);
    return result;
    
  } // execute()
  
} // InboundEncryptor

Sample Outbound Decryption Class

Example 3-8 provides a sample custom assertion executor for decrypting an element of an outbound message.

Example 3-8 Sample Outbound Decryption Class

package owsm.custom.soa;
 
import java.util.HashMap;
 
import javax.xml.soap.SOAPBody;
 
import oracle.wsm.common.sdk.IContext;
import oracle.wsm.common.sdk.IMessageContext;
import oracle.wsm.common.sdk.IResult;
import oracle.wsm.common.sdk.Result;
import oracle.wsm.common.sdk.SOAPBindingMessageContext;
import oracle.wsm.common.sdk.WSMException;
import oracle.wsm.policy.model.IAssertionBindings;
import oracle.wsm.policy.model.IConfig;
import oracle.wsm.policy.model.IProperty;
import oracle.wsm.policy.model.IPropertySet;
import oracle.wsm.policy.model.impl.SimpleAssertion;
 
import oracle.xml.parser.v2.XMLElement;
 
import org.w3c.dom.Node;
 
 
/**
 * A custom assertion class for decrypting an element of an outbound message.
 */
public class OutboundDecryptor
  extends CustomAssertion
{
 
  /**
   * Constructor
   */
  public OutboundDecryptor()
  {
    super("[OutboundDecryptor] ");
  } // OutboundDecryptor()
 
  //////////////////////////////////////////////////////////////////////////////
 
  /**
   * Process an outbound message for the given invocation context
   *
   * @param iContext the invocation context for a specific message
   * @return the result of any actions taken. It can return a success message or
   *         a fault with an exception message
   */
  public IResult execute(IContext iContext)
  {
    // Create the result that's going be populate with success or failure
    // depending on what happens.
    //
    IResult result = new Result();
 
    // Specify whether we are in debug mode or not. If true then debug statements
    // will be printed to the log file.
    // This can be set to true in the OWSM policy assertion.
    //
    boolean debug = false;
 
    try
    {
      // Get the property set which contains properties defined in the OWSM
      // policy assertion.
      //
      IAssertionBindings bindings = ((SimpleAssertion)
 (mAssertion)).getBindings();
      IConfig config = bindings.getConfigs().get(0);
      IPropertySet propertyset = config.getPropertySets().get(0);
      
      // Now that we have the property set, let's check it for the specific
      // properties we care about.
      //
      
      // Check for the debug flag property.
      //
      IProperty debugProp = propertyset.getPropertyByName(PROP_DEBUG);
      if (debugProp != null)
      {
        String debugStr = debugProp.getValue();
        debug = Boolean.valueOf(debugStr).booleanValue();
      }
      if (debug)
      {
        System.out.println(mTag+DEBUG_START);
        System.out.println(mTag+this.getClass().getSimpleName()+".execute()
 Starting...");
        System.out.println(mTag+"In debug mode");
      }
 
      // Check for the stage. We only care about the request stage for this
      // implementation.
      //
      IMessageContext.STAGE stage = ((IMessageContext) iContext).getStage();
      if (debug) System.out.println(mTag+"stage="+stage);
      if (stage != IMessageContext.STAGE.request)
      {
        result.setStatus(IResult.SUCCEEDED);
        if (debug)
        {
          System.out.println(mTag+"Nothing to process in this stage. Returning");
          System.out.println(mTag+DEBUG_END);
        }
        return result;
      }
      // Get the encryption key, which is a property on the assertion.
      //
      String key = propertyset.getPropertyByName("decryption_key").getValue();
      if (debug) System.out.println(mTag+"key=[" + key + "]");
      if (key == null || key.trim().length() == 0)
      {
        result.setStatus(IResult.FAILED);
        result.setFault(new WSMException("Invalid key"));
        if (debug)
        {
          System.out.println(mTag+"Invalid key");
          System.out.println(mTag+DEBUG_END);
        }
        return result;
      }
      String serviceURL = ((IMessageContext) iContext).getServiceURL();
      if (debug) System.out.println(mTag+"serviceURL=[" + serviceURL+"]");
      // Get the message.
      //
      SOAPBindingMessageContext soapbindingmessagecontext =

 (SOAPBindingMessageContext) iContext;
      javax.xml.soap.SOAPMessage soapMessage =
 soapbindingmessagecontext.getRequestMessage();
      SOAPBody soapElem = soapMessage.getSOAPBody();
                                                    
      // As as point of interest, you can get the service URL. This could be used
      // by this class to know which service this message is bound for, and
 //therefore
      // which XPath expression to use.
      // In this example no such logic is needed as we only have one servcie
      // to worry about.
      //
      if (debug)
      {
        System.out.println(mTag+"----- Start ORIGINAL inbound message -----");
        ((XMLElement) soapElem).print(System.out);
        System.out.println(mTag+"-----  End ORIGINAL inbound message  -----");
      }
      // Create the XPath to reference the element which is to be encrypted.
      //
      String xpathStr = "/soap:Envelope/soap:Body/ns1:process/ns1:ccNum";
      
      // Build up a namespace list for any namespaces referenced by the
      // XPath expression. This will be the basis for a namespace context
      // created later.
      //
      final HashMap<String, String> namespaces = new HashMap<String, String>();
      namespaces.put("soap", "http://schemas.xmlsoap.org/soap/envelope/");
      namespaces.put("ns1", "http://xmlns.oracle.com/CustomEncryption
_jws/CustomEncryptionExternalService/ExternalServiceBpel");
    
      // Extract the node that should be encrypted.
      //
      Node inputNode = getDataNode(soapElem, namespaces, xpathStr);
      if (inputNode == null)
      {
        // Something went wrong, but getDataNode() would've printed out a
 //stacktrace
        // so print out a debug statement and exit.
        //
        result.setStatus(IResult.FAILED);
        result.setFault(new WSMException("Cannot find node with XPath expression:
 "+xpathStr));
        if (debug)
        {
          System.out.println(mTag+"Cannot find node with XPath expression:
 "+xpathStr);
          System.out.println(mTag+DEBUG_END);
        }
        return result;
      }
    
      // Extract the string value of the element to be encrypted.
      //
      String inputValue = inputNode.getTextContent();
    
      // Get an instance of EncDec and perform the actual encryption.
      //
      EncDec ed = EncDec.getInstance();
      String decryptedInput = ed.decryptStrToStr(inputValue, key);
      if (debug) System.out.println(mTag+"result of decryption=[" + decryptedInput
 + "]");
      // Replace the value of the node with the encrypted value.
      //
      try
      {
        inputNode.setTextContent(decryptedInput);
      }
      catch (Exception ex)
      {
        ex.printStackTrace();
      }
      if (debug)
      {
        System.out.println(mTag+"----- Start MODIFIED inbound message -----");
        ((XMLElement) soapElem).print(System.out);
        System.out.println(mTag+"-----  End MODIFIED inbound message  -----");
      }
      // Set a happy result.
      //
      result.setStatus(IResult.SUCCEEDED);
    }
    catch (Exception e)
    {
      // This is a general or catchall handler.
      //
      result.setStatus(IResult.FAILED);
      result.setFault(new WSMException(WSMException.FAULTCODE_QNAME_FAILED_CHECK,
 e));
      if (debug) System.out.println(this.getClass().getName()+": ERROR: Got an
 exception somewhere...");
    }
    
    if (debug) System.out.println(mTag+DEBUG_END);
    return result;
    
  } // execute()
  
} // OutboundDecryptor

Sample Policy File for Encryption

Example 3-9 provides a sample custom assertion executor for encryption.

Example 3-9 Sample Policy File for Encryption

<orasp:Assertion xmlns:orawsp="http://schemas.oracle.com/ws/2006/01/policy"
                          orawsp:Id="soa_encryption_template"
                          orawsp:attachTo="generic" orawsp:category="security"
                          orawsp:description="Custom Encryption of payload"
                          orawsp:displayName="Custom Encryption"
                          orawsp:name="custom/soa_encryption"
                          xmlns:custom="http://schemas.oracle.com/ws/soa/custom">
  <custom:custom-executor orawsp:Enforced="true" orawsp:Silent="false"
                   orawsp:category="security/custom"
                   orawsp:name="WSSecurity_Custom_Assertion">
    <orawsp:bindings>
      <orawsp:Implementation>owsm.custom.soa.InboundEncryptor</orawsp:Implementation>
      <orawsp:Config orawsp:configType="declarative" orawsp:name="encrypt_soa">
        <orawsp:PropertySet orawsp:name="encrypt">
          <orawsp:Property orawsp:contentType="constant"
                           orawsp:name="encryption_key" orawsp:type="string">
            <orawsp:Value>MySecretKey</orawsp:Value>
          </orawsp:Property>
          <orawsp:Property orawsp:contentType="constant"
                           orawsp:name="debugFlag" orawsp:type="string">
            <orawsp:Value>true</orawsp:Value>
          </orawsp:Property>
        </orawsp:PropertySet>
      </orawsp:Config>
    </orawsp:bindings>
  </custom:custom-executor>
</orasp:Assertion>

Sample Policy File for Decryption

Example 3-10 provides a sample custom assertion for decryption.

Example 3-10 Sample Policy File for Decryption

<orasp:Assertion xmlns:orawsp="http://schemas.oracle.com/ws/2006/01/policy"
                          orawsp:Id="soa_decryption_template"
                          orawsp:attachTo="binding.client"
 orawsp:category="security"
                          orawsp:description="Custom Decryption of payload"
                          orawsp:displayName="Custom Decryption"
                          orawsp:name="custom/soa_decryption"
                          xmlns:custom="http://schemas.oracle.com/ws/soa/custom">
  <custom:custom-executor orawsp:Enforced="true" orawsp:Silent="false"
                   orawsp:category="security/custom"
                   orawsp:name="WSSecurity Custom Assertion">
    <orawsp:bindings>
      <orawsp:Implementation>owsm.custom.soa.OutboundDecryptor</orawsp:Implementation>
      <orawsp:Config orawsp:configType="declarative" orawsp:name="encrypt_soa">
        <orawsp:PropertySet orawsp:name="decrypt">
          <orawsp:Property orawsp:contentType="constant"
                           orawsp:name="decryption_key" orawsp:type="string">
            <orawsp:Value>MySecretKey</orawsp:Value>
          </orawsp:Property>
          <orawsp:Property orawsp:contentType="constant"
                           orawsp:name="debugFlag" orawsp:type="string">
            <orawsp:Value>true</orawsp:Value>
          </orawsp:Property>
        </orawsp:PropertySet>
      </orawsp:Config>
    </orawsp:bindings>
  </custom:custom-executor>
</orasp:Assertion>

Sample Composite for Receiving the Encrypted Message

The following sample is a composite application with a BPEL process used to demonstrate that it received the encrypted value.

Example 3-11 Sample Composite

<?xml version="1.0" encoding="UTF-8" ?>
<!-- Generated by Oracle SOA Modeler version 1.0 at [5/10/10 9:33 AM]. -->
<composite name="CustomEncryptionComposite"
           revision="1.0"
           label="2010-05-10_09-33-01_807"
           mode="active"
           state="on"
           xmlns="http://xmlns.oracle.com/sca/1.0"
           xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
           xmlns:orawsp="http://schemas.oracle.com/ws/2006/01/policy"
           xmlns:ui="http://xmlns.oracle.com/soa/designer/">
  <import namespace="http://xmlns.oracle.com/CustomEncryption
_jws/CustomEncryptionComposite/ProcessCustomer"
          location="ProcessCustomer.wsdl" importType="wsdl"/>
  <import namespace="http://xmlns.oracle.com/CustomEncryption
_jws/CustomEncryptionExternalService/ExternalServiceBpel"
          location="ExternalServiceBpel.wsdl" importType="wsdl"/>
  <service name="processcustomer_client_ep"
           ui:wsdlLocation="ProcessCustomer.wsdl">
    <interface.wsdl interface="http://xmlns.oracle.com/CustomEncryption
_jws/CustomEncryptionComposite/ProcessCustomer#wsdl.interface(ProcessCustomer)"/>
    <binding.ws port="http://xmlns.oracle.com/CustomEncryption
_jws/CustomEncryptionComposite/ProcessCustomer#wsdl.endpoint(processcustomer
_client_ep/ProcessCustomer_pt)">
      <wsp:PolicyReference URI="SOA/CustomEncryption" orawsp:category="security"
                           orawsp:status="enabled"/>
    </binding.ws>
  </service>
  <component name="ProcessCustomer">
    <implementation.bpel src="ProcessCustomer.bpel"/>
  </component>
  <reference name="ExternalSvc" ui:wsdlLocation="ExternalServiceBpel.wsdl">
    <interface.wsdl interface="http://xmlns.oracle.com/CustomEncryption
_jws/CustomEncryptionExternalService/ExternalServiceBpel#wsdl.interface(ExternalSe
rviceBpel)"/>
    <binding.ws port="http://xmlns.oracle.com/CustomEncryption
_jws/CustomEncryptionExternalService/ExternalServiceBpel#wsdl.endpoint(externalser
vicebpel_client_ep/ExternalServiceBpel_pt)"
                location="externalservicebpel_client_ep.wsdl"
                soapVersion="1.1">
      <wsp:PolicyReference URI="SOA/CustomDecryption" orawsp:category="security"
                           orawsp:status="enabled"/>
      <property name="weblogic.wsee.wsat.transaction.flowOption"
                type="xs:string" many="false">WSDLDriven</property>
    </binding.ws>
  </reference>
  <wire>
    <source.uri>processcustomer_client_ep</source.uri>
    <target.uri>ProcessCustomer/processcustomer_client</target.uri>
  </wire>
  <wire>
    <source.uri>ProcessCustomer/ExternalSvc</source.uri>
    <target.uri>ExternalSvc</target.uri>
  </wire>
</composite>

Sample External Service Composite

The following sample is a composite application used to represent an external service being called and show that it received the decrypted value.

Example 3-12 Sample External Service Composite

<?xml version="1.0" encoding="UTF-8" ?>
<!-- Generated by Oracle SOA Modeler version 1.0 at [5/10/10 9:41 AM]. -->
<composite name="CustomEncryptionExternalService"
           revision="1.0"
           label="2010-05-10_09-41-00_810"
           mode="active"
           state="on"
           xmlns="http://xmlns.oracle.com/sca/1.0"
           xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
           xmlns:orawsp="http://schemas.oracle.com/ws/2006/01/policy"
           xmlns:ui="http://xmlns.oracle.com/soa/designer/">
  <import namespace="http://xmlns.oracle.com/CustomEncryption
_jws/CustomEncryptionExternalService/ExternalServiceBpel"
          location="ExternalServiceBpel.wsdl" importType="wsdl"/>
  <service name="externalservicebpel_client_ep"
           ui:wsdlLocation="ExternalServiceBpel.wsdl">
    <interface.wsdl interface="http://xmlns.oracle.com/CustomEncryption
_jws/CustomEncryptionExternalService/ExternalServiceBpel#wsdl.interface(ExternalSe
rviceBpel)"/>
    <binding.ws port="http://xmlns.oracle.com/CustomEncryption
_jws/CustomEncryptionExternalService/ExternalServiceBpel#wsdl.endpoint(externalser
vicebpel_client_ep/ExternalServiceBpel_pt)"/>
  </service>
  <component name="ExternalServiceBpel">
    <implementation.bpel src="ExternalServiceBpel.bpel"/>
  </component>
  <wire>
    <source.uri>externalservicebpel_client_ep</source.uri>
    <target.uri>ExternalServiceBpel/externalservicebpel_client</target.uri>
  </wire>
</composite>

3.3.2 Running the Sample

To use the Encryption and Decryption sample, perform the following steps:

  1. Create the custom assertion policy file and custom assertion executor with the sample codes as described in Section 3.3.1, "Code Samples". These samples demonstrate the following key features:

    • Specify the properties encryption_key and debugFlag in the encrypt property set for the encryption custom assertion:

              <orawsp:PropertySet orawsp:name="encrypt">
                <orawsp:Property orawsp:contentType="constant"
                                 orawsp:name="encryption_key"
      orawsp:type="string">
                  <orawsp:Value>MySecretKey</orawsp:Value>
                </orawsp:Property>
                <orawsp:Property orawsp:contentType="constant"
                                 orawsp:name="debugFlag" orawsp:type="string">
                  <orawsp:Value>true</orawsp:Value>
                </orawsp:Property>
              </orawsp:PropertySet>
      

      For more information, see Section 4.1, "Inputting Parameters to Custom Assertions".

    • Set the properties decryption_key and debugFlag in the property set decrypt for decryption custom assertion:

              <orawsp:PropertySet orawsp:name="decrypt">
                <orawsp:Property orawsp:contentType="constant"
                                 orawsp:name="decryption_key"
       orawsp:type="string">
                  <orawsp:Value>MySecretKey</orawsp:Value>
                </orawsp:Property>
                <orawsp:Property orawsp:contentType="constant"
                                 orawsp:name="debugFlag" orawsp:type="string">
                  <orawsp:Value>true</orawsp:Value>
                </orawsp:Property>
              </orawsp:PropertySet>
      

      For more information, see Section 4.1, "Inputting Parameters to Custom Assertions".

    • Extract the node specified by XPath expressions with defined namespaces from the custom assertion class:

      NamespaceContext ctx = new NamespaceContext()
            {
              public String getNamespaceURI(String prefix)
              {
                return namespaces.get(prefix);
              }
              // Dummy implementation - not used
              public Iterator getPrefixes(String val)
              {
                return null;
              }
              // Dummy implemenation - not used
              public String getPrefix(String uri)
              {
                return null;
              }
            };
            XPathFactory xpathFact = XPathFactory.newInstance();
            XPath xpath = xpathFact.newXPath();
            xpath.setNamespaceContext(ctx);
            
            node = (Node)xpath.evaluate(xpathStr, payload, XPathConstants.NODE);
          }
      
      

      For more information, see Section 4.4, "Accessing Parts of a Message Using XPath".

  2. Create the JAR file as described in Section 2.2.4, "Step 4: Create the JAR File".

  3. Add the custom policy to the policy store as described in Section 2.2.5, "Step 5: Add the Custom Policy to the Policy Store".

  4. Update the classpath as described in Section 2.2.6, "Step 6: Deploy the Custom Assertion".

  5. Attach the custom policy to the Web service by any one of the methods described in Section 2.2.7, "Step 7: Attach the Custom Policy to a Web Service".

3.4 Authentication Custom Assertion Sample

The authentication custom assertion sample is used to authenticate a user using WebLogic authentication providers. The credentials (user name and password) are read from incoming SOAP message and are authenticated against WebLogic authentication provider using a custom login module.

The following sections provide samples that demonstrate how to code the custom assertion and describe the sample in detail:

3.4.1 Code Samples

This section includes the following sample codes to create and implement the custom assertion:

Sample Custom Assertion Executor

Example 3-13 describes a sample executor that invokes the custom login module to perform the authentication.

Example 3-13 Sample Custom Assertion Executor

package sampleAssertion;
/**
 * <Description>
 * <p>
 * CustomAuthExecutor class. This class is invoked for custom_auth_policy
 * This class expects that wss_username_token_client_policy is attached to the 
* calling client
 * This class fetches credentials from incoming SOAP message and performs
 * authentication against a configured login module as specified by the Login 
* Config file.
 * </p>
 * </Description>
 * 
 */
import java.util.Iterator;
 
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.soap.SOAPMessage;
 
import oracle.wsm.common.sdk.IContext;
import oracle.wsm.common.sdk.IMessageContext;
import oracle.wsm.common.sdk.IResult;
import oracle.wsm.common.sdk.Result;
import oracle.wsm.common.sdk.SOAPBindingMessageContext;
import oracle.wsm.common.sdk.WSMException;
import oracle.wsm.policy.model.IAssertion;
import oracle.wsm.policy.model.ISimpleOracleAssertion;
import oracle.wsm.policyengine.impl.AssertionExecutor;
 
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
 
public class CustomAuthExecutor extends AssertionExecutor {
 
    public void init(IAssertion assertion,
        oracle.wsm.policyengine.IExecutionContext econtext,
        oracle.wsm.common.sdk.IContext context) {
        this.assertion = assertion;
        this.econtext = econtext;
    }
 
    public oracle.wsm.policyengine.IExecutionContext getExecutionContext() {
        return this.econtext;
    }
 
    public boolean isAssertionEnabled() {
        return ((ISimpleOracleAssertion) this.assertion).isEnforced();
    }
 
    public String getAssertionName() {
        return this.assertion.getQName().toString();
    }
 
 
    /**
     * <p>
     * This method is invoked for each request/response.
     * This method retrieves credentials from incoming soap message and 
     * authenticates 
     * them against a configured login module
     * </p>
     * @param context
     * @return IResult
     * @exception WSMException
     */
    @Override
    public IResult execute(IContext context) throws WSMException {
        oracle.wsm.common.sdk.IMessageContext.STAGE stage = ((oracle.wsm.common.sdk.IMessageContext) context)
            .getStage();
        IResult result = new Result();
 
        if (stage == IMessageContext.STAGE.request) {
            try {
                SOAPBindingMessageContext soapMsgCtxt= (SOAPBindingMessageContext)
                context;
                //Intercepts the incoming SOAP message
                SOAPMessage soapMessage = soapMsgCtxt.getRequestMessage();
                
                MyCallbackHandler callbackhandler = new MyCallbackHandler();
                
                //initialize CallbackHandler instance which is passed to 
                //LoginModule implementation
                initializeCallbackHandler(callbackhandler, soapMessage);
                
                
               //In order to authenticate a user, you first need a
               //javax.security.auth.login.LoginContext. 
               /**
 
               * Following parameters are passed to LoginContext
               * 1. name - LoginContext uses the name as the index into the JAAS
               * login configuration file to determine which LoginModules should 
               * be used. Such an entry specifies the class(es) that
               * implement the desired underlying authentication
               * technology(ies). The class(es) must implement 
               *  the LoginModule interface, which is in the
               * javax.security.auth.spi package.
               * In our case CustomLoginModule refers to
               * sampleAssertion.loginmodule.CustomLoginModule
               *
               * 2. Subject - the subject (javax.security.auth.Subject) to
               * authenticate. LoginContext passes the Subject
               * object to configured LoginModules so they may perform
               * additional authentication and update the Subject.
               *           
               * 3. CallbackHandler instance -
               * javax.security.auth.callback.CallbackHandler  object is used by
               * LoginModules to 
               * communicate with the user. LoginContext passes the
               * CallbackHandler object to configured LoginModules 
               *  so they may communicate with the user. An application
               * typically provides its own CallbackHandler implementation.
               * 
               **/
 
 
                // Obtain a LoginContext, needed for authentication. 
                // Tell it to use the LoginModule implementation 
               // specified by the entry named "CustomLoginModule" in the 
               // JAAS login configuration file and to also use the 
               // specified CallbackHandler.
                Subject subject = new Subject();
               LoginContext lc = new LoginContext("CustomLoginModule", subject,
               callbackhandler);
                
               /**Once the caller has instantiated a LoginContext, it invokes the
               * login method to authenticate a Subject
               * The LoginContext instantiates a new empty
               * javax.security.auth.Subject object (which represents the user or
               * service being
               * authenticated). 
               * The LoginContext constructs the configured LoginModule (in our
               * case CustomLoginModule) and initializes it with this new Subject
               * and
               * MyCallbackHandler.
               * The SampleLoginModule will utilize the MyCallbackHandler to
               * obtain the user name and password.
               * If authentication is successful, the CustomLoginModule
               * populates the Subject with a Principal representing the user. 
               * 
                **/
               lc.login();
                
               //authenticated Subject can be retrieved by calling the               
               // LoginContext's getSubject
                //method
                 subject = lc.getSubject();
 
 System.out.println("Authentication succeeded");
                
                //sets result to succeeded if authentication succeeds
  result.setStatus(IResult.SUCCEEDED);
  } catch (LoginException e) {
               //in case there is a failure in authentication sets result to
               // failed state and
               // throw Failed authentication exception
                result.setStatus(IResult.FAILED);
                throw new WSMException(
                    WSMException.FAULTCODE_QNAME_FAILED_AUTHENTICATION, e);
            }
        }
 
        return result;
    }
 
                   /**
                    * Retrieves credentials from incoming SOAP message and 
                    * sets them into call back handler, which is than passed to
                    * Login module
                    * class
                    * via initialize(Subject, Callbackhandler,..) method of
                    *  LoginModule 
                    * @param SOAPMessage
                    * @param callbackhandler
                    * 
                    */
    private void initializeCallbackHandler(MyCallbackHandler callbackhandler,
 SOAPMessage soapElement) {
        try {
            SOAPHeader header = soapElement.getSOAPPart().getEnvelope()
                .getHeader();
            SOAPHeaderElement hdrElem = null;
            Iterator iter = header.examineAllHeaderElements();
            
            while (iter.hasNext()) {
                hdrElem = (SOAPHeaderElement) iter.next();
                String localName = hdrElem.getLocalName();
                NodeList headerNodeList = hdrElem.getChildNodes();
 
                for (int i = 0; i < headerNodeList.getLength(); i++) {
                    Node kid = headerNodeList.item(i);
                    String kidName = kid.getLocalName();
 
                    if (kidName.equals("UsernameToken")) {
                        NodeList nodeList = kid.getChildNodes();
                        
               /**check if incoming SOAP message contains UsernameToken
                *and retrieve credentials from it
               * The user name and password are set into callbackhandler
               * which are passed to Login module
                * for authentication
                **/
                        for (int j = 0; j < nodeList.getLength(); j++) {
                            String nodeName = nodeList.item(j).getLocalName();
                            String nodeValue = nodeList.item(j).getTextContent();
 
                            if (nodeName.equals("Username")) {
                                callbackhandler.setUserName(nodeValue);
                            }
 
                            if (nodeName.equals("Password")) {
                                callbackhandler.setPassword(nodeValue);
                            }
                        }
                        
                    }
                }
            }
 
        } catch (SOAPException se) {
            System.out.println("caught SOAPException: " + se.getMessage());
        }
        
    }
 
    /**
     *Executes any task required after policy execution.
     *
     */
    @Override
    public oracle.wsm.common.sdk.IResult postExecute(
        oracle.wsm.common.sdk.IContext context) {
        IResult result = new Result();
        result.setStatus(IResult.SUCCEEDED);
        return result;
    }        @Override
    public void destroy() {
    }
   }

Sample Policy File

Example 3-14 is a custom assertion that invokes the executor described in Example 3-13 which is used to authenticate users against WebLogic authentication provider.

Example 3-14 Sample Policy File

<?xml version = '1.0'?>
<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
 xmlns:oralgp="http://schemas.oracle.com/ws/2006/01/loggingpolicy"
 xmlns:orawsp="http://schemas.oracle.com/ws/2006/01/policy"
orawsp:provides="{http://docs.oasis-open.org/ns/opencsa/sca/200903}authentication,
 {http://docs.oasis-open.org/ns/opencsa/sca/200903}clientAuthentication,
 {http://docs.oasis-open.org/ns/opencsa/sca/200903}clientAuthentication.message,
 {http://schemas.oracle.com/ws/2006/01/policy}token.usernamePassword"
 orawsp:status="enabled" xmlns="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-uti
lity-1.0.xsd" wsu:Id="custom_auth_policy"
orawsp:displayName="i18n:oracle.wsm.resources.policydescription.PolicyDescription
Bundle_oracle/custom_auth_policy_PolyDispNameKey"
 xmlns:orasp="http://schemas.oracle.com/ws/2006/01/securitypolicy"
orawsp:description="i18n:oracle.wsm.resources.policydescription.PolicyDescription
Bundle_oracle/custom_auth_policy_PolyDescKey" orawsp:attachTo="binding.server"
 Name="oracle/custom_auth_policy"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" orawsp:category="security"
 orawsp:local-optimization="off">
   <orasp:custom-auth-assertion orawsp:Silent="false" orawsp:name="Custom auth"
 orawsp:Enforced="true" orawsp:category="security/authentication">
      <orawsp:bindings>
       <orawsp:Implementation>sampleAssertion.CustomAuthExecutor</orawsp:Implementation>
      </orawsp:bindings>
     </orasp:custom-auth-assertion>
</wsp:Policy>

Sample Authentication Files

The following code samples demonstrate the implementation of authentication:

  • Example 3-15 describes a Login configuration file that contains an entry specifying the Login Module that is to be used to do the user authentication.

  • Example 3-16 is a sample CustomLoginModule class that is specified by the LoginConfig file in Example 3-15. It provides an implementation of javax.security.auth.spi.LoginModule and authenticates a user against WebLogic authentication provider.

  • Example 3-17 is a sample SimpleLoginModule class that provides an implementation of javax.security.auth.spi.LoginModule, and is described for illustration purposes only.

  • Example 3-18 is a sample CallbackHandler class that provides an implementation of javax.security.auth.callback.Callback interface.

Example 3-15 Sample Configuration File

/** Login Configuration for the Sample Application 
JAAS authentication is performed in a pluggable fashion, so Java applications can
 remain independent from 
underlying authentication technologies. Users can plugin there custom loginmodule
 implementations which 
can integrate with corresponding authentication provider.
 
The name for an entry in a login configuration file is the name that applications
 use to refer to the entry when 
they instantiate a LoginContext. The specified LoginModules (described below) are
 used to control the authentication process.
 
As part of this sample we are using CustomLoginModule and SimpleLoginModule
1. CustomLoginModule - integrates with weblogic authentication provider
2. SimpleLoginModule - simply returns
 
You can also provide implementation of javax.security.auth.login.Configuration
 interface
Refer http://download.oracle.com/javase/.../docs/api/javax/security/auth/login/Config
uration.html and 
http://download.oracle.com/javase/.../docs/guide/security/jaas/tutorials/LoginC
onfigFile.html for more details.
 
**/
 
CustomLoginModule {
   sampleAssertion.loginmodule.CustomLoginModule required debug=true;
};
 
SimpleLoginModule {
  sampleAssertion.loginmodule.SimpleLoginModule required debug=true;
};

Example 3-16 Sample Implementation of javax.security.auth.spi.LoginModule

package sampleAssertion.loginmodule;
/**
 * <Description>
 * <p>
 * CustomLoginModule class implements the javax.security.auth.spi.LoginModule
 * interface. CustomLoginModule class is specified 
 * by the login configuration file i.e Login.config file.
 * This class authenticates user against weblogic authentication provider. 
 * If authentication is successful, the CustomLoginModule associate Principals and
 * Credentials with the authenticated Subject
 * 
 * Users can create there own custom login modules
 * by implementing <code>javax.security.auth.spi.LoginModule</code> interface
 * </p>
 * </Description>
 * 
 */
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Map;
 
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
 
import weblogic.security.services.Authentication;
 
public class CustomLoginModule implements LoginModule
{
    private Subject authenticatorSubject;
    private CallbackHandler callbackHandler;
    private boolean loginSucceeded;
 
    /**
     * Initialize this LoginModule.
     *
     * <p> This method is called by the <code>LoginContext</code> to initialize 
     * the <code>LoginModule</code> with the relevant information.
     * <p>
     *
     * @param subject the - <code>javax.security.auth.Subject</code> to be
     * authenticated.
     *
     * @param callbackHandler - instance of
     * <code>javax.security.auth.callback.CallbackHandler</code>
     *   the CallbackHandler object is used by LoginModules to retrieve the
     * information set by the user
     *   e.g user name / password.
     * 
     * @param sharedState state shared with other configured LoginModules. <p>
     *
     * @param options options specified in the login Configuration for this
     *  particular LoginModule.
     *          
     **/
    @Override
    public void initialize(Subject subject, CallbackHandler callbackHandler,
 Map<String, ?> sharedState, Map<String, ?> options)
    {
        this.authenticatorSubject = subject;
        this.callbackHandler = callbackHandler;
    }
 
 
    @Override
    /**
     * Method to authenticate a <code>Subject</code>.
     *
     * <p> The implementation of this method authenticates
     * a <code>Subject</code> using weblogic authentication provider
     * <p>
     *
     * @exception LoginException if the authentication fails
     *
     * @return true if the authentication succeeded
     */
    public boolean login() throws LoginException
    {
        /**authenticates user against weblogic authentication provider and sets
         * loginSucceeded
         * flag to true in case of successful authentication
         */
        this.authenticatorSubject = authenticate(this.callbackHandler);
        loginSucceeded = true;
        return loginSucceeded;
    }
    
    /**
     * authenticates using weblogic authentication provider
     * @param CallbackHandler
     * @return authenticated Subject
     * @throws LoginException
     */
    private Subject authenticate(CallbackHandler cbh) throws LoginException {
        try {
            return Authentication.login(cbh);
        } catch (LoginException e) {
            throw new LoginException("Authentication Failed"+e.getMessage());
        }
    }
 
    @Override
    /**
     * Method to commit the authentication process.
     *
     * <p> This method is called if the LoginContext's
     * overall authentication succeeded
     * <p>
     *
     * @exception LoginException if the commit fails
     *
     * @return true if this method succeeded, or false if this
     *          <code>LoginModule</code> should be ignored.
     */
    public boolean commit() throws LoginException {
        if (this.authenticatorSubject != null) {
            addToSubject(this.authenticatorSubject);
            return true;
        } else {
            return false;
        }
    }
    /**
     * Method to abort the authentication process.
     *
     * <p> This method is called if the LoginContext's
     * overall authentication failed.
     * <p>
     *
     * @exception LoginException if the abort fails
     *
     * @return true if this method succeeded, or false if this
     *          <code>LoginModule</code> should be ignored.
     */
    public boolean abort() throws LoginException {
        return this.loginSucceeded && logout();
    }
    
  
    /**
     * Method which logs out a <code>Subject</code>.  
     *
     * <p>An implementation of this method might remove/destroy a Subject's
     * Principals and Credentials.
     * <p>
     *
     * @exception LoginException if the logout fails
     *
     * @return true if this method succeeded, or false if this
     *          <code>LoginModule</code> should be ignored.
     */
    public boolean logout() throws LoginException
    {
        if (this.authenticatorSubject != null) {
            removeFromSubject(this.authenticatorSubject);
        }
        this.loginSucceeded = false;
        return true;
    }
    
    /**
     * associates relevant Principals and Credentials with the Subject located in
     * the LoginModule
     * @param Subject
     */
    protected void addToSubject(final Subject sub) {
        if (sub != null) {
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
             public Object run() {
               
             authenticatorSubject.getPrincipals().addAll(sub.getPrincipals());
 authenticatorSubject.getPrivateCredentials().addAll(sub.getPrivateCredentials());
authenticatorSubject.getPublicCredentials().addAll(sub.getPublicCredentials());
                        return null;
                    }
                });
        }
    }
    
    /**
     * removes Principals and Credentials from the subject
     * @param Subject
     */
    private void removeFromSubject(final Subject sub) {
        if (sub != null) {
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
             public Object run() {
 authenticatorSubject.getPrincipals().removeAll(sub.getPrincipals());
 authenticatorSubject.getPrivateCredentials().removeAll(sub.getPrivateCredentials(


));
authenticatorSubject.getPublicCredentials().removeAll(sub.getPublicCredentials());
                        return null;
                    }
                });
        }
    }
}

Example 3-17 Sample Implementation of javax.security.auth.spi.LoginModule

/**
 * <Description>
 * <p>
 * SimpleLoginModule class implements the LoginModule interface. SimpleLoginModule
 * class is specified 
 * by the login configuration file i.e Loginconfig file.
 * This class simply returns true resulting in successful authentication.
 * 
 * This class is shown for illustration purpose only, users can integrate it with
 * there custom authentication provider
 * </p>
 * </Description>
 * 
 */
package sampleAssertion.loginmodule;
 
import java.util.Map;
 
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
 
public class SimpleLoginModule implements LoginModule {
 
    @Override
    public boolean abort() throws LoginException {
        return false;
    }
 
    @Override
    public boolean commit() throws LoginException {
        return true;
    }
 
    @Override
    public void initialize(Subject subject, CallbackHandler callbackHandler,
        Map<String, ?> sharedState, Map<String, ?> options) {
        
    }
 
    @Override
    /**
     * This method simply returns true and results in successful authentication
     * Users can integrate it using there custom authentication provider
     */
    public boolean login() throws LoginException {
        System.out.println("Inside SimpleLoginModule");
        return true;
    }
 
    @Override
    public boolean logout() throws LoginException {
        return false;
    }
    
 
}

Example 3-18 Sample Callback Handler

package sampleAssertion;
/**
 * <Description>
 * <p>
 * MyCallbackHandler class implements the 
 *  <code>javax.security.auth.callback.CallbackHandler </code> interface.  
 * An application implements its owm implementation of CallbackHandler.
 * An instance of CallbackHandler is passed as an argument to the LoginContext
 * instantiation. 
 * The LoginContext forwards the CallbackHandler directly to the underlying
 * LoginModules
 * so that they may interact with the application to retrieve specific
 * authentication data, 
 * such as usernames and passwords.
 * </p>
 * </Description>
 * 
 */
import java.io.IOException;
 
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
 
public class MyCallbackHandler implements CallbackHandler {
    
    private String userName = null;
    
    private String password = null;
    
    public void setUserName(String userName) {
        this.userName = userName;
    }
 
    public void setPassword(String password) {
        this.password = password;
    }
    
    @Override
    /**
     * sets user name and password into callback
     */
    public void handle(Callback[] callbacks) throws IOException,
        UnsupportedCallbackException {
        
        for (int i = 0; i < callbacks.length; i++) {
            Callback c = callbacks[i];
            if (c instanceof NameCallback) {
                ((NameCallback) c).setName(this.userName);
            } else if (c instanceof PasswordCallback) {
                char[] password = this.password.toCharArray();
                ((PasswordCallback) c).setPassword(password);
            } else {
                throw new UnsupportedCallbackException(callbacks[i],
                    "Unrecognized Callback");
            }
        }
        
    }
 
}

3.4.2 Running the Sample

To use the authentication custom assertion sample, perform the following steps:

  1. Create the custom assertion and custom assertion executor with the sample codes as described in Section 3.4.1, "Code Samples". These samples demonstrate the following key features:

    • Define the custom assertion implementation class:

            <orawsp:bindings>    
      <orawsp:Implementation>sampleAssertion.CustomAuthExecutor
      </orawsp:Implementation>
            </orawsp:bindings>
      

      For more information, see Section A.2.4, "orawsp:Implementation".

    • View the execution stage in the custom assertion executor:

      oracle.wsm.common.sdk.IMessageContext.STAGE stage =
       ((oracle.wsm.common.sdk.IMessageContext) context).getStage(); 
      

      For more information, see Section 4.3, "Accessing Request, Response, and Fault Message Objects".

    • In order to authenticate a user, you first need a javax.security.auth.login.LoginContext. Obtain a LoginContext. Use the LoginModule implementation specified by the entry named "CustomLoginModule" in the JAAS login configuration file and use the specified CallbackHandler as follows:

      Subject subject = new Subject();
      LoginContext lc = new LoginContext("CustomLoginModule", subject,
      callbackhandler);
      

      Once the caller has instantiated a LoginContext, it invokes the login method to authenticate a subject. If authentication is successful, the CustomLoginModule populates the Subject with a Principal representing the user.

      For more information, see http://docs.oracle.com/javase/7/docs/technotes/guides/security/jgss/tutorials/index.html.

      initializerCallbackHandler (Example 3-13) is used to check if incoming SOAP message contains UsernameToken, retrieve credentials from the incoming SOAP message and pass them to Login module class

    • In the event of success, set the result to success:

      result.setStatus(IResult.SUCCEEDED);
      
    • In the event of failure, set the fault that caused the request execution to fail:

      result.setStatus(IResult.FAILED);
                      throw new WSMException(
                          WSMException.FAULTCODE_QNAME_FAILED_AUTHENTICATION, e);
      

      For more information, see Section 4.8, "Handling Exceptions in Custom Assertions".

  2. Create the JAR file as described in Section 2.2.4, "Step 4: Create the JAR File".

  3. Add the custom policy to the policy store as described in Section 2.2.5, "Step 5: Add the Custom Policy to the Policy Store".

  4. Update the classpath as described in Section 2.2.6, "Step 6: Deploy the Custom Assertion".

  5. Attach the custom policy to the Web service by any one of the methods described in Section 2.2.7, "Step 7: Attach the Custom Policy to a Web Service".

  6. Create a client for the Web service. This sample custom policy uses wss_username_token_client_policy on the client side. Attach the wss_username_token_client_policy to the client.

  7. Create a configuration file and the class files that implement authentication as described in "Sample Authentication Files". For more information on the configuration file, refer to the JAAS API at http://docs.oracle.com/javase/7/docs/technotes/guides/security/jgss/tutorials/index.html.

  8. Specify the Login configuration file created in Example 3-15. You can specify the file in any one of the following ways:

    • Edit the script you use to start WebLogic Server to add the following option after the java command and restart the server:

      -Djava.security.auth.login.config==<path of LoginConfig file>

    • The Java security properties file is located in the file named <JAVA_HOME>/lib/security/java.security, where <JAVA_HOME> refers to the directory where the JDK was installed. In this file, change the value of the "login.configuration.provider" security property to the fully qualified name of the Login configuration file.

  9. Invoke request from the client. The user name and password set into client will be authenticated against configured login module which integrates with Weblogic authentication provider.