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."
