CPPOST-96 - EntityMatcher implementation based on RPI registrationAuthority extension
[shibboleth/cpp-opensaml.git] / saml / saml2 / metadata / impl / RegistrationAuthorityEntityMatcher.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  * RegistrationAuthorityEntityMatcher.cpp
23  *
24  * EntityMatcher that matches based on RPI registrationAuthority.
25  */
26
27 #include "internal.h"
28 #include "saml2/metadata/EntityMatcher.h"
29 #include "saml2/metadata/Metadata.h"
30
31 #include <boost/lambda/casts.hpp>
32 #include <boost/lambda/lambda.hpp>
33 #include <xercesc/util/XMLUniDefs.hpp>
34 #include <xmltooling/logging.h>
35 #include <xmltooling/util/XMLHelper.h>
36
37 using namespace opensaml::saml2md;
38 using namespace opensaml::saml2;
39 using namespace opensaml;
40 using namespace xmltooling::logging;
41 using namespace xmltooling;
42 using namespace boost::lambda;
43 using namespace boost;
44 using namespace std;
45
46 namespace opensaml {
47     namespace saml2md {
48         class SAML_DLLLOCAL RegistrationAuthorityEntityMatcher : public EntityMatcher
49         {
50         public:
51             RegistrationAuthorityEntityMatcher(const DOMElement* e);
52             ~RegistrationAuthorityEntityMatcher() {}
53
54             bool matches(const EntityDescriptor& entity) const;
55
56         private:
57             set<xstring> m_authorities;
58             Category& m_log;
59         };
60
61         EntityMatcher* SAML_DLLLOCAL RegistrationAuthorityEntityMatcherFactory(const DOMElement* const & e)
62         {
63             return new RegistrationAuthorityEntityMatcher(e);
64         }
65     };
66 };
67
68
69 RegistrationAuthorityEntityMatcher::RegistrationAuthorityEntityMatcher(const DOMElement* e)
70     : m_log(Category::getInstance(SAML_LOGCAT ".EntityMatcher.RegistrationAuthority"))
71 {
72     // Check for shorthand syntax.
73     if (e && e->hasAttributeNS(nullptr, RegistrationInfo::REGAUTHORITY_ATTRIB_NAME)) {
74         m_authorities.insert(e->getAttributeNS(nullptr, RegistrationInfo::REGAUTHORITY_ATTRIB_NAME));
75     }
76
77     const DOMElement* child = XMLHelper::getFirstChildElement(e, RegistrationInfo::REGAUTHORITY_ATTRIB_NAME);
78     while (child) {
79         const XMLCh* text = child->getTextContent();
80         if (text && *text) {
81             m_authorities.insert(text);
82         }
83         child = XMLHelper::getNextSiblingElement(child, RegistrationInfo::REGAUTHORITY_ATTRIB_NAME);
84     }
85
86     if (m_authorities.empty())
87         throw XMLToolingException("RegistrationAuthority EntityMatcher requires at least one authority to match.");
88 }
89
90 bool RegistrationAuthorityEntityMatcher::matches(const EntityDescriptor& entity) const
91 {
92     bool extFound = false;
93
94     const Extensions* exts = entity.getExtensions();
95     if (exts) {
96         const vector<XMLObject*>& children = exts->getUnknownXMLObjects();
97         const XMLObject* xo = find_if(children, ll_dynamic_cast<RegistrationInfo*>(_1) != ((RegistrationInfo*)nullptr));
98         if (xo) {
99             extFound = true;
100             const RegistrationInfo* regInfo = dynamic_cast<const RegistrationInfo*>(xo);
101             if (regInfo->getRegistrationAuthority() && m_authorities.find(regInfo->getRegistrationAuthority()) != m_authorities.end()) {
102                 return true;
103             }
104         }
105     }
106
107     const EntitiesDescriptor* group = dynamic_cast<EntitiesDescriptor*>(entity.getParent());
108     while (group) {
109         exts = group->getExtensions();
110         if (exts) {
111             const vector<XMLObject*>& children = exts->getUnknownXMLObjects();
112             const XMLObject* xo = find_if(children, ll_dynamic_cast<RegistrationInfo*>(_1) != ((RegistrationInfo*)nullptr));
113             if (xo) {
114                 extFound = true;
115                 const RegistrationInfo* regInfo = dynamic_cast<const RegistrationInfo*>(xo);
116                 if (regInfo->getRegistrationAuthority() && m_authorities.find(regInfo->getRegistrationAuthority()) != m_authorities.end()) {
117                     return true;
118                 }
119             }
120         }
121         group = dynamic_cast<EntitiesDescriptor*>(group->getParent());
122     }
123
124     if (!extFound && m_log.isDebugEnabled()) {
125         auto_ptr_char id (entity.getEntityID());
126         m_log.debug("no RegistrationAuthority extension found for (%s)", id.get());
127     }
128
129     return false;
130 }