d730b354c86fd84c236a1e922c94cda3875ea1d1
[shibboleth/sp.git] / shibsp / attribute / resolver / impl / KeyDescriptorAttributeExtractor.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  * KeyDescriptorAttributeExtractor.cpp
19  *
20  * AttributeExtractor for KeyDescriptor information.
21  */
22
23 #include "internal.h"
24 #include "Application.h"
25 #include "attribute/AttributeDecoder.h"
26 #include "attribute/SimpleAttribute.h"
27 #include "attribute/resolver/AttributeExtractor.h"
28
29 #include <saml/saml2/metadata/Metadata.h>
30 #include <saml/saml2/metadata/MetadataCredentialCriteria.h>
31 #include <xmltooling/security/SecurityHelper.h>
32 #include <xmltooling/util/XMLHelper.h>
33 #include <xercesc/util/XMLUniDefs.hpp>
34
35 using namespace shibsp;
36 using namespace opensaml::saml2md;
37 using namespace opensaml;
38 using namespace xmltooling;
39 using namespace std;
40
41 namespace shibsp {
42
43 #if defined (_MSC_VER)
44     #pragma warning( push )
45     #pragma warning( disable : 4250 )
46 #endif
47
48     class KeyDescriptorExtractor : public AttributeExtractor
49     {
50     public:
51         KeyDescriptorExtractor(const DOMElement* e);
52         ~KeyDescriptorExtractor() {}
53
54         Lockable* lock() {
55             return this;
56         }
57
58         void unlock() {
59         }
60
61         void extractAttributes(
62             const Application& application, const RoleDescriptor* issuer, const XMLObject& xmlObject, vector<Attribute*>& attributes
63             ) const;
64
65         void getAttributeIds(std::vector<std::string>& attributes) const {
66             if (!m_hashId.empty())
67                 attributes.push_back(m_hashId.front());
68             if (!m_signingId.empty())
69                 attributes.push_back(m_signingId.front());
70             if (!m_encryptionId.empty())
71                 attributes.push_back(m_encryptionId.front());
72         }
73
74     private:
75         vector<string> m_hashId;
76         vector<string> m_signingId;
77         vector<string> m_encryptionId;
78     };
79
80 #if defined (_MSC_VER)
81     #pragma warning( pop )
82 #endif
83
84     AttributeExtractor* SHIBSP_DLLLOCAL KeyDescriptorAttributeExtractorFactory(const DOMElement* const & e)
85     {
86         return new KeyDescriptorExtractor(e);
87     }
88
89     static const XMLCh encryptionId[] = UNICODE_LITERAL_12(e,n,c,r,y,p,t,i,o,n,I,d);
90     static const XMLCh hashId[] =       UNICODE_LITERAL_6(h,a,s,h,I,d);
91     static const XMLCh signingId[] =    UNICODE_LITERAL_9(s,i,g,n,i,n,g,I,d);
92 };
93
94 KeyDescriptorExtractor::KeyDescriptorExtractor(const DOMElement* e)
95 {
96     if (e) {
97         const XMLCh* a = e->getAttributeNS(NULL, hashId);
98         if (a && *a) {
99             auto_ptr_char temp(a);
100             m_hashId.push_back(temp.get());
101         }
102         a = e->getAttributeNS(NULL, signingId);
103         if (a && *a) {
104             auto_ptr_char temp(a);
105             m_signingId.push_back(temp.get());
106         }
107         a = e->getAttributeNS(NULL, encryptionId);
108         if (a && *a) {
109             auto_ptr_char temp(a);
110             m_encryptionId.push_back(temp.get());
111         }
112     }
113     if (m_hashId.empty() && m_signingId.empty() && m_encryptionId.empty())
114         throw ConfigurationException("KeyDescriptor AttributeExtractor requires hashId, signingId, or encryptionId property.");
115 }
116
117 void KeyDescriptorExtractor::extractAttributes(
118     const Application& application, const RoleDescriptor* issuer, const XMLObject& xmlObject, vector<Attribute*>& attributes
119     ) const
120 {
121     const RoleDescriptor* role = dynamic_cast<const RoleDescriptor*>(&xmlObject);
122     if (!role)
123         return;
124
125     vector<const Credential*> creds;
126     MetadataCredentialCriteria mcc(*role);
127
128     if (!m_signingId.empty() || !m_hashId.empty()) {
129         mcc.setUsage(Credential::SIGNING_CREDENTIAL);
130         if (application.getMetadataProvider()->resolve(creds, &mcc)) {
131             if (!m_hashId.empty()) {
132                 auto_ptr<SimpleAttribute> attr(new SimpleAttribute(m_hashId));
133                 vector<string>& vals = attr->getValues();
134                 for (vector<const Credential*>::const_iterator c = creds.begin(); c != creds.end(); ++c) {
135                     if (vals.empty() || !vals.back().empty())
136                         vals.push_back(string());
137                     vals.back() = SecurityHelper::getDEREncoding(*(*c), true);
138                 }
139                 if (vals.back().empty())
140                     vals.pop_back();
141                 if (!vals.empty())
142                     attributes.push_back(attr.release());
143             }
144             if (!m_signingId.empty()) {
145                 auto_ptr<SimpleAttribute> attr(new SimpleAttribute(m_signingId));
146                 vector<string>& vals = attr->getValues();
147                 for (vector<const Credential*>::const_iterator c = creds.begin(); c != creds.end(); ++c) {
148                     if (vals.empty() || !vals.back().empty())
149                         vals.push_back(string());
150                     vals.back() = SecurityHelper::getDEREncoding(*(*c));
151                 }
152                 if (vals.back().empty())
153                     vals.pop_back();
154                 if (!vals.empty())
155                     attributes.push_back(attr.release());
156             }
157             creds.clear();
158         }
159     }
160
161     if (!m_encryptionId.empty()) {
162         mcc.setUsage(Credential::ENCRYPTION_CREDENTIAL);
163         if (application.getMetadataProvider()->resolve(creds, &mcc)) {
164             auto_ptr<SimpleAttribute> attr(new SimpleAttribute(m_encryptionId));
165             vector<string>& vals = attr->getValues();
166             for (vector<const Credential*>::const_iterator c = creds.begin(); c != creds.end(); ++c) {
167                 if (vals.empty() || !vals.back().empty())
168                     vals.push_back(string());
169                 vals.back() = SecurityHelper::getDEREncoding(*(*c));
170             }
171             if (vals.back().empty())
172                 vals.pop_back();
173             if (!vals.empty())
174                 attributes.push_back(attr.release());
175         }
176     }
177 }