XRootD
XrdSciTokensAccess.hh
Go to the documentation of this file.
1 
3 
4 #include <memory>
5 #include <string>
6 #include <string_view>
7 #include <vector>
8 
9 #include <string.h>
10 
15 typedef std::vector<std::pair<Access_Operation, std::string>> AccessRulesRaw;
16 
17 // Class representing a rule in the administrator-provided mapfile.
18 // All predicates must match for the rule to apply.
19 struct MapRule
20 {
21  MapRule(const std::string &sub,
22  const std::string &username,
23  const std::string &path_prefix,
24  const std::string &group,
25  const std::string &result)
26  : m_sub(sub),
27  m_username(username),
28  m_path_prefix(path_prefix),
29  m_group(group),
30  m_result(result)
31  {
32  //std::cerr << "Making a rule {sub=" << sub << ", username=" << username << ", path=" << path_prefix << ", group=" << group << ", result=" << name << "}" << std::endl;
33  }
34 
35  const std::string match(const std::string &sub,
36  const std::string &username,
37  const std::string_view &req_path,
38  const std::vector<std::string> &groups) const
39  {
40  if (!m_sub.empty() && sub != m_sub) {return "";}
41 
42  if (!m_username.empty() && username != m_username) {return "";}
43 
44  if (!m_path_prefix.empty() &&
45  strncmp(req_path.data(), m_path_prefix.c_str(), m_path_prefix.size()))
46  {
47  return "";
48  }
49 
50  if (!m_group.empty()) {
51  for (const auto &group : groups) {
52  if (group == m_group)
53  return m_result;
54  }
55  return "";
56  }
57  return m_result;
58  }
59 
60  std::string m_sub;
61  std::string m_username;
62  std::string m_path_prefix;
63  std::string m_group;
64  std::string m_result;
65 };
66 
67 // Control whether a given issuer is required for the paths it authorizes
68 enum class AuthzSetting {
69  None, // Issuer's authorization is not necessary
70  Read, // Authorization from this issuer is necessary for reads.
71  Write, // Authorization from this issuer is necessary for writes.
72  All, // Authorization from this issuer is necessary for all operations.
73 };
74 
75 // Controls what part of the token is used to determine a positive authorization.
76 //
77 // E.g., if IssuerAuthz::Group is set, then the positive authorization may be based
78 // on the groups embedded in the token.
80  Capability = 0x01,
81  Group = 0x02,
82  Mapping = 0x04,
83  Default = 0x07
84 };
85 
86 // Given a list of access rules, this class determines whether a requested operation / path
87 // is permitted by the access rules.
88 class SubpathMatch final {
89 public:
90  SubpathMatch() = default;
92  : m_rules(rules)
93  {}
94 
95  // Determine whether the known access rules permit the requested `oper` on `path`.
96  bool apply(Access_Operation oper, const std::string_view path) const {
97  auto is_subdirectory = [](const std::string_view& dir, const std::string_view& subdir) {
98  if (subdir.size() < dir.size())
99  return false;
100 
101  if (subdir.compare(0, dir.size(), dir, 0, dir.size()) != 0)
102  return false;
103 
104  return dir.size() == subdir.size() || subdir[dir.size()] == '/' || dir == "/";
105  };
106 
107  for (const auto & rule : m_rules) {
108  // Skip rules that don't match the current operation
109  if (rule.first != oper)
110  continue;
111 
112  // If the rule allows any path, allow the operation
113  if (rule.second == "/")
114  return true;
115 
116  // Allow operation if path is a subdirectory of the rule's path
117  if (is_subdirectory(rule.second, path)) {
118  return true;
119  } else {
120  // Allow stat and mkdir of parent directories to comply with WLCG token specs
121  if (oper == AOP_Stat || oper == AOP_Mkdir)
122  if (is_subdirectory(path, rule.second))
123  return true;
124  }
125  }
126  return false;
127  }
128 
129  bool empty() const {return m_rules.empty();} // Returns true if there are no rules to match
130 
131  std::string str() const; // Returns a human-friendly representation of the access rules
132 
133  size_t size() const {return m_rules.size();} // Returns the count of rules
134 private:
135 
136  AccessRulesRaw m_rules;
137 };
138 
146 {
147 public:
148  XrdAccRules(uint64_t expiry_time, const std::string &username, const std::string &token_subject,
149  const std::string &issuer, const std::vector<MapRule> &rules, const std::vector<std::string> &groups,
150  uint32_t authz_strategy, AuthzSetting acceptable_authz) :
151  m_authz_strategy(authz_strategy),
152  m_acceptable_authz(acceptable_authz),
153  m_expiry_time(expiry_time),
154  m_username(username),
155  m_token_subject(token_subject),
156  m_issuer(issuer),
157  m_map_rules(rules),
158  m_groups(groups)
159  {}
160 
162 
163  bool apply(Access_Operation oper, const std::string_view path) {
164  return m_matcher.apply(oper, path);
165  }
166 
167  // Check to see if the access rules generated for this token have expired
168  bool expired() const;
169 
170  void parse(const AccessRulesRaw &rules) {
171  m_matcher = SubpathMatch(rules);
172  }
173 
174  std::string get_username(const std::string_view &req_path) const
175  {
176  for (const auto &rule : m_map_rules) {
177  std::string name = rule.match(m_token_subject, m_username, req_path, m_groups);
178  if (!name.empty()) {
179  return name;
180  }
181  }
182  return "";
183  }
184 
185  const std::string str() const;
186 
187  // Return the token's subject, an opaque unique string within the issuer's
188  // namespace. It may or may not be related to the username one should
189  // use within the authorization framework.
190  const std::string & get_token_subject() const {return m_token_subject;}
191  const std::string & get_default_username() const {return m_username;}
192  const std::string & get_issuer() const {return m_issuer;}
193 
194  uint32_t get_authz_strategy() const {return m_authz_strategy;}
196  if (m_acceptable_authz == AuthzSetting::All) return true;
197  if (m_acceptable_authz == AuthzSetting::None) return false;
198 
199  bool is_read = oper == AOP_Read || oper == AOP_Readdir || oper == AOP_Stat;
200  if (is_read) return m_acceptable_authz == AuthzSetting::Read;
201  else return m_acceptable_authz == AuthzSetting::Write;
202  }
203 
204  size_t size() const {return m_matcher.size();}
205  const std::vector<std::string> &groups() const {return m_groups;}
206 
207 private:
208  const uint32_t m_authz_strategy;
209  const AuthzSetting m_acceptable_authz;
210  SubpathMatch m_matcher;
211  const uint64_t m_expiry_time{0};
212  const std::string m_username;
213  const std::string m_token_subject;
214  const std::string m_issuer;
215  const std::vector<MapRule> m_map_rules;
216  const std::vector<std::string> m_groups;
217 };
218 
219 bool AuthorizesRequiredIssuers(Access_Operation client_oper, const std::string_view &path,
220  const std::vector<std::pair<std::unique_ptr<SubpathMatch>, std::string>> &required_issuers,
221  const std::vector<std::shared_ptr<XrdAccRules>> &access_rules_list);
222 
Access_Operation
The following are supported operations.
@ AOP_Mkdir
mkdir()
@ AOP_Readdir
opendir()
@ AOP_Stat
exists(), stat()
@ AOP_Read
open() r/o, prepare()
bool AuthorizesRequiredIssuers(Access_Operation client_oper, const std::string_view &path, const std::vector< std::pair< std::unique_ptr< SubpathMatch >, std::string >> &required_issuers, const std::vector< std::shared_ptr< XrdAccRules >> &access_rules_list)
std::vector< std::pair< Access_Operation, std::string > > AccessRulesRaw
@ Default
@ Capability
@ Mapping
AuthzSetting
size_t size() const
SubpathMatch(const AccessRulesRaw &rules)
SubpathMatch()=default
std::string str() const
bool apply(Access_Operation oper, const std::string_view path) const
bool empty() const
const std::vector< std::string > & groups() const
bool apply(Access_Operation oper, const std::string_view path)
const std::string & get_issuer() const
bool expired() const
uint32_t get_authz_strategy() const
size_t size() const
void parse(const AccessRulesRaw &rules)
const std::string & get_default_username() const
const std::string & get_token_subject() const
bool acceptable_authz(Access_Operation oper) const
std::string get_username(const std::string_view &req_path) const
const std::string str() const
XrdAccRules(uint64_t expiry_time, const std::string &username, const std::string &token_subject, const std::string &issuer, const std::vector< MapRule > &rules, const std::vector< std::string > &groups, uint32_t authz_strategy, AuthzSetting acceptable_authz)
const std::string match(const std::string &sub, const std::string &username, const std::string_view &req_path, const std::vector< std::string > &groups) const
std::string m_sub
std::string m_group
std::string m_result
std::string m_path_prefix
std::string m_username
MapRule(const std::string &sub, const std::string &username, const std::string &path_prefix, const std::string &group, const std::string &result)