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