C0 code coverage information

Generated on 2009-08-09 21:22:56 with etap 0.3.4.

Name Total lines Lines of code Total coverage Code coverage
couch_httpd_oauth ?? ?? ??
13% 
....1 % Licensed under the Apache License, Version 2.0 (the "License"); you may not
....2 % use this file except in compliance with the License.  You may obtain a copy of
....3 % the License at
....4 %
....5 %   http://www.apache.org/licenses/LICENSE-2.0
....6 %
....7 % Unless required by applicable law or agreed to in writing, software
....8 % distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
....9 % WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
...10 % License for the specific language governing permissions and limitations under
...11 % the License.
...12 
...13 -module(couch_httpd_oauth).
...14 -include("couch_db.hrl").
...15 
...16 -export([oauth_authentication_handler/1, handle_oauth_req/1, consumer_lookup/2]).
...17 
...18 % OAuth auth handler using per-node user db
...19 oauth_authentication_handler(#httpd{method=Method}=Req) ->
...20     serve_oauth(Req, fun(URL, Params, Consumer, Signature) ->
...21         AccessToken = proplists:get_value("oauth_token", Params),
...22         TokenSecret = couch_config:get("oauth_token_secrets", AccessToken),
...23         case oauth:verify(Signature, atom_to_list(Method), URL, Params, Consumer, TokenSecret) of
...24             true ->
...25                 set_user_ctx(Req, AccessToken);
...26             false ->
...27                 Req
...28         end
...29     end, true).
...30 
...31 % Look up the consumer key and get the roles to give the consumer
...32 set_user_ctx(Req, AccessToken) ->
...33     DbName = couch_config:get("couch_httpd_auth", "authentication_db"),
...34     couch_httpd_auth:ensure_users_db_exists(?l2b(DbName)),
...35     case couch_db:open(?l2b(DbName), [{user_ctx, #user_ctx{roles=[<<"_admin">>]}}]) of
...36         {ok, Db} ->
...37             Name = ?l2b(couch_config:get("oauth_token_users", AccessToken)),
...38             case couch_httpd_auth:get_user(Db, Name) of
...39                 nil -> Req;
...40                 User ->
...41                     Roles = proplists:get_value(<<"roles">>, User, []),
...42                     Req#httpd{user_ctx=#user_ctx{name=Name, roles=Roles}}
...43             end;
...44         _Else->
...45             Req
...46     end.
...47 
...48 % OAuth request_token
...49 handle_oauth_req(#httpd{path_parts=[_OAuth, <<"request_token">>], method=Method}=Req) ->
...50     serve_oauth(Req, fun(URL, Params, Consumer, Signature) ->
...51         AccessToken = proplists:get_value("oauth_token", Params),
...52         TokenSecret = couch_config:get("oauth_token_secrets", AccessToken),
...53         case oauth:verify(Signature, atom_to_list(Method), URL, Params, Consumer, TokenSecret) of
...54             true ->
...55                 ok(Req, <<"oauth_token=requestkey&oauth_token_secret=requestsecret">>);
...56             false ->
...57                 invalid_signature(Req)
...58         end
...59     end, false);
...60 handle_oauth_req(#httpd{path_parts=[_OAuth, <<"authorize">>]}=Req) ->
...61     {ok, serve_oauth_authorize(Req)};
...62 handle_oauth_req(#httpd{path_parts=[_OAuth, <<"access_token">>], method='GET'}=Req) ->
...63     serve_oauth(Req, fun(URL, Params, Consumer, Signature) ->
...64         case oauth:token(Params) of
...65             "requestkey" ->
...66                 case oauth:verify(Signature, "GET", URL, Params, Consumer, "requestsecret") of
...67                     true ->
...68                         ok(Req, <<"oauth_token=accesskey&oauth_token_secret=accesssecret">>);
...69                     false ->
...70                         invalid_signature(Req)
...71                 end;
...72             _ ->
...73                 couch_httpd:send_error(Req, 400, <<"invalid_token">>, <<"Invalid OAuth token.">>)
...74         end
...75     end, false);
...76 handle_oauth_req(#httpd{path_parts=[_OAuth, <<"access_token">>]}=Req) ->
...77     couch_httpd:send_method_not_allowed(Req, "GET").
...78 
...79 invalid_signature(Req) ->
...80     couch_httpd:send_error(Req, 400, <<"invalid_signature">>, <<"Invalid signature value.">>).
...81 
...82 % This needs to be protected i.e. force user to login using HTTP Basic Auth or form-based login.
...83 serve_oauth_authorize(#httpd{method=Method}=Req) ->
...84     case Method of
...85         'GET' ->
...86             % Confirm with the User that they want to authenticate the Consumer
...87             serve_oauth(Req, fun(URL, Params, Consumer, Signature) ->
...88                 AccessToken = proplists:get_value("oauth_token", Params),
...89                 TokenSecret = couch_config:get("oauth_token_secrets", AccessToken),
...90                 case oauth:verify(Signature, "GET", URL, Params, Consumer, TokenSecret) of
...91                     true ->
...92                         ok(Req, <<"oauth_token=requestkey&oauth_token_secret=requestsecret">>);
...93                     false ->
...94                         invalid_signature(Req)
...95                 end
...96             end, false);
...97         'POST' ->
...98             % If the User has confirmed, we direct the User back to the Consumer with a verification code
...99             serve_oauth(Req, fun(URL, Params, Consumer, Signature) ->
..100                 AccessToken = proplists:get_value("oauth_token", Params),
..101                 TokenSecret = couch_config:get("oauth_token_secrets", AccessToken),
..102                 case oauth:verify(Signature, "POST", URL, Params, Consumer, TokenSecret) of
..103                     true ->
..104                         %redirect(oauth_callback, oauth_token, oauth_verifier),
..105                         ok(Req, <<"oauth_token=requestkey&oauth_token_secret=requestsecret">>);
..106                     false ->
..107                         invalid_signature(Req)
..108                 end
..109             end, false);
..110         _ ->
..111             couch_httpd:send_method_not_allowed(Req, "GET,POST")
..112     end.
..113 
..114 serve_oauth(#httpd{mochi_req=MochiReq}=Req, Fun, FailSilently) ->
..115     % 1. In the HTTP Authorization header as defined in OAuth HTTP Authorization Scheme.
..116     % 2. As the HTTP POST request body with a content-type of application/x-www-form-urlencoded.
..117     % 3. Added to the URLs in the query part (as defined by [RFC3986] section 3).
..118     AuthHeader = case MochiReq:get_header_value("authorization") of
..119         undefined ->
..120             "";
..121         Else ->
..122             [Head | Tail] = re:split(Else, "\\s", [{parts, 2}, {return, list}]),
..123             case [string:to_lower(Head) | Tail] of
..124                 ["oauth", Rest] -> Rest;
..125                 _ -> ""
..126             end
..127     end,
..128     HeaderParams = oauth_uri:params_from_header_string(AuthHeader),
..129     %Realm = proplists:get_value("realm", HeaderParams),
..130     Params = proplists:delete("realm", HeaderParams) ++ MochiReq:parse_qs(),
..131     ?LOG_DEBUG("OAuth Params: ~p", [Params]),
..132     case proplists:get_value("oauth_version", Params, "1.0") of
..133         "1.0" ->
..134             case proplists:get_value("oauth_consumer_key", Params, undefined) of
..135                 undefined ->
..136                     case FailSilently of
..137                         true -> Req;
..138                         false -> couch_httpd:send_error(Req, 400, <<"invalid_consumer">>, <<"Invalid consumer.">>)
..139                     end;
..140                 ConsumerKey ->
..141                     SigMethod = proplists:get_value("oauth_signature_method", Params),
..142                     case consumer_lookup(ConsumerKey, SigMethod) of
..143                         none ->
..144                             couch_httpd:send_error(Req, 400, <<"invalid_consumer">>, <<"Invalid consumer (key or signature method).">>);
..145                         Consumer ->
..146                             Signature = proplists:get_value("oauth_signature", Params),
..147                             URL = couch_httpd:absolute_uri(Req, MochiReq:get(path)),
..148                             Fun(URL, proplists:delete("oauth_signature", Params),
..149                                 Consumer, Signature)
..150                     end
..151             end;
..152         _ ->
..153             couch_httpd:send_error(Req, 400, <<"invalid_oauth_version">>, <<"Invalid OAuth version.">>)
..154     end.
..155 
..156 consumer_lookup(Key, MethodStr) ->
..157     SignatureMethod = case MethodStr of
..158         "PLAINTEXT" -> plaintext;
..159         "HMAC-SHA1" -> hmac_sha1;
..160         %"RSA-SHA1" -> rsa_sha1;
..161         _Else -> undefined
..162     end,
..163     case SignatureMethod of
..164         undefined -> none;
..165         _SupportedMethod ->
..166             case couch_config:get("oauth_consumer_secrets", Key, undefined) of
..167                 undefined -> none;
..168                 Secret -> {Key, Secret, SignatureMethod}
..169             end
..170     end.
..171 
..172 ok(#httpd{mochi_req=MochiReq}, Body) ->
..173     {ok, MochiReq:respond({200, [], Body})}.

Generated using etap 0.3.4.