Wednesday, August 3, 2016

Call Username/Password enabled web service in JAVA

In this case, web service is secured with username and password authentication using WS-Security. Following code is used to generated SOAP message header to create security token to call web service.

RetailerAppWS appWS = new RetailerAppWS();
        RetailerAppWSPortType retailerAppWSPortType = appWS.getRetailerAppWSHttpsSoap11Endpoint();
        BindingProvider bindingProvider = (BindingProvider) retailerAppWSPortType;
        @SuppressWarnings("rawtypes")
        List handlerChain = new ArrayList();
        handlerChain.add(new WSSecurityHeaderSOAPHandler("Retailer", "Retailer123"));
        bindingProvider.getBinding().setHandlerChain(handlerChain);

        PayBill payBill = new PayBill();
        payBill.setAmount(1.0);
        payBill.setPin("9834");
        payBill.setReceiver("1234567890");
        payBill.setUser("sujith");

        PayBillResponse pbr = retailerAppWSPortType.payBill(payBill);

In the above code, it is created a WSSecurityHeaderSOAPHandler to manipulate the SOAP message to add security token to SOAP header.

WSSecurityHeaderSOAPHandler is shown below. This code will re-generate the SOAP message.

public class WSSecurityHeaderSOAPHandler implements SOAPHandler {

    private static final String SOAP_ELEMENT_PASSWORD = "Password";
    private static final String SOAP_ELEMENT_NONCE = "Nonce";
    private static final String SOAP_ELEMENT_USERNAME = "Username";
    private static final String SOAP_ELEMENT_Created = "Created";
    private static final String SOAP_ELEMENT_Expires = "Expires";
    private static final String SOAP_ELEMENT_USERNAME_TOKEN = "UsernameToken";
    private static final String SOAP_ELEMENT_Timestamp_TOKEN = "Timestamp";
    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 static final String NAMESPACE_WSU = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
    private static final String PREFIX_WSU = "wsu";
    private static final String NAMESPACE_TYPE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText";
    private static final String ATTRIBUTE_TYPE = "Type";
    private static final String NAMESPACE_EncodingType = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary";
    private static final String ATTRIBUTE_EncodingType = "EncodingType";
    private static final String ATTRIBUTE_MustUnderstand ="mustUnderstand";

    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);
                soapElementSecurityHeader.addAttribute(soapEnvelope.createName(ATTRIBUTE_MustUnderstand), "1");
                soapElementSecurityHeader.addNamespaceDeclaration(PREFIX_WSU, NAMESPACE_WSU);

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

                SOAPElement soapElementPassword = soapElementUsernameToken.addChildElement(SOAP_ELEMENT_PASSWORD, PREFIX_SECURITY);
                soapElementPassword.addAttribute(soapEnvelope.createName(ATTRIBUTE_TYPE), NAMESPACE_TYPE);
                soapElementPassword.addTextNode(passwordText);

                SOAPElement soapElementUserCreated = soapElementUsernameToken.addChildElement(SOAP_ELEMENT_Created, PREFIX_WSU);
                long created = System.currentTimeMillis();

                TimeZone timeZone = TimeZone.getTimeZone("UTC");
                Calendar calendar = Calendar.getInstance(timeZone);
                SimpleDateFormat sdfu
                        = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
                sdfu.setTimeZone(timeZone);

                String dateu = sdfu.format(calendar.getTime());
                soapElementUserCreated.addTextNode(dateu);

                SOAPElement soapElementNonce = soapElementUsernameToken.addChildElement(SOAP_ELEMENT_NONCE, PREFIX_SECURITY);
                soapElementNonce.addAttribute(soapEnvelope.createName(ATTRIBUTE_EncodingType), NAMESPACE_EncodingType);
                soapElementNonce.addTextNode(createNonce(created));

                SOAPElement soapElementTimestampToken = soapElementSecurityHeader.addChildElement(SOAP_ELEMENT_Timestamp_TOKEN, PREFIX_WSU);
                SOAPElement soapElementCreated = soapElementTimestampToken.addChildElement(SOAP_ELEMENT_Created, PREFIX_WSU);

                soapElementCreated.addTextNode(dateu);

                calendar.set(Calendar.MINUTE, calendar.get(Calendar.MINUTE) + 2);

                SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
                String date2 = sdf2.format(calendar.getTime());
                SOAPElement soapElementExpires = soapElementTimestampToken.addChildElement(SOAP_ELEMENT_Expires, PREFIX_WSU);
                soapElementExpires.addTextNode(date2);

            } 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 getHeaders() {

        final QName securityHeader = new QName(
                NAMESPACE_SECURITY, SOAP_ELEMENT_SECURITY, PREFIX_SECURITY);

        final HashSet headers = new HashSet();
        headers.add(securityHeader);
        return headers;
    }

    public String createNonce(long value) throws Exception {
        java.security.SecureRandom random = java.security.SecureRandom.getInstance("SHA1PRNG");
        random.setSeed(value);
        byte[] nonceBytes = new byte[16];
        random.nextBytes(nonceBytes);
        String nonce = new String(org.apache.commons.codec.binary.Base64.encodeBase64(nonceBytes), "UTF-8");
        return nonce;
    }

}

NOTE :- Timestamp must be in UTC format. NONCE value must generated as above.

Call Username/Password enabled web service in JAVA

In this case, web service is secured with username and password authentication using WS-Security. Following code is used to generated SOAP message header to create security token to call web service.

RetailerAppWS appWS = new RetailerAppWS();
        RetailerAppWSPortType retailerAppWSPortType = appWS.getRetailerAppWSHttpsSoap11Endpoint();
        BindingProvider bindingProvider = (BindingProvider) retailerAppWSPortType;
        @SuppressWarnings("rawtypes")
        List handlerChain = new ArrayList();
        handlerChain.add(new WSSecurityHeaderSOAPHandler("Retailer", "Retailer123"));
        bindingProvider.getBinding().setHandlerChain(handlerChain);

        PayBill payBill = new PayBill();
        payBill.setAmount(1.0);
        payBill.setPin("9834");
        payBill.setReceiver("1234567890");
        payBill.setUser("sujith");

        PayBillResponse pbr = retailerAppWSPortType.payBill(payBill);

In the above code, it is created a WSSecurityHeaderSOAPHandler to manipulate the SOAP message to add security token to SOAP header.

WSSecurityHeaderSOAPHandler is shown below. This code will re-generate the SOAP message.

public class WSSecurityHeaderSOAPHandler implements SOAPHandler {

    private static final String SOAP_ELEMENT_PASSWORD = "Password";
    private static final String SOAP_ELEMENT_NONCE = "Nonce";
    private static final String SOAP_ELEMENT_USERNAME = "Username";
    private static final String SOAP_ELEMENT_Created = "Created";
    private static final String SOAP_ELEMENT_Expires = "Expires";
    private static final String SOAP_ELEMENT_USERNAME_TOKEN = "UsernameToken";
    private static final String SOAP_ELEMENT_Timestamp_TOKEN = "Timestamp";
    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 static final String NAMESPACE_WSU = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
    private static final String PREFIX_WSU = "wsu";
    private static final String NAMESPACE_TYPE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText";
    private static final String ATTRIBUTE_TYPE = "Type";
    private static final String NAMESPACE_EncodingType = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary";
    private static final String ATTRIBUTE_EncodingType = "EncodingType";
    private static final String ATTRIBUTE_MustUnderstand ="mustUnderstand";

    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);
                soapElementSecurityHeader.addAttribute(soapEnvelope.createName(ATTRIBUTE_MustUnderstand), "1");
                soapElementSecurityHeader.addNamespaceDeclaration(PREFIX_WSU, NAMESPACE_WSU);

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

                SOAPElement soapElementPassword = soapElementUsernameToken.addChildElement(SOAP_ELEMENT_PASSWORD, PREFIX_SECURITY);
                soapElementPassword.addAttribute(soapEnvelope.createName(ATTRIBUTE_TYPE), NAMESPACE_TYPE);
                soapElementPassword.addTextNode(passwordText);

                SOAPElement soapElementUserCreated = soapElementUsernameToken.addChildElement(SOAP_ELEMENT_Created, PREFIX_WSU);
                long created = System.currentTimeMillis();

                TimeZone timeZone = TimeZone.getTimeZone("UTC");
                Calendar calendar = Calendar.getInstance(timeZone);
                SimpleDateFormat sdfu
                        = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
                sdfu.setTimeZone(timeZone);

                String dateu = sdfu.format(calendar.getTime());
                soapElementUserCreated.addTextNode(dateu);

                SOAPElement soapElementNonce = soapElementUsernameToken.addChildElement(SOAP_ELEMENT_NONCE, PREFIX_SECURITY);
                soapElementNonce.addAttribute(soapEnvelope.createName(ATTRIBUTE_EncodingType), NAMESPACE_EncodingType);
                soapElementNonce.addTextNode(createNonce(created));

                SOAPElement soapElementTimestampToken = soapElementSecurityHeader.addChildElement(SOAP_ELEMENT_Timestamp_TOKEN, PREFIX_WSU);
                SOAPElement soapElementCreated = soapElementTimestampToken.addChildElement(SOAP_ELEMENT_Created, PREFIX_WSU);

                soapElementCreated.addTextNode(dateu);

                calendar.set(Calendar.MINUTE, calendar.get(Calendar.MINUTE) + 2);

                SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
                String date2 = sdf2.format(calendar.getTime());
                SOAPElement soapElementExpires = soapElementTimestampToken.addChildElement(SOAP_ELEMENT_Expires, PREFIX_WSU);
                soapElementExpires.addTextNode(date2);

            } 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 getHeaders() {

        final QName securityHeader = new QName(
                NAMESPACE_SECURITY, SOAP_ELEMENT_SECURITY, PREFIX_SECURITY);

        final HashSet headers = new HashSet();
        headers.add(securityHeader);
        return headers;
    }

    public String createNonce(long value) throws Exception {
        java.security.SecureRandom random = java.security.SecureRandom.getInstance("SHA1PRNG");
        random.setSeed(value);
        byte[] nonceBytes = new byte[16];
        random.nextBytes(nonceBytes);
        String nonce = new String(org.apache.commons.codec.binary.Base64.encodeBase64(nonceBytes), "UTF-8");
        return nonce;
    }

}

NOTE :- Timestamp must be in UTC format. NONCE value must generated as above.