How to consume a WebService that uses Ws-Security Authentication (UsernameToken) – OWSM – Oracle Service Bus (OSB)

The Oracle Service Bus (OSB) allows to enable OWSM authentication, there is many policies that can be applied to the Proxy Service to turn on security authentication. The most basic of this policies is:

oracle / wss_username_token_service_policy

Requiring only a username and password. Once enabled this security, following a tip on how to make a request using a Java Client.

File: MainPost.java – This is a main class to make a request

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.List;

import javax.xml.datatype.DatatypeConstants;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.handler.Handler;

public class MainPost {

public static void main(String[] args) {

try {

MyService service = new MyService();
MyServicePort myServicePort = service.getMySoapPort();

// This is the block that apply the Ws Security to the request
BindingProvider bindingProvider = (BindingProvider) myServicePort;
@SuppressWarnings("rawtypes")
List<Handler> handlerChain = new ArrayList<Handler>();
handlerChain.add(new WSSecurityHeaderSOAPHandler("myUsername", "myPassword"));
bindingProvider.getBinding().setHandlerChain(handlerChain);

RequestType myRequest = new RequestType();
myRequest.setId(25);

ResponseType response = myServicePort.searchSomething(myRequest);

} catch (Exception e) {
e.printStackTrace();
}
}
}

File: WSSecurityHeaderSOAPHandler.java – This is a handler responsible for creating the header authentication.

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.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

public class WSSecurityHeaderSOAPHandler implements SOAPHandler<SOAPMessageContext> {

private static final String SOAP_ELEMENT_PASSWORD = "Password";
private static final String SOAP_ELEMENT_USERNAME = "Username";
private static final String SOAP_ELEMENT_USERNAME_TOKEN = "UsernameToken";
private static final String SOAP_ELEMENT_SECURITY = "Security";
private static final String NAMESPACE_SECURITY = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
private static final String PREFIX_SECURITY = "wsse";

private String usernameText;
private String passwordText;

public WSSecurityHeaderSOAPHandler(String usernameText, String passwordText) {
this.usernameText = usernameText;
this.passwordText = passwordText;
}

public boolean handleMessage(SOAPMessageContext soapMessageContext) {

Boolean outboundProperty = (Boolean) soapMessageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

if (outboundProperty.booleanValue()) {

try {
SOAPEnvelope soapEnvelope = soapMessageContext.getMessage().getSOAPPart().getEnvelope();

SOAPHeader header = soapEnvelope.getHeader();
if (header == null) {
header = soapEnvelope.addHeader();
}

SOAPElement soapElementSecurityHeader = header.addChildElement(SOAP_ELEMENT_SECURITY, PREFIX_SECURITY,
NAMESPACE_SECURITY);

SOAPElement soapElementUsernameToken = soapElementSecurityHeader.addChildElement(SOAP_ELEMENT_USERNAME_TOKEN, PREFIX_SECURITY);
SOAPElement soapElementUsername = soapElementUsernameToken.addChildElement(SOAP_ELEMENT_USERNAME, PREFIX_SECURITY);
soapElementUsername.addTextNode(this.usernameText);

SOAPElement soapElementPassword = soapElementUsernameToken.addChildElement(SOAP_ELEMENT_PASSWORD, PREFIX_SECURITY);
soapElementPassword.addTextNode(this.passwordText);

} catch (Exception e) {
throw new RuntimeException("Error on wsSecurityHandler: " + e.getMessage());
}

}

return true;
}

@Override
public void close(MessageContext context) {
// TODO Auto-generated method stub
}

@Override
public boolean handleFault(SOAPMessageContext context) {
// TODO Auto-generated method stub
return true;
}

@Override
public Set<QName> getHeaders() {
// TODO Auto-generated method stub
return null;
}
}

Xml Request: This is the payload request that Java Client request to the server.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>myUsername</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">myPassword</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<searchSomething>
<Id>25</Id>
</searchSomething>
</soapenv:Body>
</soapenv:Envelope>

32 Comments

  1. Andres Rueda says:

    Thanks. It´s perfect.

  2. Thatiana Alipio Ferreira says:

    Really helpful! Congrats!

  3. Kalyan Matamarugu says:

    Thank you soo much.. Its very clear…

  4. Nrup says:

    I am not understanding what is MyService class and Request , Response type which jar or which file i have to import for that ? any one has idea please suggest me

    • victorjabur says:

      Hello Nrup,

      When you generate your Stub (WS Client), using the command wsimport http://yourEndpointHere, you get many and many Java Classes, this is what you are searching for.

      See this link: http://docs.oracle.com/javaee/5/tutorial/doc/bnayn.html

      package simpleclient;

      import javax.xml.ws.WebServiceRef;
      import helloservice.endpoint.HelloService;
      import helloservice.endpoint.Hello;

      public class HelloClient {
      @WebServiceRef(wsdlLocation=”http://localhost:8080/
      helloservice/hello?wsdl”)
      static HelloService service;

      public static void main(String[] args) {
      try {
      HelloClient client = new HelloClient();
      client.doTest(args);
      } catch(Exception e) {
      e.printStackTrace();
      }
      }

  5. Alex Olivera says:

    Thank you very much for the post , a question, I ‘m new to this but I want to ask about the method boolean handleMessage receiving a filter SOAPMessageContext data type . that parameter is that I have to send?…
    Thanks in advance

    • victorjabur says:

      Hello Alex,

      The method handleMessage is needed by Interface SOAPHandler, in this example this method
      is required to put the security header in the message.
      The parameter myRequest is the information that you have to send to the WS.

      Sincerely,
      Victor Jabur

  6. Alex Olivera says:

    I implemented as follows:
    BindingProvider bindingProvider = (BindingProvider) portLoanStatusInterface;
    @SuppressWarnings(“rawtypes”)
    List handlerChain = new ArrayList();
    handlerChain.add(new WSSecurityHeaderSOAPHandler(“ws.FFE”, “telecel123”));
    bindingProvider.getBinding().setHandlerChain(handlerChain);

    requestBodyLoanStatusBean.setMsisdn(nroCuenta);
    loanStatusRequest.setRequestBody(requestBodyLoanStatusBean);
    loanStatusRequest.setRequestHeader(new bccs.wsclient.loanStatusBean.com.tigo.xmlns.requestheader.v3.RequestHeader());
    LoanStatusResponse loanStatusResponse = portLoanStatusInterface.loanStatus(loanStatusRequest);

    I think it’s the same way you did in the MainPost.java class. but I still reports the error of invalid user.
    then try to implement it as follows….

    I was first doing an instance of the WSSecurityHeaderSOAPHandler class and then invoke the method handleMessage, for example:
    WSSecurityHeaderSOAPHandler example = new WSSecurityHeaderSOAPHandler (“asd”, “asd”);
    example.handleMessage (“?????????”); and that is the method in which not sendin ‘…

    thank you very much for your help 🙂

  7. Amir Marzouk says:

    you must add this code:

    SOAPElement soapElementPassword = soapElementUsernameToken.addChildElement(SOAP_ELEMENT_PASSWORD, PREFIX_SECURITY);
    soapElementPassword.addTextNode(this.passwordText);
     soapElementPassword.setAttribute(“Type”, “http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText”);

  8. Tony V says:

    Hi Victor:

    I run the code I get the following error:

    compile:
    run:
    javax.xml.ws.soap.SOAPFaultException: –
    at com.sun.xml.internal.ws.fault.SOAP11Fault.getProtocolException(SOAP11Fault.java:178)
    at com.sun.xml.internal.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:117)
    at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:108)
    at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:78)
    at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(SEIStub.java:135)
    at com.sun.proxy.$Proxy20.sendBill(Unknown Source)
    at testwss.TestWSS.main(TestWSS.java:68)
    BUILD SUCCESSFUL (total time: 3 seconds)

  9. Why on earth would anyone want this? WS-Security and clear text passwords are arch-enemies.

  10. lu baloba says:

    very interesting, but how about if you have to generate a header like this:

    xIS11698
    xIS11698
    TEC8xONASWEZzhAIXfZbmA==
    2016-06-17T08:18:41.891Z

    (UsernameToken and Nonce)

  11. SHAILENDRA says:

    I am using your code for adding wsse header to my soap request but getting this error :

    Caused by: org.apache.cxf.binding.soap.SoapFault: A security error was encountered when verifying the message
    at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.unmarshalFault(Soap11FaultInInterceptor.java:75) ~[cxf-rt-bindings-soap-2.4.6.jar:2.4.6]
    at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.handleMessage(Soap11FaultInInterceptor.java:46) ~[cxf-rt-bindings-soap-2.4.6.jar:2.4.6]
    at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.handleMessage(Soap11FaultInInterceptor.java:35) ~[cxf-rt-bindings-soap-2.4.6.jar:2.4.6]
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263) ~[cxf-api-2.4.6.jar:2.4.6]
    at org.apache.cxf.interceptor.AbstractFaultChainInitiatorObserver.onMessage(AbstractFaultChainInitiatorObserver.java:111) ~[cxf-rt-core-2.4.6.jar:2.4.6]
    at org.apache.cxf.jaxws.handler.soap.SOAPHandlerInterceptor.handleMessage(SOAPHandlerInterceptor.java:139) ~[cxf-rt-frontend-jaxws-2.4.6.jar:2.4.6]
    at org.apache.cxf.jaxws.handler.soap.SOAPHandlerInterceptor.handleMessage(SOAPHandlerInterceptor.java:70) ~[cxf-rt-frontend-jaxws-2.4.6.jar:2.4.6]
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263) ~[cxf-api-2.4.6.jar:2.4.6]
    at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:795) ~[cxf-rt-core-2.4.6.jar:2.4.6]

    It seems SOAPEnvelope is empty in WSSecurityHeaderSoapHandler. What am I missing ?

    • victorjabur says:

      Hello SHAILENDRA,

      Certainly your SoapHeader is empty or mallformed. It’s complicated to tell something without view the sourcecode.

      I don’t know how can I help you.

  12. smallik says:

    Hi Victor, I found and fixed the problem. I needed to set Type to password element ,
    soapElementPassword.setAttribute(“Type”,”http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText”);

    Thanks !

  13. Sandeep says:

    Hello victor , i’m getting classcast exception when i’m using
    BindingProvider bp=(BindingProvider)port;
    Do you know any work around for this??
    Thanks ,
    Sandeep.

  14. Philipp Grigoryev says:

    Thank you, it was helpful! Exactly the thing I was looking for.

  15. Magda says:

    Thank you! It’s great!

  16. Manoj Kumar says:

    Hi victor after implementing the same am not able to call the service
    am using the clientgen implemention could you please help.
    am not able to pass the security credentials.

  17. Mahi says:

    HI I’m getting casting exception I have generated client classes with axis using eclipse is it causing an issue,

    cannot be cast to javax.xml.ws.BindingProvider

  18. Yonatan says:

    this is powerfull.. 🙂

  19. siddharth kumar verma says:

    Hi, Can we pass extra parameter in the security header except username and password.
    Suppose i also need to pass phone number in the security header , so can we pass that also. For eg:

    myUsername
    myPassword
    “+1234567890+”

    25

  20. DavidWeb says:

    Great.. What if i have to add the timestamp ?

    user
    4123
    Zdtb1VhBZA0JP7x5Cvmq9Q==
    2018-10-05T19:21:39.843Z

    i had some assignment to generate bunch of SOAPs .. assuming each soap need different header

  21. Stuart katungi says:

    Thanks for this Victor. have you or any one here tried to implement this in C#? I have not been successful yet.

  22. Clement says:

    Very cool!

  23. Clement says:

    Hello Victor,

    I am getting this error:
    java.lang.RuntimeException: Error on wsSecurityHandler: NAMESPACE_ERR: An attempt is made to create or change an object in a way which is incorrect with regard to namespaces.

    Appreciate it for any hints.

Leave a Reply

Leave a Reply