From fc542df16c3b0d33b720fa0a9b4e4a5e231668e4 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Fri, 8 Jun 2018 14:59:31 -0500 Subject: [PATCH 01/29] [XrdMacaroons] Create skeleton of Macaroon issuer. This includes a simple XrdHttp external handler that intercepts POST requests and issues a minimal macaroon with a single caveat (based on the requested validity). Does not send a valid response, nor does it have any configuration that allows one to actually configure the symmetric key. --- CMakeLists.txt | 40 +++++++++ cmake/FindMacaroons.cmake | 21 +++++ cmake/FindXrootd.cmake | 51 ++++++++++++ configs/export-lib-symbols | 8 ++ src/handler.cpp | 163 +++++++++++++++++++++++++++++++++++++ src/handler.hh | 26 ++++++ src/macaroons.cpp | 41 ++++++++++ 7 files changed, 350 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 cmake/FindMacaroons.cmake create mode 100644 cmake/FindXrootd.cmake create mode 100644 configs/export-lib-symbols create mode 100644 src/handler.cpp create mode 100644 src/handler.hh create mode 100644 src/macaroons.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000000..972a0b2c0c0 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,40 @@ + +cmake_minimum_required( VERSION 2.8 ) +project( xrootd-macaroons ) + +set( CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake ) + +find_package( Xrootd REQUIRED ) +find_package( Macaroons REQUIRED ) + +include (FindPkgConfig) +pkg_check_modules(JSON REQUIRED json-c) + +macro(use_cxx11) + if (CMAKE_VERSION VERSION_LESS "3.1") + if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set (CMAKE_CXX_FLAGS "-std=gnu++11 ${CMAKE_CXX_FLAGS}") + endif () + else () + set (CMAKE_CXX_STANDARD 11) + endif () +endmacro(use_cxx11) +use_cxx11() + +if( CMAKE_COMPILER_IS_GNUCXX ) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror" ) +endif() +SET( CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined") +SET( CMAKE_MODULE_LINKER_FLAGS "-Wl,--no-undefined") + +include_directories(${MACAROONS_INCLUDES} ${XROOTD_INCLUDES} ${XROOTD_PRIVATE_INCLUDES} ${JSON_INCLUDE_DIRS}) + +add_library(XrdMacaroons SHARED src/macaroons.cpp src/handler.cpp) +target_link_libraries(XrdMacaroons -ldl ${XROOTD_UTILS_LIB} ${XROOTD_SERVER_LIB} ${MACAROONS_LIB} ${JSON_LIBRARIES} ${XROOTD_HTTP_LIB}) +set_target_properties(XrdMacaroons PROPERTIES OUTPUT_NAME XrdMacaroons-4 SUFFIX ".so" LINK_FLAGS "-Wl,--version-script=${CMAKE_SOURCE_DIR}/configs/export-lib-symbols") + +SET(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Install path for libraries") + +install( + TARGETS XrdMacaroons + LIBRARY DESTINATION ${LIB_INSTALL_DIR}) diff --git a/cmake/FindMacaroons.cmake b/cmake/FindMacaroons.cmake new file mode 100644 index 00000000000..204bf48f5df --- /dev/null +++ b/cmake/FindMacaroons.cmake @@ -0,0 +1,21 @@ + +FIND_PATH(MACAROONS_INCLUDES macaroons.h + HINTS + ${MACAROONS_DIR} + $ENV{MACAROONS_DIR} + /usr + PATH_SUFFIXES include +) + +FIND_LIBRARY(MACAROONS_LIB macaroons + HINTS + ${MACAROONS_DIR} + $ENV{MACAROONS_DIR} + /usr + PATH_SUFFIXES lib + PATH_SUFFIXES .libs +) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Macaroons DEFAULT_MSG MACAROONS_INCLUDES MACAROONS_LIB) + diff --git a/cmake/FindXrootd.cmake b/cmake/FindXrootd.cmake new file mode 100644 index 00000000000..308539f3269 --- /dev/null +++ b/cmake/FindXrootd.cmake @@ -0,0 +1,51 @@ + +FIND_PATH(XROOTD_INCLUDES XrdVersion.hh + HINTS + ${XROOTD_DIR} + $ENV{XROOTD_DIR} + /usr + /opt/xrootd/ + PATH_SUFFIXES include/xrootd + PATHS /opt/xrootd +) + +FIND_PATH(XROOTD_PRIVATE_INCLUDES XrdHttp/XrdHttpExtHandler.hh + HINTS + ${XROOTD_DIR} + $ENV{XROOTD_DIR} + /usr + /opt/xrootd/ + PATH_SUFFIXES include/xrootd/private + PATHS /opt/xrootd +) + +FIND_LIBRARY(XROOTD_UTILS_LIB XrdUtils + HINTS + ${XROOTD_DIR} + $ENV{XROOTD_DIR} + /usr + /opt/xrootd/ + PATH_SUFFIXES lib +) + +FIND_LIBRARY(XROOTD_SERVER_LIB XrdServer + HINTS + ${XROOTD_DIR} + $ENV{XROOTD_DIR} + /usr + /opt/xrootd/ + PATH_SUFFIXES lib +) + +FIND_LIBRARY(XROOTD_HTTP_LIB XrdHttp-4 + HINTS + ${XROOTD_DIR} + $ENV{XROOTD_DIR} + /usr + /opt/xrootd/ + PATH_SUFFIXES lib +) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Xrootd DEFAULT_MSG XROOTD_INCLUDES XROOTD_PRIVATE_INCLUDES XROOTD_UTILS_LIB XROOTD_SERVER_LIB XROOTD_HTTP_LIB) + diff --git a/configs/export-lib-symbols b/configs/export-lib-symbols new file mode 100644 index 00000000000..76a3ed9bb5d --- /dev/null +++ b/configs/export-lib-symbols @@ -0,0 +1,8 @@ +{ +global: + XrdAccAuthorizeObject*; + XrdHttpGetExtHandler*; + +local: + *; +}; diff --git a/src/handler.cpp b/src/handler.cpp new file mode 100644 index 00000000000..fd164f18f9e --- /dev/null +++ b/src/handler.cpp @@ -0,0 +1,163 @@ + +#include +#include +#include +#include + +#include "json.h" +#include "macaroons.h" + +#include "handler.hh" + +using namespace Macaroons; + +static +ssize_t determine_validity(const std::string& input) +{ + ssize_t duration = 0; + if (input.find("PT") != 0) + { + return -1; + } + size_t pos = 2; + std::string remaining = input; + do + { + remaining = remaining.substr(pos); + if (remaining.size() == 0) break; + long cur_duration; + try + { + cur_duration = stol(remaining, &pos); + } catch (...) + { + return -1; + } + if (pos >= remaining.size()) + { + return -1; + } + char unit = remaining[pos]; + switch (unit) { + case 'S': + break; + case 'M': + cur_duration *= 60; + break; + case 'H': + cur_duration *= 3600; + break; + default: + return -1; + }; + pos ++; + duration += cur_duration; + } while (1); + return duration; +} + +// See if the macaroon handler is interested in this request. +// We intercept all POST requests as we will be looking for a particular +// header. +bool +Handler::MatchesPath(const char *verb, const char *path) +{ + return !strcmp(verb, "POST"); +} + + +// Process a macaroon request. +int Handler::ProcessReq(XrdHttpExtReq &req) +{ + auto header = req.headers.find("Content-Type"); + if (header == req.headers.end()) + { + return req.SendSimpleResp(400, NULL, NULL, "Content-Type missing; not a valid macaroon request?", 0); + } + if (header->second != "application/macaroon-request") + { + return req.SendSimpleResp(400, NULL, NULL, "Content-Type must be set to `application/macaroon-request' to request a macaroon", 0); + } + header = req.headers.find("Content-Length"); + if (header == req.headers.end()) + { + return req.SendSimpleResp(400, NULL, NULL, "Content-Length missing; not a valid POST", 0); + } + ssize_t blen; + try + { + blen = std::stoll(header->second); + } + catch (...) + { + return req.SendSimpleResp(400, NULL, NULL, "Content-Length not parseable.", 0); + } + if (blen <= 0) + { + return req.SendSimpleResp(400, NULL, NULL, "Content-Length has invalid value.", 0); + } + //for (const auto &header : req.headers) { printf("** Request header: %s=%s\n", header.first.c_str(), header.second.c_str()); } + char *request_data; + if (req.BuffgetData(blen, &request_data, true) != blen) + { + return req.SendSimpleResp(400, NULL, NULL, "Missing or invalid body of request.", 0); + } + json_object *macaroon_req = json_tokener_parse(request_data); + if (!macaroon_req) + { + return req.SendSimpleResp(400, NULL, NULL, "Invalid JSON serialization of macaroon request.", 0); + } + json_object *validity_obj; + if (!json_object_object_get_ex(macaroon_req, "validity", &validity_obj)) + { + return req.SendSimpleResp(400, NULL, NULL, "JSON request does not include a `validity`", 0); + } + const char *validity_cstr = json_object_get_string(validity_obj); + if (!validity_cstr) + { + return req.SendSimpleResp(400, NULL, NULL, "validity key cannot be cast to a string", 0); + } + std::string validity_str(validity_cstr); + ssize_t validity = determine_validity(validity_str); + if (validity <= 0) + { + return req.SendSimpleResp(400, NULL, NULL, "Invalid ISO 8601 duration for validity key", 0); + } + time_t now; + time(&now); + now += validity; + char utc_time_buf[21]; + if (!strftime(utc_time_buf, 28, "before:%FT%TZ", gmtime(&now))) + { + return req.SendSimpleResp(500, NULL, NULL, "Internal error constructing UTC time", 0); + } + + std::string macaroon_id = "id1"; + enum macaroon_returncode mac_err; + + struct macaroon *mac = macaroon_create(reinterpret_cast(m_location.c_str()), + m_location.size(), + reinterpret_cast(m_secret.c_str()), + m_secret.size(), + reinterpret_cast(macaroon_id.c_str()), + macaroon_id.size(), &mac_err); + if (!mac) { + return req.SendSimpleResp(500, NULL, NULL, "Internal error constructing the macaroon", 0); + } + struct macaroon *mac_with_date = macaroon_add_first_party_caveat(mac, + reinterpret_cast(utc_time_buf), + strlen(utc_time_buf), + &mac_err); + macaroon_destroy(mac); + + size_t size_hint = macaroon_serialize_size_hint(mac_with_date, MACAROON_V1); + + std::vector macaroon_resp; macaroon_resp.reserve(size_hint); + if (!(size_hint = macaroon_serialize(mac_with_date, MACAROON_V1, reinterpret_cast(&macaroon_resp[0]), size_hint, &mac_err))) + { + return req.SendSimpleResp(500, NULL, NULL, "Internal error serializing macaroon", 0); + } + + return req.SendSimpleResp(500, NULL, NULL, &macaroon_resp[0], size_hint); +} + diff --git a/src/handler.hh b/src/handler.hh new file mode 100644 index 00000000000..9eb53f6c28d --- /dev/null +++ b/src/handler.hh @@ -0,0 +1,26 @@ + +#include + +#include "XrdHttp/XrdHttpExtHandler.hh" + +namespace Macaroons { + +class Handler : public XrdHttpExtHandler { +public: + Handler(XrdSysError *log, const char *config, XrdOucEnv *myEnv) : + m_location("test site"), + m_secret("top secret") + {} + virtual ~Handler() {} + + virtual bool MatchesPath(const char *verb, const char *path) override; + virtual int ProcessReq(XrdHttpExtReq &req) override; + + virtual int Init(const char *cfgfile) override {return 0;} + +private: + std::string m_location; + std::string m_secret; +}; + +} diff --git a/src/macaroons.cpp b/src/macaroons.cpp new file mode 100644 index 00000000000..ef8dcf8fd88 --- /dev/null +++ b/src/macaroons.cpp @@ -0,0 +1,41 @@ + +#include "handler.hh" + +#include "XrdSys/XrdSysLogger.hh" +#include "XrdHttp/XrdHttpExtHandler.hh" +#include "XrdAcc/XrdAccAuthorize.hh" +#include "XrdVersion.hh" + +XrdVERSIONINFO(XrdAccAuthorizeObject, XrdMacaroons); +XrdVERSIONINFO(XrdHttpGetExtHandler, XrdMacaroons); + +extern "C" { + +XrdAccAuthorize *XrdAccAuthorizeObject(XrdSysLogger *log, + const char *config, + const char *parm) +{ + return nullptr; +/* TODO: actually implement + std::unique_ptr def_authz(XrdAccDefaultAuthorizeObject(lp, cfn, parm, compiledVer)); + XrdAccMacaroons *authz{nullptr}; + authz = new XrdAccMacaroons(lp, parm, std::move(def_authz)); + return authz; +*/ +} + + +XrdHttpExtHandler *XrdHttpGetExtHandler(XrdSysError *log, const char * config, + const char * /*parms*/, XrdOucEnv *myEnv) +{ + log->Emsg("Initialize", "Creating new Macaroon handler object"); + return new Macaroons::Handler(log, config, myEnv); +/* TODO: actually implement + TPCHandler *retval{nullptr}; + retval = new TPCHandler(log, config, myEnv); + return retval; +*/ +} + + +} From 74eca6c29608e33103acb947e8557dc55d173262 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Fri, 8 Jun 2018 22:06:11 -0500 Subject: [PATCH 02/29] [XrdMacaroons] Implement generation of macaroon with activities. --- CMakeLists.txt | 5 +- src/handler.cpp | 139 +++++++++++++++++++++++++++++++++++++++++++++--- src/handler.hh | 10 ++++ 3 files changed, 144 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 972a0b2c0c0..ecdcb481339 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ find_package( Macaroons REQUIRED ) include (FindPkgConfig) pkg_check_modules(JSON REQUIRED json-c) +pkg_check_modules(UUID REQUIRED uuid) macro(use_cxx11) if (CMAKE_VERSION VERSION_LESS "3.1") @@ -27,10 +28,10 @@ endif() SET( CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined") SET( CMAKE_MODULE_LINKER_FLAGS "-Wl,--no-undefined") -include_directories(${MACAROONS_INCLUDES} ${XROOTD_INCLUDES} ${XROOTD_PRIVATE_INCLUDES} ${JSON_INCLUDE_DIRS}) +include_directories(${MACAROONS_INCLUDES} ${XROOTD_INCLUDES} ${XROOTD_PRIVATE_INCLUDES} ${JSON_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS}) add_library(XrdMacaroons SHARED src/macaroons.cpp src/handler.cpp) -target_link_libraries(XrdMacaroons -ldl ${XROOTD_UTILS_LIB} ${XROOTD_SERVER_LIB} ${MACAROONS_LIB} ${JSON_LIBRARIES} ${XROOTD_HTTP_LIB}) +target_link_libraries(XrdMacaroons -ldl ${XROOTD_UTILS_LIB} ${XROOTD_SERVER_LIB} ${MACAROONS_LIB} ${JSON_LIBRARIES} ${XROOTD_HTTP_LIB} ${UUID_LIBRARIES}) set_target_properties(XrdMacaroons PROPERTIES OUTPUT_NAME XrdMacaroons-4 SUFFIX ".so" LINK_FLAGS "-Wl,--version-script=${CMAKE_SOURCE_DIR}/configs/export-lib-symbols") SET(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Install path for libraries") diff --git a/src/handler.cpp b/src/handler.cpp index fd164f18f9e..91e3d5421fc 100644 --- a/src/handler.cpp +++ b/src/handler.cpp @@ -4,9 +4,15 @@ #include #include +#include "uuid.h" #include "json.h" #include "macaroons.h" +#include "XrdAcc/XrdAccPrivs.hh" +#include "XrdAcc/XrdAccAuthorize.hh" +#include "XrdSys/XrdSysError.hh" +#include "XrdSec/XrdSecEntity.hh" + #include "handler.hh" using namespace Macaroons; @@ -56,6 +62,47 @@ ssize_t determine_validity(const std::string& input) return duration; } + +std::string +Handler::GenerateID(const XrdSecEntity &entity, const std::string &activities, + const std::string &before) +{ + uuid_t uu; + uuid_generate_random(uu); + char uuid_buf[37]; + uuid_unparse(uu, uuid_buf); + std::string result(uuid_buf); + + std::stringstream ss; + ss << "ID=" << result << ", "; + if (entity.prot[0] != '\0') {ss << "protocol=" << entity.prot << ", ";} + if (entity.name) {ss << "name=" << entity.name << ", ";} + if (entity.host) {ss << "host=" << entity.host << ", ";} + if (entity.vorg) {ss << "vorg=" << entity.vorg << ", ";} + if (entity.role) {ss << "vorg=" << entity.role << ", ";} + if (entity.grps) {ss << "vorg=" << entity.grps << ", ";} + if (entity.endorsements) {ss << "vorg=" << entity.endorsements << ", ";} + if (activities.size()) {ss << "activities=" << activities << ", ";} + ss << "expires=" << before; + + m_log->Emsg("MacaroonGen", ss.str().c_str()); + return result; +} + +std::string +Handler::GenerateActivities(const XrdHttpExtReq & req) const +{ + std::string result = "activities:READ_METADATA,"; + // TODO - generate environment object that includes the Authorization header. + XrdAccPrivs privs = m_chain ? m_chain->Access(&req.GetSecEntity(), req.resource.c_str(), AOP_Any, NULL) : XrdAccPriv_None; + if ((privs & XrdAccPriv_Create) == XrdAccPriv_Create) {result += ",UPLOAD";} + if (privs & XrdAccPriv_Read) {result += ",DOWNLOAD";} + if (privs & XrdAccPriv_Delete) {result += ",DELETE";} + if ((privs & XrdAccPriv_Chown) == XrdAccPriv_Chown) {result += ",MANAGE,UPDATE_METADATA";} + if (privs & XrdAccPriv_Readdir) {result += ",LIST";} + return result; +} + // See if the macaroon handler is interested in this request. // We intercept all POST requests as we will be looking for a particular // header. @@ -127,12 +174,36 @@ int Handler::ProcessReq(XrdHttpExtReq &req) time(&now); now += validity; char utc_time_buf[21]; - if (!strftime(utc_time_buf, 28, "before:%FT%TZ", gmtime(&now))) + if (!strftime(utc_time_buf, 21, "%FT%TZ", gmtime(&now))) { return req.SendSimpleResp(500, NULL, NULL, "Internal error constructing UTC time", 0); } + std::string utc_time_str(utc_time_buf); + std::string utc_time_caveat = "before:" + std::string(utc_time_buf); + + json_object *caveats_obj; + std::vector other_caveats; + if (json_object_object_get_ex(macaroon_req, "caveats", &caveats_obj)) + { + if (json_object_is_type(caveats_obj, json_type_array)) + { // Caveats were provided. Let's record them. + // TODO - could just add these in-situ. No need for the other_caveats vector. + int array_length = json_object_array_length(caveats_obj); + other_caveats.reserve(array_length); + for (int idx=0; idx(m_location.c_str()), @@ -144,11 +215,48 @@ int Handler::ProcessReq(XrdHttpExtReq &req) if (!mac) { return req.SendSimpleResp(500, NULL, NULL, "Internal error constructing the macaroon", 0); } - struct macaroon *mac_with_date = macaroon_add_first_party_caveat(mac, - reinterpret_cast(utc_time_buf), - strlen(utc_time_buf), - &mac_err); + struct macaroon *mac_with_activities = macaroon_add_first_party_caveat(mac, + reinterpret_cast(activities.c_str()), + activities.size(), + &mac_err); macaroon_destroy(mac); + if (!mac_with_activities) + { + return req.SendSimpleResp(500, NULL, NULL, "Internal error adding default activities to macaroon", 0); + } + + for (const auto &caveat : other_caveats) + { + struct macaroon *mac_tmp = mac_with_activities; + mac_with_activities = macaroon_add_first_party_caveat(mac_tmp, + reinterpret_cast(caveat.c_str()), + caveat.size(), + &mac_err); + macaroon_destroy(mac_tmp); + if (!mac_with_activities) + { + return req.SendSimpleResp(500, NULL, NULL, "Internal error adding user caveat to macaroon", 0); + } + } + + std::string path_caveat = "path:" + req.resource; + struct macaroon *mac_with_path = macaroon_add_first_party_caveat(mac_with_activities, + reinterpret_cast(path_caveat.c_str()), + path_caveat.size(), + &mac_err); + macaroon_destroy(mac_with_activities); + if (!mac_with_path) { + return req.SendSimpleResp(500, NULL, NULL, "Internal error adding path to macaroon", 0); + } + + struct macaroon *mac_with_date = macaroon_add_first_party_caveat(mac_with_path, + reinterpret_cast(utc_time_caveat.c_str()), + strlen(utc_time_buf), + &mac_err); + macaroon_destroy(mac_with_path); + if (!mac_with_date) { + return req.SendSimpleResp(500, NULL, NULL, "Internal error adding date to macaroon", 0); + } size_t size_hint = macaroon_serialize_size_hint(mac_with_date, MACAROON_V1); @@ -157,7 +265,22 @@ int Handler::ProcessReq(XrdHttpExtReq &req) { return req.SendSimpleResp(500, NULL, NULL, "Internal error serializing macaroon", 0); } - - return req.SendSimpleResp(500, NULL, NULL, &macaroon_resp[0], size_hint); + + json_object *response_obj = json_object_new_object(); + if (!response_obj) + { + return req.SendSimpleResp(500, NULL, NULL, "Unable to create new JSON response object.", 0); + } + json_object *macaroon_obj = json_object_new_string_len(&macaroon_resp[0], size_hint); + if (!macaroon_obj) + { + return req.SendSimpleResp(500, NULL, NULL, "Unable to create a new JSON macaroon string.", 0); + } + json_object_object_add(response_obj, "macaroon", macaroon_obj); + + const char *macaroon_result = json_object_to_json_string_ext(response_obj, JSON_C_TO_STRING_PRETTY); + int retval = req.SendSimpleResp(200, NULL, NULL, macaroon_result, 0); + json_object_put(response_obj); + return retval; } diff --git a/src/handler.hh b/src/handler.hh index 9eb53f6c28d..35362517d76 100644 --- a/src/handler.hh +++ b/src/handler.hh @@ -1,13 +1,18 @@ #include +#include #include "XrdHttp/XrdHttpExtHandler.hh" +class XrdSecEntity; +class XrdAccAuthorize; + namespace Macaroons { class Handler : public XrdHttpExtHandler { public: Handler(XrdSysError *log, const char *config, XrdOucEnv *myEnv) : + m_log(log), m_location("test site"), m_secret("top secret") {} @@ -19,6 +24,11 @@ public: virtual int Init(const char *cfgfile) override {return 0;} private: + std::string GenerateID(const XrdSecEntity &, const std::string &, const std::string &); + std::string GenerateActivities(const XrdHttpExtReq &) const; + + std::unique_ptr m_chain; + XrdSysError *m_log; std::string m_location; std::string m_secret; }; From 798844666310ece4dca4d5a87ff64ef074dd048c Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Mon, 11 Jun 2018 22:56:01 -0500 Subject: [PATCH 03/29] [XrdMacaroons] Add support for configuring macaroons plugin. --- CMakeLists.txt | 7 ++- src/configure.cpp | 156 ++++++++++++++++++++++++++++++++++++++++++++++ src/handler.cpp | 6 ++ src/handler.hh | 24 +++++-- src/macaroons.cpp | 17 ++++- 5 files changed, 198 insertions(+), 12 deletions(-) create mode 100644 src/configure.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ecdcb481339..a7ea0909c54 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ find_package( Macaroons REQUIRED ) include (FindPkgConfig) pkg_check_modules(JSON REQUIRED json-c) pkg_check_modules(UUID REQUIRED uuid) +pkg_check_modules(LIBCRYPTO REQUIRED libcrypto) macro(use_cxx11) if (CMAKE_VERSION VERSION_LESS "3.1") @@ -28,10 +29,10 @@ endif() SET( CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined") SET( CMAKE_MODULE_LINKER_FLAGS "-Wl,--no-undefined") -include_directories(${MACAROONS_INCLUDES} ${XROOTD_INCLUDES} ${XROOTD_PRIVATE_INCLUDES} ${JSON_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS}) +include_directories(${MACAROONS_INCLUDES} ${XROOTD_INCLUDES} ${XROOTD_PRIVATE_INCLUDES} ${JSON_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS} ${LIBCRYPTO_INCLUDE_DIRS}) -add_library(XrdMacaroons SHARED src/macaroons.cpp src/handler.cpp) -target_link_libraries(XrdMacaroons -ldl ${XROOTD_UTILS_LIB} ${XROOTD_SERVER_LIB} ${MACAROONS_LIB} ${JSON_LIBRARIES} ${XROOTD_HTTP_LIB} ${UUID_LIBRARIES}) +add_library(XrdMacaroons SHARED src/macaroons.cpp src/handler.cpp src/configure.cpp) +target_link_libraries(XrdMacaroons -ldl ${XROOTD_UTILS_LIB} ${XROOTD_SERVER_LIB} ${MACAROONS_LIB} ${JSON_LIBRARIES} ${XROOTD_HTTP_LIB} ${UUID_LIBRARIES} ${LIBCRYPTO_LIBRARIES}) set_target_properties(XrdMacaroons PROPERTIES OUTPUT_NAME XrdMacaroons-4 SUFFIX ".so" LINK_FLAGS "-Wl,--version-script=${CMAKE_SOURCE_DIR}/configs/export-lib-symbols") SET(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Install path for libraries") diff --git a/src/configure.cpp b/src/configure.cpp new file mode 100644 index 00000000000..23aee205621 --- /dev/null +++ b/src/configure.cpp @@ -0,0 +1,156 @@ + +#include + +#include +#include + +#include + +#include "handler.hh" + + +using namespace Macaroons; + +#define TS_Xeq(x, m) (!strcmp(x, var)) success = m(config_obj) +bool Handler::Config(const char *config, XrdOucEnv *env) +{ + XrdOucStream config_obj(m_log, getenv("XRDINSTANCE"), env, "=====> "); + + // Open and attach the config file + // + int cfg_fd; + if ((cfg_fd = open(config, O_RDONLY, 0)) < 0) { + return m_log->Emsg("Config", errno, "open config file", config); + } + config_obj.Attach(cfg_fd); + + // Process items + // + char *orig_var, *var; + bool success = true, ismine; + while ((orig_var = config_obj.GetMyFirstWord())) { + var = orig_var; + if ((ismine = !strncmp("all.sitename", var, 12))) var += 4; + else if ((ismine = !strncmp("macaroons.", var, 10)) && var[10]) var += 10; + + + + if (!ismine) {continue;} + + if TS_Xeq("secretkey", xsecretkey); + else if TS_Xeq("sitename", xsitename); + else { + m_log->Say("Config warning: ignoring unknown directive '", orig_var, "'."); + config_obj.Echo(); + continue; + } + if (!success) { + config_obj.Echo(); + break; + } + } + + if (success && !m_location.size()) + { + m_log->Emsg("Config", "all.sitename must be specified to use macaroons."); + return false; + } + + return success; +} + + +bool Handler::xsitename(XrdOucStream &config_obj) +{ + char *val = config_obj.GetWord(); + if (!val || !val[0]) + { + m_log->Emsg("Config", "all.sitename requires a name"); + return false; + } + + m_location = val; + return true; +} + +bool Handler::xsecretkey(XrdOucStream &config_obj) +{ + char *val = config_obj.GetWord(); + if (!val || !val[0]) + { + m_log->Emsg("Config", "Shared secret key not specified"); + return false; + } + + FILE *fp = fopen(val, "r+"); + + if (fp == NULL) { + m_log->Emsg("Config", "Cannot open shared secret key file '", val, "'"); + m_log->Emsg("Config", "Cannot open shared secret key file. err: ", strerror(errno)); + return false; + } + + BIO *bio, *b64, *bio_out; + char inbuf[512]; + int inlen; + + b64 = BIO_new(BIO_f_base64()); + if (!b64) + { + m_log->Emsg("Config", "Failed to allocate base64 filter"); + return false; + } + bio = BIO_new_fp(fp, 0); // fp will be closed when BIO is freed. + if (!bio) + { + BIO_free_all(b64); + m_log->Emsg("Config", "Failed to allocate BIO filter"); + return false; + } + bio_out = BIO_new(BIO_s_mem()); + if (!bio_out) + { + BIO_free_all(b64); + BIO_free_all(bio); + m_log->Emsg("Config", "Failed to allocate BIO output"); + return false; + } + + BIO_push(b64, bio); + while ((inlen = BIO_read(b64, inbuf, 512)) > 0) + { + if (inlen < 0) { + if (errno == EINTR) continue; + break; + } else { + BIO_write(bio_out, inbuf, inlen); + } + } + if (inlen < 0) { + BIO_free_all(b64); + BIO_free_all(bio_out); + m_log->Emsg("Config", "Failure when reading secret key", strerror(errno)); + return false; + } + if (!BIO_flush(bio_out)) { + BIO_free_all(b64); + BIO_free_all(bio_out); + m_log->Emsg("Config", "Failure when flushing secret key", strerror(errno)); + return false; + } + + char *decoded; + long data_len = BIO_get_mem_data(bio_out, &decoded); + BIO_free_all(b64); + + m_secret = std::string(decoded, data_len); + + BIO_free_all(bio_out); + + if (m_secret.size() < 32) { + m_log->Emsg("Config", "Secret key is too short; must be 32 bytes long. Try running 'openssl rand -base64 -out", val, "64' to generate a new key"); + return false; + } + + return true; +} diff --git a/src/handler.cpp b/src/handler.cpp index 91e3d5421fc..fda99dea428 100644 --- a/src/handler.cpp +++ b/src/handler.cpp @@ -63,6 +63,12 @@ ssize_t determine_validity(const std::string& input) } +Handler::~Handler() +{ + delete m_chain; +} + + std::string Handler::GenerateID(const XrdSecEntity &entity, const std::string &activities, const std::string &before) diff --git a/src/handler.hh b/src/handler.hh index 35362517d76..f0672dc2693 100644 --- a/src/handler.hh +++ b/src/handler.hh @@ -1,9 +1,12 @@ #include #include +#include #include "XrdHttp/XrdHttpExtHandler.hh" +class XrdOucEnv; +class XrdOucStream; class XrdSecEntity; class XrdAccAuthorize; @@ -12,11 +15,16 @@ namespace Macaroons { class Handler : public XrdHttpExtHandler { public: Handler(XrdSysError *log, const char *config, XrdOucEnv *myEnv) : - m_log(log), - m_location("test site"), - m_secret("top secret") - {} - virtual ~Handler() {} + m_chain(nullptr), + m_log(log) + { + if (!Config(config, myEnv)) + { + throw std::runtime_error("Macaroon handler config failed."); + } + } + + virtual ~Handler(); virtual bool MatchesPath(const char *verb, const char *path) override; virtual int ProcessReq(XrdHttpExtReq &req) override; @@ -27,7 +35,11 @@ private: std::string GenerateID(const XrdSecEntity &, const std::string &, const std::string &); std::string GenerateActivities(const XrdHttpExtReq &) const; - std::unique_ptr m_chain; + bool Config(const char *config, XrdOucEnv *env); + bool xsecretkey(XrdOucStream &Config); + bool xsitename(XrdOucStream &Config); + + XrdAccAuthorize *m_chain; XrdSysError *m_log; std::string m_location; std::string m_secret; diff --git a/src/macaroons.cpp b/src/macaroons.cpp index ef8dcf8fd88..fad6a2c337d 100644 --- a/src/macaroons.cpp +++ b/src/macaroons.cpp @@ -1,4 +1,6 @@ +#include + #include "handler.hh" #include "XrdSys/XrdSysLogger.hh" @@ -25,11 +27,20 @@ XrdAccAuthorize *XrdAccAuthorizeObject(XrdSysLogger *log, } -XrdHttpExtHandler *XrdHttpGetExtHandler(XrdSysError *log, const char * config, - const char * /*parms*/, XrdOucEnv *myEnv) +XrdHttpExtHandler *XrdHttpGetExtHandler( + XrdSysError *log, const char * config, + const char * /*parms*/, XrdOucEnv *env) { log->Emsg("Initialize", "Creating new Macaroon handler object"); - return new Macaroons::Handler(log, config, myEnv); + try + { + return new Macaroons::Handler(log, config, env); + } + catch (std::runtime_error e) + { + log->Emsg("Config", "Generation of Macaroon handler failed", e.what()); + return nullptr; + } /* TODO: actually implement TPCHandler *retval{nullptr}; retval = new TPCHandler(log, config, myEnv); From da53ba11e2c6ebd999da735077d123bf5e4b0f48 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Mon, 11 Jun 2018 23:08:57 -0500 Subject: [PATCH 04/29] [XrdMacaroons] Add simple license and readme files. --- LGPL3.0.txt | 165 ++++++++++++++++++++++++++++++++++++++++++++++++++++ LICENSE | 15 +++++ README.md | 28 +++++++++ 3 files changed, 208 insertions(+) create mode 100644 LGPL3.0.txt create mode 100644 LICENSE create mode 100644 README.md diff --git a/LGPL3.0.txt b/LGPL3.0.txt new file mode 100644 index 00000000000..0a041280bd0 --- /dev/null +++ b/LGPL3.0.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000000..69922abe7ea --- /dev/null +++ b/LICENSE @@ -0,0 +1,15 @@ +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3.0 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +See LGPL3.0.txt next to this file for the text of the LGPL version 3.0. diff --git a/README.md b/README.md new file mode 100644 index 00000000000..2021f6a9b90 --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ + +Macaroon support for Xrootd +=========================== + +*WARNING*: This plugin is a work-in-progress and not all functionality described +is present. + +This plugin adds support for macaroon-style authorizations in XRootD, particularly +for the XrdHttp protocol implementation. + +To enable, you need to add three lines to the configuration file: + +``` +http.exthandler xrdmacaroons libXrdMacaroons.so +macaroons.secretkey /etc/xrootd/macaroon-secret +all.sitename Example_Site +``` + +You will need to change `all.sitename` accordingly. The secret key is a symmetric +key necessary to verify macaroons; the same key must be deployed to all XRootD +servers in your cluster. + +The secret key must be base64-encoded. The most straightforward way to generate +this is the following: + +``` +openssl rand -base64 -out /etc/xrootd/macaroon-secret 64 +``` From b0d438a05d1773d22703b0029ca4f06108af6673 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Tue, 12 Jun 2018 13:57:46 -0500 Subject: [PATCH 05/29] [XrdMacaroons] Add outlines of an XrdAccAuthorize implementation for Macaroons. --- src/authz.hh | 38 +++++++++++++++++++++++++++++++++++++ src/configure.cpp | 48 +++++++++++++++++++++++------------------------ src/handler.cpp | 16 +++++++++------- src/handler.hh | 16 ++++++++++------ src/macaroons.cpp | 38 +++++++++++++++++++++++++++---------- 5 files changed, 109 insertions(+), 47 deletions(-) create mode 100644 src/authz.hh diff --git a/src/authz.hh b/src/authz.hh new file mode 100644 index 00000000000..bd93f834c86 --- /dev/null +++ b/src/authz.hh @@ -0,0 +1,38 @@ + +#include "XrdAcc/XrdAccAuthorize.hh" +#include "XrdSys/XrdSysLogger.hh" + +namespace Macaroons +{ + +class Authz : public XrdAccAuthorize +{ +public: + Authz(XrdSysLogger *lp, const char *parms, XrdAccAuthorize *chain); + + virtual ~Authz() {} + + virtual XrdAccPrivs Access(const XrdSecEntity *Entity, + const char *path, + const Access_Operation oper, + XrdOucEnv *env); + + virtual int Audit(const int accok, const XrdSecEntity *Entity, + const char *path, const Access_Operation oper, + XrdOucEnv *Env) + { + return 0; + } + + virtual int Test(const XrdAccPrivs priv, + const Access_Operation oper) + { + return 0; + } + +private: + std::string m_secretkey; + std::string m_location; +}; + +} diff --git a/src/configure.cpp b/src/configure.cpp index 23aee205621..9d9acb91025 100644 --- a/src/configure.cpp +++ b/src/configure.cpp @@ -11,16 +11,16 @@ using namespace Macaroons; -#define TS_Xeq(x, m) (!strcmp(x, var)) success = m(config_obj) -bool Handler::Config(const char *config, XrdOucEnv *env) +bool Handler::Config(const char *config, XrdOucEnv *env, XrdSysError *log, + std::string &location, std::string &secret) { - XrdOucStream config_obj(m_log, getenv("XRDINSTANCE"), env, "=====> "); + XrdOucStream config_obj(log, getenv("XRDINSTANCE"), env, "=====> "); // Open and attach the config file // int cfg_fd; if ((cfg_fd = open(config, O_RDONLY, 0)) < 0) { - return m_log->Emsg("Config", errno, "open config file", config); + return log->Emsg("Config", errno, "open config file", config); } config_obj.Attach(cfg_fd); @@ -37,10 +37,10 @@ bool Handler::Config(const char *config, XrdOucEnv *env) if (!ismine) {continue;} - if TS_Xeq("secretkey", xsecretkey); - else if TS_Xeq("sitename", xsitename); + if (!strcmp("secretkey", var)) {success = xsecretkey(config_obj, log, secret);} + else if (!strcmp("sitename", var)) {success = xsitename(config_obj, log, location);} else { - m_log->Say("Config warning: ignoring unknown directive '", orig_var, "'."); + log->Say("Config warning: ignoring unknown directive '", orig_var, "'."); config_obj.Echo(); continue; } @@ -50,9 +50,9 @@ bool Handler::Config(const char *config, XrdOucEnv *env) } } - if (success && !m_location.size()) + if (success && !location.size()) { - m_log->Emsg("Config", "all.sitename must be specified to use macaroons."); + log->Emsg("Config", "all.sitename must be specified to use macaroons."); return false; } @@ -60,33 +60,33 @@ bool Handler::Config(const char *config, XrdOucEnv *env) } -bool Handler::xsitename(XrdOucStream &config_obj) +bool Handler::xsitename(XrdOucStream &config_obj, XrdSysError *log, std::string &location) { char *val = config_obj.GetWord(); if (!val || !val[0]) { - m_log->Emsg("Config", "all.sitename requires a name"); + log->Emsg("Config", "all.sitename requires a name"); return false; } - m_location = val; + location = val; return true; } -bool Handler::xsecretkey(XrdOucStream &config_obj) +bool Handler::xsecretkey(XrdOucStream &config_obj, XrdSysError *log, std::string &secret) { char *val = config_obj.GetWord(); if (!val || !val[0]) { - m_log->Emsg("Config", "Shared secret key not specified"); + log->Emsg("Config", "Shared secret key not specified"); return false; } FILE *fp = fopen(val, "r+"); if (fp == NULL) { - m_log->Emsg("Config", "Cannot open shared secret key file '", val, "'"); - m_log->Emsg("Config", "Cannot open shared secret key file. err: ", strerror(errno)); + log->Emsg("Config", "Cannot open shared secret key file '", val, "'"); + log->Emsg("Config", "Cannot open shared secret key file. err: ", strerror(errno)); return false; } @@ -97,14 +97,14 @@ bool Handler::xsecretkey(XrdOucStream &config_obj) b64 = BIO_new(BIO_f_base64()); if (!b64) { - m_log->Emsg("Config", "Failed to allocate base64 filter"); + log->Emsg("Config", "Failed to allocate base64 filter"); return false; } bio = BIO_new_fp(fp, 0); // fp will be closed when BIO is freed. if (!bio) { BIO_free_all(b64); - m_log->Emsg("Config", "Failed to allocate BIO filter"); + log->Emsg("Config", "Failed to allocate BIO filter"); return false; } bio_out = BIO_new(BIO_s_mem()); @@ -112,7 +112,7 @@ bool Handler::xsecretkey(XrdOucStream &config_obj) { BIO_free_all(b64); BIO_free_all(bio); - m_log->Emsg("Config", "Failed to allocate BIO output"); + log->Emsg("Config", "Failed to allocate BIO output"); return false; } @@ -129,13 +129,13 @@ bool Handler::xsecretkey(XrdOucStream &config_obj) if (inlen < 0) { BIO_free_all(b64); BIO_free_all(bio_out); - m_log->Emsg("Config", "Failure when reading secret key", strerror(errno)); + log->Emsg("Config", "Failure when reading secret key", strerror(errno)); return false; } if (!BIO_flush(bio_out)) { BIO_free_all(b64); BIO_free_all(bio_out); - m_log->Emsg("Config", "Failure when flushing secret key", strerror(errno)); + log->Emsg("Config", "Failure when flushing secret key", strerror(errno)); return false; } @@ -143,12 +143,12 @@ bool Handler::xsecretkey(XrdOucStream &config_obj) long data_len = BIO_get_mem_data(bio_out, &decoded); BIO_free_all(b64); - m_secret = std::string(decoded, data_len); + secret = std::string(decoded, data_len); BIO_free_all(bio_out); - if (m_secret.size() < 32) { - m_log->Emsg("Config", "Secret key is too short; must be 32 bytes long. Try running 'openssl rand -base64 -out", val, "64' to generate a new key"); + if (secret.size() < 32) { + log->Emsg("Config", "Secret key is too short; must be 32 bytes long. Try running 'openssl rand -base64 -out", val, "64' to generate a new key"); return false; } diff --git a/src/handler.cpp b/src/handler.cpp index fda99dea428..1a84b10844e 100644 --- a/src/handler.cpp +++ b/src/handler.cpp @@ -85,10 +85,10 @@ Handler::GenerateID(const XrdSecEntity &entity, const std::string &activities, if (entity.name) {ss << "name=" << entity.name << ", ";} if (entity.host) {ss << "host=" << entity.host << ", ";} if (entity.vorg) {ss << "vorg=" << entity.vorg << ", ";} - if (entity.role) {ss << "vorg=" << entity.role << ", ";} - if (entity.grps) {ss << "vorg=" << entity.grps << ", ";} - if (entity.endorsements) {ss << "vorg=" << entity.endorsements << ", ";} - if (activities.size()) {ss << "activities=" << activities << ", ";} + if (entity.role) {ss << "role=" << entity.role << ", ";} + if (entity.grps) {ss << "groups=" << entity.grps << ", ";} + if (entity.endorsements) {ss << "endorsements=" << entity.endorsements << ", ";} + if (activities.size()) {ss << "activity=" << activities << ", ";} ss << "expires=" << before; m_log->Emsg("MacaroonGen", ss.str().c_str()); @@ -98,7 +98,7 @@ Handler::GenerateID(const XrdSecEntity &entity, const std::string &activities, std::string Handler::GenerateActivities(const XrdHttpExtReq & req) const { - std::string result = "activities:READ_METADATA,"; + std::string result = "activity:READ_METADATA"; // TODO - generate environment object that includes the Authorization header. XrdAccPrivs privs = m_chain ? m_chain->Access(&req.GetSecEntity(), req.resource.c_str(), AOP_Any, NULL) : XrdAccPriv_None; if ((privs & XrdAccPriv_Create) == XrdAccPriv_Create) {result += ",UPLOAD";} @@ -185,7 +185,9 @@ int Handler::ProcessReq(XrdHttpExtReq &req) return req.SendSimpleResp(500, NULL, NULL, "Internal error constructing UTC time", 0); } std::string utc_time_str(utc_time_buf); - std::string utc_time_caveat = "before:" + std::string(utc_time_buf); + std::stringstream ss; + ss << "before:" << utc_time_str; + std::string utc_time_caveat = ss.str(); json_object *caveats_obj; std::vector other_caveats; @@ -257,7 +259,7 @@ int Handler::ProcessReq(XrdHttpExtReq &req) struct macaroon *mac_with_date = macaroon_add_first_party_caveat(mac_with_path, reinterpret_cast(utc_time_caveat.c_str()), - strlen(utc_time_buf), + utc_time_caveat.size(), &mac_err); macaroon_destroy(mac_with_path); if (!mac_with_date) { diff --git a/src/handler.hh b/src/handler.hh index f0672dc2693..03dea1a6f21 100644 --- a/src/handler.hh +++ b/src/handler.hh @@ -14,11 +14,12 @@ namespace Macaroons { class Handler : public XrdHttpExtHandler { public: - Handler(XrdSysError *log, const char *config, XrdOucEnv *myEnv) : - m_chain(nullptr), + Handler(XrdSysError *log, const char *config, XrdOucEnv *myEnv, + XrdAccAuthorize *chain) : + m_chain(chain), m_log(log) { - if (!Config(config, myEnv)) + if (!Config(config, myEnv, m_log, m_location, m_secret)) { throw std::runtime_error("Macaroon handler config failed."); } @@ -35,9 +36,12 @@ private: std::string GenerateID(const XrdSecEntity &, const std::string &, const std::string &); std::string GenerateActivities(const XrdHttpExtReq &) const; - bool Config(const char *config, XrdOucEnv *env); - bool xsecretkey(XrdOucStream &Config); - bool xsitename(XrdOucStream &Config); + // 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); + static bool xsecretkey(XrdOucStream &Config, XrdSysError *log, std::string &secret); + static bool xsitename(XrdOucStream &Config, XrdSysError *log, std::string &location); XrdAccAuthorize *m_chain; XrdSysError *m_log; diff --git a/src/macaroons.cpp b/src/macaroons.cpp index fad6a2c337d..f1e7c2c54f7 100644 --- a/src/macaroons.cpp +++ b/src/macaroons.cpp @@ -2,6 +2,7 @@ #include #include "handler.hh" +#include "authz.hh" #include "XrdSys/XrdSysLogger.hh" #include "XrdHttp/XrdHttpExtHandler.hh" @@ -11,30 +12,47 @@ XrdVERSIONINFO(XrdAccAuthorizeObject, XrdMacaroons); XrdVERSIONINFO(XrdHttpGetExtHandler, XrdMacaroons); +// Trick to access compiled version and directly call for the default object +// is taken from xrootd-scitokens. +static XrdVERSIONINFODEF(compiledVer, XrdAccTest, XrdVNUMBER, XrdVERSION); +extern XrdAccAuthorize *XrdAccDefaultAuthorizeObject(XrdSysLogger *lp, + const char *cfn, + const char *parm, + XrdVersionInfo &myVer); + + extern "C" { XrdAccAuthorize *XrdAccAuthorizeObject(XrdSysLogger *log, const char *config, - const char *parm) + const char *parms) { - return nullptr; -/* TODO: actually implement - std::unique_ptr def_authz(XrdAccDefaultAuthorizeObject(lp, cfn, parm, compiledVer)); - XrdAccMacaroons *authz{nullptr}; - authz = new XrdAccMacaroons(lp, parm, std::move(def_authz)); - return authz; -*/ + XrdAccAuthorize *def_authz = XrdAccDefaultAuthorizeObject(log, config, + parms, compiledVer); + try + { + return new Macaroons::Authz(log, config, def_authz); + } + catch (std::runtime_error e) + { + // TODO: Upgrade to XrdSysError + //log->Emsg("Config", "Configuration of Macaroon authorization handler failed", e.what()); + return nullptr; + } } XrdHttpExtHandler *XrdHttpGetExtHandler( XrdSysError *log, const char * config, - const char * /*parms*/, XrdOucEnv *env) + const char * parms, XrdOucEnv *env) { + XrdAccAuthorize *def_authz = XrdAccDefaultAuthorizeObject(log->logger(), + config, parms, compiledVer); + log->Emsg("Initialize", "Creating new Macaroon handler object"); try { - return new Macaroons::Handler(log, config, env); + return new Macaroons::Handler(log, config, env, def_authz); } catch (std::runtime_error e) { From d7d8fc973e255c5b597d74b0365ccba0ba7c9c4a Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Tue, 12 Jun 2018 23:02:38 -0500 Subject: [PATCH 06/29] [XrdMacaroons] Finish initial authorizor for macaroons. --- CMakeLists.txt | 2 +- src/authz.cpp | 316 +++++++++++++++++++++++++++++++++++++++++++++++++ src/authz.hh | 9 +- src/handler.hh | 9 +- 4 files changed, 329 insertions(+), 7 deletions(-) create mode 100644 src/authz.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a7ea0909c54..3e5e79ea15a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,7 +31,7 @@ SET( CMAKE_MODULE_LINKER_FLAGS "-Wl,--no-undefined") include_directories(${MACAROONS_INCLUDES} ${XROOTD_INCLUDES} ${XROOTD_PRIVATE_INCLUDES} ${JSON_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS} ${LIBCRYPTO_INCLUDE_DIRS}) -add_library(XrdMacaroons SHARED src/macaroons.cpp src/handler.cpp src/configure.cpp) +add_library(XrdMacaroons SHARED src/macaroons.cpp src/handler.cpp src/authz.cpp src/configure.cpp) target_link_libraries(XrdMacaroons -ldl ${XROOTD_UTILS_LIB} ${XROOTD_SERVER_LIB} ${MACAROONS_LIB} ${JSON_LIBRARIES} ${XROOTD_HTTP_LIB} ${UUID_LIBRARIES} ${LIBCRYPTO_LIBRARIES}) set_target_properties(XrdMacaroons PROPERTIES OUTPUT_NAME XrdMacaroons-4 SUFFIX ".so" LINK_FLAGS "-Wl,--version-script=${CMAKE_SOURCE_DIR}/configs/export-lib-symbols") diff --git a/src/authz.cpp b/src/authz.cpp new file mode 100644 index 00000000000..01ac03165cb --- /dev/null +++ b/src/authz.cpp @@ -0,0 +1,316 @@ + +#include +#include + +#include + +#include "macaroons.h" + +#include "XrdOuc/XrdOucEnv.hh" + +#include "handler.hh" +#include "authz.hh" + +using namespace Macaroons; + + +namespace { + +class AuthzCheck +{ +public: + AuthzCheck(const char *req_path, const Access_Operation req_oper, XrdSysError &log) + : m_log(log), + m_path(req_path), + m_oper(req_oper), + m_now(time(NULL)) + {} + + static int verify_before_s(void *authz_ptr, + const unsigned char *pred, + size_t pred_sz); + + static int verify_activity_s(void *authz_ptr, + const unsigned char *pred, + size_t pred_sz); + + static int verify_path_s(void *authz_ptr, + const unsigned char *pred, + size_t pred_sz); + +private: + int verify_before(const unsigned char *pred, size_t pred_sz); + int verify_activity(const unsigned char *pred, size_t pred_sz); + int verify_path(const unsigned char *pred, size_t pred_sz); + + XrdSysError &m_log; + const std::string m_path; + Access_Operation m_oper; + time_t m_now; +}; + + +static XrdAccPrivs AddPriv(Access_Operation op, XrdAccPrivs privs) +{ + int new_privs = privs; + switch (op) { + case AOP_Any: + break; + case AOP_Chmod: + new_privs |= static_cast(XrdAccPriv_Chmod); + break; + case AOP_Chown: + new_privs |= static_cast(XrdAccPriv_Chown); + break; + case AOP_Create: + new_privs |= static_cast(XrdAccPriv_Create); + break; + case AOP_Delete: + new_privs |= static_cast(XrdAccPriv_Delete); + break; + case AOP_Insert: + new_privs |= static_cast(XrdAccPriv_Insert); + break; + case AOP_Lock: + new_privs |= static_cast(XrdAccPriv_Lock); + break; + case AOP_Mkdir: + new_privs |= static_cast(XrdAccPriv_Mkdir); + break; + case AOP_Read: + new_privs |= static_cast(XrdAccPriv_Read); + break; + case AOP_Readdir: + new_privs |= static_cast(XrdAccPriv_Readdir); + break; + case AOP_Rename: + new_privs |= static_cast(XrdAccPriv_Rename); + break; + case AOP_Stat: + new_privs |= static_cast(XrdAccPriv_Lookup); + break; + case AOP_Update: + new_privs |= static_cast(XrdAccPriv_Update); + break; + }; + return static_cast(new_privs); +} + +} + + +Authz::Authz(XrdSysLogger *log, char const *config, XrdAccAuthorize *chain) + : m_chain(chain), + m_log(log, "macarons_") +{ + if (!Handler::Config(config, nullptr, &m_log, m_location, m_secret)) + { + throw std::runtime_error("Macaroon authorization config failed."); + } +} + + +XrdAccPrivs +Authz::Access(const XrdSecEntity *Entity, const char *path, + const Access_Operation oper, XrdOucEnv *env) +{ + 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) + { + //m_log.Emsg("Access", "No bearer token present"); + return m_chain ? m_chain->Access(Entity, path, oper, env) : XrdAccPriv_None; + } + authz += 9; + + struct macaroon_verifier *verifier = macaroon_verifier_create(); + if (!verifier) + { + m_log.Emsg("Access", "Failed to create a new macaroon verifier"); + return XrdAccPriv_None; + } + if (!path) + { + m_log.Emsg("Access", "Request with no provided path."); + return XrdAccPriv_None; + } + + AuthzCheck check_helper(path, oper, 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_path_s, &check_helper, &mac_err)) + { + m_log.Emsg("Access", "Failed to configure caveat verifier:", macaroon_error(mac_err)); + macaroon_verifier_destroy(verifier); + return XrdAccPriv_None; + } + + struct macaroon* macaroon = macaroon_deserialize( + reinterpret_cast(authz), + strlen(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; + } + + // TODO: check location matches our location + // TODO: record identifier into the log. + + if (macaroon_verify(verifier, macaroon, + reinterpret_cast(m_secret.c_str()), + m_secret.size(), + NULL, 0, // discharge macaroons + &mac_err)) + { + //m_log.Emsg("Access", "Macaroon verification failed:", macaroon_error(mac_err)); + macaroon_verifier_destroy(verifier); + macaroon_destroy(macaroon); + return m_chain ? m_chain->Access(Entity, path, oper, env) : XrdAccPriv_None; + } + //m_log.Emsg("Access", "Macaroon verification successful."); + + // We passed verification - give the correct privilege. + return AddPriv(oper, XrdAccPriv_None); +} + + +int +AuthzCheck::verify_before_s(void *authz_ptr, + const unsigned char *pred, + size_t pred_sz) +{ + return static_cast(authz_ptr)->verify_before(pred, pred_sz); +} + + +int +AuthzCheck::verify_activity_s(void *authz_ptr, + const unsigned char *pred, + size_t pred_sz) +{ + return static_cast(authz_ptr)->verify_activity(pred, pred_sz); +} + + +int +AuthzCheck::verify_path_s(void *authz_ptr, + const unsigned char *pred, + size_t pred_sz) +{ + return static_cast(authz_ptr)->verify_path(pred, pred_sz); +} + + +int +AuthzCheck::verify_before(const unsigned char * pred, size_t pred_sz) +{ + std::string pred_str(reinterpret_cast(pred), pred_sz); + if (strncmp("before:", pred_str.c_str(), 7)) + { + return 1; + } + //m_log.Emsg("AuthzCheck", "running verify before", pred_str.c_str()); + + struct tm caveat_tm; + if (strptime(&pred_str[7], "%Y-%m-%dT%H:%M:%SZ", &caveat_tm) == nullptr) + { + m_log.Emsg("AuthzCheck", "failed to parse time string", &pred_str[7]); + return 1; + } + caveat_tm.tm_isdst = -1; + + time_t caveat_time = timegm(&caveat_tm); + if (-1 == caveat_time) + { + m_log.Emsg("AuthzCheck", "failed to generate unix time", &pred_str[7]); + return 1; + } + int result = (m_now >= caveat_time); + //if (!result) m_log.Emsg("AuthzCheck", "verify before successful"); + //else m_log.Emsg("AuthzCheck", "verify before failed"); + return result; +} + + +int +AuthzCheck::verify_activity(const unsigned char * pred, size_t pred_sz) +{ + std::string pred_str(reinterpret_cast(pred), pred_sz); + if (strncmp("activity:", pred_str.c_str(), 9)) {return 1;} + //m_log.Emsg("AuthzCheck", "running verify activity", pred_str.c_str()); + + std::string desired_activity; + switch (m_oper) + { + case AOP_Any: + break; + case AOP_Chmod: + case AOP_Chown: + desired_activity = "UPDATE_METADATA"; + break; + case AOP_Insert: + case AOP_Lock: + case AOP_Mkdir: + case AOP_Rename: + case AOP_Update: + desired_activity = "MANAGE"; + break; + case AOP_Create: + desired_activity = "UPLOAD"; + break; + case AOP_Delete: + desired_activity = "DELETE"; + break; + case AOP_Read: + desired_activity = "DOWNLOAD"; + break; + case AOP_Readdir: + desired_activity = "LIST"; + break; + case AOP_Stat: + desired_activity = "READ_METADATA"; + }; + if (!desired_activity.size()) {return 1;} + + std::stringstream ss(pred_str.substr(9)); + for (std::string activity; std::getline(ss, activity, ','); ) + { + if (activity == desired_activity) + { + //m_log.Emsg("AuthzCheck", "macaroon has desired activity", activity.c_str()); + return 0; + } + } + //m_log.Emsg("AuthzCheck", "macaroon does NOT have desired activity", desired_activity.c_str()); + return 1; +} + + +int +AuthzCheck::verify_path(const unsigned char * pred, size_t pred_sz) +{ + std::string pred_str(reinterpret_cast(pred), pred_sz); + if (strncmp("path:", pred_str.c_str(), 5)) {return 1;} + //m_log.Emsg("AuthzCheck", "running verify path", pred_str.c_str()); + + if ((m_path.find("/./") != std::string::npos) || + (m_path.find("/../") != std::string::npos)) + { + m_log.Emsg("AuthzCheck", "invalid requested path", m_path.c_str()); + return 1; + } + size_t compare_chars = pred_str.size() - 5; + if (pred_str[compare_chars + 5 - 1] == '/') {compare_chars--;} + + int result = strncmp(pred_str.c_str() + 5, m_path.c_str(), compare_chars); + //if (!result) {m_log.Emsg("AuthzCheck", "path request verified for", m_path.c_str());} + //else {m_log.Emsg("AuthzCheck", "path request NOT allowed", m_path.c_str());} + + return result; +} diff --git a/src/authz.hh b/src/authz.hh index bd93f834c86..ef04c623de0 100644 --- a/src/authz.hh +++ b/src/authz.hh @@ -1,6 +1,9 @@ #include "XrdAcc/XrdAccAuthorize.hh" -#include "XrdSys/XrdSysLogger.hh" +#include "XrdSys/XrdSysError.hh" + + +class XrdSysError; namespace Macaroons { @@ -31,7 +34,9 @@ public: } private: - std::string m_secretkey; + XrdAccAuthorize *m_chain; + XrdSysError m_log; + std::string m_secret; std::string m_location; }; diff --git a/src/handler.hh b/src/handler.hh index 03dea1a6f21..86ff2438d2b 100644 --- a/src/handler.hh +++ b/src/handler.hh @@ -32,14 +32,15 @@ public: virtual int Init(const char *cfgfile) override {return 0;} -private: - std::string GenerateID(const XrdSecEntity &, const std::string &, const std::string &); - std::string GenerateActivities(const XrdHttpExtReq &) const; - // 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); + +private: + std::string GenerateID(const XrdSecEntity &, const std::string &, const std::string &); + std::string GenerateActivities(const XrdHttpExtReq &) const; + static bool xsecretkey(XrdOucStream &Config, XrdSysError *log, std::string &secret); static bool xsitename(XrdOucStream &Config, XrdSysError *log, std::string &location); From 62a4c1d204ff23f506d25f086b5a33326ea2db04 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Wed, 13 Jun 2018 21:42:25 -0500 Subject: [PATCH 07/29] [XrdMacaroons] Tweak behavior around READ_METADATA. - Any allowed activity in the token automatically implies READ_METADATA. - Stat requests on the parent path of an allowed path are allowed. --- src/authz.cpp | 105 +++++++++++++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 43 deletions(-) diff --git a/src/authz.cpp b/src/authz.cpp index 01ac03165cb..8f7174a841e 100644 --- a/src/authz.cpp +++ b/src/authz.cpp @@ -19,12 +19,7 @@ namespace { class AuthzCheck { public: - AuthzCheck(const char *req_path, const Access_Operation req_oper, XrdSysError &log) - : m_log(log), - m_path(req_path), - m_oper(req_oper), - m_now(time(NULL)) - {} + AuthzCheck(const char *req_path, const Access_Operation req_oper, XrdSysError &log); static int verify_before_s(void *authz_ptr, const unsigned char *pred, @@ -45,6 +40,7 @@ class AuthzCheck XrdSysError &m_log; const std::string m_path; + std::string m_desired_activity; Access_Operation m_oper; time_t m_now; }; @@ -180,6 +176,45 @@ Authz::Access(const XrdSecEntity *Entity, const char *path, } +AuthzCheck::AuthzCheck(const char *req_path, const Access_Operation req_oper, XrdSysError &log) + : m_log(log), + m_path(req_path), + m_oper(req_oper), + m_now(time(NULL)) +{ + switch (m_oper) + { + case AOP_Any: + break; + case AOP_Chmod: + case AOP_Chown: + m_desired_activity = "UPDATE_METADATA"; + break; + case AOP_Insert: + case AOP_Lock: + case AOP_Mkdir: + case AOP_Rename: + case AOP_Update: + m_desired_activity = "MANAGE"; + break; + case AOP_Create: + m_desired_activity = "UPLOAD"; + break; + case AOP_Delete: + m_desired_activity = "DELETE"; + break; + case AOP_Read: + m_desired_activity = "DOWNLOAD"; + break; + case AOP_Readdir: + m_desired_activity = "LIST"; + break; + case AOP_Stat: + m_desired_activity = "READ_METADATA"; + }; +} + + int AuthzCheck::verify_before_s(void *authz_ptr, const unsigned char *pred, @@ -241,53 +276,23 @@ AuthzCheck::verify_before(const unsigned char * pred, size_t pred_sz) int AuthzCheck::verify_activity(const unsigned char * pred, size_t pred_sz) { + if (!m_desired_activity.size()) {return 1;} std::string pred_str(reinterpret_cast(pred), pred_sz); if (strncmp("activity:", pred_str.c_str(), 9)) {return 1;} //m_log.Emsg("AuthzCheck", "running verify activity", pred_str.c_str()); - std::string desired_activity; - switch (m_oper) - { - case AOP_Any: - break; - case AOP_Chmod: - case AOP_Chown: - desired_activity = "UPDATE_METADATA"; - break; - case AOP_Insert: - case AOP_Lock: - case AOP_Mkdir: - case AOP_Rename: - case AOP_Update: - desired_activity = "MANAGE"; - break; - case AOP_Create: - desired_activity = "UPLOAD"; - break; - case AOP_Delete: - desired_activity = "DELETE"; - break; - case AOP_Read: - desired_activity = "DOWNLOAD"; - break; - case AOP_Readdir: - desired_activity = "LIST"; - break; - case AOP_Stat: - desired_activity = "READ_METADATA"; - }; - if (!desired_activity.size()) {return 1;} - std::stringstream ss(pred_str.substr(9)); for (std::string activity; std::getline(ss, activity, ','); ) { - if (activity == desired_activity) + // Any allowed activity also implies "READ_METADATA" + if (m_desired_activity == "READ_METADATA") {return 0;} + if (activity == m_desired_activity) { //m_log.Emsg("AuthzCheck", "macaroon has desired activity", activity.c_str()); return 0; } } - //m_log.Emsg("AuthzCheck", "macaroon does NOT have desired activity", desired_activity.c_str()); + //m_log.Emsg("AuthzCheck", "macaroon does NOT have desired activity", m_desired_activity.c_str()); return 1; } @@ -309,8 +314,22 @@ AuthzCheck::verify_path(const unsigned char * pred, size_t pred_sz) if (pred_str[compare_chars + 5 - 1] == '/') {compare_chars--;} int result = strncmp(pred_str.c_str() + 5, m_path.c_str(), compare_chars); - //if (!result) {m_log.Emsg("AuthzCheck", "path request verified for", m_path.c_str());} - //else {m_log.Emsg("AuthzCheck", "path request NOT allowed", m_path.c_str());} + if (!result) + { + //m_log.Emsg("AuthzCheck", "path request verified for", m_path.c_str()); + } + // READ_METADATA permission for /foo/bar automatically implies permission + // to READ_METADATA for /foo. + else if (m_oper == AOP_Stat) + { + result = strncmp(m_path.c_str(), pred_str.c_str() + 5, m_path.size()); + //if (!result) {m_log.Emsg("AuthzCheck", "READ_METADATA path request verified for", m_path.c_str());} + //else {m_log.Emsg("AuthzCheck", "READ_METADATA path request NOT allowed", m_path.c_str());} + } + else + { + //m_log.Emsg("AuthzCheck", "path request NOT allowed", m_path.c_str()); + } return result; } From 7510cc18ab6d4fb1ca2957e278f2c59e61265ef5 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Thu, 14 Jun 2018 21:20:52 -0500 Subject: [PATCH 08/29] [XrdMacaroons] Backport API use to libmacaroons 0.3.0. --- src/authz.cpp | 5 ++--- src/handler.cpp | 7 ++++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/authz.cpp b/src/authz.cpp index 8f7174a841e..1c587e4b129 100644 --- a/src/authz.cpp +++ b/src/authz.cpp @@ -139,14 +139,13 @@ Authz::Access(const XrdSecEntity *Entity, const char *path, macaroon_verifier_satisfy_general(verifier, AuthzCheck::verify_activity_s, &check_helper, &mac_err) || macaroon_verifier_satisfy_general(verifier, AuthzCheck::verify_path_s, &check_helper, &mac_err)) { - m_log.Emsg("Access", "Failed to configure caveat verifier:", macaroon_error(mac_err)); + m_log.Emsg("Access", "Failed to configure caveat verifier:"); macaroon_verifier_destroy(verifier); return XrdAccPriv_None; } struct macaroon* macaroon = macaroon_deserialize( - reinterpret_cast(authz), - strlen(authz), + authz, &mac_err); if (!macaroon) { diff --git a/src/handler.cpp b/src/handler.cpp index 1a84b10844e..3f40414d8c9 100644 --- a/src/handler.cpp +++ b/src/handler.cpp @@ -266,11 +266,12 @@ int Handler::ProcessReq(XrdHttpExtReq &req) return req.SendSimpleResp(500, NULL, NULL, "Internal error adding date to macaroon", 0); } - size_t size_hint = macaroon_serialize_size_hint(mac_with_date, MACAROON_V1); + size_t size_hint = macaroon_serialize_size_hint(mac_with_date); std::vector macaroon_resp; macaroon_resp.reserve(size_hint); - if (!(size_hint = macaroon_serialize(mac_with_date, MACAROON_V1, reinterpret_cast(&macaroon_resp[0]), size_hint, &mac_err))) + if (macaroon_serialize(mac_with_date, &macaroon_resp[0], size_hint, &mac_err)) { + printf("Returned macaroon_serialize code: %lu\n", size_hint); return req.SendSimpleResp(500, NULL, NULL, "Internal error serializing macaroon", 0); } @@ -279,7 +280,7 @@ int Handler::ProcessReq(XrdHttpExtReq &req) { return req.SendSimpleResp(500, NULL, NULL, "Unable to create new JSON response object.", 0); } - json_object *macaroon_obj = json_object_new_string_len(&macaroon_resp[0], size_hint); + json_object *macaroon_obj = json_object_new_string_len(&macaroon_resp[0], strlen(&macaroon_resp[0])); if (!macaroon_obj) { return req.SendSimpleResp(500, NULL, NULL, "Unable to create a new JSON macaroon string.", 0); From e1b4809722fbbd033940a2e30c7d6fd23460a019 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Fri, 15 Jun 2018 12:23:24 -0500 Subject: [PATCH 09/29] [XrdMacaroons] Update readme with some sample usage. --- README.md | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2021f6a9b90..a66113525f9 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,12 @@ Macaroon support for Xrootd =========================== -*WARNING*: This plugin is a work-in-progress and not all functionality described -is present. - This plugin adds support for macaroon-style authorizations in XRootD, particularly for the XrdHttp protocol implementation. +Configuration +============= + To enable, you need to add three lines to the configuration file: ``` @@ -26,3 +26,36 @@ this is the following: ``` openssl rand -base64 -out /etc/xrootd/macaroon-secret 64 ``` + +Usage +===== + +To generate a macaroon for personal use, you can run: + +``` +macaroon-init https://host.example.com//path/to/directory/ --validity 60 --activity DOWNLOAD,UPLOAD +``` + +(the `macaroon-init` CLI can be found as part of the `x509-scitokens-issuer-client` package). This +will generate a macaroon with 60 minutes of validity that has upload and download access to the path +specified at `/path/to/directory`, provided that your X509 identity has that access. + +The output will look like the following: + +``` +Querying https://host.example.com//path/to/directory/ for new token. +Validity: PT60M, activities: DOWNLOAD,UPLOAD,READ_METADATA. +Successfully generated a new token: +{ + "macaroon":"MDAxY2xvY2F0aW9uIFQyX1VTX05lYnJhc2thCjAwMzRpZGVudGlmaWVyIGMzODU3MjQ3LThjYzItNGI0YS04ZDUwLWNiZDYzN2U2MzJhMQowMDUyY2lkIGFjdGl2aXR5OlJFQURfTUVUQURBVEEsVVBMT0FELERPV05MT0FELERFTEVURSxNQU5BR0UsVVBEQVRFX01FVEFEQVRBLExJU1QKMDAyZmNpZCBhY3Rpdml0eTpET1dOTE9BRCxVUExPQUQsUkVBRF9NRVRBREFUQQowMDM2Y2lkIHBhdGg6L2hvbWUvY3NlNDk2L2Jib2NrZWxtL3RtcC94cm9vdGRfZXhwb3J0LwowMDI0Y2lkIGJlZm9yZToyMDE4LTA2LTE1VDE4OjE5OjI5WgowMDJmc2lnbmF0dXJlIFXI_x3v8Tq1jYcP-2WUvPV-BIewn5MHRODVu8UszyYkCg" +} +``` + +The contents of the `macaroon` key is your new security token. Anyone you share it with will be able to read and write from the same path. +You can use this token as a bearer token for HTTPS authorization. For example, it can authorize the following transfer: + +``` +curl -v + -H 'Authorization: Bearer MDAxY2xvY2F0aW9uIFQyX1VTX05lYnJhc2thCjAwMzRpZGVudGlmaWVyIGMzODU3MjQ3LThjYzItNGI0YS04ZDUwLWNiZDYzN2U2MzJhMQowMDUyY2lkIGFjdGl2aXR5OlJFQURfTUVUQURBVEEsVVBMT0FELERPV05MT0FELERFTEVURSxNQU5BR0UsVVBEQVRFX01FVEFEQVRBLExJU1QKMDAyZmNpZCBhY3Rpdml0eTpET1dOTE9BRCxVUExPQUQsUkVBRF9NRVRBREFUQQowMDM2Y2lkIHBhdGg6L2hvbWUvY3NlNDk2L2Jib2NrZWxtL3RtcC94cm9vdGRfZXhwb3J0LwowMDI0Y2lkIGJlZm9yZToyMDE4LTA2LTE1VDE4OjE5OjI5WgowMDJmc2lnbmF0dXJlIFXI_x3v8Tq1jYcP-2WUvPV-BIewn5MHRODVu8UszyYkCg' \ + https://host.example.com//path/to/directory/hello_world +``` From 4dd73249242ce2bb3fc4c74dc885ab46d1e5a964 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Fri, 15 Jun 2018 12:28:20 -0500 Subject: [PATCH 10/29] [XrdMacaroons] Create RPM packaging for macaroons plugin --- rpm/xrootd-macaroons.spec | 44 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 rpm/xrootd-macaroons.spec diff --git a/rpm/xrootd-macaroons.spec b/rpm/xrootd-macaroons.spec new file mode 100644 index 00000000000..2a50db9d5f3 --- /dev/null +++ b/rpm/xrootd-macaroons.spec @@ -0,0 +1,44 @@ + +Name: xrootd-macaroons +Version: 0.1.0 +Release: 1%{?dist} +Summary: Macaroons support for XRootD + +Group: System Environment/Daemons +License: LGPL +URL: https://github.com/bbockelm/xrootd-macaroons +# Generated from: +# git archive v%{version} --prefix=%{name}-%{version}/ | gzip -7 > ~/rpmbuild/SOURCES/%{name}-%{version}.tar.gz +Source0: %{name}-%{version}.tar.gz +BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) +BuildRequires: xrootd-devel +BuildRequires: xrootd-server-libs +BuildRequires: xrootd-server-devel +BuildRequires: xrootd-private-devel +BuildRequires: cmake +BuildRequires: gcc-c++ +BuildRequires: libcurl-devel +BuildRequires: libuuid-devel +BuildRequires: libmacaroons + +%description +%{summary} + +%prep +%setup -q + +%build +%cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo . +%make_build + +%install +%make_install + +%files +%defattr(-,root,root,-) +%{_libdir}/libXrdMacaroons-4.so + +%changelog +* Fri Jun 15 2018 Brian Bockelman - 0.1.0-1 +- Initial macaroons build. + From b34c0e00a358d9f687cf232feed1c66d82684a7c Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Fri, 15 Jun 2018 15:09:58 -0500 Subject: [PATCH 11/29] [XrdMacaroons] We need the development headers, not the runtime library. --- rpm/xrootd-macaroons.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpm/xrootd-macaroons.spec b/rpm/xrootd-macaroons.spec index 2a50db9d5f3..44aa3f64d2f 100644 --- a/rpm/xrootd-macaroons.spec +++ b/rpm/xrootd-macaroons.spec @@ -19,7 +19,7 @@ BuildRequires: cmake BuildRequires: gcc-c++ BuildRequires: libcurl-devel BuildRequires: libuuid-devel -BuildRequires: libmacaroons +BuildRequires: libmacaroons-devel %description %{summary} From 8411ff0915916fe8d037fb4be39506d9828f26c3 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Sat, 16 Jun 2018 22:04:09 -0500 Subject: [PATCH 12/29] [XrdMacaroons] Add missing build dependency on openssl. --- rpm/xrootd-macaroons.spec | 1 + 1 file changed, 1 insertion(+) diff --git a/rpm/xrootd-macaroons.spec b/rpm/xrootd-macaroons.spec index 44aa3f64d2f..f9f7a65d2af 100644 --- a/rpm/xrootd-macaroons.spec +++ b/rpm/xrootd-macaroons.spec @@ -20,6 +20,7 @@ BuildRequires: gcc-c++ BuildRequires: libcurl-devel BuildRequires: libuuid-devel BuildRequires: libmacaroons-devel +BuildRequires: openssl-devel %description %{summary} From cfd9580589fde225a5ad33f55f87df0ab5b32153 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Mon, 18 Jun 2018 09:06:31 -0500 Subject: [PATCH 13/29] [XrdMacaroons] Add missing build dep on json-c-devel. --- rpm/xrootd-macaroons.spec | 1 + 1 file changed, 1 insertion(+) diff --git a/rpm/xrootd-macaroons.spec b/rpm/xrootd-macaroons.spec index f9f7a65d2af..4788fe027bf 100644 --- a/rpm/xrootd-macaroons.spec +++ b/rpm/xrootd-macaroons.spec @@ -21,6 +21,7 @@ BuildRequires: libcurl-devel BuildRequires: libuuid-devel BuildRequires: libmacaroons-devel BuildRequires: openssl-devel +BuildRequires: json-c-devel %description %{summary} From 42ae5be116b55c37d46f55f822bba291ee2a7d8e Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Mon, 18 Jun 2018 10:48:27 -0500 Subject: [PATCH 14/29] [XrdMacaroons] Open secret file with correct mode. --- src/configure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/configure.cpp b/src/configure.cpp index 9d9acb91025..7c740cdaa7b 100644 --- a/src/configure.cpp +++ b/src/configure.cpp @@ -82,7 +82,7 @@ bool Handler::xsecretkey(XrdOucStream &config_obj, XrdSysError *log, std::string return false; } - FILE *fp = fopen(val, "r+"); + FILE *fp = fopen(val, "rb"); if (fp == NULL) { log->Emsg("Config", "Cannot open shared secret key file '", val, "'"); From 51fe980d73d4c140aedb2c14c26e334923f6b758 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Sun, 8 Jul 2018 02:02:31 -0500 Subject: [PATCH 15/29] [XrdMacaroons] Cleanup TODO logging items. --- src/macaroons.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/macaroons.cpp b/src/macaroons.cpp index f1e7c2c54f7..f87adcd1c36 100644 --- a/src/macaroons.cpp +++ b/src/macaroons.cpp @@ -4,6 +4,7 @@ #include "handler.hh" #include "authz.hh" +#include "XrdSys/XrdSysError.hh" #include "XrdSys/XrdSysLogger.hh" #include "XrdHttp/XrdHttpExtHandler.hh" #include "XrdAcc/XrdAccAuthorize.hh" @@ -35,8 +36,8 @@ XrdAccAuthorize *XrdAccAuthorizeObject(XrdSysLogger *log, } catch (std::runtime_error e) { - // TODO: Upgrade to XrdSysError - //log->Emsg("Config", "Configuration of Macaroon authorization handler failed", e.what()); + XrdSysError err(log, "macaroons"); + err.Emsg("Config", "Configuration of Macaroon authorization handler failed", e.what()); return nullptr; } } @@ -59,11 +60,6 @@ XrdHttpExtHandler *XrdHttpGetExtHandler( log->Emsg("Config", "Generation of Macaroon handler failed", e.what()); return nullptr; } -/* TODO: actually implement - TPCHandler *retval{nullptr}; - retval = new TPCHandler(log, config, myEnv); - return retval; -*/ } From a1ec4502ac85485044fd35346a3238d381fdf33f Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Sun, 8 Jul 2018 02:02:47 -0500 Subject: [PATCH 16/29] [XrdMacaroons] Serialize the XrdSecEntity name field in macaroon. This allows the XrdSecEntity name to be set correctly before invocation of the various filesystem plugins. --- src/authz.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ src/handler.cpp | 26 ++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/authz.cpp b/src/authz.cpp index 1c587e4b129..ff5aeabe593 100644 --- a/src/authz.cpp +++ b/src/authz.cpp @@ -7,6 +7,7 @@ #include "macaroons.h" #include "XrdOuc/XrdOucEnv.hh" +#include "XrdSec/XrdSecEntity.hh" #include "handler.hh" #include "authz.hh" @@ -21,6 +22,8 @@ class AuthzCheck public: AuthzCheck(const char *req_path, const Access_Operation req_oper, XrdSysError &log); + const std::string &GetSecName() const {return m_sec_name;} + static int verify_before_s(void *authz_ptr, const unsigned char *pred, size_t pred_sz); @@ -33,14 +36,20 @@ class AuthzCheck const unsigned char *pred, size_t pred_sz); + static int verify_name_s(void *authz_ptr, + const unsigned char *pred, + size_t pred_sz); + private: int verify_before(const unsigned char *pred, size_t pred_sz); int verify_activity(const unsigned char *pred, size_t pred_sz); int verify_path(const unsigned char *pred, size_t pred_sz); + int verify_name(const unsigned char *pred, size_t pred_sz); XrdSysError &m_log; const std::string m_path; std::string m_desired_activity; + std::string m_sec_name; Access_Operation m_oper; time_t m_now; }; @@ -137,6 +146,7 @@ Authz::Access(const XrdSecEntity *Entity, const char *path, 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) || macaroon_verifier_satisfy_general(verifier, AuthzCheck::verify_path_s, &check_helper, &mac_err)) { m_log.Emsg("Access", "Failed to configure caveat verifier:"); @@ -170,6 +180,14 @@ Authz::Access(const XrdSecEntity *Entity, const char *path, } //m_log.Emsg("Access", "Macaroon verification successful."); + // Copy the name, if present into the macaroon, into the credential object. + if (Entity && check_helper.GetSecName().size()) { + //m_log.Emsg("Access", "Setting the security name to", check_helper.GetSecName().c_str()); + XrdSecEntity &myEntity = *const_cast(Entity); + if (myEntity.name) {free(myEntity.name);} + myEntity.name = strdup(check_helper.GetSecName().c_str()); + } + // We passed verification - give the correct privilege. return AddPriv(oper, XrdAccPriv_None); } @@ -241,6 +259,15 @@ AuthzCheck::verify_path_s(void *authz_ptr, } +int +AuthzCheck::verify_name_s(void *authz_ptr, + const unsigned char *pred, + size_t pred_sz) +{ + return static_cast(authz_ptr)->verify_name(pred, pred_sz); +} + + int AuthzCheck::verify_before(const unsigned char * pred, size_t pred_sz) { @@ -332,3 +359,18 @@ AuthzCheck::verify_path(const unsigned char * pred, size_t pred_sz) return result; } + + +int +AuthzCheck::verify_name(const unsigned char * pred, size_t pred_sz) +{ + std::string pred_str(reinterpret_cast(pred), pred_sz); + if (strncmp("name:", pred_str.c_str(), 5)) {return 1;} + if (pred_str.size() < 6) {return 1;} + //m_log.Emsg("AuthzCheck", "Verifying macaroon with", pred_str.c_str()); + + // Make a copy of the name for the XrdSecEntity; this will be used later. + m_sec_name = pred_str.substr(5); + + return 0; +} diff --git a/src/handler.cpp b/src/handler.cpp index 3f40414d8c9..345869df3ad 100644 --- a/src/handler.cpp +++ b/src/handler.cpp @@ -223,16 +223,38 @@ int Handler::ProcessReq(XrdHttpExtReq &req) if (!mac) { return req.SendSimpleResp(500, NULL, NULL, "Internal error constructing the macaroon", 0); } - struct macaroon *mac_with_activities = macaroon_add_first_party_caveat(mac, + + // Embed the SecEntity name, if present. + struct macaroon *mac_with_name; + const char * sec_name = req.GetSecEntity().name; + if (sec_name) { + std::stringstream name_caveat_ss; + name_caveat_ss << "name:" << sec_name; + std::string name_caveat = name_caveat_ss.str(); + mac_with_name = macaroon_add_first_party_caveat(mac, + reinterpret_cast(name_caveat.c_str()), + name_caveat.size(), + &mac_err); + macaroon_destroy(mac); + } else { + mac_with_name = mac; + } + if (!mac_with_name) + { + return req.SendSimpleResp(500, NULL, NULL, "Internal error adding default activities to macaroon", 0); + } + + struct macaroon *mac_with_activities = macaroon_add_first_party_caveat(mac_with_name, reinterpret_cast(activities.c_str()), activities.size(), &mac_err); - macaroon_destroy(mac); + macaroon_destroy(mac_with_name); if (!mac_with_activities) { return req.SendSimpleResp(500, NULL, NULL, "Internal error adding default activities to macaroon", 0); } + for (const auto &caveat : other_caveats) { struct macaroon *mac_tmp = mac_with_activities; From 3366ac7c20cd7a6924b9a532e86a756d4581515a Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Sun, 8 Jul 2018 20:29:49 -0500 Subject: [PATCH 17/29] [XrdMacaroons] Add multiple tracing levels to the module's logging. Provides reasonable control of what log messages are emitted at runtime. --- src/authz.cpp | 30 +++++++++++++-------------- src/configure.cpp | 52 +++++++++++++++++++++++++++++++++++++++++++++++ src/handler.hh | 9 ++++++++ 3 files changed, 76 insertions(+), 15 deletions(-) diff --git a/src/authz.cpp b/src/authz.cpp index ff5aeabe593..b4eb703fad9 100644 --- a/src/authz.cpp +++ b/src/authz.cpp @@ -276,12 +276,12 @@ AuthzCheck::verify_before(const unsigned char * pred, size_t pred_sz) { return 1; } - //m_log.Emsg("AuthzCheck", "running verify before", pred_str.c_str()); + m_log.Log(LogMask::Debug, "AuthzCheck", "running verify before", pred_str.c_str()); struct tm caveat_tm; if (strptime(&pred_str[7], "%Y-%m-%dT%H:%M:%SZ", &caveat_tm) == nullptr) { - m_log.Emsg("AuthzCheck", "failed to parse time string", &pred_str[7]); + m_log.Log(LogMask::Debug, "AuthzCheck", "failed to parse time string", &pred_str[7]); return 1; } caveat_tm.tm_isdst = -1; @@ -289,12 +289,12 @@ AuthzCheck::verify_before(const unsigned char * pred, size_t pred_sz) time_t caveat_time = timegm(&caveat_tm); if (-1 == caveat_time) { - m_log.Emsg("AuthzCheck", "failed to generate unix time", &pred_str[7]); + m_log.Log(LogMask::Debug, "AuthzCheck", "failed to generate unix time", &pred_str[7]); return 1; } int result = (m_now >= caveat_time); - //if (!result) m_log.Emsg("AuthzCheck", "verify before successful"); - //else m_log.Emsg("AuthzCheck", "verify before failed"); + if (!result) m_log.Log(LogMask::Debug, "AuthzCheck", "verify before successful"); + else m_log.Log(LogMask::Debug, "AuthzCheck", "verify before failed"); return result; } @@ -305,7 +305,7 @@ AuthzCheck::verify_activity(const unsigned char * pred, size_t pred_sz) if (!m_desired_activity.size()) {return 1;} std::string pred_str(reinterpret_cast(pred), pred_sz); if (strncmp("activity:", pred_str.c_str(), 9)) {return 1;} - //m_log.Emsg("AuthzCheck", "running verify activity", pred_str.c_str()); + m_log.Log(LogMask::Debug, "AuthzCheck", "running verify activity", pred_str.c_str()); std::stringstream ss(pred_str.substr(9)); for (std::string activity; std::getline(ss, activity, ','); ) @@ -314,11 +314,11 @@ AuthzCheck::verify_activity(const unsigned char * pred, size_t pred_sz) if (m_desired_activity == "READ_METADATA") {return 0;} if (activity == m_desired_activity) { - //m_log.Emsg("AuthzCheck", "macaroon has desired activity", activity.c_str()); + m_log.Log(LogMask::Debug, "AuthzCheck", "macaroon has desired activity", activity.c_str()); return 0; } } - //m_log.Emsg("AuthzCheck", "macaroon does NOT have desired activity", m_desired_activity.c_str()); + m_log.Log(LogMask::Info, "AuthzCheck", "macaroon does NOT have desired activity", m_desired_activity.c_str()); return 1; } @@ -328,12 +328,12 @@ AuthzCheck::verify_path(const unsigned char * pred, size_t pred_sz) { std::string pred_str(reinterpret_cast(pred), pred_sz); if (strncmp("path:", pred_str.c_str(), 5)) {return 1;} - //m_log.Emsg("AuthzCheck", "running verify path", pred_str.c_str()); + m_log.Log(LogMask::Debug, "AuthzCheck", "running verify path", pred_str.c_str()); if ((m_path.find("/./") != std::string::npos) || (m_path.find("/../") != std::string::npos)) { - m_log.Emsg("AuthzCheck", "invalid requested path", m_path.c_str()); + m_log.Log(LogMask::Info, "AuthzCheck", "invalid requested path", m_path.c_str()); return 1; } size_t compare_chars = pred_str.size() - 5; @@ -342,19 +342,19 @@ AuthzCheck::verify_path(const unsigned char * pred, size_t pred_sz) int result = strncmp(pred_str.c_str() + 5, m_path.c_str(), compare_chars); if (!result) { - //m_log.Emsg("AuthzCheck", "path request verified for", m_path.c_str()); + m_log.Log(LogMask::Debug, "AuthzCheck", "path request verified for", m_path.c_str()); } // READ_METADATA permission for /foo/bar automatically implies permission // to READ_METADATA for /foo. else if (m_oper == AOP_Stat) { result = strncmp(m_path.c_str(), pred_str.c_str() + 5, m_path.size()); - //if (!result) {m_log.Emsg("AuthzCheck", "READ_METADATA path request verified for", m_path.c_str());} - //else {m_log.Emsg("AuthzCheck", "READ_METADATA path request NOT allowed", m_path.c_str());} + if (!result) {m_log.Log(LogMask::Debug, "AuthzCheck", "READ_METADATA path request verified for", m_path.c_str());} + else {m_log.Log(LogMask::Debug, "AuthzCheck", "READ_METADATA path request NOT allowed", m_path.c_str());} } else { - //m_log.Emsg("AuthzCheck", "path request NOT allowed", m_path.c_str()); + m_log.Log(LogMask::Debug, "AuthzCheck", "path request NOT allowed", m_path.c_str()); } return result; @@ -367,7 +367,7 @@ AuthzCheck::verify_name(const unsigned char * pred, size_t pred_sz) std::string pred_str(reinterpret_cast(pred), pred_sz); if (strncmp("name:", pred_str.c_str(), 5)) {return 1;} if (pred_str.size() < 6) {return 1;} - //m_log.Emsg("AuthzCheck", "Verifying macaroon with", pred_str.c_str()); + m_log.Log(LogMask::Debug, "AuthzCheck", "Verifying macaroon with", pred_str.c_str()); // Make a copy of the name for the XrdSecEntity; this will be used later. m_sec_name = pred_str.substr(5); diff --git a/src/configure.cpp b/src/configure.cpp index 7c740cdaa7b..94df0a1a3dd 100644 --- a/src/configure.cpp +++ b/src/configure.cpp @@ -24,6 +24,9 @@ bool Handler::Config(const char *config, XrdOucEnv *env, XrdSysError *log, } config_obj.Attach(cfg_fd); + // Set default mask for logging. + log->setMsgMask(LogMask::Error | LogMask::Warning); + // Process items // char *orig_var, *var; @@ -39,6 +42,7 @@ bool Handler::Config(const char *config, XrdOucEnv *env, XrdSysError *log, if (!strcmp("secretkey", var)) {success = xsecretkey(config_obj, log, secret);} else if (!strcmp("sitename", var)) {success = xsitename(config_obj, log, location);} + else if (!strcmp("trace", var)) {success = xtrace(config_obj, log);} else { log->Say("Config warning: ignoring unknown directive '", orig_var, "'."); config_obj.Echo(); @@ -60,6 +64,54 @@ bool Handler::Config(const char *config, XrdOucEnv *env, XrdSysError *log, } +bool Handler::xtrace(XrdOucStream &config_obj, XrdSysError *log) +{ + char *val = config_obj.GetWord(); + if (!val || !val[0]) + { + log->Emsg("Config", "macaroons.trace requires at least one directive [all | error | warning | info | debug | none]"); + return false; + } + // If the config option is given, reset the log mask. + log->setMsgMask(0); + + do { + if (!strcmp(val, "all")) + { + log->setMsgMask(log->getMsgMask() | LogMask::All); + } + else if (!strcmp(val, "error")) + { + log->setMsgMask(log->getMsgMask() | LogMask::Error); + } + else if (!strcmp(val, "warning")) + { + log->setMsgMask(log->getMsgMask() | LogMask::Warning); + } + else if (!strcmp(val, "info")) + { + log->setMsgMask(log->getMsgMask() | LogMask::Info); + } + else if (!strcmp(val, "debug")) + { + log->setMsgMask(log->getMsgMask() | LogMask::Debug); + } + else if (!strcmp(val, "none")) + { + log->setMsgMask(0); + } + else + { + log->Emsg("Config", "macaroons.trace encountered an unknown directive:", val); + return false; + } + val = config_obj.GetWord(); + } while (val); + + return true; +} + + bool Handler::xsitename(XrdOucStream &config_obj, XrdSysError *log, std::string &location) { char *val = config_obj.GetWord(); diff --git a/src/handler.hh b/src/handler.hh index 86ff2438d2b..89956198d91 100644 --- a/src/handler.hh +++ b/src/handler.hh @@ -12,6 +12,14 @@ class XrdAccAuthorize; namespace Macaroons { +enum LogMask { + Debug = 0x01, + Info = 0x02, + Warning = 0x04, + Error = 0x08, + All = 0xff +}; + class Handler : public XrdHttpExtHandler { public: Handler(XrdSysError *log, const char *config, XrdOucEnv *myEnv, @@ -43,6 +51,7 @@ private: static bool xsecretkey(XrdOucStream &Config, XrdSysError *log, std::string &secret); static bool xsitename(XrdOucStream &Config, XrdSysError *log, std::string &location); + static bool xtrace(XrdOucStream &Config, XrdSysError *log); XrdAccAuthorize *m_chain; XrdSysError *m_log; From af2c141ffe13550826430506f322a20420e9c727 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Sun, 8 Jul 2018 20:55:53 -0500 Subject: [PATCH 18/29] [XrdMacaroons] Allow macaroon plugin to chain another authlib. --- src/macaroons.cpp | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/src/macaroons.cpp b/src/macaroons.cpp index f87adcd1c36..e71c49f8010 100644 --- a/src/macaroons.cpp +++ b/src/macaroons.cpp @@ -1,9 +1,11 @@ #include +#include #include "handler.hh" #include "authz.hh" +#include "XrdOuc/XrdOucPinPath.hh" #include "XrdSys/XrdSysError.hh" #include "XrdSys/XrdSysLogger.hh" #include "XrdHttp/XrdHttpExtHandler.hh" @@ -28,17 +30,49 @@ XrdAccAuthorize *XrdAccAuthorizeObject(XrdSysLogger *log, const char *config, const char *parms) { - XrdAccAuthorize *def_authz = XrdAccDefaultAuthorizeObject(log, config, - parms, compiledVer); + XrdAccAuthorize *chain_authz; + + if (parms && parms[0]) { + // TODO: tokenize string instead. + XrdSysError *err = new XrdSysError(log, "authlib"); + char resolvePath[2048]; + bool usedAltPath{true}; + if (!XrdOucPinPath(parms, usedAltPath, resolvePath, 2048)) { + err->Emsg("Config", "Failed to locate appropriately versioned chained auth library:", parms); + delete err; + return NULL; + } + void *handle_base = dlopen(resolvePath, RTLD_LOCAL|RTLD_NOW); + if (handle_base == NULL) { + err->Emsg("Config", "Failed to base plugin ", resolvePath, dlerror()); + delete err; + return NULL; + } + + XrdAccAuthorize *(*ep)(XrdSysLogger *, const char *, const char *); + ep = (XrdAccAuthorize *(*)(XrdSysLogger *, const char *, const char *)) + (dlsym(handle_base, "XrdAccAuthorizeObject")); + if (!ep) + { + err->Emsg("Config", "Unable to chain second authlib after macaroons", parms); + delete err; + return NULL; + } + chain_authz = (*ep)(log, config, NULL); + } + else + { + chain_authz = XrdAccDefaultAuthorizeObject(log, config, parms, compiledVer); + } try { - return new Macaroons::Authz(log, config, def_authz); + return new Macaroons::Authz(log, config, chain_authz); } catch (std::runtime_error e) { XrdSysError err(log, "macaroons"); err.Emsg("Config", "Configuration of Macaroon authorization handler failed", e.what()); - return nullptr; + return NULL; } } @@ -58,7 +92,7 @@ XrdHttpExtHandler *XrdHttpGetExtHandler( catch (std::runtime_error e) { log->Emsg("Config", "Generation of Macaroon handler failed", e.what()); - return nullptr; + return NULL; } } From 4b542de2a771678a3e9fafaa74d97275ea79259b Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Mon, 9 Jul 2018 04:10:34 -0500 Subject: [PATCH 19/29] [XrdMacaroons] Forward remaining arguments to chained authlib. --- src/macaroons.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/macaroons.cpp b/src/macaroons.cpp index e71c49f8010..c1f756a6538 100644 --- a/src/macaroons.cpp +++ b/src/macaroons.cpp @@ -5,6 +5,7 @@ #include "handler.hh" #include "authz.hh" +#include "XrdOuc/XrdOucString.hh" #include "XrdOuc/XrdOucPinPath.hh" #include "XrdSys/XrdSysError.hh" #include "XrdSys/XrdSysLogger.hh" @@ -33,11 +34,24 @@ XrdAccAuthorize *XrdAccAuthorizeObject(XrdSysLogger *log, XrdAccAuthorize *chain_authz; if (parms && parms[0]) { - // TODO: tokenize string instead. + XrdOucString parms_str(parms); + XrdOucString chained_lib; XrdSysError *err = new XrdSysError(log, "authlib"); + int from = parms_str.tokenize(chained_lib, 0, ' '); + const char *chained_parms = NULL; + err->Emsg("Config", "Will chain library", chained_lib.c_str()); + if (from > 0) + { + parms_str.erasefromstart(from); + if (parms_str.length()) + { + err->Emsg("Config", "Will chain parameters", parms_str.c_str()); + chained_parms = parms_str.c_str(); + } + } char resolvePath[2048]; bool usedAltPath{true}; - if (!XrdOucPinPath(parms, usedAltPath, resolvePath, 2048)) { + if (!XrdOucPinPath(chained_lib.c_str(), usedAltPath, resolvePath, 2048)) { err->Emsg("Config", "Failed to locate appropriately versioned chained auth library:", parms); delete err; return NULL; @@ -58,7 +72,7 @@ XrdAccAuthorize *XrdAccAuthorizeObject(XrdSysLogger *log, delete err; return NULL; } - chain_authz = (*ep)(log, config, NULL); + chain_authz = (*ep)(log, config, chained_parms); } else { From 630cac2b47b2f9fe465cd0f749f3b0c6caddebc2 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Mon, 9 Jul 2018 04:23:51 -0500 Subject: [PATCH 20/29] [XrdMacaroons] Update RPM spec file for release. --- rpm/xrootd-macaroons.spec | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/rpm/xrootd-macaroons.spec b/rpm/xrootd-macaroons.spec index 4788fe027bf..70699928303 100644 --- a/rpm/xrootd-macaroons.spec +++ b/rpm/xrootd-macaroons.spec @@ -1,6 +1,6 @@ Name: xrootd-macaroons -Version: 0.1.0 +Version: 0.2.0 Release: 1%{?dist} Summary: Macaroons support for XRootD @@ -41,6 +41,11 @@ BuildRequires: json-c-devel %{_libdir}/libXrdMacaroons-4.so %changelog +* Mon Jul 09 2018 Brian Bockelman - 0.2.0-1 +- Record authz name within the macaroon; set it on request. +- Allow multiple logging levels. +- Allow chaining of authorization libraries. + * Fri Jun 15 2018 Brian Bockelman - 0.1.0-1 - Initial macaroons build. From 8b43f2d9e86ae62f24cfd2a761574a41e4457341 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Mon, 9 Jul 2018 07:38:09 -0500 Subject: [PATCH 21/29] [XrdMacaroons] Add concept of max duration of a macaroon lifetime. --- src/authz.cpp | 21 +++++++++++++++------ src/authz.hh | 1 + src/configure.cpp | 30 +++++++++++++++++++++++++++++- src/handler.cpp | 9 ++++++++- src/handler.hh | 7 +++++-- 5 files changed, 58 insertions(+), 10 deletions(-) diff --git a/src/authz.cpp b/src/authz.cpp index b4eb703fad9..3fe86aac948 100644 --- a/src/authz.cpp +++ b/src/authz.cpp @@ -20,7 +20,7 @@ namespace { class AuthzCheck { public: - AuthzCheck(const char *req_path, const Access_Operation req_oper, XrdSysError &log); + AuthzCheck(const char *req_path, const Access_Operation req_oper, ssize_t m_max_duration, XrdSysError &log); const std::string &GetSecName() const {return m_sec_name;} @@ -46,6 +46,7 @@ class AuthzCheck int verify_path(const unsigned char *pred, size_t pred_sz); int verify_name(const unsigned char *pred, size_t pred_sz); + ssize_t m_max_duration; XrdSysError &m_log; const std::string m_path; std::string m_desired_activity; @@ -105,10 +106,11 @@ static XrdAccPrivs AddPriv(Access_Operation op, XrdAccPrivs privs) Authz::Authz(XrdSysLogger *log, char const *config, XrdAccAuthorize *chain) - : m_chain(chain), + : m_max_duration(86400), + m_chain(chain), m_log(log, "macarons_") { - if (!Handler::Config(config, nullptr, &m_log, m_location, m_secret)) + if (!Handler::Config(config, nullptr, &m_log, m_location, m_secret, m_max_duration)) { throw std::runtime_error("Macaroon authorization config failed."); } @@ -141,7 +143,7 @@ Authz::Access(const XrdSecEntity *Entity, const char *path, return XrdAccPriv_None; } - AuthzCheck check_helper(path, oper, m_log); + 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) || @@ -193,8 +195,9 @@ Authz::Access(const XrdSecEntity *Entity, const char *path, } -AuthzCheck::AuthzCheck(const char *req_path, const Access_Operation req_oper, XrdSysError &log) - : m_log(log), +AuthzCheck::AuthzCheck(const char *req_path, const Access_Operation req_oper, ssize_t max_duration, XrdSysError &log) + : m_max_duration(max_duration), + m_log(log), m_path(req_path), m_oper(req_oper), m_now(time(NULL)) @@ -292,6 +295,12 @@ AuthzCheck::verify_before(const unsigned char * pred, size_t pred_sz) m_log.Log(LogMask::Debug, "AuthzCheck", "failed to generate unix time", &pred_str[7]); return 1; } + if ((m_max_duration > 0) && (caveat_time > m_now + m_max_duration)) + { + m_log.Log(LogMask::Warning, "AuthzCheck", "Max token age is greater than configured max duration; rejecting"); + return 1; + } + int result = (m_now >= caveat_time); if (!result) m_log.Log(LogMask::Debug, "AuthzCheck", "verify before successful"); else m_log.Log(LogMask::Debug, "AuthzCheck", "verify before failed"); diff --git a/src/authz.hh b/src/authz.hh index ef04c623de0..7081f8d8912 100644 --- a/src/authz.hh +++ b/src/authz.hh @@ -34,6 +34,7 @@ public: } private: + ssize_t m_max_duration; XrdAccAuthorize *m_chain; XrdSysError m_log; std::string m_secret; diff --git a/src/configure.cpp b/src/configure.cpp index 94df0a1a3dd..e36a8e2397f 100644 --- a/src/configure.cpp +++ b/src/configure.cpp @@ -12,7 +12,7 @@ using namespace Macaroons; bool Handler::Config(const char *config, XrdOucEnv *env, XrdSysError *log, - std::string &location, std::string &secret) + std::string &location, std::string &secret, ssize_t &max_duration) { XrdOucStream config_obj(log, getenv("XRDINSTANCE"), env, "=====> "); @@ -27,6 +27,9 @@ bool Handler::Config(const char *config, XrdOucEnv *env, XrdSysError *log, // Set default mask for logging. log->setMsgMask(LogMask::Error | LogMask::Warning); + // Set default maximum duration (24 hours). + max_duration = 24*3600; + // Process items // char *orig_var, *var; @@ -43,6 +46,7 @@ bool Handler::Config(const char *config, XrdOucEnv *env, XrdSysError *log, if (!strcmp("secretkey", var)) {success = xsecretkey(config_obj, log, secret);} 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 { log->Say("Config warning: ignoring unknown directive '", orig_var, "'."); config_obj.Echo(); @@ -112,6 +116,30 @@ bool Handler::xtrace(XrdOucStream &config_obj, XrdSysError *log) } +bool Handler::xmaxduration(XrdOucStream &config_obj, XrdSysError *log, ssize_t &max_duration) +{ + char *val = config_obj.GetWord(); + if (!val || !val[0]) + { + log->Emsg("Config", "macaroons.maxduration requires a value"); + return false; + } + char *endptr = NULL; + long int max_duration_parsed = strtoll(val, &endptr, 10); + if (endptr == val) + { + log->Emsg("Config", "Unable to parse macaroons.maxduration as an integer", val); + return false; + } + if (errno != 0) + { + log->Emsg("Config", "Failure when parsing macaroons.maxduration as an integer", strerror(errno)); + } + max_duration = max_duration_parsed; + + return true; +} + bool Handler::xsitename(XrdOucStream &config_obj, XrdSysError *log, std::string &location) { char *val = config_obj.GetWord(); diff --git a/src/handler.cpp b/src/handler.cpp index 345869df3ad..c9c26e13d8f 100644 --- a/src/handler.cpp +++ b/src/handler.cpp @@ -178,7 +178,14 @@ int Handler::ProcessReq(XrdHttpExtReq &req) } time_t now; time(&now); - now += validity; + if (m_max_duration > 0) + { + now += (validity > m_max_duration) ? m_max_duration : validity; + } + else + { + now += validity; + } char utc_time_buf[21]; if (!strftime(utc_time_buf, 21, "%FT%TZ", gmtime(&now))) { diff --git a/src/handler.hh b/src/handler.hh index 89956198d91..3cfb22f230c 100644 --- a/src/handler.hh +++ b/src/handler.hh @@ -24,10 +24,11 @@ class Handler : public XrdHttpExtHandler { public: Handler(XrdSysError *log, const char *config, XrdOucEnv *myEnv, XrdAccAuthorize *chain) : + m_max_duration(86400), m_chain(chain), m_log(log) { - if (!Config(config, myEnv, m_log, m_location, m_secret)) + if (!Config(config, myEnv, m_log, m_location, m_secret, m_max_duration)) { throw std::runtime_error("Macaroon handler config failed."); } @@ -43,7 +44,7 @@ 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); + std::string &location, std::string &secret, ssize_t &max_duration); private: std::string GenerateID(const XrdSecEntity &, const std::string &, const std::string &); @@ -52,7 +53,9 @@ private: static bool xsecretkey(XrdOucStream &Config, XrdSysError *log, std::string &secret); static bool xsitename(XrdOucStream &Config, XrdSysError *log, std::string &location); static bool xtrace(XrdOucStream &Config, XrdSysError *log); + static bool xmaxduration(XrdOucStream &Config, XrdSysError *log, ssize_t &max_duration); + ssize_t m_max_duration; XrdAccAuthorize *m_chain; XrdSysError *m_log; std::string m_location; From 952e5d05c5858f487a726a5693e86aa0c1a3ee23 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Mon, 9 Jul 2018 09:57:13 -0500 Subject: [PATCH 22/29] [XrdMacaroons] Check location header and record IDs as we use them. --- src/authz.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/authz.cpp b/src/authz.cpp index 3fe86aac948..d2cb49fe318 100644 --- a/src/authz.cpp +++ b/src/authz.cpp @@ -166,8 +166,15 @@ Authz::Access(const XrdSecEntity *Entity, const char *path, return m_chain ? m_chain->Access(Entity, path, oper, env) : XrdAccPriv_None; } - // TODO: check location matches our location - // TODO: record identifier into the log. + const unsigned char *macaroon_loc; + size_t location_sz; + macaroon_location(macaroon, &macaroon_loc, &location_sz); + if (strncmp(reinterpret_cast(macaroon_loc), m_location.c_str(), location_sz)) + { + m_log.Emsg("Access", "Macaroon is for incorrect location", reinterpret_cast(macaroon_loc)); + macaroon_verifier_destroy(verifier); + return m_chain ? m_chain->Access(Entity, path, oper, env) : XrdAccPriv_None; + } if (macaroon_verify(verifier, macaroon, reinterpret_cast(m_secret.c_str()), @@ -175,16 +182,20 @@ Authz::Access(const XrdSecEntity *Entity, const char *path, NULL, 0, // discharge macaroons &mac_err)) { - //m_log.Emsg("Access", "Macaroon verification failed:", macaroon_error(mac_err)); + m_log.Log(LogMask::Debug, "Access", "Macaroon verification failed"); macaroon_verifier_destroy(verifier); macaroon_destroy(macaroon); return m_chain ? m_chain->Access(Entity, path, oper, env) : XrdAccPriv_None; } - //m_log.Emsg("Access", "Macaroon verification successful."); + 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()); // Copy the name, if present into the macaroon, into the credential object. if (Entity && check_helper.GetSecName().size()) { - //m_log.Emsg("Access", "Setting the security name to", check_helper.GetSecName().c_str()); + m_log.Log(LogMask::Debug, "Access", "Setting the security name to", check_helper.GetSecName().c_str()); XrdSecEntity &myEntity = *const_cast(Entity); if (myEntity.name) {free(myEntity.name);} myEntity.name = strdup(check_helper.GetSecName().c_str()); From cf1d08575350f1d32536060d3db19fb81d045a82 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Mon, 9 Jul 2018 10:02:46 -0500 Subject: [PATCH 23/29] [XrdMacaroons] Bump RPM for 0.3.0 release. --- rpm/xrootd-macaroons.spec | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/rpm/xrootd-macaroons.spec b/rpm/xrootd-macaroons.spec index 70699928303..f142f26ea53 100644 --- a/rpm/xrootd-macaroons.spec +++ b/rpm/xrootd-macaroons.spec @@ -1,6 +1,6 @@ Name: xrootd-macaroons -Version: 0.2.0 +Version: 0.3.0 Release: 1%{?dist} Summary: Macaroons support for XRootD @@ -41,6 +41,11 @@ BuildRequires: json-c-devel %{_libdir}/libXrdMacaroons-4.so %changelog +* Mon Jul 09 2018 Brian Bockelman - 0.3.0-1 +- Add the concept of a max duration. +- Check the location matches the current location. +- Record ID usage in the logs. + * Mon Jul 09 2018 Brian Bockelman - 0.2.0-1 - Record authz name within the macaroon; set it on request. - Allow multiple logging levels. From 81de7e94f5c2720aac153ae19055a99018fac6c9 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Tue, 10 Jul 2018 01:31:02 -0500 Subject: [PATCH 24/29] [XrdMacaroons] Rename macaroon-related files in preparation for merge. --- CMakeLists.txt => src/XrdMacaroons/CMakeLists.txt | 0 LGPL3.0.txt => src/XrdMacaroons/LGPL3.0.txt | 0 LICENSE => src/XrdMacaroons/LICENSE | 0 README.md => src/XrdMacaroons/README.md | 0 src/{ => XrdMacaroons}/authz.cpp | 0 src/{ => XrdMacaroons}/authz.hh | 0 {cmake => src/XrdMacaroons/cmake}/FindMacaroons.cmake | 0 {cmake => src/XrdMacaroons/cmake}/FindXrootd.cmake | 0 {configs => src/XrdMacaroons/configs}/export-lib-symbols | 0 src/{ => XrdMacaroons}/configure.cpp | 0 src/{ => XrdMacaroons}/handler.cpp | 0 src/{ => XrdMacaroons}/handler.hh | 0 src/{ => XrdMacaroons}/macaroons.cpp | 0 {rpm => src/XrdMacaroons/rpm}/xrootd-macaroons.spec | 0 14 files changed, 0 insertions(+), 0 deletions(-) rename CMakeLists.txt => src/XrdMacaroons/CMakeLists.txt (100%) rename LGPL3.0.txt => src/XrdMacaroons/LGPL3.0.txt (100%) rename LICENSE => src/XrdMacaroons/LICENSE (100%) rename README.md => src/XrdMacaroons/README.md (100%) rename src/{ => XrdMacaroons}/authz.cpp (100%) rename src/{ => XrdMacaroons}/authz.hh (100%) rename {cmake => src/XrdMacaroons/cmake}/FindMacaroons.cmake (100%) rename {cmake => src/XrdMacaroons/cmake}/FindXrootd.cmake (100%) rename {configs => src/XrdMacaroons/configs}/export-lib-symbols (100%) rename src/{ => XrdMacaroons}/configure.cpp (100%) rename src/{ => XrdMacaroons}/handler.cpp (100%) rename src/{ => XrdMacaroons}/handler.hh (100%) rename src/{ => XrdMacaroons}/macaroons.cpp (100%) rename {rpm => src/XrdMacaroons/rpm}/xrootd-macaroons.spec (100%) diff --git a/CMakeLists.txt b/src/XrdMacaroons/CMakeLists.txt similarity index 100% rename from CMakeLists.txt rename to src/XrdMacaroons/CMakeLists.txt diff --git a/LGPL3.0.txt b/src/XrdMacaroons/LGPL3.0.txt similarity index 100% rename from LGPL3.0.txt rename to src/XrdMacaroons/LGPL3.0.txt diff --git a/LICENSE b/src/XrdMacaroons/LICENSE similarity index 100% rename from LICENSE rename to src/XrdMacaroons/LICENSE diff --git a/README.md b/src/XrdMacaroons/README.md similarity index 100% rename from README.md rename to src/XrdMacaroons/README.md diff --git a/src/authz.cpp b/src/XrdMacaroons/authz.cpp similarity index 100% rename from src/authz.cpp rename to src/XrdMacaroons/authz.cpp diff --git a/src/authz.hh b/src/XrdMacaroons/authz.hh similarity index 100% rename from src/authz.hh rename to src/XrdMacaroons/authz.hh diff --git a/cmake/FindMacaroons.cmake b/src/XrdMacaroons/cmake/FindMacaroons.cmake similarity index 100% rename from cmake/FindMacaroons.cmake rename to src/XrdMacaroons/cmake/FindMacaroons.cmake diff --git a/cmake/FindXrootd.cmake b/src/XrdMacaroons/cmake/FindXrootd.cmake similarity index 100% rename from cmake/FindXrootd.cmake rename to src/XrdMacaroons/cmake/FindXrootd.cmake diff --git a/configs/export-lib-symbols b/src/XrdMacaroons/configs/export-lib-symbols similarity index 100% rename from configs/export-lib-symbols rename to src/XrdMacaroons/configs/export-lib-symbols diff --git a/src/configure.cpp b/src/XrdMacaroons/configure.cpp similarity index 100% rename from src/configure.cpp rename to src/XrdMacaroons/configure.cpp diff --git a/src/handler.cpp b/src/XrdMacaroons/handler.cpp similarity index 100% rename from src/handler.cpp rename to src/XrdMacaroons/handler.cpp diff --git a/src/handler.hh b/src/XrdMacaroons/handler.hh similarity index 100% rename from src/handler.hh rename to src/XrdMacaroons/handler.hh diff --git a/src/macaroons.cpp b/src/XrdMacaroons/macaroons.cpp similarity index 100% rename from src/macaroons.cpp rename to src/XrdMacaroons/macaroons.cpp diff --git a/rpm/xrootd-macaroons.spec b/src/XrdMacaroons/rpm/xrootd-macaroons.spec similarity index 100% rename from rpm/xrootd-macaroons.spec rename to src/XrdMacaroons/rpm/xrootd-macaroons.spec From ab7a33675b197205e0629010655b6f3498ad1db4 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Tue, 10 Jul 2018 02:11:05 -0500 Subject: [PATCH 25/29] [XrdMacaroons] Initial CMake integration of Macaroons. --- .../cmake => cmake}/FindMacaroons.cmake | 0 cmake/XRootDDefaults.cmake | 21 +-- cmake/XRootDFindLibs.cmake | 11 ++ cmake/XRootDSummary.cmake | 22 +-- packaging/debian/xrootd-server-libs.install | 1 + packaging/rhel/xrootd.spec.in | 1 + src/CMakeLists.txt | 4 + src/XrdMacaroons.cmake | 53 ++++++ src/XrdMacaroons/CMakeLists.txt | 42 ----- src/XrdMacaroons/LGPL3.0.txt | 165 ------------------ src/XrdMacaroons/LICENSE | 15 -- .../{configs => }/export-lib-symbols | 0 12 files changed, 93 insertions(+), 242 deletions(-) rename {src/XrdMacaroons/cmake => cmake}/FindMacaroons.cmake (100%) create mode 100644 src/XrdMacaroons.cmake delete mode 100644 src/XrdMacaroons/CMakeLists.txt delete mode 100644 src/XrdMacaroons/LGPL3.0.txt delete mode 100644 src/XrdMacaroons/LICENSE rename src/XrdMacaroons/{configs => }/export-lib-symbols (100%) diff --git a/src/XrdMacaroons/cmake/FindMacaroons.cmake b/cmake/FindMacaroons.cmake similarity index 100% rename from src/XrdMacaroons/cmake/FindMacaroons.cmake rename to cmake/FindMacaroons.cmake diff --git a/cmake/XRootDDefaults.cmake b/cmake/XRootDDefaults.cmake index 9554515293d..d41e80d8e43 100644 --- a/cmake/XRootDDefaults.cmake +++ b/cmake/XRootDDefaults.cmake @@ -9,14 +9,15 @@ if( "${CMAKE_BUILD_TYPE}" STREQUAL "" ) endif() endif() -define_default( PLUGIN_VERSION 4 ) -define_default( ENABLE_FUSE TRUE ) -define_default( ENABLE_CRYPTO TRUE ) -define_default( ENABLE_KRB5 TRUE ) -define_default( ENABLE_READLINE TRUE ) -define_default( ENABLE_XRDCL TRUE ) -define_default( ENABLE_TESTS FALSE ) -define_default( ENABLE_HTTP TRUE ) -define_default( ENABLE_CEPH TRUE ) -define_default( ENABLE_PYTHON TRUE ) +define_default( PLUGIN_VERSION 4 ) +define_default( ENABLE_FUSE TRUE ) +define_default( ENABLE_CRYPTO TRUE ) +define_default( ENABLE_KRB5 TRUE ) +define_default( ENABLE_READLINE TRUE ) +define_default( ENABLE_XRDCL TRUE ) +define_default( ENABLE_TESTS FALSE ) +define_default( ENABLE_HTTP TRUE ) +define_default( ENABLE_MACAROONS TRUE ) +define_default( ENABLE_CEPH TRUE ) +define_default( ENABLE_PYTHON TRUE ) define_default( XRD_PYTHON_REQ_VERSION 2.4 ) diff --git a/cmake/XRootDFindLibs.cmake b/cmake/XRootDFindLibs.cmake index d44ad887469..cf761023dbd 100644 --- a/cmake/XRootDFindLibs.cmake +++ b/cmake/XRootDFindLibs.cmake @@ -89,6 +89,17 @@ check_function_exists( curl_multi_wait HAVE_CURL_MULTI_WAIT ) compiler_define_if_found( HAVE_CURL_MULTI_WAIT HAVE_CURL_MULTI_WAIT ) endif() +if( ENABLE_MACAROONS ) +find_package( Macaroons REQUIRED ) +include (FindPkgConfig) +pkg_check_modules(JSON REQUIRED json-c) +pkg_check_modules(UUID REQUIRED uuid) + +set( BUILD_MACAROONS TRUE ) +else() +set( BUILD_MACAROONS FALSE ) +endif() + if( ENABLE_CEPH ) find_package( ceph ) if( CEPH_FOUND ) diff --git a/cmake/XRootDSummary.cmake b/cmake/XRootDSummary.cmake index 606c613e676..f44b0e53c76 100644 --- a/cmake/XRootDSummary.cmake +++ b/cmake/XRootDSummary.cmake @@ -2,16 +2,17 @@ # Print the configuration summary #------------------------------------------------------------------------------- set( TRUE_VAR TRUE ) -component_status( READLINE ENABLE_READLINE READLINE_FOUND ) -component_status( FUSE BUILD_FUSE FUSE_FOUND ) -component_status( CRYPTO BUILD_CRYPTO OPENSSL_FOUND ) -component_status( KRB5 BUILD_KRB5 KERBEROS5_FOUND ) -component_status( XRDCL ENABLE_XRDCL TRUE_VAR ) -component_status( TESTS BUILD_TESTS CPPUNIT_FOUND ) -component_status( HTTP BUILD_HTTP OPENSSL_FOUND ) -component_status( TPC BUILD_TPC CURL_FOUND ) -component_status( CEPH BUILD_CEPH CEPH_FOUND ) -component_status( PYTHON BUILD_PYTHON PYTHON_FOUND ) +component_status( READLINE ENABLE_READLINE READLINE_FOUND ) +component_status( FUSE BUILD_FUSE FUSE_FOUND ) +component_status( CRYPTO BUILD_CRYPTO OPENSSL_FOUND ) +component_status( KRB5 BUILD_KRB5 KERBEROS5_FOUND ) +component_status( XRDCL ENABLE_XRDCL TRUE_VAR ) +component_status( TESTS BUILD_TESTS CPPUNIT_FOUND ) +component_status( HTTP BUILD_HTTP OPENSSL_FOUND ) +component_status( TPC BUILD_TPC CURL_FOUND ) +component_status( MACAROONS BUILD_MACAROONS MACAROONS_FOUND ) +component_status( CEPH BUILD_CEPH CEPH_FOUND ) +component_status( PYTHON BUILD_PYTHON PYTHON_FOUND ) message( STATUS "----------------------------------------" ) message( STATUS "Installation path: " ${CMAKE_INSTALL_PREFIX} ) @@ -28,6 +29,7 @@ message( STATUS "XrdCl: " ${STATUS_XRDCL} ) message( STATUS "Tests: " ${STATUS_TESTS} ) message( STATUS "HTTP support: " ${STATUS_HTTP} ) message( STATUS "HTTP TPC support: " ${STATUS_TPC} ) +message( STATUS "Macaroons support: " ${STATUS_MACAROONS} ) message( STATUS "CEPH support: " ${STATUS_CEPH} ) message( STATUS "Python support: " ${STATUS_PYTHON} ) message( STATUS "----------------------------------------" ) diff --git a/packaging/debian/xrootd-server-libs.install b/packaging/debian/xrootd-server-libs.install index 9472aff6204..b0de2911373 100644 --- a/packaging/debian/xrootd-server-libs.install +++ b/packaging/debian/xrootd-server-libs.install @@ -6,6 +6,7 @@ usr/lib/*/libXrdBlacklistDecision-4.so usr/lib/*/libXrdHttp-4.so usr/lib/*/libXrdHttpTPC-4.so usr/lib/*/libXrdHttpUtils.so.* +usr/lib/*/libXrdMacaroons-4.so usr/lib/*/libXrdN2No2p-4.so usr/lib/*/libXrdOssSIgpfsT-4.so usr/lib/*/libXrdServer.so.* diff --git a/packaging/rhel/xrootd.spec.in b/packaging/rhel/xrootd.spec.in index 5f6d5375eee..65b90551dba 100644 --- a/packaging/rhel/xrootd.spec.in +++ b/packaging/rhel/xrootd.spec.in @@ -781,6 +781,7 @@ fi %{_libdir}/libXrdHttp-4.so %{_libdir}/libXrdHttpTPC-4.so %{_libdir}/libXrdHttpUtils.so.* +%{_libdir}/libXrdMacaroons-4.so %{_libdir}/libXrdN2No2p-4.so %{_libdir}/libXrdOssSIgpfsT-4.so %{_libdir}/libXrdServer.so.* diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eafa85da0bc..dac3116a0bb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -41,6 +41,10 @@ if( BUILD_HTTP ) include( XrdTpc ) endif() +if( BUILD_MACAROONS ) + include( XrdMacaroons ) +endif() + if( BUILD_CEPH ) include( XrdCeph ) endif() diff --git a/src/XrdMacaroons.cmake b/src/XrdMacaroons.cmake new file mode 100644 index 00000000000..72f905698da --- /dev/null +++ b/src/XrdMacaroons.cmake @@ -0,0 +1,53 @@ +include( XRootDCommon ) + +#------------------------------------------------------------------------------- +# Modules +#------------------------------------------------------------------------------- +set( LIB_XRD_MACAROONS XrdMacaroons-${PLUGIN_VERSION} ) + +#------------------------------------------------------------------------------- +# Shared library version +#------------------------------------------------------------------------------- + +if( BUILD_MACAROONS ) + include_directories(${MACAROONS_INCLUDES} ${JSON_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR}) + + add_library( + ${LIB_XRD_MACAROONS} + MODULE + XrdMacaroons/macaroons.cpp + XrdMacaroons/handler.cpp XrdMacaroons/handler.hh + XrdMacaroons/authz.cpp XrdMacaroons/authz.hh + XrdMacaroons//configure.cpp) + + target_link_libraries( + ${LIB_XRD_MACAROONS} -ldl + XrdUtils + XrdServer + ${MACAROONS_LIB} + ${JSON_LIBRARIES} + ${XROOTD_HTTP_LIB} + ${UUID_LIBRARIES} + ${OPENSSL_CRYPTO_LIBRARY}) + + if( MacOSX ) + SET( MACAROONS_LINK_FLAGS "-Wl") + else() + SET( MACAROONS_LINK_FLAGS "-Wl,--version-script=${CMAKE_SOURCE_DIR}/src/XrdMacaroons/export-lib-symbols" ) + endif() + + set_target_properties( + ${LIB_XRD_MACAROONS} + PROPERTIES + INTERFACE_LINK_LIBRARIES "" + LINK_INTERFACE_LIBRARIES "" + LINK_FLAGS "${MACAROONS_LINK_FLAGS}") + + #----------------------------------------------------------------------------- + # Install + #----------------------------------------------------------------------------- + install( + TARGETS ${LIB_XRD_MACAROONS} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +endif() diff --git a/src/XrdMacaroons/CMakeLists.txt b/src/XrdMacaroons/CMakeLists.txt deleted file mode 100644 index 3e5e79ea15a..00000000000 --- a/src/XrdMacaroons/CMakeLists.txt +++ /dev/null @@ -1,42 +0,0 @@ - -cmake_minimum_required( VERSION 2.8 ) -project( xrootd-macaroons ) - -set( CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake ) - -find_package( Xrootd REQUIRED ) -find_package( Macaroons REQUIRED ) - -include (FindPkgConfig) -pkg_check_modules(JSON REQUIRED json-c) -pkg_check_modules(UUID REQUIRED uuid) -pkg_check_modules(LIBCRYPTO REQUIRED libcrypto) - -macro(use_cxx11) - if (CMAKE_VERSION VERSION_LESS "3.1") - if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set (CMAKE_CXX_FLAGS "-std=gnu++11 ${CMAKE_CXX_FLAGS}") - endif () - else () - set (CMAKE_CXX_STANDARD 11) - endif () -endmacro(use_cxx11) -use_cxx11() - -if( CMAKE_COMPILER_IS_GNUCXX ) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror" ) -endif() -SET( CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined") -SET( CMAKE_MODULE_LINKER_FLAGS "-Wl,--no-undefined") - -include_directories(${MACAROONS_INCLUDES} ${XROOTD_INCLUDES} ${XROOTD_PRIVATE_INCLUDES} ${JSON_INCLUDE_DIRS} ${UUID_INCLUDE_DIRS} ${LIBCRYPTO_INCLUDE_DIRS}) - -add_library(XrdMacaroons SHARED src/macaroons.cpp src/handler.cpp src/authz.cpp src/configure.cpp) -target_link_libraries(XrdMacaroons -ldl ${XROOTD_UTILS_LIB} ${XROOTD_SERVER_LIB} ${MACAROONS_LIB} ${JSON_LIBRARIES} ${XROOTD_HTTP_LIB} ${UUID_LIBRARIES} ${LIBCRYPTO_LIBRARIES}) -set_target_properties(XrdMacaroons PROPERTIES OUTPUT_NAME XrdMacaroons-4 SUFFIX ".so" LINK_FLAGS "-Wl,--version-script=${CMAKE_SOURCE_DIR}/configs/export-lib-symbols") - -SET(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Install path for libraries") - -install( - TARGETS XrdMacaroons - LIBRARY DESTINATION ${LIB_INSTALL_DIR}) diff --git a/src/XrdMacaroons/LGPL3.0.txt b/src/XrdMacaroons/LGPL3.0.txt deleted file mode 100644 index 0a041280bd0..00000000000 --- a/src/XrdMacaroons/LGPL3.0.txt +++ /dev/null @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/src/XrdMacaroons/LICENSE b/src/XrdMacaroons/LICENSE deleted file mode 100644 index 69922abe7ea..00000000000 --- a/src/XrdMacaroons/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 3.0 of the License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -See LGPL3.0.txt next to this file for the text of the LGPL version 3.0. diff --git a/src/XrdMacaroons/configs/export-lib-symbols b/src/XrdMacaroons/export-lib-symbols similarity index 100% rename from src/XrdMacaroons/configs/export-lib-symbols rename to src/XrdMacaroons/export-lib-symbols From 613dda2f15c50e565f543809dfe91992867b0745 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Tue, 10 Jul 2018 02:32:04 -0500 Subject: [PATCH 26/29] [XrdMacaroons] Rename macaroon files to match Xrootd-style. --- src/XrdMacaroons.cmake | 9 +++++---- src/XrdMacaroons/{macaroons.cpp => XrdMacaroons.cc} | 4 ++-- src/XrdMacaroons/{authz.cpp => XrdMacaroonsAuthz.cc} | 4 ++-- src/XrdMacaroons/{authz.hh => XrdMacaroonsAuthz.hh} | 0 .../{configure.cpp => XrdMacaroonsConfigure.cc} | 2 +- src/XrdMacaroons/{handler.cpp => XrdMacaroonsHandler.cc} | 2 +- src/XrdMacaroons/{handler.hh => XrdMacaroonsHandler.hh} | 0 7 files changed, 11 insertions(+), 10 deletions(-) rename src/XrdMacaroons/{macaroons.cpp => XrdMacaroons.cc} (98%) rename src/XrdMacaroons/{authz.cpp => XrdMacaroonsAuthz.cc} (99%) rename src/XrdMacaroons/{authz.hh => XrdMacaroonsAuthz.hh} (100%) rename src/XrdMacaroons/{configure.cpp => XrdMacaroonsConfigure.cc} (99%) rename src/XrdMacaroons/{handler.cpp => XrdMacaroonsHandler.cc} (99%) rename src/XrdMacaroons/{handler.hh => XrdMacaroonsHandler.hh} (100%) diff --git a/src/XrdMacaroons.cmake b/src/XrdMacaroons.cmake index 72f905698da..f6d42004190 100644 --- a/src/XrdMacaroons.cmake +++ b/src/XrdMacaroons.cmake @@ -15,13 +15,14 @@ if( BUILD_MACAROONS ) add_library( ${LIB_XRD_MACAROONS} MODULE - XrdMacaroons/macaroons.cpp - XrdMacaroons/handler.cpp XrdMacaroons/handler.hh - XrdMacaroons/authz.cpp XrdMacaroons/authz.hh - XrdMacaroons//configure.cpp) + XrdMacaroons/XrdMacaroons.cc + XrdMacaroons/XrdMacaroonsHandler.cc XrdMacaroons/XrdMacaroonsHandler.hh + XrdMacaroons/XrdMacaroonsAuthz.cc XrdMacaroons/XrdMacaroonsAuthz.hh + XrdMacaroons/XrdMacaroonsConfigure.cc) target_link_libraries( ${LIB_XRD_MACAROONS} -ldl + XrdHttpUtils XrdUtils XrdServer ${MACAROONS_LIB} diff --git a/src/XrdMacaroons/macaroons.cpp b/src/XrdMacaroons/XrdMacaroons.cc similarity index 98% rename from src/XrdMacaroons/macaroons.cpp rename to src/XrdMacaroons/XrdMacaroons.cc index c1f756a6538..0f3f94e808d 100644 --- a/src/XrdMacaroons/macaroons.cpp +++ b/src/XrdMacaroons/XrdMacaroons.cc @@ -2,8 +2,8 @@ #include #include -#include "handler.hh" -#include "authz.hh" +#include "XrdMacaroonsHandler.hh" +#include "XrdMacaroonsAuthz.hh" #include "XrdOuc/XrdOucString.hh" #include "XrdOuc/XrdOucPinPath.hh" diff --git a/src/XrdMacaroons/authz.cpp b/src/XrdMacaroons/XrdMacaroonsAuthz.cc similarity index 99% rename from src/XrdMacaroons/authz.cpp rename to src/XrdMacaroons/XrdMacaroonsAuthz.cc index d2cb49fe318..44625939417 100644 --- a/src/XrdMacaroons/authz.cpp +++ b/src/XrdMacaroons/XrdMacaroonsAuthz.cc @@ -9,8 +9,8 @@ #include "XrdOuc/XrdOucEnv.hh" #include "XrdSec/XrdSecEntity.hh" -#include "handler.hh" -#include "authz.hh" +#include "XrdMacaroonsHandler.hh" +#include "XrdMacaroonsAuthz.hh" using namespace Macaroons; diff --git a/src/XrdMacaroons/authz.hh b/src/XrdMacaroons/XrdMacaroonsAuthz.hh similarity index 100% rename from src/XrdMacaroons/authz.hh rename to src/XrdMacaroons/XrdMacaroonsAuthz.hh diff --git a/src/XrdMacaroons/configure.cpp b/src/XrdMacaroons/XrdMacaroonsConfigure.cc similarity index 99% rename from src/XrdMacaroons/configure.cpp rename to src/XrdMacaroons/XrdMacaroonsConfigure.cc index e36a8e2397f..fccf8d25f9c 100644 --- a/src/XrdMacaroons/configure.cpp +++ b/src/XrdMacaroons/XrdMacaroonsConfigure.cc @@ -6,7 +6,7 @@ #include -#include "handler.hh" +#include "XrdMacaroonsHandler.hh" using namespace Macaroons; diff --git a/src/XrdMacaroons/handler.cpp b/src/XrdMacaroons/XrdMacaroonsHandler.cc similarity index 99% rename from src/XrdMacaroons/handler.cpp rename to src/XrdMacaroons/XrdMacaroonsHandler.cc index c9c26e13d8f..095693a6717 100644 --- a/src/XrdMacaroons/handler.cpp +++ b/src/XrdMacaroons/XrdMacaroonsHandler.cc @@ -13,7 +13,7 @@ #include "XrdSys/XrdSysError.hh" #include "XrdSec/XrdSecEntity.hh" -#include "handler.hh" +#include "XrdMacaroonsHandler.hh" using namespace Macaroons; diff --git a/src/XrdMacaroons/handler.hh b/src/XrdMacaroons/XrdMacaroonsHandler.hh similarity index 100% rename from src/XrdMacaroons/handler.hh rename to src/XrdMacaroons/XrdMacaroonsHandler.hh From 011ad86b5cf10293b21565fa08e34687f2e833fc Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Tue, 10 Jul 2018 02:41:00 -0500 Subject: [PATCH 27/29] [XrdMacaroons] Additional build-related cleanup from merge. --- packaging/rhel/xrootd.spec.in | 3 ++ src/XrdMacaroons/README.md | 1 + src/XrdMacaroons/cmake/FindXrootd.cmake | 51 -------------------- src/XrdMacaroons/rpm/xrootd-macaroons.spec | 56 ---------------------- 4 files changed, 4 insertions(+), 107 deletions(-) delete mode 100644 src/XrdMacaroons/cmake/FindXrootd.cmake delete mode 100644 src/XrdMacaroons/rpm/xrootd-macaroons.spec diff --git a/packaging/rhel/xrootd.spec.in b/packaging/rhel/xrootd.spec.in index 65b90551dba..37915595bc5 100644 --- a/packaging/rhel/xrootd.spec.in +++ b/packaging/rhel/xrootd.spec.in @@ -63,6 +63,9 @@ BuildRequires: krb5-devel BuildRequires: zlib-devel BuildRequires: ncurses-devel BuildRequires: libcurl-devel +BuildRequires: libuuid-devel +BuildRequires: libmacaroons-devel +BuildRequires: json-c-devel BuildRequires: python2-devel %if %{?fedora}%{!?fedora:0} >= 13 diff --git a/src/XrdMacaroons/README.md b/src/XrdMacaroons/README.md index a66113525f9..beac66bbc97 100644 --- a/src/XrdMacaroons/README.md +++ b/src/XrdMacaroons/README.md @@ -11,6 +11,7 @@ Configuration To enable, you need to add three lines to the configuration file: ``` +ofs.authlib libXrdMacaroons.so http.exthandler xrdmacaroons libXrdMacaroons.so macaroons.secretkey /etc/xrootd/macaroon-secret all.sitename Example_Site diff --git a/src/XrdMacaroons/cmake/FindXrootd.cmake b/src/XrdMacaroons/cmake/FindXrootd.cmake deleted file mode 100644 index 308539f3269..00000000000 --- a/src/XrdMacaroons/cmake/FindXrootd.cmake +++ /dev/null @@ -1,51 +0,0 @@ - -FIND_PATH(XROOTD_INCLUDES XrdVersion.hh - HINTS - ${XROOTD_DIR} - $ENV{XROOTD_DIR} - /usr - /opt/xrootd/ - PATH_SUFFIXES include/xrootd - PATHS /opt/xrootd -) - -FIND_PATH(XROOTD_PRIVATE_INCLUDES XrdHttp/XrdHttpExtHandler.hh - HINTS - ${XROOTD_DIR} - $ENV{XROOTD_DIR} - /usr - /opt/xrootd/ - PATH_SUFFIXES include/xrootd/private - PATHS /opt/xrootd -) - -FIND_LIBRARY(XROOTD_UTILS_LIB XrdUtils - HINTS - ${XROOTD_DIR} - $ENV{XROOTD_DIR} - /usr - /opt/xrootd/ - PATH_SUFFIXES lib -) - -FIND_LIBRARY(XROOTD_SERVER_LIB XrdServer - HINTS - ${XROOTD_DIR} - $ENV{XROOTD_DIR} - /usr - /opt/xrootd/ - PATH_SUFFIXES lib -) - -FIND_LIBRARY(XROOTD_HTTP_LIB XrdHttp-4 - HINTS - ${XROOTD_DIR} - $ENV{XROOTD_DIR} - /usr - /opt/xrootd/ - PATH_SUFFIXES lib -) - -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(Xrootd DEFAULT_MSG XROOTD_INCLUDES XROOTD_PRIVATE_INCLUDES XROOTD_UTILS_LIB XROOTD_SERVER_LIB XROOTD_HTTP_LIB) - diff --git a/src/XrdMacaroons/rpm/xrootd-macaroons.spec b/src/XrdMacaroons/rpm/xrootd-macaroons.spec deleted file mode 100644 index f142f26ea53..00000000000 --- a/src/XrdMacaroons/rpm/xrootd-macaroons.spec +++ /dev/null @@ -1,56 +0,0 @@ - -Name: xrootd-macaroons -Version: 0.3.0 -Release: 1%{?dist} -Summary: Macaroons support for XRootD - -Group: System Environment/Daemons -License: LGPL -URL: https://github.com/bbockelm/xrootd-macaroons -# Generated from: -# git archive v%{version} --prefix=%{name}-%{version}/ | gzip -7 > ~/rpmbuild/SOURCES/%{name}-%{version}.tar.gz -Source0: %{name}-%{version}.tar.gz -BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) -BuildRequires: xrootd-devel -BuildRequires: xrootd-server-libs -BuildRequires: xrootd-server-devel -BuildRequires: xrootd-private-devel -BuildRequires: cmake -BuildRequires: gcc-c++ -BuildRequires: libcurl-devel -BuildRequires: libuuid-devel -BuildRequires: libmacaroons-devel -BuildRequires: openssl-devel -BuildRequires: json-c-devel - -%description -%{summary} - -%prep -%setup -q - -%build -%cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo . -%make_build - -%install -%make_install - -%files -%defattr(-,root,root,-) -%{_libdir}/libXrdMacaroons-4.so - -%changelog -* Mon Jul 09 2018 Brian Bockelman - 0.3.0-1 -- Add the concept of a max duration. -- Check the location matches the current location. -- Record ID usage in the logs. - -* Mon Jul 09 2018 Brian Bockelman - 0.2.0-1 -- Record authz name within the macaroon; set it on request. -- Allow multiple logging levels. -- Allow chaining of authorization libraries. - -* Fri Jun 15 2018 Brian Bockelman - 0.1.0-1 -- Initial macaroons build. - From 406d3040a6739b66670663731b0a1f90a47b7b94 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Tue, 17 Jul 2018 14:02:30 -0500 Subject: [PATCH 28/29] [XrdMacaroons] Only build Macaroons when library is present. --- cmake/XRootDDefaults.cmake | 1 - cmake/XRootDFindLibs.cmake | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/cmake/XRootDDefaults.cmake b/cmake/XRootDDefaults.cmake index d41e80d8e43..330c8c402fd 100644 --- a/cmake/XRootDDefaults.cmake +++ b/cmake/XRootDDefaults.cmake @@ -17,7 +17,6 @@ define_default( ENABLE_READLINE TRUE ) define_default( ENABLE_XRDCL TRUE ) define_default( ENABLE_TESTS FALSE ) define_default( ENABLE_HTTP TRUE ) -define_default( ENABLE_MACAROONS TRUE ) define_default( ENABLE_CEPH TRUE ) define_default( ENABLE_PYTHON TRUE ) define_default( XRD_PYTHON_REQ_VERSION 2.4 ) diff --git a/cmake/XRootDFindLibs.cmake b/cmake/XRootDFindLibs.cmake index cf761023dbd..5619967a518 100644 --- a/cmake/XRootDFindLibs.cmake +++ b/cmake/XRootDFindLibs.cmake @@ -89,15 +89,15 @@ check_function_exists( curl_multi_wait HAVE_CURL_MULTI_WAIT ) compiler_define_if_found( HAVE_CURL_MULTI_WAIT HAVE_CURL_MULTI_WAIT ) endif() -if( ENABLE_MACAROONS ) -find_package( Macaroons REQUIRED ) +find_package( Macaroons ) include (FindPkgConfig) -pkg_check_modules(JSON REQUIRED json-c) -pkg_check_modules(UUID REQUIRED uuid) +pkg_check_modules(JSON json-c) +pkg_check_modules(UUID uuid) -set( BUILD_MACAROONS TRUE ) +if( Macaroons_FOUND AND JSON_FOUND AND UUID_FOUND ) + set( BUILD_MACAROONS TRUE ) else() -set( BUILD_MACAROONS FALSE ) + set( BUILD_MACAROONS FALSE ) endif() if( ENABLE_CEPH ) From c67fcac4be90c2aea5eebc6b5d00ab85d1c18a28 Mon Sep 17 00:00:00 2001 From: Brian Bockelman Date: Tue, 17 Jul 2018 14:06:12 -0500 Subject: [PATCH 29/29] [XrdMacaroons] Do not attempt to install libXrdMacaroons on debian. --- packaging/debian/xrootd-server-libs.install | 1 - 1 file changed, 1 deletion(-) diff --git a/packaging/debian/xrootd-server-libs.install b/packaging/debian/xrootd-server-libs.install index b0de2911373..9472aff6204 100644 --- a/packaging/debian/xrootd-server-libs.install +++ b/packaging/debian/xrootd-server-libs.install @@ -6,7 +6,6 @@ usr/lib/*/libXrdBlacklistDecision-4.so usr/lib/*/libXrdHttp-4.so usr/lib/*/libXrdHttpTPC-4.so usr/lib/*/libXrdHttpUtils.so.* -usr/lib/*/libXrdMacaroons-4.so usr/lib/*/libXrdN2No2p-4.so usr/lib/*/libXrdOssSIgpfsT-4.so usr/lib/*/libXrdServer.so.*