XRootD
Macaroons::Handler Class Reference

#include <XrdMacaroonsHandler.hh>

+ Inheritance diagram for Macaroons::Handler:
+ Collaboration diagram for Macaroons::Handler:

Public Types

enum  AuthzBehavior {
  PASSTHROUGH ,
  ALLOW ,
  DENY
}
 

Public Member Functions

 Handler (XrdSysError *log, const char *config, XrdOucEnv *myEnv, XrdAccAuthorize *chain)
 
virtual ~Handler ()
 
virtual int Init (const char *cfgfile) override
 Initializes the external request handler. More...
 
virtual bool MatchesPath (const char *verb, const char *path) override
 Tells if the incoming path is recognized as one of the paths that have to be processed. More...
 
virtual int ProcessReq (XrdHttpExtReq &req) override
 
- Public Member Functions inherited from XrdHttpExtHandler
 XrdHttpExtHandler ()
 Constructor. More...
 
virtual ~XrdHttpExtHandler ()
 Destructor. More...
 

Static Public Member Functions

static bool Config (const char *config, XrdOucEnv *env, XrdSysError *log, std::string &location, std::string &secret, ssize_t &max_duration, AuthzBehavior &behavior)
 

Detailed Description

Definition at line 39 of file XrdMacaroonsHandler.hh.

Member Enumeration Documentation

◆ AuthzBehavior

Enumerator
PASSTHROUGH 
ALLOW 
DENY 

Definition at line 54 of file XrdMacaroonsHandler.hh.

Constructor & Destructor Documentation

◆ Handler()

Macaroons::Handler::Handler ( XrdSysError log,
const char *  config,
XrdOucEnv myEnv,
XrdAccAuthorize chain 
)
inline

Definition at line 41 of file XrdMacaroonsHandler.hh.

42  :
43  m_max_duration(86400),
44  m_chain(chain),
45  m_log(log)
46  {
47  AuthzBehavior behavior;
48  if (!Config(config, myEnv, m_log, m_location, m_secret, m_max_duration, behavior))
49  {
50  throw std::runtime_error("Macaroon handler config failed.");
51  }
52  }
static bool Config(const char *config, XrdOucEnv *env, XrdSysError *log, std::string &location, std::string &secret, ssize_t &max_duration, AuthzBehavior &behavior)

References Config().

+ Here is the call graph for this function:

◆ ~Handler()

Handler::~Handler ( )
virtual

Definition at line 132 of file XrdMacaroonsHandler.cc.

133 {
134  delete m_chain;
135 }

Member Function Documentation

◆ Config()

bool Handler::Config ( const char *  config,
XrdOucEnv env,
XrdSysError log,
std::string &  location,
std::string &  secret,
ssize_t &  max_duration,
AuthzBehavior behavior 
)
static

Definition at line 39 of file XrdMacaroonsConfigure.cc.

42 {
43  XrdOucStream config_obj(log, getenv("XRDINSTANCE"), env, "=====> ");
44 
45  // Open and attach the config file
46  //
47  int cfg_fd;
48  if ((cfg_fd = open(config, O_RDONLY, 0)) < 0) {
49  return log->Emsg("Config", errno, "open config file", config);
50  }
51  config_obj.Attach(cfg_fd);
52  static const char *cvec[] = { "*** macaroons plugin config:", 0 };
53  config_obj.Capture(cvec);
54 
55  // Set default mask for logging.
57 
58  // Set default maximum duration (24 hours).
59  max_duration = 24*3600;
60 
61  // Process items
62  //
63  char *orig_var, *var;
64  bool success = true, ismine;
65  while ((orig_var = config_obj.GetMyFirstWord())) {
66  var = orig_var;
67  if ((ismine = !strncmp("all.sitename", var, 12))) var += 4;
68  else if ((ismine = !strncmp("macaroons.", var, 10)) && var[10]) var += 10;
69 
70 
71 
72  if (!ismine) {continue;}
73 
74  if (!strcmp("secretkey", var)) {success = xsecretkey(config_obj, log, secret);}
75  else if (!strcmp("sitename", var)) {success = xsitename(config_obj, log, location);}
76  else if (!strcmp("trace", var)) {success = xtrace(config_obj, log);}
77  else if (!strcmp("maxduration", var)) {success = xmaxduration(config_obj, log, max_duration);}
78  else if (!strcmp("onmissing", var)) {success = xonmissing(config_obj, log, behavior);}
79  else {
80  log->Say("Config warning: ignoring unknown directive '", orig_var, "'.");
81  config_obj.Echo();
82  continue;
83  }
84  if (!success) {
85  config_obj.Echo();
86  break;
87  }
88  }
89 
90  if (success && !location.size())
91  {
92  log->Emsg("Config", "all.sitename must be specified to use macaroons.");
93  return false;
94  }
95 
96  return success;
97 }
static bool xonmissing(XrdOucStream &config_obj, XrdSysError *log, Handler::AuthzBehavior &behavior)
#define open
Definition: XrdPosix.hh:76
@ Error
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:95
void Say(const char *text1, const char *text2=0, const char *txt3=0, const char *text4=0, const char *text5=0, const char *txt6=0)
Definition: XrdSysError.cc:141
void setMsgMask(int mask)
Definition: XrdSysError.hh:154
@ Warning

References XrdOucStream::Attach(), XrdOucStream::Capture(), XrdOucStream::Echo(), XrdSysError::Emsg(), Error, XrdOucStream::GetMyFirstWord(), open, XrdSysError::Say(), XrdSysError::setMsgMask(), TPC::Warning, and xonmissing().

Referenced by Macaroons::Authz::Authz(), and Handler().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ Init()

virtual int Macaroons::Handler::Init ( const char *  cfgfile)
inlineoverridevirtual

Initializes the external request handler.

Implements XrdHttpExtHandler.

Definition at line 65 of file XrdMacaroonsHandler.hh.

65 {return 0;}

◆ MatchesPath()

bool Handler::MatchesPath ( const char *  verb,
const char *  path 
)
overridevirtual

Tells if the incoming path is recognized as one of the paths that have to be processed.

Implements XrdHttpExtHandler.

Definition at line 203 of file XrdMacaroonsHandler.cc.

204 {
205  return !strcmp(verb, "POST") || !strncmp(path, "/.well-known/", 13) ||
206  !strncmp(path, "/.oauth2/", 9);
207 }

◆ ProcessReq()

int Handler::ProcessReq ( XrdHttpExtReq )
overridevirtual

Process an HTTP request and send the response using the calling XrdHttpProtocol instance directly Returns 0 if ok, non0 if errors

Implements XrdHttpExtHandler.

Definition at line 373 of file XrdMacaroonsHandler.cc.

374 {
375  if (req.resource == "/.well-known/oauth-authorization-server") {
376  return ProcessOAuthConfig(req);
377  } else if (req.resource == "/.oauth2/token") {
378  return ProcessTokenRequest(req);
379  }
380 
381  auto header = XrdOucTUtils::caseInsensitiveFind(req.headers,"content-type");
382  if (header == req.headers.end())
383  {
384  return req.SendSimpleResp(400, NULL, NULL, "Content-Type missing; not a valid macaroon request?", 0);
385  }
386  if (header->second != "application/macaroon-request")
387  {
388  return req.SendSimpleResp(400, NULL, NULL, "Content-Type must be set to `application/macaroon-request' to request a macaroon", 0);
389  }
390  header = XrdOucTUtils::caseInsensitiveFind(req.headers,"content-length");
391  if (header == req.headers.end())
392  {
393  return req.SendSimpleResp(400, NULL, NULL, "Content-Length missing; not a valid POST", 0);
394  }
395  ssize_t blen;
396  try
397  {
398  blen = std::stoll(header->second);
399  }
400  catch (...)
401  {
402  return req.SendSimpleResp(400, NULL, NULL, "Content-Length not parseable.", 0);
403  }
404  if (blen <= 0)
405  {
406  return req.SendSimpleResp(400, NULL, NULL, "Content-Length has invalid value.", 0);
407  }
408  //for (const auto &header : req.headers) { printf("** Request header: %s=%s\n", header.first.c_str(), header.second.c_str()); }
409 
410  // request_data is not necessarily null-terminated; hence, we use the more advanced _ex variant
411  // of the tokener to avoid making a copy of the character buffer.
412  char *request_data;
413  if (req.BuffgetData(blen, &request_data, true) != blen)
414  {
415  return req.SendSimpleResp(400, NULL, NULL, "Missing or invalid body of request.", 0);
416  }
417  json_tokener *tokener = json_tokener_new();
418  if (!tokener)
419  {
420  return req.SendSimpleResp(500, NULL, NULL, "Internal error when allocating token parser.", 0);
421  }
422  json_object *macaroon_req = json_tokener_parse_ex(tokener, request_data, blen);
423  enum json_tokener_error err = json_tokener_get_error(tokener);
424  json_tokener_free(tokener);
425  if (err != json_tokener_success)
426  {
427  if (macaroon_req) json_object_put(macaroon_req);
428  return req.SendSimpleResp(400, NULL, NULL, "Invalid JSON serialization of macaroon request.", 0);
429  }
430  json_object *validity_obj;
431  if (!json_object_object_get_ex(macaroon_req, "validity", &validity_obj))
432  {
433  json_object_put(macaroon_req);
434  return req.SendSimpleResp(400, NULL, NULL, "JSON request does not include a `validity`", 0);
435  }
436  const char *validity_cstr = json_object_get_string(validity_obj);
437  if (!validity_cstr)
438  {
439  json_object_put(macaroon_req);
440  return req.SendSimpleResp(400, NULL, NULL, "validity key cannot be cast to a string", 0);
441  }
442  std::string validity_str(validity_cstr);
443  ssize_t validity = determine_validity(validity_str);
444  if (validity <= 0)
445  {
446  json_object_put(macaroon_req);
447  return req.SendSimpleResp(400, NULL, NULL, "Invalid ISO 8601 duration for validity key", 0);
448  }
449  json_object *caveats_obj;
450  std::vector<std::string> other_caveats;
451  if (json_object_object_get_ex(macaroon_req, "caveats", &caveats_obj))
452  {
453  if (json_object_is_type(caveats_obj, json_type_array))
454  { // Caveats were provided. Let's record them.
455  // TODO - could just add these in-situ. No need for the other_caveats vector.
456  int array_length = json_object_array_length(caveats_obj);
457  other_caveats.reserve(array_length);
458  for (int idx=0; idx<array_length; idx++)
459  {
460  json_object *caveat_item = json_object_array_get_idx(caveats_obj, idx);
461  if (caveat_item)
462  {
463  const char *caveat_item_str = json_object_get_string(caveat_item);
464  if (caveat_item_str && is_reserved_caveat(caveat_item_str)) {
465  json_object_put(macaroon_req);
466  return req.SendSimpleResp(400, NULL, NULL,
467  "Caveat uses a reserved predicate key (name:/path:/activity:/before:)", 0);
468  }
469  other_caveats.emplace_back(caveat_item_str);
470  }
471  }
472  }
473  }
474  json_object_put(macaroon_req);
475 
476  return GenerateMacaroonResponse(req, req.resource, other_caveats, validity, false);
477 }
static bool is_reserved_caveat(const std::string &cv)
static ssize_t determine_validity(const std::string &input)
static std::map< std::string, T >::const_iterator caseInsensitiveFind(const std::map< std::string, T > &m, const std::string &lowerCaseSearchKey)
Definition: XrdOucTUtils.hh:79

References XrdHttpExtReq::BuffgetData(), XrdOucTUtils::caseInsensitiveFind(), determine_validity(), XrdHttpExtReq::headers, is_reserved_caveat(), XrdHttpExtReq::resource, and XrdHttpExtReq::SendSimpleResp().

+ Here is the call graph for this function:

The documentation for this class was generated from the following files: