~ubuntu-branches/ubuntu/wily/davix/wily

« back to all changes in this revision

Viewing changes to src/copy/delegation/delegation.cpp

  • Committer: Package Import Robot
  • Author(s): Mattias Ellert
  • Date: 2014-10-23 16:02:47 UTC
  • mfrom: (5.1.1 sid)
  • Revision ID: package-import@ubuntu.com-20141023160247-izv1acuq0bcfv3qn
Tags: 0.3.6-1
Update to version 0.3.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <openssl/err.h>
 
2
#include <openssl/pem.h>
 
3
#include <openssl/x509.h>
 
4
 
 
5
#include <cstdlib>
 
6
#include <cstring>
 
7
#include <stdsoap2.h>
 
8
 
 
9
#include <sstream>
 
10
 
 
11
#include "delegation2H.h"
 
12
#include "delegation.hpp"
 
13
#include "../auth/davixx509cred_internal.hpp"
 
14
 
 
15
using namespace Davix;
 
16
 
 
17
const std::string Davix::DELEGATION_SCOPE = "Davix::HttpThirdPartyCopy::Delegation";
 
18
 
 
19
SOAP_NMAC struct Namespace namespaces[] =
 
20
{
 
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}
 
28
};
 
29
 
 
30
// Timestamp from ASN1 representation
 
31
static int get_timestamp_from_asn1(ASN1_TIME* asn1)
 
32
{
 
33
    char* data = (char*) ASN1_STRING_data(asn1);
 
34
    size_t len = strlen(data);
 
35
    struct tm time_tm;
 
36
    char zone = 0;
 
37
 
 
38
    memset(&time_tm, 0, sizeof(struct tm));
 
39
 
 
40
    if (len == 11
 
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) {
 
44
    }
 
45
    else if (len == 13
 
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) {
 
49
        return 0;
 
50
    }
 
51
    else if (len == 15
 
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) {
 
55
        return 0;
 
56
    }
 
57
 
 
58
    if (zone != 'Z')
 
59
        return 0;
 
60
 
 
61
    if (time_tm.tm_year < 90)
 
62
        time_tm.tm_year += 100;
 
63
    --(time_tm.tm_mon);
 
64
 
 
65
    return timegm(&time_tm);
 
66
}
 
67
 
 
68
// Remaining lifetime from the given certificate
 
69
static int get_cert_remaining_life(const std::string& cert)
 
70
{
 
71
    FILE* f = fopen(cert.c_str(), "r");
 
72
    if (f == NULL)
 
73
        return 0;
 
74
 
 
75
    X509 *x509_cert = PEM_read_X509(f, NULL, NULL, NULL);
 
76
    if (x509_cert == NULL)
 
77
        return 0;
 
78
 
 
79
    ASN1_TIME* expiration = X509_get_notAfter(x509_cert);
 
80
    int expiration_timestamp = get_timestamp_from_asn1(expiration);
 
81
    X509_free(x509_cert);
 
82
 
 
83
    return (expiration_timestamp - time(NULL)) / 60;
 
84
}
 
85
 
 
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
 
89
// Sets err on error
 
90
bool DavixDelegation::get_credentials(const Davix::RequestParams& params,
 
91
                std::string& ucred, std::string&passwd, std::string& capath,
 
92
                int* lifetime, DavixError** err)
 
93
{
 
94
        X509Credential credentials = params.getClientCertX509();
 
95
        if (!credentials.hasCert()) {
 
96
                std::pair<authCallbackClientCertX509, void*> x509callback =
 
97
                                params.getClientCertCallbackX509();
 
98
 
 
99
                if (!x509callback.first) {
 
100
                        DavixError::setupError(err, DELEGATION_SCOPE,
 
101
                                        StatusCode::CredentialNotFound,
 
102
                                        "No callback set for getting credentials. Can not delegate");
 
103
                        return false;
 
104
                }
 
105
 
 
106
                SessionInfo sess;
 
107
 
 
108
                x509callback.first(x509callback.second, sess, &credentials, err);
 
109
                if (err && *err)
 
110
                        return false;
 
111
        }
 
112
 
 
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"));
 
118
                return false;
 
119
        }
 
120
 
 
121
        const std::vector<std::string> &capathList = params.listCertificateAuthorityPath();
 
122
        if (capathList.size() > 0)
 
123
                capath = capathList[0];
 
124
 
 
125
        // Delegation lifetime (in minutes!)
 
126
        int cert_remaining_life = get_cert_remaining_life(ucert);
 
127
        int delegation_max_life = 12 * 60; // 12 hours
 
128
 
 
129
        // Delegated proxy lifetime should be shorter than the current lifetime!
 
130
        *lifetime = std::min(cert_remaining_life, delegation_max_life) - 1;
 
131
 
 
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!"));
 
137
                return false;
 
138
        }
 
139
 
 
140
        // Cert and key need to be in the same file
 
141
        if (ucert == ukey) {
 
142
                ucred.assign(ucert);
 
143
                return false;
 
144
        } else {
 
145
                FILE *ifp, *ofp;
 
146
                int fd;
 
147
                int c;
 
148
 
 
149
                char* aux = strdup("/tmp/.XXXXXX");
 
150
 
 
151
                fd = mkstemp(aux);
 
152
                ofp = fdopen(fd, "w");
 
153
 
 
154
                ifp = fopen(ukey.c_str(), "r");
 
155
                while ((c = fgetc(ifp)) != EOF)
 
156
                        fputc(c, ofp);
 
157
                fclose(ifp);
 
158
 
 
159
                ifp = fopen(ukey.c_str(), "r");
 
160
                while ((c = fgetc(ifp)) != EOF)
 
161
                        fputc(c, ofp);
 
162
                fclose(ifp);
 
163
 
 
164
                fclose(ofp);
 
165
 
 
166
                ucred.assign(aux);
 
167
                free(aux);
 
168
                return true;
 
169
        }
 
170
}
 
171
 
 
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,
 
175
                DavixError** err)
 
176
{
 
177
    struct soap *soap_v;
 
178
    char err_buffer[512];
 
179
    int version = -1;
 
180
 
 
181
    soap_v = soap_new();
 
182
 
 
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);
 
188
 
 
189
        if (soap_v->error == 0) {
 
190
            version = atoi(response.getVersionReturn);
 
191
        }
 
192
        else {
 
193
            // Assume version 1 (does not implement the version method)
 
194
            version = 1;
 
195
        }
 
196
    }
 
197
    else {
 
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);
 
202
    }
 
203
 
 
204
    soap_free(soap_v);
 
205
    soap_done(soap_v);
 
206
 
 
207
        return version;
 
208
}
 
209
 
 
210
static void triggerHooks(Context & context, RequestParams & params){
 
211
    RequestPreRunHook preRun = context.getHook<RequestPreRunHook>();
 
212
    Uri u;
 
213
    HttpRequest tmp_req(context, u, NULL);
 
214
    if(preRun){
 
215
        // force the run of the hook on req + params
 
216
        preRun(params, tmp_req, u);
 
217
    }
 
218
}
 
219
 
 
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)
 
223
{
 
224
        std::string ucreds, capath, passwd;
 
225
        int lifetime;
 
226
        bool should_unlink;
 
227
 
 
228
        RequestParams params(_p);
 
229
        triggerHooks(context, params);
 
230
 
 
231
        should_unlink = get_credentials(params, ucreds, passwd, capath, &lifetime, err);
 
232
        if (*err)
 
233
                return std::string();
 
234
 
 
235
        // Initialize SSL
 
236
        ERR_load_crypto_strings();
 
237
        OpenSSL_add_all_algorithms();
 
238
 
 
239
        // Figure out the version
 
240
        int delegation_version = get_delegation_version(ucreds, passwd, capath, dlg_endpoint, err);
 
241
        if (*err)
 
242
                return std::string();
 
243
 
 
244
    davix_logger(DAVIX_LOG_VERBOSE, "Delegation version: %d", delegation_version);
 
245
 
 
246
    switch (delegation_version)
 
247
    {
 
248
        case 1:
 
249
            return delegate_v1(context, dlg_endpoint,
 
250
                    params, ucreds, passwd, capath, lifetime, err);
 
251
        case 2:
 
252
            return delegate_v2(context, dlg_endpoint,
 
253
                                params, ucreds, passwd, capath, lifetime, err);
 
254
        default: {
 
255
            std::ostringstream err_msg;
 
256
            err_msg << "Unknown delegation version: " << delegation_version;
 
257
            DavixError::setupError(err, DELEGATION_SCOPE,
 
258
                    StatusCode::DelegationError,
 
259
                    err_msg.str());
 
260
        }
 
261
    }
 
262
 
 
263
        return std::string();
 
264
}