source: server/common/oursrc/httpdmods/mod_auth_sslcert.c @ 390

Last change on this file since 390 was 390, checked in by andersk, 17 years ago
httpd module updates, including support for optional authentication.
File size: 5.1 KB
Line 
1/* mod_auth_sslcert
2 * version 1.1, released 2007-09-01 [NOT RELEASED YET]
3 * Anders Kaseorg <andersk@mit.edu>
4 *
5 * This module does authentication based on SSL client certificates:
6 *   AuthType SSLCert
7 *   AuthSSLCertVar SSL_CLIENT_S_DN_Email
8 *   AuthSSLCertStripSuffix "@MIT.EDU"
9 */
10
11#include "apr_strings.h"
12#define APR_WANT_STRFUNC        /* for strcasecmp */
13#include "apr_want.h"
14
15#include "ap_config.h"
16#include "httpd.h"
17#include "http_config.h"
18#include "http_core.h"
19#include "http_log.h"
20#include "http_request.h"
21
22#include "mod_auth.h"
23#include "mod_ssl.h"
24
25static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *ssl_var_lookup;
26
27typedef struct {
28    int authoritative;
29    char *var;
30    char *strip_suffix;
31    int strip_suffix_required;
32} auth_sslcert_config_rec;
33
34static void *create_auth_sslcert_dir_config(apr_pool_t *p, char *dirspec)
35{
36    auth_sslcert_config_rec *conf = apr_pcalloc(p, sizeof(*conf));
37
38    conf->authoritative = 1;
39    conf->var = NULL;
40    conf->strip_suffix = NULL;
41    conf->strip_suffix_required = 1;
42
43    return conf;
44}
45
46static void *merge_auth_sslcert_dir_config(apr_pool_t *p, void *parent_conf, void *newloc_conf)
47{
48    auth_sslcert_config_rec *pconf = parent_conf, *nconf = newloc_conf,
49        *conf = apr_pcalloc(p, sizeof(*conf));
50
51    conf->authoritative = nconf->authoritative;
52    conf->var = (nconf->var != NULL) ? nconf->var : pconf->var;
53    conf->strip_suffix = (nconf->var != NULL || nconf->strip_suffix != NULL) ?
54        nconf->strip_suffix : pconf->strip_suffix;
55
56    return conf;
57}
58
59static const command_rec auth_sslcert_cmds[] =
60{
61    AP_INIT_FLAG("AuthSSLCertAuthoritative", ap_set_flag_slot,
62                 (void *)APR_OFFSETOF(auth_sslcert_config_rec, authoritative),
63                 OR_AUTHCFG,
64                 "Set to 'Off' to allow access control to be passed along to "
65                 "lower modules if the UserID is not known to this module"),
66    AP_INIT_TAKE1("AuthSSLCertVar", ap_set_string_slot,
67                  (void*)APR_OFFSETOF(auth_sslcert_config_rec, var),
68                  OR_AUTHCFG,
69                  "SSL variable to use as the username"),
70    AP_INIT_TAKE1("AuthSSLCertStripSuffix", ap_set_string_slot,
71                  (void*)APR_OFFSETOF(auth_sslcert_config_rec, strip_suffix),
72                  OR_AUTHCFG,
73                  "An optional suffix to strip from the username"),
74    AP_INIT_FLAG("AuthSSLCertStripSuffixRequired", ap_set_flag_slot,
75                 (void *)APR_OFFSETOF(auth_sslcert_config_rec, strip_suffix_required),
76                 OR_AUTHCFG,
77                 "Set to 'Off' to allow certs that don't end with a recognized "
78                 "suffix to still authenticate"),
79    {NULL}
80};
81
82module AP_MODULE_DECLARE_DATA auth_sslcert_module;
83
84static int authenticate_sslcert_user(request_rec *r)
85{
86    auth_sslcert_config_rec *conf = ap_get_module_config(r->per_dir_config,
87                                                         &auth_sslcert_module);
88    const char *current_auth;
89
90    /* Are we configured to be SSLCert auth? */
91    current_auth = ap_auth_type(r);
92    if (!current_auth || strcasecmp(current_auth, "SSLCert") != 0) {
93        return DECLINED;
94    }
95
96    r->ap_auth_type = "SSLCert";
97
98    if (strcasecmp((char *)ssl_var_lookup(r->pool, r->server, r->connection, r,
99                                          "SSL_CLIENT_VERIFY"),
100                   "SUCCESS") == 0) {
101        if (conf->var == NULL) {
102            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
103                          "AuthSSLCertVar is not set: \"%s\"", r->uri);
104            return HTTP_INTERNAL_SERVER_ERROR;
105        }
106        char *user = (char *)ssl_var_lookup(r->pool, r->server, r->connection, r,
107                                            conf->var);
108        if (user != NULL && user[0] != '\0') {
109            if (conf->strip_suffix != NULL) {
110                int i = strlen(user) - strlen(conf->strip_suffix);
111                if (i >= 0 && strcasecmp(user + i, conf->strip_suffix) == 0) {
112                    r->user = apr_pstrmemdup(r->pool, user, i);
113                    return OK;
114                } else if (!conf->strip_suffix_required) {
115                    r->user = user;
116                    return OK;
117                } else {
118                    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
119                                  "SSL username for \"%s\" has wrong suffix: \"%s\"",
120                                  r->uri, user);
121                }
122            } else {
123                r->user = user;
124                return OK;
125            }
126        } else {
127            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
128                          "no SSL username for \"%s\"", r->uri);
129        }
130    } else if (conf->authoritative) {
131        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
132                      "SSL client not verified for \"%s\"", r->uri);
133    }
134
135    /* If we're not authoritative, then any error is ignored. */
136    if (!conf->authoritative) {
137        return DECLINED;
138    }
139
140    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
141                  "SSLCert authentication failure for \"%s\"",
142                  r->uri);
143    return HTTP_UNAUTHORIZED;
144}
145
146static void import_ssl_var_lookup()
147{
148    ssl_var_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup);
149}
150
151static void register_hooks(apr_pool_t *p)
152{
153    ap_hook_check_user_id(authenticate_sslcert_user, NULL, NULL, APR_HOOK_MIDDLE);
154    ap_hook_optional_fn_retrieve(import_ssl_var_lookup, NULL, NULL, APR_HOOK_MIDDLE);
155}
156
157module AP_MODULE_DECLARE_DATA auth_sslcert_module =
158{
159    STANDARD20_MODULE_STUFF,
160    create_auth_sslcert_dir_config,  /* dir config creater */
161    merge_auth_sslcert_dir_config,   /* dir merger */
162    NULL,                            /* server config */
163    NULL,                            /* merge server config */
164    auth_sslcert_cmds,               /* command apr_table_t */
165    register_hooks                   /* register hooks */
166};
Note: See TracBrowser for help on using the repository browser.