View | Details | Raw Unified | Return to bug 48780
Collapse All | Expand All

(-)modules/aaa/mod_authnz_ldap.c (-7 / +38 lines)
Lines 398-405 Link Here
398
    authn_ldap_build_filter(filtbuf, r, user, NULL, sec);
398
    authn_ldap_build_filter(filtbuf, r, user, NULL, sec);
399
399
400
    /* do the user search */
400
    /* do the user search */
401
    result = util_ldap_cache_checkuserid(r, ldc, sec->url, sec->basedn, sec->scope,
401
    if (r->ap_auth_type && !strcasecmp(r->ap_auth_type, "Basic")) {
402
                                         sec->attributes, filtbuf, password, &dn, &vals);
402
        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0 ,r,
403
                      "[%" APR_PID_T_FMT "] auth_ldap authenticate: using filter %s", getpid(), filtbuf);
404
        result = util_ldap_cache_checkuserid(r, ldc, sec->url, sec->basedn, sec->scope,
405
                                             sec->attributes, filtbuf, password, &dn, &vals);
406
    } else if (r->ap_auth_type && !strcasecmp(r->ap_auth_type, "Certificate")) {
407
        result = (sec->user_is_dn) ? util_ldap_cache_getuserdn(r, ldc, sec->url, user, LDAP_SCOPE_BASE,
408
                                                               sec->attributes, sec->filter, &dn, &vals) :
409
                                     util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn, sec->scope,
410
                                                               sec->attributes, filtbuf, &dn, &vals);
411
    }
403
    util_ldap_connection_close(ldc);
412
    util_ldap_connection_close(ldc);
404
413
405
    /* sanity check - if server is down, retry it up to 5 times */
414
    /* sanity check - if server is down, retry it up to 5 times */
Lines 487-492 Link Here
487
    return AUTH_GRANTED;
496
    return AUTH_GRANTED;
488
}
497
}
489
498
499
static authn_status authn_ldap_check_certificate(request_rec *r,const char *username)
500
{
501
    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "[%" APR_PID_T_FMT "] auth_ldap check_certificate: user %s",
502
                  getpid(), username);
503
    /* short-circuit this error early so that we don't get a misleading error later */
504
    if (username == NULL || username == "") {
505
        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
506
                      "[%" APR_PID_T_FMT "] auth_ldap authenticate: no certificate specified", getpid());
507
        return AUTH_GENERAL_ERROR;
508
    }
509
510
    /* To borrow check_password we have to supply a placeholder password */
511
    authn_status result = authn_ldap_check_password(r, username, "password");
512
    return result;
513
}
490
/*
514
/*
491
 * Authorisation Phase
515
 * Authorisation Phase
492
 * -------------------
516
 * -------------------
Lines 613-620 Link Here
613
        authn_ldap_build_filter(filtbuf, r, r->user, NULL, sec);
637
        authn_ldap_build_filter(filtbuf, r, r->user, NULL, sec);
614
638
615
        /* Search for the user DN */
639
        /* Search for the user DN */
616
        result = util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn,
640
        result = (sec->user_is_dn && r->ap_auth_type && !strcasecmp(r->ap_auth_type, "Certificate")) ?
617
             sec->scope, sec->attributes, filtbuf, &dn, &vals);
641
                  util_ldap_cache_getuserdn(r, ldc, sec->url, r->user, LDAP_SCOPE_BASE,
642
                                            sec->attributes, sec->filter, &dn, &vals) :
643
                  util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn, sec->scope,
644
                                            sec->attributes, filtbuf, &dn, &vals);
618
645
619
        /* Search failed, log error and return failure */
646
        /* Search failed, log error and return failure */
620
        if(result != LDAP_SUCCESS) {
647
        if(result != LDAP_SUCCESS) {
Lines 818-825 Link Here
818
                authn_ldap_build_filter(filtbuf, r, req->user, t, sec);
845
                authn_ldap_build_filter(filtbuf, r, req->user, t, sec);
819
846
820
                /* Search for the user DN */
847
                /* Search for the user DN */
821
                result = util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn,
848
                result = (sec->user_is_dn && r->ap_auth_type && !strcasecmp(r->ap_auth_type, "Certificate")) ?
822
                     sec->scope, sec->attributes, filtbuf, &dn, &vals);
849
                  util_ldap_cache_getuserdn(r, ldc, sec->url, req->dn, LDAP_SCOPE_BASE,
850
                                            sec->attributes, t, &dn, &vals) :
851
                  util_ldap_cache_getuserdn(r, ldc, sec->url, sec->basedn, sec->scope,
852
                                            sec->attributes, filtbuf, &dn, &vals);
823
853
824
                /* Make sure that the filtered search returned the correct user dn */
854
                /* Make sure that the filtered search returned the correct user dn */
825
                if (result == LDAP_SUCCESS) {
855
                if (result == LDAP_SUCCESS) {
Lines 1234-1244 Link Here
1234
static void register_hooks(apr_pool_t *p)
1264
static void register_hooks(apr_pool_t *p)
1235
{
1265
{
1236
    static const char * const aszPost[]={ "mod_authz_user.c", NULL };
1266
    static const char * const aszPost[]={ "mod_authz_user.c", NULL };
1267
    static const char * const aszPre[]={ "mod_ssl.c", NULL };
1237
1268
1238
    ap_register_provider(p, AUTHN_PROVIDER_GROUP, "ldap", "0",
1269
    ap_register_provider(p, AUTHN_PROVIDER_GROUP, "ldap", "0",
1239
                         &authn_ldap_provider);
1270
                         &authn_ldap_provider);
1240
    ap_hook_post_config(authnz_ldap_post_config,NULL,NULL,APR_HOOK_MIDDLE);
1271
    ap_hook_post_config(authnz_ldap_post_config,NULL,NULL,APR_HOOK_MIDDLE);
1241
    ap_hook_auth_checker(authz_ldap_check_user_access, NULL, aszPost, APR_HOOK_MIDDLE);
1272
    ap_hook_auth_checker(authz_ldap_check_user_access, aszPre, aszPost, APR_HOOK_MIDDLE);
1242
1273
1243
    ap_hook_optional_fn_retrieve(ImportULDAPOptFn,NULL,NULL,APR_HOOK_MIDDLE);
1274
    ap_hook_optional_fn_retrieve(ImportULDAPOptFn,NULL,NULL,APR_HOOK_MIDDLE);
1244
}
1275
}
(-)modules/aaa/config.m4 (+1 lines)
Lines 54-58 Link Here
54
    enable_auth_digest="no"
54
    enable_auth_digest="no"
55
  fi
55
  fi
56
])
56
])
57
APACHE_MODULE(auth_cert, X.509 certificate authentication, , , most)
57
58
58
APACHE_MODPATH_FINISH
59
APACHE_MODPATH_FINISH
(-)modules/aaa/mod_auth.h (+5 lines)
Lines 62-67 Link Here
62
     */
62
     */
63
    authn_status (*get_realm_hash)(request_rec *r, const char *user,
63
    authn_status (*get_realm_hash)(request_rec *r, const char *user,
64
                                   const char *realm, char **rethash);
64
                                   const char *realm, char **rethash);
65
66
    /* Given an X.509 certificate, expected to return AUTH_GRANTED
67
     * if the provider authenticates the certificate */
68
    authn_status (*check_certificate)(request_rec *r, const char *certificate);
69
65
} authn_provider;
70
} authn_provider;
66
71
67
/* A linked-list of authn providers. */
72
/* A linked-list of authn providers. */
(-)modules/aaa/mod_auth_cert.c (+292 lines)
Line 0 Link Here
1
/* Licensed to the Apache Software Foundation (ASF) under one or more
2
 * contributor license agreements.  See the NOTICE file distributed with
3
 * this work for additional information regarding copyright ownership.
4
 * The ASF licenses this file to You under the Apache License, Version 2.0
5
 * (the "License"); you may not use this file except in compliance with
6
 * the License.  You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
#include "apr_strings.h"
18
#define APR_WANT_STRFUNC        /* for strcasecmp */
19
#include "apr_want.h"
20
21
#include "ap_config.h"
22
#include "httpd.h"
23
#include "http_config.h"
24
#include "http_core.h"
25
#include "http_log.h"
26
#include "http_protocol.h"
27
#include "http_request.h"
28
#include "ap_provider.h"
29
30
#include "mod_auth.h"
31
#include "mod_ssl.h"
32
33
typedef struct {
34
    authn_provider_list *providers;
35
    char *dir;
36
    int authoritative;
37
} auth_cert_config_rec;
38
39
static void *create_auth_cert_dir_config(apr_pool_t *p, char *d)
40
{
41
    auth_cert_config_rec *conf = apr_pcalloc(p, sizeof(*conf));
42
43
    conf->dir = d;
44
    /* Any failures are fatal. */
45
    conf->authoritative = 1;
46
47
    return conf;
48
}
49
50
static const char *add_authn_provider(cmd_parms *cmd, void *config,
51
                                      const char *arg)
52
{
53
    auth_cert_config_rec *conf = (auth_cert_config_rec*)config;
54
    authn_provider_list *newp;
55
56
    newp = apr_pcalloc(cmd->pool, sizeof(authn_provider_list));
57
    newp->provider_name = apr_pstrdup(cmd->pool, arg);
58
59
    /* lookup and cache the actual provider now */
60
    newp->provider = ap_lookup_provider(AUTHN_PROVIDER_GROUP,
61
                                        newp->provider_name, "0");
62
63
    if (newp->provider == NULL) {
64
        /* by the time they use it, the provider should be loaded and
65
           registered with us. */
66
        return apr_psprintf(cmd->pool,
67
                            "Unknown Authn provider: %s",
68
                            newp->provider_name);
69
    }
70
71
    if (!newp->provider->check_certificate) {
72
        /* if it doesn't provide the appropriate function, reject it */
73
        return apr_psprintf(cmd->pool,
74
                            "The '%s' Authn provider doesn't support "
75
                            "Certificate Authentication", newp->provider_name);
76
    }
77
78
    /* Add it to the list now. */
79
    if (!conf->providers) {
80
        conf->providers = newp;
81
    }
82
    else {
83
        authn_provider_list *last = conf->providers;
84
85
        while (last->next) {
86
            last = last->next;
87
        }
88
        last->next = newp;
89
    }
90
91
    return NULL;
92
}
93
94
static const command_rec auth_cert_cmds[] =
95
{
96
    AP_INIT_ITERATE("AuthCertificateProvider", add_authn_provider, NULL, OR_AUTHCFG,
97
                    "specify the auth providers for a directory or location"),
98
    AP_INIT_FLAG("AuthCertificateAuthoritative", ap_set_flag_slot,
99
                 (void *)APR_OFFSETOF(auth_cert_config_rec, authoritative),
100
                 OR_AUTHCFG,
101
                 "Set to 'Off' to allow access control to be passed along to "
102
                 "lower modules if the UserID is not known to this module"),
103
    {NULL}
104
};
105
106
static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *ssl_svl_func = NULL;
107
108
module AP_MODULE_DECLARE_DATA auth_cert_module;
109
110
/* These functions return 0 if client is OK, and proper error status
111
 * if not... either HTTP_UNAUTHORIZED, if we made a check, and it failed, or
112
 * HTTP_INTERNAL_SERVER_ERROR, if things are so totally confused that we
113
 * couldn't figure out how to tell if the client is authorized or not.
114
 *
115
 * If they return DECLINED, and all other modules also decline, that's
116
 * treated by the server core as a configuration error, logged and
117
 * reported as such.
118
 */
119
120
/* Determine user ID, and check if it really is that user, for HTTP
121
 */
122
static int authenticate_cert_user(request_rec *r)
123
{
124
    auth_cert_config_rec *conf = ap_get_module_config(r->per_dir_config,
125
                                                       &auth_cert_module);
126
    const char *username, *current_auth;
127
    const char *verstatus;
128
    authn_status auth_result;
129
    authn_provider_list *current_provider;
130
131
    /* Are we configured to be Certificate auth? */
132
    current_auth = ap_auth_type(r);
133
    if (!current_auth || strcasecmp(current_auth, "Certificate")) {
134
        return DECLINED;
135
    }
136
137
    /* We need an authentication realm. */
138
    if (!ap_auth_name(r)) {
139
        ap_log_rerror(APLOG_MARK, APLOG_ERR,
140
                      0, r, "need AuthName: %s", r->uri);
141
        return HTTP_INTERNAL_SERVER_ERROR;
142
    }
143
144
    r->ap_auth_type = (char*)current_auth;
145
146
    verstatus = ssl_svl_func(r->pool,r->server,r->connection,r,"SSL_CLIENT_VERIFY");
147
    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
148
                              "Client certificate status is: %s", verstatus);
149
150
    switch (verstatus[0]) {
151
        case 'G': // ENEROUS
152
            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
153
                              "Client certificate is not from a trusted CA");
154
            break;
155
        case 'S': // UCCESS
156
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
157
                              "Client certificate accepted.");
158
            break;
159
        case 'N': // ONE
160
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
161
                          "Client certificate not provided");
162
            return HTTP_INTERNAL_SERVER_ERROR;
163
        case 'F': // AILED
164
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Authentication "
165
                          "aborted; certificate verification %s",
166
                          verstatus);
167
            return HTTP_UNAUTHORIZED;
168
        default: // Only possible if another return is defined by mod_ssl.c
169
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Unexpected return "
170
                          "code from certificate verification %s",
171
                          verstatus);
172
            return HTTP_INTERNAL_SERVER_ERROR;
173
    }
174
175
    /*
176
     * At this point we know we have a certificate.
177
     */
178
179
    username = ssl_svl_func(r->pool,r->server,r->connection,r,"SSL_CLIENT_S_DN");
180
    r->user = (char *) username;
181
    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
182
              "user %s: attempting certificate authentication for \"%s\": ",
183
              username, r->uri);
184
185
    current_provider = conf->providers;
186
    do {
187
        const authn_provider *provider;
188
189
        /* For now, if a provider isn't set, we'll be nice and use the file
190
         * provider.
191
         */
192
        if (!current_provider) {
193
            provider = ap_lookup_provider(AUTHN_PROVIDER_GROUP,
194
                                          AUTHN_DEFAULT_PROVIDER, "0");
195
196
            if (!provider || !provider->check_certificate) {
197
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
198
                              "No Authn provider configured");
199
                auth_result = AUTH_GENERAL_ERROR;
200
                break;
201
            }
202
            apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, AUTHN_DEFAULT_PROVIDER);
203
        }
204
        else {
205
            provider = current_provider->provider;
206
            apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, current_provider->provider_name);
207
        }
208
209
        auth_result = provider->check_certificate(r, r->user);
210
211
        apr_table_unset(r->notes, AUTHN_PROVIDER_NAME_NOTE);
212
213
        /* Something occured. Stop checking. */
214
        if (auth_result != AUTH_USER_NOT_FOUND) {
215
            break;
216
        }
217
218
        /* If we're not really configured for providers, stop now. */
219
        if (!conf->providers) {
220
            break;
221
        }
222
223
        current_provider = current_provider->next;
224
    } while (current_provider);
225
226
    if (auth_result != AUTH_GRANTED) {
227
        int return_code;
228
229
        /* If we're not authoritative, then any error is ignored. */
230
        if (!(conf->authoritative) && auth_result != AUTH_DENIED) {
231
            return DECLINED;
232
        }
233
234
        switch (auth_result) {
235
        case AUTH_DENIED:
236
            /* Currently we are not passing a user name with the certificate.
237
             * This may change eventually, in which case we could see a denial
238
             * where the requested user is found, but there is no corresponding
239
             * certificate in its attributes.  Until then AUTH_DENIED 
240
             * and AUTH_USER_NOT_FOUND are really identical results.
241
             */
242
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
243
                      "user %s: authentication failure for \"%s\": "
244
                      "Certificate Mismatch",
245
                      r->user, r->uri);
246
            return_code = HTTP_UNAUTHORIZED;
247
            break;
248
        case AUTH_USER_NOT_FOUND:
249
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
250
                      "user %s not found: %s", r->user, r->uri);
251
            return_code = HTTP_UNAUTHORIZED;
252
            break;
253
        case AUTH_GENERAL_ERROR:
254
        default:
255
            /* We'll assume that the module has already said what its error
256
             * was in the logs.
257
             */
258
            return_code = HTTP_INTERNAL_SERVER_ERROR;
259
            break;
260
        }
261
262
        return return_code;
263
    }
264
265
    return OK;
266
}
267
268
static int auth_cert_post_config(apr_pool_t *pconf, apr_pool_t *plog,
269
                                apr_pool_t *ptemp, server_rec *s)
270
{
271
    ssl_svl_func = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup);
272
    return OK;
273
}
274
275
276
static void register_hooks(apr_pool_t *p)
277
{
278
    static const char * const aszPre[]={ "mod_ssl.c",NULL };
279
    ap_hook_check_user_id(authenticate_cert_user, aszPre, NULL, APR_HOOK_MIDDLE);
280
    ap_hook_post_config(auth_cert_post_config, NULL, NULL, APR_HOOK_MIDDLE);
281
}
282
283
module AP_MODULE_DECLARE_DATA auth_cert_module =
284
{
285
    STANDARD20_MODULE_STUFF,
286
    create_auth_cert_dir_config,  /* dir config creater */
287
    NULL,                          /* dir merger --- default is to override */
288
    NULL,                          /* server config */
289
    NULL,                          /* merge server config */
290
    auth_cert_cmds,               /* command apr_table_t */
291
    register_hooks                 /* register hooks */
292
};
(-)modules/ssl/ssl_engine_vars.c (-4 / +14 lines)
Lines 367-376 Link Here
367
    }
367
    }
368
    else if (strcEQ(var, "S_DN")) {
368
    else if (strcEQ(var, "S_DN")) {
369
        xsname = X509_get_subject_name(xs);
369
        xsname = X509_get_subject_name(xs);
370
        cp = X509_NAME_oneline(xsname, NULL, 0);
370
        BIO *bio;
371
        result = apr_pstrdup(p, cp);
371
        int n;
372
        modssl_free(cp);
372
373
        resdup = FALSE;
373
        if ((bio = BIO_new(BIO_s_mem())) == NULL) {
374
            result = NULL;
375
        } else {
376
            X509_NAME_print_ex(bio, xsname, 0, XN_FLAG_RFC2253);
377
            n = BIO_pending(bio);
378
            result = apr_pcalloc(p, n+1);
379
            n = BIO_read(bio, result, n);
380
            result[n] = NUL;
381
            BIO_free(bio);
382
            resdup = FALSE;
383
        }
374
    }
384
    }
375
    else if (strlen(var) > 5 && strcEQn(var, "S_DN_", 5)) {
385
    else if (strlen(var) > 5 && strcEQn(var, "S_DN_", 5)) {
376
        xsname = X509_get_subject_name(xs);
386
        xsname = X509_get_subject_name(xs);

Return to bug 48780