com.hiperium.integration.access.control.SoapSignatureHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.hiperium.integration.access.control.SoapSignatureHandler.java

Source

/**
 * Product  : Hiperium Project
 * Architect: Andres Solorzano.
 * Created  : 08-05-2009 - 23:30:00
 * 
 * The contents of this file are copyrighted by Andres Solorzano 
 * and it is protected by the license: "GPL V3." You can find a copy of this 
 * license at: http://www.hiperium.com/about/licence.html
 * 
 * Copyright 2014 Andres Solorzano. All rights reserved.
 * 
 */
package com.hiperium.integration.access.control;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.inject.Inject;
import javax.validation.constraints.NotNull;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFault;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import javax.xml.ws.soap.SOAPFaultException;

import org.apache.commons.lang.StringUtils;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.hiperium.bo.delegate.SecurityBusinessDelegate;
import com.hiperium.commons.CommonsUtil;
import com.hiperium.commons.EnumHiperiumTier;
import com.hiperium.commons.HiperiumTier;
import com.hiperium.commons.log.HiperiumLogger;
import com.hiperium.commons.sign.Signature;

/**
 * @author Andres Solorzano
 *
 */
public class SoapSignatureHandler implements SOAPHandler<SOAPMessageContext> {

    /** The LOGGER property for logger messages. */
    private static final HiperiumLogger LOGGER = HiperiumLogger.getLogger(SoapSignatureHandler.class);

    /** The property securityBusinessDelegate. */
    @Inject
    @HiperiumTier(EnumHiperiumTier.INTEGRATION)
    private SecurityBusinessDelegate securityBusinessDelegate;

    /* (non-Javadoc)
     * @see javax.xml.ws.handler.Handler#handleMessage(javax.xml.ws.handler.MessageContext)
     */
    @SuppressWarnings("unchecked")
    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        LOGGER.debug("handleMessage - BEGIN");
        // Only message arriving from the client. Not processing responses.
        Boolean outbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (!outbound) {
            // Get the sessionId from the entire HTTP Message
            StringBuffer sessionIdBuffer = new StringBuffer();
            Map<String, List<String>> map = (Map<String, List<String>>) context
                    .get(MessageContext.HTTP_REQUEST_HEADERS);
            for (String session : this.getHTTPHeader(map, CommonsUtil.SESSIONID)) {
                sessionIdBuffer.append(session);
            }
            // Try to get SOAP header values from the SOAP message
            try {
                SOAPMessage msg = context.getMessage();
                if (LOGGER.isDebugEnabled()) {
                    System.out.println("REQUEST:");
                    msg.writeTo(System.out);
                    System.out.println();
                }
                Node node = msg.getSOAPHeader().getFirstChild();

                // Header values
                NodeList nodeList = node.getChildNodes(); // Name, TimeStamp, Signature.
                if (nodeList.getLength() < 3) {
                    this.generateFault(msg, "Too few header nodes!");
                }

                // Extract the required attributes.
                Long homeId = Long.valueOf(nodeList.item(0).getFirstChild().getNodeValue());
                String signature = nodeList.item(1).getFirstChild().getNodeValue();
                String timestamp = nodeList.item(2).getFirstChild().getNodeValue();
                if (StringUtils.isBlank(timestamp) || StringUtils.isBlank(signature)) {
                    this.generateFault(msg, "Missing header key/value pairs!");
                }

                // Validates that the user Token exists in the DB for valid registered external Application.
                String token = this.securityBusinessDelegate.getHomeGatewayBO().findTokenInSession(homeId,
                        sessionIdBuffer.toString());
                if (StringUtils.isBlank(token)) {
                    this.generateFault(msg, homeId.toString().concat(" not registered!"));
                }

                // Generate comparison signature and compare against what's sent.
                byte[] secretBytes = Signature.getBytes(token);
                String localSignature = Signature.createSignature(homeId, timestamp, secretBytes);
                if (!this.verify(signature, localSignature)) {
                    this.generateFault(msg, "HMAC signatures do not match.");
                }
            } catch (Exception e) {
                throw new RuntimeException("SOAPException thrown.", e);
            }
        }
        LOGGER.debug("handleMessage - END");
        return true; //continue other handler chain
    }

    /* (non-Javadoc)
     * @see javax.xml.ws.handler.Handler#close(javax.xml.ws.handler.MessageContext)
     */
    @Override
    public void close(MessageContext arg0) {
        // Nothing to do.
    }

    /* (non-Javadoc)
     * @see javax.xml.ws.handler.Handler#handleFault(javax.xml.ws.handler.MessageContext)
     */
    @Override
    public boolean handleFault(SOAPMessageContext arg0) {
        return false;
    }

    /* (non-Javadoc)
     * @see javax.xml.ws.handler.soap.SOAPHandler#getHeaders()
     */
    @Override
    public Set<QName> getHeaders() {
        return null;
    }

    /**
     * 
     * @param headers
     * @param header
     * @return
     */
    private List<String> getHTTPHeader(@NotNull Map<String, List<String>> headers, @NotNull String header) {
        for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
            String name = entry.getKey();
            if (name.equalsIgnoreCase(header))
                return entry.getValue();
        }
        return null;
    }

    /**
     * 
     * @param msg
     * @param reason
     */
    private void generateFault(SOAPMessage msg, String reason) {
        try {
            SOAPBody body = msg.getSOAPBody();
            SOAPFault fault = body.addFault();
            fault.setFaultString(reason);
            throw new SOAPFaultException(fault);
        } catch (SOAPException e) {
            LOGGER.error(e.getMessage(), e);
        }
    }

    /**
     * 
     * @param sig1
     * @param sig2
     * @return
     */
    private boolean verify(String sig1, String sig2) {
        return Arrays.equals(sig1.getBytes(), sig2.getBytes());
    }
}