1 /**
2  * Licensed to the University Corporation for Advanced Internet
3  * Development, Inc. (UCAID) under one or more contributor license
4  * agreements. See the NOTICE file distributed with this work for
5  * additional information regarding copyright ownership.
6  *
7  * UCAID licenses this file to you under the Apache License,
8  * Version 2.0 (the "License"); you may not use this file except
9  * in compliance with the License. You may obtain a copy of the
10  * License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing,
15  * software distributed under the License is distributed on an
16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17  * either express or implied. See the License for the specific
18  * language governing permissions and limitations under the License.
19  */
20 
21 /**
22  * AssertionAttributeExtractor.cpp
23  *
24  * AttributeExtractor for SAML assertion content.
25  */
26 
27 #include "internal.h"
28 #include "Application.h"
29 #include "ServiceProvider.h"
30 #include "attribute/SimpleAttribute.h"
31 #include "attribute/resolver/AttributeExtractor.h"
32 
33 #include <saml/saml1/core/Assertions.h>
34 #include <saml/saml2/core/Protocols.h>
35 #include <saml/saml2/metadata/Metadata.h>
36 #include <xmltooling/util/XMLHelper.h>
37 #include <xercesc/util/XMLUniDefs.hpp>
38 
39 using namespace shibsp;
40 using namespace opensaml::saml2;
41 using namespace opensaml::saml2md;
42 using namespace opensaml::saml1;
43 using namespace opensaml;
44 using namespace xmltooling;
45 using namespace std;
46 
47 namespace shibsp {
48 
49 #if defined (_MSC_VER)
50     #pragma warning( push )
51     #pragma warning( disable : 4250 )
52 #endif
53 
54     class AssertionExtractor : public AttributeExtractor
55     {
56     public:
57         AssertionExtractor(const DOMElement* e);
~AssertionExtractor()58         ~AssertionExtractor() {}
59 
lock()60         Lockable* lock() {
61             return this;
62         }
63 
unlock()64         void unlock() {
65         }
66 
67         void extractAttributes(
68             const Application& application,
69             const GenericRequest* request,
70             const RoleDescriptor* issuer,
71             const XMLObject& xmlObject,
72             vector<shibsp::Attribute*>& attributes
73             ) const;
74         void getAttributeIds(vector<string>& attributes) const;
75 
76     private:
77         string m_authnAuthority,
78             m_authnClass,
79             m_authnDecl,
80             m_authnInstant,
81             m_issuer,
82             m_issuerFormat,
83             m_notBefore,
84             m_notOnOrAfter,
85             m_sessionIndex,
86             m_sessionNotOnOrAfter,
87             m_subjectAddress,
88             m_subjectDNS,
89             m_consent;
90     };
91 
92 #if defined (_MSC_VER)
93     #pragma warning( pop )
94 #endif
95 
AssertionAttributeExtractorFactory(const DOMElement * const & e,bool)96     AttributeExtractor* SHIBSP_DLLLOCAL AssertionAttributeExtractorFactory(const DOMElement* const & e, bool)
97     {
98         return new AssertionExtractor(e);
99     }
100 
101     static const XMLCh IssuerFormat[] = UNICODE_LITERAL_12(I,s,s,u,e,r,F,o,r,m,a,t);
102 };
103 
AssertionExtractor(const DOMElement * e)104 AssertionExtractor::AssertionExtractor(const DOMElement* e)
105     : m_authnAuthority(XMLHelper::getAttrString(e, nullptr, AuthenticatingAuthority::LOCAL_NAME)),
106         m_authnClass(XMLHelper::getAttrString(e, nullptr, AuthnContextClassRef::LOCAL_NAME)),
107         m_authnDecl(XMLHelper::getAttrString(e, nullptr, AuthnContextDeclRef::LOCAL_NAME)),
108         m_authnInstant(XMLHelper::getAttrString(e, nullptr, AuthnStatement::AUTHNINSTANT_ATTRIB_NAME)),
109         m_issuer(XMLHelper::getAttrString(e, nullptr, Issuer::LOCAL_NAME)),
110         m_issuerFormat(XMLHelper::getAttrString(e, nullptr, IssuerFormat)),
111         m_notBefore(XMLHelper::getAttrString(e, nullptr, saml2::Conditions::NOTBEFORE_ATTRIB_NAME)),
112         m_notOnOrAfter(XMLHelper::getAttrString(e, nullptr, saml2::Conditions::NOTONORAFTER_ATTRIB_NAME)),
113         m_sessionIndex(XMLHelper::getAttrString(e, nullptr, AuthnStatement::SESSIONINDEX_ATTRIB_NAME)),
114         m_sessionNotOnOrAfter(XMLHelper::getAttrString(e, nullptr, AuthnStatement::SESSIONNOTONORAFTER_ATTRIB_NAME)),
115         m_subjectAddress(XMLHelper::getAttrString(e, nullptr, saml2::SubjectLocality::ADDRESS_ATTRIB_NAME)),
116         m_subjectDNS(XMLHelper::getAttrString(e, nullptr, saml2::SubjectLocality::DNSNAME_ATTRIB_NAME)),
117         m_consent(XMLHelper::getAttrString(e, nullptr, saml2p::StatusResponseType::CONSENT_ATTRIB_NAME))
118 {
119 }
120 
extractAttributes(const Application & application,const GenericRequest * request,const RoleDescriptor * issuer,const XMLObject & xmlObject,vector<shibsp::Attribute * > & attributes) const121 void AssertionExtractor::extractAttributes(
122     const Application& application, const GenericRequest* request, const RoleDescriptor* issuer, const XMLObject& xmlObject, vector<shibsp::Attribute*>& attributes
123     ) const
124 {
125     const saml2p::StatusResponseType* srt = dynamic_cast<const saml2p::StatusResponseType*>(&xmlObject);
126     if (srt) {
127         // Consent
128         if (!m_consent.empty() && srt->getConsent()) {
129             auto_ptr_char temp(srt->getConsent());
130             if (temp.get() && *temp.get()) {
131                 auto_ptr<SimpleAttribute> consent(new SimpleAttribute(vector<string>(1, m_consent)));
132                 consent->getValues().push_back(temp.get());
133                 attributes.push_back(consent.get());
134                 consent.release();
135             }
136         }
137         return;
138     }
139 
140     const saml2::Assertion* saml2assertion = dynamic_cast<const saml2::Assertion*>(&xmlObject);
141     if (saml2assertion) {
142 
143         if (saml2assertion->getIssuer()) {
144             // Issuer
145             if (!m_issuer.empty()) {
146                 auto_ptr_char temp(saml2assertion->getIssuer()->getName());
147                 if (temp.get() && *temp.get()) {
148                     auto_ptr<SimpleAttribute> issuer(new SimpleAttribute(vector<string>(1, m_issuer)));
149                     issuer->getValues().push_back(temp.get());
150                     attributes.push_back(issuer.get());
151                     issuer.release();
152                 }
153             }
154 
155             // Format
156             if (!m_issuerFormat.empty()) {
157                 auto_ptr_char temp(saml2assertion->getIssuer()->getFormat());
158                 if (temp.get()) {
159                     auto_ptr<SimpleAttribute> format(new SimpleAttribute(vector<string>(1, m_issuerFormat)));
160                     format->getValues().push_back(temp.get());
161                     attributes.push_back(format.get());
162                     format.release();
163                 }
164             }
165         }
166 
167         // NotBefore / NotOnOrAfter
168         if (saml2assertion->getConditions()) {
169             if (!m_notBefore.empty() && saml2assertion->getConditions()->getNotBefore()) {
170                 auto_ptr_char temp(saml2assertion->getConditions()->getNotBefore()->getRawData());
171                 if (temp.get()) {
172                     auto_ptr<SimpleAttribute> notbefore(new SimpleAttribute(vector<string>(1, m_notBefore)));
173                     notbefore->getValues().push_back(temp.get());
174                     attributes.push_back(notbefore.get());
175                     notbefore.release();
176                 }
177             }
178             if (!m_notOnOrAfter.empty() && saml2assertion->getConditions()->getNotOnOrAfter()) {
179                 auto_ptr_char temp(saml2assertion->getConditions()->getNotOnOrAfter()->getRawData());
180                 if (temp.get()) {
181                     auto_ptr<SimpleAttribute> notonorafter(new SimpleAttribute(vector<string>(1, m_notOnOrAfter)));
182                     notonorafter->getValues().push_back(temp.get());
183                     attributes.push_back(notonorafter.get());
184                     notonorafter.release();
185                 }
186             }
187         }
188 
189         return;
190     }
191 
192     const AuthnStatement* saml2statement = dynamic_cast<const AuthnStatement*>(&xmlObject);
193     if (saml2statement) {
194         // AuthnInstant
195         if (!m_authnInstant.empty() && saml2statement->getAuthnInstant()) {
196             auto_ptr_char temp(saml2statement->getAuthnInstant()->getRawData());
197             if (temp.get()) {
198                 auto_ptr<SimpleAttribute> authninstant(new SimpleAttribute(vector<string>(1, m_authnInstant)));
199                 authninstant->getValues().push_back(temp.get());
200                 attributes.push_back(authninstant.get());
201                 authninstant.release();
202             }
203         }
204 
205         // SessionIndex
206         if (!m_sessionIndex.empty() && saml2statement->getSessionIndex() && *(saml2statement->getSessionIndex())) {
207             auto_ptr_char temp(saml2statement->getSessionIndex());
208             if (temp.get()) {
209                 auto_ptr<SimpleAttribute> sessionindex(new SimpleAttribute(vector<string>(1, m_sessionIndex)));
210                 sessionindex->getValues().push_back(temp.get());
211                 attributes.push_back(sessionindex.get());
212                 sessionindex.release();
213             }
214         }
215 
216         // SessionNotOnOrAfter
217         if (!m_sessionNotOnOrAfter.empty() && saml2statement->getSessionNotOnOrAfter()) {
218             auto_ptr_char temp(saml2statement->getSessionNotOnOrAfter()->getRawData());
219             if (temp.get()) {
220                 auto_ptr<SimpleAttribute> sessionnotonorafter(new SimpleAttribute(vector<string>(1, m_sessionNotOnOrAfter)));
221                 sessionnotonorafter->getValues().push_back(temp.get());
222                 attributes.push_back(sessionnotonorafter.get());
223                 sessionnotonorafter.release();
224             }
225         }
226 
227         if (saml2statement->getSubjectLocality()) {
228             const saml2::SubjectLocality* locality = saml2statement->getSubjectLocality();
229             // Address
230             if (!m_subjectAddress.empty() && locality->getAddress() && *(locality->getAddress())) {
231                 auto_ptr_char temp(locality->getAddress());
232                 if (temp.get()) {
233                     auto_ptr<SimpleAttribute> address(new SimpleAttribute(vector<string>(1, m_subjectAddress)));
234                     address->getValues().push_back(temp.get());
235                     attributes.push_back(address.get());
236                     address.release();
237                 }
238             }
239 
240             // DNSName
241             if (!m_subjectDNS.empty() && locality->getDNSName() && *(locality->getDNSName())) {
242                 auto_ptr_char temp(locality->getDNSName());
243                 if (temp.get()) {
244                     auto_ptr<SimpleAttribute> dns(new SimpleAttribute(vector<string>(1, m_subjectDNS)));
245                     dns->getValues().push_back(temp.get());
246                     attributes.push_back(dns.get());
247                     dns.release();
248                 }
249             }
250         }
251 
252         if (saml2statement->getAuthnContext()) {
253             const AuthnContext* ac = saml2statement->getAuthnContext();
254             // AuthnContextClassRef
255             if (!m_authnClass.empty() && ac->getAuthnContextClassRef() && ac->getAuthnContextClassRef()->getReference()) {
256                 auto_ptr_char temp(ac->getAuthnContextClassRef()->getReference());
257                 if (temp.get()) {
258                     auto_ptr<SimpleAttribute> classref(new SimpleAttribute(vector<string>(1, m_authnClass)));
259                     classref->getValues().push_back(temp.get());
260                     attributes.push_back(classref.get());
261                     classref.release();
262                 }
263             }
264 
265             // AuthnContextDeclRef
266             if (!m_authnDecl.empty() && ac->getAuthnContextDeclRef() && ac->getAuthnContextDeclRef()->getReference()) {
267                 auto_ptr_char temp(ac->getAuthnContextDeclRef()->getReference());
268                 if (temp.get()) {
269                     auto_ptr<SimpleAttribute> declref(new SimpleAttribute(vector<string>(1, m_authnDecl)));
270                     declref->getValues().push_back(temp.get());
271                     attributes.push_back(declref.get());
272                     declref.release();
273                 }
274             }
275 
276             // AuthenticatingAuthority
277             if (!m_authnAuthority.empty() && !ac->getAuthenticatingAuthoritys().empty()) {
278                 auto_ptr<SimpleAttribute> attr(new SimpleAttribute(vector<string>(1, m_authnAuthority)));
279                 const vector<AuthenticatingAuthority*>& authorities = ac->getAuthenticatingAuthoritys();
280                 for (vector<AuthenticatingAuthority*>::const_iterator a = authorities.begin(); a != authorities.end(); ++a) {
281                     auto_ptr_char temp((*a)->getID());
282                     if (temp.get())
283                         attr->getValues().push_back(temp.get());
284                 }
285                 if (attr->valueCount() > 0) {
286                     attributes.push_back(attr.get());
287                     attr.release();
288                 }
289             }
290         }
291 
292         return;
293     }
294 
295     const saml1::Assertion* saml1assertion = dynamic_cast<const saml1::Assertion*>(&xmlObject);
296     if (saml1assertion) {
297         // Issuer
298         if (!m_issuer.empty()) {
299             if (saml1assertion->getIssuer() && *(saml1assertion->getIssuer())) {
300                 auto_ptr_char temp(saml1assertion->getIssuer());
301                 if (temp.get()) {
302                     auto_ptr<SimpleAttribute> issuer(new SimpleAttribute(vector<string>(1, m_issuer)));
303                     issuer->getValues().push_back(temp.get());
304                     attributes.push_back(issuer.get());
305                     issuer.release();
306                 }
307             }
308         }
309 
310         // NotOnOrAfter
311         if (!m_notOnOrAfter.empty() && saml1assertion->getConditions() && saml1assertion->getConditions()->getNotOnOrAfter()) {
312             auto_ptr_char temp(saml1assertion->getConditions()->getNotOnOrAfter()->getRawData());
313             if (temp.get()) {
314                 auto_ptr<SimpleAttribute> notonorafter(new SimpleAttribute(vector<string>(1, m_notOnOrAfter)));
315                 notonorafter->getValues().push_back(temp.get());
316                 attributes.push_back(notonorafter.get());
317                 notonorafter.release();
318             }
319         }
320 
321         return;
322     }
323 
324     const AuthenticationStatement* saml1statement = dynamic_cast<const AuthenticationStatement*>(&xmlObject);
325     if (saml1statement) {
326         // AuthnInstant
327         if (!m_authnInstant.empty() && saml1statement->getAuthenticationInstant()) {
328             auto_ptr_char temp(saml1statement->getAuthenticationInstant()->getRawData());
329             if (temp.get()) {
330                 auto_ptr<SimpleAttribute> authninstant(new SimpleAttribute(vector<string>(1, m_authnInstant)));
331                 authninstant->getValues().push_back(temp.get());
332                 attributes.push_back(authninstant.get());
333                 authninstant.release();
334             }
335         }
336 
337         // AuthenticationMethod
338         if (!m_authnClass.empty() && saml1statement->getAuthenticationMethod() && *(saml1statement->getAuthenticationMethod())) {
339             auto_ptr_char temp(saml1statement->getAuthenticationMethod());
340             if (temp.get()) {
341                 auto_ptr<SimpleAttribute> authnmethod(new SimpleAttribute(vector<string>(1, m_authnClass)));
342                 authnmethod->getValues().push_back(temp.get());
343                 attributes.push_back(authnmethod.get());
344                 authnmethod.release();
345             }
346         }
347 
348         if (saml1statement->getSubjectLocality()) {
349             const saml1::SubjectLocality* locality = saml1statement->getSubjectLocality();
350             // IPAddress
351             if (!m_subjectAddress.empty() && locality->getIPAddress() && *(locality->getIPAddress())) {
352                 auto_ptr_char temp(locality->getIPAddress());
353                 if (temp.get()) {
354                     auto_ptr<SimpleAttribute> address(new SimpleAttribute(vector<string>(1, m_subjectAddress)));
355                     address->getValues().push_back(temp.get());
356                     attributes.push_back(address.get());
357                     address.release();
358                 }
359             }
360 
361             // DNSAddress
362             if (!m_subjectDNS.empty() && locality->getDNSAddress() && *(locality->getDNSAddress())) {
363                 auto_ptr_char temp(locality->getDNSAddress());
364                 if (temp.get()) {
365                     auto_ptr<SimpleAttribute> dns(new SimpleAttribute(vector<string>(1, m_subjectDNS)));
366                     dns->getValues().push_back(temp.get());
367                     attributes.push_back(dns.get());
368                     dns.release();
369                 }
370             }
371         }
372     }
373 }
374 
getAttributeIds(vector<string> & attributes) const375 void AssertionExtractor::getAttributeIds(vector<string>& attributes) const
376 {
377     if (!m_authnAuthority.empty())
378         attributes.push_back(m_authnAuthority);
379     if (!m_authnClass.empty())
380         attributes.push_back(m_authnClass);
381     if (!m_authnDecl.empty())
382         attributes.push_back(m_authnDecl);
383     if (!m_authnInstant.empty())
384         attributes.push_back(m_authnInstant);
385     if (!m_issuer.empty())
386         attributes.push_back(m_issuer);
387     if (!m_notOnOrAfter.empty())
388         attributes.push_back(m_notOnOrAfter);
389     if (!m_sessionIndex.empty())
390         attributes.push_back(m_sessionIndex);
391     if (!m_sessionNotOnOrAfter.empty())
392         attributes.push_back(m_sessionNotOnOrAfter);
393     if (!m_subjectAddress.empty())
394         attributes.push_back(m_subjectAddress);
395     if (!m_subjectDNS.empty())
396         attributes.push_back(m_subjectDNS);
397     if (!m_consent.empty())
398         attributes.push_back(m_consent);
399 }
400