b4a899e5ef991f4e80048e453e5f97258d7f9eb2
[shibboleth/sp.git] / shibsp / attribute / filtering / impl / AttributeValueRegexFunctor.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  * AttributeValueRegexFunctor.cpp
19  * 
20  * A match function that evaluates an attribute's value against the provided regular expression.
21  */
22
23 #include "internal.h"
24 #include "exceptions.h"
25 #include "attribute/Attribute.h"
26 #include "attribute/filtering/FilteringContext.h"
27 #include "attribute/filtering/FilterPolicyContext.h"
28
29 #include <xercesc/util/regx/RegularExpression.hpp>
30
31 using namespace shibsp;
32 using namespace std;
33
34 namespace shibsp {
35
36     static const XMLCh attributeID[] =  UNICODE_LITERAL_11(a,t,t,r,i,b,u,t,e,I,D);
37     static const XMLCh options[] =  UNICODE_LITERAL_7(o,p,t,i,o,n,s);
38     static const XMLCh regex[] =    UNICODE_LITERAL_5(r,e,g,e,x);
39
40     /**
41      * A match function that evaluates an attribute's value against the provided regular expression.
42      */
43     class SHIBSP_DLLLOCAL AttributeValueRegexFunctor : public MatchFunctor
44     {
45         xmltooling::auto_ptr_char m_attributeID;
46         RegularExpression* m_regex;
47
48         bool hasValue(const FilteringContext& filterContext) const;
49         bool matches(const Attribute& attribute, size_t index) const;
50
51     public:
52         AttributeValueRegexFunctor(const DOMElement* e)
53                 : m_attributeID(e ? e->getAttributeNS(NULL,attributeID) : NULL) {
54             const XMLCh* r = e ? e->getAttributeNS(NULL,regex) : NULL;
55             if (!r || !*r)
56                 throw ConfigurationException("AttributeValueRegex MatchFunctor requires non-empty regex attribute.");
57             try {
58                 m_regex = new RegularExpression(r, e->getAttributeNS(NULL,options));
59             }
60             catch (XMLException& ex) {\r
61                 xmltooling::auto_ptr_char temp(ex.getMessage());\r
62                 throw ConfigurationException(temp.get());\r
63             }\r
64         }
65
66         bool evaluatePolicyRequirement(const FilteringContext& filterContext) const {
67             if (!m_attributeID.get() || !*m_attributeID.get())
68                 throw AttributeFilteringException("No attributeID specified.");
69             return hasValue(filterContext);
70         }
71
72         bool evaluatePermitValue(const FilteringContext& filterContext, const Attribute& attribute, size_t index) const {
73             if (!XMLString::equals(m_attributeID.get(), attribute.getId()))
74                 return hasValue(filterContext);
75             return matches(attribute, index);
76         }
77     };
78
79     MatchFunctor* SHIBSP_DLLLOCAL AttributeValueRegexFactory(const std::pair<const FilterPolicyContext*,const DOMElement*>& p)
80     {
81         return new AttributeValueRegexFunctor(p.second);
82     }
83
84 };
85
86 bool AttributeValueRegexFunctor::hasValue(const FilteringContext& filterContext) const
87 {
88     size_t count;
89     pair<multimap<string,Attribute*>::const_iterator,multimap<string,Attribute*>::const_iterator> attrs =
90         filterContext.getAttributes().equal_range(m_attributeID.get());
91     for (; attrs.first != attrs.second; ++attrs.first) {
92         count = attrs.first->second->valueCount();
93         for (size_t index = 0; index < count; ++index) {
94             if (matches(*(attrs.first->second), index))
95                 return true;
96         }
97     }
98     return false;
99 }
100
101 bool AttributeValueRegexFunctor::matches(const Attribute& attribute, size_t index) const
102 {
103     const char* val = attribute.getString(index);
104     if (!val)
105         return false;
106     XMLCh* temp = xmltooling::fromUTF8(val);
107     bool ret = m_regex->matches(temp);
108     delete[] temp;
109     return ret;
110 }