org.apache.juddi.validation.ValidateReplication.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.juddi.validation.ValidateReplication.java

Source

/*
 * Copyright 2001-2008 The Apache Software Foundation.
 * 
 * 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.juddi.validation;

import java.math.BigInteger;
import java.security.cert.CertificateException;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicReference;
import javax.persistence.EntityManager;
import javax.xml.ws.WebServiceContext;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.juddi.config.AppConfig;
import org.apache.juddi.config.Property;
import org.apache.juddi.model.Node;
import org.apache.juddi.model.UddiEntityPublisher;
import org.apache.juddi.v3.client.cryptor.CryptorFactory;
import org.apache.juddi.v3.client.cryptor.DigSigUtil;
import org.apache.juddi.v3.error.ErrorMessage;
import org.apache.juddi.v3.error.FatalErrorException;
import org.apache.juddi.v3.error.InvalidValueException;
import org.apache.juddi.v3.error.TransferNotAllowedException;
import org.apache.juddi.v3.error.ValueNotAllowedException;
import org.uddi.custody_v3.TransferEntities;
import org.uddi.repl_v3.CommunicationGraph.Edge;
import org.uddi.repl_v3.HighWaterMarkVectorType;
import org.uddi.repl_v3.NotifyChangeRecordsAvailable;
import org.uddi.repl_v3.Operator;
import org.uddi.repl_v3.ReplicationConfiguration;
import org.uddi.repl_v3.TransferCustody;
import org.uddi.v3_service.DispositionReportFaultMessage;

/**
 * @author <a href="mailto:alexoree@apache.org">Alex O'Ree</a>
 * Processing an inbound replication message may fail due to a server internal
 * error. The common behavior for all error cases is to return an E_fatalError
 * error code. Error reporting SHALL be that specified by Section 4.8  Success
 * and Error Reporting of this specification.
 */
public class ValidateReplication extends ValidateUDDIApi {

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

    public ValidateReplication(UddiEntityPublisher publisher) {
        super(publisher);
    }

    public ValidateReplication(UddiEntityPublisher publisher, String nodeid) {
        super(publisher, nodeid);
    }

    public void validateNotifyChangeRecordsAvailable(NotifyChangeRecordsAvailable body, WebServiceContext ctx)
            throws DispositionReportFaultMessage {
        //TODO
    }

    public void validateGetChangeRecords(String requestingNode, HighWaterMarkVectorType changesAlreadySeen,
            BigInteger responseLimitCount, HighWaterMarkVectorType responseLimitVector,
            ReplicationConfiguration FetchEdges, WebServiceContext ctx) throws DispositionReportFaultMessage {
        //TODO

        if (requestingNode == null || requestingNode.trim().equalsIgnoreCase("")) {
            //requestingNode: The requestingNode element provides the identity of the calling node.  
            //This is the unique key for the calling node and SHOULD be specified within the Replication Configuration Structure.
            throw new FatalErrorException(new ErrorMessage("errors.replication.nodeNotSpecified"));
        }
        //if (!ContainsNode(requestingNode, FetchEdges)) {
        //        throw new FatalErrorException(new ErrorMessage("errors.replication.unknownNode"));
        //}

        if (changesAlreadySeen != null) {
            // changesAlreadySeen: The changesAlreadySeen element, if present, indicates changes from each
            //node that the requestor has successfully processed, and thus which should not be resent, if possible.

            //no validation needed?
        }

        if (responseLimitCount != null && responseLimitVector != null) {
            throw new FatalErrorException(new ErrorMessage("errors.replication.bothLimitsSpecified"));
        }
        if (responseLimitCount != null) {
            //can't be 0 since 0 is banned as being a change record id
            if (responseLimitCount.longValue() <= 0) {
                throw new FatalErrorException(
                        new ErrorMessage("errors.replication.negativeLimit", responseLimitCount.toString()));
            }
        }
        if (responseLimitVector != null) {
            for (int i = 0; i < responseLimitVector.getHighWaterMark().size(); i++) {
                if (responseLimitVector.getHighWaterMark().get(i).getOriginatingUSN() == null
                        || responseLimitVector.getHighWaterMark().get(i).getOriginatingUSN() <= 0) {
                    throw new FatalErrorException(new ErrorMessage("errors.replication.limitVectorNull"));
                }
                if (responseLimitVector.getHighWaterMark().get(i).getNodeID() == null
                        || responseLimitVector.getHighWaterMark().get(i).getNodeID().trim().equalsIgnoreCase("")) {
                    throw new FatalErrorException(new ErrorMessage("errors.replication.limitVectorNoNode"));
                }
            }
        }

        /**
         * responseLimitCount or responseLimitVector: A caller MAY place
         * an upper bound on the number of change records he wishes to
         * receive in response to this message by either providing a
         * integer responseLimitCount, or, using responseLimitVector,
         * indicating for each node in the graph the first change
         * originating there that he does not wish to be returned.
         *
         */
    }

    private static boolean ContainsNode(String requestingNode, ReplicationConfiguration FetchEdges) {
        if (FetchEdges == null) {
            return false;
        }
        if (FetchEdges.getCommunicationGraph() == null) {
            return false;
        }
        for (int i = 0; i < FetchEdges.getCommunicationGraph().getNode().size(); i++) {
            if (FetchEdges.getCommunicationGraph().getNode().get(i).equalsIgnoreCase(requestingNode)) {
                return true;
            }
        }
        return false;
    }

    public void validateSetReplicationNodes(ReplicationConfiguration replicationConfiguration, EntityManager em,
            String thisnode, Configuration config) throws DispositionReportFaultMessage, ConfigurationException {
        if (replicationConfiguration == null) {
            throw new InvalidValueException(new ErrorMessage("errors.replication.configNull"));

        }
        if (replicationConfiguration.getCommunicationGraph() == null) {
            throw new InvalidValueException(new ErrorMessage("errors.replication.configNull"));
        }
        if (replicationConfiguration.getRegistryContact() == null) {
            throw new InvalidValueException(new ErrorMessage("errors.replication.contactNull"));
        }
        if (replicationConfiguration.getRegistryContact().getContact() == null) {
            throw new InvalidValueException(new ErrorMessage("errors.replication.contactNull"));
        }
        if (replicationConfiguration.getRegistryContact().getContact().getPersonName().get(0) == null) {
            throw new InvalidValueException(new ErrorMessage("errors.replication.contactNull"));
        }

        if (replicationConfiguration.getOperator() == null || replicationConfiguration.getOperator().isEmpty()) {
            throw new InvalidValueException(
                    new ErrorMessage("errors.replication.contactNull", "Operator is null or empty"));
        }
        for (int i = 0; i < replicationConfiguration.getOperator().size(); i++) {
            if (replicationConfiguration.getOperator().get(i).getSoapReplicationURL() == null
                    || "".equals(replicationConfiguration.getOperator().get(i).getSoapReplicationURL())) {
                throw new InvalidValueException(
                        new ErrorMessage("errors.replication.contactNull", "Replication URL is null or empty"));
            }
            if (!replicationConfiguration.getOperator().get(i).getSoapReplicationURL().toLowerCase()
                    .startsWith("http")) {
                throw new InvalidValueException(new ErrorMessage("errors.replication.contactNull",
                        "Replication URL is invalid, only HTTP is supported"));
            }
            if (replicationConfiguration.getOperator().get(i).getOperatorNodeID() == null
                    || replicationConfiguration.getOperator().get(i).getOperatorNodeID().equalsIgnoreCase("")) {
                throw new InvalidValueException(
                        new ErrorMessage("errors.replication.contactNull", "Node ID is not defined"));
            }
        }
        if (replicationConfiguration.getCommunicationGraph() != null) {
            for (String s : replicationConfiguration.getCommunicationGraph().getNode()) {
                if (!Contains(replicationConfiguration.getOperator(), s)) {
                    throw new InvalidValueException(new ErrorMessage("errors.replication.configNodeNotFound"));
                }
            }
            for (Edge s : replicationConfiguration.getCommunicationGraph().getEdge()) {
                //TODO revisit this for correctness
                //Node find = null;
                //if (!thisnode.equalsIgnoreCase(s.getMessageReceiver())) {
                if (!Contains(replicationConfiguration.getOperator(), s.getMessageReceiver())) {
                    throw new InvalidValueException(new ErrorMessage("errors.replication.configNodeNotFound"));
                    //}
                }
                //find = null;
                //if (!thisnode.equalsIgnoreCase(s.getMessageSender())) {
                if (!Contains(replicationConfiguration.getOperator(), s.getMessageSender())) {
                    throw new InvalidValueException(new ErrorMessage("errors.replication.configNodeNotFound"));
                    //}
                }
                if (s.getMessageReceiver().equalsIgnoreCase(s.getMessageSender())) {
                    throw new InvalidValueException(new ErrorMessage("errors.replication.configNodeLoop"));
                }
                for (String id : s.getMessageReceiverAlternate()) {
                    if (!Contains(replicationConfiguration.getOperator(), id)) {
                        throw new InvalidValueException(new ErrorMessage("errors.replication.configNodeNotFound"));
                    }
                }

            }
        }
        boolean shouldcheck = config.getBoolean(Property.JUDDI_REJECT_ENTITIES_WITH_INVALID_SIG_ENABLE, false);
        initDigSig(config);
        if (shouldcheck && !replicationConfiguration.getSignature().isEmpty() && ds != null) {
            AtomicReference<String> outmsg = new AtomicReference<String>();
            boolean ok = ds.verifySignedUddiEntity(replicationConfiguration, outmsg);
            if (!ok) {
                throw new FatalErrorException(
                        new ErrorMessage("errors.digitalsignature.validationfailure" + " " + outmsg.get()));
            }

        }
    }

    private org.apache.juddi.v3.client.cryptor.DigSigUtil ds = null;

    private synchronized void initDigSig(Configuration config) {
        if (ds == null) {

            Properties p = new Properties();
            /**
             * <trustStorePath>truststore.jks</trustStorePath>
             * <trustStoreType>JKS</trustStoreType>
             * <trustStorePassword
             * isPasswordEncrypted="false"
             * cryptoProvider="org.apache.juddi.v3.client.crypto.AES128Cryptor">password</trustStorePassword>
             *
             * <checkTimestamps>true</checkTimestamps>
             * <checkTrust>true</checkTrust>
             * <checkRevocationCRL>true</checkRevocationCRL>
             */
            p.put(DigSigUtil.TRUSTSTORE_FILE, config
                    .getString(Property.JUDDI_REJECT_ENTITIES_WITH_INVALID_SIG_PREFIX + "trustStorePath", ""));
            p.put(DigSigUtil.TRUSTSTORE_FILETYPE, config
                    .getString(Property.JUDDI_REJECT_ENTITIES_WITH_INVALID_SIG_PREFIX + "trustStoreType", ""));

            String enc = config
                    .getString(Property.JUDDI_REJECT_ENTITIES_WITH_INVALID_SIG_PREFIX + "trustStorePassword", "");
            if (config.getBoolean(Property.JUDDI_REJECT_ENTITIES_WITH_INVALID_SIG_PREFIX
                    + "trustStorePassword[@isPasswordEncrypted]", false)) {
                log.debug("trust password is encrypted, decrypting...");

                String prov = config.getString(Property.JUDDI_REJECT_ENTITIES_WITH_INVALID_SIG_PREFIX
                        + "trustStorePassword[@cryptoProvider]", "");
                try {
                    p.setProperty(DigSigUtil.TRUSTSTORE_FILE_PASSWORD,
                            CryptorFactory.getCryptor(prov).decrypt(enc));
                } catch (Exception ex) {
                    log.warn("unable to decrypt trust store password " + ex.getMessage());
                    log.debug("unable to decrypt trust store password " + ex.getMessage(), ex);
                }

            } else if (!"".equals(enc)) {
                log.warn("Hey, you should consider encrypting your trust store password!");
                p.setProperty(DigSigUtil.TRUSTSTORE_FILE_PASSWORD, enc);
            }

            p.put(DigSigUtil.CHECK_REVOCATION_STATUS_CRL, config.getString(
                    Property.JUDDI_REJECT_ENTITIES_WITH_INVALID_SIG_PREFIX + "checkRevocationCRL", "true"));
            p.put(DigSigUtil.CHECK_TRUST_CHAIN, config
                    .getString(Property.JUDDI_REJECT_ENTITIES_WITH_INVALID_SIG_PREFIX + "checkTrust", "true"));
            p.put(DigSigUtil.CHECK_TIMESTAMPS, config
                    .getString(Property.JUDDI_REJECT_ENTITIES_WITH_INVALID_SIG_PREFIX + "checkTimestamps", "true"));

            try {
                ds = new DigSigUtil(p);
            } catch (CertificateException ex) {
                log.error("", ex);
            }
            //System.out.println("loaded from " + AppConfig.getConfigFileURL());
            //p.list(System.out);
        }
    }

    private boolean Contains(List<Operator> operator, String s) {
        if (operator == null) {
            return false;
        }
        for (Operator o : operator) {
            if (o.getOperatorNodeID().equalsIgnoreCase(s)) {
                return true;
            }
        }
        return false;
    }

    public void validateTransfer(EntityManager em, TransferCustody body) throws DispositionReportFaultMessage {

        if (body == null) {
            throw new TransferNotAllowedException(new ErrorMessage("errors.NullInput"));
        }
        if (body.getTransferToken() == null) {
            throw new TransferNotAllowedException(new ErrorMessage("errors.NullInput"));
        }
        if (body.getKeyBag() == null) {
            throw new TransferNotAllowedException(new ErrorMessage("errors.NullInput"));
        }
        if (body.getTransferOperationalInfo() == null) {
            throw new TransferNotAllowedException(new ErrorMessage("errors.NullInput"));
        }

        if (body.getTransferOperationalInfo().getNodeID() == null) {
            throw new TransferNotAllowedException(new ErrorMessage("errors.NullInput"));
        }
        if (body.getTransferOperationalInfo().getAuthorizedName() == null) {
            throw new TransferNotAllowedException(new ErrorMessage("errors.NullInput"));
        }

        //confirm i own the records in question
        //confirm i issued the transfer token
        TransferEntities x = new TransferEntities();
        x.setKeyBag(body.getKeyBag());
        x.setTransferToken(body.getTransferToken());
        String transferTokenId = new String(body.getTransferToken().getOpaqueToken());
        new ValidateCustodyTransfer(null).validateTransferLocalEntities(em, transferTokenId,
                body.getKeyBag().getKey());

    }

}