Hardcoded a base of file:/// so relative URIs can be used.
[shibboleth/sp.git] / shib / XMLOriginSiteMapper.cpp
1 /* 
2  * The Shibboleth License, Version 1. 
3  * Copyright (c) 2002 
4  * University Corporation for Advanced Internet Development, Inc. 
5  * All rights reserved
6  * 
7  * 
8  * Redistribution and use in source and binary forms, with or without 
9  * modification, are permitted provided that the following conditions are met:
10  * 
11  * Redistributions of source code must retain the above copyright notice, this 
12  * list of conditions and the following disclaimer.
13  * 
14  * Redistributions in binary form must reproduce the above copyright notice, 
15  * this list of conditions and the following disclaimer in the documentation 
16  * and/or other materials provided with the distribution, if any, must include 
17  * the following acknowledgment: "This product includes software developed by 
18  * the University Corporation for Advanced Internet Development 
19  * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement 
20  * may appear in the software itself, if and wherever such third-party 
21  * acknowledgments normally appear.
22  * 
23  * Neither the name of Shibboleth nor the names of its contributors, nor 
24  * Internet2, nor the University Corporation for Advanced Internet Development, 
25  * Inc., nor UCAID may be used to endorse or promote products derived from this 
26  * software without specific prior written permission. For written permission, 
27  * please contact shibboleth@shibboleth.org
28  * 
29  * Products derived from this software may not be called Shibboleth, Internet2, 
30  * UCAID, or the University Corporation for Advanced Internet Development, nor 
31  * may Shibboleth appear in their name, without prior written permission of the 
32  * University Corporation for Advanced Internet Development.
33  * 
34  * 
35  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
36  * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
37  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
38  * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK 
39  * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE. 
40  * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY 
41  * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, 
42  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
43  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
44  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
46  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
47  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48  */
49
50 /* XMLOriginSiteMapper.h - a mapper implementation that uses an XML-based registry
51
52    Scott Cantor
53    9/27/02
54
55    $History:$
56 */
57
58 #ifdef WIN32
59 # define SHIB_EXPORTS __declspec(dllexport)
60 #endif
61
62 #include <shib.h>
63 #include <log4cpp/Category.hh>
64 using namespace shibboleth;
65 using namespace saml;
66 using namespace log4cpp;
67 using namespace std;
68
69 #include <xercesc/framework/URLInputSource.hpp>
70
71 XMLOriginSiteMapper::XMLOriginSiteMapper(const char* registryURI,
72                                          const Iterator<X509Certificate*>& roots,
73                                          Key* verifyKey)
74 {
75     NDC ndc("XMLOriginSiteMapper");
76     Category& log=Category::getInstance(SHIB_LOGCAT".XMLOriginSiteMapper");
77
78     saml::XML::Parser p;
79     DOMDocument* doc=NULL;
80         try
81     {
82         static XMLCh base[]={chLatin_f, chLatin_i, chLatin_l, chLatin_e, chColon, chForwardSlash, chForwardSlash, chForwardSlash, chNull};
83         URLInputSource src(base,registryURI);
84         Wrapper4InputSource dsrc(&src,false);
85                 doc=p.parse(dsrc);
86
87         log.infoStream() << "Loaded and parsed site file (" << registryURI << ")"
88             << CategoryStream::ENDLINE;
89
90                 DOMElement* e = doc->getDocumentElement();
91         if (XMLString::compareString(XML::SHIB_NS,e->getNamespaceURI()) ||
92             XMLString::compareString(XML::Literals::Sites,e->getLocalName()))
93         {
94                         log.error("Construction requires a valid site file: (shib:Sites as root element)");
95                         throw OriginSiteMapperException("Construction requires a valid site file: (shib:Sites as root element)");
96                 }
97
98                 // Loop over the OriginSite elements.
99         DOMNodeList* nlist = e->getElementsByTagNameNS(XML::SHIB_NS,XML::Literals::OriginSite);
100                 for (int i=0; nlist && i<nlist->getLength(); i++)
101         {
102             auto_ptr<XMLCh> os_name(XMLString::replicate(static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,XML::Literals::Name)));
103             XMLString::trim(os_name.get());
104                         if (!os_name.get() || !*os_name)
105                                 continue;
106
107                         OriginSite* os_obj = new OriginSite();
108                         m_sites[os_name.get()]=os_obj;
109
110                         DOMNode* os_child = nlist->item(i)->getFirstChild();
111                         while (os_child)
112             {
113                 if (os_child->getNodeType()!=DOMNode::ELEMENT_NODE)
114                 {
115                                         os_child = os_child->getNextSibling();
116                                         continue;
117                                 }
118
119                                 // Process the various kinds of OriginSite children that we care about...
120                 if (!XMLString::compareString(XML::SHIB_NS,os_child->getNamespaceURI()) &&
121                                         !XMLString::compareString(XML::Literals::HandleService,os_child->getLocalName()))
122                 {
123                     auto_ptr<XMLCh> hs_name(XMLString::replicate(static_cast<DOMElement*>(os_child)->getAttributeNS(NULL,XML::Literals::Name)));
124                     XMLString::trim(hs_name.get());
125
126                                         if (hs_name.get() && *hs_name)
127                     {
128                                                 os_obj->m_handleServices.push_back(hs_name.get());
129
130                                                 /* Ignore KeyInfo for now...
131                                                 DOM*Node ki = os_child->getFirstChild();
132                         while (ki && ki->getNodeType()!=DOMNode::ELEMENT_NODE)
133                                                         ki = ki->getNextSibling();
134                         if (ki && !XMLString::compareString(saml::XML::XMLSIG_NS,ki->getNamespaceURI()) &&
135                             !XMLString::compareString(saml::XML::Literals::KeyInfo,ki->getNamespaceURI()))
136                         {
137                                                 }
138                         */
139                                         }
140                                 }
141                 else if (!XMLString::compareString(XML::SHIB_NS,os_child->getNamespaceURI()) &&
142                                              !XMLString::compareString(XML::Literals::Domain,os_child->getLocalName()))
143                 {
144                     auto_ptr<XMLCh> dom(XMLString::replicate(os_child->getFirstChild()->getNodeValue()));
145                     XMLString::trim(dom.get());
146                                         if (dom.get() && *dom)
147                                                 os_obj->m_domains.push_back(dom.get());
148                                 }
149                                 os_child = os_child->getNextSibling();
150                         }
151                 }
152
153                 if (verifyKey)
154         {
155                         log.info("Initialized with a key: attempting to verify document signature.");
156             log.error("Signature verification not implemented yet, this may be a forged file!");
157                         // validateSignature(verifyKey, e);
158                 }
159         else
160                         log.info("Initialized without key: skipping signature verification.");
161     }
162     catch (SAMLException& e)
163     {
164                 log.errorStream() << "XML error while parsing site configuration: " << e.what()
165             << CategoryStream::ENDLINE;
166         if (doc)
167             doc->release();
168                 throw;
169         }
170     catch (...)
171     {
172                 log.error("Unexpected error while parsing site configuration");
173         if (doc)
174             doc->release();
175                 throw;
176     }
177 }
178
179 XMLOriginSiteMapper::~XMLOriginSiteMapper()
180 {
181     for (map<xstring,OriginSite*>::iterator i=m_sites.begin(); i!=m_sites.end(); i++)
182         delete i->second;
183 }
184
185 /* TBD...
186 private void validateSignature(Key verifyKey, Element e) throws OriginSiteMapperException {
187
188         Node n = e.getLastChild();
189         while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
190                 n = n.getPreviousSibling();
191
192         if (n != null
193                 && org.opensaml.XML.XMLSIG_NS.equals(n.getNamespaceURI())
194                 && "Signature".equals(n.getLocalName())) {
195                         log.info("Located signature in document... verifying.");
196                 try {
197                         XMLSignature sig = new XMLSignature((Element) n, null);
198                         if (sig.checkSignatureValue(verifyKey)) {
199                                 // Now we verify that what is signed is what we expect.
200                                 SignedInfo sinfo = sig.getSignedInfo();
201                                 if (sinfo.getLength() == 1
202                                         && (sinfo
203                                                 .getCanonicalizationMethodURI()
204                                                 .equals(Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS)
205                                                 || sinfo.getCanonicalizationMethodURI().equals(
206                                                         Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS))) {
207                                         Reference ref = sinfo.item(0);
208                                         if (ref.getURI() == null || ref.getURI().equals("")) {
209                                                 Transforms trans = ref.getTransforms();
210                                                 if (trans.getLength() == 1
211                                                         && trans.item(0).getURI().equals(Transforms.TRANSFORM_ENVELOPED_SIGNATURE))
212                                                         log.info("Signature verification successful.");
213                                                         return;
214                                         }
215                                         log.error(
216                                                 "Unable to verify signature on registry file: Unsupported dsig reference or transform data submitted with signature.");
217                                         throw new OriginSiteMapperException("Unable to verify signature on registry file: Unsupported dsig reference or transform data submitted with signature.");
218                                 } else {
219                                         log.error(
220                                                 "Unable to verify signature on registry file: Unsupported canonicalization method.");
221                                         throw new OriginSiteMapperException("Unable to verify signature on registry file: Unsupported canonicalization method.");
222                                 }
223                         } else {
224                                 log.error(
225                                         "Unable to verify signature on registry file: signature cannot be verified with the specified key.");
226                                 throw new OriginSiteMapperException("Unable to verify signature on registry file: signature cannot be verified with the specified key.");
227                         }
228                 } catch (Exception sigE) {
229                         log.error(
230                                 "Unable to verify signature on registry file: An error occured while attempting to verify the signature:"
231                                         + sigE);
232                         throw new OriginSiteMapperException(
233                                 "Unable to verify signature on registry file: An error occured while attempting to verify the signature:"
234                                         + sigE);
235                 }
236         } else {
237                 log.error("Unable to verify signature on registry file: no signature found in document.");
238                 throw new OriginSiteMapperException("Unable to verify signature on registry file: no signature found in document.");
239         }
240
241 }
242 */
243
244 Iterator<xstring> XMLOriginSiteMapper::getHandleServiceNames(const XMLCh* originSite)
245 {
246     map<xstring,OriginSite*>::const_iterator i=m_sites.find(originSite);
247     if (i==m_sites.end())
248         return Iterator<xstring>();
249     return Iterator<xstring>(i->second->m_handleServices);
250 }
251
252 Key* XMLOriginSiteMapper::getHandleServiceKey(const XMLCh* handleService)
253 {
254     map<xstring,Key*>::const_iterator i=m_hsKeys.find(handleService);
255     return (i!=m_hsKeys.end()) ? i->second : NULL;
256 }
257
258 Iterator<xstring> XMLOriginSiteMapper::getSecurityDomains(const XMLCh* originSite)
259 {
260     map<xstring,OriginSite*>::const_iterator i=m_sites.find(originSite);
261     if (i==m_sites.end())
262         return Iterator<xstring>();
263     return Iterator<xstring>(i->second->m_domains);
264 }
265
266 Iterator<X509Certificate*> XMLOriginSiteMapper::getTrustedRoots()
267 {
268         return Iterator<X509Certificate*>(m_roots);
269 }
270