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 
static BESCatalogList * TheCatalogList()
Get the singleton BESCatalogList instance.
Catalogs provide a hierarchical organization for data.
Definition: BESCatalog.h:51
virtual std::string get_root() const =0
virtual std::string get_catalog_name() const
Get the name for this catalog.
Definition: BESCatalog.h:103
virtual BESCatalogUtils * get_catalog_utils() const
Get a pointer to the utilities, customized for this catalog.
Definition: BESCatalog.h:113
error thrown if the BES is not allowed to access the resource requested
exception thrown if internal error encountered
error thrown if the resource requested cannot be found
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
static TheBESKeys * TheKeys()
Definition: TheBESKeys.cc:62
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
Can a given URL be dereferenced given the BES's configuration?
Definition: WhiteList.h:51