Convert logging to log4shib via compile time switch.
[shibboleth/opensaml2.git] / saml / saml2 / metadata / impl / SignatureMetadataFilter.cpp
1 /*
2  *  Copyright 2001-2007 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  * SignatureMetadataFilter.cpp
19  * 
20  * Filters out unsigned or mis-signed elements.
21  */
22
23 #include "internal.h"
24 #include "saml2/metadata/Metadata.h"
25 #include "saml2/metadata/MetadataFilter.h"
26 #include "signature/SignatureProfileValidator.h"
27
28 #include <xmltooling/logging.h>
29 #include <xmltooling/security/Credential.h>
30 #include <xmltooling/security/CredentialCriteria.h>
31 #include <xmltooling/security/CredentialResolver.h>
32 #include <xmltooling/signature/SignatureValidator.h>
33 #include <xmltooling/util/NDC.h>
34
35 using namespace opensaml::saml2md;
36 using namespace opensaml;
37 using namespace xmlsignature;
38 using namespace xmltooling::logging;
39 using namespace xmltooling;
40 using namespace std;
41
42 namespace opensaml {
43     namespace saml2md {
44                 
45         class SAML_DLLLOCAL SignatureMetadataFilter : public MetadataFilter
46         {
47         public:
48             SignatureMetadataFilter(const DOMElement* e);
49             ~SignatureMetadataFilter() {
50                 delete m_credResolver;
51             }
52             
53             const char* getId() const { return SIGNATURE_METADATA_FILTER; }
54             void doFilter(XMLObject& xmlObject) const;
55
56         private:
57             void doFilter(EntitiesDescriptor& entities, bool rootObject=false) const;
58             void verifySignature(Signature* sig) const {
59                 if (sig) {
60                     m_profileValidator.validate(sig);
61                     m_sigValidator.validate(sig);
62                 }
63             }
64             
65             CredentialResolver* m_credResolver;
66             SignatureProfileValidator m_profileValidator;
67             mutable SignatureValidator m_sigValidator;
68         }; 
69
70         MetadataFilter* SAML_DLLLOCAL SignatureMetadataFilterFactory(const DOMElement* const & e)
71         {
72             return new SignatureMetadataFilter(e);
73         }
74
75     };
76 };
77
78 static const XMLCh _CredentialResolver[] =  UNICODE_LITERAL_18(C,r,e,d,e,n,t,i,a,l,R,e,s,o,l,v,e,r);
79 static const XMLCh type[] =                 UNICODE_LITERAL_4(t,y,p,e);
80 static const XMLCh certificate[] =          UNICODE_LITERAL_11(c,e,r,t,i,f,i,c,a,t,e);
81 static const XMLCh Certificate[] =          UNICODE_LITERAL_11(C,e,r,t,i,f,i,c,a,t,e);
82 static const XMLCh Path[] =                 UNICODE_LITERAL_4(P,a,t,h);
83
84 SignatureMetadataFilter::SignatureMetadataFilter(const DOMElement* e) : m_credResolver(NULL)
85 {
86     if (e && e->hasAttributeNS(NULL,certificate)) {
87         // Dummy up a file resolver.
88         DOMElement* dummy = e->getOwnerDocument()->createElementNS(NULL,_CredentialResolver);
89         DOMElement* child = e->getOwnerDocument()->createElementNS(NULL,Certificate);
90         dummy->appendChild(child);
91         DOMElement* path = e->getOwnerDocument()->createElementNS(NULL,Path);
92         child->appendChild(path);
93         path->appendChild(e->getOwnerDocument()->createTextNode(e->getAttributeNS(NULL,certificate)));
94         m_credResolver = XMLToolingConfig::getConfig().CredentialResolverManager.newPlugin(FILESYSTEM_CREDENTIAL_RESOLVER,dummy);
95         return;
96     }
97
98     e = e ? XMLHelper::getFirstChildElement(e, _CredentialResolver) : NULL;
99     auto_ptr_char t(e ? e->getAttributeNS(NULL,type) : NULL);
100     if (t.get()) {
101         m_credResolver = XMLToolingConfig::getConfig().CredentialResolverManager.newPlugin(t.get(),e);
102     }
103     else
104         throw MetadataFilterException("Missing <CredentialResolver> element, or no type attribute found");
105 }
106
107 void SignatureMetadataFilter::doFilter(XMLObject& xmlObject) const
108 {
109 #ifdef _DEBUG
110     NDC ndc("doFilter");
111 #endif
112     
113     CredentialCriteria cc;
114     cc.setUsage(CredentialCriteria::SIGNING_CREDENTIAL);
115     Locker locker(m_credResolver);
116     m_sigValidator.setCredential(m_credResolver->resolve(&cc));
117
118     try {
119         EntitiesDescriptor& entities = dynamic_cast<EntitiesDescriptor&>(xmlObject);
120         doFilter(entities, true);
121         return;
122     }
123     catch (bad_cast) {
124     }
125
126     try {
127         EntityDescriptor& entity = dynamic_cast<EntityDescriptor&>(xmlObject);
128         if (!entity.getSignature())
129             throw MetadataFilterException("Root metadata element was unsigned.");
130         verifySignature(entity.getSignature());
131     }
132     catch (bad_cast) {
133     }
134      
135     throw MetadataFilterException("SignatureMetadataFilter was given an improper metadata instance to filter.");
136 }
137
138 void SignatureMetadataFilter::doFilter(EntitiesDescriptor& entities, bool rootObject) const
139 {
140     Category& log=Category::getInstance(SAML_LOGCAT".Metadata");
141     
142     Signature* sig = entities.getSignature();
143     if (!sig && rootObject)
144         throw MetadataFilterException("Root metadata element was unsigned.");
145     verifySignature(sig);
146     
147     VectorOf(EntityDescriptor) v=entities.getEntityDescriptors();
148     for (VectorOf(EntityDescriptor)::size_type i=0; i<v.size(); ) {
149         try {
150             verifySignature(v[i]->getSignature());
151             i++;
152         }
153         catch (XMLToolingException& e) {
154             auto_ptr_char id(v[i]->getEntityID());
155             log.info("filtering out entity (%s) after failed signature check: ", id.get(), e.what());
156             v.erase(v.begin() + i);
157         }
158     }
159     
160     VectorOf(EntitiesDescriptor) w=entities.getEntitiesDescriptors();
161     for (VectorOf(EntitiesDescriptor)::size_type j=0; j<w.size(); ) {
162         try {
163             verifySignature(w[j]->getSignature());
164             j++;
165         }
166         catch (XMLToolingException& e) {
167             auto_ptr_char name(w[j]->getName());
168             log.info("filtering out group (%s) after failed signature check: ", name.get(), e.what());
169             w.erase(w.begin() + j);
170         }
171     }
172 }