Add support for IdP initiated SOAP single logout.
git-svn-id: https://modmellon.googlecode.com/svn/trunk@49 a716ebb1-153a-0410-b759-cfb97c6a1b53
This commit is contained in:
parent
4bbb403f59
commit
1803631503
|
@ -189,7 +189,10 @@ typedef struct am_cache_entry_t {
|
|||
am_cache_env_t env[AM_CACHE_ENVSIZE];
|
||||
} am_cache_entry_t;
|
||||
|
||||
|
||||
typedef enum {
|
||||
AM_CACHE_SESSION,
|
||||
AM_CACHE_NAMEID
|
||||
} am_cache_key_t;
|
||||
|
||||
extern const command_rec auth_mellon_commands[];
|
||||
|
||||
|
@ -203,7 +206,8 @@ void am_cookie_set(request_rec *r, const char *id);
|
|||
void am_cookie_delete(request_rec *r);
|
||||
|
||||
|
||||
am_cache_entry_t *am_cache_lock(server_rec *s, const char *key);
|
||||
am_cache_entry_t *am_cache_lock(server_rec *s,
|
||||
am_cache_key_t type, const char *key);
|
||||
am_cache_entry_t *am_cache_new(server_rec *s, const char *key);
|
||||
void am_cache_unlock(server_rec *s, am_cache_entry_t *entry);
|
||||
|
||||
|
@ -212,6 +216,8 @@ void am_cache_update_expires(am_cache_entry_t *t, apr_time_t expires);
|
|||
void am_cache_env_populate(request_rec *r, am_cache_entry_t *session);
|
||||
int am_cache_env_append(am_cache_entry_t *session,
|
||||
const char *var, const char *val);
|
||||
const char *am_cache_env_fetch_first(am_cache_entry_t *t,
|
||||
const char *var);
|
||||
void am_cache_delete(server_rec *s, am_cache_entry_t *session);
|
||||
|
||||
int am_cache_set_lasso_state(am_cache_entry_t *session,
|
||||
|
@ -222,6 +228,8 @@ const char *am_cache_get_lasso_session(am_cache_entry_t *session);
|
|||
|
||||
|
||||
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_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);
|
||||
|
|
|
@ -28,12 +28,15 @@
|
|||
*
|
||||
* Parameters:
|
||||
* server_rec *s The current server.
|
||||
* const char *key The session key.
|
||||
* const char *key The session key or user
|
||||
* am_cache_key_t type AM_CACHE_SESSION or AM_CACHE_NAMEID
|
||||
*
|
||||
* Returns:
|
||||
* The session entry on success or NULL on failure.
|
||||
*/
|
||||
am_cache_entry_t *am_cache_lock(server_rec *s, const char *key)
|
||||
am_cache_entry_t *am_cache_lock(server_rec *s,
|
||||
am_cache_key_t type,
|
||||
const char *key)
|
||||
{
|
||||
am_mod_cfg_rec *mod_cfg;
|
||||
am_cache_entry_t *table;
|
||||
|
@ -43,10 +46,22 @@ am_cache_entry_t *am_cache_lock(server_rec *s, const char *key)
|
|||
|
||||
|
||||
/* Check if we have a valid session key. We abort if we don't. */
|
||||
if(key == NULL || strlen(key) != AM_SESSION_ID_LENGTH) {
|
||||
if (key == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case AM_CACHE_SESSION:
|
||||
if (strlen(key) != AM_SESSION_ID_LENGTH)
|
||||
return NULL;
|
||||
break;
|
||||
case AM_CACHE_NAMEID:
|
||||
if (strlen(key) > AM_CACHE_MAX_LASSO_IDENTITY_SIZE)
|
||||
return NULL;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
mod_cfg = am_get_mod_cfg(s);
|
||||
|
||||
|
@ -63,7 +78,25 @@ am_cache_entry_t *am_cache_lock(server_rec *s, const char *key)
|
|||
|
||||
|
||||
for(i = 0; i < mod_cfg->init_cache_size; i++) {
|
||||
if(strcmp(table[i].key, key) == 0) {
|
||||
const char *tablekey;
|
||||
|
||||
switch (type) {
|
||||
case AM_CACHE_SESSION:
|
||||
tablekey = table[i].key;
|
||||
break;
|
||||
case AM_CACHE_NAMEID:
|
||||
/* tablekey may be NULL */
|
||||
tablekey = am_cache_env_fetch_first(&table[i], "NAME_ID");
|
||||
break;
|
||||
default:
|
||||
tablekey = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tablekey == NULL)
|
||||
continue;
|
||||
|
||||
if(strcmp(tablekey, key) == 0) {
|
||||
/* We found the entry. */
|
||||
if(table[i].expires > apr_time_now()) {
|
||||
/* And it hasn't expired. */
|
||||
|
@ -113,7 +146,7 @@ am_cache_entry_t *am_cache_new(server_rec *s, const char *key)
|
|||
|
||||
|
||||
/* First we try to find another session with the given key. */
|
||||
t = am_cache_lock(s, key);
|
||||
t = am_cache_lock(s, AM_CACHE_SESSION, key);
|
||||
|
||||
|
||||
if(t == NULL) {
|
||||
|
@ -288,6 +321,29 @@ int am_cache_env_append(am_cache_entry_t *t,
|
|||
return OK;
|
||||
}
|
||||
|
||||
/* This function fetches a value from a session.
|
||||
* If multiple values are available, the first one is returned.
|
||||
*
|
||||
* Parameters:
|
||||
* am_cache_entry_t *t The current session.
|
||||
* const char *var The name of the value to be stored.
|
||||
*
|
||||
* Returns:
|
||||
* The first value, NULL if it does not exist.
|
||||
*/
|
||||
const char *am_cache_env_fetch_first(am_cache_entry_t *t,
|
||||
const char *var)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; t->size; i++) {
|
||||
if (strcmp(t->env[i].varname, var) == 0)
|
||||
return t->env[i].value;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* This function populates the subprocess environment with data received
|
||||
* from the IdP.
|
||||
|
|
|
@ -112,6 +112,9 @@ static char *am_generate_metadata(apr_pool_t *p, request_rec *r)
|
|||
"WantAssertionsSigned=\"true\" "
|
||||
"protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">"
|
||||
"%s"
|
||||
"<SingleLogoutService "
|
||||
"Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:SOAP\" "
|
||||
"Location=\"%slogout\" />"
|
||||
"<SingleLogoutService "
|
||||
"Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect\" "
|
||||
"Location=\"%slogout\" />"
|
||||
|
@ -128,7 +131,7 @@ static char *am_generate_metadata(apr_pool_t *p, request_rec *r)
|
|||
"Location=\"%spostResponse\" />"
|
||||
"</SPSSODescriptor>"
|
||||
"</EntityDescriptor>",
|
||||
url, cert, url, url, url);
|
||||
url, cert, url, url, url, url);
|
||||
}
|
||||
#endif /* HAVE_lasso_server_new_from_buffers */
|
||||
|
||||
|
@ -532,19 +535,20 @@ static int am_restore_lasso_profile_state(request_rec *r,
|
|||
*
|
||||
* Parameters:
|
||||
* request_rec *r The logout request.
|
||||
* LassoLogout *logout A LassoLogout object initiatet with
|
||||
* LassoLogout *logout A LassoLogout object initiated with
|
||||
* the current session.
|
||||
*
|
||||
* Returns:
|
||||
* OK on success, or an error if any of the steps fail.
|
||||
*/
|
||||
static int am_handle_logout_request(request_rec *r, LassoLogout *logout)
|
||||
static int am_handle_logout_request(request_rec *r,
|
||||
LassoLogout *logout, char *msg)
|
||||
{
|
||||
gint res;
|
||||
am_cache_entry_t *session;
|
||||
|
||||
/* Process the logout message. Ignore missing signature. */
|
||||
res = lasso_logout_process_request_msg(logout, r->args);
|
||||
res = lasso_logout_process_request_msg(logout, msg);
|
||||
if(res != 0 && res != LASSO_DS_ERROR_SIGNATURE_NOT_FOUND) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
"Error processing logout request message."
|
||||
|
@ -556,7 +560,9 @@ static int am_handle_logout_request(request_rec *r, LassoLogout *logout)
|
|||
|
||||
/* Validate the logout message. Ignore missing signature. */
|
||||
res = lasso_logout_validate_request(logout);
|
||||
if(res != 0 && res != LASSO_DS_ERROR_SIGNATURE_NOT_FOUND) {
|
||||
if(res != 0 &&
|
||||
res != LASSO_DS_ERROR_SIGNATURE_NOT_FOUND &&
|
||||
res != LASSO_PROFILE_ERROR_SESSION_NOT_FOUND) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
|
||||
"Error validating logout request."
|
||||
" Lasso error: [%i] %s", res, lasso_strerror(res));
|
||||
|
@ -566,12 +572,23 @@ static int am_handle_logout_request(request_rec *r, LassoLogout *logout)
|
|||
}
|
||||
|
||||
|
||||
/* Delete the session. */
|
||||
/* Search session using cookie */
|
||||
session = am_get_request_session(r);
|
||||
if(session != NULL) {
|
||||
am_delete_request_session(r, session);
|
||||
|
||||
/* If no session found, search by NameID, for IdP initiated SOAP SLO */
|
||||
if (session == NULL) {
|
||||
LassoSaml2NameID *nameid;
|
||||
|
||||
nameid = LASSO_SAML2_NAME_ID(LASSO_PROFILE(logout)->nameIdentifier);
|
||||
|
||||
if (nameid != NULL)
|
||||
session = am_get_request_session_by_nameid(r, nameid->content);
|
||||
}
|
||||
|
||||
/* Delete the session. */
|
||||
if (session != NULL)
|
||||
am_delete_request_session(r, session);
|
||||
|
||||
|
||||
/* Create response message. */
|
||||
res = lasso_logout_build_response_msg(logout);
|
||||
|
@ -824,21 +841,40 @@ static int am_handle_logout(request_rec *r)
|
|||
/* Check which type of request to the logout handler this is.
|
||||
* We have three types:
|
||||
* - logout requests: The IdP sends a logout request to this service.
|
||||
* it can be either through HTTP-Redirect or SOAP.
|
||||
* - logout responses: We have sent a logout request to the IdP, and
|
||||
* are receiving a response.
|
||||
* - We want to initiate a logout request.
|
||||
*/
|
||||
if(am_extract_query_parameter(r->pool, r->args, "SAMLRequest") != NULL) {
|
||||
|
||||
/* First check for IdP-initiated SOAP logout request */
|
||||
if ((r->args == NULL) && (r->method_number == M_POST)) {
|
||||
int rc;
|
||||
char *post_data;
|
||||
|
||||
rc = am_read_post_data(r, &post_data, NULL);
|
||||
if (rc != OK) {
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
|
||||
"Error reading POST data.");
|
||||
return HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
return am_handle_logout_request(r, logout, post_data);
|
||||
|
||||
} else if(am_extract_query_parameter(r->pool, r->args,
|
||||
"SAMLRequest") != NULL) {
|
||||
/* SAMLRequest - logout request from the IdP. */
|
||||
return am_handle_logout_request(r, logout);
|
||||
} else if(am_extract_query_parameter(r->pool, r->args, "SAMLResponse")
|
||||
!= NULL) {
|
||||
return am_handle_logout_request(r, logout, r->args);
|
||||
|
||||
} else if(am_extract_query_parameter(r->pool, r->args,
|
||||
"SAMLResponse") != NULL) {
|
||||
/* SAMLResponse - logout response from the IdP. */
|
||||
return am_handle_logout_response(r, logout);
|
||||
} else if(am_extract_query_parameter(r->pool, r->args, "ReturnTo")
|
||||
!= NULL) {
|
||||
|
||||
} else if(am_extract_query_parameter(r->pool, r->args,
|
||||
"ReturnTo") != NULL) {
|
||||
/* RedirectTo - SP initiated logout. */
|
||||
return am_init_logout_request(r, logout);
|
||||
|
||||
} else {
|
||||
/* Unknown request to the logout handler. */
|
||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "auth_mellon.h"
|
||||
|
||||
|
||||
/* This function gets the session associated with a user.
|
||||
/* This function gets the session associated with a user, using a cookie
|
||||
*
|
||||
* Parameters:
|
||||
* request_rec *r The request we received from the user.
|
||||
|
@ -42,9 +42,23 @@ am_cache_entry_t *am_get_request_session(request_rec *r)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return am_cache_lock(r->server, session_id);
|
||||
return am_cache_lock(r->server, AM_CACHE_SESSION, session_id);
|
||||
}
|
||||
|
||||
/* 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:
|
||||
* The session associated with the user who places the request, or
|
||||
* NULL if we don't have a session yet.
|
||||
*/
|
||||
am_cache_entry_t *am_get_request_session_by_nameid(request_rec *r, char *nameid)
|
||||
{
|
||||
return am_cache_lock(r->server, AM_CACHE_NAMEID, nameid);
|
||||
}
|
||||
|
||||
/* This function creates a new session.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue