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