summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason David Davies <jasondavies@apache.org>2010-01-12 19:29:23 +0000
committerJason David Davies <jasondavies@apache.org>2010-01-12 19:29:23 +0000
commitb9f59ca2986075112ff1de42320168affa10921e (patch)
tree5e2a443b255803cd1c4f75689055db2099fd9c4e
parent84fd4ae77ef7b4c53a9159394747676a1c65ab51 (diff)
Add utility for verifying hashes.
git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@898477 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--src/couchdb/couch_httpd_auth.erl32
-rw-r--r--src/couchdb/couch_util.erl17
-rw-r--r--src/erlang-oauth/oauth_hmac_sha1.erl2
-rw-r--r--src/erlang-oauth/oauth_plaintext.erl2
-rwxr-xr-xtest/etap/040-util.t14
5 files changed, 51 insertions, 16 deletions
diff --git a/src/couchdb/couch_httpd_auth.erl b/src/couchdb/couch_httpd_auth.erl
index a1222df4..5c87f427 100644
--- a/src/couchdb/couch_httpd_auth.erl
+++ b/src/couchdb/couch_httpd_auth.erl
@@ -71,8 +71,9 @@ default_authentication_handler(Req) ->
UserProps ->
UserSalt = proplists:get_value(<<"salt">>, UserProps, <<>>),
PasswordHash = hash_password(?l2b(Pass), UserSalt),
- case proplists:get_value(<<"password_sha">>, UserProps, nil) of
- ExpectedHash when ExpectedHash == PasswordHash ->
+ ExpectedHash = proplists:get_value(<<"password_sha">>, UserProps, nil),
+ case couch_util:verify(ExpectedHash, PasswordHash) of
+ true ->
Req#httpd{user_ctx=#user_ctx{
name=?l2b(User),
roles=proplists:get_value(<<"roles">>, UserProps, []),
@@ -268,15 +269,19 @@ cookie_authentication_handler(#httpd{mochi_req=MochiReq}=Req) ->
Timeout = to_int(couch_config:get("couch_httpd_auth", "timeout", 600)),
?LOG_DEBUG("timeout ~p", [Timeout]),
case (catch erlang:list_to_integer(TimeStr, 16)) of
- TimeStamp when CurrentTime < TimeStamp + Timeout
- andalso ExpectedHash == Hash ->
- TimeLeft = TimeStamp + Timeout - CurrentTime,
- ?LOG_DEBUG("Successful cookie auth as: ~p", [User]),
- Req#httpd{user_ctx=#user_ctx{
- name=?l2b(User),
- roles=proplists:get_value(<<"roles">>, UserProps, []),
- user_doc=proplists:get_value(<<"user_doc">>, UserProps, null)
- }, auth={FullSecret, TimeLeft < Timeout*0.9}};
+ TimeStamp when CurrentTime < TimeStamp + Timeout ->
+ case couch_util:verify(ExpectedHash, Hash) of
+ true ->
+ TimeLeft = TimeStamp + Timeout - CurrentTime,
+ ?LOG_DEBUG("Successful cookie auth as: ~p", [User]),
+ Req#httpd{user_ctx=#user_ctx{
+ name=?l2b(User),
+ roles=proplists:get_value(<<"roles">>, UserProps, []),
+ user_doc=proplists:get_value(<<"user_doc">>, UserProps, null)
+ }, auth={FullSecret, TimeLeft < Timeout*0.9}};
+ _Else ->
+ Req
+ end;
_Else ->
Req
end
@@ -344,8 +349,9 @@ handle_session_req(#httpd{method='POST', mochi_req=MochiReq}=Req) ->
end,
UserSalt = proplists:get_value(<<"salt">>, User, <<>>),
PasswordHash = hash_password(Password, UserSalt),
- case proplists:get_value(<<"password_sha">>, User, nil) of
- ExpectedHash when ExpectedHash == PasswordHash ->
+ ExpectedHash = proplists:get_value(<<"password_sha">>, User, nil),
+ case couch_util:verify(ExpectedHash, PasswordHash) of
+ true ->
% setup the session cookie
Secret = ?l2b(ensure_cookie_auth_secret()),
{NowMS, NowS, _} = erlang:now(),
diff --git a/src/couchdb/couch_util.erl b/src/couchdb/couch_util.erl
index 6edfb781..45d1d336 100644
--- a/src/couchdb/couch_util.erl
+++ b/src/couchdb/couch_util.erl
@@ -21,6 +21,7 @@
-export([file_read_size/1, get_nested_json_value/2, json_user_ctx/1]).
-export([to_binary/1, to_integer/1, to_list/1, url_encode/1]).
-export([json_encode/1, json_decode/1]).
+-export([verify/2]).
-include("couch_db.hrl").
-include_lib("kernel/include/file.hrl").
@@ -423,3 +424,19 @@ json_decode(V) ->
_Type:_Error ->
throw({invalid_json,V})
end.
+
+verify([X|RestX], [Y|RestY], Result) ->
+ verify(RestX, RestY, (X bxor Y) bor Result);
+verify([], [], Result) ->
+ Result == 0.
+
+verify(<<X/binary>>, <<Y/binary>>) ->
+ verify(?b2l(X), ?b2l(Y));
+verify(X, Y) when is_list(X) and is_list(Y) ->
+ case length(X) == length(Y) of
+ true ->
+ verify(X, Y, 0);
+ false ->
+ false
+ end;
+verify(_X, _Y) -> false.
diff --git a/src/erlang-oauth/oauth_hmac_sha1.erl b/src/erlang-oauth/oauth_hmac_sha1.erl
index 69064edd..79d59f37 100644
--- a/src/erlang-oauth/oauth_hmac_sha1.erl
+++ b/src/erlang-oauth/oauth_hmac_sha1.erl
@@ -8,4 +8,4 @@ signature(BaseString, CS, TS) ->
base64:encode_to_string(crypto:sha_mac(Key, BaseString)).
verify(Signature, BaseString, CS, TS) ->
- Signature =:= signature(BaseString, CS, TS).
+ couch_util:verify(signature(BaseString, CS, TS), Signature).
diff --git a/src/erlang-oauth/oauth_plaintext.erl b/src/erlang-oauth/oauth_plaintext.erl
index d8085e02..41a1e9b2 100644
--- a/src/erlang-oauth/oauth_plaintext.erl
+++ b/src/erlang-oauth/oauth_plaintext.erl
@@ -7,4 +7,4 @@ signature(CS, TS) ->
oauth_uri:calate("&", [CS, TS]).
verify(Signature, CS, TS) ->
- Signature =:= signature(CS, TS).
+ couch_util:verify(signature(CS, TS), Signature).
diff --git a/test/etap/040-util.t b/test/etap/040-util.t
index 6d6da2c1..4500d38a 100755
--- a/test/etap/040-util.t
+++ b/test/etap/040-util.t
@@ -17,7 +17,7 @@ main(_) ->
test_util:init_code_path(),
application:start(crypto),
- etap:plan(11),
+ etap:plan(16),
case (catch test()) of
ok ->
etap:end_tests();
@@ -88,4 +88,16 @@ test() ->
etap:ok(not couch_util:should_flush(),
"Checking to flush invokes GC."),
+ % verify
+ etap:is(true, couch_util:verify("It4Vooya", "It4Vooya"),
+ "String comparison."),
+ etap:is(false, couch_util:verify("It4VooyaX", "It4Vooya"),
+ "String comparison (unequal lengths)."),
+ etap:is(true, couch_util:verify(<<"ahBase3r">>, <<"ahBase3r">>),
+ "Binary comparison."),
+ etap:is(false, couch_util:verify(<<"ahBase3rX">>, <<"ahBase3r">>),
+ "Binary comparison (unequal lengths)."),
+ etap:is(false, couch_util:verify(nil, <<"ahBase3r">>),
+ "Binary comparison with atom."),
+
ok.