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 /* ShibPOSTProfile.cpp - Shibboleth-specific wrapper around SAML POST profile
62 #include <openssl/x509v3.h>
64 using namespace shibboleth;
66 using namespace log4cpp;
69 ShibPOSTProfile::ShibPOSTProfile(
70 const Iterator<IMetadata*>& metadatas,
71 const Iterator<IRevocation*>& revocations,
72 const Iterator<ITrust*>& trusts,
73 const Iterator<ICredentials*>& creds
74 ) : m_metadatas(metadatas), m_revocations(revocations), m_trusts(trusts), m_creds(creds) {}
76 const SAMLAssertion* ShibPOSTProfile::getSSOAssertion(const SAMLResponse& r, const Iterator<const XMLCh*>& audiences)
78 return SAMLPOSTProfile::getSSOAssertion(r,audiences);
81 const SAMLAuthenticationStatement* ShibPOSTProfile::getSSOStatement(const SAMLAssertion& a)
83 return SAMLPOSTProfile::getSSOStatement(a);
86 const XMLCh* ShibPOSTProfile::getProviderId(const saml::SAMLResponse& r)
88 // Switch to Issuer by itself, stop using NameQualifier.
89 Iterator<SAMLAssertion*> ia=r.getAssertions();
91 return (ia.next())->getIssuer();
95 SAMLResponse* ShibPOSTProfile::accept(
97 const XMLCh* recipient,
99 const saml::Iterator<const XMLCh*>& audiences,
103 Category& log=Category::getInstance(SHIB_LOGCAT".ShibPOSTProfile");
105 // The built-in SAML functionality will do most of the basic non-crypto checks.
106 // Note that if the response only contains a status error, it gets tossed out
108 auto_ptr<SAMLResponse> r(SAMLPOSTProfile::accept(buf, recipient, ttlSeconds, false));
110 // Now we do some more non-crypto (ie. cheap) work to match up the origin site
111 // with its associated data.
112 const SAMLAssertion* assertion = NULL;
113 const SAMLAuthenticationStatement* sso = NULL;
116 assertion = getSSOAssertion(*(r.get()),audiences);
117 sso = getSSOStatement(*assertion);
120 // We want to try our best to locate an origin site name so we can fill it in.
122 *pproviderId=XMLString::replicate(getProviderId(*(r.get())));
126 // Finish SAML processing.
127 SAMLPOSTProfile::process(*(r.get()), recipient, ttlSeconds);
129 // Try and locate metadata for the IdP. With this new version, we try Issuer first.
130 log.debug("searching metadata for assertion issuer...");
131 Metadata m(m_metadatas);
132 const IEntityDescriptor* provider=m.lookup(assertion->getIssuer());
135 *pproviderId=XMLString::replicate(assertion->getIssuer());
136 log.debug("matched assertion issuer against metadata");
139 // Might be a down-level origin.
140 provider=m.lookup(sso->getSubject()->getNameIdentifier()->getNameQualifier());
143 *pproviderId=XMLString::replicate(sso->getSubject()->getNameIdentifier()->getNameQualifier());
144 log.debug("matched subject name qualifier against metadata");
148 // No metadata at all.
150 auto_ptr_char issuer(assertion->getIssuer());
151 auto_ptr_char nq(sso->getSubject()->getNameIdentifier()->getNameQualifier());
152 log.error("assertion issuer not found in metadata (Issuer='%s', NameQualifier='%s'",
153 issuer.get(), (nq.get() ? nq.get() : "null"));
154 throw MetadataException("ShibPOSTProfile::accept() metadata lookup failed, unable to process assertion");
157 // Is this provider an IdP?
158 const IIDPSSODescriptor* role=provider->getIDPSSODescriptor(saml::XML::SAML11_PROTOCOL_ENUM);
160 log.debug("passing response to trust layer");
162 // Use this role to evaluate the signature.
164 if (!t.validate(m_revocations,role,*r))
165 throw TrustException("ShibPOSTProfile::accept() unable to verify signed response");
167 // Assertion(s) signed?
168 Iterator<SAMLAssertion*> itera=r->getAssertions();
169 while (itera.hasNext()) {
170 SAMLAssertion* _a=itera.next();
171 if (_a->isSigned()) {
172 log.debug("passing signed assertion to trust layer");
173 if (!t.validate(m_revocations,role,*_a))
174 throw TrustException("ShibPOSTProfile::accept() unable to verify signed assertion");
180 auto_ptr_char issuer(assertion->getIssuer());
181 auto_ptr_char nq(sso->getSubject()->getNameIdentifier()->getNameQualifier());
182 log.error("metadata for assertion issuer indicates no SAML 1.x identity provider role (Issuer='%s', NameQualifier='%s'",
183 issuer.get(), (nq.get() ? nq.get() : "null"));
184 throw MetadataException("ShibPOSTProfile::accept() metadata lookup failed, issuer not registered as SAML 1.x identity provider");
187 SAMLResponse* ShibPOSTProfile::prepare(
188 const IIDPSSODescriptor* role,
189 const char* credResolverId,
190 const XMLCh* recipient,
191 const XMLCh* authMethod,
192 const SAMLDateTime& authInstant,
195 const XMLCh* nameQualifier,
196 const XMLCh* subjectIP,
197 const saml::Iterator<const XMLCh*>& audiences,
198 const saml::Iterator<saml::SAMLAuthorityBinding*>& bindings)
200 SAMLResponse* r = SAMLPOSTProfile::prepare(
202 role->getEntityDescriptor()->getId(),
213 Credentials c(m_creds);
214 const ICredResolver* cr=c.lookup(credResolverId);
217 throw CredentialException("ShibPOSTProfile::prepare() unable to access credential resolver");
219 XSECCryptoKey* key=cr->getKey();
222 throw CredentialException("ShibPOSTProfile::prepare() unable to resolve signing key");
225 r->sign(SIGNATURE_RSA,key,cr->getCertificates());
229 bool ShibPOSTProfile::checkReplayCache(const SAMLAssertion& a)
231 // Default implementation uses the basic replay cache implementation.
232 return SAMLPOSTProfile::checkReplayCache(a);