Let complex values pass AnyValue rules.
[shibboleth/sp.git] / shib / AAP.cpp
1 /*
2  * The Shibboleth License, Version 1.
3  * Copyright (c) 2002
4  * University Corporation for Advanced Internet Development, Inc.
5  * All rights reserved
6  *
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * Redistributions of source code must retain the above copyright notice, this
12  * list of conditions and the following disclaimer.
13  *
14  * Redistributions in binary form must reproduce the above copyright notice,
15  * this list of conditions and the following disclaimer in the documentation
16  * and/or other materials provided with the distribution, if any, must include
17  * the following acknowledgment: "This product includes software developed by
18  * the University Corporation for Advanced Internet Development
19  * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement
20  * may appear in the software itself, if and wherever such third-party
21  * acknowledgments normally appear.
22  *
23  * Neither the name of Shibboleth nor the names of its contributors, nor
24  * Internet2, nor the University Corporation for Advanced Internet Development,
25  * Inc., nor UCAID may be used to endorse or promote products derived from this
26  * software without specific prior written permission. For written permission,
27  * please contact shibboleth@shibboleth.org
28  *
29  * Products derived from this software may not be called Shibboleth, Internet2,
30  * UCAID, or the University Corporation for Advanced Internet Development, nor
31  * may Shibboleth appear in their name, without prior written permission of the
32  * University Corporation for Advanced Internet Development.
33  *
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
36  * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
38  * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK
39  * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE.
40  * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY
41  * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT,
42  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
43  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
44  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
47  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48  */
49
50
51 /* AAP.cpp - XML AAP implementation
52
53    Scott Cantor
54    12/21/02
55
56    $History:$
57 */
58
59 #include "internal.h"
60
61 #include <log4cpp/Category.hh>
62
63 using namespace shibboleth;
64 using namespace saml;
65 using namespace log4cpp;
66 using namespace std;
67
68 #include <xercesc/framework/URLInputSource.hpp>
69 #include <xercesc/util/regx/RegularExpression.hpp>
70
71 class shibboleth::XMLAAPImpl
72 {
73 public:
74     XMLAAPImpl(const char* pathname);
75     ~XMLAAPImpl();
76     
77     void regAttributes() const;
78
79     class AttributeRule : public IAttributeRule
80     {
81     public:
82         AttributeRule(const DOMElement* e);
83         ~AttributeRule() {}
84         
85         const XMLCh* getName() const { return m_name; }
86         const XMLCh* getNamespace() const { return m_namespace; }
87         const char* getFactory() const { return m_factory.get(); }
88         const char* getAlias() const { return m_alias.get(); }
89         const char* getHeader() const { return m_header.get(); }
90         bool accept(const XMLCh* originSite, const DOMElement* e) const;
91
92         enum value_type { literal, regexp, xpath };
93     private:    
94         const XMLCh* m_name;
95         const XMLCh* m_namespace;
96         auto_ptr<char> m_factory;
97         auto_ptr<char> m_alias;
98         auto_ptr<char> m_header;
99         
100         value_type toValueType(const DOMElement* e);
101         bool scopeCheck(const XMLCh* originSite, const DOMElement* e) const;
102         
103         struct SiteRule
104         {
105             SiteRule() : anyValue(false) {}
106             bool anyValue;
107             vector<pair<value_type,const XMLCh*> > valueRules;
108             vector<pair<value_type,const XMLCh*> > scopeDenials;
109             vector<pair<value_type,const XMLCh*> > scopeAccepts;
110         };
111
112         SiteRule m_anySiteRule;
113         map<xstring,SiteRule> m_siteMap;
114     };
115
116     vector<const IAttributeRule*> m_attrs;
117     map<string,const IAttributeRule*> m_aliasMap;
118     map<xstring,AttributeRule*> m_attrMap;
119     DOMDocument* m_doc;
120 };
121
122 XMLAAPImpl::XMLAAPImpl(const char* pathname) : m_doc(NULL)
123 {
124     NDC ndc("XMLAAPImpl");
125     Category& log=Category::getInstance(SHIB_LOGCAT".XMLAAPImpl");
126
127     saml::XML::Parser p;
128     try
129     {
130         static XMLCh base[]={chLatin_f, chLatin_i, chLatin_l, chLatin_e, chColon, chForwardSlash, chForwardSlash, chForwardSlash, chNull};
131         URLInputSource src(base,pathname);
132         Wrapper4InputSource dsrc(&src,false);
133         m_doc=p.parse(dsrc);
134
135         log.infoStream() << "Loaded and parsed AAP file (" << pathname << ")" << CategoryStream::ENDLINE;
136
137         DOMElement* e = m_doc->getDocumentElement();
138         if (XMLString::compareString(XML::SHIB_NS,e->getNamespaceURI()) ||
139             XMLString::compareString(SHIB_L(AttributeAcceptancePolicy),e->getLocalName()))
140         {
141             log.error("Construction requires a valid AAP file: (shib:AttributeAcceptancePolicy as root element)");
142             throw MalformedException("Construction requires a valid AAP file: (shib:AttributeAcceptancePolicy as root element)");
143         }
144
145         // Loop over the AttributeRule elements.
146         DOMNodeList* nlist = e->getElementsByTagNameNS(XML::SHIB_NS,SHIB_L(AttributeRule));
147         for (int i=0; nlist && i<nlist->getLength(); i++)
148         {
149             AttributeRule* rule=new AttributeRule(static_cast<DOMElement*>(nlist->item(i)));
150             m_attrMap[xstring(rule->getName()) + chBang + chBang + (rule->getNamespace() ? rule->getNamespace() : Constants::SHIB_ATTRIBUTE_NAMESPACE_URI)]=rule;
151             m_attrs.push_back(rule);
152             if (rule->getAlias())
153                 m_aliasMap[rule->getAlias()]=rule;
154         }
155     }
156     catch (SAMLException& e)
157     {
158         log.errorStream() << "XML error while parsing AAP: " << e.what() << CategoryStream::ENDLINE;
159         for (map<xstring,AttributeRule*>::iterator i=m_attrMap.begin(); i!=m_attrMap.end(); i++)
160             delete i->second;
161         if (m_doc)
162             m_doc->release();
163         throw;
164     }
165     catch (...)
166     {
167         log.error("Unexpected error while parsing AAP");
168         for (map<xstring,AttributeRule*>::iterator i=m_attrMap.begin(); i!=m_attrMap.end(); i++)
169             delete i->second;
170         if (m_doc)
171             m_doc->release();
172         throw;
173     }
174
175 }
176
177 XMLAAPImpl::~XMLAAPImpl()
178 {
179     for (map<xstring,AttributeRule*>::iterator i=m_attrMap.begin(); i!=m_attrMap.end(); i++)
180     {
181         SAMLAttribute::unregFactory(i->second->getName(),i->second->getNamespace());
182         delete i->second;
183     }
184     if (m_doc)
185         m_doc->release();
186 }
187
188 void XMLAAPImpl::regAttributes() const
189 {
190     for (map<xstring,AttributeRule*>::const_iterator i=m_attrMap.begin(); i!=m_attrMap.end(); i++)
191     {
192         SAMLAttributeFactory* f=ShibConfig::getConfig().getAttributeFactory(i->second->getFactory());
193         if (f)
194             SAMLAttribute::regFactory(i->second->getName(),i->second->getNamespace(),f);
195     }
196 }
197
198 XMLAAPImpl::AttributeRule::AttributeRule(const DOMElement* e) :
199     m_factory(e->hasAttributeNS(NULL,SHIB_L(Factory)) ? XMLString::transcode(e->getAttributeNS(NULL,SHIB_L(Factory))) : NULL),
200     m_alias(e->hasAttributeNS(NULL,SHIB_L(Alias)) ? XMLString::transcode(e->getAttributeNS(NULL,SHIB_L(Alias))) : NULL),
201     m_header(e->hasAttributeNS(NULL,SHIB_L(Header)) ? XMLString::transcode(e->getAttributeNS(NULL,SHIB_L(Header))) : NULL)
202     
203 {
204     static const XMLCh wTrue[] = {chLatin_t, chLatin_r, chLatin_u, chLatin_e, chNull};
205
206     m_name=e->getAttributeNS(NULL,SHIB_L(Name));
207     m_namespace=e->getAttributeNS(NULL,SHIB_L(Namespace));
208     if (!m_namespace || !*m_namespace)
209         m_namespace=Constants::SHIB_ATTRIBUTE_NAMESPACE_URI;
210     
211     // Check for an AnySite rule.
212     DOMNode* anysite = e->getFirstChild();
213     while (anysite && anysite->getNodeType()!=DOMNode::ELEMENT_NODE)
214     {
215         anysite = anysite->getNextSibling();
216         continue;
217     }
218
219     if (anysite && !XMLString::compareString(XML::SHIB_NS,static_cast<DOMElement*>(anysite)->getNamespaceURI()) &&
220         !XMLString::compareString(SHIB_L(AnySite),static_cast<DOMElement*>(anysite)->getLocalName()))
221     {
222         // Process Scope elements.
223         DOMNodeList* vlist = static_cast<DOMElement*>(anysite)->getElementsByTagNameNS(XML::SHIB_NS,SHIB_L(Scope));
224         for (int i=0; vlist && i<vlist->getLength(); i++)
225         {
226             DOMElement* se=static_cast<DOMElement*>(vlist->item(i));
227             DOMNode* valnode=se->getFirstChild();
228             if (valnode && valnode->getNodeType()==DOMNode::TEXT_NODE)
229             {
230                 const XMLCh* accept=se->getAttributeNS(NULL,SHIB_L(Accept));
231                 if (!accept || !*accept || *accept==chDigit_1 || !XMLString::compareString(accept,wTrue))
232                     m_anySiteRule.scopeAccepts.push_back(pair<value_type,const XMLCh*>(toValueType(se),valnode->getNodeValue()));
233                 else
234                     m_anySiteRule.scopeDenials.push_back(pair<value_type,const XMLCh*>(toValueType(se),valnode->getNodeValue()));
235             }
236         }
237
238         // Check for an AnyValue rule.
239         vlist = static_cast<DOMElement*>(anysite)->getElementsByTagNameNS(XML::SHIB_NS,SHIB_L(AnyValue));
240         if (vlist && vlist->getLength())
241         {
242             m_anySiteRule.anyValue=true;
243         }
244         else
245         {
246             // Process each Value element.
247             vlist = static_cast<DOMElement*>(anysite)->getElementsByTagNameNS(XML::SHIB_NS,XML::Literals::Value);
248             for (int j=0; vlist && j<vlist->getLength(); j++)
249             {
250                 DOMElement* ve=static_cast<DOMElement*>(vlist->item(j));
251                 DOMNode* valnode=ve->getFirstChild();
252                 if (valnode && valnode->getNodeType()==DOMNode::TEXT_NODE)
253                     m_anySiteRule.valueRules.push_back(pair<value_type,const XMLCh*>(toValueType(ve),valnode->getNodeValue()));
254             }
255         }
256     }
257
258     // Loop over the SiteRule elements.
259     DOMNodeList* slist = e->getElementsByTagNameNS(XML::SHIB_NS,SHIB_L(SiteRule));
260     for (int k=0; slist && k<slist->getLength(); k++)
261     {
262         m_siteMap[static_cast<DOMElement*>(slist->item(k))->getAttributeNS(NULL,SHIB_L(Name))]=SiteRule();
263         SiteRule& srule=m_siteMap[static_cast<DOMElement*>(slist->item(k))->getAttributeNS(NULL,SHIB_L(Name))];
264
265         // Process Scope elements.
266         DOMNodeList* vlist = static_cast<DOMElement*>(slist->item(k))->getElementsByTagNameNS(XML::SHIB_NS,SHIB_L(Scope));
267         for (int i=0; vlist && i<vlist->getLength(); i++)
268         {
269             DOMElement* se=static_cast<DOMElement*>(vlist->item(i));
270             DOMNode* valnode=se->getFirstChild();
271             if (valnode && valnode->getNodeType()==DOMNode::TEXT_NODE)
272             {
273                 const XMLCh* accept=se->getAttributeNS(NULL,SHIB_L(Accept));
274                 if (!accept || *accept==chDigit_1 || !XMLString::compareString(accept,wTrue))
275                     srule.scopeAccepts.push_back(pair<value_type,const XMLCh*>(toValueType(se),valnode->getNodeValue()));
276                 else
277                     srule.scopeDenials.push_back(pair<value_type,const XMLCh*>(toValueType(se),valnode->getNodeValue()));
278             }
279         }
280
281         // Check for an AnyValue rule.
282         vlist = static_cast<DOMElement*>(slist->item(k))->getElementsByTagNameNS(XML::SHIB_NS,SHIB_L(AnyValue));
283         if (vlist && vlist->getLength())
284         {
285             srule.anyValue=true;
286         }
287         else
288         {
289             // Process each Value element.
290             vlist = static_cast<DOMElement*>(slist->item(k))->getElementsByTagNameNS(XML::SHIB_NS,SHIB_L(Value));
291             for (int j=0; vlist && j<vlist->getLength(); j++)
292             {
293                 DOMElement* ve=static_cast<DOMElement*>(vlist->item(j));
294                 DOMNode* valnode=ve->getFirstChild();
295                 if (valnode && valnode->getNodeType()==DOMNode::TEXT_NODE)
296                     srule.valueRules.push_back(pair<value_type,const XMLCh*>(toValueType(ve),valnode->getNodeValue()));
297             }
298         }
299     }
300 }
301
302 XMLAAPImpl::AttributeRule::value_type XMLAAPImpl::AttributeRule::toValueType(const DOMElement* e)
303 {
304     if (!XMLString::compareString(SHIB_L(literal),e->getAttributeNS(NULL,SHIB_L(Type))))
305         return literal;
306     else if (!XMLString::compareString(SHIB_L(regexp),e->getAttributeNS(NULL,SHIB_L(Type))))
307         return regexp;
308     else if (!XMLString::compareString(SHIB_L(xpath),e->getAttributeNS(NULL,SHIB_L(Type))))
309         return xpath;
310     throw MalformedException("Found an invalid value or scope rule type.");
311 }
312
313 XMLAAP::XMLAAP(const char* pathname) : m_filestamp(0), m_source(pathname), m_impl(NULL)
314 {
315 #ifdef WIN32
316     struct _stat stat_buf;
317     if (_stat(pathname, &stat_buf) == 0)
318 #else
319     struct stat stat_buf;
320     if (stat(pathname, &stat_buf) == 0)
321 #endif
322         m_filestamp=stat_buf.st_mtime;
323     m_impl=new XMLAAPImpl(pathname);
324     SAMLConfig::getConfig().saml_lock();
325     m_impl->regAttributes();
326     SAMLConfig::getConfig().saml_unlock();
327     m_lock=RWLock::create();
328 }
329
330 XMLAAP::~XMLAAP()
331 {
332     delete m_lock;
333     delete m_impl;
334 }
335
336 void XMLAAP::lock()
337 {
338     m_lock->rdlock();
339
340     // Check if we need to refresh.
341 #ifdef WIN32
342     struct _stat stat_buf;
343     if (_stat(m_source.c_str(), &stat_buf) == 0)
344 #else
345     struct stat stat_buf;
346     if (stat(m_source.c_str(), &stat_buf) == 0)
347 #endif
348     {
349         if (m_filestamp>0 && m_filestamp<stat_buf.st_mtime)
350         {
351             // Elevate lock and recheck.
352             m_lock->unlock();
353             m_lock->wrlock();
354             if (m_filestamp>0 && m_filestamp<stat_buf.st_mtime)
355             {
356                 try
357                 {
358                     XMLAAPImpl* new_mapper=new XMLAAPImpl(m_source.c_str());
359                     SAMLConfig::getConfig().saml_lock();
360                     delete m_impl;
361                     m_impl=new_mapper;
362                     m_impl->regAttributes();
363                     SAMLConfig::getConfig().saml_unlock();
364                     m_filestamp=stat_buf.st_mtime;
365                     m_lock->unlock();
366                 }
367                 catch(SAMLException& e)
368                 {
369                     m_lock->unlock();
370                     saml::NDC ndc("lock");
371                     Category::getInstance(SHIB_LOGCAT".XMLAAP").error("failed to reload AAP, sticking with what we have: %s", e.what());
372                 }
373                 catch(...)
374                 {
375                     m_lock->unlock();
376                     saml::NDC ndc("lock");
377                     Category::getInstance(SHIB_LOGCAT".XMLAAP").error("caught an unknown exception, sticking with what we have");
378                 }
379             }
380             else
381             {
382                 m_lock->unlock();
383             }
384             m_lock->rdlock();
385         }
386     }
387 }
388
389 void XMLAAP::unlock()
390 {
391     m_lock->unlock();
392 }
393
394 const IAttributeRule* XMLAAP::lookup(const XMLCh* attrName, const XMLCh* attrNamespace) const
395 {
396     map<xstring,XMLAAPImpl::AttributeRule*>::const_iterator i=m_impl->m_attrMap.find(
397         xstring(attrName) + chBang + chBang + (attrNamespace ? attrNamespace : Constants::SHIB_ATTRIBUTE_NAMESPACE_URI)
398         );
399     return (i==m_impl->m_attrMap.end()) ? NULL : i->second;
400 }
401
402 const IAttributeRule* XMLAAP::lookup(const char* alias) const
403 {
404     map<string,const IAttributeRule*>::const_iterator i=m_impl->m_aliasMap.find(alias);
405     return (i==m_impl->m_aliasMap.end()) ? NULL : i->second;
406 }
407
408 Iterator<const IAttributeRule*> XMLAAP::getAttributeRules() const
409 {
410     return m_impl->m_attrs;
411 }
412
413 namespace {
414     bool match(const XMLCh* exp, const XMLCh* test)
415     {
416         try
417         {
418             RegularExpression re(exp);
419             if (re.matches(test))
420                 return true;
421         }
422         catch (XMLException& ex)
423         {
424             auto_ptr<char> tmp(XMLString::transcode(ex.getMessage()));
425             Category::getInstance(SHIB_LOGCAT".XMLAAPImpl").errorStream()
426                 << "caught exception while parsing regular expression: " << tmp.get() << CategoryStream::ENDLINE;
427         }
428         return false;
429     }
430 }
431
432 bool XMLAAPImpl::AttributeRule::scopeCheck(const XMLCh* originSite, const DOMElement* e) const
433 {
434     // Are we scoped?
435     const XMLCh* scope=e->getAttributeNS(NULL,SHIB_L(Scope));
436     if (!scope || !*scope)
437         return true;
438
439     NDC ndc("scopeCheck");
440     Category& log=Category::getInstance(SHIB_LOGCAT".XMLAAPImpl");
441
442     vector<pair<value_type,const XMLCh*> >::const_iterator i;
443
444     // Denials take precedence, always.
445     
446     // Any site denials...
447     for (i=m_anySiteRule.scopeDenials.begin(); i!=m_anySiteRule.scopeDenials.end(); i++)
448     {
449         if ((i->first==literal && !XMLString::compareString(i->second,scope)) ||
450             (i->first==regexp && match(i->second,scope)))
451         {
452             if (log.isWarnEnabled())
453             {
454                 auto_ptr<char> temp(XMLString::transcode(m_name));
455                 auto_ptr<char> temp2(XMLString::transcode(scope));
456                 log.warn("attribute %s scope {%s} denied by any-site AAP, rejecting it",temp.get(),temp2.get());
457             }
458             return false;
459         }
460         else if (i->first==xpath)
461             log.warn("scope checking does not permit XPath rules");
462     }
463
464     map<xstring,SiteRule>::const_iterator srule=m_siteMap.find(originSite);
465     if (srule!=m_siteMap.end())
466     {
467         // Site-specific denials...
468         for (i=srule->second.scopeDenials.begin(); i!=srule->second.scopeDenials.end(); i++)
469         {
470             if ((i->first==literal && !XMLString::compareString(i->second,scope)) ||
471                 (i->first==regexp && match(i->second,scope)))
472             {
473                 if (log.isWarnEnabled())
474                 {
475                     auto_ptr<char> temp(XMLString::transcode(m_name));
476                     auto_ptr<char> temp2(XMLString::transcode(scope));
477                     log.warn("attribute %s scope {%s} denied by site AAP, rejecting it",temp.get(),temp2.get());
478                 }
479                 return false;
480             }
481             else if (i->first==xpath)
482                 log.warn("scope checking does not permit XPath rules");
483         }
484     }
485
486     // Any site accepts...
487     for (i=m_anySiteRule.scopeAccepts.begin(); i!=m_anySiteRule.scopeAccepts.end(); i++)
488     {
489         if ((i->first==literal && !XMLString::compareString(i->second,scope)) ||
490             (i->first==regexp && match(i->second,scope)))
491         {
492             log.debug("any site, scope match");
493             return true;
494         }
495         else if (i->first==xpath)
496             log.warn("scope checking does not permit XPath rules");
497     }
498
499     if (srule!=m_siteMap.end())
500     {
501         // Site-specific accepts...
502         for (i=srule->second.scopeAccepts.begin(); i!=srule->second.scopeAccepts.end(); i++)
503         {
504             if ((i->first==literal && !XMLString::compareString(i->second,scope)) ||
505                 (i->first==regexp && match(i->second,scope)))
506             {
507                 log.debug("matching site, scope match");
508                 return true;
509             }
510             else if (i->first==xpath)
511                 log.warn("scope checking does not permit XPath rules");
512         }
513     }
514     
515     // If we still can't decide, defer to site metadata.
516     OriginMetadata mapper(originSite);
517     Iterator<pair<const XMLCh*,bool> > domains=
518         (mapper.fail()) ? Iterator<pair<const XMLCh*,bool> >() : mapper->getSecurityDomains();
519     while (domains.hasNext())
520     {
521         const pair<const XMLCh*,bool>& p=domains.next();
522         if ((p.second && match(p.first,scope)) || !XMLString::compareString(p.first,scope))
523         {
524             log.debug("scope match via site metadata");
525             return true;
526         }
527     }
528
529     if (log.isWarnEnabled())
530     {
531         auto_ptr<char> temp(XMLString::transcode(m_name));
532         auto_ptr<char> temp2(XMLString::transcode(scope));
533         log.warn("attribute %s scope {%s} not accepted",temp.get(),temp2.get());
534     }
535     return false;
536 }
537
538 bool XMLAAPImpl::AttributeRule::accept(const XMLCh* originSite, const DOMElement* e) const
539 {
540     NDC ndc("accept");
541     Category& log=Category::getInstance(SHIB_LOGCAT".XMLAAPImpl");
542     
543     if (log.isDebugEnabled())
544     {
545         auto_ptr<char> temp(XMLString::transcode(m_name));
546         auto_ptr<char> temp2(XMLString::transcode(originSite));
547         log.debug("evaluating value for attribute %s from site %s",temp.get(),temp2.get());
548     }
549     
550     if (m_anySiteRule.anyValue)
551     {
552         log.debug("any site, any value, match");
553         return scopeCheck(originSite,e);
554     }
555
556     // Don't fully support complex content models...
557     DOMNode* n=e->getFirstChild();
558     bool bSimple=(n && n->getNodeType()==DOMNode::TEXT_NODE);
559
560     vector<pair<value_type,const XMLCh*> >::const_iterator i;
561     for (i=m_anySiteRule.valueRules.begin(); bSimple && i!=m_anySiteRule.valueRules.end(); i++)
562     {
563         if ((i->first==literal && !XMLString::compareString(i->second,n->getNodeValue())) ||
564             (i->first==regexp && match(i->second,n->getNodeValue())))
565         {
566             log.debug("any site, value match");
567             return scopeCheck(originSite,e);
568         }
569         else if (i->first==xpath)
570             log.warn("implementation does not support XPath value rules");
571     }
572
573     map<xstring,SiteRule>::const_iterator srule=m_siteMap.find(originSite);
574     if (srule==m_siteMap.end())
575     {
576         if (log.isWarnEnabled())
577         {
578             auto_ptr<char> temp(XMLString::transcode(m_name));
579             auto_ptr<char> temp2(XMLString::transcode(originSite));
580             log.warn("site %s not found in attribute %s ruleset, any value is rejected",temp2.get(),temp.get());
581         }
582         return false;
583     }
584
585     if (srule->second.anyValue)
586     {
587         log.debug("matching site, any value, match");
588         return scopeCheck(originSite,e);
589     }
590
591     for (i=srule->second.valueRules.begin(); bSimple && i!=srule->second.valueRules.end(); i++)
592     {
593         if ((i->first==literal && !XMLString::compareString(i->second,n->getNodeValue())) ||
594             (i->first==regexp && match(i->second,n->getNodeValue())))
595         {
596             log.debug("matching site, value match");
597             return scopeCheck(originSite,e);
598         }
599         else if (i->first==xpath)
600             log.warn("implementation does not support XPath value rules");
601     }
602
603     if (log.isWarnEnabled())
604     {
605         auto_ptr<char> temp(XMLString::transcode(m_name));
606         auto_ptr<char> temp2(XMLString::transcode(n->getNodeValue()));
607         log.warn("%sattribute %s value {%s} could not be validated by AAP, rejecting it",
608                  (bSimple ? "" : "complex "),temp.get(),temp2.get());
609     }
610     return false;
611 }