org.nimbustools.messaging.gt4_0_elastic.rpc.RequestEngine.java Source code

Java tutorial

Introduction

Here is the source code for org.nimbustools.messaging.gt4_0_elastic.rpc.RequestEngine.java

Source

/*
 * Copyright 1999-2008 University of Chicago
 *
 * 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.nimbustools.messaging.gt4_0_elastic.rpc;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ws.security.WSSConfig;
import org.apache.ws.security.message.token.Timestamp;
import org.globus.wsrf.Resource;
import org.globus.wsrf.ResourceContext;
import org.globus.wsrf.ResourceContextException;
import org.globus.wsrf.ResourceException;
import org.globus.wsrf.impl.security.authentication.wssec.ReplayAttackFilter;
import org.globus.wsrf.impl.security.authentication.wssec.WSSecurityEngine;
import org.globus.wsrf.impl.security.authentication.wssec.WSSecurityException;
import org.globus.wsrf.impl.security.authentication.wssec.WSSecurityRequestEngine;
import org.globus.wsrf.impl.security.descriptor.SecurityPropertiesHelper;
import org.globus.wsrf.utils.ContextUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import javax.xml.rpc.handler.MessageContext;
import javax.xml.rpc.handler.soap.SOAPMessageContext;
import javax.xml.soap.SOAPHeaderElement;
import java.text.ParseException;
import java.text.SimpleDateFormat;

public class RequestEngine extends WSSecurityRequestEngine {

    // -------------------------------------------------------------------------
    // STATIC VARIABLES
    // -------------------------------------------------------------------------

    private static final Log logger = LogFactory.getLog(RequestEngine.class.getName());

    protected static final SimpleDateFormat problematicFormat = new SimpleDateFormat(
            "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");

    private static WSSecurityEngine engine;

    // -------------------------------------------------------------------------
    // overrides WSSecurityRequestEngine
    // -------------------------------------------------------------------------

    public synchronized static WSSecurityEngine getEngine() {
        if (engine == null) {
            engine = new RequestEngine();
        }

        return engine;
    }

    // -------------------------------------------------------------------------
    // overrides WSSecurityEngine
    // -------------------------------------------------------------------------

    /**
     * Overrides processTimestampHeader in WSSecurityEngine
     *
     * The secmsg Timestamp constructor fails on timestamps with milliseconds
     * in them.
     *
     * Since this is handled after the envelope integrity check, it's OK to
     * replace the timestamp if necessary (this allows the the constructor to
     * succeed and attack window analysis to proceed).
     *
     * @param givenTimestampElem timestampElem from soap
     * @param msgCtx msgCtx
     * @param messageIDHeader messageIDHeader
     * @throws Exception problem
     * @see #perhapsChangeTimestampFormat(Element);
     */
    protected void processTimestampHeader(Element givenTimestampElem, MessageContext msgCtx,
            SOAPHeaderElement messageIDHeader) throws Exception {

        final String servicePath = ContextUtils.getTargetServicePath((org.apache.axis.MessageContext) msgCtx);

        if (servicePath == null) {
            throw new Exception(i18n.getMessage("serviceNull"));
        }

        Resource resource = null;
        try {
            final ResourceContext resCtx = ResourceContext.getResourceContext((SOAPMessageContext) msgCtx);
            resource = resCtx.getResource();
        } catch (ResourceContextException exp) {
            // Not an issue
        } catch (ResourceException exp) {
            // Not an issue
        }

        if (givenTimestampElem != null) {

            final Element timestampElem = this.perhapsChangeTimestampFormat(givenTimestampElem);

            final String propertyValue = SecurityPropertiesHelper.getReplayAttackWindow(servicePath, resource);
            final ReplayAttackFilter replayFilter = ReplayAttackFilter.getInstance(propertyValue);

            if (messageIDHeader == null) {
                final Timestamp timestamp = new Timestamp(WSSConfig.getDefaultWSConfig(), timestampElem);
                final boolean stampOk = verifyTimestamp(timestamp, replayFilter.getMessageWindow());
                if (!stampOk) {
                    throw new WSSecurityException(WSSecurityException.FAILURE, "timestampNotOk");
                }
            } else {
                checkMessageValidity(replayFilter, timestampElem, messageIDHeader);
            }
        } else {
            final String propertyValue = SecurityPropertiesHelper.getReplayAttackFilter(servicePath, resource);
            if (rejectMsgSansTimestampHeader(msgCtx, propertyValue)) {
                logger.debug("Required time stamp header was not added.");
                throw new WSSecurityException(WSSecurityException.FAILURE, "timestampRequired");
            }
        }
    }

    // -------------------------------------------------------------------------
    // TIMESTAMP CHANGES
    // -------------------------------------------------------------------------

    protected Element perhapsChangeTimestampFormat(Element timestampElem) throws Exception {

        if (timestampElem == null) {
            throw new Exception("timestampElem may not be null");
        }

        final Node firstChild = timestampElem.getFirstChild();
        if (firstChild == null) {
            logger.warn("Timestamp but no data enclosed?");
            return timestampElem;
        }

        final String firstChildLocal = firstChild.getLocalName();
        if (firstChildLocal != null && firstChildLocal.equals("Created")) {

            if (firstChildLocal.equals("Created")) {
                this.handleCreatedOrExpires(firstChild, "Created");
            } else {
                logger.warn("Timestamp with something besides " + "Created: '" + firstChildLocal + "'");
                return timestampElem;
            }

            final Node sibling = firstChild.getNextSibling();
            if (sibling == null) {
                logger.warn("Timestamp with Created but no Expires?");
                return timestampElem;
            }

            final String siblingLocal = sibling.getLocalName();
            if (siblingLocal != null && siblingLocal.equals("Expires")) {
                this.handleCreatedOrExpires(sibling, "Expires");
            } else {
                logger.warn("Timestamp with Created but no Expires?");
                logger.warn(
                        "Timestamp with Created and then something " + "besides Expires: '" + siblingLocal + "'");
                return timestampElem;
            }
        }

        return timestampElem;
    }

    protected void handleCreatedOrExpires(Node node, String name) {

        final Node firstChild = node.getFirstChild();
        final String firstChildNodeValue = firstChild.getNodeValue();

        if (firstChildNodeValue == null) {
            logger.warn("Timestamp with null value for " + name);
        } else {
            final String newValue = this.chop(firstChildNodeValue);
            if (newValue != null) {
                firstChild.setNodeValue(newValue);
            }
        }
    }

    protected String chop(String stamp) {

        try {
            problematicFormat.parse(stamp);
        } catch (ParseException e) {
            // not in the problematic format
            return null; // *** EARLY RETURN ***
        }

        // remove milliseconds, Timestamp class wants "yyyy-MM-ddTHH:mm:ssZ"
        // and the problematic one looks like "yyyy-MM-ddTHH:mm:ss.SSSZ"

        // get first 19 characters then tack on Z
        final String prefix = stamp.substring(0, 19);
        return prefix + 'Z';
    }
}