Blob Blame History Raw
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.
+
 </Location>
 
 
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. */