From 7a83e39d0fb5e13699648d19be6832ac6118b279 Mon Sep 17 00:00:00 2001 From: Aimoto Norihito Date: Thu, 4 Apr 2024 17:20:31 +0900 Subject: [PATCH] Internal Server Error when IdP-Initiated Single Logout(#140) Stores the SessionIndex in the cache, Validate SessionIndex on single logout. --- auth_mellon.h | 18 +++- auth_mellon_cache.c | 212 +++++++++++++++++++++++++++++++++----- auth_mellon_diagnostics.c | 6 ++ auth_mellon_handler.c | 89 ++++++++++++---- auth_mellon_session.c | 150 +++++++++++++++++++++++++-- 5 files changed, 418 insertions(+), 57 deletions(-) diff --git a/auth_mellon.h b/auth_mellon.h index a90db97..d739a84 100644 --- a/auth_mellon.h +++ b/auth_mellon.h @@ -390,7 +390,8 @@ typedef struct am_cache_entry_t { typedef enum { AM_CACHE_SESSION, AM_CACHE_NAMEID, - AM_CACHE_ASSERTIONID + AM_CACHE_ASSERTIONID, + AM_CACHE_SESSIONINDEX } am_cache_key_t; /* Type for configuring environment variable names */ @@ -472,6 +473,8 @@ am_cache_entry_t *am_cache_new(request_rec *r, const char *key, const char *cookie_token); void am_cache_unlock(request_rec *r, am_cache_entry_t *entry); +bool am_cache_mutex_lock(request_rec *r); +void am_cache_mutex_unlock(request_rec *r); void am_cache_update_expires(request_rec *r, am_cache_entry_t *t, apr_time_t expires); void am_cache_update_idle_timeout(request_rec *r, am_cache_entry_t *t, int session_idle_timeout); @@ -482,6 +485,7 @@ int am_cache_env_append(am_cache_entry_t *session, const char *am_cache_env_fetch_first(am_cache_entry_t *t, const char *var); void am_cache_delete(request_rec *r, am_cache_entry_t *session); +void am_cache_delete_sessions(request_rec *r, apr_array_header_t *sessions); int am_cache_set_lasso_state(am_cache_entry_t *session, const char *lasso_identity, @@ -489,17 +493,25 @@ int am_cache_set_lasso_state(am_cache_entry_t *session, const char *lasso_saml_response); const char *am_cache_get_lasso_identity(am_cache_entry_t *session); const char *am_cache_get_lasso_session(am_cache_entry_t *session); - +am_cache_entry_t *am_cache_get_session(request_rec *r, + am_cache_key_t type, + const char *key); +apr_array_header_t *am_cache_get_sessions(request_rec *r, + am_cache_key_t type, + const char *key); am_cache_entry_t *am_get_request_session(request_rec *r); am_cache_entry_t *am_get_request_session_by_nameid(request_rec *r, char *nameid); am_cache_entry_t *am_get_request_session_by_assertionid(request_rec *r, char *assertionid); +apr_array_header_t *am_get_request_sessions_by_sessionindex(request_rec *r, GList *sessionindex); +apr_array_header_t *am_get_request_sessions_by_nameid(request_rec *r, char *nameid); am_cache_entry_t *am_new_request_session(request_rec *r); void am_release_request_session(request_rec *r, am_cache_entry_t *session); void am_delete_request_session(request_rec *r, am_cache_entry_t *session); - +void am_delete_request_sessions(request_rec *r, apr_array_header_t *sessions); +bool am_validate_session_cookie_token(request_rec *r, am_cache_entry_t *session); char *am_reconstruct_url(request_rec *r); int am_validate_redirect_url(request_rec *r, const char *url); diff --git a/auth_mellon_cache.c b/auth_mellon_cache.c index 61a4d75..4e1a66d 100644 --- a/auth_mellon_cache.c +++ b/auth_mellon_cache.c @@ -80,12 +80,38 @@ void am_cache_init(am_mod_cfg_rec *mod_cfg) am_cache_entry_t *am_cache_lock(request_rec *r, am_cache_key_t type, const char *key) +{ + /* Lock the table. */ + if (!am_cache_mutex_lock(r)) { + return NULL; + } + + am_cache_entry_t *e = am_cache_get_session(r, type, key); + if (e == NULL) { + am_cache_mutex_unlock(r); + } + return e; +} + +/* This function locates a session entry. + * The table must be locked before calling this function. + * + * Parameters: + * request_rec *r The request we are processing. + * am_cache_key_t type AM_CACHE_SESSION, AM_CACHE_NAMEID or AM_CACHE_ASSERTIONID + * or AM_CACHE_SESSIONINDEX + * const char *key The session key or user + * + * Returns: + * The session entry on success or NULL on failure. + */ +am_cache_entry_t *am_cache_get_session(request_rec *r, + am_cache_key_t type, + const char *key) { am_mod_cfg_rec *mod_cfg; void *table; apr_size_t i; - int rv; - char buffer[512]; /* Check if we have a valid session key. We abort if we don't. */ @@ -99,6 +125,7 @@ am_cache_entry_t *am_cache_lock(request_rec *r, break; case AM_CACHE_NAMEID: case AM_CACHE_ASSERTIONID: + case AM_CACHE_SESSIONINDEX: break; default: return NULL; @@ -106,16 +133,103 @@ am_cache_entry_t *am_cache_lock(request_rec *r, } mod_cfg = am_get_mod_cfg(r->server); + table = apr_shm_baseaddr_get(mod_cfg->cache); - /* Lock the table. */ - if((rv = apr_global_mutex_lock(mod_cfg->lock)) != APR_SUCCESS) { - AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r, - "apr_global_mutex_lock() failed [%d]: %s", - rv, apr_strerror(rv, buffer, sizeof(buffer))); + for(i = 0; i < mod_cfg->init_cache_size; i++) { + am_cache_entry_t *e = am_cache_entry_ptr(mod_cfg, table, i); + const char *tablekey; + + if (e->key[0] == '\0') { + /* This entry is empty. Skip it. */ + continue; + } + + switch (type) { + case AM_CACHE_SESSION: + tablekey = e->key; + break; + case AM_CACHE_NAMEID: + /* tablekey may be NULL */ + tablekey = am_cache_env_fetch_first(e, "NAME_ID"); + break; + case AM_CACHE_ASSERTIONID: + /* tablekey may be NULL */ + tablekey = am_cache_env_fetch_first(e, "ASSERTION_ID"); + break; + case AM_CACHE_SESSIONINDEX: + /* tablekey may be NULL */ + tablekey = am_cache_env_fetch_first(e, "SESSIONINDEX"); + break; + default: + tablekey = NULL; + break; + } + + if (tablekey == NULL) + continue; + + if(strcmp(tablekey, key) == 0) { + apr_time_t now = apr_time_now(); + /* We found the entry. */ + if ((e->expires > now) && + ((e->idle_timeout == -1) || + (e->idle_timeout > now))) { + /* And it hasn't expired. */ + return e; + } + else { + am_diag_log_cache_entry(r, 0, e, + "found expired session, now %s\n", + am_diag_time_t_to_8601(r, now)); + } + } + } + + + return NULL; +} + +/* This function locates a session entries. + * The table must be locked before calling this function. + * + * Parameters: + * request_rec *r The request we are processing. + * am_cache_key_t type AM_CACHE_SESSION, AM_CACHE_NAMEID or AM_CACHE_ASSERTIONID + * or AM_CACHE_SESSIONINDEX + * const char *key The session key or user + * + * Returns: + * The session entries on success or NULL on failure. + */ +apr_array_header_t *am_cache_get_sessions(request_rec *r, + am_cache_key_t type, + const char *key) +{ + am_mod_cfg_rec *mod_cfg; + void *table; + apr_size_t i; + apr_array_header_t *sessions = apr_array_make(r->pool, 0, sizeof(am_cache_entry_t *)); + + /* Check if we have a valid session key. We abort if we don't. */ + if (key == NULL) return NULL; + + switch (type) { + case AM_CACHE_SESSION: + if (strlen(key) != AM_ID_LENGTH) + return NULL; + break; + case AM_CACHE_NAMEID: + case AM_CACHE_ASSERTIONID: + case AM_CACHE_SESSIONINDEX: + break; + default: + return NULL; + break; } + mod_cfg = am_get_mod_cfg(r->server); table = apr_shm_baseaddr_get(mod_cfg->cache); @@ -140,6 +254,10 @@ am_cache_entry_t *am_cache_lock(request_rec *r, /* tablekey may be NULL */ tablekey = am_cache_env_fetch_first(e, "ASSERTION_ID"); break; + case AM_CACHE_SESSIONINDEX: + /* tablekey may be NULL */ + tablekey = am_cache_env_fetch_first(e, "SESSIONINDEX"); + break; default: tablekey = NULL; break; @@ -155,7 +273,7 @@ am_cache_entry_t *am_cache_lock(request_rec *r, ((e->idle_timeout == -1) || (e->idle_timeout > now))) { /* And it hasn't expired. */ - return e; + APR_ARRAY_PUSH(sessions, am_cache_entry_t *) = e; } else { am_diag_log_cache_entry(r, 0, e, @@ -164,15 +282,10 @@ am_cache_entry_t *am_cache_lock(request_rec *r, } } } - - - /* We didn't find a entry matching the key. Unlock the table and - * return NULL; - */ - apr_global_mutex_unlock(mod_cfg->lock); - return NULL; + return sessions; } + static inline bool am_cache_entry_slot_is_empty(am_cache_storage_t *slot) { return (slot->ptr == 0); @@ -304,7 +417,6 @@ am_cache_entry_t *am_cache_new(request_rec *r, int i; apr_time_t age; int rv; - char buffer[512]; /* Check if we have a valid session key. We abort if we don't. */ if(key == NULL || strlen(key) != AM_ID_LENGTH) { @@ -316,10 +428,7 @@ am_cache_entry_t *am_cache_new(request_rec *r, /* Lock the table. */ - if((rv = apr_global_mutex_lock(mod_cfg->lock)) != APR_SUCCESS) { - AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r, - "apr_global_mutex_lock() failed [%d]: %s", - rv, apr_strerror(rv, buffer, sizeof(buffer))); + if (!am_cache_mutex_lock(r)) { return NULL; } @@ -415,7 +524,7 @@ am_cache_entry_t *am_cache_new(request_rec *r, AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r, "Unable to store cookie token in new session."); t->key[0] = '\0'; /* Mark the entry as free. */ - apr_global_mutex_unlock(mod_cfg->lock); + am_cache_mutex_unlock(r); return NULL; } @@ -439,11 +548,45 @@ am_cache_entry_t *am_cache_new(request_rec *r, */ void am_cache_unlock(request_rec *r, am_cache_entry_t *entry) { - am_mod_cfg_rec *mod_cfg; - /* Update access time. */ entry->access = apr_time_now(); + am_cache_mutex_unlock(r); +} + +/* This function mutex lock + * + * Parameters: + * request_rec *r The request we are processing. + * + * Returns: + * true on success or false on failure. + */ +bool am_cache_mutex_lock(request_rec *r) +{ + am_mod_cfg_rec *mod_cfg = am_get_mod_cfg(r->server); + int rv; + char buffer[512]; + if((rv = apr_global_mutex_lock(mod_cfg->lock)) != APR_SUCCESS) { + AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r, + "apr_global_mutex_lock() failed [%d]: %s", + rv, apr_strerror(rv, buffer, sizeof(buffer))); + return false; + } + return true; +} + +/* This function mutext unlocks + * + * Parameters: + * request_rec *r The request we are processing. + * + * Returns: + * Nothing. + */ +void am_cache_mutex_unlock(request_rec *r) +{ + am_mod_cfg_rec *mod_cfg; mod_cfg = am_get_mod_cfg(r->server); apr_global_mutex_unlock(mod_cfg->lock); } @@ -758,6 +901,29 @@ void am_cache_delete(request_rec *r, am_cache_entry_t *cache) am_cache_unlock(r, cache); } +/* This function deletes the specified keys from the session store + * and releases the locks. + * Equivalent to performing am_cache_delete on multiple sessions. + * + * Parameters: + * request_rec *r The request we are processing. + * apr_array_header_t *sessions The entry we are deleting. + * + * Returns: + * Nothing. + */ +void am_cache_delete_sessions(request_rec *r, apr_array_header_t *sessions) +{ + am_cache_entry_t *cache; + int i; + for (i = 0; i < sessions->nelts; i++) { + cache = APR_ARRAY_IDX(sessions, i, am_cache_entry_t *); + am_diag_log_cache_entry(r, 0, cache, "delete session"); + cache->key[0] = '\0'; + cache->access = apr_time_now(); + } + am_cache_mutex_unlock(r); +} /* This function stores a lasso identity dump and a lasso session dump in * the given session object. diff --git a/auth_mellon_diagnostics.c b/auth_mellon_diagnostics.c index 896dc61..56650b3 100644 --- a/auth_mellon_diagnostics.c +++ b/auth_mellon_diagnostics.c @@ -813,6 +813,7 @@ am_diag_cache_key_type_str(am_cache_key_t key_type) case AM_CACHE_SESSION: return "session"; case AM_CACHE_NAMEID: return "name id"; case AM_CACHE_ASSERTIONID: return "assertion id"; + case AM_CACHE_SESSIONINDEX: return "SessionIndex"; default: return "unknown"; } } @@ -1111,6 +1112,7 @@ am_diag_log_cache_entry(request_rec *r, int level, am_cache_entry_t *entry, const char *name_id = NULL; const char *assertion_id = NULL; + const char *sessionindex = NULL; if (!AM_DIAG_ENABLED(diag_cfg)) return; if (!am_diag_initialize_req(r, diag_cfg, req_cfg)) return; @@ -1122,6 +1124,7 @@ am_diag_log_cache_entry(request_rec *r, int level, am_cache_entry_t *entry, if (entry) { name_id = am_cache_env_fetch_first(entry, "NAME_ID"); assertion_id = am_cache_env_fetch_first(entry, "ASSERTION_ID"); + sessionindex = am_cache_env_fetch_first(entry, "SESSIONINDEX"); apr_file_printf(diag_cfg->fd, "%skey: %s\n", @@ -1132,6 +1135,9 @@ am_diag_log_cache_entry(request_rec *r, int level, am_cache_entry_t *entry, apr_file_printf(diag_cfg->fd, "%sassertion_id: %s\n", indent(level+1), assertion_id); + apr_file_printf(diag_cfg->fd, + "%ssessionindex: %s\n", + indent(level+1), sessionindex); apr_file_printf(diag_cfg->fd, "%sexpires: %s\n", indent(level+1), diff --git a/auth_mellon_handler.c b/auth_mellon_handler.c index 99a013c..169e57f 100644 --- a/auth_mellon_handler.c +++ b/auth_mellon_handler.c @@ -757,8 +757,11 @@ static int am_handle_logout_request(request_rec *r, char *post_data) { gint res = 0, rc = HTTP_OK; - am_cache_entry_t *session = NULL; + am_cache_entry_t *session = NULL, *e = NULL; am_dir_cfg_rec *cfg = am_get_dir_cfg(r); + GList *sessionindex_list; + apr_array_header_t *cache_sessions = NULL, *logout_sessions = NULL; + int i; am_diag_printf(r, "enter function %s\n", __func__); @@ -795,25 +798,60 @@ static int am_handle_logout_request(request_rec *r, am_diag_printf(r, "%s name id %s\n", __func__, ((LassoSaml2NameID*)logout->parent.nameIdentifier)->content); - session = am_get_request_session_by_nameid(r, - ((LassoSaml2NameID*)logout->parent.nameIdentifier)->content); - if (session == NULL) { - AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r, - "Error processing logout request message." - " No session found for NameID %s", - ((LassoSaml2NameID*)logout->parent.nameIdentifier)->content); + LassoProfile *profile = &logout->parent; + char *req_nameid = (char *)((LassoSaml2NameID *)profile->nameIdentifier)->content; + sessionindex_list = lasso_samlp2_logout_request_get_session_indexes((LassoSamlp2LogoutRequest*)profile->request); + if (req_nameid) { + if (sessionindex_list) { + cache_sessions = am_get_request_sessions_by_sessionindex(r, sessionindex_list); + } else { + cache_sessions = am_get_request_sessions_by_nameid(r, req_nameid); + } + } else { + AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r, + "Error processing logout request message. Can't find NameID."); + rc = HTTP_BAD_REQUEST; + goto exit; } - am_diag_log_cache_entry(r, 0, session, "%s", __func__); - - if (session == NULL) { - AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r, - "Error processing logout request message." - " No session found."); + if (cache_sessions && cache_sessions->nelts != 0) { + if (sessionindex_list) { + const char *cache_nameid; + logout_sessions = apr_array_make(r->pool, 0, sizeof(am_cache_entry_t *)); + for (i = 0; i < cache_sessions->nelts; i++) { + e = APR_ARRAY_IDX(cache_sessions, i, am_cache_entry_t *); + cache_nameid = am_cache_env_fetch_first(e, "NAME_ID"); + if (cache_nameid == NULL) { + continue; + } + if (strcmp(req_nameid, cache_nameid) == 0) { + APR_ARRAY_PUSH(logout_sessions, am_cache_entry_t *) = e; + session = e; + } + } + } else { + /* no SessionIndex from IdP, all sessions logout */ + logout_sessions = cache_sessions; + session = APR_ARRAY_IDX(cache_sessions, 0, am_cache_entry_t *); + } + if (session == NULL) { + AM_LOG_RERROR(APLOG_MARK, APLOG_WARNING, 0, r, + "Error processing logout request message." + " Does not match the NameID of the session. [%s]", req_nameid); + } else { + for (i = 0; i < logout_sessions->nelts; i++) { + e = APR_ARRAY_IDX(logout_sessions, i, am_cache_entry_t *); + am_diag_log_cache_entry(r, 0, e, "%s", __func__); + } + /* Even if multiple sessions are subject to logout, only one of them is passed to lasso */ + am_restore_lasso_profile_state(r, &logout->parent, session); + } } else { - am_restore_lasso_profile_state(r, &logout->parent, session); + AM_LOG_RERROR(APLOG_MARK, APLOG_WARNING, 0, r, + "Error processing logout request message." + " No session found. [%s]", req_nameid); } /* Validate the logout message. Ignore missing signature. */ @@ -821,7 +859,7 @@ static int am_handle_logout_request(request_rec *r, if(res != 0 && res != LASSO_DS_ERROR_SIGNATURE_NOT_FOUND && res != LASSO_PROFILE_ERROR_SESSION_NOT_FOUND) { - AM_LOG_RERROR(APLOG_MARK, APLOG_WARNING, 0, r, + AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r, "Error validating logout request." " Lasso error: [%i] %s", res, lasso_strerror(res)); rc = HTTP_INTERNAL_SERVER_ERROR; @@ -831,10 +869,10 @@ static int am_handle_logout_request(request_rec *r, * caused by the IdP believing that we are logged in when we are not. */ - if (session != NULL && res != LASSO_PROFILE_ERROR_SESSION_NOT_FOUND) { + if (logout_sessions != NULL && res != LASSO_PROFILE_ERROR_SESSION_NOT_FOUND) { /* We found a matching session -- delete it. */ - am_delete_request_session(r, session); - session = NULL; + am_delete_request_sessions(r, logout_sessions); + cache_sessions = NULL; } /* Create response message. */ @@ -850,8 +888,8 @@ static int am_handle_logout_request(request_rec *r, rc = am_return_logout_response(r, &logout->parent, post_data); exit: - if (session != NULL) { - am_release_request_session(r, session); + if (cache_sessions != NULL) { + am_cache_mutex_unlock(r); } lasso_logout_destroy(logout); @@ -1828,6 +1866,15 @@ static int add_attributes(am_cache_entry_t *session, request_rec *r, return ret; } + /* Save session SessionIndex information. */ + if(assertion->AuthnStatement && + ((LassoSaml2AuthnStatement *)assertion->AuthnStatement->data)->SessionIndex) { + ret = am_cache_env_append(session, "SESSIONINDEX", ((LassoSaml2AuthnStatement *)assertion->AuthnStatement->data)->SessionIndex); + if(ret != OK) { + return ret; + } + } + /* Update expires timestamp of session. */ am_handle_session_expire(r, session, assertion); diff --git a/auth_mellon_session.c b/auth_mellon_session.c index af50de2..723828f 100644 --- a/auth_mellon_session.c +++ b/auth_mellon_session.c @@ -53,16 +53,7 @@ am_cache_entry_t *am_lock_and_validate(request_rec *r, am_diag_log_cache_entry(r, 0, session, "Session Cache Entry"); } - const char *cookie_token_session = am_cache_entry_get_string( - session, &session->cookie_token); - const char *cookie_token_target = am_cookie_token(r); - if (strcmp(cookie_token_session, cookie_token_target)) { - AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r, - "Session cookie parameter mismatch. " - "Session created with {%s}, but current " - "request has {%s}.", - cookie_token_session, - cookie_token_target); + if (!am_validate_session_cookie_token(r, session)) { am_cache_unlock(r, session); return NULL; } @@ -123,6 +114,93 @@ am_cache_entry_t *am_get_request_session_by_assertionid(request_rec *r, char *as return am_lock_and_validate(r, AM_CACHE_ASSERTIONID, assertionid); } +/* This function gets the session associated with a user, using the SessionIndex + * + * Parameters: + * request_rec *r The request we received from the user. + * GList *sessionindex The SessionIndexes + * + * Returns: + * apr_array_header_t containing matched am_cache_entry_t + * NULL if we don't have a session yet. + */ +apr_array_header_t *am_get_request_sessions_by_sessionindex(request_rec *r, GList *sessionindex) +{ + apr_array_header_t *sessions = apr_array_make(r->pool, 0, sizeof(am_cache_entry_t *)); + am_cache_entry_t *session; + GList *i_glist; + + /* Lock the table. */ + if (!am_cache_mutex_lock(r)) { + return NULL; + } + + for (i_glist = sessionindex; i_glist != NULL; i_glist = g_list_next(i_glist)) { + am_diag_printf(r, "searching for session with key %s (%s) ... ", + (char *)i_glist->data, am_diag_cache_key_type_str(AM_CACHE_SESSIONINDEX)); + + session = am_cache_get_session(r, AM_CACHE_SESSIONINDEX, (char *)i_glist->data); + if (session == NULL) { + am_diag_printf(r, "not found\n"); + } else { + am_diag_printf(r, "found.\n"); + am_diag_log_cache_entry(r, 0, session, "Session Cache Entry"); + if (am_validate_session_cookie_token(r, session)) { + APR_ARRAY_PUSH(sessions, am_cache_entry_t *) = session; + } + } + } + return sessions; +} + + +/* This function gets the session associated with a user, using a NameID + * + * Parameters: + * request_rec *r The request we received from the user. + * char *nameid The NameID + * + * Returns: + * apr_array_header_t containing matched am_cache_entry_t + * NULL if we don't have a session yet. + */ +apr_array_header_t *am_get_request_sessions_by_nameid(request_rec *r, char *nameid) +{ + apr_array_header_t *cache_sessions; + apr_array_header_t *sessions; + am_cache_entry_t *session; + int i = 0; + + if (nameid == NULL) { + return NULL; + } + + /* Lock the table. */ + if (!am_cache_mutex_lock(r)) { + return NULL; + } + + am_diag_printf(r, "searching for sessions with key %s (%s) ... ", + nameid, am_diag_cache_key_type_str(AM_CACHE_NAMEID)); + + cache_sessions = am_cache_get_sessions(r, AM_CACHE_NAMEID, nameid); + if (cache_sessions == NULL || cache_sessions->nelts == 0) { + am_diag_printf(r, "not found\n"); + am_cache_mutex_unlock(r); + return NULL; + } + am_diag_printf(r, "found. session entry size:[%d]\n", cache_sessions->nelts); + + sessions = apr_array_make(r->pool, 0, sizeof(am_cache_entry_t *)); + for (i = 0; i < cache_sessions->nelts; i++) { + session = APR_ARRAY_IDX(cache_sessions, i, am_cache_entry_t *); + if (session && am_validate_session_cookie_token(r, session)) { + APR_ARRAY_PUSH(sessions, am_cache_entry_t *) = session; + } + } + return sessions; +} + /* This function creates a new session. * * Parameters: @@ -195,3 +273,55 @@ void am_delete_request_session(request_rec *r, am_cache_entry_t *session) /* Delete session from the session store. */ am_cache_delete(r, session); } + + +/* This function releases and deletes multiple sessions. + * + * Parameters: + * request_rec *r The request we are processing. + * apr_array_header_t *sessions List of sessions we are deleting. + * + * Returns: + * Nothing. + */ +void am_delete_request_sessions(request_rec *r, apr_array_header_t *sessions) +{ + /* Delete the cookie. */ + am_cookie_delete(r); + + if(sessions == NULL || sessions->nelts == 0) { + return; + } + + /* Delete sessions from the session store. */ + am_cache_delete_sessions(r, sessions); +} + + +/* this function validate the cookie token in the session entry + * + * Parameters: + * request_rec *r The request we are processing. + * am_cache_entry_t *session The session we are validating. + * + * Returns: + * true on success or false on failure. + */ +bool am_validate_session_cookie_token(request_rec *r, am_cache_entry_t *session) +{ + if (session == NULL) { + return false; + } + const char *cookie_token_session = am_cache_entry_get_string( + session, &session->cookie_token); + const char *cookie_token_target = am_cookie_token(r); + if (strcmp(cookie_token_session, cookie_token_target)) { + AM_LOG_RERROR(APLOG_MARK, APLOG_ERR, 0, r, + "Session cookie parameter mismatch. " + "Session created with {%s}, but current " + "request has {%s}.", + cookie_token_session, cookie_token_target); + return false; + } + return true; +}