diff --git a/src/XrdMacaroons/XrdMacaroonsAuthz.cc b/src/XrdMacaroons/XrdMacaroonsAuthz.cc index 44625939417..c0d474ffa21 100644 --- a/src/XrdMacaroons/XrdMacaroonsAuthz.cc +++ b/src/XrdMacaroons/XrdMacaroonsAuthz.cc @@ -108,15 +108,34 @@ static XrdAccPrivs AddPriv(Access_Operation op, XrdAccPrivs privs) Authz::Authz(XrdSysLogger *log, char const *config, XrdAccAuthorize *chain) : m_max_duration(86400), m_chain(chain), - m_log(log, "macarons_") + m_log(log, "macarons_"), + m_authz_behavior(static_cast(Handler::AuthzBehavior::PASSTHROUGH)) { - if (!Handler::Config(config, nullptr, &m_log, m_location, m_secret, m_max_duration)) + Handler::AuthzBehavior behavior; + if (!Handler::Config(config, nullptr, &m_log, m_location, m_secret, m_max_duration, behavior)) { throw std::runtime_error("Macaroon authorization config failed."); } + m_authz_behavior = static_cast(behavior); } +XrdAccPrivs +Authz::OnMissing(const XrdSecEntity *Entity, const char *path, + const Access_Operation oper, XrdOucEnv *env) +{ + switch (m_authz_behavior) { + case Handler::AuthzBehavior::PASSTHROUGH: + return m_chain ? m_chain->Access(Entity, path, oper, env) : XrdAccPriv_None; + case Handler::AuthzBehavior::ALLOW: + return AddPriv(oper, XrdAccPriv_None);; + case Handler::AuthzBehavior::DENY: + return XrdAccPriv_None; + } + // Code should be unreachable. + return XrdAccPriv_None; +} + XrdAccPrivs Authz::Access(const XrdSecEntity *Entity, const char *path, const Access_Operation oper, XrdOucEnv *env) @@ -124,13 +143,28 @@ Authz::Access(const XrdSecEntity *Entity, const char *path, const char *authz = env ? env->Get("authz") : nullptr; // We don't allow any testing to occur in this authz module, preventing // a macaroon to be used to receive further macaroons. - if (!authz || strncmp(authz, "Bearer%20", 9) || oper == AOP_Any) + if (oper == AOP_Any) { - //m_log.Emsg("Access", "No bearer token present"); return m_chain ? m_chain->Access(Entity, path, oper, env) : XrdAccPriv_None; } + if (!authz || strncmp(authz, "Bearer%20", 9)) + { + //m_log.Emsg("Access", "No bearer token present"); + return OnMissing(Entity, path, oper, env); + } authz += 9; + macaroon_returncode mac_err = MACAROON_SUCCESS; + struct macaroon* macaroon = macaroon_deserialize( + authz, + &mac_err); + if (!macaroon) + { + // Do not log - might be other token type! + //m_log.Emsg("Access", "Failed to parse the macaroon"); + return OnMissing(Entity, path, oper, env); + } + struct macaroon_verifier *verifier = macaroon_verifier_create(); if (!verifier) { @@ -140,12 +174,12 @@ Authz::Access(const XrdSecEntity *Entity, const char *path, if (!path) { m_log.Emsg("Access", "Request with no provided path."); + macaroon_verifier_destroy(verifier); return XrdAccPriv_None; } AuthzCheck check_helper(path, oper, m_max_duration, m_log); - macaroon_returncode mac_err = MACAROON_SUCCESS; if (macaroon_verifier_satisfy_general(verifier, AuthzCheck::verify_before_s, &check_helper, &mac_err) || macaroon_verifier_satisfy_general(verifier, AuthzCheck::verify_activity_s, &check_helper, &mac_err) || macaroon_verifier_satisfy_general(verifier, AuthzCheck::verify_name_s, &check_helper, &mac_err) || @@ -156,16 +190,6 @@ Authz::Access(const XrdSecEntity *Entity, const char *path, return XrdAccPriv_None; } - struct macaroon* macaroon = macaroon_deserialize( - authz, - &mac_err); - if (!macaroon) - { - m_log.Emsg("Access", "Failed to parse the macaroon"); - macaroon_verifier_destroy(verifier); - return m_chain ? m_chain->Access(Entity, path, oper, env) : XrdAccPriv_None; - } - const unsigned char *macaroon_loc; size_t location_sz; macaroon_location(macaroon, &macaroon_loc, &location_sz); @@ -173,6 +197,7 @@ Authz::Access(const XrdSecEntity *Entity, const char *path, { m_log.Emsg("Access", "Macaroon is for incorrect location", reinterpret_cast(macaroon_loc)); macaroon_verifier_destroy(verifier); + macaroon_destroy(macaroon); return m_chain ? m_chain->Access(Entity, path, oper, env) : XrdAccPriv_None; } @@ -187,11 +212,15 @@ Authz::Access(const XrdSecEntity *Entity, const char *path, macaroon_destroy(macaroon); return m_chain ? m_chain->Access(Entity, path, oper, env) : XrdAccPriv_None; } + macaroon_verifier_destroy(verifier); + const unsigned char *macaroon_id; size_t id_sz; macaroon_identifier(macaroon, &macaroon_id, &id_sz); + std::string macaroon_id_str(reinterpret_cast(macaroon_id), id_sz); m_log.Log(LogMask::Info, "Access", "Macaroon verification successful; ID", macaroon_id_str.c_str()); + macaroon_destroy(macaroon); // Copy the name, if present into the macaroon, into the credential object. if (Entity && check_helper.GetSecName().size()) { diff --git a/src/XrdMacaroons/XrdMacaroonsAuthz.hh b/src/XrdMacaroons/XrdMacaroonsAuthz.hh index 7081f8d8912..4a9ac3d251d 100644 --- a/src/XrdMacaroons/XrdMacaroonsAuthz.hh +++ b/src/XrdMacaroons/XrdMacaroonsAuthz.hh @@ -34,11 +34,17 @@ public: } private: + XrdAccPrivs OnMissing(const XrdSecEntity *Entity, + const char *path, + const Access_Operation oper, + XrdOucEnv *env); + ssize_t m_max_duration; XrdAccAuthorize *m_chain; XrdSysError m_log; std::string m_secret; std::string m_location; + int m_authz_behavior; }; } diff --git a/src/XrdMacaroons/XrdMacaroonsConfigure.cc b/src/XrdMacaroons/XrdMacaroonsConfigure.cc index fccf8d25f9c..746140412e6 100644 --- a/src/XrdMacaroons/XrdMacaroonsConfigure.cc +++ b/src/XrdMacaroons/XrdMacaroonsConfigure.cc @@ -11,8 +11,32 @@ using namespace Macaroons; + +static bool xonmissing(XrdOucStream &config_obj, XrdSysError *log, Handler::AuthzBehavior &behavior) +{ + char *val = config_obj.GetWord(); + if (!val || !val[0]) + { + log->Emsg("Config", "macaroons.onmissing requires a value (valid values: passthrough [default], allow, deny)"); + return false; + } + if (!strcasecmp(val, "passthrough")) { + behavior = Handler::AuthzBehavior::PASSTHROUGH; + } else if (!strcasecmp(val, "allow")) { + behavior = Handler::AuthzBehavior::ALLOW; + } else if (!strcasecmp(val, "deny")) { + behavior = Handler::AuthzBehavior::DENY; + } else + { + log->Emsg("Config", "macaroons.onmissing is invalid (valid values: passthrough [default], allow, deny)! Provided value:", val); + return false; + } + return true; +} + bool Handler::Config(const char *config, XrdOucEnv *env, XrdSysError *log, - std::string &location, std::string &secret, ssize_t &max_duration) + std::string &location, std::string &secret, ssize_t &max_duration, + AuthzBehavior &behavior) { XrdOucStream config_obj(log, getenv("XRDINSTANCE"), env, "=====> "); @@ -47,6 +71,7 @@ bool Handler::Config(const char *config, XrdOucEnv *env, XrdSysError *log, else if (!strcmp("sitename", var)) {success = xsitename(config_obj, log, location);} else if (!strcmp("trace", var)) {success = xtrace(config_obj, log);} else if (!strcmp("maxduration", var)) {success = xmaxduration(config_obj, log, max_duration);} + else if (!strcmp("onmissing", var)) {success = xonmissing(config_obj, log, behavior);} else { log->Say("Config warning: ignoring unknown directive '", orig_var, "'."); config_obj.Echo(); diff --git a/src/XrdMacaroons/XrdMacaroonsHandler.hh b/src/XrdMacaroons/XrdMacaroonsHandler.hh index d75a0a260ce..6a2c95ae87d 100644 --- a/src/XrdMacaroons/XrdMacaroonsHandler.hh +++ b/src/XrdMacaroons/XrdMacaroonsHandler.hh @@ -29,12 +29,19 @@ public: m_chain(chain), m_log(log) { - if (!Config(config, myEnv, m_log, m_location, m_secret, m_max_duration)) + AuthzBehavior behavior; + if (!Config(config, myEnv, m_log, m_location, m_secret, m_max_duration, behavior)) { throw std::runtime_error("Macaroon handler config failed."); } } + enum AuthzBehavior { + PASSTHROUGH, + ALLOW, + DENY + }; + virtual ~Handler(); virtual bool MatchesPath(const char *verb, const char *path) override; @@ -45,7 +52,8 @@ public: // Static configuration method; made static to allow Authz object to reuse // this code. static bool Config(const char *config, XrdOucEnv *env, XrdSysError *log, - std::string &location, std::string &secret, ssize_t &max_duration); + std::string &location, std::string &secret, ssize_t &max_duration, + AuthzBehavior &behavior); private: std::string GenerateID(const std::string &, const XrdSecEntity &, const std::string &, const std::vector &, const std::string &);