On 03/10/2016 03:25 PM, Simo Sorce wrote:
On Thu, 2016-03-10 at 15:03 +0100, Petr Vobornik wrote:
Attaching also mod_auth_gssapi patch. If the approach is good, then I'd
send it as a push request to upstream git repo.

Copr build of mod_auth_gssapi with the patch:
https://copr.fedorainfracloud.org/coprs/pvoborni/freeipa-4-3/build/167157/

IPA patch attached uses the functionality.

https://fedorahosted.org/freeipa/ticket/5653

I think the mod_auth_gssapi patch needs more work.

New iteration, but not a final patch, mostly because of reaping of the files, but there are also some debug prints.


For one you are not storing the generated ccname in the cookie, which
means any following request using mod_auth_gssapi sessions will not be
able to point to the ccache file.

Do you mean session? Cookie should contain only session ID, right?


It is also not clear to me why you are using a timestamp and not just
call something like mkstemp() with a template, and add an option called
GssapiDelegCcacheTemplate instead.

I didn't think about that.


The templated part would have to be saved in the session so that
following requests can keep using the same ccache file.

Fixed (but not tested yet)


There are other minor niticks around naming stuff, but those can be
handled in the PR.

One thing I am still undecided about is deletion of the files, I'd like
to have a better option than "application must delete them", I was
thinking about keeping a record of the expiration time (not sure where
yet), and then provide a cron job or a systemd timer to clean up all
expired stuff.

I thought we won't need it and that it could be handled by apps, but that won't work.

Case 1: ipa kerberize entire /ipa directory so a request to a random resource might leave a ccache behind, e.g.: curl -v --negotiate -u : --cacert /etc/ipa/ca.crt https://$(hostname)/ipa/foo

leaves:
ls /var/run/httpd/ipa/clientcaches/
   ipacchache-sgwB9v

Case 2: custodia, it doesn't clean anything as well.

When sessions are not it play then, the plugin can remove the ccache at the end of request. AFAIK mod_auth_kerb does it.

With sessions, there needs to be a reaper.


Simo.

--
Petr Vobornik
From 888004fa23b66785029d5218134c21467f05e03f Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Tue, 8 Mar 2016 19:38:59 +0100
Subject: [PATCH] Support unique credential cache names

Add new configuration option:
  GssapiDelegCcacheTemplate ccacheXXXXXX

To enable unique names of credential caches. It allows consuming application
to work on top of the cache, without affecting other concurent http requests
of the same principal.
---
 README                     | 11 +++++++++
 src/asn1c/GSSSessionData.c | 17 ++++++++++---
 src/asn1c/GSSSessionData.h |  2 +-
 src/asn1c/Uint32.c         |  1 -
 src/asn1c/Uint32.h         |  1 -
 src/asn1c/session.asn1     |  3 ++-
 src/environ.c              | 12 +++------
 src/mod_auth_gssapi.c      | 61 ++++++++++++++++++++++++++++++++++++++++------
 src/mod_auth_gssapi.h      |  8 ++++--
 src/sessions.c             |  8 ++++++
 10 files changed, 98 insertions(+), 26 deletions(-)

diff --git a/README b/README
index b4eca28..d9cf320 100644
--- a/README
+++ b/README
@@ -171,6 +171,17 @@ A user f...@example.com delegating its credentials would cause the server to
 create a ccache file named /var/run/httpd/clientcaches/f...@example.com
 
 
+### GssapiDelegCcacheTemplate
+
+A template for credential cache name. Must end with XXXXXX before file name
+suffix.
+
+**Note:** Consuming application must delete the ccache otherwise it will
+litter the filesystem.
+
+#### Example
+    GssapiDelegCcacheTemplate ccacheXXXXXX
+
 ### GssapiUseS4U2Proxy
 
 Enables the use of the s4u2Proxy Kerberos extension also known as
diff --git a/src/asn1c/GSSSessionData.c b/src/asn1c/GSSSessionData.c
index 12a98e3..f0dcc2e 100644
--- a/src/asn1c/GSSSessionData.c
+++ b/src/asn1c/GSSSessionData.c
@@ -2,7 +2,6 @@
  * Generated by asn1c-0.9.27 (http://lionet.info/asn1c)
  * From ASN.1 module "GssapiSessionModule"
  * 	found in "session.asn1"
- * 	`asn1c -fskeletons-copy`
  */
 
 #include "GSSSessionData.h"
@@ -62,6 +61,15 @@ static asn_TYPE_member_t asn_MBR_GSSSessionData_1[] = {
 		0,
 		"basichash"
 		},
+	{ ATF_NOFLAGS, 0, offsetof(struct GSSSessionData, ccname),
+		(ASN_TAG_CLASS_CONTEXT | (6 << 2)),
+		+1,	/* EXPLICIT tag at current level */
+		&asn_DEF_OCTET_STRING,
+		0,	/* Defer constraints checking to the member type */
+		0,	/* PER is not compiled, use -gen-PER */
+		0,
+		"ccname"
+		},
 };
 static ber_tlv_tag_t asn_DEF_GSSSessionData_tags_1[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (16 << 2))
@@ -72,13 +80,14 @@ static asn_TYPE_tag2member_t asn_MAP_GSSSessionData_tag2el_1[] = {
     { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 }, /* expiration */
     { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 3, 0, 0 }, /* username */
     { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 4, 0, 0 }, /* gssname */
-    { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 5, 0, 0 } /* basichash */
+    { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 5, 0, 0 }, /* basichash */
+    { (ASN_TAG_CLASS_CONTEXT | (6 << 2)), 6, 0, 0 } /* ccname */
 };
 static asn_SEQUENCE_specifics_t asn_SPC_GSSSessionData_specs_1 = {
 	sizeof(struct GSSSessionData),
 	offsetof(struct GSSSessionData, _asn_ctx),
 	asn_MAP_GSSSessionData_tag2el_1,
-	6,	/* Count of tags in the map */
+	7,	/* Count of tags in the map */
 	0, 0, 0,	/* Optional elements (not needed) */
 	-1,	/* Start extensions */
 	-1	/* Stop extensions */
@@ -103,7 +112,7 @@ asn_TYPE_descriptor_t asn_DEF_GSSSessionData = {
 		/sizeof(asn_DEF_GSSSessionData_tags_1[0]), /* 1 */
 	0,	/* No PER visible constraints */
 	asn_MBR_GSSSessionData_1,
-	6,	/* Elements count */
+	7,	/* Elements count */
 	&asn_SPC_GSSSessionData_specs_1	/* Additional specs */
 };
 
diff --git a/src/asn1c/GSSSessionData.h b/src/asn1c/GSSSessionData.h
index 53556d8..4ae224f 100644
--- a/src/asn1c/GSSSessionData.h
+++ b/src/asn1c/GSSSessionData.h
@@ -2,7 +2,6 @@
  * Generated by asn1c-0.9.27 (http://lionet.info/asn1c)
  * From ASN.1 module "GssapiSessionModule"
  * 	found in "session.asn1"
- * 	`asn1c -fskeletons-copy`
  */
 
 #ifndef	_GSSSessionData_H_
@@ -29,6 +28,7 @@ typedef struct GSSSessionData {
 	OCTET_STRING_t	 username;
 	OCTET_STRING_t	 gssname;
 	OCTET_STRING_t	 basichash;
+	OCTET_STRING_t	 ccname;
 	
 	/* Context for parsing across buffer boundaries */
 	asn_struct_ctx_t _asn_ctx;
diff --git a/src/asn1c/Uint32.c b/src/asn1c/Uint32.c
index 794f98b..f5d125a 100644
--- a/src/asn1c/Uint32.c
+++ b/src/asn1c/Uint32.c
@@ -2,7 +2,6 @@
  * Generated by asn1c-0.9.27 (http://lionet.info/asn1c)
  * From ASN.1 module "GssapiSessionModule"
  * 	found in "session.asn1"
- * 	`asn1c -fskeletons-copy`
  */
 
 #include "Uint32.h"
diff --git a/src/asn1c/Uint32.h b/src/asn1c/Uint32.h
index a0ed876..436e26e 100644
--- a/src/asn1c/Uint32.h
+++ b/src/asn1c/Uint32.h
@@ -2,7 +2,6 @@
  * Generated by asn1c-0.9.27 (http://lionet.info/asn1c)
  * From ASN.1 module "GssapiSessionModule"
  * 	found in "session.asn1"
- * 	`asn1c -fskeletons-copy`
  */
 
 #ifndef	_Uint32_H_
diff --git a/src/asn1c/session.asn1 b/src/asn1c/session.asn1
index 1762812..f499779 100644
--- a/src/asn1c/session.asn1
+++ b/src/asn1c/session.asn1
@@ -8,6 +8,7 @@ GssapiSessionModule DEFINITIONS ::= BEGIN
         expiration  [2] Uint32,
         username    [3] OCTET STRING,
         gssname     [4] OCTET STRING,
-        basichash   [5] OCTET STRING
+        basichash   [5] OCTET STRING,
+        ccname      [6] OCTET STRING
     }
 END
diff --git a/src/environ.c b/src/environ.c
index f9bbf30..edf31cc 100644
--- a/src/environ.c
+++ b/src/environ.c
@@ -243,7 +243,7 @@ static void mag_set_name_attributes(request_rec *req, struct mag_conn *mc)
     }
 }
 
-static void mag_set_KRB5CCANME(request_rec *req, char *ccname)
+static void mag_set_KRB5CCANME(request_rec *req, const char *ccname)
 {
     apr_status_t status;
     apr_finfo_t finfo;
@@ -277,14 +277,8 @@ void mag_set_req_data(request_rec *req,
     }
 
 #ifdef HAVE_CRED_STORE
-    if (cfg->deleg_ccache_dir && mc->delegated) {
-        char *ccname;
-        ccname = mag_gss_name_to_ccache_name(req,
-                                             cfg->deleg_ccache_dir,
-                                             mc->gss_name);
-        if (ccname) {
-            mag_set_KRB5CCANME(req, ccname);
-        }
+    if (cfg->deleg_ccache_dir && mc->delegated && mc->ccname) {
+        mag_set_KRB5CCANME(req, mc->ccname);
     }
 #endif
 }
diff --git a/src/mod_auth_gssapi.c b/src/mod_auth_gssapi.c
index 97e365c..660377e 100644
--- a/src/mod_auth_gssapi.c
+++ b/src/mod_auth_gssapi.c
@@ -239,19 +239,37 @@ char *mag_gss_name_to_ccache_name(request_rec *req,
     return apr_psprintf(req->pool, "%s/%s", dir, escaped);
 }
 
-static void mag_store_deleg_creds(request_rec *req,
-                                  char *dir, const char *gss_name,
+char *mag_tmpl_to_ccache_name(request_rec *req, char *dir, char *tmpl)
+{
+    char * ccname;
+    int ccachefd;
+
+    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s", tmpl);
+    ccname = apr_psprintf(req->pool, "%s/%s", dir, tmpl);
+    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s", ccname);
+
+    ccachefd = mkstemp(ccname);
+    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s", ccname);
+
+    if (ccachefd == -1) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
+                      "creating unique ccache file failed");
+        return NULL;
+    }
+    close(ccachefd);
+    return ccname;
+}
+
+static void mag_store_deleg_creds(request_rec *req, const char *ccname,
                                   gss_cred_id_t delegated_cred)
 {
     gss_key_value_element_desc element;
     gss_key_value_set_desc store;
-    char *ccname;
     uint32_t maj, min;
     element.key = "ccache";
     store.elements = &element;
     store.count = 1;
 
-    ccname = mag_gss_name_to_ccache_name(req, dir, gss_name);
     element.value = apr_psprintf(req->pool, "FILE:%s", ccname);
 
     maj = gss_store_cred_into(&min, delegated_cred, GSS_C_INITIATE,
@@ -899,9 +917,24 @@ complete:
 
 #ifdef HAVE_CRED_STORE
     if (cfg->deleg_ccache_dir && delegated_cred != GSS_C_NO_CREDENTIAL) {
-        mag_store_deleg_creds(req, cfg->deleg_ccache_dir, mc->gss_name,
-                              delegated_cred);
-        mc->delegated = true;
+        mc->ccname = 0;
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "requester: %s", mc->gss_name);
+        if (cfg->deleg_ccache_tmpl) {
+            mc->ccname = mag_tmpl_to_ccache_name(req, cfg->deleg_ccache_dir,
+                                                 cfg->deleg_ccache_tmpl);
+
+        } else {
+            mc->ccname = mag_gss_name_to_ccache_name(req,
+                                                     cfg->deleg_ccache_dir,
+                                                     mc->gss_name);
+        }
+
+        if (mc->ccname) {
+            mag_store_deleg_creds(req, mc->ccname, delegated_cred);
+            mc->delegated = true;
+        } else {
+            goto done;
+        }
     }
 #endif
 
@@ -1028,6 +1061,17 @@ static const char *mag_use_s4u2p(cmd_parms *parms, void *mconfig, int on)
 
     return NULL;
 }
+
+static const char *mag_deleg_ccache_tmpl(cmd_parms *parms, void *mconfig,
+                                         const char *value)
+{
+    struct mag_config *cfg = (struct mag_config *)mconfig;
+
+    cfg->deleg_ccache_tmpl = apr_pstrdup(parms->pool, value);
+
+    return NULL;
+}
+
 #endif
 
 static const char *mag_sess_key(cmd_parms *parms, void *mconfig, const char *w)
@@ -1352,6 +1396,9 @@ static const command_rec mag_commands[] = {
                     "Credential Store"),
     AP_INIT_RAW_ARGS("GssapiDelegCcacheDir", mag_deleg_ccache_dir, NULL,
                      OR_AUTHCFG, "Directory to store delegated credentials"),
+    AP_INIT_RAW_ARGS("GssapiDelegCcacheTemplate", mag_deleg_ccache_tmpl, NULL,
+                     OR_AUTHCFG, "Delegated ccache name template"),
+
 #endif
 #ifdef HAVE_GSS_ACQUIRE_CRED_WITH_PASSWORD
     AP_INIT_FLAG("GssapiBasicAuth", mag_use_basic_auth, NULL, OR_AUTHCFG,
diff --git a/src/mod_auth_gssapi.h b/src/mod_auth_gssapi.h
index ea563ec..86fd264 100644
--- a/src/mod_auth_gssapi.h
+++ b/src/mod_auth_gssapi.h
@@ -2,7 +2,9 @@
 
 #include <stdbool.h>
 #include <stdint.h>
+#include <stdlib.h>
 #include <time.h>
+#include <unistd.h>
 
 #define APR_WANT_STRFUNC
 #include "apr_want.h"
@@ -68,6 +70,7 @@ struct mag_config {
     bool use_s4u2proxy;
     char *deleg_ccache_dir;
     gss_key_value_set_desc *cred_store;
+    char *deleg_ccache_tmpl;
 #endif
     struct seal_key *mag_skey;
 
@@ -112,12 +115,13 @@ struct mag_conn {
     bool is_preserved;
     int na_count;
     struct mag_attr *name_attributes;
+    const char *ccname;
 };
 
 #define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
 
 struct mag_conn *mag_new_conn_ctx(apr_pool_t *pool);
 const char *mag_str_auth_type(int auth_type);
-char *mag_gss_name_to_ccache_name(request_rec *req,
-                                  char *dir, const char *gss_name);
+char *mag_gss_name_to_ccache_name(request_rec *req, char *dir,
+                                  const char *gss_name);
 char *mag_error(request_rec *req, const char *msg, uint32_t maj, uint32_t min);
diff --git a/src/sessions.c b/src/sessions.c
index c31a51a..cd54764 100644
--- a/src/sessions.c
+++ b/src/sessions.c
@@ -179,6 +179,12 @@ void mag_check_session(struct mag_req_cfg *cfg, struct mag_conn **conn)
     memcpy(mc->basic_hash.value,
            gsessdata->basichash.buf, gsessdata->basichash.size);
 
+    /* ccname */
+    mc->ccname = apr_pstrndup(mc->pool,
+                              (char *)gsessdata->ccname.buf,
+                              gsessdata->ccname.size);
+    if (!mc->ccname) goto done;
+
     /* OK we have a valid token */
     mc->established = true;
 
@@ -224,6 +230,8 @@ void mag_attempt_session(struct mag_req_cfg *cfg, struct mag_conn *mc)
                              (const char *)mc->basic_hash.value,
                              mc->basic_hash.length) != 0)
         goto done;
+    if (OCTET_STRING_fromString(&gsessdata.ccname, mc->ccname) != 0)
+        goto done;
     ret = encode_GSSSessionData(req->pool, &gsessdata,
                                 &plainbuf.value, &plainbuf.length);
     if (ret == false) {
-- 
2.5.0

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to