Add licenses, remove dependency on OpenSSL.
[shibboleth/cpp-opensaml.git] / saml / SAMLConfig.cpp
1
2 /*
3  *  Copyright 2001-2007 Internet2
4  * 
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 /**
19  * SAMLConfig.cpp
20  * 
21  * Library configuration 
22  */
23
24 #include "internal.h"
25 #include "exceptions.h"
26 #include "SAMLConfig.h"
27 #include "binding/ArtifactMap.h"
28 #include "binding/MessageDecoder.h"
29 #include "binding/MessageEncoder.h"
30 #include "binding/SAMLArtifact.h"
31 #include "binding/SecurityPolicyRule.h"
32 #include "saml1/core/Assertions.h"
33 #include "saml1/core/Protocols.h"
34 #include "saml2/core/Protocols.h"
35 #include "saml2/metadata/Metadata.h"
36 #include "saml2/metadata/MetadataFilter.h"
37 #include "saml2/metadata/MetadataProvider.h"
38 #include "util/SAMLConstants.h"
39
40 #include <xmltooling/XMLToolingConfig.h>
41 #include <xmltooling/signature/Signature.h>
42 #include <xmltooling/util/NDC.h>
43
44 #include <log4cpp/Category.hh>
45 #include <xsec/enc/XSECCryptoException.hpp>
46 #include <xsec/enc/XSECCryptoProvider.hpp>
47 #include <xsec/utils/XSECPlatformUtils.hpp>
48
49 using namespace opensaml;
50 using namespace xmlsignature;
51 using namespace xmltooling;
52 using namespace log4cpp;
53 using namespace std;
54
55 // Expose entry points when used as an extension library
56
57 extern "C" int SAML_API xmltooling_extension_init(void*)
58 {
59     if (SAMLConfig::getConfig().init(false))
60         return 0;
61     return -1;
62 }
63
64 extern "C" void SAML_API xmltooling_extension_term()
65 {
66     SAMLConfig::getConfig().term(false);
67 }
68
69 DECL_XMLTOOLING_EXCEPTION_FACTORY(ArtifactException,opensaml);
70 DECL_XMLTOOLING_EXCEPTION_FACTORY(MetadataException,opensaml::saml2md);
71 DECL_XMLTOOLING_EXCEPTION_FACTORY(MetadataFilterException,opensaml::saml2md);
72 DECL_XMLTOOLING_EXCEPTION_FACTORY(BindingException,opensaml);
73 DECL_XMLTOOLING_EXCEPTION_FACTORY(ProfileException,opensaml);
74 DECL_XMLTOOLING_EXCEPTION_FACTORY(FatalProfileException,opensaml);
75 DECL_XMLTOOLING_EXCEPTION_FACTORY(RetryableProfileException,opensaml);
76
77 namespace opensaml {
78    SAMLInternalConfig g_config;
79 }
80
81 SAMLConfig& SAMLConfig::getConfig()
82 {
83     return g_config;
84 }
85
86 SAMLInternalConfig& SAMLInternalConfig::getInternalConfig()
87 {
88     return g_config;
89 }
90
91 void SAMLConfig::setArtifactMap(ArtifactMap* artifactMap)
92 {
93     delete m_artifactMap;
94     m_artifactMap = artifactMap;
95 }
96
97 bool SAMLInternalConfig::init(bool initXMLTooling)
98 {
99 #ifdef _DEBUG
100     xmltooling::NDC ndc("init");
101 #endif
102     Category& log=Category::getInstance(SAML_LOGCAT".SAMLConfig");
103     log.debug("library initialization started");
104
105     if (initXMLTooling) {
106         XMLToolingConfig::getConfig().init();
107         log.debug("XMLTooling library initialized");
108     }
109
110     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(ArtifactException,opensaml);
111     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(MetadataException,opensaml::saml2md);
112     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(MetadataFilterException,opensaml::saml2md);
113     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(BindingException,opensaml);
114     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(ProfileException,opensaml);
115     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(FatalProfileException,opensaml);
116     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(RetryableProfileException,opensaml);
117
118     saml1::registerAssertionClasses();
119     saml1p::registerProtocolClasses();
120     saml2::registerAssertionClasses();
121     saml2p::registerProtocolClasses();
122     saml2md::registerMetadataClasses();
123     saml2md::registerMetadataProviders();
124     saml2md::registerMetadataFilters();
125     registerSAMLArtifacts();
126     registerMessageEncoders();
127     registerMessageDecoders();
128     registerSecurityPolicyRules();
129
130     log.info("library initialization complete");
131     return true;
132 }
133
134 void SAMLInternalConfig::term(bool termXMLTooling)
135 {
136 #ifdef _DEBUG
137     xmltooling::NDC ndc("term");
138 #endif
139     Category& log=Category::getInstance(SAML_LOGCAT".SAMLConfig");
140
141     MessageDecoderManager.deregisterFactories();
142     MessageEncoderManager.deregisterFactories();
143     SecurityPolicyRuleManager.deregisterFactories();
144     SAMLArtifactManager.deregisterFactories();
145     MetadataFilterManager.deregisterFactories();
146     MetadataProviderManager.deregisterFactories();
147
148     delete m_artifactMap;
149     m_artifactMap = NULL;
150
151     if (termXMLTooling) {
152         XMLToolingConfig::getConfig().term();
153         log.debug("XMLTooling library shut down");
154     }
155     log.info("library shutdown complete");
156 }
157
158 void SAMLInternalConfig::generateRandomBytes(void* buf, unsigned int len)
159 {
160     try {
161         if (XSECPlatformUtils::g_cryptoProvider->getRandom(reinterpret_cast<unsigned char*>(buf),len)<len)
162             throw XMLSecurityException("Unable to generate random data; was PRNG seeded?");
163     }
164     catch (XSECCryptoException& e) {
165         throw XMLSecurityException("Unable to generate random data: $1",params(1,e.getMsg()));
166     }
167 }
168
169 void SAMLInternalConfig::generateRandomBytes(std::string& buf, unsigned int len)
170 {
171     buf.erase();
172     auto_ptr<unsigned char> hold(new unsigned char[len]);
173     generateRandomBytes(hold.get(),len);
174     for (unsigned int i=0; i<len; i++)
175         buf+=(hold.get())[i];
176 }
177
178 XMLCh* SAMLInternalConfig::generateIdentifier()
179 {
180     unsigned char key[17];
181     generateRandomBytes(key,16);
182     
183     char hexform[34];
184     sprintf(hexform,"_%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
185             key[0],key[1],key[2],key[3],key[4],key[5],key[6],key[7],
186             key[8],key[9],key[10],key[11],key[12],key[13],key[14],key[15]);
187     hexform[33]=0;
188     return XMLString::transcode(hexform);
189 }
190
191 string SAMLInternalConfig::hashSHA1(const char* s, bool toHex)
192 {
193     static char DIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
194
195     auto_ptr<XSECCryptoHash> hasher(XSECPlatformUtils::g_cryptoProvider->hashSHA1());
196     if (hasher.get()) {
197         unsigned char buf[21];
198         hasher->hash(reinterpret_cast<unsigned char*>(const_cast<char*>(s)),strlen(s));
199         if (hasher->finish(buf,20)==20) {
200             string ret;
201             if (toHex) {
202                 for (unsigned int i=0; i<20; i++) {
203                     ret+=(DIGITS[((unsigned char)(0xF0 & buf[i])) >> 4 ]);
204                     ret+=(DIGITS[0x0F & buf[i]]);
205                 }
206             }
207             else {
208                 for (unsigned int i=0; i<20; i++) {
209                     ret+=buf[i];
210                 }
211             }
212             return ret;
213         }
214     }
215     throw XMLSecurityException("Unable to generate SHA-1 hash.");
216 }
217
218 using namespace saml2md;
219
220 void opensaml::annotateException(XMLToolingException* e, const EntityDescriptor* entity, bool rethrow)
221 {
222     if (entity) {
223         auto_ptr_char id(entity->getEntityID());
224         e->addProperty("entityID",id.get());
225         const list<XMLObject*>& roles=entity->getOrderedChildren();
226         for (list<XMLObject*>::const_iterator child=roles.begin(); child!=roles.end(); ++child) {
227             const RoleDescriptor* role=dynamic_cast<RoleDescriptor*>(*child);
228             if (role && role->isValid()) {
229                 const vector<ContactPerson*>& contacts=role->getContactPersons();
230                 for (vector<ContactPerson*>::const_iterator c=contacts.begin(); c!=contacts.end(); ++c) {
231                     const XMLCh* ctype=(*c)->getContactType();
232                     if (ctype && (XMLString::equals(ctype,ContactPerson::CONTACT_SUPPORT)
233                             || XMLString::equals(ctype,ContactPerson::CONTACT_TECHNICAL))) {
234                         GivenName* fname=(*c)->getGivenName();
235                         SurName* lname=(*c)->getSurName();
236                         auto_ptr_char first(fname ? fname->getName() : NULL);
237                         auto_ptr_char last(lname ? lname->getName() : NULL);
238                         if (first.get() && last.get()) {
239                             string contact=string(first.get()) + ' ' + last.get();
240                             e->addProperty("contactName",contact.c_str());
241                         }
242                         else if (first.get())
243                             e->addProperty("contactName",first.get());
244                         else if (last.get())
245                             e->addProperty("contactName",last.get());
246                         const vector<EmailAddress*>& emails=const_cast<const ContactPerson*>(*c)->getEmailAddresss();
247                         if (!emails.empty()) {
248                             auto_ptr_char email(emails.front()->getAddress());
249                             if (email.get())
250                                 e->addProperty("contactEmail",email.get());
251                         }
252                         break;
253                     }
254                 }
255                 if (e->getProperty("contactName") || e->getProperty("contactEmail")) {
256                     auto_ptr_char eurl(role->getErrorURL());
257                     if (eurl.get()) {
258                         e->addProperty("errorURL",eurl.get());
259                     }
260                 }
261                 break;
262             }
263         }
264     }
265     
266     if (rethrow)
267         e->raise();
268 }
269
270 void opensaml::annotateException(XMLToolingException* e, const RoleDescriptor* role, bool rethrow)
271 {
272     if (role) {
273         auto_ptr_char id(dynamic_cast<EntityDescriptor*>(role->getParent())->getEntityID());
274         e->addProperty("entityID",id.get());
275
276         const vector<ContactPerson*>& contacts=role->getContactPersons();
277         for (vector<ContactPerson*>::const_iterator c=contacts.begin(); c!=contacts.end(); ++c) {
278             const XMLCh* ctype=(*c)->getContactType();
279             if (ctype && (XMLString::equals(ctype,ContactPerson::CONTACT_SUPPORT)
280                     || XMLString::equals(ctype,ContactPerson::CONTACT_TECHNICAL))) {
281                 GivenName* fname=(*c)->getGivenName();
282                 SurName* lname=(*c)->getSurName();
283                 auto_ptr_char first(fname ? fname->getName() : NULL);
284                 auto_ptr_char last(lname ? lname->getName() : NULL);
285                 if (first.get() && last.get()) {
286                     string contact=string(first.get()) + ' ' + last.get();
287                     e->addProperty("contactName",contact.c_str());
288                 }
289                 else if (first.get())
290                     e->addProperty("contactName",first.get());
291                 else if (last.get())
292                     e->addProperty("contactName",last.get());
293                 const vector<EmailAddress*>& emails=const_cast<const ContactPerson*>(*c)->getEmailAddresss();
294                 if (!emails.empty()) {
295                     auto_ptr_char email(emails.front()->getAddress());
296                     if (email.get())
297                         e->addProperty("contactEmail",email.get());
298                 }
299                 break;
300             }
301         }
302
303         auto_ptr_char eurl(role->getErrorURL());
304         if (eurl.get()) {
305             e->addProperty("errorURL",eurl.get());
306         }
307     }
308     
309     if (rethrow)
310         e->raise();
311 }