I'm missing something. Is there any place where pre_rewrite_user_ctx is read? I only see put and erase calls.
On Sat, Dec 10, 2011 at 12:11, Filipe David Manana <[email protected]> wrote: > On Sat, Dec 10, 2011 at 8:08 PM, Benoit Chesneau <[email protected]> wrote: >> what is the point of wariting in the process registry? > > To make it simple, not adding a new handle_request_int clause to > couch_httpd or a new entry point. > >> >> On Sat, Dec 10, 2011 at 9:03 PM, <[email protected]> wrote: >>> Fix OAuth authentication with VHosts + URL rewriting >>> >>> The OAuth handler was not getting the right path (the one >>> the client used to compute its OAuth signature) to verify >>> the client's signature. The right path is the one from >>> before doing the VHost dispatch. >>> Secondly, after the OAuth handler succeeds, the rewriter >>> kicks in and calls couch_httpd:handle_request_int/5 with a >>> new mochiweb request which contains the rewritten patch. >>> This will cause all the authentication handlers to run again, >>> which makes the OAuth handler fail this second time because >>> it gets a rewritten patch. >>> >>> COUCHDB-1320 >>> >>> >>> Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo >>> Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/b86fa1f6 >>> Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/b86fa1f6 >>> Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/b86fa1f6 >>> >>> Branch: refs/heads/1.2.x >>> Commit: b86fa1f6bedee9d441bf4cac53c2794a60c69216 >>> Parents: 25754ac >>> Author: Filipe David Borba Manana <[email protected]> >>> Authored: Sat Dec 10 19:05:52 2011 +0000 >>> Committer: Filipe David Borba Manana <[email protected]> >>> Committed: Sat Dec 10 19:40:37 2011 +0000 >>> >>> ---------------------------------------------------------------------- >>> src/couchdb/couch_httpd.erl | 3 +- >>> src/couchdb/couch_httpd_oauth.erl | 11 +++- >>> src/couchdb/couch_httpd_rewrite.erl | 4 +- >>> test/etap/160-vhosts.t | 89 +++++++++++++++++++++++++++++- >>> 4 files changed, 102 insertions(+), 5 deletions(-) >>> ---------------------------------------------------------------------- >>> >>> >>> http://git-wip-us.apache.org/repos/asf/couchdb/blob/b86fa1f6/src/couchdb/couch_httpd.erl >>> ---------------------------------------------------------------------- >>> diff --git a/src/couchdb/couch_httpd.erl b/src/couchdb/couch_httpd.erl >>> index 11b0bca..2d4c38d 100644 >>> --- a/src/couchdb/couch_httpd.erl >>> +++ b/src/couchdb/couch_httpd.erl >>> @@ -298,7 +298,8 @@ handle_request_int(MochiReq, DefaultFun, >>> db_url_handlers = DbUrlHandlers, >>> design_url_handlers = DesignUrlHandlers, >>> default_fun = DefaultFun, >>> - url_handlers = UrlHandlers >>> + url_handlers = UrlHandlers, >>> + user_ctx = erlang:erase(pre_rewrite_user_ctx) >>> }, >>> >>> HandlerFun = couch_util:dict_find(HandlerKey, UrlHandlers, DefaultFun), >>> >>> http://git-wip-us.apache.org/repos/asf/couchdb/blob/b86fa1f6/src/couchdb/couch_httpd_oauth.erl >>> ---------------------------------------------------------------------- >>> diff --git a/src/couchdb/couch_httpd_oauth.erl >>> b/src/couchdb/couch_httpd_oauth.erl >>> index 4d58a88..65304a3 100644 >>> --- a/src/couchdb/couch_httpd_oauth.erl >>> +++ b/src/couchdb/couch_httpd_oauth.erl >>> @@ -133,8 +133,15 @@ serve_oauth(#httpd{mochi_req=MochiReq}=Req, Fun, >>> FailSilently) -> >>> >>> % get requested path >>> RequestedPath = case >>> MochiReq:get_header_value("x-couchdb-requested-path") of >>> - undefined -> MochiReq:get(raw_path); >>> - RequestedPath0 -> RequestedPath0 >>> + undefined -> >>> + case MochiReq:get_header_value("x-couchdb-vhost-path") of >>> + undefined -> >>> + MochiReq:get(raw_path); >>> + VHostPath -> >>> + VHostPath >>> + end; >>> + RequestedPath0 -> >>> + RequestedPath0 >>> end, >>> {_, QueryString, _} = mochiweb_util:urlsplit_path(RequestedPath), >>> >>> >>> http://git-wip-us.apache.org/repos/asf/couchdb/blob/b86fa1f6/src/couchdb/couch_httpd_rewrite.erl >>> ---------------------------------------------------------------------- >>> diff --git a/src/couchdb/couch_httpd_rewrite.erl >>> b/src/couchdb/couch_httpd_rewrite.erl >>> index bf93478..c8cab85 100644 >>> --- a/src/couchdb/couch_httpd_rewrite.erl >>> +++ b/src/couchdb/couch_httpd_rewrite.erl >>> @@ -187,8 +187,10 @@ handle_rewrite_req(#httpd{ >>> db_url_handlers = DbUrlHandlers, >>> design_url_handlers = DesignUrlHandlers, >>> default_fun = DefaultFun, >>> - url_handlers = UrlHandlers >>> + url_handlers = UrlHandlers, >>> + user_ctx = UserCtx >>> } = Req, >>> + erlang:put(pre_rewrite_user_ctx, UserCtx), >>> couch_httpd:handle_request_int(MochiReq1, DefaultFun, >>> UrlHandlers, DbUrlHandlers, DesignUrlHandlers) >>> end. >>> >>> http://git-wip-us.apache.org/repos/asf/couchdb/blob/b86fa1f6/test/etap/160-vhosts.t >>> ---------------------------------------------------------------------- >>> diff --git a/test/etap/160-vhosts.t b/test/etap/160-vhosts.t >>> index e959f74..0b239a1 100755 >>> --- a/test/etap/160-vhosts.t >>> +++ b/test/etap/160-vhosts.t >>> @@ -52,7 +52,7 @@ admin_user_ctx() -> {user_ctx, >>> #user_ctx{roles=[<<"_admin">>]}}. >>> main(_) -> >>> test_util:init_code_path(), >>> >>> - etap:plan(15), >>> + etap:plan(18), >>> case (catch test()) of >>> ok -> >>> etap:end_tests(); >>> @@ -135,9 +135,11 @@ test() -> >>> test_vhost_request_path2(), >>> test_vhost_request_path3(), >>> test_vhost_request_to_root(), >>> + test_vhost_request_with_oauth(Db), >>> >>> %% restart boilerplate >>> couch_db:close(Db), >>> + ok = couch_server:delete(couch_db:name(Db), [admin_user_ctx()]), >>> timer:sleep(3000), >>> couch_server_sup:stop(), >>> >>> @@ -301,3 +303,88 @@ test_vhost_request_to_root() -> >>> etap:is(HasCouchDBWelcome, true, "should allow redirect to /"); >>> _Else -> etap:is(false, true, <<"ibrowse fail">>) >>> end. >>> + >>> +test_vhost_request_with_oauth(Db) -> >>> + {ok, AuthDb} = couch_db:create( >>> + <<"tap_test_sec_db">>, [admin_user_ctx(), overwrite]), >>> + PrevAuthDbName = couch_config:get("couch_httpd_auth", >>> "authentication_db"), >>> + couch_config:set("couch_httpd_auth", "authentication_db", >>> "tap_test_sec_db", false), >>> + couch_config:set("oauth_token_users", "otoksec1", "joe", false), >>> + couch_config:set("oauth_consumer_secrets", "consec1", "foo", false), >>> + couch_config:set("oauth_token_secrets", "otoksec1", "foobar", false), >>> + couch_config:set("couch_httpd_auth", "require_valid_user", "true", >>> false), >>> + >>> + DDoc = couch_doc:from_json_obj({[ >>> + {<<"_id">>, <<"_design/test">>}, >>> + {<<"language">>, <<"javascript">>}, >>> + {<<"rewrites">>, [ >>> + {[ >>> + {<<"from">>, <<"foobar">>}, >>> + {<<"to">>, <<"_info">>} >>> + ]} >>> + ]} >>> + ]}), >>> + {ok, _} = couch_db:update_doc(Db, DDoc, []), >>> + >>> + RewritePath = "/etap-test-db/_design/test/_rewrite/foobar", >>> + ok = couch_config:set("vhosts", "oauth-example.com", RewritePath, >>> false), >>> + couch_httpd_vhost:reload(), >>> + >>> + case ibrowse:send_req(server(), [], get, [], [{host_header, >>> "oauth-example.com"}]) of >>> + {ok, "401", _, Body} -> >>> + {JsonBody} = ejson:decode(Body), >>> + etap:is( >>> + couch_util:get_value(<<"error">>, JsonBody), >>> + <<"unauthorized">>, >>> + "Request without OAuth credentials failed"); >>> + Error -> >>> + etap:bail("Request without OAuth credentials did not fail: " ++ >>> + couch_util:to_list(Error)) >>> + end, >>> + >>> + JoeDoc = couch_doc:from_json_obj({[ >>> + {<<"_id">>, <<"org.couchdb.user:joe">>}, >>> + {<<"type">>, <<"user">>}, >>> + {<<"name">>, <<"joe">>}, >>> + {<<"roles">>, []}, >>> + {<<"password_sha">>, >>> <<"fe95df1ca59a9b567bdca5cbaf8412abd6e06121">>}, >>> + {<<"salt">>, <<"4e170ffeb6f34daecfd814dfb4001a73">>} >>> + ]}), >>> + {ok, _} = couch_db:update_doc(AuthDb, JoeDoc, []), >>> + >>> + Url = "http://oauth-example.com/", >>> + Consumer = {"consec1", "foo", hmac_sha1}, >>> + SignedParams = oauth:signed_params( >>> + "GET", Url, [], Consumer, "otoksec1", "foobar"), >>> + OAuthUrl = oauth:uri(server(), SignedParams), >>> + >>> + case ibrowse:send_req(OAuthUrl, [], get, [], [{host_header, >>> "oauth-example.com"}]) of >>> + {ok, "200", _, Body2} -> >>> + {JsonBody2} = ejson:decode(Body2), >>> + etap:is(couch_util:get_value(<<"name">>, JsonBody2), >>> <<"test">>, >>> + "should return ddoc info with OAuth credentials"); >>> + Error2 -> >>> + etap:bail("Failed to access vhost with OAuth credentials: " ++ >>> + couch_util:to_list(Error2)) >>> + end, >>> + >>> + Consumer2 = {"consec1", "bad_secret", hmac_sha1}, >>> + SignedParams2 = oauth:signed_params( >>> + "GET", Url, [], Consumer2, "otoksec1", "foobar"), >>> + OAuthUrl2 = oauth:uri(server(), SignedParams2), >>> + >>> + case ibrowse:send_req(OAuthUrl2, [], get, [], [{host_header, >>> "oauth-example.com"}]) of >>> + {ok, "401", _, Body3} -> >>> + {JsonBody3} = ejson:decode(Body3), >>> + etap:is( >>> + couch_util:get_value(<<"error">>, JsonBody3), >>> + <<"unauthorized">>, >>> + "Request with bad OAuth credentials failed"); >>> + Error3 -> >>> + etap:bail("Failed to access vhost with bad OAuth credentials: " >>> ++ >>> + couch_util:to_list(Error3)) >>> + end, >>> + >>> + couch_config:set("couch_httpd_auth", "authentication_db", >>> PrevAuthDbName, false), >>> + couch_config:set("couch_httpd_auth", "require_valid_user", "false", >>> false), >>> + ok = couch_server:delete(couch_db:name(AuthDb), [admin_user_ctx()]). >>> > > > > -- > Filipe David Manana, > > "Reasonable men adapt themselves to the world. > Unreasonable men adapt the world to themselves. > That's why all progress depends on unreasonable men."
