Migrate to xmlsec 1.3 release, shrink a few headers.
[shibboleth/cpp-opensaml.git] / saml / saml2 / metadata / impl / MetadataProvider.cpp
1 /*
2  *  Copyright 2001-2006 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  * MetadataProvider.cpp
19  * 
20  * Registration of factories for built-in providers
21  */
22
23 #include "internal.h"
24 #include "SAMLArtifact.h"
25 #include "saml2/metadata/Metadata.h"
26 #include "saml2/metadata/MetadataProvider.h"
27
28 #include <log4cpp/Category.hh>
29 #include <xercesc/util/XMLUniDefs.hpp>
30 #include <xmltooling/util/NDC.h>
31 #include <xmltooling/util/XMLHelper.h>
32
33 using namespace opensaml::saml2md;
34 using namespace opensaml;
35 using namespace xmltooling;
36 using namespace log4cpp;
37 using namespace std;
38
39 namespace opensaml {
40     namespace saml2md {
41         SAML_DLLLOCAL PluginManager<MetadataProvider,const DOMElement*>::Factory FilesystemMetadataProviderFactory; 
42         SAML_DLLLOCAL PluginManager<MetadataFilter,const DOMElement*>::Factory BlacklistMetadataFilterFactory; 
43         SAML_DLLLOCAL PluginManager<MetadataFilter,const DOMElement*>::Factory WhitelistMetadataFilterFactory; 
44         SAML_DLLLOCAL PluginManager<MetadataFilter,const DOMElement*>::Factory SignatureMetadataFilterFactory; 
45     };
46 };
47
48 void SAML_API opensaml::saml2md::registerMetadataProviders()
49 {
50     SAMLConfig& conf=SAMLConfig::getConfig();
51     conf.MetadataProviderManager.registerFactory(FILESYSTEM_METADATA_PROVIDER, FilesystemMetadataProviderFactory);
52     conf.MetadataProviderManager.registerFactory("edu.internet2.middleware.shibboleth.metadata.provider.XMLMetadata", FilesystemMetadataProviderFactory);
53     conf.MetadataProviderManager.registerFactory("edu.internet2.middleware.shibboleth.common.provider.XMLMetadata", FilesystemMetadataProviderFactory);
54 }
55
56 void SAML_API opensaml::saml2md::registerMetadataFilters()
57 {
58     SAMLConfig::getConfig().MetadataFilterManager.registerFactory(BLACKLIST_METADATA_FILTER, BlacklistMetadataFilterFactory);
59     SAMLConfig::getConfig().MetadataFilterManager.registerFactory(WHITELIST_METADATA_FILTER, WhitelistMetadataFilterFactory);
60     SAMLConfig::getConfig().MetadataFilterManager.registerFactory(SIGNATURE_METADATA_FILTER, SignatureMetadataFilterFactory);
61 }
62
63 static const XMLCh Blacklist[] =                    UNICODE_LITERAL_23(B,l,a,c,k,l,i,s,t,M,e,t,a,d,a,t,a,F,i,l,t,e,r);
64 static const XMLCh Whitelist[] =                    UNICODE_LITERAL_23(W,h,i,t,e,l,i,s,t,M,e,t,a,d,a,t,a,F,i,l,t,e,r);
65 static const XMLCh SigFilter[] =                    UNICODE_LITERAL_23(S,i,g,n,a,t,u,r,e,M,e,t,a,d,a,t,a,F,i,l,t,e,r);
66 static const XMLCh Exclude[] =                      UNICODE_LITERAL_7(E,x,c,l,u,d,e);
67 static const XMLCh Include[] =                      UNICODE_LITERAL_7(I,n,c,l,u,d,e);
68 static const XMLCh GenericKeyResolver[] =           UNICODE_LITERAL_11(K,e,y,R,e,s,o,l,v,e,r);
69 static const XMLCh GenericMetadataFilter[] =        UNICODE_LITERAL_14(M,e,t,a,d,a,t,a,F,i,l,t,e,r);
70 static const XMLCh type[] =                         UNICODE_LITERAL_4(t,y,p,e);
71
72 MetadataProvider::MetadataProvider(const DOMElement* e) : m_resolver(NULL)
73 {
74 #ifdef _DEBUG
75     NDC ndc("MetadataProvider");
76 #endif
77     SAMLConfig& conf=SAMLConfig::getConfig();
78     
79     // Locate any default recognized filters and plugins.
80     try {
81         DOMElement* child = e ? XMLHelper::getFirstChildElement(e) : NULL;
82         while (child) {
83             if (!m_resolver && XMLString::equals(child->getLocalName(),GenericKeyResolver)) {
84                 auto_ptr_char t(child->getAttributeNS(NULL,type));
85                 if (t.get())
86                     m_resolver = XMLToolingConfig::getConfig().KeyResolverManager.newPlugin(t.get(),child);
87                 else
88                     throw UnknownExtensionException("<KeyResolver> element found with no type attribute");
89             }
90             else if (XMLString::equals(child->getLocalName(),GenericMetadataFilter)) {
91                 auto_ptr_char t(child->getAttributeNS(NULL,type));
92                 if (t.get())
93                     m_filters.push_back(conf.MetadataFilterManager.newPlugin(t.get(),child));
94                 else
95                     throw UnknownExtensionException("<MetadataFilter> element found with no type attribute");
96             }
97             else if (XMLString::equals(child->getLocalName(),SigFilter)) {
98                 m_filters.push_back(conf.MetadataFilterManager.newPlugin(SIGNATURE_METADATA_FILTER,child));
99             }
100             else if (XMLString::equals(child->getLocalName(),Whitelist)) {
101                 m_filters.push_back(conf.MetadataFilterManager.newPlugin(WHITELIST_METADATA_FILTER,child));
102             }
103             else if (XMLString::equals(child->getLocalName(),Blacklist)) {
104                 m_filters.push_back(conf.MetadataFilterManager.newPlugin(BLACKLIST_METADATA_FILTER,child));
105             }
106             else if (XMLString::equals(child->getLocalName(),Include)) {
107                 m_filters.push_back(conf.MetadataFilterManager.newPlugin(WHITELIST_METADATA_FILTER,e));
108             }
109             else if (XMLString::equals(child->getLocalName(),Exclude)) {
110                 m_filters.push_back(conf.MetadataFilterManager.newPlugin(BLACKLIST_METADATA_FILTER,e));
111             }
112             child = XMLHelper::getNextSiblingElement(child);
113         }
114         
115         if (!m_resolver) {
116             m_resolver = XMLToolingConfig::getConfig().KeyResolverManager.newPlugin(INLINE_KEY_RESOLVER, child);
117         }
118     }
119     catch (XMLToolingException& ex) {
120         Category::getInstance(SAML_LOGCAT".Metadata").error("caught exception while installing plugins and filters: %s", ex.what());
121         delete m_resolver;
122         for_each(m_filters.begin(),m_filters.end(),xmltooling::cleanup<MetadataFilter>());
123         throw;
124     }
125 }
126
127 MetadataProvider::~MetadataProvider()
128 {
129     delete m_resolver;
130     for_each(m_filters.begin(),m_filters.end(),xmltooling::cleanup<MetadataFilter>());
131 }
132
133 void MetadataProvider::doFilters(XMLObject& xmlObject) const
134 {
135 #ifdef _DEBUG
136     NDC ndc("doFilters");
137 #endif
138     Category& log=Category::getInstance(SAML_LOGCAT".Metadata");
139     for (std::vector<MetadataFilter*>::const_iterator i=m_filters.begin(); i!=m_filters.end(); i++) {
140         log.info("applying metadata filter (%s)", (*i)->getId());
141         (*i)->doFilter(xmlObject);
142     }
143 }
144
145 void MetadataProvider::index(EntityDescriptor* site, time_t validUntil)
146 {
147     if (validUntil < site->getValidUntilEpoch())
148         site->setValidUntil(validUntil);
149
150     auto_ptr_char id(site->getEntityID());
151     if (id.get()) {
152         m_sites.insert(make_pair(id.get(),site));
153     }
154     
155     // Process each IdP role.
156     const vector<IDPSSODescriptor*>& roles=const_cast<const EntityDescriptor*>(site)->getIDPSSODescriptors();
157     for (vector<IDPSSODescriptor*>::const_iterator i=roles.begin(); i!=roles.end(); i++) {
158         // SAML 1.x?
159         if ((*i)->hasSupport(SAMLConstants::SAML10_PROTOCOL_ENUM) || (*i)->hasSupport(SAMLConstants::SAML11_PROTOCOL_ENUM)) {
160             // Check for SourceID extension element.
161             const Extensions* exts=(*i)->getExtensions();
162             if (exts) {
163                 const list<XMLObject*>& children=exts->getXMLObjects();
164                 for (list<XMLObject*>::const_iterator ext=children.begin(); ext!=children.end(); ext++) {
165                     SourceID* sid=dynamic_cast<SourceID*>(*ext);
166                     if (sid) {
167                         auto_ptr_char sourceid(sid->getID());
168                         if (sourceid.get()) {
169                             m_sources.insert(pair<string,const EntityDescriptor*>(sourceid.get(),site));
170                             break;
171                         }
172                     }
173                 }
174             }
175             
176             // Hash the ID.
177             m_sources.insert(
178                 pair<string,const EntityDescriptor*>(SAMLConfig::getConfig().hashSHA1(id.get(), true),site)
179                 );
180                 
181             // Load endpoints for type 0x0002 artifacts.
182             const vector<ArtifactResolutionService*>& locs=const_cast<const IDPSSODescriptor*>(*i)->getArtifactResolutionServices();
183             for (vector<ArtifactResolutionService*>::const_iterator loc=locs.begin(); loc!=locs.end(); loc++) {
184                 auto_ptr_char location((*loc)->getLocation());
185                 if (location.get())
186                     m_sources.insert(pair<string,const EntityDescriptor*>(location.get(),site));
187             }
188         }
189         
190         // SAML 2.0?
191         if ((*i)->hasSupport(SAMLConstants::SAML20P_NS)) {
192             // Hash the ID.
193             m_sources.insert(
194                 pair<string,const EntityDescriptor*>(SAMLConfig::getConfig().hashSHA1(id.get(), true),site)
195                 );
196         }
197     }
198 }
199
200 void MetadataProvider::index(EntitiesDescriptor* group, time_t validUntil)
201 {
202     if (validUntil < group->getValidUntilEpoch())
203         group->setValidUntil(validUntil);
204
205     auto_ptr_char name(group->getName());
206     if (name.get()) {
207         m_groups.insert(make_pair(name.get(),group));
208     }
209     
210     const vector<EntitiesDescriptor*>& groups=const_cast<const EntitiesDescriptor*>(group)->getEntitiesDescriptors();
211     for (vector<EntitiesDescriptor*>::const_iterator i=groups.begin(); i!=groups.end(); i++)
212         index(*i,group->getValidUntilEpoch());
213
214     const vector<EntityDescriptor*>& sites=const_cast<const EntitiesDescriptor*>(group)->getEntityDescriptors();
215     for (vector<EntityDescriptor*>::const_iterator j=sites.begin(); j!=sites.end(); j++)
216         index(*j,group->getValidUntilEpoch());
217 }
218
219 void MetadataProvider::clearDescriptorIndex()
220 {
221     m_sources.clear();
222     m_sites.clear();
223     m_groups.clear();
224 }
225
226 const EntitiesDescriptor* MetadataProvider::getEntitiesDescriptor(const char* name, bool strict) const
227 {
228     pair<groupmap_t::const_iterator,groupmap_t::const_iterator> range=m_groups.equal_range(name);
229
230     time_t now=time(NULL);
231     for (groupmap_t::const_iterator i=range.first; i!=range.second; i++)
232         if (now < i->second->getValidUntilEpoch())
233             return i->second;
234     
235     if (!strict && range.first!=range.second)
236         return range.first->second;
237         
238     return NULL;
239 }
240
241 const EntitiesDescriptor* MetadataProvider::getEntitiesDescriptor(const XMLCh* name, bool strict) const
242 {
243     auto_ptr_char temp(name);
244     return getEntitiesDescriptor(temp.get(),strict);
245 }
246
247 const EntityDescriptor* MetadataProvider::getEntityDescriptor(const char* name, bool strict) const
248 {
249     pair<sitemap_t::const_iterator,sitemap_t::const_iterator> range=m_sites.equal_range(name);
250
251     time_t now=time(NULL);
252     for (sitemap_t::const_iterator i=range.first; i!=range.second; i++)
253         if (now < i->second->getValidUntilEpoch())
254             return i->second;
255     
256     if (!strict && range.first!=range.second)
257         return range.first->second;
258         
259     return NULL;
260 }
261
262 const EntityDescriptor* MetadataProvider::getEntityDescriptor(const XMLCh* name, bool strict) const
263 {
264     auto_ptr_char temp(name);
265     return getEntityDescriptor(temp.get(),strict);
266 }
267
268 const EntityDescriptor* MetadataProvider::getEntityDescriptor(const SAMLArtifact* artifact) const
269 {
270     pair<sitemap_t::const_iterator,sitemap_t::const_iterator> range=m_sources.equal_range(artifact->getSource());
271
272     time_t now=time(NULL);
273     for (sitemap_t::const_iterator i=range.first; i!=range.second; i++)
274         if (now < i->second->getValidUntilEpoch())
275             return i->second;
276
277     return NULL;
278 }