summaryrefslogtreecommitdiffstats
path: root/src/sessions.c
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2014-04-21 16:36:56 -0400
committerSimo Sorce <simo@redhat.com>2014-07-10 06:47:18 -0400
commit63dbb99337d0423253cb1ead0dcc3da54af5d13e (patch)
tree84bdcdb5f13f03dc41e0d19576eab248cf63d5cd /src/sessions.c
parent342cea568dc94ed0d35dca27a90fc704d0424da1 (diff)
downloadmod_auth_gssapi-63dbb99337d0423253cb1ead0dcc3da54af5d13e.tar.gz
mod_auth_gssapi-63dbb99337d0423253cb1ead0dcc3da54af5d13e.tar.xz
mod_auth_gssapi-63dbb99337d0423253cb1ead0dcc3da54af5d13e.zip
Add mod_session support
By setting GssapiUseSessions we enable the module to store a bearer token with the user and gss names in the client, this way we can allow clients to perform authentication once but then remain authenticaed for the duration of the session or until the original credentials expire. The Secure cookie used to store the token is encrypted using a randomly generated AES key at process startup. This means multiple apache servers will not be able to use the same cookie, however the client will reauth transparently if the cookie cannot be read.
Diffstat (limited to 'src/sessions.c')
-rw-r--r--src/sessions.c187
1 files changed, 187 insertions, 0 deletions
diff --git a/src/sessions.c b/src/sessions.c
new file mode 100644
index 0000000..766ca66
--- /dev/null
+++ b/src/sessions.c
@@ -0,0 +1,187 @@
+/* Copyright (C) 2014 mod_auth_gssapi authors - See COPYING for (C) terms */
+
+#include "mod_auth_gssapi.h"
+
+static APR_OPTIONAL_FN_TYPE(ap_session_load) *mag_sess_load_fn = NULL;
+static APR_OPTIONAL_FN_TYPE(ap_session_get) *mag_sess_get_fn = NULL;
+static APR_OPTIONAL_FN_TYPE(ap_session_set) *mag_sess_set_fn = NULL;
+
+void mag_post_config_session(void)
+{
+ mag_sess_load_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_load);
+ mag_sess_get_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_get);
+ mag_sess_set_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_set);
+}
+
+static apr_status_t mag_session_load(request_rec *req, session_rec **sess)
+{
+ if (mag_sess_load_fn) {
+ return mag_sess_load_fn(req, sess);
+ }
+ return DECLINED;
+}
+
+static apr_status_t mag_session_get(request_rec *req, session_rec *sess,
+ const char *key, const char **value)
+{
+ if (mag_sess_get_fn) {
+ return mag_sess_get_fn(req, sess, key, value);
+ }
+ return DECLINED;
+}
+
+static apr_status_t mag_session_set(request_rec *req, session_rec *sess,
+ const char *key, const char *value)
+{
+ if (mag_sess_set_fn) {
+ return mag_sess_set_fn(req, sess, key, value);
+ }
+ return DECLINED;
+}
+
+#define MAG_BEARER_KEY "MagBearerToken"
+
+void mag_check_session(request_rec *req,
+ struct mag_config *cfg, struct mag_conn **conn)
+{
+ struct mag_conn *mc;
+ apr_status_t rc;
+ session_rec *sess = NULL;
+ const char *sessval = NULL;
+ int declen;
+ struct databuf ctxbuf = { 0 };
+ struct databuf cipherbuf = { 0 };
+ char *next, *last;
+ time_t expiration;
+
+ rc = mag_session_load(req, &sess);
+ if (rc != OK || sess == NULL) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, req,
+ "Sessions not available, no cookies!");
+ return;
+ }
+
+ mc = *conn;
+ if (!mc) {
+ mc = apr_pcalloc(req->pool, sizeof(struct mag_conn));
+ if (!mc) return;
+
+ mc->parent = req->pool;
+ *conn = mc;
+ }
+
+ rc = mag_session_get(req, sess, MAG_BEARER_KEY, &sessval);
+ if (rc != OK) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
+ "Failed to get session data!");
+ return;
+ }
+ if (!sessval) {
+ /* no session established, just return */
+ return;
+ }
+
+ if (!cfg->mag_skey) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, req,
+ "Session key not available, no cookies!");
+ /* we do not have a key, just return */
+ return;
+ }
+
+ /* decode it */
+ declen = apr_base64_decode_len(sessval);
+ cipherbuf.value = apr_palloc(req->pool, declen);
+ if (!cipherbuf.value) return;
+ cipherbuf.length = (int)apr_base64_decode((char *)cipherbuf.value, sessval);
+
+ rc = UNSEAL_BUFFER(req->pool, cfg->mag_skey, &cipherbuf, &ctxbuf);
+ if (rc != OK) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
+ "Failed to unseal session data!");
+ return;
+ }
+
+ /* get time */
+ next = apr_strtok((char *)ctxbuf.value, ":", &last);
+ expiration = (time_t)apr_atoi64(next);
+ if (expiration < time(NULL)) {
+ /* credentials fully expired, return nothing */
+ return;
+ }
+
+ /* user name is next */
+ next = apr_strtok(NULL, ":", &last);
+ mc->user_name = apr_pstrdup(mc->parent, next);
+ if (!mc->user_name) return;
+
+ /* gssapi name (often a principal) is last.
+ * (because it may contain the separator as a valid char we
+ * just read last as is, without further tokenizing */
+ mc->gss_name = apr_pstrdup(mc->parent, last);
+ if (!mc->gss_name) return;
+
+ /* OK we have a valid token */
+ mc->established = true;
+}
+
+void mag_attempt_session(request_rec *req,
+ struct mag_config *cfg, struct mag_conn *mc)
+{
+ session_rec *sess = NULL;
+ char *sessval = NULL;
+ struct databuf plainbuf = { 0 };
+ struct databuf cipherbuf = { 0 };
+ struct databuf ctxbuf = { 0 };
+ apr_status_t rc;
+
+ /* we save the session only if the authentication is established */
+
+ if (!mc->established) return;
+ rc = mag_session_load(req, &sess);
+ if (rc != OK || sess == NULL) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, req,
+ "Sessions not available, can't send cookies!");
+ return;
+ }
+
+ if (!cfg->mag_skey) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, req,
+ "Session key not available, generating new one.");
+ rc = SEAL_KEY_CREATE(&cfg->mag_skey);
+ if (rc != OK) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
+ "Failed to create sealing key!");
+ return;
+ }
+ }
+
+ sessval = apr_psprintf(req->pool, "%ld:%s:%s",
+ (long)mc->expiration, mc->user_name, mc->gss_name);
+ if (!sessval) return;
+
+ plainbuf.length = strlen(sessval) + 1;
+ plainbuf.value = (unsigned char *)sessval;
+
+ rc = SEAL_BUFFER(req->pool, cfg->mag_skey, &plainbuf, &cipherbuf);
+ if (rc != OK) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
+ "Failed to seal session data!");
+ return;
+ }
+
+ ctxbuf.length = apr_base64_encode_len(cipherbuf.length);
+ ctxbuf.value = apr_pcalloc(req->pool, ctxbuf.length);
+ if (!ctxbuf.value) return;
+
+ ctxbuf.length = apr_base64_encode((char *)ctxbuf.value,
+ (char *)cipherbuf.value,
+ cipherbuf.length);
+
+ rc = mag_session_set(req, sess, MAG_BEARER_KEY, (char *)ctxbuf.value);
+ if (rc != OK) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
+ "Failed to set session data!");
+ return;
+ }
+}
+