AccessControl.cpp
上传用户:xqtpzdz
上传日期:2022-05-21
资源大小:1764k
文件大小:6k
源码类别:

xml/soap/webservice

开发平台:

Visual C++

  1. /****************License************************************************
  2.  * Vocalocity OpenVXI
  3.  * Copyright (C) 2004-2005 by Vocalocity, Inc. All Rights Reserved.
  4.  * This program is free software; you can redistribute it and/or
  5.  * modify it under the terms of the GNU General Public License
  6.  * as published by the Free Software Foundation; either version 2
  7.  * of the License, or (at your option) any later version.
  8.  *  
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  17.  * Vocalocity, the Vocalocity logo, and VocalOS are trademarks or 
  18.  * registered trademarks of Vocalocity, Inc. 
  19.  * OpenVXI is a trademark of Scansoft, Inc. and used under license 
  20.  * by Vocalocity.
  21.  ***********************************************************************/
  22. #include "AccessControl.hpp"
  23. #include "TokenList.hpp"
  24. #include <algorithm>
  25. #include "XMLChConverter.hpp"
  26. #include <xercesc/dom/DOMNode.hpp>
  27. #include <xercesc/dom/DOMDocument.hpp>
  28. #include <xercesc/dom/DOMProcessingInstruction.hpp>
  29. #include <xercesc/dom/DOMNodeList.hpp>
  30. AccessControl::AccessControl(bool defAccess) : _default(defAccess)
  31. {
  32. }
  33. AccessControl::AccessControl(bool defAccess, xercesc::DOMDocument *doc) : _default(defAccess)
  34. {
  35.   DOMNodeList *nl = doc->getChildNodes();
  36.   if (nl && nl->getLength()){
  37.     int len = nl->getLength();
  38.     for (int i = 0; i < len; i++) {
  39.       DOMNode *node = nl->item(i);
  40.   if (node->getNodeType() == DOMNode::PROCESSING_INSTRUCTION_NODE) {
  41.         DOMProcessingInstruction *pi = reinterpret_cast<DOMProcessingInstruction*>(node);
  42.         if (pi) {
  43.           vxistring target(XMLChToVXIchar(pi->getTarget()).c_str());
  44.           if (target == L"access-control") {
  45. vxistring data(XMLChToVXIchar(pi->getData()).c_str());
  46. addAllow(getValue(L"allow", data));
  47. addDeny(getValue(L"deny", data));
  48.           }
  49.         }
  50.       }
  51.     }
  52.   }
  53. }
  54. vxistring AccessControl::getValue(const vxistring &key, const vxistring &data) const
  55. {
  56.   // find attr
  57.   int keyStart = data.find( key );
  58.   if (keyStart == vxistring::npos) return L"";
  59.   // set index to start of value (not including opening quote)
  60.   int valueStart = keyStart + key.length() + 2;
  61.   // find end of value by finding matching end quote
  62.   vxistring::value_type quote = data[valueStart - 1];
  63.   int valueEnd = data.find(quote, valueStart);
  64.   if (valueEnd == vxistring::npos)
  65.       valueEnd = data.length();
  66.   return data.substr(valueStart, valueEnd - valueStart);
  67. }
  68. void AccessControl::addAllow(const vxistring &allow)
  69. {
  70.   addEntries(allow, _allowList);
  71. }
  72. void AccessControl::addDeny(const vxistring &deny)
  73. {
  74.   addEntries(deny, _denyList);
  75. }
  76. void AccessControl::addEntries(const vxistring &data, EntryList &list)
  77. {
  78.   if (data.empty()) 
  79.     return;
  80.   TokenList el(data);
  81.   TokenList::iterator i;
  82.   for (i = el.begin(); i != el.end(); ++i)
  83.     list.push_back(Entry(*i));
  84. }
  85. bool AccessControl::canAccess(const vxistring &url) const
  86. {
  87.   // treat missing/empty "allow" and "deny" the same as 
  88.   // as missing <?access-control?> element.
  89.   if (_allowList.empty() && _denyList.empty())
  90.     return _default;
  91.   // this should never happen, but without a URL, there
  92.   // is no way to validate.
  93.   if (url.empty())
  94.     return false;
  95.   // get hostname and protocol
  96.   vxistring proto;
  97.   vxistring host;
  98.   if (!parseURL(url, proto, host))
  99.     return false;
  100.   // always allow file access
  101.   if (proto == L"file")
  102.     return true;
  103.   // deny, exact
  104.   EntryList::const_iterator i = _denyList.begin();
  105.   for (; i != _denyList.end(); i++){
  106.     if ((*i).match(host))
  107.       return false;
  108.   }
  109.   // allow, exact
  110.   i = _allowList.begin();
  111.   for (; i != _allowList.end(); i++){
  112.     if ((*i).match(host))
  113.       return true;
  114.   }
  115.   // deny, bestmatch
  116.   int bestDeny = 0;
  117.   i = _denyList.begin();
  118.   for (; i != _denyList.end(); i++){
  119.     int score = (*i).bestmatch(host);
  120. if (score > bestDeny) bestDeny = score;
  121.   }
  122.   // allow, bestmatch
  123.   int bestAllow = 0;
  124.   i = _allowList.begin();
  125.   for (; i != _allowList.end(); i++){
  126.     int score = (*i).bestmatch(host);
  127. if (score > bestAllow) bestAllow = score;
  128.   }
  129.   if (bestAllow > bestDeny)
  130.     return true;
  131.   return false;
  132. }
  133. bool AccessControl::parseURL(const vxistring &url, vxistring &proto, vxistring &host) const
  134. {
  135.   proto.clear();
  136.   host.clear();
  137.   // get protocol
  138.   int pos = url.find(':');
  139.   if (pos == vxistring::npos)
  140.     return false;
  141.   proto = url.substr(0,pos);
  142.   if (proto == L"file")
  143.     return true;
  144.   if (proto.length() == 1){
  145.     proto = L"file";
  146. return true;
  147.   }
  148.   // find beginning of hostname
  149.   ++pos;
  150.   VXIchar c;
  151.   do {
  152.     c = url[pos];
  153. if (c == L'/') pos++;
  154.   } while(c!=0 && c==L'/');
  155.   // get host
  156.   while(url[pos] != ':' && url[pos] != '/' && url[pos] != 0)
  157.     host.append(1,url[pos++]);
  158.   // convert to lowercase
  159.   std::transform(host.begin(), host.end(), host.begin(), tolower);
  160.   return true;
  161. }
  162. AccessControl::Entry::Entry(const vxistring &data)
  163. {
  164.   _isWild = (data[0] == L'*');
  165.   if (!_isWild)
  166.     _data = data;
  167.   else {
  168. _data = data.substr(1);
  169. if ( _data.length() > 0 && _data[0] != '.')
  170.       _data = L"." + _data;
  171.   }
  172.   std::transform(_data.begin(), _data.end(), _data.begin(), tolower );
  173. }
  174. bool AccessControl::Entry::match(const vxistring &host) const
  175. {
  176.   if (_isWild) return false;
  177.   return _data == host;
  178. }
  179. // returns a "score" between 0 and 100, which 0 meaning no
  180. // match at all, and 100 being a exact.
  181. //
  182. // given an "allow" of "*.example.com" and a "deny" of "*.visitors.example.com", then
  183. // a URL of "mach1.visitors.example.com" would give a score of 46 against the "allow",
  184. // and a score of 80 against the deny list.
  185. int AccessControl::Entry::bestmatch(const vxistring &host) const
  186. {
  187.   if (!_isWild)
  188.     return 0;
  189.   // no data would mean a spec of "*", in which case
  190.   // we return a score of 1.
  191.   if (_data.length() == 0)
  192.     return 1;
  193.   int score = 0;
  194.   int pos = host.find(_data);
  195.   if (pos != vxistring::npos){
  196.     int len = host.length();
  197.     score = ((len - pos) * 100) / len;
  198.   }
  199.   return score;
  200. }