diff --git a/mod_mellon2/README b/mod_mellon2/README index 78b5f3f..eb48deb 100644 --- a/mod_mellon2/README +++ b/mod_mellon2/README @@ -491,6 +491,15 @@ MellonPostCount 100 # The default is that it is "Off". # MellonPostReplay Off + # Page to redirect to if the IdP sends an error in response to + # the authentication request. + # + # Example: + # MellonNoSuccessErrorPage https://sp.example.org/login_failed.html + # + # The default is to not redirect, but rather send a + # 401 Unautorized error. + diff --git a/mod_mellon2/auth_mellon.h b/mod_mellon2/auth_mellon.h index f99cf6f..8347013 100644 --- a/mod_mellon2/auth_mellon.h +++ b/mod_mellon2/auth_mellon.h @@ -210,6 +210,9 @@ typedef struct am_dir_cfg_rec { /* No cookie error page. */ const char *no_cookie_error_page; + /* Authorization error page. */ + const char *no_success_error_page; + /* Login path for IdP initiated logins */ const char *login_path; @@ -276,6 +279,13 @@ typedef struct am_envattr_conf_t { extern const command_rec auth_mellon_commands[]; +typedef struct am_error_map_t { + int lasso_error; + int http_error; +} am_error_map_t; + +extern const am_error_map_t auth_mellon_errormap[]; + /* When using a value from a directory configuration structure, a special value is used * to state "inherit" from parent, when reading a value and the value is still inherit from, it * means that no value has ever been set for this directive, in this case, we use the default diff --git a/mod_mellon2/auth_mellon_config.c b/mod_mellon2/auth_mellon_config.c index 855330a..36f6b96 100644 --- a/mod_mellon2/auth_mellon_config.c +++ b/mod_mellon2/auth_mellon_config.c @@ -1046,6 +1046,15 @@ const command_rec auth_mellon_commands[] = { " ha disabled cookies." ), AP_INIT_TAKE1( + "MellonNoSuccessErrorPage", + ap_set_string_slot, + (void *)APR_OFFSETOF(am_dir_cfg_rec, no_success_error_page), + OR_AUTHCFG, + "Web page to display if the idp posts with a failed" + " authentication error. We will return a 401 Unauthorized error" + " if this is unset and the idp posts such assertion." + ), + AP_INIT_TAKE1( "MellonSPMetadataFile", am_set_filestring_slot, (void *)APR_OFFSETOF(am_dir_cfg_rec, sp_metadata_file), @@ -1205,6 +1214,13 @@ const command_rec auth_mellon_commands[] = { {NULL} }; +const am_error_map_t auth_mellon_errormap[] = { + { LASSO_PROFILE_ERROR_STATUS_NOT_SUCCESS, HTTP_UNAUTHORIZED }, +#ifdef LASSO_PROFILE_ERROR_REQUEST_DENIED + { LASSO_PROFILE_ERROR_REQUEST_DENIED, HTTP_UNAUTHORIZED }, +#endif + { 0, 0 } +}; /* Release a lasso_server object associated with this configuration. * @@ -1264,6 +1280,7 @@ void *auth_mellon_dir_config(apr_pool_t *p, char *d) dir->session_length = -1; /* -1 means use default. */ dir->no_cookie_error_page = NULL; + dir->no_success_error_page = NULL; dir->sp_metadata_file = NULL; dir->sp_private_key_file = NULL; @@ -1418,6 +1435,10 @@ void *auth_mellon_dir_merge(apr_pool_t *p, void *base, void *add) add_cfg->no_cookie_error_page : base_cfg->no_cookie_error_page); + new_cfg->no_success_error_page = (add_cfg->no_success_error_page != NULL ? + add_cfg->no_success_error_page : + base_cfg->no_success_error_page); + new_cfg->sp_metadata_file = (add_cfg->sp_metadata_file ? add_cfg->sp_metadata_file : diff --git a/mod_mellon2/auth_mellon_handler.c b/mod_mellon2/auth_mellon_handler.c index 1d42fd7..1de217a 100644 --- a/mod_mellon2/auth_mellon_handler.c +++ b/mod_mellon2/auth_mellon_handler.c @@ -1974,6 +1974,8 @@ static int am_handle_post_reply(request_rec *r) LassoServer *server; LassoLogin *login; char *relay_state; + am_dir_cfg_rec *dir_cfg = am_get_dir_cfg(r); + int i, err; /* Make sure that this is a POST request. */ if(r->method_number != M_POST) { @@ -2040,7 +2042,21 @@ static int am_handle_post_reply(request_rec *r) " Lasso error: [%i] %s", rc, lasso_strerror(rc)); lasso_login_destroy(login); - return HTTP_BAD_REQUEST; + err = HTTP_BAD_REQUEST; + for (i = 0; auth_mellon_errormap[i].lasso_error != 0; i++) { + if (auth_mellon_errormap[i].lasso_error == rc) { + err = auth_mellon_errormap[i].http_error; + break; + } + } + if (err == HTTP_UNAUTHORIZED) { + if (dir_cfg->no_success_error_page != NULL) { + apr_table_setn(r->headers_out, "Location", + dir_cfg->no_success_error_page); + return HTTP_SEE_OTHER; + } + } + return err; } /* Extract RelayState parameter. */