1
#include <openssl/err.h>
2
#include <openssl/pem.h>
3
#include <openssl/x509.h>
11
#include "delegation2H.h"
12
#include "delegation.hpp"
13
#include "../auth/davixx509cred_internal.hpp"
15
using namespace Davix;
17
const std::string Davix::DELEGATION_SCOPE = "Davix::HttpThirdPartyCopy::Delegation";
19
SOAP_NMAC struct Namespace namespaces[] =
21
{"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/", "http://www.w3.org/*/soap-envelope", NULL},
22
{"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/", "http://www.w3.org/*/soap-encoding", NULL},
23
{"xsi", "http://www.w3.org/2001/XMLSchema-instance", "http://www.w3.org/*/XMLSchema-instance", NULL},
24
{"xsd", "http://www.w3.org/2001/XMLSchema", "http://www.w3.org/*/XMLSchema", NULL},
25
{"tns", "http://www.gridsite.org/namespaces/delegation-1", NULL, NULL},
26
{"tns2", "http://www.gridsite.org/namespaces/delegation-2", NULL, NULL},
27
{NULL, NULL, NULL, NULL}
30
// Timestamp from ASN1 representation
31
static int get_timestamp_from_asn1(ASN1_TIME* asn1)
33
char* data = (char*) ASN1_STRING_data(asn1);
34
size_t len = strlen(data);
38
memset(&time_tm, 0, sizeof(struct tm));
41
&& sscanf(data, "%02d%02d%02d%02d%02d%c", &(time_tm.tm_year),
42
&(time_tm.tm_mon), &(time_tm.tm_mday), &(time_tm.tm_hour),
43
&(time_tm.tm_min), &zone) != 7) {
46
&& sscanf(data, "%02d%02d%02d%02d%02d%02d%c", &(time_tm.tm_year),
47
&(time_tm.tm_mon), &(time_tm.tm_mday), &(time_tm.tm_hour),
48
&(time_tm.tm_min), &(time_tm.tm_sec), &zone) != 7) {
52
&& sscanf(data, "20%02d%02d%02d%02d%02d%02d%c", &(time_tm.tm_year),
53
&(time_tm.tm_mon), &(time_tm.tm_mday), &(time_tm.tm_hour),
54
&(time_tm.tm_min), &(time_tm.tm_sec), &zone) != 7) {
61
if (time_tm.tm_year < 90)
62
time_tm.tm_year += 100;
65
return timegm(&time_tm);
68
// Remaining lifetime from the given certificate
69
static int get_cert_remaining_life(const std::string& cert)
71
FILE* f = fopen(cert.c_str(), "r");
75
X509 *x509_cert = PEM_read_X509(f, NULL, NULL, NULL);
76
if (x509_cert == NULL)
79
ASN1_TIME* expiration = X509_get_notAfter(x509_cert);
80
int expiration_timestamp = get_timestamp_from_asn1(expiration);
83
return (expiration_timestamp - time(NULL)) / 60;
86
// Puts into ucred the credentials paths
87
// Puts into capath the CA directory
88
// Returns true if the path should be removed at the end
90
bool DavixDelegation::get_credentials(const Davix::RequestParams& params,
91
std::string& ucred, std::string&passwd, std::string& capath,
92
int* lifetime, DavixError** err)
94
X509Credential credentials = params.getClientCertX509();
95
if (!credentials.hasCert()) {
96
std::pair<authCallbackClientCertX509, void*> x509callback =
97
params.getClientCertCallbackX509();
99
if (!x509callback.first) {
100
DavixError::setupError(err, DELEGATION_SCOPE,
101
StatusCode::CredentialNotFound,
102
"No callback set for getting credentials. Can not delegate");
108
x509callback.first(x509callback.second, sess, &credentials, err);
113
std::string ucert, ukey;
114
if (!X509CredentialExtra::get_x509_info(credentials, &ucert, &ukey, &passwd)) {
115
DavixError::setupError(err, DELEGATION_SCOPE,
116
StatusCode::DelegationError,
117
std::string("Third party copy only supports PEM certificates"));
121
const std::vector<std::string> &capathList = params.listCertificateAuthorityPath();
122
if (capathList.size() > 0)
123
capath = capathList[0];
125
// Delegation lifetime (in minutes!)
126
int cert_remaining_life = get_cert_remaining_life(ucert);
127
int delegation_max_life = 12 * 60; // 12 hours
129
// Delegated proxy lifetime should be shorter than the current lifetime!
130
*lifetime = std::min(cert_remaining_life, delegation_max_life) - 1;
132
// Should at least remain one minute
133
if (*lifetime <= 1) {
134
DavixError::setupError(err, DELEGATION_SCOPE,
135
StatusCode::DelegationError,
136
std::string("The certificate expired or has less than two minutes left!"));
140
// Cert and key need to be in the same file
149
char* aux = strdup("/tmp/.XXXXXX");
152
ofp = fdopen(fd, "w");
154
ifp = fopen(ukey.c_str(), "r");
155
while ((c = fgetc(ifp)) != EOF)
159
ifp = fopen(ukey.c_str(), "r");
160
while ((c = fgetc(ifp)) != EOF)
172
// Guess the delegation version that should be used
173
static int get_delegation_version(const std::string& ucred, const std::string& passwd,
174
const std::string& capath, const std::string& dlg_endpoint,
178
char err_buffer[512];
183
if (soap_ssl_client_context(soap_v, SOAP_SSL_DEFAULT, ucred.c_str(), passwd.c_str(),
184
ucred.c_str(), capath.c_str(), NULL) == 0) {
185
delegation2::tns2__getVersionResponse response;
186
delegation2::soap_call_tns2__getVersion(soap_v, dlg_endpoint.c_str(),
187
"http://www.gridsite.org/namespaces/delegation-2", response);
189
if (soap_v->error == 0) {
190
version = atoi(response.getVersionReturn);
193
// Assume version 1 (does not implement the version method)
198
soap_sprint_fault(soap_v, err_buffer, sizeof(err_buffer));
199
DavixError::setupError(err, DELEGATION_SCOPE,
200
StatusCode::DelegationError,
201
std::string("Could not connect to the delegation endpoint: ") + err_buffer);
210
static void triggerHooks(Context & context, RequestParams & params){
211
RequestPreRunHook preRun = context.getHook<RequestPreRunHook>();
213
HttpRequest tmp_req(context, u, NULL);
215
// force the run of the hook on req + params
216
preRun(params, tmp_req, u);
220
// Perform delegation, abstracting the version that is running on the server
221
std::string DavixDelegation::delegate(Context & context, const std::string &dlg_endpoint,
222
const RequestParams& _p, Davix::DavixError** err)
224
std::string ucreds, capath, passwd;
228
RequestParams params(_p);
229
triggerHooks(context, params);
231
should_unlink = get_credentials(params, ucreds, passwd, capath, &lifetime, err);
233
return std::string();
236
ERR_load_crypto_strings();
237
OpenSSL_add_all_algorithms();
239
// Figure out the version
240
int delegation_version = get_delegation_version(ucreds, passwd, capath, dlg_endpoint, err);
242
return std::string();
244
davix_logger(DAVIX_LOG_VERBOSE, "Delegation version: %d", delegation_version);
246
switch (delegation_version)
249
return delegate_v1(context, dlg_endpoint,
250
params, ucreds, passwd, capath, lifetime, err);
252
return delegate_v2(context, dlg_endpoint,
253
params, ucreds, passwd, capath, lifetime, err);
255
std::ostringstream err_msg;
256
err_msg << "Unknown delegation version: " << delegation_version;
257
DavixError::setupError(err, DELEGATION_SCOPE,
258
StatusCode::DelegationError,
263
return std::string();