In reference to Issue #20:

On Thu 2011-12-08 11:53:44 -0500, Christian Boos 
<reply+i-2489113-97f3eb1c5c6ef559403b66ade9d4d94c192f4bfa-66...@reply.github.com>
 wrote:

> Short summary: in a custom login page
> (https://members.mayfirst.org/openid/login/), the form adds a hidden
> referer parameter. This query parameter gets preserved as expected,
> but the problem is that it is also **duplicated** (see
> http://trac.edgewall.org/ticket/10491#comment:11 for a reproduction
> recipe). The targeted application (Trac) doesn't like this duplicated
> parameter and fails.

I can give more details about the situation in which this happens.

My relevant apache configuration for foo.example.org is:

        <Location "/login">
            AuthType OpenID
            require valid-user
            AuthOpenIDDBLocation /srv/mod_auth_openid/db/openid.db
            AuthOpenIDUseCookie Off
            AuthOpenIDLoginPage http://bar.example.org/openid/login/
        </Location>

I start with an empty database.

The login sequence is:

0) GET http://foo.example.org/

 (user clicks for:)

1) GET http://foo.example.org/login

 (HTTP 302 redirection to:)
 
2) GET http://bar.example.org/openid/login/?
       modauthopenid.referrer=http%3A%2F%2Ffoo.example.org%2Flogin%3F

 (user chooses an ID, and clicks submit:)

3) GET http://foo.example.org/login?
       referer=http%3A%2F%2Ffoo.example.org%2F&
       openid_identifier=https%3A%2F%2Fid.mayfirst.org%2Fdkg

 (HTTP 302 redirection to:)

4) GET https://id.mayfirst.org/openid/provider?
       
openid.assoc_handle=2012-11-26T18%3A44%3A42Zc4ffb4be939d1f3af09b1f810928cb35c0836d0102c950f839b19622df577ceb&
       openid.claimed_id=https%3A%2F%2Fid.mayfirst.org%2Fdkg&
       openid.identity=https%3A%2F%2Fid.mayfirst.org%2Fdkg&
       openid.mode=checkid_setup&
       openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&
       openid.realm=http%3A%2F%2Ffoo.example.org%2F&
       
openid.return_to=http%3A%2F%2Ffoo.example.org%2Flogin%3Freferer%3Dhttp%253A%252F%252Ffoo.example.org%252F%26modauthopenid.nonce%3DLh1AO9ngBY%26referer%3Dhttp%253A%252F%252Ffoo.example.org%252F&
       openid.trust_root=http%3A%2F%2Ffoo.example.org%2F


note that openid.return_to here is (decoded and re-wrapped):

  http://foo.example.org/login?
       referer=http%3A%2F%2Ffoo.example.org%2F&
       modauthopenid.nonce=Lh1AO9ngBY&
       referer=http%3A%2F%2Ffoo.example.org%2F

So the HTTP 302 redirection that leads from GET 3 to GET 4 is generated
by mod_auth_openid, based on the parameters which come in from the
AuthOpenIDLoginPage.  It duplicates the "referer" GET parameter, which
was passed by the AuthOpenIDLoginPage.

So i think what is happening is:

 a) mod_authopenid_method_handler() extracts the current request's GET
    parameters into an opkele::params_t object named params(), and
    (based on the presence of the openid_identifier parameter), decides
    to start_authentication_session() with that params object.

 b) in start_authentication_session(), we extract the full URL
    (including all the non-openid GET parameters) of the current request
    into return_to via full_uri(), and then append the params to it.

This results in a doubling of every non-openid GET parameter into the
return_to variable.

I don't understand why it's done this way, or what is gained from it.

The attached patch avoids keeping the params in the return_to extraction
in (b), and seems to resolve the issue for me under this configuration.

      --dkg

diff --git a/src/mod_auth_openid.cpp b/src/mod_auth_openid.cpp
index 8196506..777e779 100644
--- a/src/mod_auth_openid.cpp
+++ b/src/mod_auth_openid.cpp
@@ -217,9 +217,11 @@ static const command_rec mod_authopenid_cmds[] = {
   {NULL}
 };
 
+enum keep_params_t { kp_all, kp_clean, kp_none };
+
 // Get the full URI of the request_rec's request location 
-// clean_params specifies whether or not all openid.* and modauthopenid.* params should be cleared
-static void full_uri(request_rec *r, std::string& result, modauthopenid_config *s_cfg, bool clean_params=false) {
+// keep_params specifies whether whether we keep all parameters, clean out the openid.* and modauthopenid.* params, or keep none of them.
+static void full_uri(request_rec *r, std::string& result, modauthopenid_config *s_cfg, keep_params_t keep_params=kp_all) {
   std::string hostname(r->hostname);
   std::string uri(r->uri);
   apr_port_t i_port = ap_get_server_port(r);
@@ -230,12 +232,19 @@ static void full_uri(request_rec *r, std::string& result, modauthopenid_config *
   std::string s_port = (i_port == 80 || i_port == 443) ? "" : ":" + std::string(port);
 
   std::string args;
-  if(clean_params) {
-    opkele::params_t params;
-    if(r->args != NULL) params = modauthopenid::parse_query_string(std::string(r->args));
-    modauthopenid::remove_openid_vars(params);
-    args = params.append_query("", "");
-  } else {
+  switch (keep_params) {
+  case kp_clean:
+    {
+      opkele::params_t params;
+      if(r->args != NULL) params = modauthopenid::parse_query_string(std::string(r->args));
+      modauthopenid::remove_openid_vars(params);
+      args = params.append_query("", "");
+    }
+    break;
+  case kp_none:
+    args = "";
+    break;
+  default:
     args = (r->args == NULL) ? "" : "?" + std::string(r->args);
   }
 
@@ -256,7 +266,7 @@ static int show_input(request_rec *r, modauthopenid_config *s_cfg, modauthopenid
   modauthopenid::remove_openid_vars(params);  
 
   std::string uri_location;
-  full_uri(r, uri_location, s_cfg, true);
+  full_uri(r, uri_location, s_cfg, kp_clean);
   params["modauthopenid.referrer"] = uri_location;
 
   params["modauthopenid.error"] = modauthopenid::error_to_string(e, true);
@@ -271,7 +281,7 @@ static int show_input(request_rec *r, modauthopenid_config *s_cfg) {
     params = modauthopenid::parse_query_string(std::string(r->args));
   modauthopenid::remove_openid_vars(params);
   std::string uri_location;
-  full_uri(r, uri_location, s_cfg, true);
+  full_uri(r, uri_location, s_cfg, kp_clean);
   params["modauthopenid.referrer"] = uri_location;
   return modauthopenid::http_redirect(r, params.append_query(s_cfg->login_page, ""));
 }
@@ -390,7 +400,7 @@ static int start_authentication_session(request_rec *r, modauthopenid_config *s_
   modauthopenid::make_rstring(10, nonce);
   modauthopenid::MoidConsumer consumer(std::string(s_cfg->db_location), nonce, return_to);    
   params["modauthopenid.nonce"] = nonce;
-  full_uri(r, return_to, s_cfg, true);
+  full_uri(r, return_to, s_cfg, kp_none);
   return_to = params.append_query(return_to, "");
 
   // get identity provider and redirect

Attachment: pgpUYazk3JM1u.pgp
Description: PGP signature

Reply via email to