Friday, April 9, 2010

While creating Metro client for a basic authenticated webservice

I was facing with an issue creating the Metro client for a webservice - secured with plain text username & password.
Issue:
     Header was not appearing the Soap Request
Error logged:
    Apr 9, 2010 3:49:57 PM [com.sun.xml.ws.policy.EffectiveAlternativeSelector]  doSelection
    WARNING: WSP0075: Policy assertion "{http://www.bea.com/wls90/security/policy}Identity" was evaluated as "UNKNOWN".
    Apr 9, 2010 3:49:57 PM [com.sun.xml.ws.policy.EffectiveAlternativeSelector]  doSelection
    WARNING: WSP0019: Suboptimal policy alternative selected on the client side with fitness "UNKNOWN".
    ..
    ..
    javax.xml.ws.soap.SOAPFaultException: No Security header in message but required by policy.
    ..


The Workarounds:
 1. Adding the Username & Password in BindingProvider.USERNAME_PROPERTY in RequestContext. It sets value for "javax.xml.ws.security.auth.username(password)". The BindingProvider interface provides access to the protocol binding and associated context objects for request and response message processing. Eventually, the username and password has to be added in the form of an HTTP Basic Authentication header. (List of javax.xml constants)
    Result: didn't work


2. XWSSConstants.USERNAME_PROPERTY in RequestContext
    Result: didn't work (for my app)


3. Programmatically added the header ;)
    Result:    it worked :)

Here is how I did it - explained:

    Click here to Enlarge

Code - For copy & paste
try {
            SOAPFactory soapFactory = SOAPFactory.newInstance();
            String SECURITY_NAMESPACE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
            QName securityQName = new QName(SECURITY_NAMESPACE, "Security");
            SOAPElement security = soapFactory.createElement(securityQName);
            QName usernameTokenQName = new QName(SECURITY_NAMESPACE, "UsernameToken");
            SOAPElement usernameToken = soapFactory.createElement(usernameTokenQName);
            QName usernameQName = new QName(SECURITY_NAMESPACE, "Username");
            SOAPElement username = soapFactory.createElement(usernameQName);
            username.addTextNode("username");
            QName passwordQName = new QName(SECURITY_NAMESPACE, "Password");
            SOAPElement password = soapFactory.createElement(passwordQName);
            password.addTextNode("password");
            usernameToken.addChildElement(username);
            usernameToken.addChildElement(password);
            security.addChildElement(usernameToken);
            Header header = Headers.create(security);
            ((WSBindingProvider) port).setOutboundHeaders(header);
        } catch (SOAPException e) {
            System.out.println("Failed adding the security token to header");
            e.printStackTrace();
        }


Misc:

1 comment:

  1. Hi Noufal,

    do you mind if I ask one question.

    The 1st and 2nd option do not work. Because the 1st one add username and password in the HTTP Header, not the SOAP Header. And the 2nd option does not add anything in the SOAP Header, or it will add with a specific dependency.

    My question is, do you know which dependency or condition for the second option (XWSSConstants)?

    Thank you very much

    ReplyDelete