Search code examples
javasoapweblogicsoapuisoap-client

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 am trying to call a Webservice using jax-ws. While calling the WS I faced below error,

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
   <S:Body>
      <S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
         <faultcode>S:Server</faultcode>
         <faultstring>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</faultstring>
         <faultactor/>
      </S:Fault>
   </S:Body>
</S:Envelope>

I searched for this error and found out that it expects userid/password in header. So to add the user credentials in header I have implemented custom handler.

import java.util.Set;
import java.util.TreeSet;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFactory;
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 UsrSecHandler implements SOAPHandler<SOAPMessageContext>
{
    private static final String AUTH_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
    private static final String AUTH_PREFIX="wsse";
    private String pwd;
    private String userName = null;
    private SOAPFactory mSoapFactory = null;
    

    

    public UsrSecHandler(String username, String password) {
        this.userName = username;
        this.pwd = password;
    }



    @Override
    public boolean handleMessage(SOAPMessageContext context)
    {

        Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (outboundProperty.booleanValue())
        {

            try
            {
            
                SOAPEnvelope envelope = context.getMessage().getSOAPPart().getEnvelope();
                if (mSoapFactory == null)
                {
                        mSoapFactory = SOAPFactory.newInstance();
                    
                }
                SOAPElement wsSecHeaderElm, userNameTokenElm, userNameElm, passwdElm;
                // WSSecurity <Security> header
                
                    wsSecHeaderElm = mSoapFactory.createElement("Security",AUTH_PREFIX,AUTH_NS);
                    userNameTokenElm = mSoapFactory.createElement("UsernameToken",AUTH_PREFIX,AUTH_NS);
                    userNameElm = mSoapFactory.createElement("Username",AUTH_PREFIX,AUTH_NS);
                    passwdElm = mSoapFactory.createElement("Password",AUTH_PREFIX,AUTH_NS);
                
                userNameElm.addTextNode(this.userName);
                passwdElm.addTextNode(this.pwd);

                userNameTokenElm.addChildElement(userNameElm);
                userNameTokenElm.addChildElement(passwdElm);
                
                // add child elements to the root element
                wsSecHeaderElm.addChildElement(userNameTokenElm);

                // create SOAPHeader instance for SOAP envelope             
                SOAPHeader header = envelope.getHeader();
                
                if (header == null) {
                    header = envelope.addHeader();
                }
                
                
                header.addChildElement(wsSecHeaderElm);
            }
            catch (SOAPException e)
            {
                    e.printStackTrace();
            }catch (Exception e){
                    e.printStackTrace();
            }
        }
        return true;
    }

    @Override
    public Set<QName> getHeaders()
    {
        return new TreeSet<QName>();
    }

    @Override
    public boolean handleFault(SOAPMessageContext context)
    {
        return false;
    }

    @Override
    public void close(MessageContext context)
    {
        //
    }
    
}

I am using below code to plug the custom handler and call the WS.

            ManagementServices  service = new ManagementServices(webServiceUrl);
            
            Impl_ManagementServices port = service.getManagementServices();
            
            final Binding binding = ((BindingProvider) port).getBinding();
             
            List<Handler> handlerList = binding.getHandlerChain();
    
            handlerList.add(new UsrSecHandler(LOGIN, PASS));
            
            binding.setHandlerChain(handlerList);
            
            port.callingManageService(some_input);

After adding Handler, The code worked fine on Eclipse when I run it standalone. But when I deployed the same code on Weblogic It is still throwing the same error. In the logs I am printing the Envelope. When I am using the same exact envelope(copy/paste) in Soap UI again it is working fine. But some how it is not working when deployed on Weblogic.

Below is The policy defined.

<wsp:Policy wssutil:Id="UsernameToken">
<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>

client : WebLogic Server Version: 14.1.1.0.0

Server/host : WebLogic Server Version: 10.3.6.0

Not able to understand this behavior, Could any one please help me out with this ?


Solution

  • Finally resolved this.

    • Removed the Custom Handler entirely.
    • Instead modified code of calling WS

    Before

    
                ManagementServices  service = new ManagementServices(webServiceUrl);
                
                Impl_ManagementServices port = service.getManagementServices();
                
                final Binding binding = ((BindingProvider) port).getBinding();
                 
                List<Handler> handlerList = binding.getHandlerChain();
        
                handlerList.add(new UsrSecHandler(LOGIN, PASS));
                
                binding.setHandlerChain(handlerList);
                
                port.callingManageService(some_input);
    

    Now (changed/working code)

            import weblogic.wsee.security.unt.ClientUNTCredentialProvider;
            import weblogic.xml.crypto.wss.WSSecurityContext;
            import weblogic.xml.crypto.wss.provider.CredentialProvider;
            import javax.xml.ws.BindingProvider;
    
    
            ManagementServices  service = new ManagementServices(webServiceUrl);
        
            Impl_ManagementServices port = service.getManagementServices();
    
            List<CredentialProvider> credProviders = new ArrayList<CredentialProvider>(); 
            CredentialProvider  cp = new ClientUNTCredentialProvider("username".getBytes(), "password".getBytes()); 
            credProviders.add(cp); 
            Map<String, Object> requestContext = ((BindingProvider) port).getRequestContext();
            requestContext.put(WSSecurityContext.CREDENTIAL_PROVIDER_LIST, credProviders);
        
                
            port.callingManageService(some_input);