Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ ylwrap
src/lex.c
src/parser.c
src/parser.h
testdir/
*.o
*.lo
*.la
15 changes: 15 additions & 0 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ Configuration Directives
[GssapiNameAttributes](#gssapinameattributes)<br>
[GssapiNegotiateOnce](#gssapinegotiateonce)<br>
[GssapiPublishErrors](#gssapipublisherrors)<br>
[GssapiPublishMech](#gssapipublishmech)<br>
[GssapiRequiredNameAttributes](#gssapirequirednameattributes)<br>
[GssapiSessionKey](#gssapisessionkey)<br>
[GssapiSignalPersistentAuth](#gssapisignalpersistentauth)<br>
Expand Down Expand Up @@ -543,3 +544,17 @@ Note: the value is specified in seconds.
Sets ticket/session validity to 10 hours.


### GssapiPublishMech

This option is used to publish the mech used for authentication as an
Environment variable named GSS_MECH.

It will return a string of the form 'Authtype/Mechname'.
Authtype represents the type of auth performed by the module. Possible values
are 'Basic', 'Negotiate', 'NTLM', 'Impersonate'.
Mechname is the name of the mechanism as reported by GSSAPI or the OID of the
mechanism if a name is not available. In case of errors the 'Unavailable'
string may also be returned for either Authtype or Mechname.

- **Enable with:** GssapiPublishMech On
- **Default:** GssapiPublishMech Off
38 changes: 38 additions & 0 deletions src/environ.c
Original file line number Diff line number Diff line change
Expand Up @@ -498,3 +498,41 @@ void mag_publish_error(request_rec *req, uint32_t maj, uint32_t min,
if (mag_err)
apr_table_set(req->subprocess_env, "MAG_ERROR", mag_err);
}

void mag_publish_mech(request_rec *req, struct mag_conn *mc,
const char *auth_type, gss_OID mech_type)
{
gss_buffer_desc sasl_mech_name = GSS_C_EMPTY_BUFFER;
gss_buffer_desc mech_name = GSS_C_EMPTY_BUFFER;
gss_buffer_desc mech_description = GSS_C_EMPTY_BUFFER;
char *mechdata;
uint32_t maj, min;

maj = gss_inquire_saslname_for_mech(&min, mech_type, &sasl_mech_name,
&mech_name, &mech_description);
if (maj != GSS_S_COMPLETE) {
/* something failed, let's try to get a string OID */
/* and if that fails there is nothing we can do */
maj = gss_oid_to_str(&min, mech_type, &mech_name);
if (maj != GSS_S_COMPLETE) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
"Failed to source mechanism name or OID");
mech_name.value = strdup("Unavailable");
mech_name.length = strlen(mech_name.value);
}
}

mechdata = apr_psprintf(req->pool, "%s/%.*s", auth_type,
(int)mech_name.length,
(char *)mech_name.value);

apr_table_set(mc->env, "GSS_MECH", mechdata);

/* also log at info level */
ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, req,
"User %s authenticated with %s", mc->gss_name, mechdata);

(void)gss_release_buffer(&min, &sasl_mech_name);
(void)gss_release_buffer(&min, &mech_name);
(void)gss_release_buffer(&min, &mech_description);
}
2 changes: 2 additions & 0 deletions src/environ.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ void mag_publish_error(request_rec *req, uint32_t maj, uint32_t min,
const char *gss_err, const char *mag_err);
void mag_set_req_attr_fail(request_rec *req, struct mag_config *cfg,
struct mag_conn *mc);
void mag_publish_mech(request_rec *req, struct mag_conn *mc,
const char *auth_type, gss_OID mech_type);
7 changes: 7 additions & 0 deletions src/mod_auth_gssapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1294,6 +1294,10 @@ static int mag_complete(struct mag_req_cfg *req_cfg, struct mag_conn *mc,
mc->user_name = apr_pstrdup(mc->pool, mc->gss_name);
}

if (cfg->pubmech) {
mag_publish_mech(req, mc, mag_str_auth_type(mc->auth_type), mech_type);
}

mc->established = true;
if (req_cfg->use_sessions) {
mag_attempt_session(req_cfg, mc);
Expand Down Expand Up @@ -1899,6 +1903,9 @@ static const command_rec mag_commands[] = {
AP_INIT_FLAG("GssapiPublishErrors", ap_set_flag_slot,
(void *)APR_OFFSETOF(struct mag_config, enverrs), OR_AUTHCFG,
"Publish GSSAPI Errors in Envionment Variables"),
AP_INIT_FLAG("GssapiPublishMech", ap_set_flag_slot,
(void *)APR_OFFSETOF(struct mag_config, pubmech), OR_AUTHCFG,
"Publish GSSAPI Mech Name in Envionment Variables"),
AP_INIT_RAW_ARGS("GssapiAcceptorName", mag_acceptor_name, NULL, OR_AUTHCFG,
"Name of the acceptor credentials."),
AP_INIT_TAKE1("GssapiBasicTicketTimeout", mag_basic_timeout, NULL,
Expand Down
1 change: 1 addition & 0 deletions src/mod_auth_gssapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ struct mag_config {
struct mag_name_attributes *name_attributes;
const char *required_na_expr;
int enverrs;
int pubmech;
gss_name_t acceptor_name;
bool acceptor_name_from_req;
uint32_t basic_timeout;
Expand Down
4 changes: 3 additions & 1 deletion tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ EXTRA_DIST = \
index.html \
localname.html \
magtests.py \
mech.html \
t_bad_acceptor_name.py \
t_basic_k5_fail_second.py \
t_basic_k5.py \
t_basic_k5_two_users.py \
t_basic_proxy.py \
t_basic_timeout.py \
t_localname.py \
t_hostname_acceptor.py \
t_localname.py \
t_mech_name.py \
t_nonego.py \
t_required_name_attr.py \
t_spnego_negotiate_once.py \
Expand Down
15 changes: 15 additions & 0 deletions tests/httpd.conf
Original file line number Diff line number Diff line change
Expand Up @@ -331,3 +331,18 @@ CoreDumpDirectory "{HTTPROOT}"
GssapiSessionKey file:{HTTPROOT}/session.key
Require valid-user
</Location>

<Location /mech_name>
Options +Includes
AddOutputFilter INCLUDES .html
AuthType GSSAPI
AuthName "Password Login"
GssapiSSLonly Off
GssapiCredStore ccache:{HTTPROOT}/tmp/httpd_krb5_ccache
GssapiCredStore client_keytab:{HTTPROOT}/http.keytab
GssapiCredStore keytab:{HTTPROOT}/http.keytab
GssapiBasicAuth On
GssapiBasicAuthMech krb5
GssapiPublishMech On
Require valid-user
</Location>
18 changes: 18 additions & 0 deletions tests/magtests.py
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,22 @@ def http_restart(testdir, so_dir, testenv):
return httpproc


def test_mech_name(testdir, testenv, logfile):
basicdir = os.path.join(testdir, 'httpd', 'html', 'mech_name')
os.mkdir(basicdir)
shutil.copy('tests/mech.html', basicdir)

mname = subprocess.Popen(["tests/t_mech_name.py"],
stdout=logfile, stderr=logfile,
env=testenv, preexec_fn=os.setsid)
mname.wait()
if mname.returncode != 0:
sys.stderr.write('MECH-NAME: FAILED\n')
return 1
sys.stderr.write('MECH-NAME: SUCCESS\n')
return 0


if __name__ == '__main__':
args = parse_args()

Expand Down Expand Up @@ -832,6 +848,8 @@ def http_restart(testdir, so_dir, testenv):

errs += test_no_negotiate(testdir, testenv, logfile)

errs += test_mech_name(testdir, testenv, logfile)

# After this point we need to speed up httpd to test creds timeout
try:
fakeenv = faketime_setup(kdcenv)
Expand Down
1 change: 1 addition & 0 deletions tests/mech.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!--#echo var="GSS_MECH" -->
19 changes: 19 additions & 0 deletions tests/t_mech_name.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env python
# Copyright (C) 2015 - mod_auth_gssapi contributors, see COPYING for license.

import os
import requests
from requests.auth import HTTPBasicAuth


if __name__ == '__main__':
url = 'http://%s/mech_name/mech.html' % os.environ['NSS_WRAPPER_HOSTNAME']
r = requests.get(url, auth=HTTPBasicAuth(os.environ['MAG_USER_NAME'],
os.environ['MAG_USER_PASSWORD']))
if r.status_code != 200:
raise ValueError('Basic Auth Failed')

if r.text.rstrip() != 'Basic/krb5':
raise ValueError(
'GSS_MECH check failed, expected Basic/krb5, got "%s"' %
r.text.rstrip())