Change license header.
[shibboleth/cpp-sp.git] / shibsp / attribute / resolver / impl / DelegationAttributeExtractor.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  * DelegationAttributeExtractor.cpp
23  *
24  * AttributeExtractor for DelegationRestriction information.
25  */
26
27 #include "internal.h"
28 #include "Application.h"
29 #include "ServiceProvider.h"
30 #include "attribute/ExtensibleAttribute.h"
31 #include "attribute/resolver/AttributeExtractor.h"
32 #include "util/SPConstants.h"
33
34 #include <saml/saml2/core/Assertions.h>
35 #include <saml/saml2/metadata/Metadata.h>
36 #include <saml/saml2/metadata/MetadataCredentialCriteria.h>
37 #include <xmltooling/security/CredentialResolver.h>
38 #include <xmltooling/util/DateTime.h>
39 #include <xmltooling/util/XMLHelper.h>
40 #include <xercesc/util/XMLUniDefs.hpp>
41
42 using namespace shibsp;
43 using namespace opensaml::saml2md;
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 DelegationExtractor : public AttributeExtractor
56     {
57     public:
58         DelegationExtractor(const DOMElement* e);
59         ~DelegationExtractor() {}
60
61         Lockable* lock() {
62             return this;
63         }
64
65         void unlock() {
66         }
67
68         void extractAttributes(
69             const Application& application, const RoleDescriptor* issuer, const XMLObject& xmlObject, vector<Attribute*>& attributes
70             ) const;
71
72         void getAttributeIds(std::vector<std::string>& attributes) const {
73             attributes.push_back(m_attributeId);
74         }
75
76     private:
77         string m_attributeId,m_formatter;
78     };
79
80 #if defined (_MSC_VER)
81     #pragma warning( pop )
82 #endif
83
84     AttributeExtractor* SHIBSP_DLLLOCAL DelegationAttributeExtractorFactory(const DOMElement* const & e)
85     {
86         return new DelegationExtractor(e);
87     }
88
89     static const XMLCh attributeId[] =  UNICODE_LITERAL_11(a,t,t,r,i,b,u,t,e,I,d);
90     static const XMLCh formatter[] =    UNICODE_LITERAL_9(f,o,r,m,a,t,t,e,r);
91 };
92
93 DelegationExtractor::DelegationExtractor(const DOMElement* e)
94     : m_attributeId(XMLHelper::getAttrString(e, "delegate", attributeId)),
95         m_formatter(XMLHelper::getAttrString(e, "$Name", formatter))
96 {
97 }
98
99 void DelegationExtractor::extractAttributes(
100     const Application& application, const RoleDescriptor* issuer, const XMLObject& xmlObject, vector<Attribute*>& attributes
101     ) const
102 {
103     const saml2::Assertion* assertion = dynamic_cast<const saml2::Assertion*>(&xmlObject);
104     if (!assertion || !assertion->getConditions())
105         return;
106
107     Category& log = Category::getInstance(SHIBSP_LOGCAT".AttributeExtractor.Delegation");
108
109     const vector<saml2::Condition*>& conditions = const_cast<const saml2::Conditions*>(assertion->getConditions())->getConditions();
110     for (vector<saml2::Condition*>::const_iterator c = conditions.begin(); c != conditions.end(); ++c) {
111         const saml2::DelegationRestrictionType* drt = dynamic_cast<const saml2::DelegationRestrictionType*>(*c);
112         if (drt) {
113             auto_ptr<ExtensibleAttribute> attr(new ExtensibleAttribute(vector<string>(1,m_attributeId), m_formatter.c_str()));
114
115             const vector<saml2::Delegate*>& dels = drt->getDelegates();
116             for (vector<saml2::Delegate*>::const_iterator d = dels.begin(); d != dels.end(); ++d) {
117                 if ((*d)->getBaseID()) {
118                     log.error("delegate identified by saml:BaseID cannot be processed into an attribute value");
119                     continue;
120                 }
121
122                 saml2::NameID* n = nullptr;
123                 if ((*d)->getEncryptedID()) {
124                     CredentialResolver* cr = application.getCredentialResolver();
125                     if (!cr) {
126                         log.warn("found encrypted Delegate, but no CredentialResolver was available");
127                     }
128
129                     try {
130                         const XMLCh* recipient = application.getRelyingParty(
131                             issuer ? dynamic_cast<EntityDescriptor*>(issuer->getParent()) : nullptr
132                             )->getXMLString("entityID").second;
133                         Locker credlocker(cr);
134                         if (issuer) {
135                             MetadataCredentialCriteria mcc(*issuer);
136                             auto_ptr<XMLObject> decrypted((*d)->getEncryptedID()->decrypt(*cr, recipient, &mcc));
137                             n = dynamic_cast<saml2::NameID*>(decrypted.release());
138                         }
139                         else {
140                             auto_ptr<XMLObject> decrypted((*d)->getEncryptedID()->decrypt(*cr, recipient));
141                             n = dynamic_cast<saml2::NameID*>(decrypted.release());
142                         }
143                         if (n && log.isDebugEnabled())
144                             log.debugStream() << "decrypted Delegate: " << *n << logging::eol;
145                     }
146                     catch (exception& ex) {
147                         log.error("caught exception decrypting Delegate: %s", ex.what());
148                     }
149                 }
150                 else {
151                     n = (*d)->getNameID();
152                 }
153
154                 if (n) {
155                     DDF val = DDF(nullptr).structure();
156                     if ((*d)->getConfirmationMethod()) {
157                         auto_ptr_char temp((*d)->getConfirmationMethod());
158                         val.addmember("ConfirmationMethod").string(temp.get());
159                     }
160                     if ((*d)->getDelegationInstant()) {
161                         auto_ptr_char temp((*d)->getDelegationInstant()->getRawData());
162                         val.addmember("DelegationInstant").string(temp.get());
163                     }
164
165                     auto_arrayptr<char> name(toUTF8(n->getName()));
166                     if (name.get() && *name.get()) {
167                         val.addmember("Name").string(name.get());
168                         char* str = toUTF8(n->getFormat());
169                         if (str && *str)
170                             val.addmember("Format").string(str);
171                         delete[] str;
172
173                         str = toUTF8(n->getNameQualifier());
174                         if (str && *str)
175                             val.addmember("NameQualifier").string(str);
176                         delete[] str;
177
178                         str = toUTF8(n->getSPNameQualifier());
179                         if (str && *str)
180                             val.addmember("SPNameQualifier").string(str);
181                         delete[] str;
182
183                         str = toUTF8(n->getSPProvidedID());
184                         if (str && *str)
185                             val.addmember("SPProvidedID").string(str);
186                         delete[] str;
187                     }
188
189                     if (n != (*d)->getNameID())
190                         delete n;
191
192                     if (val.integer())
193                         attr->getValues().add(val);
194                     else
195                         val.destroy();
196                 }
197             }
198
199             attributes.push_back(attr.release());
200         }
201     }
202 }