Blame SOURCES/Add-ability-to-expose-the-used-mechanism.patch

2cb7d5
From 46caec4def9fd8df21e560db065b755e1d87354d Mon Sep 17 00:00:00 2001
2cb7d5
From: rpm-build <rpm-build>
2cb7d5
Date: Fri, 6 May 2022 22:54:45 +0200
2cb7d5
Subject: [PATCH 1/2] Add-ability-to-expose-the-used-mechanism.patch
2cb7d5
2cb7d5
---
2cb7d5
 README                | 15 +++++++++++++++
2cb7d5
 src/environ.c         | 39 +++++++++++++++++++++++++++++++++++++++
2cb7d5
 src/environ.h         |  2 ++
2cb7d5
 src/mod_auth_gssapi.c |  7 +++++++
2cb7d5
 src/mod_auth_gssapi.h |  1 +
2cb7d5
 tests/Makefile.am     |  4 +++-
2cb7d5
 tests/httpd.conf      | 15 +++++++++++++++
2cb7d5
 tests/magtests.py     | 18 ++++++++++++++++++
2cb7d5
 tests/mech.html       |  1 +
2cb7d5
 tests/t_mech_name.py  | 19 +++++++++++++++++++
2cb7d5
 10 files changed, 120 insertions(+), 1 deletion(-)
2cb7d5
 create mode 100644 tests/mech.html
2cb7d5
 create mode 100755 tests/t_mech_name.py
2cb7d5
2cb7d5
diff --git a/README b/README
2cb7d5
index 654a8918cc1cd078d84b8e571596444e262e83af..bbf2657d47c9b111e20fdc2b76fde8799c76e3cd 100644
2cb7d5
--- a/README
2cb7d5
+++ b/README
2cb7d5
@@ -109,6 +109,7 @@ Configuration Directives
2cb7d5
 [GssapiNameAttributes](#gssapinameattributes)
2cb7d5
 [GssapiNegotiateOnce](#gssapinegotiateonce)
2cb7d5
 [GssapiPublishErrors](#gssapipublisherrors)
2cb7d5
+[GssapiPublishMech](#gssapipublishmech)
2cb7d5
 [GssapiRequiredNameAttributes](#gssapirequirednameattributes)
2cb7d5
 [GssapiSessionKey](#gssapisessionkey)
2cb7d5
 [GssapiSignalPersistentAuth](#gssapisignalpersistentauth)
2cb7d5
@@ -527,3 +528,17 @@ Note: the value is specified in seconds.
2cb7d5
 Sets ticket/session validity to 10 hours.
2cb7d5
 
2cb7d5
 
2cb7d5
+### GssapiPublishMech
2cb7d5
+
2cb7d5
+This option is used to publish the mech used for authentication as an
2cb7d5
+Environment variable named GSS_MECH.
2cb7d5
+
2cb7d5
+It will return a string of the form 'Authtype/Mechname'.
2cb7d5
+Authtype represents the type of auth performed by the module. Possible values
2cb7d5
+are 'Basic', 'Negotiate', 'NTLM', 'Impersonate'.
2cb7d5
+Mechname is the name of the mechanism as reported by GSSAPI or the OID of the
2cb7d5
+mechanism if a name is not available. In case of errors the 'Unavailable'
2cb7d5
+string may also be returned for either Authtype or Mechname.
2cb7d5
+
2cb7d5
+- **Enable with:** GssapiPublishMech On
2cb7d5
+- **Default:** GssapiPublishMech Off
2cb7d5
\ No newline at end of file
2cb7d5
diff --git a/src/environ.c b/src/environ.c
2cb7d5
index 7ee56a1ba434d5c1041968fb3f64191340cb0ea7..71a8564284cafa62c4cbeaf7ab8484a48c064e66 100644
2cb7d5
--- a/src/environ.c
2cb7d5
+++ b/src/environ.c
2cb7d5
@@ -498,3 +498,42 @@ void mag_publish_error(request_rec *req, uint32_t maj, uint32_t min,
2cb7d5
     if (mag_err)
2cb7d5
         apr_table_set(req->subprocess_env, "MAG_ERROR", mag_err);
2cb7d5
 }
2cb7d5
+
2cb7d5
+
2cb7d5
+void mag_publish_mech(request_rec *req, struct mag_conn *mc,
2cb7d5
+                      const char *auth_type, gss_OID mech_type)
2cb7d5
+{
2cb7d5
+    gss_buffer_desc sasl_mech_name = GSS_C_EMPTY_BUFFER;
2cb7d5
+    gss_buffer_desc mech_name = GSS_C_EMPTY_BUFFER;
2cb7d5
+    gss_buffer_desc mech_description = GSS_C_EMPTY_BUFFER;
2cb7d5
+    char *mechdata;
2cb7d5
+    uint32_t maj, min;
2cb7d5
+
2cb7d5
+    maj = gss_inquire_saslname_for_mech(&min, mech_type, &sasl_mech_name,
2cb7d5
+                                        &mech_name, &mech_description);
2cb7d5
+    if (maj != GSS_S_COMPLETE) {
2cb7d5
+        /* something failed, let's try to get a string OID */
2cb7d5
+        /* and if that fails there is nothing we can do */
2cb7d5
+        maj = gss_oid_to_str(&min, mech_type, &mech_name);
2cb7d5
+        if (maj != GSS_S_COMPLETE) {
2cb7d5
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
2cb7d5
+                          "Failed to source mechanism name or OID");
2cb7d5
+            mech_name.value = strdup("Unavailable");
2cb7d5
+            mech_name.length = strlen(mech_name.value);
2cb7d5
+        }
2cb7d5
+    }
2cb7d5
+
2cb7d5
+    mechdata = apr_psprintf(req->pool, "%s/%.*s", auth_type,
2cb7d5
+                            (int)mech_name.length,
2cb7d5
+                            (char *)mech_name.value);
2cb7d5
+
2cb7d5
+    apr_table_set(mc->env, "GSS_MECH", mechdata);
2cb7d5
+
2cb7d5
+    /* also log at info level */
2cb7d5
+    ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, req,
2cb7d5
+                  "User %s authenticated with %s", mc->gss_name, mechdata);
2cb7d5
+
2cb7d5
+    (void)gss_release_buffer(&min, &sasl_mech_name);
2cb7d5
+    (void)gss_release_buffer(&min, &mech_name);
2cb7d5
+    (void)gss_release_buffer(&min, &mech_description);
2cb7d5
+}
2cb7d5
diff --git a/src/environ.h b/src/environ.h
2cb7d5
index 40bca9877f600246d19a3bf4be370310636ce6c7..b0813da6508df7c5594b51cada7712dc44393e44 100644
2cb7d5
--- a/src/environ.h
2cb7d5
+++ b/src/environ.h
2cb7d5
@@ -18,3 +18,5 @@ void mag_publish_error(request_rec *req, uint32_t maj, uint32_t min,
2cb7d5
                        const char *gss_err, const char *mag_err);
2cb7d5
 void mag_set_req_attr_fail(request_rec *req, struct mag_config *cfg,
2cb7d5
                            struct mag_conn *mc);
2cb7d5
+void mag_publish_mech(request_rec *req, struct mag_conn *mc,
2cb7d5
+                      const char *auth_type, gss_OID mech_type);
2cb7d5
diff --git a/src/mod_auth_gssapi.c b/src/mod_auth_gssapi.c
2cb7d5
index c91aa60707ba9b237a84f95670d483f1a7eab86b..93c43308585cf140297de82e118a367f69d25a92 100644
2cb7d5
--- a/src/mod_auth_gssapi.c
2cb7d5
+++ b/src/mod_auth_gssapi.c
2cb7d5
@@ -1289,6 +1289,10 @@ static int mag_complete(struct mag_req_cfg *req_cfg, struct mag_conn *mc,
2cb7d5
         mc->user_name = apr_pstrdup(mc->pool, mc->gss_name);
2cb7d5
     }
2cb7d5
 
2cb7d5
+    if (cfg->pubmech) {
2cb7d5
+        mag_publish_mech(req, mc, mag_str_auth_type(mc->auth_type), mech_type);
2cb7d5
+    }
2cb7d5
+
2cb7d5
     mc->established = true;
2cb7d5
     if (req_cfg->use_sessions) {
2cb7d5
         mag_attempt_session(req_cfg, mc);
2cb7d5
@@ -1894,6 +1898,9 @@ static const command_rec mag_commands[] = {
2cb7d5
     AP_INIT_FLAG("GssapiPublishErrors", ap_set_flag_slot,
2cb7d5
                  (void *)APR_OFFSETOF(struct mag_config, enverrs), OR_AUTHCFG,
2cb7d5
                  "Publish GSSAPI Errors in Envionment Variables"),
2cb7d5
+    AP_INIT_FLAG("GssapiPublishMech", ap_set_flag_slot,
2cb7d5
+                 (void *)APR_OFFSETOF(struct mag_config, pubmech), OR_AUTHCFG,
2cb7d5
+                 "Publish GSSAPI Mech Name in Envionment Variables"),
2cb7d5
     AP_INIT_RAW_ARGS("GssapiAcceptorName", mag_acceptor_name, NULL, OR_AUTHCFG,
2cb7d5
                      "Name of the acceptor credentials."),
2cb7d5
     AP_INIT_TAKE1("GssapiBasicTicketTimeout", mag_basic_timeout, NULL,
2cb7d5
diff --git a/src/mod_auth_gssapi.h b/src/mod_auth_gssapi.h
2cb7d5
index 2312ab57f4b2e0bd50f191018b081a3ecb86f15a..8ab3bdc57be793cc493176c02910219e905900e9 100644
2cb7d5
--- a/src/mod_auth_gssapi.h
2cb7d5
+++ b/src/mod_auth_gssapi.h
2cb7d5
@@ -91,6 +91,7 @@ struct mag_config {
2cb7d5
     struct mag_name_attributes *name_attributes;
2cb7d5
     const char *required_na_expr;
2cb7d5
     int enverrs;
2cb7d5
+    int pubmech;
2cb7d5
     gss_name_t acceptor_name;
2cb7d5
     bool acceptor_name_from_req;
2cb7d5
     uint32_t basic_timeout;
2cb7d5
diff --git a/tests/Makefile.am b/tests/Makefile.am
2cb7d5
index c830e951d04316e4cbc76fa3b5961baedb516ec6..2ddb46ea30e6ebf9ff0b30278c609178d02c1efc 100644
2cb7d5
--- a/tests/Makefile.am
2cb7d5
+++ b/tests/Makefile.am
2cb7d5
@@ -6,14 +6,16 @@ EXTRA_DIST = \
2cb7d5
 	index.html \
2cb7d5
 	localname.html \
2cb7d5
 	magtests.py \
2cb7d5
+        mech.html \
2cb7d5
 	t_bad_acceptor_name.py \
2cb7d5
 	t_basic_k5_fail_second.py \
2cb7d5
 	t_basic_k5.py \
2cb7d5
 	t_basic_k5_two_users.py \
2cb7d5
 	t_basic_proxy.py \
2cb7d5
 	t_basic_timeout.py \
2cb7d5
-	t_localname.py \
2cb7d5
 	t_hostname_acceptor.py \
2cb7d5
+        t_localname.py \
2cb7d5
+        t_mech_name.py \
2cb7d5
 	t_nonego.py \
2cb7d5
 	t_required_name_attr.py \
2cb7d5
 	t_spnego_negotiate_once.py \
2cb7d5
diff --git a/tests/httpd.conf b/tests/httpd.conf
2cb7d5
index b3777574d9f0547560f24eff992fc1018569b5cc..775294b7d600e82c3955316a2d5b667c8b3c5581 100644
2cb7d5
--- a/tests/httpd.conf
2cb7d5
+++ b/tests/httpd.conf
2cb7d5
@@ -331,3 +331,18 @@ CoreDumpDirectory "{HTTPROOT}"
2cb7d5
   GssapiSessionKey file:{HTTPROOT}/session.key
2cb7d5
   Require valid-user
2cb7d5
 </Location>
2cb7d5
+
2cb7d5
+<Location /mech_name>
2cb7d5
+  Options +Includes
2cb7d5
+  AddOutputFilter INCLUDES .html
2cb7d5
+  AuthType GSSAPI
2cb7d5
+  AuthName "Password Login"
2cb7d5
+  GssapiSSLonly Off
2cb7d5
+  GssapiCredStore ccache:{HTTPROOT}/tmp/httpd_krb5_ccache
2cb7d5
+  GssapiCredStore client_keytab:{HTTPROOT}/http.keytab
2cb7d5
+  GssapiCredStore keytab:{HTTPROOT}/http.keytab
2cb7d5
+  GssapiBasicAuth On
2cb7d5
+  GssapiBasicAuthMech krb5
2cb7d5
+  GssapiPublishMech On
2cb7d5
+  Require valid-user
2cb7d5
+</Location>
2cb7d5
\ No newline at end of file
2cb7d5
diff --git a/tests/magtests.py b/tests/magtests.py
2cb7d5
index d100413b371e7ecf4e09d944b7ff6e9bec7e316f..9aba68f826a37a890bfefb62665697eef7d07dfa 100755
2cb7d5
--- a/tests/magtests.py
2cb7d5
+++ b/tests/magtests.py
2cb7d5
@@ -786,6 +786,22 @@ def test_gss_localname(testdir, testenv, logfile):
2cb7d5
     return error_count
2cb7d5
 
2cb7d5
 
2cb7d5
+def test_mech_name(testdir, testenv, logfile):
2cb7d5
+    basicdir = os.path.join(testdir, 'httpd', 'html', 'mech_name')
2cb7d5
+    os.mkdir(basicdir)
2cb7d5
+    shutil.copy('tests/mech.html', basicdir)
2cb7d5
+
2cb7d5
+    mname = subprocess.Popen(["tests/t_mech_name.py"],
2cb7d5
+                             stdout=logfile, stderr=logfile,
2cb7d5
+                             env=testenv, preexec_fn=os.setsid)
2cb7d5
+    mname.wait()
2cb7d5
+    if mname.returncode != 0:
2cb7d5
+        sys.stderr.write('MECH-NAME: FAILED\n')
2cb7d5
+        return 1
2cb7d5
+    sys.stderr.write('MECH-NAME: SUCCESS\n')
2cb7d5
+    return 0
2cb7d5
+
2cb7d5
+
2cb7d5
 if __name__ == '__main__':
2cb7d5
     args = parse_args()
2cb7d5
 
2cb7d5
@@ -847,6 +863,8 @@ if __name__ == '__main__':
2cb7d5
 
2cb7d5
         errs += test_no_negotiate(testdir, testenv, logfile)
2cb7d5
 
2cb7d5
+        errs += test_mech_name(testdir, testenv, logfile)
2cb7d5
+
2cb7d5
         # After this point we need to speed up httpd to test creds timeout
2cb7d5
         try:
2cb7d5
             fakeenv = faketime_setup(kdcenv)
2cb7d5
diff --git a/tests/mech.html b/tests/mech.html
2cb7d5
new file mode 100644
2cb7d5
index 0000000000000000000000000000000000000000..bb7b3cd5278f055e278a7dfde73c15aa400a6a17
2cb7d5
--- /dev/null
2cb7d5
+++ b/tests/mech.html
2cb7d5
@@ -0,0 +1 @@
2cb7d5
+
2cb7d5
diff --git a/tests/t_mech_name.py b/tests/t_mech_name.py
2cb7d5
new file mode 100755
2cb7d5
index 0000000000000000000000000000000000000000..69f451f2bbe58a16f61418f96eca26e7994bcb8a
2cb7d5
--- /dev/null
2cb7d5
+++ b/tests/t_mech_name.py
2cb7d5
@@ -0,0 +1,19 @@
2cb7d5
+#!/usr/bin/env python3
2cb7d5
+# Copyright (C) 2015 - mod_auth_gssapi contributors, see COPYING for license.
2cb7d5
+
2cb7d5
+import os
2cb7d5
+import requests
2cb7d5
+from requests.auth import HTTPBasicAuth
2cb7d5
+
2cb7d5
+
2cb7d5
+if __name__ == '__main__':
2cb7d5
+    url = 'http://%s/mech_name/mech.html' % os.environ['NSS_WRAPPER_HOSTNAME']
2cb7d5
+    r = requests.get(url, auth=HTTPBasicAuth(os.environ['MAG_USER_NAME'],
2cb7d5
+                                             os.environ['MAG_USER_PASSWORD']))
2cb7d5
+    if r.status_code != 200:
2cb7d5
+        raise ValueError('Basic Auth Failed')
2cb7d5
+
2cb7d5
+    if r.text.rstrip() != 'Basic/krb5':
2cb7d5
+        raise ValueError(
2cb7d5
+            'GSS_MECH check failed, expected Basic/krb5, got "%s"' %
2cb7d5
+            r.text.rstrip())
2cb7d5
-- 
2cb7d5
2.35.3
2cb7d5