Change license header, remove stale pkg files.
[shibboleth/cpp-opensaml.git] / saml / SAMLConfig.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  * SAMLConfig.cpp
23  * 
24  * Library configuration.
25  */
26
27 #include "internal.h"
28
29 #if defined(XMLTOOLING_LOG4SHIB)
30 # ifndef OPENSAML_LOG4SHIB
31 #  error "Logging library mismatch (XMLTooling is using log4shib)."
32 # endif
33 #elif defined(XMLTOOLING_LOG4CPP)
34 # ifndef OPENSAML_LOG4CPP
35 #  error "Logging library mismatch (XMLTooling is using log4cpp)."
36 # endif
37 #else
38 # error "No supported logging library."
39 #endif
40
41 #include "exceptions.h"
42 #include "SAMLConfig.h"
43 #include "binding/ArtifactMap.h"
44 #include "binding/MessageDecoder.h"
45 #include "binding/MessageEncoder.h"
46 #include "binding/SAMLArtifact.h"
47 #include "binding/SecurityPolicyRule.h"
48 #include "saml1/core/Assertions.h"
49 #include "saml1/core/Protocols.h"
50 #include "saml2/core/Protocols.h"
51 #include "saml2/metadata/Metadata.h"
52 #include "saml2/metadata/MetadataFilter.h"
53 #include "saml2/metadata/MetadataProvider.h"
54 #include "util/SAMLConstants.h"
55
56 #include <xmltooling/logging.h>
57 #include <xmltooling/XMLToolingConfig.h>
58 #include <xmltooling/security/SecurityHelper.h>
59 #include <xmltooling/signature/Signature.h>
60 #include <xmltooling/util/NDC.h>
61 #include <xmltooling/util/PathResolver.h>
62 #include <xmltooling/util/Threads.h>
63
64 #include <xsec/enc/XSECCryptoException.hpp>
65 #include <xsec/enc/XSECCryptoProvider.hpp>
66 #include <xsec/utils/XSECPlatformUtils.hpp>
67
68 using namespace opensaml;
69 using namespace xmlsignature;
70 using namespace xmltooling::logging;
71 using namespace xmltooling;
72 using namespace std;
73
74 // Expose entry points when used as an extension library
75
76 extern "C" int SAML_API xmltooling_extension_init(void*)
77 {
78     if (SAMLConfig::getConfig().init(false))
79         return 0;
80     return -1;
81 }
82
83 extern "C" void SAML_API xmltooling_extension_term()
84 {
85     SAMLConfig::getConfig().term(false);
86 }
87
88 DECL_XMLTOOLING_EXCEPTION_FACTORY(ArtifactException,opensaml);
89 DECL_XMLTOOLING_EXCEPTION_FACTORY(SecurityPolicyException,opensaml);
90 DECL_XMLTOOLING_EXCEPTION_FACTORY(MetadataException,opensaml::saml2md);
91 DECL_XMLTOOLING_EXCEPTION_FACTORY(MetadataFilterException,opensaml::saml2md);
92 DECL_XMLTOOLING_EXCEPTION_FACTORY(BindingException,opensaml);
93 DECL_XMLTOOLING_EXCEPTION_FACTORY(ProfileException,opensaml);
94 DECL_XMLTOOLING_EXCEPTION_FACTORY(FatalProfileException,opensaml);
95 DECL_XMLTOOLING_EXCEPTION_FACTORY(RetryableProfileException,opensaml);
96
97 namespace opensaml {
98    SAMLInternalConfig g_config;
99 }
100
101 SAMLConfig& SAMLConfig::getConfig()
102 {
103     return g_config;
104 }
105
106 SAMLInternalConfig& SAMLInternalConfig::getInternalConfig()
107 {
108     return g_config;
109 }
110
111 SAMLConfig::SAMLConfig() : m_artifactMap(nullptr)
112 {
113 }
114
115 SAMLConfig::~SAMLConfig()
116 {
117 }
118
119 ArtifactMap* SAMLConfig::getArtifactMap() const
120 {
121     return m_artifactMap;
122 }
123
124 void SAMLConfig::setArtifactMap(ArtifactMap* artifactMap)
125 {
126     delete m_artifactMap;
127     m_artifactMap = artifactMap;
128 }
129
130 SAMLInternalConfig::SAMLInternalConfig() : m_initCount(0), m_lock(Mutex::create())
131 {
132 }
133
134 SAMLInternalConfig::~SAMLInternalConfig()
135 {
136     delete m_lock;
137 }
138
139 bool SAMLInternalConfig::init(bool initXMLTooling)
140 {
141 #ifdef _DEBUG
142     xmltooling::NDC ndc("init");
143 #endif
144     Category& log=Category::getInstance(SAML_LOGCAT".Config");
145
146     Lock initLock(m_lock);
147
148     if (m_initCount == INT_MAX) {
149         log.crit("library initialized too many times");
150         return false;
151     }
152
153     if (m_initCount >= 1) {
154         ++m_initCount;
155         return true;
156     }
157
158     log.debug("library initialization started");
159
160     if (initXMLTooling && !XMLToolingConfig::getConfig().init()) {
161         return false;
162     }
163
164     XMLToolingConfig::getConfig().getPathResolver()->setDefaultPackageName("opensaml");
165
166     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(ArtifactException,opensaml);
167     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(SecurityPolicyException,opensaml);
168     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(MetadataException,opensaml::saml2md);
169     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(MetadataFilterException,opensaml::saml2md);
170     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(BindingException,opensaml);
171     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(ProfileException,opensaml);
172     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(FatalProfileException,opensaml);
173     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(RetryableProfileException,opensaml);
174
175     saml1::registerAssertionClasses();
176     saml1p::registerProtocolClasses();
177     saml2::registerAssertionClasses();
178     saml2p::registerProtocolClasses();
179     saml2md::registerMetadataClasses();
180     saml2md::registerMetadataProviders();
181     saml2md::registerMetadataFilters();
182     registerSAMLArtifacts();
183     registerMessageEncoders();
184     registerMessageDecoders();
185     registerSecurityPolicyRules();
186
187     log.info("%s library initialization complete", PACKAGE_STRING);
188     ++m_initCount;
189     return true;
190 }
191
192 void SAMLInternalConfig::term(bool termXMLTooling)
193 {
194 #ifdef _DEBUG
195     xmltooling::NDC ndc("term");
196 #endif
197
198     Lock initLock(m_lock);
199     if (m_initCount == 0) {
200         Category::getInstance(SAML_LOGCAT".Config").crit("term without corresponding init");
201         return;
202     }
203     else if (--m_initCount > 0) {
204         return;
205     }
206
207     MessageDecoderManager.deregisterFactories();
208     MessageEncoderManager.deregisterFactories();
209     SecurityPolicyRuleManager.deregisterFactories();
210     SAMLArtifactManager.deregisterFactories();
211     MetadataFilterManager.deregisterFactories();
212     MetadataProviderManager.deregisterFactories();
213
214     delete m_artifactMap;
215     m_artifactMap = nullptr;
216
217     if (termXMLTooling)
218         XMLToolingConfig::getConfig().term();
219     
220     Category::getInstance(SAML_LOGCAT".Config").info("%s library shutdown complete", PACKAGE_STRING);
221 }
222
223 void SAMLInternalConfig::generateRandomBytes(void* buf, unsigned int len)
224 {
225     try {
226         if (XSECPlatformUtils::g_cryptoProvider->getRandom(reinterpret_cast<unsigned char*>(buf),len)<len)
227             throw XMLSecurityException("Unable to generate random data; was PRNG seeded?");
228     }
229     catch (XSECCryptoException& e) {
230         throw XMLSecurityException("Unable to generate random data: $1",params(1,e.getMsg()));
231     }
232 }
233
234 void SAMLInternalConfig::generateRandomBytes(std::string& buf, unsigned int len)
235 {
236     buf.erase();
237     auto_ptr<unsigned char> hold(new unsigned char[len]);
238     generateRandomBytes(hold.get(),len);
239     for (unsigned int i=0; i<len; i++)
240         buf+=(hold.get())[i];
241 }
242
243 XMLCh* SAMLInternalConfig::generateIdentifier()
244 {
245     unsigned char key[17];
246     generateRandomBytes(key,16);
247     
248     char hexform[34];
249     sprintf(hexform,"_%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
250             key[0],key[1],key[2],key[3],key[4],key[5],key[6],key[7],
251             key[8],key[9],key[10],key[11],key[12],key[13],key[14],key[15]);
252     hexform[33]=0;
253     return XMLString::transcode(hexform);
254 }
255
256 string SAMLInternalConfig::hashSHA1(const char* s, bool toHex)
257 {
258     return SecurityHelper::doHash("SHA1", s, strlen(s), toHex);
259 }
260
261 SignableObject::SignableObject()
262 {
263 }
264
265 SignableObject::~SignableObject()
266 {
267 }
268
269 RootObject::RootObject()
270 {
271 }
272
273 RootObject::~RootObject()
274 {
275 }
276
277 Assertion::Assertion()
278 {
279 }
280
281 Assertion::~Assertion()
282 {
283 }
284
285 using namespace saml2p;
286 using namespace saml2md;
287
288 void opensaml::annotateException(XMLToolingException* e, const EntityDescriptor* entity, const Status* status, bool rethrow)
289 {
290     const RoleDescriptor* role = nullptr;
291     if (entity) {
292         const list<XMLObject*>& roles=entity->getOrderedChildren();
293         for (list<XMLObject*>::const_iterator child=roles.begin(); !role && child!=roles.end(); ++child) {
294             role=dynamic_cast<RoleDescriptor*>(*child);
295             if (role && !role->isValid())
296                 role = nullptr;
297         }
298     }
299     annotateException(e, role, status, rethrow);
300 }
301
302 void opensaml::annotateException(XMLToolingException* e, const RoleDescriptor* role, const Status* status, bool rethrow)
303 {
304     if (role) {
305         auto_ptr_char id(dynamic_cast<EntityDescriptor*>(role->getParent())->getEntityID());
306         e->addProperty("entityID",id.get());
307
308         const vector<ContactPerson*>& contacts=role->getContactPersons();
309         for (vector<ContactPerson*>::const_iterator c=contacts.begin(); c!=contacts.end(); ++c) {
310             const XMLCh* ctype=(*c)->getContactType();
311             if (ctype && (XMLString::equals(ctype,ContactPerson::CONTACT_SUPPORT)
312                     || XMLString::equals(ctype,ContactPerson::CONTACT_TECHNICAL))) {
313                 GivenName* fname=(*c)->getGivenName();
314                 SurName* lname=(*c)->getSurName();
315                 auto_ptr_char first(fname ? fname->getName() : nullptr);
316                 auto_ptr_char last(lname ? lname->getName() : nullptr);
317                 if (first.get() && last.get()) {
318                     string contact=string(first.get()) + ' ' + last.get();
319                     e->addProperty("contactName",contact.c_str());
320                 }
321                 else if (first.get())
322                     e->addProperty("contactName",first.get());
323                 else if (last.get())
324                     e->addProperty("contactName",last.get());
325                 const vector<EmailAddress*>& emails=const_cast<const ContactPerson*>(*c)->getEmailAddresss();
326                 if (!emails.empty()) {
327                     auto_ptr_char email(emails.front()->getAddress());
328                     if (email.get())
329                         e->addProperty("contactEmail",email.get());
330                 }
331                 break;
332             }
333         }
334
335         auto_ptr_char eurl(role->getErrorURL());
336         if (eurl.get()) {
337             e->addProperty("errorURL",eurl.get());
338         }
339     }
340     
341     if (status) {
342         auto_ptr_char sc(status->getStatusCode() ? status->getStatusCode()->getValue() : nullptr);
343         if (sc.get() && *sc.get())
344             e->addProperty("statusCode", sc.get());
345         if (status->getStatusCode()->getStatusCode()) {
346             auto_ptr_char sc2(status->getStatusCode()->getStatusCode()->getValue());
347             if (sc2.get() && *sc.get())
348                 e->addProperty("statusCode2", sc2.get());
349         }
350         if (status->getStatusMessage()) {
351             auto_ptr_char msg(status->getStatusMessage()->getMessage());
352             if (msg.get() && *msg.get())
353                 e->addProperty("statusMessage", msg.get());
354         }
355     }
356     
357     if (rethrow)
358         e->raise();
359 }