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 {
cFULL_GRID_CERT, cNOT_FOUND = -1,
cJOB_TOKEN, cJBOX_TOKEN = 0,
cOTHER_TOKEN, cFULL_GRID_CERT,
cJOB_TOKEN,
cOTHER_TOKEN,
}; };
class TJAlienCredentialsObject { class TJAlienCredentialsObject {
public: public:
string certpath; string certpath;
string keypath; string keypath;
string password; string password;
CredentialsKind kind; CredentialsKind kind;
bool autoremove; bool autoremove;
TJAlienCredentialsObject() {} TJAlienCredentialsObject() {}
TJAlienCredentialsObject(string certpath,
string keypath,
CredentialsKind kind = cOTHER_TOKEN,
bool autoremove = false)
{
this->certpath = certpath;
this->keypath = keypath;
this->kind = kind;
this->autoremove = autoremove;
};
void wipe() { TJAlienCredentialsObject(string certpath, string keypath,
if(autoremove) { CredentialsKind kind = cOTHER_TOKEN,
if(gDebug) printf("removing safe files: %s %s\n", certpath.c_str(), keypath.c_str()); bool autoremove = false) {
remove(certpath.c_str()); this->certpath = certpath;
remove(keypath.c_str()); this->keypath = keypath;
} this->kind = kind;
this->autoremove = autoremove;
};
void wipe() {
if (autoremove) {
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(keypath.c_str());
} }
}
bool exists(); bool exists();
const string getKey(); const string getKey();
const string getCertificate(); const string getCertificate();
const string getPassword(); const string getPassword();
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 {
fileExists = false; fileExists = false;
} }
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 fd = open(filename.c_str(), O_RDWR | O_CREAT, 0600); int gDebug = std::getenv("gDebug") ? std::stoi(std::getenv("gDebug")) : 0;
write(fd, content.c_str(), content.length()); if (gDebug)
close(fd); INFO("writing safe file " << filename.c_str());
int fd = open(filename.c_str(), O_RDWR | O_CREAT, 0600);
if (write(fd, content.c_str(), content.length()) == -1)
if (gDebug)
ERROR("writing safe file failed: " << std::strerror(errno));
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");
if(JOB_ID != NULL) { const char *JOB_ID = getenv("ALIEN_PROC_ID");
filename += JOB_ID;
} else {
pid_t pid = getpid();
unsigned int rnd = random() % 100 + 1;
do { if (JOB_ID != NULL) {
filename += std::to_string(pid) + "_" + std::to_string(rnd); filename += JOB_ID;
} while(fileExists(filename)); } else {
} pid_t pid = getpid();
unsigned int rnd = random() % 100 + 1;
do {
filename += std::to_string(pid) + "_" + std::to_string(rnd);
} 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");
else if (getenv("TMP") != NULL) else if (getenv("TMP") != NULL)
tmpdir = getenv("TMP"); tmpdir = getenv("TMP");
else if (getenv("TEMP") != NULL) else if (getenv("TEMP") != NULL)
tmpdir = getenv("TEMP"); tmpdir = getenv("TEMP");
else else
tmpdir = P_tmpdir; tmpdir = P_tmpdir;
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");
else else
homedir = "~"; homedir = "~";
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;
} }
TJAlienCredentials::TJAlienCredentials() { TJAlienCredentials::TJAlienCredentials() {
tmpdir = getTmpDir(); tmpdir = getTmpDir();
homedir = getHomeDir(); homedir = getHomeDir();
} }
void TJAlienCredentials::loadCredentials() { void TJAlienCredentials::loadCredentials() {
removeCredentials(cJOB_TOKEN); removeCredentials(cJOB_TOKEN);
found_credentials.clear(); found_credentials.clear();
loadTokenCertificate(); loadTokenCertificate();
loadFullGridCertificate(); loadFullGridCertificate();
loadJobTokenCertificate(); loadJobTokenCertificate();
} }
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;
} }
} }
void TJAlienCredentials::loadJobTokenCertificate() { void TJAlienCredentials::loadJobTokenCertificate() {
const char *env_cert = getenv(ENV_JOBTOKEN_CERT); const char *env_cert = getenv(ENV_JOBTOKEN_CERT);
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 (!env_cert || !env_key) {
return;
}
// environment variables contain valid filepaths instead of the actual token
if (fileExists(env_cert) && fileExists(env_key)) {
found_credentials[cJOB_TOKEN] =
TJAlienCredentialsObject(env_cert, env_key, cJOB_TOKEN);
} else {
const string &tmpcertpath = getSafeFilename(TMP_JOBTOKEN_CERT_FNAME_PREFIX);
writeSafeFile(tmpcertpath, env_cert);
const string &tmpkeypath = getSafeFilename(TMP_JOBTOKEN_KEY_FNAME_PREFIX);
writeSafeFile(tmpkeypath, env_key);
found_credentials[cJOB_TOKEN] =
TJAlienCredentialsObject(tmpcertpath, tmpkeypath, cJOB_TOKEN, true);
}
}
// if it doesn't have both environment variables bool TJAlienCredentials::has(CredentialsKind kind) const {
if(!env_cert || !env_key) { return found_credentials.count(kind) == 1;
return; }
}
// environment variables contain valid filepaths instead of the actual token TJAlienCredentialsObject TJAlienCredentials::get(CredentialsKind kind) const {
if(fileExists(env_cert) && fileExists(env_key)) { if (this->has(kind)) {
found_credentials[cJOB_TOKEN] = TJAlienCredentialsObject(env_cert, env_key, cJOB_TOKEN); return found_credentials.at(kind);
} else { } else {
const string& tmpcertpath = getSafeFilename(TMP_JOBTOKEN_CERT_FNAME_PREFIX); return TJAlienCredentialsObject();
writeSafeFile(tmpcertpath, env_cert); }
}
const string& tmpkeypath = getSafeFilename(TMP_JOBTOKEN_KEY_FNAME_PREFIX); TJAlienCredentialsObject TJAlienCredentials::get() {
writeSafeFile(tmpkeypath, env_key); 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 {
ERROR("Failed to get any credentials");
return TJAlienCredentialsObject();
}
}
void TJAlienCredentials::removeCredentials(CredentialsKind kind) {
if (this->has(kind)) {
if (kind == cJOB_TOKEN)
get(kind).wipe();
found_credentials.erase(kind);
}
}
short TJAlienCredentials::count() { return found_credentials.size(); }
found_credentials[cJOB_TOKEN] = TJAlienCredentialsObject(tmpcertpath, tmpkeypath, cJOB_TOKEN, true); std::string readFile(const char *filename) {
std::string line;
std::stringstream contents;
std::ifstream f(filename);
if (f.is_open()) {
while (getline(f, line)) {
contents << line << std::endl;
} }
}
return contents.str();
}
const std::string TJAlienCredentialsObject::getKey() {
return readFile(keypath.c_str());
} }
bool TJAlienCredentials::has(CredentialsKind kind) { const std::string TJAlienCredentialsObject::getCertificate() {
return found_credentials.count(kind) == 1; return readFile(certpath.c_str());
} }
TJAlienCredentialsObject TJAlienCredentials::get(CredentialsKind kind) { void TJAlienCredentialsObject::readPassword() {
if(this->has(kind)) { if (this->kind == cFULL_GRID_CERT &&
return found_credentials[kind]; this->getKey().find("ENCRYPTED") != std::string::npos) {
printf("[Grid certificate password: ]");
struct termios termold, termnew;
tcgetattr(fileno(stdin), &termold);
termnew = termold;
termnew.c_lflag &= ~ECHO;
termnew.c_lflag |= ECHONL;
tcsetattr(fileno(stdin), TCSANOW, &termnew);
char password[64];
if (fgets(password, sizeof(password), stdin) != nullptr) {
tcsetattr(0, TCSANOW, &termold);
password[strlen(password) - 1] = 0;
this->password = std::string(password);
} else { } else {
return TJAlienCredentialsObject(); ERROR("Error while reading from stdin");
this->password = "";
} }
} else
this->password = "";
} }
void TJAlienCredentials::removeCredentials(CredentialsKind kind) { const std::string TJAlienCredentialsObject::getPassword() {
if (this->has(kind)) { if (this->password.empty())
if(kind == cJOB_TOKEN) readPassword();
get(kind).wipe();
found_credentials.erase(kind); return this->password;
}