https://issues.shibboleth.net/jira/browse/SSPCPP-421
[shibboleth/sp.git] / shibsp / attribute / resolver / impl / AssertionAttributeExtractor.cpp
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/DateTime.h>
37 #include <xmltooling/util/XMLHelper.h>
38 #include <xercesc/util/XMLUniDefs.hpp>
39
40 using namespace shibsp;
41 using namespace opensaml::saml2;
42 using namespace opensaml::saml2md;
43 using namespace opensaml::saml1;
44 using namespace opensaml;
45 using namespace xmltooling;
46 using namespace std;
47
48 namespace shibsp {
49
50 #if defined (_MSC_VER)
51     #pragma warning( push )
52     #pragma warning( disable : 4250 )
53 #endif
54
55     class AssertionExtractor : public AttributeExtractor
56     {
57     public:
58         AssertionExtractor(const DOMElement* e);
59         ~AssertionExtractor() {}
60
61         Lockable* lock() {
62             return this;
63         }
64
65         void unlock() {
66         }
67
68         void extractAttributes(
69             const Application& application,
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_notOnOrAfter,
83             m_sessionIndex,
84             m_sessionNotOnOrAfter,
85             m_subjectAddress,
86             m_subjectDNS,
87             m_consent;
88     };
89
90 #if defined (_MSC_VER)
91     #pragma warning( pop )
92 #endif
93
94     AttributeExtractor* SHIBSP_DLLLOCAL AssertionAttributeExtractorFactory(const DOMElement* const & e)
95     {
96         return new AssertionExtractor(e);
97     }
98
99 };
100
101 AssertionExtractor::AssertionExtractor(const DOMElement* e)
102     : m_authnAuthority(XMLHelper::getAttrString(e, nullptr, AuthenticatingAuthority::LOCAL_NAME)),
103         m_authnClass(XMLHelper::getAttrString(e, nullptr, AuthnContextClassRef::LOCAL_NAME)),
104         m_authnDecl(XMLHelper::getAttrString(e, nullptr, AuthnContextDeclRef::LOCAL_NAME)),
105         m_authnInstant(XMLHelper::getAttrString(e, nullptr, AuthnStatement::AUTHNINSTANT_ATTRIB_NAME)),
106         m_issuer(XMLHelper::getAttrString(e, nullptr, Issuer::LOCAL_NAME)),
107         m_notOnOrAfter(XMLHelper::getAttrString(e, nullptr, saml2::Conditions::NOTONORAFTER_ATTRIB_NAME)),
108         m_sessionIndex(XMLHelper::getAttrString(e, nullptr, AuthnStatement::SESSIONINDEX_ATTRIB_NAME)),
109         m_sessionNotOnOrAfter(XMLHelper::getAttrString(e, nullptr, AuthnStatement::SESSIONNOTONORAFTER_ATTRIB_NAME)),
110         m_subjectAddress(XMLHelper::getAttrString(e, nullptr, saml2::SubjectLocality::ADDRESS_ATTRIB_NAME)),
111         m_subjectDNS(XMLHelper::getAttrString(e, nullptr, saml2::SubjectLocality::DNSNAME_ATTRIB_NAME)),
112         m_consent(XMLHelper::getAttrString(e, nullptr, saml2p::StatusResponseType::CONSENT_ATTRIB_NAME))
113 {
114 }
115
116 void AssertionExtractor::extractAttributes(
117     const Application& application, const RoleDescriptor* issuer, const XMLObject& xmlObject, vector<shibsp::Attribute*>& attributes
118     ) const
119 {
120     const saml2p::StatusResponseType* srt = dynamic_cast<const saml2p::StatusResponseType*>(&xmlObject);
121     if (srt) {
122         // Consent
123         if (!m_consent.empty() && srt->getConsent()) {
124             auto_ptr_char temp(srt->getConsent());
125             if (temp.get() && *temp.get()) {
126                 auto_ptr<SimpleAttribute> consent(new SimpleAttribute(vector<string>(1, m_consent)));
127                 consent->getValues().push_back(temp.get());
128                 attributes.push_back(consent.get());
129                 consent.release();
130             }
131         }
132         return;
133     }
134
135     const saml2::Assertion* saml2assertion = dynamic_cast<const saml2::Assertion*>(&xmlObject);
136     if (saml2assertion) {
137         // Issuer
138         if (!m_issuer.empty()) {
139             const Issuer* i = saml2assertion->getIssuer();
140             if (i && (!i->getFormat() || !*(i->getFormat()) || XMLString::equals(i->getFormat(), NameIDType::ENTITY))) {
141                 auto_ptr_char temp(i->getName());
142                 if (temp.get() && *temp.get()) {
143                     auto_ptr<SimpleAttribute> issuer(new SimpleAttribute(vector<string>(1, m_issuer)));
144                     issuer->getValues().push_back(temp.get());
145                     attributes.push_back(issuer.get());
146                     issuer.release();
147                 }
148             }
149         }
150
151         // NotOnOrAfter
152         if (!m_notOnOrAfter.empty() && saml2assertion->getConditions() && saml2assertion->getConditions()->getNotOnOrAfter()) {
153             auto_ptr_char temp(saml2assertion->getConditions()->getNotOnOrAfter()->getRawData());
154             if (temp.get()) {
155                 auto_ptr<SimpleAttribute> notonorafter(new SimpleAttribute(vector<string>(1, m_notOnOrAfter)));
156                 notonorafter->getValues().push_back(temp.get());
157                 attributes.push_back(notonorafter.get());
158                 notonorafter.release();
159             }
160         }
161
162         return;
163     }
164
165     const AuthnStatement* saml2statement = dynamic_cast<const AuthnStatement*>(&xmlObject);
166     if (saml2statement) {
167         // AuthnInstant
168         if (!m_authnInstant.empty() && saml2statement->getAuthnInstant()) {
169             auto_ptr_char temp(saml2statement->getAuthnInstant()->getRawData());
170             if (temp.get()) {
171                 auto_ptr<SimpleAttribute> authninstant(new SimpleAttribute(vector<string>(1, m_authnInstant)));
172                 authninstant->getValues().push_back(temp.get());
173                 attributes.push_back(authninstant.get());
174                 authninstant.release();
175             }
176         }
177
178         // SessionIndex
179         if (!m_sessionIndex.empty() && saml2statement->getSessionIndex() && *(saml2statement->getSessionIndex())) {
180             auto_ptr_char temp(saml2statement->getSessionIndex());
181             if (temp.get()) {
182                 auto_ptr<SimpleAttribute> sessionindex(new SimpleAttribute(vector<string>(1, m_sessionIndex)));
183                 sessionindex->getValues().push_back(temp.get());
184                 attributes.push_back(sessionindex.get());
185                 sessionindex.release();
186             }
187         }
188
189         // SessionNotOnOrAfter
190         if (!m_sessionNotOnOrAfter.empty() && saml2statement->getSessionNotOnOrAfter()) {
191             auto_ptr_char temp(saml2statement->getSessionNotOnOrAfter()->getRawData());
192             if (temp.get()) {
193                 auto_ptr<SimpleAttribute> sessionnotonorafter(new SimpleAttribute(vector<string>(1, m_sessionNotOnOrAfter)));
194                 sessionnotonorafter->getValues().push_back(temp.get());
195                 attributes.push_back(sessionnotonorafter.get());
196                 sessionnotonorafter.release();
197             }
198         }
199
200         if (saml2statement->getSubjectLocality()) {
201             const saml2::SubjectLocality* locality = saml2statement->getSubjectLocality();
202             // Address
203             if (!m_subjectAddress.empty() && locality->getAddress() && *(locality->getAddress())) {
204                 auto_ptr_char temp(locality->getAddress());
205                 if (temp.get()) {
206                     auto_ptr<SimpleAttribute> address(new SimpleAttribute(vector<string>(1, m_subjectAddress)));
207                     address->getValues().push_back(temp.get());
208                     attributes.push_back(address.get());
209                     address.release();
210                 }
211             }
212
213             // DNSName
214             if (!m_subjectDNS.empty() && locality->getDNSName() && *(locality->getDNSName())) {
215                 auto_ptr_char temp(locality->getDNSName());
216                 if (temp.get()) {
217                     auto_ptr<SimpleAttribute> dns(new SimpleAttribute(vector<string>(1, m_subjectDNS)));
218                     dns->getValues().push_back(temp.get());
219                     attributes.push_back(dns.get());
220                     dns.release();
221                 }
222             }
223         }
224
225         if (saml2statement->getAuthnContext()) {
226             const AuthnContext* ac = saml2statement->getAuthnContext();
227             // AuthnContextClassRef
228             if (!m_authnClass.empty() && ac->getAuthnContextClassRef() && ac->getAuthnContextClassRef()->getReference()) {
229                 auto_ptr_char temp(ac->getAuthnContextClassRef()->getReference());
230                 if (temp.get()) {
231                     auto_ptr<SimpleAttribute> classref(new SimpleAttribute(vector<string>(1, m_authnClass)));
232                     classref->getValues().push_back(temp.get());
233                     attributes.push_back(classref.get());
234                     classref.release();
235                 }
236             }
237
238             // AuthnContextDeclRef
239             if (!m_authnDecl.empty() && ac->getAuthnContextDeclRef() && ac->getAuthnContextDeclRef()->getReference()) {
240                 auto_ptr_char temp(ac->getAuthnContextDeclRef()->getReference());
241                 if (temp.get()) {
242                     auto_ptr<SimpleAttribute> declref(new SimpleAttribute(vector<string>(1, m_authnDecl)));
243                     declref->getValues().push_back(temp.get());
244                     attributes.push_back(declref.get());
245                     declref.release();
246                 }
247             }
248
249             // AuthenticatingAuthority
250             if (!m_authnAuthority.empty() && !ac->getAuthenticatingAuthoritys().empty()) {
251                 auto_ptr<SimpleAttribute> attr(new SimpleAttribute(vector<string>(1, m_authnAuthority)));
252                 const vector<AuthenticatingAuthority*>& authorities = ac->getAuthenticatingAuthoritys();
253                 for (vector<AuthenticatingAuthority*>::const_iterator a = authorities.begin(); a != authorities.end(); ++a) {
254                     auto_ptr_char temp((*a)->getID());
255                     if (temp.get())
256                         attr->getValues().push_back(temp.get());
257                 }
258                 if (attr->valueCount() > 0) {
259                     attributes.push_back(attr.get());
260                     attr.release();
261                 }
262             }
263         }
264
265         return;
266     }
267
268     const saml1::Assertion* saml1assertion = dynamic_cast<const saml1::Assertion*>(&xmlObject);
269     if (saml1assertion) {
270         // Issuer
271         if (!m_issuer.empty()) {
272             if (saml1assertion->getIssuer() && *(saml1assertion->getIssuer())) {
273                 auto_ptr_char temp(saml1assertion->getIssuer());
274                 if (temp.get()) {
275                     auto_ptr<SimpleAttribute> issuer(new SimpleAttribute(vector<string>(1, m_issuer)));
276                     issuer->getValues().push_back(temp.get());
277                     attributes.push_back(issuer.get());
278                     issuer.release();
279                 }
280             }
281         }
282
283         // NotOnOrAfter
284         if (!m_notOnOrAfter.empty() && saml1assertion->getConditions() && saml1assertion->getConditions()->getNotOnOrAfter()) {
285             auto_ptr_char temp(saml1assertion->getConditions()->getNotOnOrAfter()->getRawData());
286             if (temp.get()) {
287                 auto_ptr<SimpleAttribute> notonorafter(new SimpleAttribute(vector<string>(1, m_notOnOrAfter)));
288                 notonorafter->getValues().push_back(temp.get());
289                 attributes.push_back(notonorafter.get());
290                 notonorafter.release();
291             }
292         }
293
294         return;
295     }
296
297     const AuthenticationStatement* saml1statement = dynamic_cast<const AuthenticationStatement*>(&xmlObject);
298     if (saml1statement) {
299         // AuthnInstant
300         if (!m_authnInstant.empty() && saml1statement->getAuthenticationInstant()) {
301             auto_ptr_char temp(saml1statement->getAuthenticationInstant()->getRawData());
302             if (temp.get()) {
303                 auto_ptr<SimpleAttribute> authninstant(new SimpleAttribute(vector<string>(1, m_authnInstant)));
304                 authninstant->getValues().push_back(temp.get());
305                 attributes.push_back(authninstant.get());
306                 authninstant.release();
307             }
308         }
309
310         // AuthenticationMethod
311         if (!m_authnClass.empty() && saml1statement->getAuthenticationMethod() && *(saml1statement->getAuthenticationMethod())) {
312             auto_ptr_char temp(saml1statement->getAuthenticationMethod());
313             if (temp.get()) {
314                 auto_ptr<SimpleAttribute> authnmethod(new SimpleAttribute(vector<string>(1, m_authnClass)));
315                 authnmethod->getValues().push_back(temp.get());
316                 attributes.push_back(authnmethod.get());
317                 authnmethod.release();
318             }
319         }
320
321         if (saml1statement->getSubjectLocality()) {
322             const saml1::SubjectLocality* locality = saml1statement->getSubjectLocality();
323             // IPAddress
324             if (!m_subjectAddress.empty() && locality->getIPAddress() && *(locality->getIPAddress())) {
325                 auto_ptr_char temp(locality->getIPAddress());
326                 if (temp.get()) {
327                     auto_ptr<SimpleAttribute> address(new SimpleAttribute(vector<string>(1, m_subjectAddress)));
328                     address->getValues().push_back(temp.get());
329                     attributes.push_back(address.get());
330                     address.release();
331                 }
332             }
333
334             // DNSAddress
335             if (!m_subjectDNS.empty() && locality->getDNSAddress() && *(locality->getDNSAddress())) {
336                 auto_ptr_char temp(locality->getDNSAddress());
337                 if (temp.get()) {
338                     auto_ptr<SimpleAttribute> dns(new SimpleAttribute(vector<string>(1, m_subjectDNS)));
339                     dns->getValues().push_back(temp.get());
340                     attributes.push_back(dns.get());
341                     dns.release();
342                 }
343             }
344         }
345     }
346 }
347
348 void AssertionExtractor::getAttributeIds(vector<string>& attributes) const
349 {
350     if (!m_authnAuthority.empty())
351         attributes.push_back(m_authnAuthority);
352     if (!m_authnClass.empty())
353         attributes.push_back(m_authnClass);
354     if (!m_authnDecl.empty())
355         attributes.push_back(m_authnDecl);
356     if (!m_authnInstant.empty())
357         attributes.push_back(m_authnInstant);
358     if (!m_issuer.empty())
359         attributes.push_back(m_issuer);
360     if (!m_notOnOrAfter.empty())
361         attributes.push_back(m_notOnOrAfter);
362     if (!m_sessionIndex.empty())
363         attributes.push_back(m_sessionIndex);
364     if (!m_sessionNotOnOrAfter.empty())
365         attributes.push_back(m_sessionNotOnOrAfter);
366     if (!m_subjectAddress.empty())
367         attributes.push_back(m_subjectAddress);
368     if (!m_subjectDNS.empty())
369         attributes.push_back(m_subjectDNS);
370     if (!m_consent.empty())
371         attributes.push_back(m_consent);
372 }