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, 2016, Oracle and/or its affiliates. All rights reserved.
25 */
26/*
27 * $Id: DOMURIDereferencer.java 1231033 2012-01-13 12:12:12Z coheigea $
28 */
29package org.jcp.xml.dsig.internal.dom;
30
31import org.w3c.dom.Attr;
32import org.w3c.dom.Element;
33import org.w3c.dom.Node;
34
35import com.sun.org.apache.xml.internal.security.Init;
36import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
37import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver;
38import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput;
39
40import javax.xml.crypto.*;
41import javax.xml.crypto.dom.*;
42
43/**
44 * DOM-based implementation of URIDereferencer.
45 *
46 * @author Sean Mullan
47 */
48public class DOMURIDereferencer implements URIDereferencer {
49
50    static final URIDereferencer INSTANCE = new DOMURIDereferencer();
51
52    private DOMURIDereferencer() {
53        // need to call com.sun.org.apache.xml.internal.security.Init.init()
54        // before calling any apache security code
55        Init.init();
56    }
57
58    public Data dereference(URIReference uriRef, XMLCryptoContext context)
59        throws URIReferenceException {
60
61        if (uriRef == null) {
62            throw new NullPointerException("uriRef cannot be null");
63        }
64        if (context == null) {
65            throw new NullPointerException("context cannot be null");
66        }
67
68        DOMURIReference domRef = (DOMURIReference) uriRef;
69        Attr uriAttr = (Attr) domRef.getHere();
70        String uri = uriRef.getURI();
71        DOMCryptoContext dcc = (DOMCryptoContext) context;
72        String baseURI = context.getBaseURI();
73
74        boolean secVal = Utils.secureValidation(context);
75
76        if (secVal && Policy.restrictReferenceUriScheme(uri)) {
77            throw new URIReferenceException(
78                "Uri " + uri + " is forbidden when secure validation is enabled");
79        }
80
81        // Check if same-document URI and already registered on the context
82        if (uri != null && uri.length() != 0 && uri.charAt(0) == '#') {
83            String id = uri.substring(1);
84
85            if (id.startsWith("xpointer(id(")) {
86                int i1 = id.indexOf('\'');
87                int i2 = id.indexOf('\'', i1+1);
88                id = id.substring(i1+1, i2);
89            }
90
91            // check if element is registered by Id
92            Node referencedElem = uriAttr.getOwnerDocument().getElementById(id);
93            if (referencedElem == null) {
94               // see if element is registered in DOMCryptoContext
95               referencedElem = dcc.getElementById(id);
96            }
97            if (referencedElem != null) {
98                if (secVal && Policy.restrictDuplicateIds()) {
99                    Element start = referencedElem.getOwnerDocument().getDocumentElement();
100                    if (!XMLUtils.protectAgainstWrappingAttack(start, (Element)referencedElem, id)) {
101                        String error = "Multiple Elements with the same ID "
102                            + id + " detected when secure validation"
103                            + " is enabled";
104                        throw new URIReferenceException(error);
105                    }
106                }
107
108                XMLSignatureInput result = new XMLSignatureInput(referencedElem);
109                if (!uri.substring(1).startsWith("xpointer(id(")) {
110                    result.setExcludeComments(true);
111                }
112
113                result.setMIMEType("text/xml");
114                if (baseURI != null && baseURI.length() > 0) {
115                    result.setSourceURI(baseURI.concat(uriAttr.getNodeValue()));
116                } else {
117                    result.setSourceURI(uriAttr.getNodeValue());
118                }
119                return new ApacheNodeSetData(result);
120            }
121        }
122
123        try {
124            ResourceResolver apacheResolver =
125                ResourceResolver.getInstance(uriAttr, baseURI, false);
126            XMLSignatureInput in = apacheResolver.resolve(uriAttr,
127                                                          baseURI, false);
128            if (in.isOctetStream()) {
129                return new ApacheOctetStreamData(in);
130            } else {
131                return new ApacheNodeSetData(in);
132            }
133        } catch (Exception e) {
134            throw new URIReferenceException(e);
135        }
136    }
137}
138