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
#ifndef ROOT_TJAlienCredentials
#define ROOT_TJAlienCredentials
#include <string>
#include <cstring>
#include <iostream>
#include <map>
#include <string>
#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::string;
enum CredentialsKind { cJBOX_TOKEN = 0,
enum CredentialsKind {
cNOT_FOUND = -1,
cJBOX_TOKEN = 0,
cFULL_GRID_CERT,
cJOB_TOKEN,
cOTHER_TOKEN,
};
class TJAlienCredentialsObject {
public:
public:
string certpath;
string keypath;
string password;
......@@ -25,11 +38,10 @@ class TJAlienCredentialsObject {
bool autoremove;
TJAlienCredentialsObject() {}
TJAlienCredentialsObject(string certpath,
string keypath,
TJAlienCredentialsObject(string certpath, string keypath,
CredentialsKind kind = cOTHER_TOKEN,
bool autoremove = false)
{
bool autoremove = false) {
this->certpath = certpath;
this->keypath = keypath;
this->kind = kind;
......@@ -37,8 +49,10 @@ class TJAlienCredentialsObject {
};
void wipe() {
if(autoremove) {
if(gDebug) printf("removing safe files: %s %s\n", certpath.c_str(), keypath.c_str());
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());
}
......@@ -51,7 +65,7 @@ class TJAlienCredentialsObject {
void readPassword();
};
class TJAlienCredentials : public TObject {
class TJAlienCredentials {
public:
TJAlienCredentials();
~TJAlienCredentials();
......@@ -60,10 +74,15 @@ public:
static string getHomeDir();
void loadCredentials();
bool has(CredentialsKind kind);
TJAlienCredentialsObject get(CredentialsKind kind);
bool has(CredentialsKind kind) const;
TJAlienCredentialsObject get(CredentialsKind kind) const;
TJAlienCredentialsObject get();
void removeCredentials(CredentialsKind kind);
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_CERT;
......@@ -71,6 +90,7 @@ public:
static const char *TMP_JOBTOKEN_CERT_FNAME_PREFIX;
private:
CredentialsKind preferedCredentials;
void loadTokenCertificate();
void loadFullGridCertificate();
void loadJobTokenCertificate();
......@@ -79,13 +99,12 @@ private:
string getTokencertPath();
string getTokenkeyPath();
string getSafeFilename(const string& prefix);
void writeSafeFile(const string& filepath, const string& content);
string getSafeFilename(const string &prefix);
void writeSafeFile(const string &filepath, const string &content);
string tmpdir;
string homedir;
string msg;
map<CredentialsKind, TJAlienCredentialsObject> found_credentials;
ClassDef(TJAlienCredentials, 0)
};
#endif
#include "TJAlienCredentials.h"
#include <sstream>
#include <cerrno>
#include <cstdlib>
#include <unistd.h>
#include <fcntl.h>
#include <fstream>
#include <cstdlib>
#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::ofstream;
using std::stringstream;
using std::endl;
using std::getenv;
const char* TJAlienCredentials::ENV_JOBTOKEN_KEY = "JALIEN_TOKEN_KEY";
const char* TJAlienCredentials::ENV_JOBTOKEN_CERT = "JALIEN_TOKEN_CERT";
const char *TJAlienCredentials::ENV_JOBTOKEN_KEY = "JALIEN_TOKEN_KEY";
const char *TJAlienCredentials::ENV_JOBTOKEN_CERT = "JALIEN_TOKEN_CERT";
const char* TJAlienCredentials::TMP_JOBTOKEN_KEY_FNAME_PREFIX = "tmpjobtokenkey_";
const char* TJAlienCredentials::TMP_JOBTOKEN_CERT_FNAME_PREFIX = "tmpjobtokencert_";
const char *TJAlienCredentials::TMP_JOBTOKEN_KEY_FNAME_PREFIX =
"tmpjobtokenkey_";
const char *TJAlienCredentials::TMP_JOBTOKEN_CERT_FNAME_PREFIX =
"tmpjobtokencert_";
bool fileExists(const string &filename)
{
bool fileExists(const string &filename) {
bool fileExists = false;
FILE *f = fopen(filename.c_str(), "r");
if (f != NULL ) {
if (f != NULL) {
fclose(f);
fileExists = true;
} else {
......@@ -34,24 +37,28 @@ bool fileExists(const string &filename)
return fileExists;
}
bool TJAlienCredentialsObject::exists() {
return fileExists(certpath) && fileExists(keypath);
}
void TJAlienCredentials::writeSafeFile(const string& filename, const string& content) {
if(gDebug) printf("writing safe file %s\n", filename.c_str());
void TJAlienCredentials::writeSafeFile(const string &filename,
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);
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);
}
string TJAlienCredentials::getSafeFilename(const string& prefix) {
string TJAlienCredentials::getSafeFilename(const string &prefix) {
string filename = TJAlienCredentials::getTmpDir() + "/" + prefix;
const char *JOB_ID = getenv("ALIEN_PROC_ID");
if(JOB_ID != NULL) {
if (JOB_ID != NULL) {
filename += JOB_ID;
} else {
pid_t pid = getpid();
......@@ -59,15 +66,14 @@ string TJAlienCredentials::getSafeFilename(const string& prefix) {
do {
filename += std::to_string(pid) + "_" + std::to_string(rnd);
} while(fileExists(filename));
} while (fileExists(filename));
}
return filename;
}
string TJAlienCredentials::getTmpDir() {
string tmpdir;
std::string TJAlienCredentials::getTmpDir() {
std::string tmpdir;
if (getenv("TMPDIR") != NULL)
tmpdir = getenv("TMPDIR");
......@@ -81,8 +87,8 @@ string TJAlienCredentials::getTmpDir() {
return tmpdir;
}
string TJAlienCredentials::getHomeDir() {
string homedir;
std::string TJAlienCredentials::getHomeDir() {
std::string homedir;
if (getenv("HOME") != NULL)
homedir = getenv("HOME");
......@@ -92,37 +98,33 @@ string TJAlienCredentials::getHomeDir() {
return homedir;
}
string TJAlienCredentials::getTokencertPath()
{
std::string TJAlienCredentials::getTokencertPath() {
std::stringstream tokencert_s;
tokencert_s << tmpdir << "/tokencert_" << getuid() << ".pem";
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;
}
string TJAlienCredentials::getTokenkeyPath()
{
std::string TJAlienCredentials::getTokenkeyPath() {
std::stringstream tokenkey_s;
tokenkey_s << tmpdir << "/tokenkey_" << getuid() << ".pem";
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;
}
string TJAlienCredentials::getUsercertPath()
{
std::string TJAlienCredentials::getUsercertPath() {
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;
}
string TJAlienCredentials::getUserkeyPath()
{
string TJAlienCredentials::getUserkeyPath() {
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;
}
......@@ -140,15 +142,17 @@ void TJAlienCredentials::loadCredentials() {
}
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;
}
}
void TJAlienCredentials::loadFullGridCertificate() {
TJAlienCredentialsObject grid_certificate(getUsercertPath(), getUserkeyPath(), cFULL_GRID_CERT);
TJAlienCredentialsObject grid_certificate(getUsercertPath(), getUserkeyPath(),
cFULL_GRID_CERT);
if (grid_certificate.exists()) {
found_credentials[cFULL_GRID_CERT] = grid_certificate;
......@@ -160,73 +164,89 @@ void TJAlienCredentials::loadJobTokenCertificate() {
const char *env_key = getenv(ENV_JOBTOKEN_KEY);
// if it doesn't have both environment variables
if(!env_cert || !env_key) {
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);
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);
const string &tmpcertpath = getSafeFilename(TMP_JOBTOKEN_CERT_FNAME_PREFIX);
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);
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;
}
TJAlienCredentialsObject TJAlienCredentials::get(CredentialsKind kind) {
if(this->has(kind)) {
return found_credentials[kind];
TJAlienCredentialsObject TJAlienCredentials::get(CredentialsKind kind) const {
if (this->has(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 {
ERROR("Failed to get any credentials");
return TJAlienCredentialsObject();
}
}
void TJAlienCredentials::removeCredentials(CredentialsKind kind) {
if (this->has(kind)) {
if(kind == cJOB_TOKEN)
if (kind == cJOB_TOKEN)
get(kind).wipe();
found_credentials.erase(kind);
}
}
short TJAlienCredentials::count() {
return found_credentials.size();
}
short TJAlienCredentials::count() { return found_credentials.size(); }
string readFile(const char* filename) {
string line;
stringstream contents;
ifstream f(filename);
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 << endl;
if (f.is_open()) {
while (getline(f, line)) {
contents << line << std::endl;
}
}
return contents.str();
}
const string TJAlienCredentialsObject::getKey() {
const std::string TJAlienCredentialsObject::getKey() {
return readFile(keypath.c_str());
}
const string TJAlienCredentialsObject::getCertificate() {
const std::string TJAlienCredentialsObject::getCertificate() {
return readFile(certpath.c_str());
}
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: ]");
struct termios termold, termnew;
tcgetattr(fileno(stdin), &termold);
......@@ -236,17 +256,20 @@ void TJAlienCredentialsObject::readPassword() {
tcsetattr(fileno(stdin), TCSANOW, &termnew);
char password[64];
if (!fgets(password, sizeof(password), stdin))
printf("\nFailed to get password input\n");
if (fgets(password, sizeof(password), stdin) != nullptr) {
tcsetattr(0, TCSANOW, &termold);
password[strlen(password) - 1] = 0;
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())
readPassword();
......@@ -256,3 +279,84 @@ const string TJAlienCredentialsObject::getPassword() {
TJAlienCredentials::~TJAlienCredentials() {
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;
}
msg += "Failed to find any credentials\n";
preferedCredentials = cNOT_FOUND;
}
CredentialsKind TJAlienCredentials::getPreferedCredentials() const {
return preferedCredentials;
}
const string& TJAlienCredentials::getMessages() const {
return msg;
}
bool TJAlienCredentials::checkCertValidity(const char *path) {
FILE *fCert = fopen(path, "r");
bool result = false;
X509 *x509 = NULL;
ASN1_TIME *expire = NULL;
using namespace std;
// failed to open certificate file
if(!fCert) {
return false;
}
// if file exists but expired,
char cert[4096];
fread(cert, 1, 4096, fCert);
fclose(fCert);
BIO *b = BIO_new(BIO_s_mem());
BIO_puts(b, cert);
x509 = PEM_read_bio_X509(b, NULL, NULL, NULL);
if(!x509) {
result = false;
} else {
expire = X509_get_notAfter(x509);
}
// Failed to parse certificate expiration time
if(expire != NULL) {
if(!ASN1_TIME_check(expire)) {
result = false;
} else {
int day, sec;
// Compare certificate expiration time with current time
ASN1_TIME_diff(&day, &sec, NULL, expire);
result = day > 0 || sec > 0;
}
}
if(b) BIO_free(b);
if(x509) X509_free(x509);
return result;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment