Skip to content

Commit

Permalink
CONSOLE: Add C++ generator for JWK info and drop the go implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
Elvin Alin Sindrilaru authored and esindril committed Dec 3, 2024
1 parent b7f0df9 commit be6915d
Show file tree
Hide file tree
Showing 13 changed files with 25,054 additions and 85 deletions.
2 changes: 2 additions & 0 deletions console/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
# * along with this program. If not, see <http://www.gnu.org/licenses/>.*
# ************************************************************************

include_directories(${CMAKE_CURRENT_SOURCE_DIR}/commands/helpers/)

#-------------------------------------------------------------------------------
# eos executable
#-------------------------------------------------------------------------------
Expand Down
161 changes: 88 additions & 73 deletions console/commands/com_scitoken.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ com_scitoken(char* arg1)
}

#else
#include "console/ConsoleMain.hh"
#include "console/commands/helpers/jwk_generator/jwk_generator.hpp"
#include "common/Mapping.hh"
#include "common/StringTokenizer.hh"
#include "common/Utils.hh"
#include "console/ConsoleMain.hh"
#include <common/Logging.hh>
#include <cstdio>
#include <fstream>
Expand Down Expand Up @@ -282,91 +283,105 @@ com_scitoken(char* arg1)
}

if (subcommand == "create-keys") {
struct stat buf;
do {
const char* o = subtokenizer.GetTokenUnquoted();
const char* v = subtokenizer.GetTokenUnquoted();

if (::stat("/sbin/eos-jwker", &buf)) {
std::cerr << "error: couldn't find /sbin/eos-jwker" << std::endl;
global_retc = EOPNOTSUPP;
if (o && !v) {
goto com_scitoken_usage;
}

if (!o && !v) {
break;
}

option = o;
value = v;

if (option == "--keyid") {
keyid = value;
}
} while (option.length());

std::string prefix;

if (!keyid.empty()) {
prefix = "/etc/xrootd/";
} else {
do {
const char* o = subtokenizer.GetTokenUnquoted();
const char* v = subtokenizer.GetTokenUnquoted();
keyid = "default";
const size_t size = 1024;
char buffer[size];

if (o && !v) {
goto com_scitoken_usage;
}
if (getcwd(buffer, size) == nullptr) {
std::cerr << "error: can not get CWD" << std::endl;
global_retc = errno;
return 0;
}

if (!o && !v) {
break;
}
prefix = buffer;
}

option = o;
value = v;
if (*prefix.rbegin() != '/') {
prefix += '/';
}

if (option == "--keyid") {
keyid = value;
}
// If the public/private key files exist then we use them to generate
// the jwk file, otherwise we generate new keys
bool store_keys = false;
std::string fn_public = SSTR(prefix << keyid << "-pkey.pem").c_str();
std::string fn_private = SSTR(prefix << keyid << "-key.pem").c_str();
std::string jwk_file;
struct stat buf;

if (option == "--jwk") {
jwk = value;
}
} while (option.length());
if (::stat(fn_public.c_str(), &buf) ||
::stat(fn_private.c_str(), &buf)) {
// We generate new keys
fn_public = "";
fn_private = "";
store_keys = true;
}

system("openssl ecparam -genkey -name prime256v1 > /tmp/.eossci.ec "
"2>/dev/null");
system("openssl pkcs8 -topk8 -nocrypt -in /tmp/.eossci.ec -out "
"/tmp/.eossci-key.pem 2>/dev/null");
system("cat /tmp/.eossci.ec | openssl ec -pubout > /tmp/.eossci-pkey.pem "
"2>/dev/null");
system(
"/sbin/eos-jwker /tmp/.eossci-pkey.pem | json_pp > /tmp/.eossci.jwk ");
{
Json::Value json;
Json::Value root;
std::string errs;
Json::CharReaderBuilder reader;
std::ifstream configfile("/tmp/.eossci.jwk", std::ifstream::binary);
bool ok = parseFromStream(reader, configfile, &root, &errs);

if (ok) {
// store the keyid into the JSON document
root["kid"] = keyid.length() ? keyid : "default";
} else {
global_retc = EIO;
return (0);
}
using namespace jwk_generator;
JwkGenerator<ES256> jwk(keyid, fn_public, fn_private);
std::cout << "JWK:\n" << jwk.to_pretty_string()
<< std::endl << std::endl;

if (store_keys) {
fn_public = SSTR(prefix << keyid << "-pkey.pem").c_str();
fn_private = SSTR(prefix << keyid << "-key.pem").c_str();
jwk_file = SSTR(prefix << keyid << "-sci.jwk").c_str();

for (auto pair : std::list<std::pair<std::string, std::string>> {
{fn_public, jwk.public_to_pem()},
{fn_private, jwk.private_to_pem()},
{jwk_file, jwk.to_pretty_string()}
}) {
std::ofstream file(pair.first);

if (!file.is_open()) {
std::cerr << "error: failed to open public key file "
<< pair.first << std::endl;
global_retc = EINVAL;
return 0;
}

json["keys"].append(root);
std::cout << SSTR(json) << std::endl;
file << pair.second << std::endl;
file.close();
}
}
std::string prefix;

if (keyid.length()) {
prefix = "/etc/xrootd/";
} else {
keyid = "default";
if (!fn_public.empty() && !fn_private.empty()) {
std::cerr << (store_keys ? "Wrote" : "Used") << " public key : "
<< fn_public << std::endl
<< (store_keys ? "Wrote" : "Used") << " private key: "
<< fn_private << std::endl;

if (!jwk_file.empty()) {
std::cerr << "Wrote JWK file : " << jwk_file << std::endl;
}
}

std::string s;
s = "mv /tmp/.eossci-pkey.pem ";
s += prefix;
s += keyid;
s += "-pkey.pem";
system(s.c_str());
::unlink("/tmp/.eossci-pkey.pem");
s = "mv /tmp/.eossci-key.pem ";
s += prefix;
s += keyid;
s += "-key.pem";
system(s.c_str());
::unlink("/tmp/.eossci-key.pem");
::unlink("/tmp/.eossci.ec");
std::cerr << "# private key : " << prefix << keyid << "-key.pem"
<< std::endl;
std::cerr << "# public key : " << prefix << keyid << "-pkey.pem"
<< std::endl;
return (0);
return 0;
}

com_scitoken_usage:
Expand Down Expand Up @@ -399,7 +414,7 @@ com_scitoken(char* arg1)
<< " eos scitoken create --issuer eos.cern.ch --keyid eos "
<< "profile wlcg --claim sub=foo --claim scope=storage.read:/eos\n"
<< " eos scitoken dump eyJhb ...\n"
<< " eos scitoken create-keys --keyid eos > /etc/xrootrd/eos.json\n";
<< " eos scitoken create-keys --keyid eos > /etc/xrootd/eos.jwk\n";
std::cerr << oss.str().c_str() << std::endl;
global_retc = EINVAL;
return 0;
Expand Down
53 changes: 53 additions & 0 deletions console/commands/helpers/jwk_generator/c_resource.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#pragma once
#include <memory>
#include <functional>
#include <type_traits>
#include <stdexcept>

template <typename T, auto deleter, auto allocator = nullptr>
class c_resource
{
private:
std::unique_ptr<T, decltype(deleter)> ptr;
public:
c_resource(std::function<T*()> creater) : ptr{creater(), deleter} {}
c_resource(T* ptr) : ptr{ptr, deleter} {}
c_resource() : ptr {nullptr, deleter} {}

static c_resource allocate()
{
static_assert(not std::is_null_pointer_v<decltype(allocator)>,
"allocate should not be used without a defined allocator");
return c_resource(allocator);
}

operator bool() const
{
return ptr;
}

auto release()
{
return ptr.release();
}

auto get()
{
return ptr.get();
}

auto get() const
{
return ptr.get();
}

operator T* ()
{
return get();
}

operator const T* () const
{
return get();
}
};
22 changes: 22 additions & 0 deletions console/commands/helpers/jwk_generator/errors.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once
#include <openssl/err.h>
#include <string>
#include <stdexcept>

namespace jwk_generator
{
struct openssl_error: public std::runtime_error {
private:
static inline std::string open_ssl_last_error()
{
int err = ERR_get_error();
char errStr[256];
ERR_error_string(err, errStr);
return std::string(errStr);
}
public:
openssl_error(std::string what) : std::runtime_error(what +
open_ssl_last_error()) {}
};
};

Loading

0 comments on commit be6915d

Please sign in to comment.