25 AuthzCheck(
const char *req_path,
const Access_Operation req_oper, ssize_t max_duration, XrdSysError &log);
27 const std::string &GetSecName()
const {
return m_sec_name;}
28 const std::string &GetErrorMessage()
const {
return m_emsg;}
30 static int verify_before_s(
void *authz_ptr,
31 const unsigned char *pred,
34 static int verify_activity_s(
void *authz_ptr,
35 const unsigned char *pred,
38 static int verify_path_s(
void *authz_ptr,
39 const unsigned char *pred,
42 static int verify_name_s(
void *authz_ptr,
43 const unsigned char *pred,
47 int verify_before(
const unsigned char *pred,
size_t pred_sz);
48 int verify_activity(
const unsigned char *pred,
size_t pred_sz);
49 int verify_path(
const unsigned char *pred,
size_t pred_sz);
50 int verify_name(
const unsigned char *pred,
size_t pred_sz);
52 ssize_t m_max_duration;
55 const std::string m_path;
56 std::string m_desired_activity;
57 std::string m_sec_name;
65 int new_privs = privs;
119int validate_verify_empty(
void *emsg_ptr,
120 const unsigned char *pred,
123 if ((pred_sz >= 5) && (!memcmp(
reinterpret_cast<const char *
>(pred),
"path:", 5) ||
124 !memcmp(
reinterpret_cast<const char *
>(pred),
"name:", 5)))
128 if ((pred_sz >= 9) && (!memcmp(
reinterpret_cast<const char *
>(pred),
"activity:", 9)))
139 : m_max_duration(86400),
141 m_log(log,
"macarons_"),
142 m_authz_behavior(static_cast<int>(
Handler::AuthzBehavior::PASSTHROUGH))
146 if (!
Handler::Config(config, &env, &m_log, m_location, m_secret, m_max_duration, behavior))
148 throw std::runtime_error(
"Macaroon authorization config failed.");
150 m_authz_behavior =
static_cast<int>(behavior);
155Authz::OnMissing(
const XrdSecEntity *Entity,
const char *path,
158 switch (m_authz_behavior) {
178 return m_chain ? m_chain->Access(Entity, path, oper, env) :
XrdAccPriv_None;
181 const char *authz = env ? env->
Get(
"authz") :
nullptr;
182 if (authz && !strncmp(authz,
"Bearer%20", 9))
186 else if (!authz && (authz = env ? env->
Get(
"access_token") :
nullptr) && !strncmp(authz,
"Bearer%20", 9))
192 if (!authz && Entity && !strcmp(
"ztn", Entity->
prot) && Entity->
creds &&
195 authz = Entity->
creds;
199 return OnMissing(Entity, path, oper, env);
202 macaroon_returncode mac_err = MACAROON_SUCCESS;
203 struct macaroon* macaroon = macaroon_deserialize(
210 return OnMissing(Entity, path, oper, env);
213 struct macaroon_verifier *verifier = macaroon_verifier_create();
216 m_log.Emsg(
"Access",
"Failed to create a new macaroon verifier");
221 m_log.Emsg(
"Access",
"Request with no provided path.");
222 macaroon_verifier_destroy(verifier);
226 AuthzCheck check_helper(path, oper, m_max_duration, m_log);
228 if (macaroon_verifier_satisfy_general(verifier, AuthzCheck::verify_before_s, &check_helper, &mac_err) ||
229 macaroon_verifier_satisfy_general(verifier, AuthzCheck::verify_activity_s, &check_helper, &mac_err) ||
230 macaroon_verifier_satisfy_general(verifier, AuthzCheck::verify_name_s, &check_helper, &mac_err) ||
231 macaroon_verifier_satisfy_general(verifier, AuthzCheck::verify_path_s, &check_helper, &mac_err))
233 m_log.Emsg(
"Access",
"Failed to configure caveat verifier:");
234 macaroon_verifier_destroy(verifier);
238 const unsigned char *macaroon_loc;
240 macaroon_location(macaroon, &macaroon_loc, &location_sz);
241 if (strncmp(
reinterpret_cast<const char *
>(macaroon_loc), m_location.c_str(), location_sz))
243 std::string location_str(
reinterpret_cast<const char *
>(macaroon_loc), location_sz);
244 m_log.Emsg(
"Access",
"Macaroon is for incorrect location", location_str.c_str());
245 macaroon_verifier_destroy(verifier);
246 macaroon_destroy(macaroon);
247 return m_chain ? m_chain->Access(Entity, path, oper, env) :
XrdAccPriv_None;
250 if (macaroon_verify(verifier, macaroon,
251 reinterpret_cast<const unsigned char *
>(m_secret.c_str()),
256 m_log.Log(
LogMask::Debug,
"Access",
"Macaroon verification failed");
257 macaroon_verifier_destroy(verifier);
258 macaroon_destroy(macaroon);
259 return m_chain ? m_chain->Access(Entity, path, oper, env) :
XrdAccPriv_None;
261 macaroon_verifier_destroy(verifier);
263 const unsigned char *macaroon_id;
265 macaroon_identifier(macaroon, &macaroon_id, &id_sz);
267 std::string macaroon_id_str(
reinterpret_cast<const char *
>(macaroon_id), id_sz);
268 m_log.Log(
LogMask::Info,
"Access",
"Macaroon verification successful; ID", macaroon_id_str.c_str());
269 macaroon_destroy(macaroon);
272 if (Entity && check_helper.GetSecName().size()) {
273 const std::string &username = check_helper.GetSecName();
274 m_log.Log(
LogMask::Debug,
"Access",
"Setting the request name to", username.c_str());
275 Entity->
eaAPI->
Add(
"request.name", username,
true);
287 macaroon_returncode mac_err = MACAROON_SUCCESS;
288 std::unique_ptr<
struct macaroon, decltype(&macaroon_destroy)> macaroon(
289 macaroon_deserialize(token, &mac_err),
294 emsg =
"Failed to deserialize the token as a macaroon";
301 std::unique_ptr<
struct macaroon_verifier, decltype(&macaroon_verifier_destroy)> verifier(
302 macaroon_verifier_create(), &macaroon_verifier_destroy);
305 emsg =
"Internal error: failed to create a verifier.";
311 AuthzCheck check_helper(
"/",
AOP_Read, m_max_duration, m_log);
313 if (macaroon_verifier_satisfy_general(verifier.get(), AuthzCheck::verify_before_s, &check_helper, &mac_err) ||
314 macaroon_verifier_satisfy_general(verifier.get(), validate_verify_empty,
nullptr, &mac_err))
316 emsg =
"Failed to configure the verifier";
321 const unsigned char *macaroon_loc;
323 macaroon_location(macaroon.get(), &macaroon_loc, &location_sz);
324 if (strncmp(
reinterpret_cast<const char *
>(macaroon_loc), m_location.c_str(), location_sz))
326 emsg =
"Macaroon contains incorrect location: " +
327 std::string(
reinterpret_cast<const char *
>(macaroon_loc), location_sz);
328 m_log.Log(
LogMask::Warning,
"Validate",
emsg.c_str(), (
"all.sitename is " + m_location).c_str());
332 if (macaroon_verify(verifier.get(), macaroon.get(),
333 reinterpret_cast<const unsigned char *
>(m_secret.c_str()),
338 emsg =
"Macaroon verification error" + (check_helper.GetErrorMessage().size() ?
339 (
", " + check_helper.GetErrorMessage()) :
"");
344 const unsigned char *macaroon_id;
346 macaroon_identifier(macaroon.get(), &macaroon_id, &id_sz);
347 m_log.Log(
LogMask::Info,
"Validate", (
"Macaroon verification successful; ID " +
348 std::string(
reinterpret_cast<const char *
>(macaroon_id), id_sz)).c_str());
355 : m_max_duration(max_duration),
367 m_desired_activity =
"UPDATE_METADATA";
374 m_desired_activity =
"MANAGE";
379 m_desired_activity =
"UPLOAD";
382 m_desired_activity =
"DELETE";
385 m_desired_activity =
"DOWNLOAD";
388 m_desired_activity =
"LIST";
391 m_desired_activity =
"READ_METADATA";
401AuthzCheck::verify_before_s(
void *authz_ptr,
402 const unsigned char *pred,
405 return static_cast<AuthzCheck*
>(authz_ptr)->verify_before(pred, pred_sz);
410AuthzCheck::verify_activity_s(
void *authz_ptr,
411 const unsigned char *pred,
414 return static_cast<AuthzCheck*
>(authz_ptr)->verify_activity(pred, pred_sz);
419AuthzCheck::verify_path_s(
void *authz_ptr,
420 const unsigned char *pred,
423 return static_cast<AuthzCheck*
>(authz_ptr)->verify_path(pred, pred_sz);
428AuthzCheck::verify_name_s(
void *authz_ptr,
429 const unsigned char *pred,
432 return static_cast<AuthzCheck*
>(authz_ptr)->verify_name(pred, pred_sz);
437AuthzCheck::verify_before(
const unsigned char * pred,
size_t pred_sz)
439 std::string pred_str(
reinterpret_cast<const char *
>(pred), pred_sz);
440 if (strncmp(
"before:", pred_str.c_str(), 7))
444 m_log.Log(
LogMask::Debug,
"AuthzCheck",
"Checking macaroon for expiration; caveat:", pred_str.c_str());
447 if (strptime(&pred_str[7],
"%Y-%m-%dT%H:%M:%SZ", &caveat_tm) ==
nullptr)
449 m_emsg =
"Failed to parse time string: " + pred_str.substr(7);
453 caveat_tm.tm_isdst = -1;
455 time_t caveat_time = timegm(&caveat_tm);
456 if (-1 == caveat_time)
458 m_emsg =
"Failed to generate unix time: " + pred_str.substr(7);
462 if ((m_max_duration > 0) && (caveat_time > m_now + m_max_duration))
464 m_emsg =
"Max token age is greater than configured max duration; rejecting";
469 int result = (m_now >= caveat_time);
472 m_log.Log(
LogMask::Debug,
"AuthzCheck",
"Macaroon has not expired.");
476 m_emsg =
"Macaroon expired at " + pred_str.substr(7);
484AuthzCheck::verify_activity(
const unsigned char * pred,
size_t pred_sz)
486 if (!m_desired_activity.size()) {
return 1;}
487 std::string pred_str(
reinterpret_cast<const char *
>(pred), pred_sz);
488 if (strncmp(
"activity:", pred_str.c_str(), 9)) {
return 1;}
489 m_log.Log(
LogMask::Debug,
"AuthzCheck",
"running verify activity", pred_str.c_str());
491 std::stringstream ss(pred_str.substr(9));
492 for (std::string activity; std::getline(ss, activity,
','); )
495 if (m_desired_activity ==
"READ_METADATA") {
return 0;}
496 if ((activity == m_desired_activity) || ((m_desired_activity ==
"UPLOAD") && (activity ==
"MANAGE")))
498 m_log.Log(
LogMask::Debug,
"AuthzCheck",
"macaroon has desired activity", activity.c_str());
502 m_log.Log(
LogMask::Info,
"AuthzCheck",
"macaroon does NOT have desired activity", m_desired_activity.c_str());
508AuthzCheck::verify_path(
const unsigned char * pred,
size_t pred_sz)
510 std::string pred_str_raw(
reinterpret_cast<const char *
>(pred), pred_sz);
511 if (strncmp(
"path:", pred_str_raw.c_str(), 5)) {
return 1;}
513 m_log.Log(
LogMask::Debug,
"AuthzCheck",
"running verify path", pred_str.c_str());
515 if ((m_path.find(
"/./") != std::string::npos) ||
516 (m_path.find(
"/../") != std::string::npos))
518 m_log.Log(
LogMask::Info,
"AuthzCheck",
"invalid requested path", m_path.c_str());
529 m_log.Log(
LogMask::Debug,
"AuthzCheck",
"path request verified for", m_path.c_str());
538 const char *opName = (m_oper ==
AOP_Stat) ?
"READ_METADATA" :
"MKDIR";
540 (std::string(opName) + (is_subdir?
" Path request verified for" :
" Path request NOT allowed for")).c_str(),
545 m_log.Log(
LogMask::Debug,
"AuthzCheck",
"path request NOT allowed", m_path.c_str());
553AuthzCheck::verify_name(
const unsigned char * pred,
size_t pred_sz)
555 std::string pred_str(
reinterpret_cast<const char *
>(pred), pred_sz);
556 if (strncmp(
"name:", pred_str.c_str(), 5)) {
return 1;}
557 if (pred_str.size() < 6) {
return 1;}
558 m_log.Log(
LogMask::Debug,
"AuthzCheck",
"Verifying macaroon with", pred_str.c_str());
561 m_sec_name = pred_str.substr(5);
Access_Operation
The following are supported operations.
@ AOP_Delete
rm() or rmdir()
@ AOP_Update
open() r/w or append
@ AOP_Create
open() with create
@ AOP_Any
Special for getting privs.
@ AOP_Stat
exists(), stat()
@ AOP_Poll
stage polling operations
@ AOP_Rename
mv() for source
@ AOP_Read
open() r/o, prepare()
@ AOP_Excl_Create
open() with O_EXCL|O_CREAT
@ AOP_Insert
mv() for target
@ AOP_Stage
stage and or read data, plus related operations
@ AOP_Excl_Insert
mv() where destination doesn't exist.
static bool is_subdirectory(const std::string_view dir, const std::string_view subdir)
int emsg(int rc, char *msg)
virtual bool Validate(const char *token, std::string &emsg, long long *expT, XrdSecEntity *entP) override
Authz(XrdSysLogger *lp, const char *parms, XrdAccAuthorize *chain)
virtual XrdAccPrivs Access(const XrdSecEntity *Entity, const char *path, const Access_Operation oper, XrdOucEnv *env) override
static bool Config(const char *config, XrdOucEnv *env, XrdSysError *log, std::string &location, std::string &secret, ssize_t &max_duration, AuthzBehavior &behavior)
XrdAccAuthorize()
Constructor.
virtual XrdAccPrivs Access(const XrdSecEntity *Entity, const char *path, const Access_Operation oper, XrdOucEnv *Env=0)=0
char * Get(const char *varname)
bool Add(XrdSecAttr &attr)
int credslen
Length of the 'creds' data.
XrdSecEntityAttr * eaAPI
non-const API to attributes
char prot[XrdSecPROTOIDSIZE]
Auth protocol used (e.g. krb5)
char * creds
Raw entity credentials or cert.
std::string NormalizeSlashes(const std::string &)