Blame 0001-Modify-am_handler-setup-to-run-before-mod_proxy.patch

Jakub Hrozek 83b8373
From e09a28a30e13e5c22b481010f26b4a7743a09280 Mon Sep 17 00:00:00 2001
Jakub Hrozek 83b8373
From: John Dennis <jdennis@redhat.com>
Jakub Hrozek 83b8373
Date: Tue, 5 Mar 2019 10:15:48 +0100
Jakub Hrozek 83b8373
Subject: [PATCH] Modify am_handler setup to run before mod_proxy
Jakub Hrozek 83b8373
Jakub Hrozek 83b8373
The way the ECP flow works is that when a client initiates the flow, the
Jakub Hrozek 83b8373
SP's response is HTTP 200, but not the requested content, but a signed XML
Jakub Hrozek 83b8373
document that contains the "samlp:AuthnRequest" element. The idea is that
Jakub Hrozek 83b8373
the ECP client would then determine the IDP and send the document to the
Jakub Hrozek 83b8373
IDP, get a samlp:Response and convey that to the SP to get access to the
Jakub Hrozek 83b8373
protected resource.
Jakub Hrozek 83b8373
Jakub Hrozek 83b8373
Internally, the auth check which is normally done with am_check_uid() set to
Jakub Hrozek 83b8373
apache's ap_hook_check_user_id() hook, just responds with OK, so it pretends
Jakub Hrozek 83b8373
to authenticate the user. Then in the usual flow, the request reaches the
Jakub Hrozek 83b8373
ap_hook_handler which handles the request. There in the pipeline, mellon
Jakub Hrozek 83b8373
registers functions am_handler() which should run first (APR_HOOK_FIRST),
Jakub Hrozek 83b8373
determine that this request is an ECP one and return the ECP AuthnRequest
Jakub Hrozek 83b8373
document. But in case the proxy module is also in the picture, the proxy
Jakub Hrozek 83b8373
module "races" for who gets to be the first to handle the request in the
Jakub Hrozek 83b8373
pipeline and wins. Therefore, the request reaches the protected resource
Jakub Hrozek 83b8373
via mod_proxy and returns it.
Jakub Hrozek 83b8373
Jakub Hrozek 83b8373
This fix modifies the ap_hook_handler() call to explicitly run before
Jakub Hrozek 83b8373
handlers from mod_proxy.c
Jakub Hrozek 83b8373
Jakub Hrozek 83b8373
To reproduce the bug:
Jakub Hrozek 83b8373
0) Have a SP with mellon connected to a Keycloak IDP (or any other IDP I
Jakub Hrozek 83b8373
   guess). In the example below, my SAML SP is saml.federation.test
Jakub Hrozek 83b8373
1) Set a Location protected by mellon that proxies requests to another
Jakub Hrozek 83b8373
   URL. For example:
Jakub Hrozek 83b8373
Jakub Hrozek 83b8373
    ProxyPass         /sp-proxy  http://app.federation.test/example_app/
Jakub Hrozek 83b8373
    <Location /sp-proxy>
Jakub Hrozek 83b8373
        AuthType Mellon
Jakub Hrozek 83b8373
        MellonEnable auth
Jakub Hrozek 83b8373
        Require valid-user
Jakub Hrozek 83b8373
    </Location>
Jakub Hrozek 83b8373
Jakub Hrozek 83b8373
2) call:
Jakub Hrozek 83b8373
 curl -L -H "Accept: application/vnd.paos+xml" \
Jakub Hrozek 83b8373
         -H 'PAOS: ver="urn:liberty:paos:2003-08";"urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp"' \
Jakub Hrozek 83b8373
          http://saml.federation.test/sp-proxy
Jakub Hrozek 83b8373
Jakub Hrozek 83b8373
Before the patch, you would see whatever is served from the proxied
Jakub Hrozek 83b8373
page. With the patch, you should get back a XML document with a
Jakub Hrozek 83b8373
samlp:AuthnRequest.
Jakub Hrozek 83b8373
---
Jakub Hrozek 83b8373
 mod_auth_mellon.c | 8 +++++++-
Jakub Hrozek 83b8373
 1 file changed, 7 insertions(+), 1 deletion(-)
Jakub Hrozek 83b8373
Jakub Hrozek 83b8373
diff --git a/mod_auth_mellon.c b/mod_auth_mellon.c
Jakub Hrozek 83b8373
index 74bd328..5330f48 100644
Jakub Hrozek 83b8373
--- a/mod_auth_mellon.c
Jakub Hrozek 83b8373
+++ b/mod_auth_mellon.c
Jakub Hrozek 83b8373
@@ -207,6 +207,12 @@ static int am_create_request(request_rec *r)
Jakub Hrozek 83b8373
 
Jakub Hrozek 83b8373
 static void register_hooks(apr_pool_t *p)
Jakub Hrozek 83b8373
 {
Jakub Hrozek 83b8373
+    /* Our handler needs to run before mod_proxy so that it can properly
Jakub Hrozek 83b8373
+     * return ECP AuthnRequest messages when running as a reverse proxy.
Jakub Hrozek 83b8373
+     * See: https://github.com/Uninett/mod_auth_mellon/pull/196
Jakub Hrozek 83b8373
+     */
Jakub Hrozek 83b8373
+    static const char * const run_handler_before[]={ "mod_proxy.c", NULL };
Jakub Hrozek 83b8373
+
Jakub Hrozek 83b8373
     ap_hook_access_checker(am_auth_mellon_user, NULL, NULL, APR_HOOK_MIDDLE);
Jakub Hrozek 83b8373
     ap_hook_check_user_id(am_check_uid, NULL, NULL, APR_HOOK_MIDDLE);
Jakub Hrozek 83b8373
     ap_hook_post_config(am_global_init, NULL, NULL, APR_HOOK_MIDDLE);
Jakub Hrozek 83b8373
@@ -222,7 +228,7 @@ static void register_hooks(apr_pool_t *p)
Jakub Hrozek 83b8373
      * Therefore this hook must run before any handler that may check
Jakub Hrozek 83b8373
      * r->handler and decide that it is the only handler for this URL.
Jakub Hrozek 83b8373
      */
Jakub Hrozek 83b8373
-    ap_hook_handler(am_handler, NULL, NULL, APR_HOOK_FIRST);
Jakub Hrozek 83b8373
+    ap_hook_handler(am_handler, NULL, run_handler_before, APR_HOOK_FIRST);
Jakub Hrozek 83b8373
 
Jakub Hrozek 83b8373
 #ifdef ENABLE_DIAGNOSTICS
Jakub Hrozek 83b8373
     ap_hook_open_logs(am_diag_log_init,NULL,NULL,APR_HOOK_MIDDLE);
Jakub Hrozek 83b8373
-- 
Jakub Hrozek 83b8373
2.19.2
Jakub Hrozek 83b8373