Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create Password Digest for use with Web Service?

I am trying to create a passwordDigest util which can be used in different environments which are capable of running java byte code.

First of all I create nonce. It is done like so.

public static String buildNonce(){
        StringBuffer nonce=new StringBuffer();
        String dateTimeString = Long.toString(new Date().getTime());
        byte[] nonceByte= dateTimeString.getBytes();
        return Base64.encode(nonceByte);
    }

Once I have nonce, I build password digest.

public static String buildPasswordDigest(String userName, String password, String nonce, String dateTime){
    MessageDigest sha1;
    String passwordDigest=null;
    try {
        sha1= MessageDigest.getInstance("SHA-1");
        byte[] hash = MessageDigest.getInstance("SHA-1").digest(password.getBytes("UTF-8"));
        sha1.update(nonce.getBytes("UTF-8"));
        sha1.update(dateTime.getBytes("UTF-8"));
        passwordDigest = new String(Base64.encode(sha1.digest(hash)));
        sha1.reset();
    } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return passwordDigest;

In order to test that everything works correctly. I have created a test web service using CXF 2.7. I have manually created SOAP Envelope to test authentication. The envelope looks like this.

 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
                xmlns:ws="http://ws.mytest.org/" 
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance/">
    <soapenv:Header>
        <wsse:Security soapenv:mustUnderstand="1" 
          xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
          xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
          <wsse:UsernameToken wsu:Id="UsernameToken-2">
            <wsse:Username>TEST_USER</wsse:Username>
            <wsse:Password 
            Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">UZsDSW/vANu6fHg4rAHo2OwsF9s=</wsse:Password
            <wsse:Nonce>MTQwMTMwMDQzNjA3OA==</wsse:Nonce>
            <wsu:Created>2014-05-28T18:07:16.087Z</wsu:Created>
         </wsse:UsernameToken>
        </wsse:Security>
    </soapenv:Header>
    <soapenv:Body>
        <ws:record>
            <val1>1</val1>
            <val2>Some Text</val2>
        </ws:record>
    </soapenv:Body>
</soapenv:Envelope>

When I send the envelope using SOAP UI. I get the following authentication error.

WARNING: Interceptor for {http://ws.mytest.org/}TestService has thrown exception, unwinding now
org.apache.cxf.binding.soap.SoapFault: The security token could not be authenticated or authorized
    at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.createSoapFault(WSS4JInInterceptor.java:788)
    at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessage(WSS4JInInterceptor.java:336)
    at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessage(WSS4JInInterceptor.java:95)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272)
    at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
    at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:239)
    at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:248)
    at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:222)
    at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:153)
    at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:167)
    at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:286)
    at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:206)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:646)
    at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:262)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:313)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:744)
Caused by: org.apache.ws.security.WSSecurityException: The security token could not be authenticated or authorized
    at org.apache.ws.security.validate.UsernameTokenValidator.verifyDigestPassword(UsernameTokenValidator.java:199)
    at org.apache.ws.security.validate.UsernameTokenValidator.validate(UsernameTokenValidator.java:97)
    at org.apache.ws.security.processor.UsernameTokenProcessor.handleUsernameToken(UsernameTokenProcessor.java:172)
    at org.apache.ws.security.processor.UsernameTokenProcessor.handleToken(UsernameTokenProcessor.java:67)
    at org.apache.ws.security.WSSecurityEngine.processSecurityHeader(WSSecurityEngine.java:396)
    at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessage(WSS4JInInterceptor.java:279)
    ... 31 more

I suspect that I have an issue creating either nonce or password.

Your help is appreciated.

like image 574
svager Avatar asked May 28 '14 18:05

svager


Video Answer


1 Answers

WS-Security defines password digest as

Base64 ( SHA1 ( nonce + created + password ) )

not

Base64 ( SHA1 ( password + nonce + created) )

And nonce is supposed to be 128 bits (16 bytes) encoded as Base64. e.g.

java.security.SecureRandom random = java.security.SecureRandom.getInstance("SHA1PRNG");
random.setSeed(System.currentTimeMillis()); 
byte[] nonceBytes = new byte[16]; 
random.nextBytes(nonceBytes); 
String nonce = new String(org.apache.commons.codec.binary.Base64.encodeBase64(nonceBytes), "UTF-8");
like image 55
Martin Avatar answered Nov 01 '22 10:11

Martin