Extend SSPCPP-343 with generic Assertion extractor
[shibboleth/cpp-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/Assertions.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     };
88
89 #if defined (_MSC_VER)
90     #pragma warning( pop )
91 #endif
92
93     AttributeExtractor* SHIBSP_DLLLOCAL AssertionAttributeExtractorFactory(const DOMElement* const & e)
94     {
95         return new AssertionExtractor(e);
96     }
97
98 };
99
100 AssertionExtractor::AssertionExtractor(const DOMElement* e)
101     : m_authnAuthority(XMLHelper::getAttrString(e, nullptr, AuthenticatingAuthority::LOCAL_NAME)),
102         m_authnClass(XMLHelper::getAttrString(e, nullptr, AuthnContextClassRef::LOCAL_NAME)),
103         m_authnDecl(XMLHelper::getAttrString(e, nullptr, AuthnContextDeclRef::LOCAL_NAME)),
104         m_authnInstant(XMLHelper::getAttrString(e, nullptr, AuthnStatement::AUTHNINSTANT_ATTRIB_NAME)),
105         m_issuer(XMLHelper::getAttrString(e, nullptr, Issuer::LOCAL_NAME)),
106         m_notOnOrAfter(XMLHelper::getAttrString(e, nullptr, saml2::Conditions::NOTONORAFTER_ATTRIB_NAME)),
107         m_sessionIndex(XMLHelper::getAttrString(e, nullptr, AuthnStatement::SESSIONINDEX_ATTRIB_NAME)),
108         m_sessionNotOnOrAfter(XMLHelper::getAttrString(e, nullptr, AuthnStatement::SESSIONNOTONORAFTER_ATTRIB_NAME)),
109         m_subjectAddress(XMLHelper::getAttrString(e, nullptr, saml2::SubjectLocality::ADDRESS_ATTRIB_NAME)),
110         m_subjectDNS(XMLHelper::getAttrString(e, nullptr, saml2::SubjectLocality::DNSNAME_ATTRIB_NAME))
111 {
112 }
113
114 void AssertionExtractor::extractAttributes(
115     const Application& application, const RoleDescriptor* issuer, const XMLObject& xmlObject, vector<shibsp::Attribute*>& attributes
116     ) const
117 {
118     const saml2::Assertion* saml2assertion = dynamic_cast<const saml2::Assertion*>(&xmlObject);
119     if (saml2assertion) {
120         // Issuer
121         if (!m_issuer.empty()) {
122             const Issuer* i = saml2assertion->getIssuer();
123             if (i && (!i->getFormat() || !*(i->getFormat()) || XMLString::equals(i->getFormat(), NameIDType::ENTITY))) {
124                 auto_ptr<SimpleAttribute> issuer(new SimpleAttribute(vector<string>(1, m_issuer)));
125                 auto_ptr_char temp(i->getName());
126                 if (temp.get()) {
127                     issuer->getValues().push_back(temp.get());
128                     attributes.push_back(issuer.release());
129                 }
130             }
131         }
132
133         // NotOnOrAfter
134         if (!m_notOnOrAfter.empty() && saml2assertion->getConditions() && saml2assertion->getConditions()->getNotOnOrAfter()) {
135             auto_ptr<SimpleAttribute> notonorafter(new SimpleAttribute(vector<string>(1, m_notOnOrAfter)));
136             auto_ptr_char temp(saml2assertion->getConditions()->getNotOnOrAfter()->getRawData());
137             if (temp.get()) {
138                 notonorafter->getValues().push_back(temp.get());
139                 attributes.push_back(notonorafter.release());
140             }
141         }
142     }
143     else {
144         const AuthnStatement* saml2statement = dynamic_cast<const AuthnStatement*>(&xmlObject);
145         if (saml2statement) {
146             // AuthnInstant
147             if (!m_authnInstant.empty() && saml2statement->getAuthnInstant()) {
148                 auto_ptr<SimpleAttribute> authninstant(new SimpleAttribute(vector<string>(1, m_authnInstant)));
149                 auto_ptr_char temp(saml2statement->getAuthnInstant()->getRawData());
150                 if (temp.get()) {
151                     authninstant->getValues().push_back(temp.get());
152                     attributes.push_back(authninstant.release());
153                 }
154             }
155
156             // SessionIndex
157             if (!m_sessionIndex.empty() && saml2statement->getSessionIndex() && *(saml2statement->getSessionIndex())) {
158                 auto_ptr<SimpleAttribute> sessionindex(new SimpleAttribute(vector<string>(1, m_sessionIndex)));
159                 auto_ptr_char temp(saml2statement->getSessionIndex());
160                 if (temp.get()) {
161                     sessionindex->getValues().push_back(temp.get());
162                     attributes.push_back(sessionindex.release());
163                 }
164             }
165
166             // SessionNotOnOrAfter
167             if (!m_sessionNotOnOrAfter.empty() && saml2statement->getSessionNotOnOrAfter()) {
168                 auto_ptr<SimpleAttribute> sessionnotonorafter(new SimpleAttribute(vector<string>(1, m_sessionNotOnOrAfter)));
169                 auto_ptr_char temp(saml2statement->getSessionNotOnOrAfter()->getRawData());
170                 if (temp.get()) {
171                     sessionnotonorafter->getValues().push_back(temp.get());
172                     attributes.push_back(sessionnotonorafter.release());
173                 }
174             }
175
176             if (saml2statement->getSubjectLocality()) {
177                 const saml2::SubjectLocality* locality = saml2statement->getSubjectLocality();
178                 // Address
179                 if (!m_subjectAddress.empty() && locality->getAddress() && *(locality->getAddress())) {
180                     auto_ptr<SimpleAttribute> address(new SimpleAttribute(vector<string>(1, m_subjectAddress)));
181                     auto_ptr_char temp(locality->getAddress());
182                     if (temp.get()) {
183                         address->getValues().push_back(temp.get());
184                         attributes.push_back(address.release());
185                     }
186                 }
187
188                 // DNSName
189                 if (!m_subjectDNS.empty() && locality->getDNSName() && *(locality->getDNSName())) {
190                     auto_ptr<SimpleAttribute> dns(new SimpleAttribute(vector<string>(1, m_subjectDNS)));
191                     auto_ptr_char temp(locality->getDNSName());
192                     if (temp.get()) {
193                         dns->getValues().push_back(temp.get());
194                         attributes.push_back(dns.release());
195                     }
196                 }
197             }
198
199             if (saml2statement->getAuthnContext()) {
200                 const AuthnContext* ac = saml2statement->getAuthnContext();
201                 // AuthnContextClassRef
202                 if (!m_authnClass.empty() && ac->getAuthnContextClassRef() && ac->getAuthnContextClassRef()->getReference()) {
203                     auto_ptr<SimpleAttribute> classref(new SimpleAttribute(vector<string>(1, m_authnClass)));
204                     auto_ptr_char temp(ac->getAuthnContextClassRef()->getReference());
205                     if (temp.get()) {
206                         classref->getValues().push_back(temp.get());
207                         attributes.push_back(classref.release());
208                     }
209                 }
210
211                 // AuthnContextDeclRef
212                 if (!m_authnDecl.empty() && ac->getAuthnContextDeclRef() && ac->getAuthnContextDeclRef()->getReference()) {
213                     auto_ptr<SimpleAttribute> declref(new SimpleAttribute(vector<string>(1, m_authnDecl)));
214                     auto_ptr_char temp(ac->getAuthnContextDeclRef()->getReference());
215                     if (temp.get()) {
216                         declref->getValues().push_back(temp.get());
217                         attributes.push_back(declref.release());
218                     }
219                 }
220
221                 // AuthenticatingAuthority
222                 if (!m_authnAuthority.empty() && !ac->getAuthenticatingAuthoritys().empty()) {
223                     auto_ptr<SimpleAttribute> attr(new SimpleAttribute(vector<string>(1, m_authnAuthority)));
224                     const vector<AuthenticatingAuthority*>& authorities = ac->getAuthenticatingAuthoritys();
225                     for (vector<AuthenticatingAuthority*>::const_iterator a = authorities.begin(); a != authorities.end(); ++a) {
226                         auto_ptr_char temp((*a)->getID());
227                         if (temp.get())
228                             attr->getValues().push_back(temp.get());
229                     }
230                     if (attr->valueCount() > 0) {
231                         attributes.push_back(attr.release());
232                     }
233                 }
234             }
235         }
236         else {
237             const saml1::Assertion* saml1assertion = dynamic_cast<const saml1::Assertion*>(&xmlObject);
238             if (saml1assertion) {
239                 // Issuer
240                 if (!m_issuer.empty()) {
241                     if (saml1assertion->getIssuer() && *(saml1assertion->getIssuer())) {
242                         auto_ptr<SimpleAttribute> issuer(new SimpleAttribute(vector<string>(1, m_issuer)));
243                         auto_ptr_char temp(saml1assertion->getIssuer());
244                         if (temp.get()) {
245                             issuer->getValues().push_back(temp.get());
246                             attributes.push_back(issuer.release());
247                         }
248                     }
249                 }
250
251                 // NotOnOrAfter
252                 if (!m_notOnOrAfter.empty() && saml1assertion->getConditions() && saml1assertion->getConditions()->getNotOnOrAfter()) {
253                     auto_ptr<SimpleAttribute> notonorafter(new SimpleAttribute(vector<string>(1, m_notOnOrAfter)));
254                     auto_ptr_char temp(saml1assertion->getConditions()->getNotOnOrAfter()->getRawData());
255                     if (temp.get()) {
256                         notonorafter->getValues().push_back(temp.get());
257                         attributes.push_back(notonorafter.release());
258                     }
259                 }
260             }
261             else {
262                 const AuthenticationStatement* saml1statement = dynamic_cast<const AuthenticationStatement*>(&xmlObject);
263                 if (saml1statement) {
264                     // AuthnInstant
265                     if (!m_authnInstant.empty() && saml1statement->getAuthenticationInstant()) {
266                         auto_ptr<SimpleAttribute> authninstant(new SimpleAttribute(vector<string>(1, m_authnInstant)));
267                         auto_ptr_char temp(saml1statement->getAuthenticationInstant()->getRawData());
268                         if (temp.get()) {
269                             authninstant->getValues().push_back(temp.get());
270                             attributes.push_back(authninstant.release());
271                         }
272                     }
273
274                     // AuthenticationMethod
275                     if (!m_authnClass.empty() && saml1statement->getAuthenticationMethod() && *(saml1statement->getAuthenticationMethod())) {
276                         auto_ptr<SimpleAttribute> authnmethod(new SimpleAttribute(vector<string>(1, m_authnClass)));
277                         auto_ptr_char temp(saml1statement->getAuthenticationMethod());
278                         if (temp.get()) {
279                             authnmethod->getValues().push_back(temp.get());
280                             attributes.push_back(authnmethod.release());
281                         }
282                     }
283
284                     if (saml1statement->getSubjectLocality()) {
285                         const saml1::SubjectLocality* locality = saml1statement->getSubjectLocality();
286                         // IPAddress
287                         if (!m_subjectAddress.empty() && locality->getIPAddress() && *(locality->getIPAddress())) {
288                             auto_ptr<SimpleAttribute> address(new SimpleAttribute(vector<string>(1, m_subjectAddress)));
289                             auto_ptr_char temp(locality->getIPAddress());
290                             if (temp.get()) {
291                                 address->getValues().push_back(temp.get());
292                                 attributes.push_back(address.release());
293                             }
294                         }
295
296                         // DNSAddress
297                         if (!m_subjectDNS.empty() && locality->getDNSAddress() && *(locality->getDNSAddress())) {
298                             auto_ptr<SimpleAttribute> dns(new SimpleAttribute(vector<string>(1, m_subjectDNS)));
299                             auto_ptr_char temp(locality->getDNSAddress());
300                             if (temp.get()) {
301                                 dns->getValues().push_back(temp.get());
302                                 attributes.push_back(dns.release());
303                             }
304                         }
305                     }
306                 }
307             }
308         }
309     }
310
311     /*auto_ptr<SimpleAttribute> attr(new SimpleAttribute(vector<string>(1,m_attributeId)));
312
313         if (!(*s)->getAuthnContext() || (*s)->getAuthnContext()->getAuthenticatingAuthoritys().empty())
314             continue;
315
316         const vector<AuthenticatingAuthority*>& authorities =
317             const_cast<const AuthnContext*>((*s)->getAuthnContext())->getAuthenticatingAuthoritys();
318         for (vector<AuthenticatingAuthority*>::const_iterator a = authorities.begin(); a != authorities.end(); ++a) {
319             const XMLCh* n = (*a)->getID();
320             if (n && *n) {
321                 auto_ptr_char temp(n);
322                 attr->getValues().push_back(temp.get());
323             }
324         }
325
326         if (attr->valueCount() > 0) {
327             attributes.push_back(attr.release());
328             return;
329         }
330     }
331     */
332 }
333
334 void AssertionExtractor::getAttributeIds(vector<string>& attributes) const
335 {
336     if (!m_authnAuthority.empty())
337         attributes.push_back(m_authnAuthority);
338     if (!m_authnClass.empty())
339         attributes.push_back(m_authnClass);
340     if (!m_authnDecl.empty())
341         attributes.push_back(m_authnDecl);
342     if (!m_authnInstant.empty())
343         attributes.push_back(m_authnInstant);
344     if (!m_issuer.empty())
345         attributes.push_back(m_issuer);
346     if (!m_notOnOrAfter.empty())
347         attributes.push_back(m_notOnOrAfter);
348     if (!m_sessionIndex.empty())
349         attributes.push_back(m_sessionIndex);
350     if (!m_sessionNotOnOrAfter.empty())
351         attributes.push_back(m_sessionNotOnOrAfter);
352     if (!m_subjectAddress.empty())
353         attributes.push_back(m_subjectAddress);
354     if (!m_subjectDNS.empty())
355         attributes.push_back(m_subjectDNS);
356 }