# RelaySecuirtyMessageBuilderDispatchandler.java

    /*
     * Copyright 2005,2006 WSO2, Inc. http://www.wso2.org
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     * http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    package org.apache.synapse.transport.passthru.util;

    import org.apache.axiom.om.OMAbstractFactory;
    import org.apache.axiom.om.OMElement;
    import org.apache.axiom.om.OMNamespace;
    import org.apache.axiom.om.OMNode;
    import org.apache.axiom.om.util.AXIOMUtil;
    import org.apache.axiom.soap.SOAPFactory;
    import org.apache.axiom.soap.SOAPHeader;
    import org.apache.axiom.soap.SOAPHeaderBlock;
    import org.apache.axis2.AxisFault;
    import org.apache.axis2.Constants;
    import org.apache.axis2.addressing.EndpointReference;
    import org.apache.axis2.context.ConfigurationContext;
    import org.apache.axis2.context.MessageContext;
    import org.apache.axis2.description.AxisOperation;
    import org.apache.axis2.description.AxisService;
    import org.apache.axis2.description.HandlerDescription;
    import org.apache.axis2.description.Parameter;
    import org.apache.axis2.engine.AbstractDispatcher;
    import org.apache.axis2.engine.AxisConfiguration;
    import org.apache.axis2.transport.http.HTTPConstants;
    import org.apache.axis2.util.Utils;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.apache.synapse.transport.util.MessageHandlerProvider;
    import org.apache.synapse.transport.netty.util.RequestResponseUtils;
    import org.apache.synapse.transport.passthru.PassThroughConstants;
    import org.apache.synapse.transport.passthru.Pipe;

    import javax.xml.namespace.QName;
    import java.util.Iterator;
    import java.util.Map;

    public class RelaySecuirtyMessageBuilderDispatchandler  extends AbstractDispatcher{

    	private static final Log log = LogFactory.getLog(RelaySecuirtyMessageBuilderDispatchandler.class);

    	private static final String APPLICATION_XML = "application/xml";
    	private static final String WSSE = "wsse";
    	private static final String WSS_WSSECURITY_SECEXT_1_0_XSD = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
    	private static final String PROXY = "proxy";
    	private static final String SERVICE_TYPE = "serviceType";
    	public static final String NAME = "RelaySecuirtyMessageBuilderDispatchandler";

    	@Override
    	public InvocationResponse invoke(MessageContext messageContext) throws AxisFault {
    		InvocationResponse invocationResponse = super.invoke(messageContext);

    		EndpointReference toEPR = messageContext.getTo();

    		Pipe pipe = (Pipe) messageContext.getProperty(PassThroughConstants.PASS_THROUGH_PIPE);

    		if (pipe != null || RequestResponseUtils.isHttpCarbonMessagePresent(messageContext)) {
    			if (toEPR != null) {

    				ConfigurationContext configurationContext = messageContext.getConfigurationContext();
    				AxisConfiguration registry = configurationContext.getAxisConfiguration();
    				String filePart = toEPR.getAddress();

    				if (filePart != null) {
    					String serviceOpPart = Utils.getServiceAndOperationPart(filePart,
    					                       messageContext.getConfigurationContext().getServiceContextPath());

    					AxisService axisService = null;

    					// only service context path onwards values will be taken
    					if (messageContext.getConfigurationContext().getServiceContextPath() != null &&
    					    serviceOpPart != null) {
    						axisService = registry.getService(serviceOpPart);
    						if (axisService != null) {
    							Parameter parameter = axisService.getParameter(SERVICE_TYPE);
    							if (parameter != null) {
    								if (!parameter.getValue().equals(PROXY)) {
    									build(messageContext);
    								}
    							} else {
    								build(messageContext);
    							}
    						}
    					}
    				}

    			}
    			if (messageContext.isEngaged(PassThroughConstants.SECURITY_MODULE_NAME)) {
    				SOAPHeader header = null;
    				if (messageContext.getEnvelope().getHeader() != null) {
    					header = messageContext.getEnvelope().getHeader();
    				}
    				build(messageContext);
    				this.handlePOXRequests(messageContext, header);
    			}
    		}

    		return invocationResponse;
    	}

    	private void handlePOXRequests(MessageContext messageContext, SOAPHeader header) {
    	    String contentType = (String) messageContext.getProperty(Constants.Configuration.CONTENT_TYPE);
    	    String _contentType =contentType;
    	    if (contentType != null) {
    	    	int j = contentType.indexOf(";");
    	    	if (j > 0) {
    	    		_contentType = contentType.substring(0, j);
    	    	}
    	    }

    	    //if the request message is a POX and if authenticate enables, which means a custom security header added to the SOAP header
    	    //and in PT case, since the message is getting build forcefully we need to make sure the POX security headers added by POXSecurityHandler
    	    //is existing in the newly build soap envelope.

            /*Handling SOAP with BasicAuth*/
            boolean isSOAPWithBasicAuth = false;
            Object o = messageContext.getProperty(MessageContext.TRANSPORT_HEADERS);
            if (o != null && o instanceof Map) {
                Map httpHeaders = (Map) o;
                for (Object httpHeader : httpHeaders.keySet()) {
                    Object value = httpHeaders.get(httpHeader);
                    if (httpHeader instanceof String && value != null && value instanceof String) {
                        if (HTTPConstants.HEADER_AUTHORIZATION.equalsIgnoreCase((String) httpHeader) && ((String) value).startsWith("Basic")) {
                            isSOAPWithBasicAuth = true;
                            break;
                        }
                    }
                }
            }

            if (_contentType != null && _contentType.equals(APPLICATION_XML) && header != null
                    && header.getChildElements() != null
                    && messageContext.isDoingREST()
                    && isSOAPWithBasicAuth) {
                try {
    				OMElement poxSecurityHeader = AXIOMUtil.stringToOM(header.toString()).getFirstElement();

    				if (poxSecurityHeader != null) {
    					OMNamespace omNamespace =
    							OMAbstractFactory.getOMFactory().createOMNamespace(WSS_WSSECURITY_SECEXT_1_0_XSD, WSSE);

    					Iterator headerIterator = messageContext.getEnvelope().getHeader().examineAllHeaderBlocks();

    					// If a ws:Security header already exists, we should add the POX headers to the same element instead
    					// of creating a new Sec Header.
    					boolean existingWSSecurityHeaderFound = false;

    					while (headerIterator.hasNext()) {
    						OMElement headerElement = (OMElement) headerIterator.next();

    						if (headerElement.getQName().equals(new QName(WSS_WSSECURITY_SECEXT_1_0_XSD, "Security"))) {
    							while (poxSecurityHeader.getChildElements().hasNext()) {
    								headerElement.addChild((OMNode) poxSecurityHeader.getChildElements().next());
    							}
    							existingWSSecurityHeaderFound = true;
    							break;
    						}
    					}

    					if (!existingWSSecurityHeaderFound) {
    						SOAPHeaderBlock soapBloackingHeader = OMAbstractFactory.getSOAP12Factory()
    								.createSOAPHeaderBlock("Security", omNamespace);

    						while (poxSecurityHeader.getChildElements().hasNext()) {
    							soapBloackingHeader.addChild((OMNode) poxSecurityHeader.getChildElements().next());
    						}
    						messageContext.getEnvelope().getHeader().addChild(soapBloackingHeader);
    					}
    				}
    			} catch (Exception e) {
                    log.error("Error while executing the message at relaySecurity handler", e);
                }

            }
        }

    	private void build(MessageContext messageContext) {
    	    try {
    	    	MessageHandlerProvider.getMessageHandler(messageContext).buildMessage(messageContext, false);
                if (messageContext.getEnvelope().getHeader() == null) {
                    SOAPFactory fac =
                            messageContext.isSOAP11() ? OMAbstractFactory.getSOAP11Factory()
                                                      : OMAbstractFactory.getSOAP12Factory();
                    fac.createSOAPHeader(messageContext.getEnvelope());
                }
    	    } catch (Exception e) {
    	    	 log.error("Error while executing the message at relaySecurity handler", e);
    	    }
        }

    	@Override
    	public AxisOperation findOperation(AxisService arg0, MessageContext arg1)
    			throws AxisFault {
    		// TODO Auto-generated method stub
    		return null;
    	}

    	@Override
    	public AxisService findService(MessageContext arg0) throws AxisFault {
    		// TODO Auto-generated method stub
    		return null;
    	}

    	@Override
    	public void initDispatcher() {
    		init(new HandlerDescription(NAME));
    	}

    }