bes  Updated for version 3.20.6
WhiteList.cc
1 // RemoteAccess.cc
2 
3 // -*- mode: c++; c-basic-offset:4 -*-
4 
5 // This file is part of the OPeNDAP Back-End Server (BES)
6 // and embodies a whitelist of remote system that may be
7 // accessed by the server as part of it's routine operation.
8 
9 // Copyright (c) 2018 OPeNDAP, Inc.
10 // Author: Nathan D. Potter <ndp@opendap.org>
11 //
12 // This library is free software; you can redistribute it and/or
13 // modify it under the terms of the GNU Lesser General Public
14 // License as published by the Free Software Foundation; either
15 // version 2.1 of the License, or (at your option) any later version.
16 //
17 // This library is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 // Lesser General Public License for more details.
21 //
22 // You should have received a copy of the GNU Lesser General Public
23 // License along with this library; if not, write to the Free Software
24 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 //
26 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
27 
28 #include "config.h"
29 
30 #include <BESUtil.h>
31 #include <BESCatalog.h>
32 #include <BESCatalogList.h>
33 #include <BESCatalogUtils.h>
34 #include <BESRegex.h>
35 #include <TheBESKeys.h>
36 #include <BESInternalError.h>
37 #include <BESSyntaxUserError.h>
38 #include <BESDebug.h>
39 #include <BESNotFoundError.h>
40 #include <BESForbiddenError.h>
41 
42 #include "WhiteList.h"
43 
44 using namespace std;
45 using namespace bes;
46 
47 WhiteList *WhiteList::d_instance = 0;
48 
54 WhiteList *
55 WhiteList::get_white_list()
56 {
57  if (d_instance) return d_instance;
58  d_instance = new WhiteList;
59  return d_instance;
60 }
61 
62 WhiteList::WhiteList()
63 {
64  bool found = false;
65  string key = REMOTE_ACCESS_WHITELIST;
66  TheBESKeys::TheKeys()->get_values(REMOTE_ACCESS_WHITELIST, d_white_list, found);
67  if(!found){
68  throw BESInternalError(string("The remote access whitelist, '")+REMOTE_ACCESS_WHITELIST
69  +"' has not been configured.", __FILE__, __LINE__);
70  }
71 }
72 
87 bool WhiteList::is_white_listed(const std::string &url)
88 {
89  bool whitelisted = false;
90  const string file_url("file://");
91  const string http_url("http://");
92  const string https_url("https://");
93 
94  // Special case: This allows any file: URL to pass if the URL starts with the default
95  // catalog's path.
96  if (url.compare(0, file_url.size(), file_url) == 0 /*equals a file url*/) {
97 
98  // Ensure that the file path starts with the catalog root dir.
99  string file_path = url.substr(file_url.size());
100  BESDEBUG("bes", "WhiteList::Is_Whitelisted() - file_path: "<< file_path << endl);
101 
102  BESCatalog *bcat = BESCatalogList::TheCatalogList()->find_catalog(BES_DEFAULT_CATALOG);
103  if (bcat) {
104  BESDEBUG("bes", "WhiteList::Is_Whitelisted() - Found catalog: "<< bcat->get_catalog_name() << endl);
105  }
106  else {
107  string msg = "OUCH! Unable to locate default catalog!";
108  BESDEBUG("bes", "WhiteList::Is_Whitelisted() - " << msg << endl);
109  throw BESInternalError(msg, __FILE__, __LINE__);
110  }
111 
112  string catalog_root = bcat->get_root();
113  BESDEBUG("bes", "WhiteList::Is_Whitelisted() - Catalog root: "<< catalog_root << endl);
114 
115 
116  // Never a relative path shall be accepted.
117  // change??
118  // if( file_path[0] != '/'){
119  // file_path.insert(0,"/");
120  //}
121 
122  string relative_path;
123  if(file_path[0] == '/'){
124  if(file_path.length() < catalog_root.length()) {
125  whitelisted = false;
126  }
127  else {
128  int ret = file_path.compare(0, catalog_root.npos, catalog_root) == 0;
129  BESDEBUG("bes", "WhiteList::Is_Whitelisted() - file_path.compare(): " << ret << endl);
130  whitelisted = (ret==0);
131  relative_path = file_path.substr(catalog_root.length());
132  }
133  }
134  else {
135  BESDEBUG("bes", "WhiteList::Is_Whitelisted() - relative path detected");
136  relative_path = file_path;
137  whitelisted = true;
138  }
139 
140  // string::compare() returns 0 if the path strings match exactly.
141  // And since we are just looking at the catalog.root as a prefix of the resource
142  // name we only allow to be white-listed for an exact match.
143  if(whitelisted){
144  // If we stop adding a '/' to file_path values that don't begin with one
145  // then we need to detect the use of the relative path here
146  bool follow_sym_links = bcat->get_catalog_utils()->follow_sym_links();
147  try {
148  BESUtil::check_path(relative_path, catalog_root, follow_sym_links);
149  }
150  catch (BESNotFoundError &e) {
151  whitelisted=false;
152  }
153  catch (BESForbiddenError &e) {
154  whitelisted=false;
155  }
156  }
157 
158 
159  BESDEBUG("bes", "WhiteList::Is_Whitelisted() - Is_Whitelisted: "<< (whitelisted?"true ":"false ") << endl);
160  }
161  else {
162  // This checks HTTP and HTTPS URLs against the whitelist patterns.
163  if (url.compare(0, http_url.size(), http_url) == 0 /*equals http url */
164  || url.compare(0, https_url.size(), https_url) == 0 /*equals https url */) {
165 
166  vector<string>::const_iterator i = d_white_list.begin();
167  vector<string>::const_iterator e = d_white_list.end();
168  for (; i != e && !whitelisted; i++) {
169  if ((*i).length() <= url.length()) {
170  if (url.substr(0, (*i).length()) == (*i)) {
171  whitelisted = true;
172  }
173  }
174  }
175  }
176  else {
177  string msg;
178  msg = "WhiteList - ERROR! Unknown URL protocol! Only " + http_url + ", " + https_url + ", and " + file_url + " are supported.";
179  BESDEBUG("bes", msg << endl);
180  throw BESForbiddenError(msg, __FILE__, __LINE__);
181  }
182  }
183 
184  return whitelisted;
185 }
186 
bes::WhiteList
Can a given URL be dereferenced given the BES's configuration?
Definition: WhiteList.h:51
BESNotFoundError
error thrown if the resource requested cannot be found
Definition: BESNotFoundError.h:40
BESUtil::check_path
static void check_path(const std::string &path, const std::string &root, bool follow_sym_links)
Check if the specified path is valid.
Definition: BESUtil.cc:254
BESCatalog::get_catalog_name
virtual std::string get_catalog_name() const
Get the name for this catalog.
Definition: BESCatalog.h:103
BESCatalogList::TheCatalogList
static BESCatalogList * TheCatalogList()
Get the singleton BESCatalogList instance.
Definition: BESCatalogList.cc:81
TheBESKeys::TheKeys
static TheBESKeys * TheKeys()
Definition: TheBESKeys.cc:62
BESForbiddenError
error thrown if the BES is not allowed to access the resource requested
Definition: BESForbiddenError.h:40
BESInternalError
exception thrown if internal error encountered
Definition: BESInternalError.h:43
BESCatalog::get_catalog_utils
virtual BESCatalogUtils * get_catalog_utils() const
Get a pointer to the utilities, customized for this catalog.
Definition: BESCatalog.h:113
TheBESKeys::get_values
void get_values(const std::string &s, std::vector< std::string > &vals, bool &found)
Retrieve the values of a given key, if set.
Definition: TheBESKeys.cc:303
BESCatalog::get_root
virtual std::string get_root() const =0
BESCatalog
Catalogs provide a hierarchical organization for data.
Definition: BESCatalog.h:51