3 Managing Sample Custom Assertions

Managing custom assertions include activities such as validating IP address, encrypting and decrypting data, and authenticating a user in a custom assertion.

The following topics explain this further:

3.1 Validating IP Address in Custom Assertion

The IP Address 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.

This section includes the following topics:

3.1.1 Validating IP Address Using Custom Assertion Executor

Follow this sample to validate an IP address using the custom assertion executor.

The following is the 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;
    }
}

3.1.2 Validating IP Address Using Policy File

Follow this sample to validate the IP address using Policy File.

The following is the 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>

3.1.3 Validating IP Address Using policy-config.xml File

Follow the sample 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 Specifying the Custom Assertion Executor.

<?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>

3.1.4 Validating IP Address Using Web Service

Follow the sample to validate the IP address using web service.

You can attach the custom assertion to a web service as described in Attaching the Custom Policy to a 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";
    }
}

3.1.5 Validating IP Address Using JSE Client

Follow the sample to validate IP Address using JSE client generated from the web service.

The following sample shows a JSE client generated from the web service shown in Validating IP Address Using Web Service.

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 Performing IP Address Validation in Custom Assertion

You can perform IP address validation in custom assertion by creating the custom assertion and the JAR file, adding the custom policy to the custom store, updating the CLASSPATH, attaching the custom policy to the web service, and finally testing the web service.

To perform IP address validation in custom assertion:

  1. Create the custom assertion and custom assertion executor with the sample codes as described in Validating IP Address Using Custom Assertion Executor. These samples demonstrate the following key features:
    • Specify the valid values of IP addresses in the custom assertion:

      <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>
      

      For more information, see Supplying Parameters for Custom Assertions.

    • 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 Accessing OWSM Custom Security Assertion.

    • Access the IP address from the custom assertion executor:

      IConfig config = bindings.getConfigs().get(0);
      IPropertySet propertyset = config.getPropertySets().get(0);
      String valid_ips = propertyset.getPropertyByName("valid_ips").getValue();
      

      For more information, see Supplying Parameters for Custom Assertions.

    • Access the context property remote address:

      String ipAddr = ((IMessageContext)context).getRemoteAddr();
      

      For more information, see Examining OWSM Context Properties.

    • In the event of failure, set the fault that caused the request execution to fail:

      result.setFault(new WSMException(WSMException.FAULT_FAILED_CHECK));
      

      For more information, see Handling Exceptions in Custom Assertions.

  2. Create the JAR file as described in Creating the Custom Assertion JAR File.
  3. Add the custom policy to the policy store as described in Adding the Custom Policy to the Policy Store.
  4. Update the CLASSPATH as described in Deploying the Custom Assertion.
  5. Attach the custom policy to the web service by any one of the methods described in Attaching the Custom Policy to a Web Service.
  6. Test the web service by creating a JSE client as shown in Validating IP Address Using JSE Client.

3.3 Encrypting and Decrypting Data in Custom Assertion

The Encryption and Decryption Custom Assertion sample uses a set of custom assertions to encrypt data from an inbound message, which makes it unreadable from consoles, audit trails, or logs. The encrypted data is decrypted for outbound messages for downstream services that require access to the data.

This section includes the following topics:

3.3.1 Encrypting and Decrypting Data Using Custom Assertion Executor

Follow the sample custom assertion executor for encryption and decryption of data.

The following is the sample custom assertion executor. For more information on the implementation, see Performing Data Encryption and Decryption in Custom Assertion.

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()
  
} 

3.3.2 Encrypting Elements of an Inbound Message Using Custom Assertion Executor

Follow the sample custom assertion executor for encrypting an element of an inbound message.

The following is the sample custom assertion executor:

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

3.3.3 Decrypting Elements of an Outbound Message Using Custom Assertion Executor

Follow the sample custom assertion executor for decrypting an element of an outbound message.

The following is the sample custom assertion executor:

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;
      }
    
      // 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

3.3.4 Encrypting Data Using Custom Assertion Executor

Follow the sample custom assertion executor for encryption.

The following is the sample custom assertion executor:

<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>

3.3.5 Decrypting Data Using Custom Assertion Executor

Follow the sample custom assertion executor to decrypt data.

The following is a sample custom assertion 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>

3.3.6 Receiving the Encrypted Message Using Composite Application

Follow the sample composite application with a BPEL process to demonstrate that it received the encrypted value.

The following is the sample composite application:

<?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>

3.3.7 Receiving the Decrypted Message Using Composite Application

Follow the sample composite application to represent an external service being called and show that it received the decrypted value.

The following is the sample composite application:

<?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.4 Performing Data Encryption and Decryption in Custom Assertion

You can perform data encryption and decryption in custom assertion by creating custom assertion policy file and JAR file, adding the custom policy to the policy store, updating the CLASSPATH and finally attaching the custom policy to the web service.

To perform data encryption and decryption in custom assertion:

  1. Create the custom assertion policy file and custom assertion executor with the sample codes as described in Encrypting and Decrypting Data in Custom Assertion. 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 Supplying Parameters for 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 Supplying Parameters for 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 Accessing Parts of a Message Using XPath.

  2. Create the JAR file as described in Creating the Custom Assertion JAR File.
  3. Add the custom policy to the policy store as described in Adding the Custom Policy to the Policy Store.
  4. Update the CLASSPATH as described in Deploying the Custom Assertion.
  5. Attach the custom policy to the web service by any one of the methods described in Attaching the Custom Policy to a Web Service.

3.5 Authenticating a User in Custom Assertion

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.

This section includes the following topics:

3.5.1 Authenticating Using Custom Assertion Executor

Follow the sample executor to understand how it invokes the custom login module to perform the authentication.

The following example describes it.

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");

 context.setProperty(oracle.wsm.common.sdk.IMessageContext.SECURITY_SUBJECT,sub);                
                //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() {
    }
   }

3.5.2 Authenticating Using Policy File

Follow the sample custom assertion that invokes the executor which is used to authenticate users against WebLogic authentication provider.

The following sample is a custom assertion that invokes the executor described in Authenticating Using Custom Assertion Executor, which is used to authenticate users against WebLogic authentication provider.

<?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>

3.5.3 Implementing User Authentication Using Files

You can authenticate a user using the login configuration file and the implement various classes as specified in the file.

It contains the following topics:

3.5.3.1 Authenticating Using Login Configuration File

The following sample describes a Login configuration file that contains an entry specifying the Login Module that is to be used to do the user authentication.

/** 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/1.4.2/docs/api/javax/security/auth/login/Config
uration.html and 
http://download.oracle.com/javase/1.4.2/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;
};

3.5.3.2 Implementing a Custom Login Module Class

Follow the sample CustomLoginModule class that provides an implementation of javax.security.auth.spi.LoginModule and authenticates a user against WebLogic authentication provider.

The following is a sample CustomLoginModule class that is specified by the LoginConfig file in Authenticating Using Login Configuration File.

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;
                    }
                });
        }
    }
}

3.5.3.3 Implementing a Simple Login Module Class

Follow the sample SimpleLoginModule class that provides an implementation of javax.security.auth.spi.LoginModule.

The following is the sample SimpleLoginModule class:

/**
 * <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;
    }
    
 
}

3.5.3.4 Implementing a Callback Handler Class

Follow the sample CallbackHandler class that provides an implementation of javax.security.auth.callback.Callback interface.

The following is the sample CallbackHandler class:

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.6 Performing User Authentication in Custom Assertion

You can perform user authentication in custom assertion by creating the necessary files, specifying the login configuration file and by invoking the request from the client for authentication.

To perform user authentication in custom assertion:

  1. Create the custom assertion and custom assertion executor with the sample codes as described in Authenticating a User in Custom Assertion. 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 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 Accessing OWSM Custom Security Assertion.

    • 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://download.oracle.com/javase/1.5.0/docs/guide/security/jgss/tutorials/index.html.

      initializerCallbackHandler (from Authenticating Using Custom Assertion Executor) 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 Handling Exceptions in Custom Assertions.

  2. Create the JAR file as described in Creating the Custom Assertion JAR File.
  3. Add the custom policy to the policy store as described in Adding the Custom Policy to the Policy Store.
  4. Update the CLASSPATH as described in Deploying the Custom Assertion.
  5. Attach the custom policy to the web service by any one of the methods described in Attaching 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 Implementing a Custom Login Module Class. For more information on the configuration file, refer to the JAAS API at http://download.oracle.com/javase/1.5.0/docs/guide/security/jgss/tutorials/index.html.
  8. Specify the Login configuration file created in Authenticating Using Login Configuration File. 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.