Hello, 

I am injecting a SAML Assertion in a SOAP Header from the SOAPClient and
then issuing a service request to a CXF webservice. On the service end I
have a JAX WS SOAP Handler that intercepts and unmarshals the header. The
client and service handlers are from Glen Mazza's weblog. 
http://www.jroller.com/gmazza/entry/using_the_opensaml_library_in

I am still including them incase any customary changes I may have made
messed up something. So here it is

------------------------------------------------------------------------------------------------------
SOAPClient:
------------------------------------------------------------------------------------------------------
package com.hsc.security.saml.soap;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Service;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import javax.xml.ws.soap.SOAPBinding;

import com.syscom.hsc.web.IBpmService;

public class SpringWSClient {
                
        String wsdlString =
"http://localhost:9088/bpm-servicesCXF/services/IBpmService";;
         //String wsdlString =
"http://localhost:9088/bpm-servicesCXF/services/IBpmService?wsdl=IBpmService.wsdl";;
          private static final QName SERVICE_NAME
      = new QName("http://web.hsc.syscom.com";, "BPMWebService");
          
           private static final QName PORT_NAME 
       = new QName("http://web.hsc.syscom.com";, "BpmServicePort");



        
        public static String xmlFileNamePath =  "BpmServices.xml";

        public static void main(String [] args){
                
                SpringWSClient ws = new SpringWSClient();
                System.out.println("Starting SOAP request");
                Service service = Service.create(SERVICE_NAME);
                
                //BPMWebService bpmServices = new BPMWebService(SERVICE_NAME);
                HeaderHandlerResolver handlerResolver = new  
HeaderHandlerResolver();
                service.setHandlerResolver(handlerResolver);
                
                   
                // Endpoint Address
                String endpointAddress =
"http://localhost:9088/bpm-servicesCXF/services/IBpmService";;
                try {
                        java.net.URL url = new URL(endpointAddress);
                } catch (MalformedURLException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                }

                // Add a port to the Service
                
                IBpmService client = service.getPort(IBpmService.class);

                Map<String, Object> requestContext =
((BindingProvider)client).getRequestContext();
                requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
endpointAddress);
                requestContext.put(BindingProvider.SESSION_MAINTAIN_PROPERTY,
Boolean.TRUE);

                String username = "kpham";
         String password = "hdfuhgdg";
         String category = "GETFULLEOPINWRK";
                 int max = -1;
                 Properties arguments = null;
                String response =null;
                try {
                        response = client.findTaskListUsingLoginCreds(username, 
password,
category, arguments, max);
                        //response = client.findTaskList(category, arguments, 
max);

                        System.out.println("Response: " + response);
                } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
                
           
        }

------------------------------------------------------------------------------------------------------
ClientSAMLHandler
------------------------------------------------------------------------------------------------------
public class ClientSAMLHandler implements SOAPHandler<SOAPMessageContext> {

   // change this to redirect output if desired
   private static PrintStream out = System.out;

   public static final String WS_SECURITY_NS_URI = 
         
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";;
   
   private static final Set<QName> HEADERS = new HashSet<QName>();
/*   static {
          HEADERS.add(new QName(WSConstants.WSSE_NS, "Security"));
          HEADERS.add(new QName(WSConstants.WSSE11_NS, "Security"));
          HEADERS.add(new QName(WSConstants.ENC_NS, "EncryptedData"));

      }
*/
   public Set getHeaders() {
    //return HEADERS;
           return null;
   }

   public boolean handleMessage(SOAPMessageContext smc) {
      Boolean outboundProperty = (Boolean)
smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

      if (outboundProperty.booleanValue()) {
         out.println("(debug) Adding SAML token to outbound message from
client");
         System.out.println("(debug) Adding SAML token to outbound message
from client");

         try {
            DefaultBootstrap.bootstrap();
            SOAPMessage message = smc.getMessage();
            SOAPPart soapPart = message.getSOAPPart();
            SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
            Name wsseHeaderName = soapEnvelope.createName("Security",
                  "wsse", WS_SECURITY_NS_URI);
            if (soapEnvelope.getHeader() == null) {
               soapEnvelope.addHeader();
            }
            SOAPHeaderElement securityElement = soapEnvelope.getHeader()
                  .addHeaderElement(wsseHeaderName);

            AssertionBuilder ab = new AssertionBuilder();
            Assertion assertion = ab.buildObject();
            assertion.setVersion(SAMLVersion.VERSION_20);
            assertion.setID("123"); // in reality, must be unique for all
assertions
            assertion.setIssueInstant(new DateTime());

            IssuerBuilder ib = new IssuerBuilder();
            Issuer myIssuer = ib.buildObject();
            myIssuer.setValue("http://localhost:9088";);
            assertion.setIssuer(myIssuer);

            SubjectBuilder sb = new SubjectBuilder();
            Subject mySubject = sb.buildObject();
            NameIDBuilder nb = new NameIDBuilder();
            NameID myNameID = nb.buildObject();
            myNameID.setValue("p8admin");
            myNameID.setFormat(NameIdentifier.X509_SUBJECT);
            mySubject.setNameID(myNameID);
            assertion.setSubject(mySubject);

            // user authenticated via X509 token
            AuthnStatementBuilder asb = new AuthnStatementBuilder();
            AuthnStatement myAuthnStatement = asb.buildObject();
            myAuthnStatement.setAuthnInstant(new DateTime());
            AuthnContextBuilder acb = new AuthnContextBuilder();
            AuthnContext myACI = acb.buildObject();
            AuthnContextClassRefBuilder accrb = new
AuthnContextClassRefBuilder();
            AuthnContextClassRef accr = accrb.buildObject();
            accr.setAuthnContextClassRef(AuthnContext.X509_AUTHN_CTX);
            myACI.setAuthnContextClassRef(accr);
            myAuthnStatement.setAuthnContext(myACI);
            assertion.getAuthnStatements().add(myAuthnStatement);

            // user can double even numbers
            AuthzDecisionStatementBuilder adsb = new
AuthzDecisionStatementBuilder();
            AuthzDecisionStatement ads = adsb.buildObject();
            ads.setDecision(DecisionTypeEnumeration.PERMIT);
            ads.setResource("DoubleIt");
            ActionBuilder actb = new ActionBuilder();
            Action act = actb.buildObject();
            // arbitrary unique tag to define "namespace" of action
            // note SAML actions not defined in an XSD -- XAMCL normally
used instead
            act.setNamespace("urn:doubleit:doubleitactions");
            act.setAction("DoubleEvenNumbers");
            ads.getActions().add(act);
            assertion.getAuthzDecisionStatements().add(ads);

            // user has math degree
            AttributeStatementBuilder attstmtb = new
AttributeStatementBuilder();
            AttributeStatement attstmt = attstmtb.buildObject();
            AttributeBuilder attbldr = new AttributeBuilder();
            Attribute attr = attbldr.buildObject();
            attr.setName("degree");
            attr.setNameFormat("http://www.example.org/DoubleIt/Security";);
            XSStringBuilder stringBuilder = (XSStringBuilder) Configuration
                  .getBuilderFactory().getBuilder(XSString.TYPE_NAME);
            XSString stringValue = stringBuilder
                  .buildObject(AttributeValue.DEFAULT_ELEMENT_NAME,
                        XSString.TYPE_NAME);
            stringValue.setValue("Mathematics");
            attr.getAttributeValues().add(stringValue);
            attstmt.getAttributes().add(attr);
            assertion.getAttributeStatements().add(attstmt);

            // marshall Assertion Java class into XML
            MarshallerFactory marshallerFactory = Configuration
                  .getMarshallerFactory();
            Marshaller marshaller = marshallerFactory
                  .getMarshaller(assertion);
            Element assertionElement = marshaller.marshall(assertion);
            securityElement.appendChild(soapPart.importNode(
                  assertionElement, true));
            
            //Print out the outbound SOAP message to System.out
            message.writeTo(System.out);
            System.out.println("");
            
         } catch (Exception e) {
            e.printStackTrace();
         }
      }
      else{
          try {
              
              //This handler does nothing with the response from the Web
Service so
              //we just print out the SOAP message.
              SOAPMessage message = smc.getMessage();
              message.writeTo(System.out);
              System.out.println("");

          } catch (Exception ex) {
              ex.printStackTrace();
          }
      }
      return true;
   }

   public boolean handleFault(SOAPMessageContext smc) {
      out.println("Exception in Client handler: ");
      SOAPMessage message = smc.getMessage();
      try {
         message.writeTo(out);
         out.println(""); // just to add a newline
      } catch (Exception e) {
         out.println("Unable to write exception for exception: "
            + e.toString());
      }
      return true;
   }

   // nothing to clean up
   public void close(MessageContext messageContext) {
   }

}


}

The SOAP Client then issues the service request, the Service JAX WS Handler
intercepts the incoming message. The handleMessage is invoked, however I see
a SOAPFaultException being thrown - 
------------------------------------------------------------------------------------------------------
[2/24/10 14:10:33:974 EST] 00000022 HandlerChainI 1   invoking handlers,
direction: inbound
[2/24/10 14:10:33:974 EST] 00000022 HandlerChainI 1   invoking handler of
type com.syscom.hsc.web.soap.ServiceSAMLHandler
[2/24/10 14:10:33:974 EST] 00000022 SystemOut     O   Inside handleMessage
----> 
[2/24/10 14:10:33:974 EST] 00000022 SystemOut     O   Inside handleMessage
----> outboundProperty.booleanValue() false
[2/24/10 14:10:33:974 EST] 00000022 SystemOut     O   Inside handleMessage
----> sh.toString()[soap:Header: null]
[2/24/10 14:10:33:974 EST] 00000022 SystemOut     O   Inside handleMessage
----> wsseElement.getLocalName()Security
[2/24/10 14:10:33:974 EST] 00000022 SystemOut     O   Inside handleMessage
---->
wsseElement.getNamespaceURI()http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd
[2/24/10 14:10:33:974 EST] 00000022 SystemOut     O   Inside handleMessage
----> assertionElement.getLocalName()Assertion
[2/24/10 14:10:33:974 EST] 00000022 SystemOut     O   Inside handleMessage
---->
assertionElement.getNamespaceURI()urn:oasis:names:tc:SAML:2.0:assertion
[2/24/10 14:10:34:224 EST] 00000022 Configuration W
org.opensaml.xml.Configuration validateJCEProviders The JCE providers
currently configured in the JVM do not support
required capabilities for XML Encryption, either the 'AES' cipher algorithm
or the 'ISO10126Padding' padding scheme

handleMessage raised exception
                                 javax.xml.ws.soap.SOAPFaultException:
Internal Error: local part cannot be "null" when creating a QName
        at
com.syscom.hsc.web.soap.ServiceSAMLHandler.createSOAPFaultException(ServiceSAMLHandler.java:253)
        at
com.syscom.hsc.web.soap.ServiceSAMLHandler.handleMessage(ServiceSAMLHandler.java:234)
        at
com.syscom.hsc.web.soap.ServiceSAMLHandler.handleMessage(ServiceSAMLHandler.java:1)
        at
org.apache.cxf.jaxws.handler.HandlerChainInvoker.invokeHandleMessage(HandlerChainInvoker.java:335)
        at
org.apache.cxf.jaxws.handler.HandlerChainInvoker.invokeHandlerChain(HandlerChainInvoker.java:253)
        at
org.apache.cxf.jaxws.handler.HandlerChainInvoker.invokeProtocolHandlers(HandlerChainInvoker.java:131)
.-----------------------------------------------------------------------------------------------------




Here is the ServiceHandler
------------------------------------------------------------------------------------------------------
SAMLServiceHandler
------------------------------------------------------------------------------------------------------
package com.syscom.hsc.web.soap;
import java.io.PrintStream;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFactory;
import javax.xml.soap.SOAPFault;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import javax.xml.ws.soap.SOAPFaultException;

import org.apache.ws.security.WSConstants;
import org.opensaml.Configuration;
import org.opensaml.DefaultBootstrap;
import org.opensaml.saml2.core.Action;
import org.opensaml.saml2.core.Assertion;
import org.opensaml.saml2.core.Attribute;
import org.opensaml.saml2.core.AttributeStatement;
import org.opensaml.saml2.core.AuthnContext;
import org.opensaml.saml2.core.AuthnStatement;
import org.opensaml.saml2.core.AuthzDecisionStatement;
import org.opensaml.xml.XMLObject;
import org.opensaml.xml.io.Unmarshaller;
import org.opensaml.xml.io.UnmarshallerFactory;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import org.opensaml.common.xml.SAMLConstants;

import com.syscom.hsc.web.security.saml.SAMLCredential;

/*
 * This sample SOAP Protocol Handler for DoubleIt checks for X.509
authentication,
 * attribute of Math degree, and authorization to double even numbers.
 */
public class ServiceSAMLHandler implements SOAPHandler<SOAPMessageContext> {

   // change this to redirect output if desired
   private static PrintStream out = System.out;

   private static String WS_SECURITY_URI =
     
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";;
   private static final String HANDLER_NAME = "ServiceSAMLHandler";


   private static final Set<QName> HEADERS = new HashSet<QName>();
 /*  static {
       HEADERS.add(new QName(WSConstants.WSSE_NS, "Security"));
       HEADERS.add(new QName(WSConstants.WSSE11_NS, "Security"));
       HEADERS.add(new QName(WSConstants.ENC_NS, "EncryptedData"));
   }
*/
   @PostConstruct
   public void init() {
      out.println("------------------------------------");
      out.println("In Handler " + HANDLER_NAME + ":init()");
      out.println("Exiting Handler " + HANDLER_NAME + ":init()");
      out.println("------------------------------------");
   }

   @PreDestroy
   public void destroy() {
      out.println("------------------------------------");
      out.println("In Handler " + HANDLER_NAME + ":destroy()");
      out.println("Exiting Handler " + HANDLER_NAME + ":destroy()");
      out.println("------------------------------------");
   }

   
   public Set <QName> getHeaders() {
      //return HEADERS;
           return null;
   }

   public boolean handleMessage(SOAPMessageContext smc) {
           out.println("Inside handleMessage ----> ");
           Boolean outboundProperty = (Boolean) smc
            .get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);


      if (!outboundProperty.booleanValue()) {
           out.println("Inside handleMessage ---->
outboundProperty.booleanValue() "+outboundProperty.booleanValue());
           logToSystemOut(smc);
          Element assertionElement;

         try {
            // check for SOAP Header
            SOAPHeader sh = smc.getMessage().getSOAPHeader();
            out.println("Inside handleMessage ---->
sh.toString()"+sh.toString());
            if (sh == null) {
               throw createSOAPFaultException("Missing SOAP Header", true);
            }

            // check for wsse:security element under SOAP Header
            Node wsseElement = sh.getFirstChild();
            out.println("Inside handleMessage ---->
wsseElement.getLocalName()"+wsseElement.getLocalName());
            out.println("Inside handleMessage ---->
wsseElement.getNamespaceURI()"+wsseElement.getNamespaceURI());

            if (wsseElement == null ||
!"Security".equals(wsseElement.getLocalName())
                  || !WS_SECURITY_URI.equals(wsseElement.getNamespaceURI()))
{
               throw createSOAPFaultException("Missing or invalid
WS-Security Header",
                     true);
            }

            // check for SAML assertion under wsse:security element
            assertionElement = (Element) wsseElement.getFirstChild();

            out.println("Inside handleMessage ---->
assertionElement.getLocalName()"+assertionElement.getLocalName());
            out.println("Inside handleMessage ---->
assertionElement.getNamespaceURI()"+assertionElement.getNamespaceURI());
            if (assertionElement == null
                  || !"Assertion".equals(assertionElement.getLocalName())
                  ||
!SAMLConstants.SAML20_NS.equals(assertionElement.getNamespaceURI())) {
               throw createSOAPFaultException("Missing or invalid SAML
Assertion", true);
            }

            // Unmarshall SAML Assertion into an OpenSAML Java object.
            DefaultBootstrap.bootstrap();
            UnmarshallerFactory unmarshallerFactory = Configuration
                  .getUnmarshallerFactory();
            Unmarshaller unmarshaller = unmarshallerFactory
                  .getUnmarshaller(assertionElement);
            Assertion samlAssertion = (Assertion) unmarshaller
                  .unmarshall(assertionElement);

            /*
             * Below code works with OpenSAML API to check Authentication,
             * Authorization, and attributes. Using the XPath API with the
             * assertionElement above would probably be an easier and more
             * readable option.
             */
            //Check for Subject
            out.println("Subject from Service
Handler"+samlAssertion.getSubject().getNameID().getValue());
            //SAMLCredential samlCred = new
SAMLCredential(samlAssertion.getSubject().getNameID(), samlAssertion);
           
SAMLCredential.setNameID(samlAssertion.getSubject().getNameID());
            SAMLCredential.setAuthenticationAssertion(samlAssertion);
            
            
            // Check for X509 authentication, error otherwise
            List authStmtList = samlAssertion.getAuthnStatements();
            if (authStmtList == null || authStmtList.size() < 1
                  || authStmtList.size() > 1) {
               throw createSOAPFaultException("Missing Authentication
Statement.", true);
            } else {
               AuthnStatement authStmt = (AuthnStatement)
authStmtList.get(0);
               if
(!AuthnContext.X509_AUTHN_CTX.equals(authStmt.getAuthnContext()
                     .getAuthnContextClassRef().getAuthnContextClassRef()))
{
                  throw createSOAPFaultException("Only X.509 authentication
supported.",
                        true);
               }
            }

            // Check if math degree, error otherwise
            List asList = samlAssertion.getAttributeStatements();
         /*   if (asList == null || asList.size() == 0) {
               throw createSOAPFaultException("Degree/Major is missing.",
true);
            } else {
               boolean hasMathDegree = false;
               for (Iterator it = asList.iterator(); it.hasNext();) {
                  AttributeStatement as = it.next();
                  List attList = as.getAttributes();
                  if (attList == null || attList.size() == 0) {
                     throw createSOAPFaultException("Degree/major is
missing.", true);
                  } else {
                     for (Iterator it2 = attList.iterator(); it2.hasNext();)
{
                        Attribute att = it2.next();
                        if (!att.getName().equals("degree")) {
                           continue;
                        } else {
                           List xoList = att.getAttributeValues();
                           if (xoList == null || xoList.size() < 1 ||
xoList.size() > 1) {
                              throw createSOAPFaultException("Degree/major
is missing.",
                                    true);
                           } else {
                              XMLObject xmlObj = xoList.get(0);
                              if
(xmlObj.getDOM().getFirstChild().getTextContent()
                                    .equals("Mathematics")) {
                                 hasMathDegree = true;
                              }
                           }
                        }
                     }
                  }
               }
               if (hasMathDegree == false) {
                  throw createSOAPFaultException(
                        "Must have Mathematics degree to run DoubleIt.",
true);
               }
            }
*
            // If even number being doubled, make sure user has permission
            SOAPBody sb = smc.getMessage().getSOAPBody();

            if (sb.getFirstChild() == null ||
sb.getFirstChild().getFirstChild() == null) {
               throw createSOAPFaultException("Invalid SOAP Body", true);
            } else {
               Integer intValue = new
Integer(sb.getFirstChild().getFirstChild()
                     .getTextContent());
               if ((intValue.intValue() % 2) == 0) { // if even
                  List adsList = samlAssertion
                        .getAuthzDecisionStatements();
                  if (adsList == null || adsList.size() < 1 ||
adsList.size() > 1) {
                     throw createSOAPFaultException(
                           "Missing or invalid Authorization Decision
Statement", true);
                  } else {
                     Boolean canDoubleEven = false;
                     AuthzDecisionStatement ads = (AuthzDecisionStatement)
adsList.get(0);
                     List actList = ads.getActions();
                     for (Iterator it = actList.iterator(); it.hasNext();) {
                        Action action = (Action) it.next();
                        if ("DoubleEvenNumbers".equals(action.getAction()))
{
                           canDoubleEven = true;
                           break;
                        }
                     }
                     if (canDoubleEven == false) {
                        throw createSOAPFaultException(
                              "Missing authorization to double even
numbers.", true);
                     }
                  }
               }
            }*/
         } catch (Exception e) {
            throw createSOAPFaultException("Internal Error: " +
e.getMessage(), false);
         }
      }
      return true;
   }

   /*
    * Convenience function used to generate a generic SOAPFaultException
    */
   private SOAPFaultException createSOAPFaultException(String faultString,
         Boolean clientFault) {
      try {
          System.out.println("*********clientFault***********"+clientFault);
         String faultCode = clientFault ? "Client" : "Server";
         System.out.println("*********faultCode***********"+faultCode);
         SOAPFault fault = SOAPFactory.newInstance().createFault();
         System.out.println("*********faultString***********"+faultString);
         fault.setFaultString(faultString);
         fault.setFaultCode(new QName(SOAPConstants.URI_NS_SOAP_ENVELOPE,
faultCode));
         return new SOAPFaultException(fault);
      } catch (SOAPException e) {
         throw new RuntimeException("Error creating SOAP Fault message,
faultString: "
               + faultString);
      }
   }

   public boolean handleFault(SOAPMessageContext smc) {
           
           out.println("------------------------------------");
              out.println("In Handler " + HANDLER_NAME + ":handleFault()");
              logToSystemOut(smc);
              out.println("Exiting Handler " + HANDLER_NAME + ":handleFault()");
              out.println("------------------------------------");

      return true;
   }

   // nothing to clean up
   public void close(MessageContext messageContext) {
           out.println("------------------------------------");
              out.println("In Handler " + HANDLER_NAME + ":close()");
              out.println("Exiting Handler " + HANDLER_NAME + ":close()");
              out.println("------------------------------------");

   }

   /*
    * Check the MESSAGE_OUTBOUND_PROPERTY in the context to see if this is
an
    * outgoing or incoming message. Write a brief message to the print
stream
    * and output the message. The writeTo() method can throw SOAPException
or
    * IOException
    */
   private void logToSystemOut(SOAPMessageContext smc) {
      Boolean outboundProperty = (Boolean) smc
            .get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

      if (outboundProperty.booleanValue()) {
         out.println("\nIncoming message to web service provider:");
      } else {
         out.println("\nOutgoing message from web service provider:");
      }

      SOAPMessage message = smc.getMessage();
      try {
         message.writeTo(out);
         out.println(""); // just to add a newline
      } catch (Exception e) {
         out.println("Exception in handler: " + e);
      }
   }

}

I am not sure what the local part here is and how can I circumvent it from
being Null. Any clue or suggestions will be well appreciated. 




-- 
View this message in context: 
http://old.nabble.com/local-part-cannot-be-%22null%22-when-creating-a-QName-tp27714287p27714287.html
Sent from the cxf-user mailing list archive at Nabble.com.

Reply via email to