2 * The Shibboleth License, Version 1.
4 * University Corporation for Advanced Internet Development, Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
11 * Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
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.
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
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.
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.
50 /* XMLOriginSiteMapper.h - a mapper implementation that uses an XML-based registry
59 # define SHIB_EXPORTS __declspec(dllexport)
63 #include <log4cpp/Category.hh>
64 using namespace shibboleth;
66 using namespace log4cpp;
69 #include <xercesc/framework/URLInputSource.hpp>
71 XMLOriginSiteMapper::XMLOriginSiteMapper(const char* registryURI,
72 const Iterator<X509Certificate*>& roots,
75 NDC ndc("XMLOriginSiteMapper");
76 Category& log=Category::getInstance(SHIB_LOGCAT".XMLOriginSiteMapper");
79 DOMDocument* doc=NULL;
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);
87 log.infoStream() << "Loaded and parsed site file (" << registryURI << ")"
88 << CategoryStream::ENDLINE;
90 DOMElement* e = doc->getDocumentElement();
91 if (XMLString::compareString(XML::SHIB_NS,e->getNamespaceURI()) ||
92 XMLString::compareString(XML::Literals::Sites,e->getLocalName()))
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)");
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++)
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)
107 OriginSite* os_obj = new OriginSite();
108 m_sites[os_name.get()]=os_obj;
110 DOMNode* os_child = nlist->item(i)->getFirstChild();
113 if (os_child->getNodeType()!=DOMNode::ELEMENT_NODE)
115 os_child = os_child->getNextSibling();
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()))
123 auto_ptr<XMLCh> hs_name(XMLString::replicate(static_cast<DOMElement*>(os_child)->getAttributeNS(NULL,XML::Literals::Name)));
124 XMLString::trim(hs_name.get());
126 if (hs_name.get() && *hs_name)
128 os_obj->m_handleServices.push_back(hs_name.get());
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()))
141 else if (!XMLString::compareString(XML::SHIB_NS,os_child->getNamespaceURI()) &&
142 !XMLString::compareString(XML::Literals::Domain,os_child->getLocalName()))
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());
149 os_child = os_child->getNextSibling();
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);
160 log.info("Initialized without key: skipping signature verification.");
162 catch (SAMLException& e)
164 log.errorStream() << "XML error while parsing site configuration: " << e.what()
165 << CategoryStream::ENDLINE;
172 log.error("Unexpected error while parsing site configuration");
179 XMLOriginSiteMapper::~XMLOriginSiteMapper()
181 for (map<xstring,OriginSite*>::iterator i=m_sites.begin(); i!=m_sites.end(); i++)
186 private void validateSignature(Key verifyKey, Element e) throws OriginSiteMapperException {
188 Node n = e.getLastChild();
189 while (n != null && n.getNodeType() != Node.ELEMENT_NODE)
190 n = n.getPreviousSibling();
193 && org.opensaml.XML.XMLSIG_NS.equals(n.getNamespaceURI())
194 && "Signature".equals(n.getLocalName())) {
195 log.info("Located signature in document... verifying.");
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
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.");
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.");
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.");
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.");
228 } catch (Exception sigE) {
230 "Unable to verify signature on registry file: An error occured while attempting to verify the signature:"
232 throw new OriginSiteMapperException(
233 "Unable to verify signature on registry file: An error occured while attempting to verify the signature:"
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.");
244 Iterator<xstring> XMLOriginSiteMapper::getHandleServiceNames(const XMLCh* originSite)
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);
252 Key* XMLOriginSiteMapper::getHandleServiceKey(const XMLCh* handleService)
254 map<xstring,Key*>::const_iterator i=m_hsKeys.find(handleService);
255 return (i!=m_hsKeys.end()) ? i->second : NULL;
258 Iterator<xstring> XMLOriginSiteMapper::getSecurityDomains(const XMLCh* originSite)
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);
266 Iterator<X509Certificate*> XMLOriginSiteMapper::getTrustedRoots()
268 return Iterator<X509Certificate*>(m_roots);