This discussion is archived
7 Replies Latest reply: Jan 9, 2013 6:31 AM by 870199 RSS

problems with JAX-WS when using security (e.g. username token profile)

870199 Newbie
Currently Being Moderated
Hello,
I have a JAX-WS 2.1.5 deployed on weblogic 11g (10.3.1) with this policy:

<wsp:UsingPolicy wssutil:Required="true"/>
<wsp:Policy wssutil:Id="Hdm-UserNameToken-Plain">
<ns1:SupportingTokens xmlns:ns1="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200512">
<wsp:Policy>
<ns1:UsernameToken ns1:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200512/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<ns1:WssUsernameToken10/>
</wsp:Policy>
</ns1:UsernameToken>
</wsp:Policy>
</ns1:SupportingTokens>
</wsp:Policy>

I have another web application as client which is using a JAX-WS SOAP handler to communicate with web service
and everything works fine when my client runs in stand-alone manner i.e. in Eclipse (JDK 6) (anthentication goes through)

The handleMessage() method of my handler is posted here :
public boolean handleMessage(SOAPMessageContext context) {
     final Boolean outbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outbound)
try {
// Get the SOAP Envelope
final SOAPEnvelope envelope = context.getMessage().getSOAPPart().getEnvelope();

// Header may or may not exist
SOAPHeader header = envelope.getHeader();
if (header == null)
header = envelope.addHeader();

// Add WSS Usertoken Element Tree
final SOAPElement security = header.addChildElement("Security", "wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
final SOAPElement userToken = security.addChildElement("UsernameToken", "wsse");
userToken.addChildElement("Username", "wsse").addTextNode(userName);
userToken.addChildElement("Password", "wsse").addTextNode(password);

}
catch (SOAPException ex) {
ex.printStackTrace();
return false;
}

return true;
}

but when I deploy the same client on weblogic server it fails to communicate with my web service with this error:
javax.xml.ws.soap.SOAPFaultException: Unable to add security token for identity, token uri =http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#UsernameToken

I noticed Weblogic has some packages to handle security like:
weblogic.wsee.security.unt.ClientUNTCredentialProvider
weblogic.xml.crypto.wss.provider.CredentialProvider
weblogic.xml.crypto.wss.WSSecurityContext

So I added another mechanism using weblogic package to add username password to SOAP header

Map<String, Object> request = ((BindingProvider) proxy).getRequestContext();
if (connectInfo.get("username") != null && connectInfo.get("password") != null) {
List<CredentialProvider> credProviders = new ArrayList<CredentialProvider>();
//client side UsernameToken credential provider
CredentialProvider cp = new ClientUNTCredentialProvider((String)connectInfo.get("username"),
(String)connectInfo.get("password"));
credProviders.add(cp);
request.put(WSSecurityContext.CREDENTIAL_PROVIDER_LIST, credProviders);
}

This seems to be ok but only for weblogic.

I don't want to use weblogic propritery style in my client code i.e. using APIs ClientUNTCredentialProvider, WSSecurityContext etc, because for these to use i would need to have Weblogic jar which would cause me another issues..

Is this an incompatibly issue or am i missing something, please suggest how to add security token for identity in SOAPHeader without using Weblogic specific APIs??
  • 1. Re: problems with JAX-WS when using security (e.g. username token profile)
    870199 Newbie
    Currently Being Moderated
    Also, adding to above details, i tried below too but NO help:

    final SOAPEnvelope envelope = context.getMessage().getSOAPPart().getEnvelope();
    SOAPHeader header = envelope.getHeader();
    final SOAPElement security = header.addHeaderElement(envelope.createName("Security", "wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"));
    final SOAPElement userToken = security.addChildElement("UsernameToken", "wsse");
    userToken.addChildElement("Username", "wsse").addTextNode(userName);
    userToken.addChildElement("Password", "wsse").addTextNode(password);

    i.e. instead of using 'addHeaderElement' i tried addHeaderElement, but No luck, got the same issue... in handleMessage(....) method i tried to print SOAPHeader, SOAPEnvelope etc after the processing and i got below:

    userToken ---------> [wsse:UsernameToken: null]

    envelope ---------> [S:Envelope: null]

    header ---------> [S:Header: null]
  • 2. Re: problems with JAX-WS when using security (e.g. username token profile)
    user696 Explorer
    Currently Being Moderated
    1)Edit WSDL file on client side

    Comment the PolicyReference under the binding element
    <wsp:PolicyReference URI="#XXXXX_Policy.xml"/>

    .
    2)Edit client code were your creating Service object
    For Example: helloImplService = new HelloImplService(HelloImplPortClient.class.getResource("HelloImplService.wsdl"), new QName("http://examples.webservices.hello_jws/","HelloImplService"));

    3)You may change the ws endpoint url by adding this line:
    requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,"https://localhost:7002/HelloImpl/HelloImplService");

    See if that works.

    Regards,
    Sunil P
  • 3. Re: problems with JAX-WS when using security (e.g. username token profile)
    870199 Newbie
    Currently Being Moderated
    Many thanks Sunil for quick response, i will try it out!

    Rgds,
  • 4. Re: problems with JAX-WS when using security (e.g. username token profile)
    user696 Explorer
    Currently Being Moderated
    1. Commenting "<wsp:PolicyReference....../>" would mean, i will be able to call my web-service without uname and pwd?
    You will comment on the client side WSDL but the server side wsdl should still have the reference <wsp:PolicyReference....../> and use the SOAP handler code to populate username and password.

    2. Do you have any sample code which reads a WSDL URL and edit it, if yes could you please share??
    You need not read it from url you can copy the wsdl file on local machine and edit it and pass this wsdl file on client side, i do not have any code.


    3. Is 3rd step mandatory?
    If you have right value inside the <soap:address location="http://localhost:7001/contextroot/app"/> you need not require it

    Regards,
    Sunil P
  • 5. Re: problems with JAX-WS when using security (e.g. username token profile)
    870199 Newbie
    Currently Being Moderated
    Indeed solution you gave worked for me :-)

    With following two changes in WSDL:

    1. Commenting "<wsp:PolicyReference....../>" [This is fine -- One time job]

    updating the wsdl manually and using for my purpose does not look like the right approach, Is there NO other way of doing this??
  • 6. Re: problems with JAX-WS when using security (e.g. username token profile)
    user696 Explorer
    Currently Being Moderated
    I am glad it worked, please mark the pst which had helped so that it benefits others, I can only think of that solution. If you do not want to change the <soap12:address you might using ENDPOINT_ADDRESS_PROPERTY

    http://jax-ws.java.net/articles/MessageContext.html
    http://tugdualgrall.blogspot.com/2009/02/jax-ws-how-to-configure-service-end_17.html

    Regards,
    Sunil P
  • 7. Re: problems with JAX-WS when using security (e.g. username token profile)
    870199 Newbie
    Currently Being Moderated
    Yes, indeed, i had done the same, I did not have to modify XML for that rather i did following:

    final Binding binding = ((BindingProvider) wsService).getBinding();
    List<Handler> handlerList = binding.getHandlerChain();
    if (handlerList == null)
         handlerList = new ArrayList<Handler>();

    handlerList.add(new WsSecuritySOAPHandler(username, password));
    binding.setHandlerChain(handlerList);

    BindingProvider bindingProvider = (BindingProvider) wsService;
    Map<String,Object> rc = (Map<String,Object>)bindingProvider.getRequestContext();
    rc.put(BindingProvider.USERNAME_PROPERTY, username);
    rc.put(BindingProvider.PASSWORD_PROPERTY, password);
    rc.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, wsdlURL.substring(0, wsdlURL.length() - "?WSDL".length()));

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points