couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dav...@apache.org
Subject [01/12] oauth commit: updated refs/heads/import-master to db23ab2
Date Wed, 12 Feb 2014 06:22:19 GMT
Updated Branches:
  refs/heads/import-master [created] db23ab232


Initial check-in of OAuth and cookie authentication.

git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@800938 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/couchdb-oauth/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-oauth/commit/06abc695
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-oauth/tree/06abc695
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-oauth/diff/06abc695

Branch: refs/heads/import-master
Commit: 06abc6954e26b4517ed7ed34b7063f0d96cc0732
Parents: 
Author: Damien F. Katz <damien@apache.org>
Authored: Tue Aug 4 19:50:46 2009 +0000
Committer: Damien F. Katz <damien@apache.org>
Committed: Tue Aug 4 19:50:46 2009 +0000

----------------------------------------------------------------------
 Makefile.am         |  47 +++++++++++++++++++++
 oauth.app           |  20 +++++++++
 oauth.erl           | 107 +++++++++++++++++++++++++++++++++++++++++++++++
 oauth_hmac_sha1.erl |  11 +++++
 oauth_http.erl      |  22 ++++++++++
 oauth_plaintext.erl |  10 +++++
 oauth_rsa_sha1.erl  |  30 +++++++++++++
 oauth_unix.erl      |  16 +++++++
 oauth_uri.erl       |  88 ++++++++++++++++++++++++++++++++++++++
 9 files changed, 351 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-oauth/blob/06abc695/Makefile.am
----------------------------------------------------------------------
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..e20bf2b
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,47 @@
+## 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.
+
+oauthebindir = $(localerlanglibdir)/erlang-oauth/ebin
+
+oauth_file_collection = \
+    oauth.erl \
+    oauth_hmac_sha1.erl \
+    oauth_http.erl \
+    oauth_plaintext.erl \
+    oauth_rsa_sha1.erl \
+    oauth_unix.erl \
+    oauth_uri.erl
+
+oauthebin_static_file = oauth.app
+
+oauthebin_make_generated_file_list = \
+    oauth.beam \
+    oauth_hmac_sha1.beam \
+    oauth_http.beam \
+    oauth_plaintext.beam \
+    oauth_rsa_sha1.beam \
+    oauth_unix.beam \
+    oauth_uri.beam
+
+oauthebin_DATA = \
+    $(oauthebin_static_file) \
+    $(oauthebin_make_generated_file_list)
+
+EXTRA_DIST =  \
+    $(oauth_file_collection) \
+    $(oauthebin_static_file)
+
+CLEANFILES = \
+    $(oauthebin_make_generated_file_list)
+
+%.beam: %.erl
+	$(ERLC) $(ERLC_FLAGS) $<

http://git-wip-us.apache.org/repos/asf/couchdb-oauth/blob/06abc695/oauth.app
----------------------------------------------------------------------
diff --git a/oauth.app b/oauth.app
new file mode 100644
index 0000000..6357b9b
--- /dev/null
+++ b/oauth.app
@@ -0,0 +1,20 @@
+{application, oauth, [
+  {description, "Erlang OAuth implementation"},
+  {vsn, "dev"},
+  {modules, [
+    oauth,
+    oauth_hmac_sha1,
+    oauth_http,
+    oauth_plaintext,
+    oauth_rsa_sha1,
+    oauth_unix,
+    oauth_uri
+  ]},
+  {registered, []},
+  {applications, [
+    kernel,
+    stdlib,
+    crypto,
+    inets
+  ]}
+]}.

http://git-wip-us.apache.org/repos/asf/couchdb-oauth/blob/06abc695/oauth.erl
----------------------------------------------------------------------
diff --git a/oauth.erl b/oauth.erl
new file mode 100644
index 0000000..866655c
--- /dev/null
+++ b/oauth.erl
@@ -0,0 +1,107 @@
+-module(oauth).
+
+-export(
+  [ get/5
+  , header/1
+  , post/5
+  , signature/5
+  , signature_base_string/3
+  , signed_params/6
+  , token/1
+  , token_secret/1
+  , uri/2
+  , verify/6
+  ]).
+
+
+get(URL, ExtraParams, Consumer, Token, TokenSecret) ->
+  SignedParams = signed_params("GET", URL, ExtraParams, Consumer, Token, TokenSecret),
+  oauth_http:get(uri(URL, SignedParams)).
+
+post(URL, ExtraParams, Consumer, Token, TokenSecret) ->
+  SignedParams = signed_params("POST", URL, ExtraParams, Consumer, Token, TokenSecret),
+  oauth_http:post(URL, oauth_uri:params_to_string(SignedParams)).
+
+uri(Base, []) ->
+  Base;
+uri(Base, Params) ->
+  lists:concat([Base, "?", oauth_uri:params_to_string(Params)]).
+
+header(Params) ->
+  {"Authorization", "OAuth " ++ oauth_uri:params_to_header_string(Params)}.
+
+token(Params) ->
+  proplists:get_value("oauth_token", Params).
+
+token_secret(Params) ->
+  proplists:get_value("oauth_token_secret", Params).
+
+verify(Signature, HttpMethod, URL, Params, Consumer, TokenSecret) ->
+  case signature_method(Consumer) of
+    plaintext ->
+      oauth_plaintext:verify(Signature, consumer_secret(Consumer), TokenSecret);
+    hmac_sha1 ->
+      BaseString = signature_base_string(HttpMethod, URL, Params),
+      oauth_hmac_sha1:verify(Signature, BaseString, consumer_secret(Consumer), TokenSecret);
+    rsa_sha1 ->
+      BaseString = signature_base_string(HttpMethod, URL, Params),
+      oauth_rsa_sha1:verify(Signature, BaseString, consumer_secret(Consumer))
+  end.
+
+signed_params(HttpMethod, URL, ExtraParams, Consumer, Token, TokenSecret) ->
+  Params = token_param(Token, params(Consumer, ExtraParams)),
+  [{"oauth_signature", signature(HttpMethod, URL, Params, Consumer, TokenSecret)}|Params].
+
+signature(HttpMethod, URL, Params, Consumer, TokenSecret) ->
+  case signature_method(Consumer) of
+    plaintext ->
+      oauth_plaintext:signature(consumer_secret(Consumer), TokenSecret);
+    hmac_sha1 ->
+      BaseString = signature_base_string(HttpMethod, URL, Params),
+      oauth_hmac_sha1:signature(BaseString, consumer_secret(Consumer), TokenSecret);
+    rsa_sha1 ->
+      BaseString = signature_base_string(HttpMethod, URL, Params),
+      oauth_rsa_sha1:signature(BaseString, consumer_secret(Consumer))
+  end.
+
+signature_base_string(HttpMethod, URL, Params) ->
+  NormalizedURL = oauth_uri:normalize(URL),
+  NormalizedParams = oauth_uri:params_to_string(lists:sort(Params)),
+  oauth_uri:calate("&", [HttpMethod, NormalizedURL, NormalizedParams]).
+
+token_param("", Params) ->
+  Params;
+token_param(Token, Params) ->
+  [{"oauth_token", Token}|Params].
+
+params(Consumer, Params) ->
+  Nonce = base64:encode_to_string(crypto:rand_bytes(32)), % cf. ruby-oauth
+  params(Consumer, oauth_unix:timestamp(), Nonce, Params).
+
+params(Consumer, Timestamp, Nonce, Params) ->
+  [ {"oauth_version", "1.0"}
+  , {"oauth_nonce", Nonce}
+  , {"oauth_timestamp", integer_to_list(Timestamp)}
+  , {"oauth_signature_method", signature_method_string(Consumer)}
+  , {"oauth_consumer_key", consumer_key(Consumer)}
+  | Params
+  ].
+
+signature_method_string(Consumer) ->
+  case signature_method(Consumer) of
+    plaintext ->
+      "PLAINTEXT";
+    hmac_sha1 ->
+      "HMAC-SHA1";
+    rsa_sha1 ->
+      "RSA-SHA1"
+  end.
+
+signature_method(_Consumer={_, _, Method}) ->
+  Method.
+
+consumer_secret(_Consumer={_, Secret, _}) ->
+  Secret.
+
+consumer_key(_Consumer={Key, _, _}) ->
+  Key.

http://git-wip-us.apache.org/repos/asf/couchdb-oauth/blob/06abc695/oauth_hmac_sha1.erl
----------------------------------------------------------------------
diff --git a/oauth_hmac_sha1.erl b/oauth_hmac_sha1.erl
new file mode 100644
index 0000000..69064ed
--- /dev/null
+++ b/oauth_hmac_sha1.erl
@@ -0,0 +1,11 @@
+-module(oauth_hmac_sha1).
+
+-export([signature/3, verify/4]).
+
+
+signature(BaseString, CS, TS) ->
+  Key = oauth_uri:calate("&", [CS, TS]),
+  base64:encode_to_string(crypto:sha_mac(Key, BaseString)).
+
+verify(Signature, BaseString, CS, TS) ->
+  Signature =:= signature(BaseString, CS, TS).

http://git-wip-us.apache.org/repos/asf/couchdb-oauth/blob/06abc695/oauth_http.erl
----------------------------------------------------------------------
diff --git a/oauth_http.erl b/oauth_http.erl
new file mode 100644
index 0000000..bf5a4ba
--- /dev/null
+++ b/oauth_http.erl
@@ -0,0 +1,22 @@
+-module(oauth_http).
+
+-export([get/1, post/2, response_params/1, response_body/1, response_code/1]).
+
+
+get(URL) ->
+  request(get, {URL, []}).
+
+post(URL, Data) ->
+  request(post, {URL, [], "application/x-www-form-urlencoded", Data}).
+
+request(Method, Request) ->
+  http:request(Method, Request, [{autoredirect, false}], []).
+
+response_params(Response) ->
+  oauth_uri:params_from_string(response_body(Response)).
+
+response_body({{_, _, _}, _, Body}) ->
+  Body.
+
+response_code({{_, Code, _}, _, _}) ->
+  Code.

http://git-wip-us.apache.org/repos/asf/couchdb-oauth/blob/06abc695/oauth_plaintext.erl
----------------------------------------------------------------------
diff --git a/oauth_plaintext.erl b/oauth_plaintext.erl
new file mode 100644
index 0000000..d8085e0
--- /dev/null
+++ b/oauth_plaintext.erl
@@ -0,0 +1,10 @@
+-module(oauth_plaintext).
+
+-export([signature/2, verify/3]).
+
+
+signature(CS, TS) ->
+  oauth_uri:calate("&", [CS, TS]).
+
+verify(Signature, CS, TS) ->
+  Signature =:= signature(CS, TS).

http://git-wip-us.apache.org/repos/asf/couchdb-oauth/blob/06abc695/oauth_rsa_sha1.erl
----------------------------------------------------------------------
diff --git a/oauth_rsa_sha1.erl b/oauth_rsa_sha1.erl
new file mode 100644
index 0000000..6f4828e
--- /dev/null
+++ b/oauth_rsa_sha1.erl
@@ -0,0 +1,30 @@
+-module(oauth_rsa_sha1).
+
+-export([signature/2, verify/3]).
+
+-include_lib("public_key/include/public_key.hrl").
+
+
+signature(BaseString, PrivateKeyPath) ->
+  {ok, [Info]} = public_key:pem_to_der(PrivateKeyPath),
+  {ok, PrivateKey} = public_key:decode_private_key(Info),
+  base64:encode_to_string(public_key:sign(list_to_binary(BaseString), PrivateKey)).
+
+verify(Signature, BaseString, PublicKey) ->
+  public_key:verify_signature(to_binary(BaseString), sha, base64:decode(Signature), public_key(PublicKey)).
+
+to_binary(Term) when is_list(Term) ->
+  list_to_binary(Term);
+to_binary(Term) when is_binary(Term) ->
+  Term.
+
+public_key(Path) when is_list(Path) ->
+  {ok, [{cert, DerCert, not_encrypted}]} = public_key:pem_to_der(Path),
+  {ok, Cert} = public_key:pkix_decode_cert(DerCert, otp),
+  public_key(Cert);
+public_key(#'OTPCertificate'{tbsCertificate=Cert}) ->
+  public_key(Cert);
+public_key(#'OTPTBSCertificate'{subjectPublicKeyInfo=Info}) ->
+  public_key(Info);
+public_key(#'OTPSubjectPublicKeyInfo'{subjectPublicKey=Key}) ->
+  Key.

http://git-wip-us.apache.org/repos/asf/couchdb-oauth/blob/06abc695/oauth_unix.erl
----------------------------------------------------------------------
diff --git a/oauth_unix.erl b/oauth_unix.erl
new file mode 100644
index 0000000..73ca314
--- /dev/null
+++ b/oauth_unix.erl
@@ -0,0 +1,16 @@
+-module(oauth_unix).
+
+-export([timestamp/0]).
+
+
+timestamp() ->
+  timestamp(calendar:universal_time()).
+
+timestamp(DateTime) ->
+  seconds(DateTime) - epoch().
+
+epoch() ->
+  seconds({{1970,1,1},{00,00,00}}).
+
+seconds(DateTime) ->
+  calendar:datetime_to_gregorian_seconds(DateTime).

http://git-wip-us.apache.org/repos/asf/couchdb-oauth/blob/06abc695/oauth_uri.erl
----------------------------------------------------------------------
diff --git a/oauth_uri.erl b/oauth_uri.erl
new file mode 100644
index 0000000..fb27ae7
--- /dev/null
+++ b/oauth_uri.erl
@@ -0,0 +1,88 @@
+-module(oauth_uri).
+
+-export([normalize/1, calate/2, encode/1]).
+-export([params_from_string/1, params_to_string/1,
+  params_from_header_string/1, params_to_header_string/1]).
+
+-import(lists, [concat/1]).
+
+-define(is_uppercase_alpha(C), C >= $A, C =< $Z).
+-define(is_lowercase_alpha(C), C >= $a, C =< $z).
+-define(is_alpha(C), ?is_uppercase_alpha(C); ?is_lowercase_alpha(C)).
+-define(is_digit(C), C >= $0, C =< $9).
+-define(is_alphanumeric(C), ?is_alpha(C); ?is_digit(C)).
+-define(is_unreserved(C), ?is_alphanumeric(C); C =:= $-; C =:= $_; C =:= $.; C =:= $~).
+-define(is_hex(C), ?is_digit(C); C >= $A, C =< $F).
+
+
+normalize(URI) ->
+  case http_uri:parse(URI) of
+    {Scheme, UserInfo, Host, Port, Path, _Query} ->
+      normalize(Scheme, UserInfo, string:to_lower(Host), Port, [Path]);
+    Else ->
+      Else
+  end.
+
+normalize(http, UserInfo, Host, 80, Acc) ->
+  normalize(http, UserInfo, [Host|Acc]);
+normalize(https, UserInfo, Host, 443, Acc) ->
+  normalize(https, UserInfo, [Host|Acc]);
+normalize(Scheme, UserInfo, Host, Port, Acc) ->
+  normalize(Scheme, UserInfo, [Host, ":", Port|Acc]).
+
+normalize(Scheme, [], Acc) ->
+  concat([Scheme, "://"|Acc]);
+normalize(Scheme, UserInfo, Acc) ->
+  concat([Scheme, "://", UserInfo, "@"|Acc]).
+
+params_to_header_string(Params) ->
+  intercalate(", ", [concat([encode(K), "=\"", encode(V), "\""]) || {K, V} <- Params]).
+
+params_from_header_string(String) ->
+  [param_from_header_string(Param) || Param <- re:split(String, ",\\s*", [{return, list}]),
Param =/= ""].
+
+param_from_header_string(Param) ->
+  [Key, QuotedValue] = string:tokens(Param, "="),
+  Value = string:substr(QuotedValue, 2, length(QuotedValue) - 2),
+  {decode(Key), decode(Value)}.
+
+params_from_string(Params) ->
+  [param_from_string(Param) || Param <- string:tokens(Params, "&")].
+
+param_from_string(Param) ->
+  list_to_tuple([decode(Value) || Value <- string:tokens(Param, "=")]).
+
+params_to_string(Params) ->
+  intercalate("&", [calate("=", [K, V]) || {K, V} <- Params]).
+
+calate(Sep, Xs) ->
+  intercalate(Sep, [encode(X) || X <- Xs]).
+
+intercalate(Sep, Xs) ->
+  concat(intersperse(Sep, Xs)).
+
+intersperse(_, []) -> [];
+intersperse(_, [X]) -> [X];
+intersperse(Sep, [X|Xs]) ->
+  [X, Sep|intersperse(Sep, Xs)].
+
+decode(Chars) ->
+  decode(Chars, []).
+
+decode([], Decoded) ->
+  lists:reverse(Decoded);
+decode([$%,A,B|Etc], Decoded) when ?is_hex(A), ?is_hex(B) ->
+  decode(Etc, [erlang:list_to_integer([A,B], 16)|Decoded]);
+decode([C|Etc], Decoded) when ?is_unreserved(C) ->
+  decode(Etc, [C|Decoded]).
+
+encode(Chars) ->
+  encode(Chars, []).
+
+encode([], Encoded) ->
+  lists:flatten(lists:reverse(Encoded));
+encode([C|Etc], Encoded) when ?is_unreserved(C) ->
+  encode(Etc, [C|Encoded]);
+encode([C|Etc], Encoded) ->
+  Value = io_lib:format("%~2.1.0s", [erlang:integer_to_list(C, 16)]),
+  encode(Etc, [Value|Encoded]).


Mime
View raw message