f98f2a2e89da98dd3df3de5f5a7435bb9d744ab5
[shibboleth/sp.git] / shibsp / attribute / resolver / impl / DelegationAttributeExtractor.cpp
1 /*
2  *  Copyright 2009 Internet2
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * DelegationAttributeExtractor.cpp
19  *
20  * AttributeExtractor for DelegationRestriction information.
21  */
22
23 #include "internal.h"
24 #include "Application.h"
25 #include "ServiceProvider.h"
26 #include "attribute/ExtensibleAttribute.h"
27 #include "attribute/resolver/AttributeExtractor.h"
28 #include "util/SPConstants.h"
29
30 #include <saml/saml2/core/Assertions.h>
31 #include <saml/saml2/metadata/Metadata.h>
32 #include <saml/saml2/metadata/MetadataCredentialCriteria.h>
33 #include <xmltooling/security/CredentialResolver.h>
34 #include <xmltooling/util/DateTime.h>
35 #include <xmltooling/util/XMLHelper.h>
36 #include <xercesc/util/XMLUniDefs.hpp>
37
38 using namespace shibsp;
39 using namespace opensaml::saml2md;
40 using namespace opensaml;
41 using namespace xmltooling;
42 using namespace std;
43
44 namespace shibsp {
45
46 #if defined (_MSC_VER)
47     #pragma warning( push )
48     #pragma warning( disable : 4250 )
49 #endif
50
51     class DelegationExtractor : public AttributeExtractor
52     {
53     public:
54         DelegationExtractor(const DOMElement* e);
55         ~DelegationExtractor() {}
56
57         Lockable* lock() {
58             return this;
59         }
60
61         void unlock() {
62         }
63
64         void extractAttributes(
65             const Application& application, const RoleDescriptor* issuer, const XMLObject& xmlObject, vector<Attribute*>& attributes
66             ) const;
67
68         void getAttributeIds(std::vector<std::string>& attributes) const {
69             attributes.push_back(m_attributeId);
70         }
71
72     private:
73         string m_attributeId,m_formatter;
74     };
75
76 #if defined (_MSC_VER)
77     #pragma warning( pop )
78 #endif
79
80     AttributeExtractor* SHIBSP_DLLLOCAL DelegationAttributeExtractorFactory(const DOMElement* const & e)
81     {
82         return new DelegationExtractor(e);
83     }
84
85     static const XMLCh attributeId[] =  UNICODE_LITERAL_11(a,t,t,r,i,b,u,t,e,I,d);
86     static const XMLCh formatter[] =    UNICODE_LITERAL_9(f,o,r,m,a,t,t,e,r);
87 };
88
89 DelegationExtractor::DelegationExtractor(const DOMElement* e) : m_attributeId("delegate"), m_formatter("$Name")
90 {
91     if (e) {
92         const XMLCh* a = e->getAttributeNS(NULL, attributeId);
93         if (a && *a) {
94             auto_ptr_char temp(a);
95             m_attributeId = temp.get();
96         }
97         a = e->getAttributeNS(NULL, formatter);
98         if (a && *a) {
99             auto_ptr_char temp(a);
100             m_formatter = temp.get();
101         }
102     }
103 }
104
105 void DelegationExtractor::extractAttributes(
106     const Application& application, const RoleDescriptor* issuer, const XMLObject& xmlObject, vector<Attribute*>& attributes
107     ) const
108 {
109     const saml2::Assertion* assertion = dynamic_cast<const saml2::Assertion*>(&xmlObject);
110     if (!assertion || !assertion->getConditions())
111         return;
112
113     Category& log = Category::getInstance(SHIBSP_LOGCAT".AttributeExtractor.Delegation");
114
115     const vector<saml2::Condition*>& conditions = const_cast<const saml2::Conditions*>(assertion->getConditions())->getConditions();
116     for (vector<saml2::Condition*>::const_iterator c = conditions.begin(); c != conditions.end(); ++c) {
117         const saml2::DelegationRestrictionType* drt = dynamic_cast<const saml2::DelegationRestrictionType*>(*c);
118         if (drt) {
119             auto_ptr<ExtensibleAttribute> attr(new ExtensibleAttribute(vector<string>(1,m_attributeId), m_formatter.c_str()));
120
121             const vector<saml2::Delegate*>& dels = drt->getDelegates();
122             for (vector<saml2::Delegate*>::const_iterator d = dels.begin(); d != dels.end(); ++d) {
123                 if ((*d)->getBaseID()) {
124                     log.error("delegate identified by saml:BaseID cannot be processed into an attribute value");
125                     continue;
126                 }
127
128                 saml2::NameID* n = NULL;
129                 if ((*d)->getEncryptedID()) {
130                     CredentialResolver* cr = application.getCredentialResolver();
131                     if (!cr) {
132                         log.warn("found encrypted Delegate, but no CredentialResolver was available");
133                     }
134
135                     try {
136                         const XMLCh* recipient = application.getRelyingParty(
137                             issuer ? dynamic_cast<EntityDescriptor*>(issuer->getParent()) : NULL
138                             )->getXMLString("entityID").second;
139                         Locker credlocker(cr);
140                         if (issuer) {
141                             MetadataCredentialCriteria mcc(*issuer);
142                             auto_ptr<XMLObject> decrypted((*d)->getEncryptedID()->decrypt(*cr, recipient, &mcc));
143                             n = dynamic_cast<saml2::NameID*>(decrypted.release());
144                         }
145                         else {
146                             auto_ptr<XMLObject> decrypted((*d)->getEncryptedID()->decrypt(*cr, recipient));
147                             n = dynamic_cast<saml2::NameID*>(decrypted.release());
148                         }
149                         if (n && log.isDebugEnabled())
150                             log.debugStream() << "decrypted Delegate: " << *n << logging::eol;
151                     }
152                     catch (exception& ex) {
153                         log.error("caught exception decrypting Delegate: %s", ex.what());
154                     }
155                 }
156                 else {
157                     n = (*d)->getNameID();
158                 }
159
160                 if (n) {
161                     DDF val = DDF(NULL).structure();
162                     if ((*d)->getConfirmationMethod()) {
163                         auto_ptr_char temp((*d)->getConfirmationMethod());
164                         val.addmember("ConfirmationMethod").string(temp.get());
165                     }
166                     if ((*d)->getDelegationInstant()) {
167                         auto_ptr_char temp((*d)->getDelegationInstant()->getRawData());
168                         val.addmember("DelegationInstant").string(temp.get());
169                     }
170
171                     auto_arrayptr<char> name(toUTF8(n->getName()));
172                     if (name.get() && *name.get()) {
173                         val.addmember("Name").string(name.get());
174                         char* str = toUTF8(n->getFormat());
175                         if (str && *str)
176                             val.addmember("Format").string(str);
177                         delete[] str;
178
179                         str = toUTF8(n->getNameQualifier());
180                         if (str && *str)
181                             val.addmember("NameQualifier").string(str);
182                         delete[] str;
183
184                         str = toUTF8(n->getSPNameQualifier());
185                         if (str && *str)
186                             val.addmember("SPNameQualifier").string(str);
187                         delete[] str;
188
189                         str = toUTF8(n->getSPProvidedID());
190                         if (str && *str)
191                             val.addmember("SPProvidedID").string(str);
192                         delete[] str;
193                     }
194
195                     if (n != (*d)->getNameID())
196                         delete n;
197
198                     if (val.integer())
199                         attr->getValues().add(val);
200                     else
201                         val.destroy();
202                 }
203             }
204
205             attributes.push_back(attr.release());
206         }
207     }
208 }