1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /**
   6  * Licensed to the Apache Software Foundation (ASF) under one
   7  * or more contributor license agreements. See the NOTICE file
   8  * distributed with this work for additional information
   9  * regarding copyright ownership. The ASF licenses this file
  10  * to you under the Apache License, Version 2.0 (the
  11  * "License"); you may not use this file except in compliance
  12  * with the License. You may obtain a copy of the License at
  13  *
  14  * http://www.apache.org/licenses/LICENSE-2.0
  15  *
  16  * Unless required by applicable law or agreed to in writing,
  17  * software distributed under the License is distributed on an
  18  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  19  * KIND, either express or implied. See the License for the
  20  * specific language governing permissions and limitations
  21  * under the License.
  22  */
  23 /*
  24  * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
  25  */
  26 /*
  27  * $Id: DOMManifest.java 1333415 2012-05-03 12:03:51Z coheigea $
  28  */
  29 package org.jcp.xml.dsig.internal.dom;
  30 
  31 import javax.xml.crypto.*;
  32 import javax.xml.crypto.dom.DOMCryptoContext;
  33 import javax.xml.crypto.dsig.*;
  34 
  35 import java.security.Provider;
  36 import java.util.*;
  37 
  38 import org.w3c.dom.Attr;
  39 import org.w3c.dom.Document;
  40 import org.w3c.dom.Element;
  41 import org.w3c.dom.Node;
  42 
  43 /**
  44  * DOM-based implementation of Manifest.
  45  *
  46  * @author Sean Mullan
  47  */
  48 public final class DOMManifest extends DOMStructure implements Manifest {
  49 
  50     private final List<Reference> references;
  51     private final String id;
  52 
  53     /**
  54      * Creates a <code>DOMManifest</code> containing the specified
  55      * list of {@link Reference}s and optional id.
  56      *
  57      * @param references a list of one or more <code>Reference</code>s. The list
  58      *    is defensively copied to protect against subsequent modification.
  59      * @param id the id (may be <code>null</code>
  60      * @throws NullPointerException if <code>references</code> is
  61      *    <code>null</code>
  62      * @throws IllegalArgumentException if <code>references</code> is empty
  63      * @throws ClassCastException if <code>references</code> contains any
  64      *    entries that are not of type {@link Reference}
  65      */
  66     public DOMManifest(List<? extends Reference> references, String id) {
  67         if (references == null) {
  68             throw new NullPointerException("references cannot be null");
  69         }
  70         this.references =
  71             Collections.unmodifiableList(new ArrayList<Reference>(references));
  72         if (this.references.isEmpty()) {
  73             throw new IllegalArgumentException("list of references must " +
  74                 "contain at least one entry");
  75         }
  76         for (int i = 0, size = this.references.size(); i < size; i++) {
  77             if (!(this.references.get(i) instanceof Reference)) {
  78                 throw new ClassCastException
  79                     ("references["+i+"] is not a valid type");
  80             }
  81         }
  82         this.id = id;
  83     }
  84 
  85     /**
  86      * Creates a <code>DOMManifest</code> from an element.
  87      *
  88      * @param manElem a Manifest element
  89      */
  90     public DOMManifest(Element manElem, XMLCryptoContext context,
  91                        Provider provider)
  92         throws MarshalException
  93     {
  94         Attr attr = manElem.getAttributeNodeNS(null, "Id");
  95         if (attr != null) {
  96             this.id = attr.getValue();
  97             manElem.setIdAttributeNode(attr, true);
  98         } else {
  99             this.id = null;
 100         }
 101 
 102         boolean secVal = Utils.secureValidation(context);
 103 
 104         Element refElem = DOMUtils.getFirstChildElement(manElem, "Reference");
 105         List<Reference> refs = new ArrayList<Reference>();
 106         refs.add(new DOMReference(refElem, context, provider));
 107 
 108         refElem = DOMUtils.getNextSiblingElement(refElem);
 109         while (refElem != null) {
 110             String localName = refElem.getLocalName();
 111             if (!localName.equals("Reference")) {
 112                 throw new MarshalException("Invalid element name: " +
 113                                            localName + ", expected Reference");
 114             }
 115             refs.add(new DOMReference(refElem, context, provider));
 116             if (secVal && (refs.size() > DOMSignedInfo.MAXIMUM_REFERENCE_COUNT)) {
 117                 String error = "A maxiumum of " + DOMSignedInfo.MAXIMUM_REFERENCE_COUNT + " "
 118                     + "references per Manifest are allowed with secure validation";
 119                 throw new MarshalException(error);
 120             }
 121             refElem = DOMUtils.getNextSiblingElement(refElem);
 122         }
 123         this.references = Collections.unmodifiableList(refs);
 124     }
 125 
 126     public String getId() {
 127         return id;
 128     }
 129 
 130     @SuppressWarnings("unchecked")
 131     static List<Reference> getManifestReferences(Manifest mf) {
 132         return mf.getReferences();
 133     }
 134 
 135     public List<Reference> getReferences() {
 136         return references;
 137     }
 138 
 139     public void marshal(Node parent, String dsPrefix, DOMCryptoContext context)
 140         throws MarshalException
 141     {
 142         Document ownerDoc = DOMUtils.getOwnerDocument(parent);
 143         Element manElem = DOMUtils.createElement(ownerDoc, "Manifest",
 144                                                  XMLSignature.XMLNS, dsPrefix);
 145 
 146         DOMUtils.setAttributeID(manElem, "Id", id);
 147 
 148         // add references
 149         for (Reference ref : references) {
 150             ((DOMReference)ref).marshal(manElem, dsPrefix, context);
 151         }
 152         parent.appendChild(manElem);
 153     }
 154 
 155     @Override
 156     public boolean equals(Object o) {
 157         if (this == o) {
 158             return true;
 159         }
 160 
 161         if (!(o instanceof Manifest)) {
 162             return false;
 163         }
 164         Manifest oman = (Manifest)o;
 165 
 166         boolean idsEqual = (id == null ? oman.getId() == null
 167                                        : id.equals(oman.getId()));
 168 
 169         return (idsEqual && references.equals(oman.getReferences()));
 170     }
 171 
 172     @Override
 173     public int hashCode() {
 174         int result = 17;
 175         if (id != null) {
 176             result = 31 * result + id.hashCode();
 177         }
 178         result = 31 * result + references.hashCode();
 179 
 180         return result;
 181     }
 182 }