summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoan Touzet <joant@atypical.net>2017-07-08 01:28:39 -0400
committerJoan Touzet <joant@atypical.net>2017-07-08 01:28:39 -0400
commit6da893458dd71419aa73d5dac99e60647f15f5f2 (patch)
tree2a7e6bf843bc4b613d39330263c9d686e2ba5c6b
parent3e4da6085b9989aa0a1436b659d7267a3c3f1226 (diff)
downloadcouchdb-656-remove-oauth.tar.gz
Remove deprecated OAuth 1.0 implementation656-remove-oauth
Helps resolve issue #656. Implementation broken since bigcouch merge. Replicator oauth hooks are left in place for future work towards adding cookie-based authentication support.
-rw-r--r--LICENSE25
-rw-r--r--NOTICE4
-rwxr-xr-xbuild-aux/print-committerlist.sh2
-rw-r--r--license.skip2
-rw-r--r--rebar.config.script4
-rw-r--r--rel/overlay/etc/default.ini29
-rw-r--r--rel/reltool.config2
-rw-r--r--src/couch/include/couch_js_functions.hrl18
-rw-r--r--src/couch/src/couch.app.src1
-rw-r--r--src/couch/src/couch.erl1
-rw-r--r--src/couch/src/couch_httpd_handlers.erl1
-rw-r--r--src/couch/src/couch_httpd_oauth.erl391
-rw-r--r--src/couch/src/test_util.erl1
-rw-r--r--src/couch/test/chttpd_endpoints_tests.erl1
-rw-r--r--src/couch/test/couchdb_auth_tests.erl2
-rw-r--r--src/couch/test/couchdb_vhosts_tests.erl139
-rwxr-xr-xsrc/couch/test/fixtures/os_daemon_configer.escript1
-rw-r--r--test/javascript/oauth.js511
-rwxr-xr-xtest/javascript/run1
-rw-r--r--test/javascript/tests/oauth_users_db.js168
-rw-r--r--test/javascript/tests/replicator_db_security.js28
21 files changed, 5 insertions, 1327 deletions
diff --git a/LICENSE b/LICENSE
index 086b2dd96..1f0b270b4 100644
--- a/LICENSE
+++ b/LICENSE
@@ -272,31 +272,6 @@ For the src/ibrowse component:
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-For the src/oauth component:
-
- Copyright the authors and contributors. All rights reserved.
-
- Permission is hereby granted, free of charge, to any person
- obtaining a copy of this software and associated documentation
- files (the "Software"), to deal in the Software without
- restriction, including without limitation the rights to use,
- copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following
- conditions:
-
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- OTHER DEALINGS IN THE SOFTWARE.
-
For the test/etap/etap.erl component:
Copyright (c) 2008-2009 Nick Gerakines <nick@gerakines.net>
diff --git a/NOTICE b/NOTICE
index d0c9f984f..cc1621bc4 100644
--- a/NOTICE
+++ b/NOTICE
@@ -38,10 +38,6 @@ This product also includes the following third-party components:
Copyright 2005-2012, Chandrashekhar Mullaparthi
- * Erlang OAuth (http://github.com/tim/erlang-oauth)
-
- Copyright 2012, the authors and contributors
-
* ETap (http://github.com/ngerakines/etap/)
Copyright 2009, Nick Gerakines <nick@gerakines.net>
diff --git a/build-aux/print-committerlist.sh b/build-aux/print-committerlist.sh
index 7fbb96b7f..f6abc4c78 100755
--- a/build-aux/print-committerlist.sh
+++ b/build-aux/print-committerlist.sh
@@ -40,7 +40,7 @@ function get_contributors {
function print_comitter_list {
# list of external repos that we exclude
- local EXCLUDE=("bear" "folsom" "goldrush" "ibrowse" "jiffy" "lager" "meck" "mochiweb" "oauth" "snappy")
+ local EXCLUDE=("bear" "folsom" "goldrush" "ibrowse" "jiffy" "lager" "meck" "mochiweb" "snappy")
local EXCLUDE=$(printf "\|%s" "${EXCLUDE[@]}")
local EXCLUDE=${EXCLUDE:2}
local SUBREPOS=$(ls src/ | grep -v "$EXCLUDE")
diff --git a/license.skip b/license.skip
index c1bd0e901..143639251 100644
--- a/license.skip
+++ b/license.skip
@@ -133,7 +133,6 @@
^src/couchjs-node/README.md
^src/couchjs-node/Makefile
^src/couchjs-node/Makefile.in
-^src/erlang-oauth/.*
^src/couch_dbupdates
^src/ejson/.*
^src/etap/.*
@@ -188,7 +187,6 @@
^src/twig/ebin/twig.app
^src/twig/README.md
^src/twig/src/trunc_io.erl
-^src/oauth/.*
^stamp-h1
^test/Makefile
^test/Makefile.in
diff --git a/rebar.config.script b/rebar.config.script
index 5d0e4e85a..ebf4d94c8 100644
--- a/rebar.config.script
+++ b/rebar.config.script
@@ -64,10 +64,8 @@ DepDescs = [
{ibrowse, "ibrowse", "4af2d408607874d124414ac45df1edbe3961d1cd"},
{jiffy, "jiffy", "1acdd1ac389dff3d763589f64331227ae594f3b7"},
{mochiweb, "mochiweb", "bd6ae7cbb371666a1f68115056f7b30d13765782"},
-{meck, "meck", {tag, "0.8.2"}},
+{meck, "meck", {tag, "0.8.2"}}
-%% Deprecated
-{oauth, "oauth", "099057a98e41f3aff91e77e3cf496d6c6fd901df"}
],
diff --git a/rel/overlay/etc/default.ini b/rel/overlay/etc/default.ini
index 30a03bc87..eaa0801b7 100644
--- a/rel/overlay/etc/default.ini
+++ b/rel/overlay/etc/default.ini
@@ -76,10 +76,10 @@ delete_dbs = false
[httpd]
port = {{backend_port}}
bind_address = 127.0.0.1
-authentication_handlers = {couch_httpd_oauth, oauth_authentication_handler}, {couch_httpd_auth, cookie_authentication_handler}, {couch_httpd_auth, default_authentication_handler}
+authentication_handlers = {couch_httpd_auth, cookie_authentication_handler}, {couch_httpd_auth, default_authentication_handler}
default_handler = {couch_httpd_db, handle_request}
secure_rewrites = true
-vhost_global_handlers = _utils, _uuids, _session, _oauth, _users
+vhost_global_handlers = _utils, _uuids, _session, _users
allow_jsonp = false
; Options for the MochiWeb HTTP server.
;server_options = [{backlog, 128}, {acceptor_pool_size, 16}]
@@ -196,30 +196,6 @@ credentials = false
; List of hosts separated by a comma. * means accept all
; hosts =
-[couch_httpd_oauth]
-; If set to 'true', oauth token and consumer secrets will be looked up
-; in the authentication database (_users). These secrets are stored in
-; a top level property named "oauth" in user documents. Example:
-; {
-; "_id": "org.couchdb.user:joe",
-; "type": "user",
-; "name": "joe",
-; "password_sha": "fe95df1ca59a9b567bdca5cbaf8412abd6e06121",
-; "salt": "4e170ffeb6f34daecfd814dfb4001a73"
-; "roles": ["foo", "bar"],
-; "oauth": {
-; "consumer_keys": {
-; "consumerKey1": "key1Secret",
-; "consumerKey2": "key2Secret"
-; },
-; "tokens": {
-; "token1": "token1Secret",
-; "token2": "token2Secret"
-; }
-; }
-; }
-use_users_db = false
-
[query_servers]
javascript = {{prefix}}/bin/couchjs {{prefix}}/share/server/main.js
coffeescript = {{prefix}}/bin/couchjs {{prefix}}/share/server/main-coffee.js
@@ -266,7 +242,6 @@ _uuids = {couch_httpd_misc_handlers, handle_uuids_req}
_restart = {couch_httpd_misc_handlers, handle_restart_req}
_stats = {couch_stats_httpd, handle_stats_req}
_session = {couch_httpd_auth, handle_session_req}
-_oauth = {couch_httpd_oauth, handle_oauth_req}
_plugins = {couch_plugins_httpd, handle_req}
_system = {chttpd_misc, handle_system_req}
diff --git a/rel/reltool.config b/rel/reltool.config
index 135d38676..762848f22 100644
--- a/rel/reltool.config
+++ b/rel/reltool.config
@@ -53,7 +53,6 @@
mango,
mem3,
mochiweb,
- oauth,
rexi,
setup,
snappy
@@ -107,7 +106,6 @@
{app, mango, [{incl_cond, include}]},
{app, mem3, [{incl_cond, include}]},
{app, mochiweb, [{incl_cond, include}]},
- {app, oauth, [{incl_cond, include}]},
{app, rexi, [{incl_cond, include}]},
{app, setup, [{incl_cond, include}]},
{app, snappy, [{incl_cond, include}]}
diff --git a/src/couch/include/couch_js_functions.hrl b/src/couch/include/couch_js_functions.hrl
index 0ae6427e4..6851718ff 100644
--- a/src/couch/include/couch_js_functions.hrl
+++ b/src/couch/include/couch_js_functions.hrl
@@ -150,21 +150,3 @@
}
}
">>).
-
-
--define(OAUTH_MAP_FUN, <<"
- function(doc) {
- if (doc.type === 'user' && doc.oauth && doc.oauth.consumer_keys) {
- for (var consumer_key in doc.oauth.consumer_keys) {
- for (var token in doc.oauth.tokens) {
- var obj = {
- 'consumer_secret': doc.oauth.consumer_keys[consumer_key],
- 'token_secret': doc.oauth.tokens[token],
- 'username': doc.name
- };
- emit([consumer_key, token], obj);
- }
- }
- }
- }
-">>).
diff --git a/src/couch/src/couch.app.src b/src/couch/src/couch.app.src
index cf3dc795d..8fc0d89ff 100644
--- a/src/couch/src/couch.app.src
+++ b/src/couch/src/couch.app.src
@@ -39,7 +39,6 @@
% Upstream deps
ibrowse,
mochiweb,
- oauth,
% ASF deps
couch_epi,
diff --git a/src/couch/src/couch.erl b/src/couch/src/couch.erl
index 44cea065a..fd5c9e101 100644
--- a/src/couch/src/couch.erl
+++ b/src/couch/src/couch.erl
@@ -23,7 +23,6 @@ deps() ->
crypto,
public_key,
ssl,
- oauth,
ibrowse,
mochiweb,
config,
diff --git a/src/couch/src/couch_httpd_handlers.erl b/src/couch/src/couch_httpd_handlers.erl
index b8ee3efd9..e64287566 100644
--- a/src/couch/src/couch_httpd_handlers.erl
+++ b/src/couch/src/couch_httpd_handlers.erl
@@ -14,7 +14,6 @@
-export([url_handler/1, db_handler/1, design_handler/1]).
-url_handler(<<"_oauth">>) -> fun couch_httpd_oauth:handle_oauth_req/1;
url_handler(_) -> no_match.
db_handler(_) -> no_match.
diff --git a/src/couch/src/couch_httpd_oauth.erl b/src/couch/src/couch_httpd_oauth.erl
deleted file mode 100644
index 03107525b..000000000
--- a/src/couch/src/couch_httpd_oauth.erl
+++ /dev/null
@@ -1,391 +0,0 @@
-% Licensed under the Apache License, Version 2.0 (the "License"); you may not
-% use this file except in compliance with the License. You may obtain a copy of
-% the License at
-%
-% http://www.apache.org/licenses/LICENSE-2.0
-%
-% Unless required by applicable law or agreed to in writing, software
-% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-% License for the specific language governing permissions and limitations under
-% the License.
-
--module(couch_httpd_oauth).
-
--include_lib("couch/include/couch_db.hrl").
--include_lib("couch/include/couch_js_functions.hrl").
-
--export([oauth_authentication_handler/1, handle_oauth_req/1]).
-
--define(OAUTH_DDOC_ID, <<"_design/oauth">>).
--define(OAUTH_VIEW_NAME, <<"oauth_credentials">>).
-
--record(callback_params, {
- consumer,
- token,
- token_secret,
- url,
- signature,
- params,
- username
-}).
-
-% OAuth auth handler using per-node user db
-oauth_authentication_handler(Req) ->
- serve_oauth(Req, fun oauth_auth_callback/2, true).
-
-
-oauth_auth_callback(Req, #callback_params{token_secret = undefined}) ->
- couch_httpd:send_error(
- Req, 400, <<"invalid_token">>, <<"Invalid OAuth token.">>);
-
-oauth_auth_callback(#httpd{mochi_req = MochiReq} = Req, CbParams) ->
- Method = atom_to_list(MochiReq:get(method)),
- #callback_params{
- consumer = Consumer,
- token = Token,
- token_secret = TokenSecret,
- url = Url,
- signature = Sig,
- params = Params,
- username = User
- } = CbParams,
- case oauth:verify(Sig, Method, Url, Params, Consumer, TokenSecret) of
- true ->
- set_user_ctx(Req, User);
- false ->
- couch_log:debug("OAuth handler: signature verification failed for"
- " user `~p`~n"
- "Received signature is `~p`~n"
- "HTTP method is `~p`~n"
- "URL is `~p`~n"
- "Parameters are `~p`~n"
- "Consumer is `~p`, token secret is `~p`~n"
- "Expected signature was `~p`~n",
- [User, Sig, Method, Url, Params, Consumer, TokenSecret,
- oauth:sign(Method, Url, Params, Consumer, Token,
- TokenSecret)]),
- Req
- end.
-
-
-% Look up the consumer key and get the roles to give the consumer
-set_user_ctx(_Req, undefined) ->
- throw({bad_request, unknown_oauth_token});
-set_user_ctx(Req, Name) ->
- case couch_auth_cache:get_user_creds(Name) of
- nil ->
- couch_log:debug("OAuth handler: user `~p` credentials not found",
- [Name]),
- Req;
- {ok, User, _AuthCtx} ->
- Roles = couch_util:get_value(<<"roles">>, User, []),
- Req#httpd{user_ctx=#user_ctx{name=Name, roles=Roles}}
- end.
-
-% OAuth request_token
-handle_oauth_req(#httpd{path_parts=[_OAuth, <<"request_token">>], method=Method}=Req1) ->
- serve_oauth(Req1, fun(Req, CbParams) ->
- #callback_params{
- consumer = Consumer,
- token_secret = TokenSecret,
- url = Url,
- signature = Sig,
- params = Params
- } = CbParams,
- case oauth:verify(
- Sig, atom_to_list(Method), Url, Params, Consumer, TokenSecret) of
- true ->
- ok(Req, <<"oauth_token=requestkey&oauth_token_secret=requestsecret">>);
- false ->
- invalid_signature(Req)
- end
- end, false);
-handle_oauth_req(#httpd{path_parts=[_OAuth, <<"authorize">>]}=Req) ->
- {ok, serve_oauth_authorize(Req)};
-handle_oauth_req(#httpd{path_parts=[_OAuth, <<"access_token">>], method='GET'}=Req1) ->
- serve_oauth(Req1, fun(Req, CbParams) ->
- #callback_params{
- consumer = Consumer,
- token = Token,
- url = Url,
- signature = Sig,
- params = Params
- } = CbParams,
- case Token of
- "requestkey" ->
- case oauth:verify(
- Sig, "GET", Url, Params, Consumer, "requestsecret") of
- true ->
- ok(Req,
- <<"oauth_token=accesskey&oauth_token_secret=accesssecret">>);
- false ->
- invalid_signature(Req)
- end;
- _ ->
- couch_httpd:send_error(
- Req, 400, <<"invalid_token">>, <<"Invalid OAuth token.">>)
- end
- end, false);
-handle_oauth_req(#httpd{path_parts=[_OAuth, <<"access_token">>]}=Req) ->
- couch_httpd:send_method_not_allowed(Req, "GET").
-
-invalid_signature(Req) ->
- couch_httpd:send_error(Req, 400, <<"invalid_signature">>, <<"Invalid signature value.">>).
-
-% This needs to be protected i.e. force user to login using HTTP Basic Auth or form-based login.
-serve_oauth_authorize(#httpd{method=Method}=Req1) ->
- case Method of
- 'GET' ->
- % Confirm with the User that they want to authenticate the Consumer
- serve_oauth(Req1, fun(Req, CbParams) ->
- #callback_params{
- consumer = Consumer,
- token_secret = TokenSecret,
- url = Url,
- signature = Sig,
- params = Params
- } = CbParams,
- case oauth:verify(
- Sig, "GET", Url, Params, Consumer, TokenSecret) of
- true ->
- ok(Req, <<"oauth_token=requestkey&",
- "oauth_token_secret=requestsecret">>);
- false ->
- invalid_signature(Req)
- end
- end, false);
- 'POST' ->
- % If the User has confirmed, we direct the User back to the Consumer with a verification code
- serve_oauth(Req1, fun(Req, CbParams) ->
- #callback_params{
- consumer = Consumer,
- token_secret = TokenSecret,
- url = Url,
- signature = Sig,
- params = Params
- } = CbParams,
- case oauth:verify(
- Sig, "POST", Url, Params, Consumer, TokenSecret) of
- true ->
- %redirect(oauth_callback, oauth_token, oauth_verifier),
- ok(Req, <<"oauth_token=requestkey&",
- "oauth_token_secret=requestsecret">>);
- false ->
- invalid_signature(Req)
- end
- end, false);
- _ ->
- couch_httpd:send_method_not_allowed(Req1, "GET,POST")
- end.
-
-serve_oauth(#httpd{mochi_req=MochiReq}=Req, Fun, FailSilently) ->
- % 1. In the HTTP Authorization header as defined in OAuth HTTP Authorization Scheme.
- % 2. As the HTTP POST request body with a content-type of application/x-www-form-urlencoded.
- % 3. Added to the URLs in the query part (as defined by [RFC3986] section 3).
- AuthHeader = case MochiReq:get_header_value("authorization") of
- undefined ->
- "";
- Else ->
- [Head | Tail] = re:split(Else, "\\s", [{parts, 2}, {return, list}]),
- case [string:to_lower(Head) | Tail] of
- ["oauth", Rest] -> Rest;
- _ -> ""
- end
- end,
- HeaderParams = oauth:header_params_decode(AuthHeader),
- %Realm = couch_util:get_value("realm", HeaderParams),
-
- % get requested path
- RequestedPath = case MochiReq:get_header_value("x-couchdb-requested-path") of
- 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),
-
- Params = proplists:delete("realm", HeaderParams) ++ mochiweb_util:parse_qs(QueryString),
-
- couch_log:debug("OAuth Params: ~p", [Params]),
- case couch_util:get_value("oauth_version", Params, "1.0") of
- "1.0" ->
- case couch_util:get_value("oauth_consumer_key", Params, undefined) of
- undefined ->
- case FailSilently of
- true -> Req;
- false -> couch_httpd:send_error(Req, 400, <<"invalid_consumer">>, <<"Invalid consumer.">>)
- end;
- ConsumerKey ->
- Url = couch_httpd:absolute_uri(Req, RequestedPath),
- case get_callback_params(ConsumerKey, Params, Url) of
- {ok, CallbackParams} ->
- Fun(Req, CallbackParams);
- invalid_consumer_token_pair ->
- couch_httpd:send_error(
- Req, 400,
- <<"invalid_consumer_token_pair">>,
- <<"Invalid consumer and token pair.">>);
- {error, {Error, Reason}} ->
- couch_httpd:send_error(Req, 400, Error, Reason)
- end
- end;
- _ ->
- couch_httpd:send_error(Req, 400, <<"invalid_oauth_version">>, <<"Invalid OAuth version.">>)
- end.
-
-
-get_callback_params(ConsumerKey, Params, Url) ->
- Token = couch_util:get_value("oauth_token", Params),
- SigMethod = sig_method(Params),
- CbParams0 = #callback_params{
- token = Token,
- signature = couch_util:get_value("oauth_signature", Params),
- params = proplists:delete("oauth_signature", Params),
- url = Url
- },
- case oauth_credentials_info(Token, ConsumerKey) of
- nil ->
- invalid_consumer_token_pair;
- {error, _} = Err ->
- Err;
- {OauthCreds} ->
- User = couch_util:get_value(<<"username">>, OauthCreds, []),
- ConsumerSecret = ?b2l(couch_util:get_value(
- <<"consumer_secret">>, OauthCreds, <<>>)),
- TokenSecret = ?b2l(couch_util:get_value(
- <<"token_secret">>, OauthCreds, <<>>)),
- case (User =:= []) orelse (ConsumerSecret =:= []) orelse
- (TokenSecret =:= []) of
- true ->
- invalid_consumer_token_pair;
- false ->
- CbParams = CbParams0#callback_params{
- consumer = {ConsumerKey, ConsumerSecret, SigMethod},
- token_secret = TokenSecret,
- username = User
- },
- couch_log:debug("Got OAuth credentials, for ConsumerKey `~p` and "
- "Token `~p`, from the views, User: `~p`, "
- "ConsumerSecret: `~p`, TokenSecret: `~p`",
- [ConsumerKey, Token, User, ConsumerSecret,
- TokenSecret]),
- {ok, CbParams}
- end
- end.
-
-
-sig_method(Params) ->
- sig_method_1(couch_util:get_value("oauth_signature_method", Params)).
-sig_method_1("PLAINTEXT") ->
- plaintext;
-% sig_method_1("RSA-SHA1") ->
-% rsa_sha1;
-sig_method_1("HMAC-SHA1") ->
- hmac_sha1;
-sig_method_1(_) ->
- undefined.
-
-
-ok(#httpd{mochi_req=MochiReq}, Body) ->
- {ok, MochiReq:respond({200, [], Body})}.
-
-
-oauth_credentials_info(Token, ConsumerKey) ->
- case use_auth_db() of
- {ok, Db} ->
- Result = case query_oauth_view(Db, [?l2b(ConsumerKey), ?l2b(Token)]) of
- [] ->
- nil;
- [Creds] ->
- Creds;
- [_ | _] ->
- Reason = iolist_to_binary(
- io_lib:format("Found multiple OAuth credentials for the pair "
- " (consumer_key: `~p`, token: `~p`)", [ConsumerKey, Token])),
- {error, {<<"oauth_token_consumer_key_pair">>, Reason}}
- end,
- couch_db:close(Db),
- Result;
- nil ->
- {
- case config:get("oauth_consumer_secrets", ConsumerKey) of
- undefined -> [];
- ConsumerSecret -> [{<<"consumer_secret">>, ?l2b(ConsumerSecret)}]
- end
- ++
- case config:get("oauth_token_secrets", Token) of
- undefined -> [];
- TokenSecret -> [{<<"token_secret">>, ?l2b(TokenSecret)}]
- end
- ++
- case config:get("oauth_token_users", Token) of
- undefined -> [];
- User -> [{<<"username">>, ?l2b(User)}]
- end
- }
- end.
-
-
-use_auth_db() ->
- case config:get("couch_httpd_oauth", "use_users_db", "false") of
- "false" ->
- nil;
- "true" ->
- AuthDb = open_auth_db(),
- {ok, _AuthDb2} = ensure_oauth_views_exist(AuthDb)
- end.
-
-
-open_auth_db() ->
- DbName = ?l2b(config:get("couch_httpd_auth", "authentication_db")),
- {ok, AuthDb} = couch_db:open_int(DbName, [?ADMIN_CTX]),
- AuthDb.
-
-
-ensure_oauth_views_exist(AuthDb) ->
- case couch_db:open_doc(AuthDb, ?OAUTH_DDOC_ID, []) of
- {ok, _DDoc} ->
- {ok, AuthDb};
- _ ->
- {ok, DDoc} = get_oauth_ddoc(),
- {ok, _Rev} = couch_db:update_doc(AuthDb, DDoc, []),
- {ok, _AuthDb2} = couch_db:reopen(AuthDb)
- end.
-
-
-get_oauth_ddoc() ->
- Json = {[
- {<<"_id">>, ?OAUTH_DDOC_ID},
- {<<"language">>, <<"javascript">>},
- {<<"views">>,
- {[
- {?OAUTH_VIEW_NAME,
- {[
- {<<"map">>, ?OAUTH_MAP_FUN}
- ]}
- }
- ]}
- }
- ]},
- {ok, couch_doc:from_json_obj(Json)}.
-
-
-query_oauth_view(Db, Key) ->
- ViewOptions = [
- {start_key, Key},
- {end_key, Key}
- ],
- Callback = fun({row, Row}, Acc) ->
- {ok, [couch_util:get_value(value, Row) | Acc]};
- (_, Acc) ->
- {ok, Acc}
- end,
- {ok, Result} = couch_mrview:query_view(
- Db, ?OAUTH_DDOC_ID, ?OAUTH_VIEW_NAME, ViewOptions, Callback, []),
- Result.
diff --git a/src/couch/src/test_util.erl b/src/couch/src/test_util.erl
index 1be177ad7..e145e421f 100644
--- a/src/couch/src/test_util.erl
+++ b/src/couch/src/test_util.erl
@@ -47,7 +47,6 @@ init_code_path() ->
Paths = [
"couchdb",
"jiffy",
- "oauth",
"ibrowse",
"mochiweb",
"snappy"
diff --git a/src/couch/test/chttpd_endpoints_tests.erl b/src/couch/test/chttpd_endpoints_tests.erl
index 06de1e923..715576713 100644
--- a/src/couch/test/chttpd_endpoints_tests.erl
+++ b/src/couch/test/chttpd_endpoints_tests.erl
@@ -47,7 +47,6 @@ handlers(url_handler) ->
{<<"_replicate">>, chttpd_misc, handle_replicate_req},
{<<"_uuids">>, chttpd_misc, handle_uuids_req},
{<<"_session">>, chttpd_auth, handle_session_req},
- {<<"_oauth">>, couch_httpd_oauth, handle_oauth_req},
{<<"_up">>, chttpd_misc, handle_up_req},
{<<"_membership">>, mem3_httpd, handle_membership_req},
{<<"_db_updates">>, global_changes_httpd, handle_global_changes_req},
diff --git a/src/couch/test/couchdb_auth_tests.erl b/src/couch/test/couchdb_auth_tests.erl
index b2a490fed..ed2c064de 100644
--- a/src/couch/test/couchdb_auth_tests.erl
+++ b/src/couch/test/couchdb_auth_tests.erl
@@ -68,7 +68,7 @@ should_not_return_authenticated_field(_PortType, Url) ->
end).
should_return_list_of_handlers(backdoor, Url) ->
- ?_assertEqual([<<"oauth">>,<<"cookie">>,<<"default">>],
+ ?_assertEqual([<<"cookie">>,<<"default">>],
begin
couch_util:get_nested_json_value(session(Url), [
<<"info">>, <<"authentication_handlers">>])
diff --git a/src/couch/test/couchdb_vhosts_tests.erl b/src/couch/test/couchdb_vhosts_tests.erl
index d1da0635a..dfac73cb3 100644
--- a/src/couch/test/couchdb_vhosts_tests.erl
+++ b/src/couch/test/couchdb_vhosts_tests.erl
@@ -59,42 +59,6 @@ setup() ->
Url = "http://" ++ Addr ++ ":" ++ Port,
{Url, ?b2l(DbName)}.
-setup_oauth() ->
- DbName = ?tempdb(),
- {ok, Db} = couch_db:create(DbName, [?ADMIN_CTX]),
-
- config:set("couch_httpd_auth", "authentication_db",
- ?b2l(?tempdb()), false),
- config:set("oauth_token_users", "otoksec1", "joe", false),
- config:set("oauth_consumer_secrets", "consec1", "foo", false),
- config:set("oauth_token_secrets", "otoksec1", "foobar", false),
- config:set("couchdb", "default_security", "everyone", false),
- config:set("couch_httpd_auth", "require_valid_user", "true", false),
-
- ok = config:set(
- "vhosts", "oauth-example.com",
- "/" ++ ?b2l(DbName) ++ "/_design/test/_rewrite/foobar", false),
-
- DDoc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"_design/test">>},
- {<<"language">>, <<"javascript">>},
- {<<"rewrites">>, [
- {[
- {<<"from">>, <<"foobar">>},
- {<<"to">>, <<"_info">>}
- ]}
- ]}
- ]}),
- {ok, _} = couch_db:update_doc(Db, DDoc, []),
-
- couch_db:ensure_full_commit(Db),
- couch_db:close(Db),
-
- Addr = config:get("httpd", "bind_address", "127.0.0.1"),
- Port = integer_to_list(mochiweb_socket_server:get(couch_httpd, port)),
- Url = "http://" ++ Addr ++ ":" ++ Port,
- {Url, ?b2l(DbName)}.
-
teardown({_, DbName}) ->
ok = couch_server:delete(?l2b(DbName), []),
ok.
@@ -127,25 +91,6 @@ vhosts_test_() ->
}
}.
-oauth_test_() ->
- {
- "Virtual Hosts OAuth tests",
- {
- setup,
- fun test_util:start_couch/0, fun test_util:stop_couch/1,
- {
- foreach,
- fun setup_oauth/0, fun teardown/1,
- [
- fun should_require_auth/1,
- fun should_succeed_oauth/1,
- fun should_fail_oauth_with_wrong_credentials/1
- ]
- }
- }
- }.
-
-
should_return_database_info({Url, DbName}) ->
?_test(begin
ok = config:set("vhosts", "example.com", "/" ++ DbName, false),
@@ -351,90 +296,6 @@ should_return_path_for_vhost_with_wildcard_host({Url, DbName}) ->
end
end).
-should_require_auth({Url, _}) ->
- ?_test(begin
- case test_request:get(Url, [], [{host_header, "oauth-example.com"}]) of
- {ok, Code, _, Body} ->
- ?assertEqual(401, Code),
- {JsonBody} = jiffy:decode(Body),
- ?assertEqual(<<"unauthorized">>,
- couch_util:get_value(<<"error">>, JsonBody));
- Else ->
- erlang:error({assertion_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {reason, ?iofmt("Request failed: ~p", [Else])}]})
- end
- end).
-
-should_succeed_oauth({Url, _}) ->
- ?_test(begin
- AuthDbName = config:get("couch_httpd_auth", "authentication_db"),
- JoeDoc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"org.couchdb.user:joe">>},
- {<<"type">>, <<"user">>},
- {<<"name">>, <<"joe">>},
- {<<"roles">>, []},
- {<<"password_sha">>, <<"fe95df1ca59a9b567bdca5cbaf8412abd6e06121">>},
- {<<"salt">>, <<"4e170ffeb6f34daecfd814dfb4001a73">>}
- ]}),
- {ok, AuthDb} = couch_db:open_int(?l2b(AuthDbName), [?ADMIN_CTX]),
- {ok, _} = couch_db:update_doc(AuthDb, JoeDoc, [?ADMIN_CTX]),
-
- Host = "oauth-example.com",
- Consumer = {"consec1", "foo", hmac_sha1},
- SignedParams = oauth:sign(
- "GET", "http://" ++ Host ++ "/", [], Consumer, "otoksec1", "foobar"),
- OAuthUrl = oauth:uri(Url, SignedParams),
-
- case test_request:get(OAuthUrl, [], [{host_header, Host}]) of
- {ok, Code, _, Body} ->
- ?assertEqual(200, Code),
- {JsonBody} = jiffy:decode(Body),
- ?assertEqual(<<"test">>,
- couch_util:get_value(<<"name">>, JsonBody));
- Else ->
- erlang:error({assertion_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {reason, ?iofmt("Request failed: ~p", [Else])}]})
- end
- end).
-
-should_fail_oauth_with_wrong_credentials({Url, _}) ->
- ?_test(begin
- AuthDbName = config:get("couch_httpd_auth", "authentication_db"),
- JoeDoc = couch_doc:from_json_obj({[
- {<<"_id">>, <<"org.couchdb.user:joe">>},
- {<<"type">>, <<"user">>},
- {<<"name">>, <<"joe">>},
- {<<"roles">>, []},
- {<<"password_sha">>, <<"fe95df1ca59a9b567bdca5cbaf8412abd6e06121">>},
- {<<"salt">>, <<"4e170ffeb6f34daecfd814dfb4001a73">>}
- ]}),
- {ok, AuthDb} = couch_db:open_int(?l2b(AuthDbName), [?ADMIN_CTX]),
- {ok, _} = couch_db:update_doc(AuthDb, JoeDoc, [?ADMIN_CTX]),
-
- Host = "oauth-example.com",
- Consumer = {"consec1", "bad_secret", hmac_sha1},
- SignedParams = oauth:sign(
- "GET", "http://" ++ Host ++ "/", [], Consumer, "otoksec1", "foobar"),
- OAuthUrl = oauth:uri(Url, SignedParams),
-
- case test_request:get(OAuthUrl, [], [{host_header, Host}]) of
- {ok, Code, _, Body} ->
- ?assertEqual(401, Code),
- {JsonBody} = jiffy:decode(Body),
- ?assertEqual(<<"unauthorized">>,
- couch_util:get_value(<<"error">>, JsonBody));
- Else ->
- erlang:error({assertion_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {reason, ?iofmt("Request failed: ~p", [Else])}]})
- end
- end).
-
ensure_index_file() ->
Body = <<"<!DOCTYPE html>\n<html>\n<body>\nHello world\n</body>\n</html>">>,
file:write_file(filename:join([?TEMPDIR, "index.html"]), Body).
diff --git a/src/couch/test/fixtures/os_daemon_configer.escript b/src/couch/test/fixtures/os_daemon_configer.escript
index 3e02ef971..f146b8314 100755
--- a/src/couch/test/fixtures/os_daemon_configer.escript
+++ b/src/couch/test/fixtures/os_daemon_configer.escript
@@ -88,7 +88,6 @@ init_code_path() ->
Paths = [
"couchdb",
"jiffy",
- "erlang-oauth",
"ibrowse",
"mochiweb",
"snappy"
diff --git a/test/javascript/oauth.js b/test/javascript/oauth.js
deleted file mode 100644
index ada00a275..000000000
--- a/test/javascript/oauth.js
+++ /dev/null
@@ -1,511 +0,0 @@
-/*
- * Copyright 2008 Netflix, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* Here's some JavaScript software for implementing OAuth.
-
- This isn't as useful as you might hope. OAuth is based around
- allowing tools and websites to talk to each other. However,
- JavaScript running in web browsers is hampered by security
- restrictions that prevent code running on one website from
- accessing data stored or served on another.
-
- Before you start hacking, make sure you understand the limitations
- posed by cross-domain XMLHttpRequest.
-
- On the bright side, some platforms use JavaScript as their
- language, but enable the programmer to access other web sites.
- Examples include Google Gadgets, and Microsoft Vista Sidebar.
- For those platforms, this library should come in handy.
-*/
-
-// The HMAC-SHA1 signature method calls b64_hmac_sha1, defined by
-// http://pajhome.org.uk/crypt/md5/sha1.js
-
-/* An OAuth message is represented as an object like this:
- {method: "GET", action: "http://server.com/path", parameters: ...}
-
- The parameters may be either a map {name: value, name2: value2}
- or an Array of name-value pairs [[name, value], [name2, value2]].
- The latter representation is more powerful: it supports parameters
- in a specific sequence, or several parameters with the same name;
- for example [["a", 1], ["b", 2], ["a", 3]].
-
- Parameter names and values are NOT percent-encoded in an object.
- They must be encoded before transmission and decoded after reception.
- For example, this message object:
- {method: "GET", action: "http://server/path", parameters: {p: "x y"}}
- ... can be transmitted as an HTTP request that begins:
- GET /path?p=x%20y HTTP/1.0
- (This isn't a valid OAuth request, since it lacks a signature etc.)
- Note that the object "x y" is transmitted as x%20y. To encode
- parameters, you can call OAuth.addToURL, OAuth.formEncode or
- OAuth.getAuthorization.
-
- This message object model harmonizes with the browser object model for
- input elements of an form, whose value property isn't percent encoded.
- The browser encodes each value before transmitting it. For example,
- see consumer.setInputs in example/consumer.js.
- */
-var OAuth; if (OAuth == null) OAuth = {};
-
-OAuth.setProperties = function setProperties(into, from) {
- if (into != null && from != null) {
- for (var key in from) {
- into[key] = from[key];
- }
- }
- return into;
-}
-
-OAuth.setProperties(OAuth, // utility functions
-{
- percentEncode: function percentEncode(s) {
- if (s == null) {
- return "";
- }
- if (s instanceof Array) {
- var e = "";
- for (var i = 0; i < s.length; ++i) {
- if (e != "") e += '&';
- e += percentEncode(s[i]);
- }
- return e;
- }
- s = encodeURIComponent(s);
- // Now replace the values which encodeURIComponent doesn't do
- // encodeURIComponent ignores: - _ . ! ~ * ' ( )
- // OAuth dictates the only ones you can ignore are: - _ . ~
- // Source: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Functions:encodeURIComponent
- s = s.replace(/\!/g, "%21");
- s = s.replace(/\*/g, "%2A");
- s = s.replace(/\'/g, "%27");
- s = s.replace(/\(/g, "%28");
- s = s.replace(/\)/g, "%29");
- return s;
- }
-,
- decodePercent: function decodePercent(s) {
- if (s != null) {
- // Handle application/x-www-form-urlencoded, which is defined by
- // http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
- s = s.replace(/\+/g, " ");
- }
- return decodeURIComponent(s);
- }
-,
- /** Convert the given parameters to an Array of name-value pairs. */
- getParameterList: function getParameterList(parameters) {
- if (parameters == null) {
- return [];
- }
- if (typeof parameters != "object") {
- return decodeForm(parameters + "");
- }
- if (parameters instanceof Array) {
- return parameters;
- }
- var list = [];
- for (var p in parameters) {
- list.push([p, parameters[p]]);
- }
- return list;
- }
-,
- /** Convert the given parameters to a map from name to value. */
- getParameterMap: function getParameterMap(parameters) {
- if (parameters == null) {
- return {};
- }
- if (typeof parameters != "object") {
- return getParameterMap(decodeForm(parameters + ""));
- }
- if (parameters instanceof Array) {
- var map = {};
- for (var p = 0; p < parameters.length; ++p) {
- var key = parameters[p][0];
- if (map[key] === undefined) { // first value wins
- map[key] = parameters[p][1];
- }
- }
- return map;
- }
- return parameters;
- }
-,
- getParameter: function getParameter(parameters, name) {
- if (parameters instanceof Array) {
- for (var p = 0; p < parameters.length; ++p) {
- if (parameters[p][0] == name) {
- return parameters[p][1]; // first value wins
- }
- }
- } else {
- return OAuth.getParameterMap(parameters)[name];
- }
- return null;
- }
-,
- formEncode: function formEncode(parameters) {
- var form = "";
- var list = OAuth.getParameterList(parameters);
- for (var p = 0; p < list.length; ++p) {
- var value = list[p][1];
- if (value == null) value = "";
- if (form != "") form += '&';
- form += OAuth.percentEncode(list[p][0])
- +'='+ OAuth.percentEncode(value);
- }
- return form;
- }
-,
- decodeForm: function decodeForm(form) {
- var list = [];
- var nvps = form.split('&');
- for (var n = 0; n < nvps.length; ++n) {
- var nvp = nvps[n];
- if (nvp == "") {
- continue;
- }
- var equals = nvp.indexOf('=');
- var name;
- var value;
- if (equals < 0) {
- name = OAuth.decodePercent(nvp);
- value = null;
- } else {
- name = OAuth.decodePercent(nvp.substring(0, equals));
- value = OAuth.decodePercent(nvp.substring(equals + 1));
- }
- list.push([name, value]);
- }
- return list;
- }
-,
- setParameter: function setParameter(message, name, value) {
- var parameters = message.parameters;
- if (parameters instanceof Array) {
- for (var p = 0; p < parameters.length; ++p) {
- if (parameters[p][0] == name) {
- if (value === undefined) {
- parameters.splice(p, 1);
- } else {
- parameters[p][1] = value;
- value = undefined;
- }
- }
- }
- if (value !== undefined) {
- parameters.push([name, value]);
- }
- } else {
- parameters = OAuth.getParameterMap(parameters);
- parameters[name] = value;
- message.parameters = parameters;
- }
- }
-,
- setParameters: function setParameters(message, parameters) {
- var list = OAuth.getParameterList(parameters);
- for (var i = 0; i < list.length; ++i) {
- OAuth.setParameter(message, list[i][0], list[i][1]);
- }
- }
-,
- /** Fill in parameters to help construct a request message.
- This function doesn't fill in every parameter.
- The accessor object should be like:
- {consumerKey:'foo', consumerSecret:'bar', accessorSecret:'nurn', token:'krelm', tokenSecret:'blah'}
- The accessorSecret property is optional.
- */
- completeRequest: function completeRequest(message, accessor) {
- if (message.method == null) {
- message.method = "GET";
- }
- var map = OAuth.getParameterMap(message.parameters);
- if (map.oauth_consumer_key == null) {
- OAuth.setParameter(message, "oauth_consumer_key", accessor.consumerKey || "");
- }
- if (map.oauth_token == null && accessor.token != null) {
- OAuth.setParameter(message, "oauth_token", accessor.token);
- }
- if (map.oauth_version == null) {
- OAuth.setParameter(message, "oauth_version", "1.0");
- }
- if (map.oauth_timestamp == null) {
- OAuth.setParameter(message, "oauth_timestamp", OAuth.timestamp());
- }
- if (map.oauth_nonce == null) {
- OAuth.setParameter(message, "oauth_nonce", OAuth.nonce(6));
- }
- OAuth.SignatureMethod.sign(message, accessor);
- }
-,
- setTimestampAndNonce: function setTimestampAndNonce(message) {
- OAuth.setParameter(message, "oauth_timestamp", OAuth.timestamp());
- OAuth.setParameter(message, "oauth_nonce", OAuth.nonce(6));
- }
-,
- addToURL: function addToURL(url, parameters) {
- newURL = url;
- if (parameters != null) {
- var toAdd = OAuth.formEncode(parameters);
- if (toAdd.length > 0) {
- var q = url.indexOf('?');
- if (q < 0) newURL += '?';
- else newURL += '&';
- newURL += toAdd;
- }
- }
- return newURL;
- }
-,
- /** Construct the value of the Authorization header for an HTTP request. */
- getAuthorizationHeader: function getAuthorizationHeader(realm, parameters) {
- var header = 'OAuth realm="' + OAuth.percentEncode(realm) + '"';
- var list = OAuth.getParameterList(parameters);
- for (var p = 0; p < list.length; ++p) {
- var parameter = list[p];
- var name = parameter[0];
- if (name.indexOf("oauth_") == 0) {
- header += ',' + OAuth.percentEncode(name) + '="' + OAuth.percentEncode(parameter[1]) + '"';
- }
- }
- return header;
- }
-,
- timestamp: function timestamp() {
- var d = new Date();
- return Math.floor(d.getTime()/1000);
- }
-,
- nonce: function nonce(length) {
- var chars = OAuth.nonce.CHARS;
- var result = "";
- for (var i = 0; i < length; ++i) {
- var rnum = Math.floor(Math.random() * chars.length);
- result += chars.substring(rnum, rnum+1);
- }
- return result;
- }
-});
-
-OAuth.nonce.CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
-
-/** Define a constructor function,
- without causing trouble to anyone who was using it as a namespace.
- That is, if parent[name] already existed and had properties,
- copy those properties into the new constructor.
- */
-OAuth.declareClass = function declareClass(parent, name, newConstructor) {
- var previous = parent[name];
- parent[name] = newConstructor;
- if (newConstructor != null && previous != null) {
- for (var key in previous) {
- if (key != "prototype") {
- newConstructor[key] = previous[key];
- }
- }
- }
- return newConstructor;
-}
-
-/** An abstract algorithm for signing messages. */
-OAuth.declareClass(OAuth, "SignatureMethod", function OAuthSignatureMethod(){});
-
-OAuth.setProperties(OAuth.SignatureMethod.prototype, // instance members
-{
- /** Add a signature to the message. */
- sign: function sign(message) {
- var baseString = OAuth.SignatureMethod.getBaseString(message);
- var signature = this.getSignature(baseString);
- OAuth.setParameter(message, "oauth_signature", signature);
- return signature; // just in case someone's interested
- }
-,
- /** Set the key string for signing. */
- initialize: function initialize(name, accessor) {
- var consumerSecret;
- if (accessor.accessorSecret != null
- && name.length > 9
- && name.substring(name.length-9) == "-Accessor")
- {
- consumerSecret = accessor.accessorSecret;
- } else {
- consumerSecret = accessor.consumerSecret;
- }
- this.key = OAuth.percentEncode(consumerSecret)
- +"&"+ OAuth.percentEncode(accessor.tokenSecret);
- }
-});
-
-/* SignatureMethod expects an accessor object to be like this:
- {tokenSecret: "lakjsdflkj...", consumerSecret: "QOUEWRI..", accessorSecret: "xcmvzc..."}
- The accessorSecret property is optional.
- */
-// Class members:
-OAuth.setProperties(OAuth.SignatureMethod, // class members
-{
- sign: function sign(message, accessor) {
- var name = OAuth.getParameterMap(message.parameters).oauth_signature_method;
- if (name == null || name == "") {
- name = "HMAC-SHA1";
- OAuth.setParameter(message, "oauth_signature_method", name);
- }
- OAuth.SignatureMethod.newMethod(name, accessor).sign(message);
- }
-,
- /** Instantiate a SignatureMethod for the given method name. */
- newMethod: function newMethod(name, accessor) {
- var impl = OAuth.SignatureMethod.REGISTERED[name];
- if (impl != null) {
- var method = new impl();
- method.initialize(name, accessor);
- return method;
- }
- var err = new Error("signature_method_rejected");
- var acceptable = "";
- for (var r in OAuth.SignatureMethod.REGISTERED) {
- if (acceptable != "") acceptable += '&';
- acceptable += OAuth.percentEncode(r);
- }
- err.oauth_acceptable_signature_methods = acceptable;
- throw err;
- }
-,
- /** A map from signature method name to constructor. */
- REGISTERED : {}
-,
- /** Subsequently, the given constructor will be used for the named methods.
- The constructor will be called with no parameters.
- The resulting object should usually implement getSignature(baseString).
- You can easily define such a constructor by calling makeSubclass, below.
- */
- registerMethodClass: function registerMethodClass(names, classConstructor) {
- for (var n = 0; n < names.length; ++n) {
- OAuth.SignatureMethod.REGISTERED[names[n]] = classConstructor;
- }
- }
-,
- /** Create a subclass of OAuth.SignatureMethod, with the given getSignature function. */
- makeSubclass: function makeSubclass(getSignatureFunction) {
- var superClass = OAuth.SignatureMethod;
- var subClass = function() {
- superClass.call(this);
- };
- subClass.prototype = new superClass();
- // Delete instance variables from prototype:
- // delete subclass.prototype... There aren't any.
- subClass.prototype.getSignature = getSignatureFunction;
- subClass.prototype.constructor = subClass;
- return subClass;
- }
-,
- getBaseString: function getBaseString(message) {
- var URL = message.action;
- var q = URL.indexOf('?');
- var parameters;
- if (q < 0) {
- parameters = message.parameters;
- } else {
- // Combine the URL query string with the other parameters:
- parameters = OAuth.decodeForm(URL.substring(q + 1));
- var toAdd = OAuth.getParameterList(message.parameters);
- for (var a = 0; a < toAdd.length; ++a) {
- parameters.push(toAdd[a]);
- }
- }
- return OAuth.percentEncode(message.method.toUpperCase())
- +'&'+ OAuth.percentEncode(OAuth.SignatureMethod.normalizeUrl(URL))
- +'&'+ OAuth.percentEncode(OAuth.SignatureMethod.normalizeParameters(parameters));
- }
-,
- normalizeUrl: function normalizeUrl(url) {
- var uri = OAuth.SignatureMethod.parseUri(url);
- var scheme = uri.protocol.toLowerCase();
- var authority = uri.authority.toLowerCase();
- var dropPort = (scheme == "http" && uri.port == 80)
- || (scheme == "https" && uri.port == 443);
- if (dropPort) {
- // find the last : in the authority
- var index = authority.lastIndexOf(":");
- if (index >= 0) {
- authority = authority.substring(0, index);
- }
- }
- var path = uri.path;
- if (!path) {
- path = "/"; // conforms to RFC 2616 section 3.2.2
- }
- // we know that there is no query and no fragment here.
- return scheme + "://" + authority + path;
- }
-,
- parseUri: function parseUri (str) {
- /* This function was adapted from parseUri 1.2.1
- http://stevenlevithan.com/demo/parseuri/js/assets/parseuri.js
- */
- var o = {key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
- parser: {strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/ }};
- var m = o.parser.strict.exec(str);
- var uri = {};
- var i = 14;
- while (i--) uri[o.key[i]] = m[i] || "";
- return uri;
- }
-,
- normalizeParameters: function normalizeParameters(parameters) {
- if (parameters == null) {
- return "";
- }
- var list = OAuth.getParameterList(parameters);
- var sortable = [];
- for (var p = 0; p < list.length; ++p) {
- var nvp = list[p];
- if (nvp[0] != "oauth_signature") {
- sortable.push([ OAuth.percentEncode(nvp[0])
- + " " // because it comes before any character that can appear in a percentEncoded string.
- + OAuth.percentEncode(nvp[1])
- , nvp]);
- }
- }
- sortable.sort(function(a,b) {
- if (a[0] < b[0]) return -1;
- if (a[0] > b[0]) return 1;
- return 0;
- });
- var sorted = [];
- for (var s = 0; s < sortable.length; ++s) {
- sorted.push(sortable[s][1]);
- }
- return OAuth.formEncode(sorted);
- }
-});
-
-OAuth.SignatureMethod.registerMethodClass(["PLAINTEXT", "PLAINTEXT-Accessor"],
- OAuth.SignatureMethod.makeSubclass(
- function getSignature(baseString) {
- return this.key;
- }
- ));
-
-OAuth.SignatureMethod.registerMethodClass(["HMAC-SHA1", "HMAC-SHA1-Accessor"],
- OAuth.SignatureMethod.makeSubclass(
- function getSignature(baseString) {
- b64pad = '=';
- var signature = b64_hmac_sha1(this.key, baseString);
- return signature;
- }
- ));
diff --git a/test/javascript/run b/test/javascript/run
index 7f366ebed..f7659b0f2 100755
--- a/test/javascript/run
+++ b/test/javascript/run
@@ -29,7 +29,6 @@ COUCHJS = "src/couch/priv/couchjs"
SCRIPTS = """
test/javascript/json2.js
test/javascript/sha1.js
- test/javascript/oauth.js
test/javascript/couch.js
test/javascript/replicator_db_inc.js
test/javascript/couch_test_runner.js
diff --git a/test/javascript/tests/oauth_users_db.js b/test/javascript/tests/oauth_users_db.js
deleted file mode 100644
index 6e4b3de33..000000000
--- a/test/javascript/tests/oauth_users_db.js
+++ /dev/null
@@ -1,168 +0,0 @@
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy
-// of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-couchTests.oauth_users_db = function(debug) {
- return console.log('TODO: oauth not available on clustered interface');
- // This tests OAuth authentication using the _users DB instead of the ini
- // configuration for storing OAuth tokens and secrets.
-
- if (debug) debugger;
-
- var users_db_name = get_random_db_name();
- var usersDb = new CouchDB(users_db_name, {"X-Couch-Full-Commit":"false"});
- usersDb.createDb();
-
- var db_name = get_random_db_name();
- var db = new CouchDB(db_name, {"X-Couch-Full-Commit":"false"});
- db.createDb();
-
- var host = CouchDB.host;
- var authorization_url = "/_oauth/authorize";
-
-
- // Simple secret key generator
- function generateSecret(length) {
- var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- var secret = '';
- for (var i = 0; i < length; i++) {
- secret += tab.charAt(Math.floor(Math.random() * 64));
- }
- return secret;
- }
-
-
- function oauthRequest(method, path, message, accessor) {
- message.action = path;
- message.method = method || 'GET';
- OAuth.SignatureMethod.sign(message, accessor);
- var parameters = message.parameters;
- if (method == "POST" || method == "GET") {
- if (method == "GET") {
- return CouchDB.request("GET", OAuth.addToURL(path, parameters));
- } else {
- return CouchDB.request("POST", path, {
- headers: {"Content-Type": "application/x-www-form-urlencoded"},
- body: OAuth.formEncode(parameters)
- });
- }
- } else {
- return CouchDB.request(method, path, {
- headers: {Authorization: OAuth.getAuthorizationHeader('', parameters)}
- });
- }
- }
-
-
- // this function will be called on the modified server
- var testFun = function () {
- var fdmanana = CouchDB.prepareUserDoc({
- name: "fdmanana",
- roles: ["dev"],
- oauth: {
- consumer_keys: {
- "key_foo": "bar",
- "key_xpto": "mars"
- },
- tokens: {
- "salut": "ola",
- "tok1": "123"
- }
- }
- }, "qwerty");
- TEquals(true, usersDb.save(fdmanana).ok);
-
- var signatureMethods = ["PLAINTEXT", "HMAC-SHA1"];
- var message, xhr, responseMessage, accessor, data;
-
- for (var i = 0; i < signatureMethods.length; i++) {
- message = {
- parameters: {
- oauth_signature_method: signatureMethods[i],
- oauth_consumer_key: "key_foo",
- oauth_token: "tok1",
- oauth_version: "1.0"
- }
- };
- accessor = {
- consumerSecret: "bar",
- tokenSecret: "123"
- };
-
- xhr = oauthRequest("GET", CouchDB.protocol + host + "/_oauth/request_token",
- message, accessor
- );
- TEquals(200, xhr.status);
-
- responseMessage = OAuth.decodeForm(xhr.responseText);
-
- // Obtaining User Authorization
- // Only needed for 3-legged OAuth
- //xhr = CouchDB.request(
- // "GET", authorization_url + '?oauth_token=' + responseMessage.oauth_token);
- //TEquals(200, xhr.status);
-
- xhr = oauthRequest(
- "GET", CouchDB.protocol + host + "/_session", message, accessor);
- TEquals(200, xhr.status);
- data = JSON.parse(xhr.responseText);
- TEquals(true, data.ok);
- TEquals("object", typeof data.userCtx);
- TEquals("fdmanana", data.userCtx.name);
- TEquals("dev", data.userCtx.roles[0]);
- TEquals("oauth", data.info.authenticated);
-
- // test invalid token
- message.parameters.oauth_token = "not a token!";
- xhr = oauthRequest("GET", CouchDB.protocol + host + "/_session",
- message, accessor
- );
- TEquals(400, xhr.status, "Request should be invalid.");
-
- // test invalid secret
- message.parameters.oauth_token = "tok1";
- accessor.tokenSecret = "badone";
- xhr = oauthRequest("GET", CouchDB.protocol + host + "/_session",
- message, accessor
- );
- data = JSON.parse(xhr.responseText);
- TEquals(null, data.userCtx.name);
- TEquals(1, data.userCtx.roles.length);
- TEquals("_admin", data.userCtx.roles[0]);
- TEquals(true, data.info.authentication_handlers.indexOf("default") >= 0);
- TEquals("default", data.info.authenticated);
- }
- };
-
-
- usersDb.deleteDb();
-
- run_on_modified_server(
- [
- {section: "httpd",
- key: "WWW-Authenticate", value: 'OAuth'},
- {section: "couch_httpd_auth",
- key: "secret", value: generateSecret(64)},
- {section: "couch_httpd_auth",
- key: "authentication_db", value: usersDb.name},
- {section: "couch_httpd_oauth",
- key: "use_users_db", value: "true"},
- {section: "httpd", key: "authentication_handlers",
- value: "{couch_httpd_oauth, oauth_authentication_handler}, " +
- "{couch_httpd_auth, default_authentication_handler}"}
- ],
- testFun
- );
-
- // cleanup
- usersDb.deleteDb();
- db.deleteDb();
-};
diff --git a/test/javascript/tests/replicator_db_security.js b/test/javascript/tests/replicator_db_security.js
index 2fc0f6c8a..ffb5c4036 100644
--- a/test/javascript/tests/replicator_db_security.js
+++ b/test/javascript/tests/replicator_db_security.js
@@ -344,34 +344,6 @@ couchTests.replicator_db_security = function(debug) {
doc.source, "source field contains credentials (doc from _changes)");
CouchDB.logout();
- var fdmananaRepDocOAuth = {
- _id: "fdmanana-rep-doc-oauth",
- source: dbC.name,
- target: {
- url: "http://" + CouchDB.host + "/" + dbA.name,
- oauth: {
- token: "abc",
- token_secret: "foo",
- consumer_key: "123",
- consumer_secret: "321"
- }
- },
- user_ctx: { name: "fdmanana", roles: [] }
- };
-
- var result = save_as(repDb, fdmananaRepDocOAuth, "fdmanana");
- TEquals(true, result.ok, "should create rep doc");
- waitForDocPos(repDb, fdmananaRepDocOAuth._id, 3);
- fdmananaRepDocOAuth = open_as(repDb, fdmananaRepDocOAuth._id, "fdmanana");
- TEquals("fdmanana", fdmananaRepDocOAuth.owner, "should assign correct owner");
- TEquals("object", typeof fdmananaRepDocOAuth.target.oauth,
- "target field has oauth credentials");
-
- fdmananaRepDocOAuth = open_as(repDb, fdmananaRepDocOAuth._id, "jchris");
- TEquals("fdmanana", fdmananaRepDocOAuth.owner, "should assign correct owner");
- TEquals("undefined", typeof fdmananaRepDocOAuth.target.oauth,
- "target field doesn't have oauth credentials");
-
// ensure "old" replicator docs still work
// done in replicator_db.js?