Commit 7b015931 authored by Nikola Hardi's avatar Nikola Hardi
Browse files

Sync the credentials manager with libjalienO2

parent b1558793
Pipeline #2447964 passed with stage
in 7 minutes and 51 seconds
// Author: Nikola Hardi 3/6/2019 // Author: Nikola Hardi 3/6/2019
#ifndef ROOT_TJAlienCredentials #ifndef ROOT_TJAlienCredentials
#define ROOT_TJAlienCredentials #define ROOT_TJAlienCredentials
#include <string> #include <cstring>
#include <iostream>
#include <map> #include <map>
#include <string>
#include <termios.h> #include <termios.h>
#include "TObject.h"
using std::string; #define __FILENAMEEXT__ \
(strrchr(__FILE__, '/') ? std::string(strrchr(__FILE__, '/') + 1) \
: std::string(__FILE__))
#define __FILENAME__ __FILENAMEEXT__.substr(0, __FILENAMEEXT__.find('.'))
#define INFO(message) \
std::cout << "\rInfo in <" << __FILENAME__ << "::" << __func__ \
<< ">: " << message << std::endl
#define ERROR(message) \
std::cerr << "\rError in <" << __FILENAME__ << "::" << __func__ \
<< ">: " << message << std::endl
using std::map; using std::map;
using std::string;
enum CredentialsKind { cJBOX_TOKEN = 0, enum CredentialsKind {
cNOT_FOUND = -1,
cJBOX_TOKEN = 0,
cFULL_GRID_CERT, cFULL_GRID_CERT,
cJOB_TOKEN, cJOB_TOKEN,
cOTHER_TOKEN, cOTHER_TOKEN,
}; };
class TJAlienCredentialsObject { class TJAlienCredentialsObject {
public: public:
string certpath; string certpath;
string keypath; string keypath;
string password; string password;
...@@ -25,11 +38,10 @@ class TJAlienCredentialsObject { ...@@ -25,11 +38,10 @@ class TJAlienCredentialsObject {
bool autoremove; bool autoremove;
TJAlienCredentialsObject() {} TJAlienCredentialsObject() {}
TJAlienCredentialsObject(string certpath,
string keypath, TJAlienCredentialsObject(string certpath, string keypath,
CredentialsKind kind = cOTHER_TOKEN, CredentialsKind kind = cOTHER_TOKEN,
bool autoremove = false) bool autoremove = false) {
{
this->certpath = certpath; this->certpath = certpath;
this->keypath = keypath; this->keypath = keypath;
this->kind = kind; this->kind = kind;
...@@ -37,8 +49,10 @@ class TJAlienCredentialsObject { ...@@ -37,8 +49,10 @@ class TJAlienCredentialsObject {
}; };
void wipe() { void wipe() {
if(autoremove) { if (autoremove) {
if(gDebug) printf("removing safe files: %s %s\n", certpath.c_str(), keypath.c_str()); int gDebug = std::getenv("gDebug") ? std::stoi(std::getenv("gDebug")) : 0;
if (gDebug)
INFO("removing safe files: " << certpath.c_str() << keypath.c_str());
remove(certpath.c_str()); remove(certpath.c_str());
remove(keypath.c_str()); remove(keypath.c_str());
} }
...@@ -51,7 +65,7 @@ class TJAlienCredentialsObject { ...@@ -51,7 +65,7 @@ class TJAlienCredentialsObject {
void readPassword(); void readPassword();
}; };
class TJAlienCredentials : public TObject { class TJAlienCredentials {
public: public:
TJAlienCredentials(); TJAlienCredentials();
~TJAlienCredentials(); ~TJAlienCredentials();
...@@ -60,10 +74,15 @@ public: ...@@ -60,10 +74,15 @@ public:
static string getHomeDir(); static string getHomeDir();
void loadCredentials(); void loadCredentials();
bool has(CredentialsKind kind); bool has(CredentialsKind kind) const;
TJAlienCredentialsObject get(CredentialsKind kind); TJAlienCredentialsObject get(CredentialsKind kind) const;
TJAlienCredentialsObject get();
void removeCredentials(CredentialsKind kind); void removeCredentials(CredentialsKind kind);
short count(); short count();
void selectPreferedCredentials();
CredentialsKind getPreferedCredentials() const;
const string& getMessages() const;
bool checkCertValidity(const char *path);
static const char *ENV_JOBTOKEN_KEY; static const char *ENV_JOBTOKEN_KEY;
static const char *ENV_JOBTOKEN_CERT; static const char *ENV_JOBTOKEN_CERT;
...@@ -71,6 +90,7 @@ public: ...@@ -71,6 +90,7 @@ public:
static const char *TMP_JOBTOKEN_CERT_FNAME_PREFIX; static const char *TMP_JOBTOKEN_CERT_FNAME_PREFIX;
private: private:
CredentialsKind preferedCredentials;
void loadTokenCertificate(); void loadTokenCertificate();
void loadFullGridCertificate(); void loadFullGridCertificate();
void loadJobTokenCertificate(); void loadJobTokenCertificate();
...@@ -79,13 +99,12 @@ private: ...@@ -79,13 +99,12 @@ private:
string getTokencertPath(); string getTokencertPath();
string getTokenkeyPath(); string getTokenkeyPath();
string getSafeFilename(const string& prefix); string getSafeFilename(const string &prefix);
void writeSafeFile(const string& filepath, const string& content); void writeSafeFile(const string &filepath, const string &content);
string tmpdir; string tmpdir;
string homedir; string homedir;
string msg;
map<CredentialsKind, TJAlienCredentialsObject> found_credentials; map<CredentialsKind, TJAlienCredentialsObject> found_credentials;
ClassDef(TJAlienCredentials, 0)
}; };
#endif #endif
#include "TJAlienCredentials.h" #include "TJAlienCredentials.h"
#include <sstream> #include <cerrno>
#include <cstdlib> #include <cstdlib>
#include <unistd.h> #include <fcntl.h>
#include <fstream> #include <fstream>
#include <cstdlib>
#include <iostream> #include <iostream>
#include <fcntl.h> #include <sstream>
#include <unistd.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
using std::endl;
using std::getenv;
using std::ifstream; using std::ifstream;
using std::ofstream; using std::ofstream;
using std::stringstream; using std::stringstream;
using std::endl;
using std::getenv;
const char* TJAlienCredentials::ENV_JOBTOKEN_KEY = "JALIEN_TOKEN_KEY"; const char *TJAlienCredentials::ENV_JOBTOKEN_KEY = "JALIEN_TOKEN_KEY";
const char* TJAlienCredentials::ENV_JOBTOKEN_CERT = "JALIEN_TOKEN_CERT"; const char *TJAlienCredentials::ENV_JOBTOKEN_CERT = "JALIEN_TOKEN_CERT";
const char* TJAlienCredentials::TMP_JOBTOKEN_KEY_FNAME_PREFIX = "tmpjobtokenkey_"; const char *TJAlienCredentials::TMP_JOBTOKEN_KEY_FNAME_PREFIX =
const char* TJAlienCredentials::TMP_JOBTOKEN_CERT_FNAME_PREFIX = "tmpjobtokencert_"; "tmpjobtokenkey_";
const char *TJAlienCredentials::TMP_JOBTOKEN_CERT_FNAME_PREFIX =
"tmpjobtokencert_";
bool fileExists(const string &filename) bool fileExists(const string &filename) {
{
bool fileExists = false; bool fileExists = false;
FILE *f = fopen(filename.c_str(), "r"); FILE *f = fopen(filename.c_str(), "r");
if (f != NULL ) { if (f != NULL) {
fclose(f); fclose(f);
fileExists = true; fileExists = true;
} else { } else {
...@@ -34,24 +37,28 @@ bool fileExists(const string &filename) ...@@ -34,24 +37,28 @@ bool fileExists(const string &filename)
return fileExists; return fileExists;
} }
bool TJAlienCredentialsObject::exists() { bool TJAlienCredentialsObject::exists() {
return fileExists(certpath) && fileExists(keypath); return fileExists(certpath) && fileExists(keypath);
} }
void TJAlienCredentials::writeSafeFile(const string& filename, const string& content) { void TJAlienCredentials::writeSafeFile(const string &filename,
if(gDebug) printf("writing safe file %s\n", filename.c_str()); const string &content) {
int gDebug = std::getenv("gDebug") ? std::stoi(std::getenv("gDebug")) : 0;
if (gDebug)
INFO("writing safe file " << filename.c_str());
int fd = open(filename.c_str(), O_RDWR | O_CREAT, 0600); int fd = open(filename.c_str(), O_RDWR | O_CREAT, 0600);
write(fd, content.c_str(), content.length()); if (write(fd, content.c_str(), content.length()) == -1)
if (gDebug)
ERROR("writing safe file failed: " << std::strerror(errno));
close(fd); close(fd);
} }
string TJAlienCredentials::getSafeFilename(const string& prefix) { string TJAlienCredentials::getSafeFilename(const string &prefix) {
string filename = TJAlienCredentials::getTmpDir() + "/" + prefix; string filename = TJAlienCredentials::getTmpDir() + "/" + prefix;
const char *JOB_ID = getenv("ALIEN_PROC_ID"); const char *JOB_ID = getenv("ALIEN_PROC_ID");
if(JOB_ID != NULL) { if (JOB_ID != NULL) {
filename += JOB_ID; filename += JOB_ID;
} else { } else {
pid_t pid = getpid(); pid_t pid = getpid();
...@@ -59,15 +66,14 @@ string TJAlienCredentials::getSafeFilename(const string& prefix) { ...@@ -59,15 +66,14 @@ string TJAlienCredentials::getSafeFilename(const string& prefix) {
do { do {
filename += std::to_string(pid) + "_" + std::to_string(rnd); filename += std::to_string(pid) + "_" + std::to_string(rnd);
} while(fileExists(filename)); } while (fileExists(filename));
} }
return filename; return filename;
} }
string TJAlienCredentials::getTmpDir() { std::string TJAlienCredentials::getTmpDir() {
string tmpdir; std::string tmpdir;
if (getenv("TMPDIR") != NULL) if (getenv("TMPDIR") != NULL)
tmpdir = getenv("TMPDIR"); tmpdir = getenv("TMPDIR");
...@@ -81,8 +87,8 @@ string TJAlienCredentials::getTmpDir() { ...@@ -81,8 +87,8 @@ string TJAlienCredentials::getTmpDir() {
return tmpdir; return tmpdir;
} }
string TJAlienCredentials::getHomeDir() { std::string TJAlienCredentials::getHomeDir() {
string homedir; std::string homedir;
if (getenv("HOME") != NULL) if (getenv("HOME") != NULL)
homedir = getenv("HOME"); homedir = getenv("HOME");
...@@ -92,37 +98,33 @@ string TJAlienCredentials::getHomeDir() { ...@@ -92,37 +98,33 @@ string TJAlienCredentials::getHomeDir() {
return homedir; return homedir;
} }
string TJAlienCredentials::getTokencertPath() std::string TJAlienCredentials::getTokencertPath() {
{
std::stringstream tokencert_s; std::stringstream tokencert_s;
tokencert_s << tmpdir << "/tokencert_" << getuid() << ".pem"; tokencert_s << tmpdir << "/tokencert_" << getuid() << ".pem";
std::string tokencert = tokencert_s.str(); std::string tokencert = tokencert_s.str();
std::string tokencertpath = std::getenv("JALIEN_TOKEN_CERT") ? : tokencert; std::string tokencertpath = std::getenv("JALIEN_TOKEN_CERT") ?: tokencert;
return tokencertpath; return tokencertpath;
} }
string TJAlienCredentials::getTokenkeyPath() std::string TJAlienCredentials::getTokenkeyPath() {
{
std::stringstream tokenkey_s; std::stringstream tokenkey_s;
tokenkey_s << tmpdir << "/tokenkey_" << getuid() << ".pem"; tokenkey_s << tmpdir << "/tokenkey_" << getuid() << ".pem";
std::string tokenkey = tokenkey_s.str(); std::string tokenkey = tokenkey_s.str();
std::string tokenkeypath = std::getenv("JALIEN_TOKEN_KEY") ? : tokenkey; std::string tokenkeypath = std::getenv("JALIEN_TOKEN_KEY") ?: tokenkey;
return tokenkeypath; return tokenkeypath;
} }
string TJAlienCredentials::getUsercertPath() std::string TJAlienCredentials::getUsercertPath() {
{
std::string usercert = homedir + "/.globus/usercert.pem"; std::string usercert = homedir + "/.globus/usercert.pem";
std::string usercertpath = std::getenv("X509_USER_CERT") ? : usercert; std::string usercertpath = std::getenv("X509_USER_CERT") ?: usercert;
return usercertpath; return usercertpath;
} }
string TJAlienCredentials::getUserkeyPath() string TJAlienCredentials::getUserkeyPath() {
{
std::string userkey = homedir + "/.globus/userkey.pem"; std::string userkey = homedir + "/.globus/userkey.pem";
std::string userkeypath = std::getenv("X509_USER_KEY") ? : userkey; std::string userkeypath = std::getenv("X509_USER_KEY") ?: userkey;
return userkeypath; return userkeypath;
} }
...@@ -140,15 +142,17 @@ void TJAlienCredentials::loadCredentials() { ...@@ -140,15 +142,17 @@ void TJAlienCredentials::loadCredentials() {
} }
void TJAlienCredentials::loadTokenCertificate() { void TJAlienCredentials::loadTokenCertificate() {
TJAlienCredentialsObject token_credentials(getTokencertPath(), getTokenkeyPath(), cJBOX_TOKEN); TJAlienCredentialsObject token_credentials(getTokencertPath(),
getTokenkeyPath(), cJBOX_TOKEN);
if(token_credentials.exists()) { if (token_credentials.exists()) {
found_credentials[cJBOX_TOKEN] = token_credentials; found_credentials[cJBOX_TOKEN] = token_credentials;
} }
} }
void TJAlienCredentials::loadFullGridCertificate() { void TJAlienCredentials::loadFullGridCertificate() {
TJAlienCredentialsObject grid_certificate(getUsercertPath(), getUserkeyPath(), cFULL_GRID_CERT); TJAlienCredentialsObject grid_certificate(getUsercertPath(), getUserkeyPath(),
cFULL_GRID_CERT);
if (grid_certificate.exists()) { if (grid_certificate.exists()) {
found_credentials[cFULL_GRID_CERT] = grid_certificate; found_credentials[cFULL_GRID_CERT] = grid_certificate;
...@@ -160,73 +164,89 @@ void TJAlienCredentials::loadJobTokenCertificate() { ...@@ -160,73 +164,89 @@ void TJAlienCredentials::loadJobTokenCertificate() {
const char *env_key = getenv(ENV_JOBTOKEN_KEY); const char *env_key = getenv(ENV_JOBTOKEN_KEY);
// if it doesn't have both environment variables // if it doesn't have both environment variables
if(!env_cert || !env_key) { if (!env_cert || !env_key) {
return; return;
} }
// environment variables contain valid filepaths instead of the actual token // environment variables contain valid filepaths instead of the actual token
if(fileExists(env_cert) && fileExists(env_key)) { if (fileExists(env_cert) && fileExists(env_key)) {
found_credentials[cJOB_TOKEN] = TJAlienCredentialsObject(env_cert, env_key, cJOB_TOKEN); found_credentials[cJOB_TOKEN] =
TJAlienCredentialsObject(env_cert, env_key, cJOB_TOKEN);
} else { } else {
const string& tmpcertpath = getSafeFilename(TMP_JOBTOKEN_CERT_FNAME_PREFIX); const string &tmpcertpath = getSafeFilename(TMP_JOBTOKEN_CERT_FNAME_PREFIX);
writeSafeFile(tmpcertpath, env_cert); writeSafeFile(tmpcertpath, env_cert);
const string& tmpkeypath = getSafeFilename(TMP_JOBTOKEN_KEY_FNAME_PREFIX); const string &tmpkeypath = getSafeFilename(TMP_JOBTOKEN_KEY_FNAME_PREFIX);
writeSafeFile(tmpkeypath, env_key); writeSafeFile(tmpkeypath, env_key);
found_credentials[cJOB_TOKEN] = TJAlienCredentialsObject(tmpcertpath, tmpkeypath, cJOB_TOKEN, true); found_credentials[cJOB_TOKEN] =
TJAlienCredentialsObject(tmpcertpath, tmpkeypath, cJOB_TOKEN, true);
} }
} }
bool TJAlienCredentials::has(CredentialsKind kind) { bool TJAlienCredentials::has(CredentialsKind kind) const {
return found_credentials.count(kind) == 1; return found_credentials.count(kind) == 1;
} }
TJAlienCredentialsObject TJAlienCredentials::get(CredentialsKind kind) { TJAlienCredentialsObject TJAlienCredentials::get(CredentialsKind kind) const {
if(this->has(kind)) { if (this->has(kind)) {
return found_credentials[kind]; return found_credentials.at(kind);
} else {
return TJAlienCredentialsObject();
}
}
TJAlienCredentialsObject TJAlienCredentials::get() {
if (this->has(cJOB_TOKEN)) {
return this->get(cJOB_TOKEN);
} else if (this->has(cJBOX_TOKEN)) {
return this->get(cJBOX_TOKEN);
} else if (this->has(cFULL_GRID_CERT)) {
TJAlienCredentialsObject co = this->get(cFULL_GRID_CERT);
if (co.password.empty())
co.readPassword();
return co;
} else { } else {
ERROR("Failed to get any credentials");
return TJAlienCredentialsObject(); return TJAlienCredentialsObject();
} }
} }
void TJAlienCredentials::removeCredentials(CredentialsKind kind) { void TJAlienCredentials::removeCredentials(CredentialsKind kind) {
if (this->has(kind)) { if (this->has(kind)) {
if(kind == cJOB_TOKEN) if (kind == cJOB_TOKEN)
get(kind).wipe(); get(kind).wipe();
found_credentials.erase(kind); found_credentials.erase(kind);
} }
} }
short TJAlienCredentials::count() { short TJAlienCredentials::count() { return found_credentials.size(); }
return found_credentials.size();
}
string readFile(const char* filename) { std::string readFile(const char *filename) {
string line; std::string line;
stringstream contents; std::stringstream contents;
ifstream f(filename); std::ifstream f(filename);
if(f.is_open()) { if (f.is_open()) {
while(getline(f, line)) { while (getline(f, line)) {
contents << line << endl; contents << line << std::endl;
} }
} }
return contents.str(); return contents.str();
} }
const string TJAlienCredentialsObject::getKey() { const std::string TJAlienCredentialsObject::getKey() {
return readFile(keypath.c_str()); return readFile(keypath.c_str());
} }
const string TJAlienCredentialsObject::getCertificate() { const std::string TJAlienCredentialsObject::getCertificate() {
return readFile(certpath.c_str()); return readFile(certpath.c_str());
} }
void TJAlienCredentialsObject::readPassword() { void TJAlienCredentialsObject::readPassword() {
if (this->kind == cFULL_GRID_CERT && this->getKey().find("ENCRYPTED") != std::string::npos) if (this->kind == cFULL_GRID_CERT &&
{ this->getKey().find("ENCRYPTED") != std::string::npos) {
printf("[Grid certificate password: ]"); printf("[Grid certificate password: ]");
struct termios termold, termnew; struct termios termold, termnew;
tcgetattr(fileno(stdin), &termold); tcgetattr(fileno(stdin), &termold);
...@@ -236,17 +256,20 @@ void TJAlienCredentialsObject::readPassword() { ...@@ -236,17 +256,20 @@ void TJAlienCredentialsObject::readPassword() {
tcsetattr(fileno(stdin), TCSANOW, &termnew); tcsetattr(fileno(stdin), TCSANOW, &termnew);
char password[64]; char password[64];
if (!fgets(password, sizeof(password), stdin)) if (fgets(password, sizeof(password), stdin) != nullptr) {
printf("\nFailed to get password input\n");
tcsetattr(0, TCSANOW, &termold); tcsetattr(0, TCSANOW, &termold);
password[strlen(password) - 1] = 0; password[strlen(password) - 1] = 0;
this->password = std::string(password); this->password = std::string(password);
} else {
ERROR("Error while reading from stdin");
this->password = "";
} }
} else
this->password = "";
} }
const string TJAlienCredentialsObject::getPassword() { const std::string TJAlienCredentialsObject::getPassword() {
if (this->password.empty()) if (this->password.empty())
readPassword(); readPassword();
...@@ -256,3 +279,84 @@ const string TJAlienCredentialsObject::getPassword() { ...@@ -256,3 +279,84 @@ const string TJAlienCredentialsObject::getPassword() {
TJAlienCredentials::~TJAlienCredentials() { TJAlienCredentials::~TJAlienCredentials() {
removeCredentials(cJOB_TOKEN); removeCredentials(cJOB_TOKEN);
} }
void TJAlienCredentials::selectPreferedCredentials() {
msg = "";
if(has(cJOB_TOKEN)) {
preferedCredentials = cJOB_TOKEN;
return;
}
if (has(cJBOX_TOKEN)) {
if(!checkCertValidity(getTokencertPath().c_str())) {
msg += "Token certificate is invalid or expired and it should be renewed.\n";
} else {
preferedCredentials = cJBOX_TOKEN;
return;
}
}
if (has(cFULL_GRID_CERT)) {
msg += "Fallback to full grid cert - please use alien-token-init or TGrid::Connect() to renew it.\n";
preferedCredentials = cFULL_GRID_CERT;
return;
}