Skip to content

Commit 7454bf6

Browse files
committed
Allow context to be attached to the connection
This means the authentication is not repeated for every request but is retained for the life of the connection. This may be a security issue if a frontend proxy shares connections between multiple users so must be used with care. RFC 4559 warns that clients should not try SPNEGO if such a proxy is present. Unfortuntely the RFC assumes a non-standard method to determine if a proxy maintain separate connections.
1 parent 76a682e commit 7454bf6

File tree

1 file changed

+83
-18
lines changed

1 file changed

+83
-18
lines changed

src/mod_auth_gssapi.c

Lines changed: 83 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
#include <httpd.h>
3131
#include <http_core.h>
32+
#include <http_connection.h>
3233
#include <http_log.h>
3334
#include <http_request.h>
3435
#include <apr_strings.h>
@@ -39,6 +40,7 @@ module AP_MODULE_DECLARE_DATA auth_gssapi_module;
3940
struct mag_config {
4041
bool ssl_only;
4142
bool map_to_local;
43+
bool gss_conn_ctx;
4244
gss_key_value_set_desc cred_store;
4345
};
4446

@@ -83,6 +85,24 @@ static char *mag_error(request_rec *req, const char *msg,
8385
return apr_psprintf(req->pool, "%s: [%s (%s)]", msg, msg_maj, msg_min);
8486
}
8587

88+
struct mag_conn {
89+
gss_ctx_id_t ctx;
90+
bool established;
91+
char *user_name;
92+
char *gss_name;
93+
};
94+
95+
static int mag_pre_connection(conn_rec *c, void *csd)
96+
{
97+
struct mag_conn *mc;
98+
99+
mc = apr_pcalloc(c->pool, sizeof(struct mag_conn));
100+
if (!mc) return DECLINED;
101+
102+
ap_set_module_config(c->conn_config, &auth_gssapi_module, (void*)mc);
103+
return OK;
104+
}
105+
86106
static int mag_auth(request_rec *req)
87107
{
88108
const char *type;
@@ -104,6 +124,7 @@ static int mag_auth(request_rec *req)
104124
char *clientname;
105125
gss_OID mech_type = GSS_C_NO_OID;
106126
gss_buffer_desc lname = GSS_C_EMPTY_BUFFER;
127+
struct mag_conn *mc = NULL;
107128

108129
type = ap_auth_type(req);
109130
if ((type == NULL) || (strcasecmp(type, "GSSAPI") != 0)) {
@@ -117,6 +138,26 @@ static int mag_auth(request_rec *req)
117138
"FIXME: check for ssl!");
118139
}
119140

141+
if (cfg->gss_conn_ctx) {
142+
mc = (struct mag_conn *)ap_get_module_config(
143+
req->connection->conn_config,
144+
&auth_gssapi_module);
145+
if (!mc) {
146+
return DECLINED;
147+
}
148+
if (mc->established) {
149+
ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, req,
150+
"Connection bound pre-authentication found.");
151+
apr_table_set(req->subprocess_env, "GSS_NAME", mc->gss_name);
152+
req->ap_auth_type = apr_pstrdup(req->pool, "Negotiate");
153+
req->user = apr_pstrdup(req->pool, mc->user_name);
154+
ret = OK;
155+
goto done;
156+
} else {
157+
ctx = mc->ctx;
158+
}
159+
}
160+
120161
auth_header = apr_table_get(req->headers_in, "Authorization");
121162
if (!auth_header) goto done;
122163

@@ -132,8 +173,6 @@ static int mag_auth(request_rec *req)
132173
if (!input.value) goto done;
133174
input.length = apr_base64_decode(input.value, auth_header_value);
134175

135-
/* FIXME: this works only with "one-roundtrip" gssapi auth for now,
136-
* should work with Krb, will fail with NTLMSSP */
137176
maj = gss_accept_sec_context(&min, &ctx, GSS_C_NO_CREDENTIAL,
138177
&input, GSS_C_NO_CHANNEL_BINDINGS,
139178
&client, &mech_type, &output, &flags, NULL,
@@ -145,23 +184,12 @@ static int mag_auth(request_rec *req)
145184
goto done;
146185
}
147186

148-
if (output.length) {
149-
replen = apr_base64_encode_len(output.length) + 1;
150-
reply = apr_pcalloc(req->pool, 10 + replen);
151-
if (!reply) goto done;
152-
memcpy(reply, "Negotiate ", 10);
153-
apr_base64_encode(&reply[10], output.value, output.length);
154-
reply[replen] = '\0';
155-
apr_table_add(req->err_headers_out, "WWW-Authenticate", reply);
187+
if (mc) {
188+
mc->ctx = ctx;
189+
ctx = GSS_C_NO_CONTEXT;
156190
}
157191

158-
maj = gss_display_name(&min, client, &name, NULL);
159-
if (GSS_ERROR(maj)) {
160-
ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
161-
mag_error(req, "gss_accept_sec_context() failed",
162-
maj, min));
163-
goto done;
164-
}
192+
if (maj == GSS_S_CONTINUE_NEEDED) goto done;
165193

166194
#ifdef HAVE_GSS_STORE_CRED_INTO
167195
if (cfg->cred_store && delegated_cred != GSS_C_NO_CREDENTIAL) {
@@ -176,6 +204,13 @@ static int mag_auth(request_rec *req)
176204
req->ap_auth_type = apr_pstrdup(req->pool, "Negotiate");
177205

178206
/* Always set the GSS name in an env var */
207+
maj = gss_display_name(&min, client, &name, NULL);
208+
if (GSS_ERROR(maj)) {
209+
ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
210+
mag_error(req, "gss_accept_sec_context() failed",
211+
maj, min));
212+
goto done;
213+
}
179214
clientname = apr_pstrndup(req->pool, name.value, name.length);
180215
apr_table_set(req->subprocess_env, "GSS_NAME", clientname);
181216

@@ -190,11 +225,31 @@ static int mag_auth(request_rec *req)
190225
} else {
191226
req->user = clientname;
192227
}
228+
229+
if (mc) {
230+
mc->user_name = apr_pstrdup(req->connection->pool, req->user);
231+
mc->gss_name = apr_pstrdup(req->connection->pool, clientname);
232+
mc->established = true;
233+
}
234+
193235
ret = OK;
194236

195237
done:
196238
if (ret == HTTP_UNAUTHORIZED) {
197-
apr_table_add(req->err_headers_out, "WWW-Authenticate", "Negotiate");
239+
if (output.length != 0) {
240+
replen = apr_base64_encode_len(output.length) + 1;
241+
reply = apr_pcalloc(req->pool, 10 + replen);
242+
if (reply) {
243+
memcpy(reply, "Negotiate ", 10);
244+
apr_base64_encode(&reply[10], output.value, output.length);
245+
reply[replen] = '\0';
246+
apr_table_add(req->err_headers_out,
247+
"WWW-Authenticate", reply);
248+
}
249+
} else {
250+
apr_table_add(req->err_headers_out,
251+
"WWW-Authenticate", "Negotiate");
252+
}
198253
}
199254
gss_release_cred(&min, &delegated_cred);
200255
gss_release_buffer(&min, &output);
@@ -230,6 +285,13 @@ static const char *mag_map_to_local(cmd_parms *parms, void *mconfig, int on)
230285
return NULL;
231286
}
232287

288+
static const char *mag_conn_ctx(cmd_parms *parms, void *mconfig, int on)
289+
{
290+
struct mag_config *cfg = (struct mag_config *)mconfig;
291+
cfg->gss_conn_ctx = on ? true : false;
292+
return NULL;
293+
}
294+
233295
static const char *mag_cred_store(cmd_parms *parms, void *mconfig,
234296
const char *w)
235297
{
@@ -281,6 +343,8 @@ static const command_rec mag_commands[] = {
281343
"Work only if connection is SSL Secured"),
282344
AP_INIT_FLAG("GSSLocalName", mag_map_to_local, NULL, OR_AUTHCFG,
283345
"Work only if connection is SSL Secured"),
346+
AP_INIT_FLAG("GSSConnectionContext", mag_conn_ctx, NULL, OR_AUTHCFG,
347+
"Authentication is valid for the life of the connection"),
284348
AP_INIT_ITERATE("GSSCredStore", mag_cred_store, NULL, OR_AUTHCFG,
285349
"Credential Store"),
286350
{ NULL }
@@ -290,6 +354,7 @@ static void
290354
mag_register_hooks(apr_pool_t *p)
291355
{
292356
ap_hook_check_user_id(mag_auth, NULL, NULL, APR_HOOK_MIDDLE);
357+
ap_hook_pre_connection(mag_pre_connection, NULL, NULL, APR_HOOK_MIDDLE);
293358
}
294359

295360
module AP_MODULE_DECLARE_DATA auth_gssapi_module =

0 commit comments

Comments
 (0)