couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From fdman...@apache.org
Subject [2/2] git commit: Fix OAuth authentication with VHosts + URL rewriting
Date Sat, 10 Dec 2011 20:02:52 GMT
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/094cfe79
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/094cfe79
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/094cfe79

Branch: refs/heads/master
Commit: 094cfe795286b74303ec517c2262e4845428def9
Parents: 8b94951
Author: Filipe David Borba Manana <fdmanana@apache.org>
Authored: Fri Nov 25 20:12:36 2011 +0000
Committer: Filipe David Borba Manana <fdmanana@apache.org>
Committed: Sat Dec 10 19:40:26 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/094cfe79/src/couchdb/couch_httpd.erl
----------------------------------------------------------------------
diff --git a/src/couchdb/couch_httpd.erl b/src/couchdb/couch_httpd.erl
index d668f98..97475c5 100644
--- a/src/couchdb/couch_httpd.erl
+++ b/src/couchdb/couch_httpd.erl
@@ -299,7 +299,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/094cfe79/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/094cfe79/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/094cfe79/test/etap/160-vhosts.t
----------------------------------------------------------------------
diff --git a/test/etap/160-vhosts.t b/test/etap/160-vhosts.t
index 6e26b59..94882fe 100755
--- a/test/etap/160-vhosts.t
+++ b/test/etap/160-vhosts.t
@@ -30,7 +30,7 @@ admin_user_ctx() -> {user_ctx, #user_ctx{roles=[<<"_admin">>]}}.
 main(_) ->
     test_util:init_code_path(),
 
-    etap:plan(17),
+    etap:plan(20),
     case (catch test()) of
         ok ->
             etap:end_tests();
@@ -113,9 +113,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(),
 
@@ -282,3 +284,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()]).


Mime
View raw message