diff options
author | Jan Lehnardt <jan@apache.org> | 2015-11-07 18:20:19 +0000 |
---|---|---|
committer | Jan Lehnardt <jan@apache.org> | 2017-10-08 18:37:51 +0200 |
commit | 1192ac83f18e3580864de978510e0f74987e78de (patch) | |
tree | 315be8a6192c049904ca81417571074bbbf6e6ba | |
parent | 97c3804d5bf9ef19ace1fb6675ea3a7ad969a3d1 (diff) | |
download | couchdb-kxepal-2752-validate-host.tar.gz |
Allow server admins to retrieve an authentication token for any other userarchive/kxepal-2752-validate-hostkxepal-2752-validate-host
First proposal is a new endpoint /_login_as/<username>, but could be any
other endpoint, even included in /_session, this is just to demonstrate
the feature.
-rw-r--r-- | src/couchdb/couch_httpd_auth.erl | 52 |
1 files changed, 41 insertions, 11 deletions
diff --git a/src/couchdb/couch_httpd_auth.erl b/src/couchdb/couch_httpd_auth.erl index 305283255..4f9d8540f 100644 --- a/src/couchdb/couch_httpd_auth.erl +++ b/src/couchdb/couch_httpd_auth.erl @@ -18,7 +18,7 @@ -export([null_authentication_handler/1]). -export([proxy_authentication_handler/1, proxy_authentification_handler/1]). -export([cookie_auth_header/2]). --export([handle_session_req/1]). +-export([handle_session_req/1,handle_delegated_session_req/1]). -import(couch_httpd, [header_value/2, send_json/2,send_json/4, send_method_not_allowed/2]). @@ -232,12 +232,15 @@ cookie_auth_header(#httpd{user_ctx=#user_ctx{name=User}, auth={Secret, true}}=Re cookie_auth_header(_Req, _Headers) -> []. cookie_auth_cookie(Req, User, Secret, TimeStamp) -> - SessionData = User ++ ":" ++ erlang:integer_to_list(TimeStamp, 16), - Hash = crypto:sha_mac(Secret, SessionData), mochiweb_cookies:cookie("AuthSession", - couch_util:encodeBase64Url(SessionData ++ ":" ++ ?b2l(Hash)), + make_cookie_hash(User, Secret, TimeStamp), [{path, "/"}] ++ cookie_scheme(Req) ++ max_age()). +make_cookie_hash(UserName, Secret, TimeStamp) -> + SessionData = UserName ++ ":" ++ erlang:integer_to_list(TimeStamp, 16), + Hash = crypto:sha_mac(Secret, SessionData), + couch_util:encodeBase64Url(SessionData ++ ":" ++ ?b2l(Hash)). + ensure_cookie_auth_secret() -> case couch_config:get("couch_httpd_auth", "secret", nil) of nil -> @@ -247,6 +250,37 @@ ensure_cookie_auth_secret() -> Secret -> Secret end. +% TODO:handle admin party + +prepare_cookie_values(UserName, Password, UserProps) -> + UserProps2 = maybe_upgrade_password_hash(UserName, Password, UserProps), + % setup the session cookie + Secret = ?l2b(ensure_cookie_auth_secret()), + UserSalt = couch_util:get_value(<<"salt">>, UserProps2), + CurrentTime = make_cookie_time(), + {Secret, UserSalt, CurrentTime}. + + +% This endpoint exists to allow users with a server admin account to get an +% authentication token for any other user. This is useful when a middleware +% layer has access to CouchDB as an admin user and needs to give browsers an +% access token that authenticates them against CouchDB. +handle_delegated_session_req(#httpd{method='POST', path_parts=[_LoginAs, UserName]}=Req) -> + ok = couch_httpd:verify_is_server_admin(Req), + case couch_auth_cache:get_user_creds(UserName) of + nil -> couch_httpd:send_error(Req, not_found); % maybe send better error message + UserProps -> + Password = ?l2b(couch_util:get_value("password", UserProps, "")), + {Secret, UserSalt, CurrentTime} = prepare_cookie_values(UserName, Password, UserProps), + Cookie = make_cookie_hash(?b2l(UserName), <<Secret/binary, UserSalt/binary>>, CurrentTime), + % Cookie = make_cookie_token(Req, UserName, UserProps), + send_json(Req, {[{<<"login_secret">>, Cookie}]}) % handle Cookie value string foo + end; +handle_delegated_session_req(#httpd{method='POST', path_parts=[_LoginAs]}=Req) -> + send_json(Req, 404, [], {[{<<"error">>, <<"missing username: /_login_as/username">>}]}); +handle_delegated_session_req(Req) -> + send_method_not_allowed(Req, "POST"). + % session handlers % Login handler with user db handle_session_req(#httpd{method='POST', mochi_req=MochiReq}=Req) -> @@ -272,11 +306,7 @@ handle_session_req(#httpd{method='POST', mochi_req=MochiReq}=Req) -> end, case authenticate(Password, UserProps) of true -> - UserProps2 = maybe_upgrade_password_hash(UserName, Password, UserProps), - % setup the session cookie - Secret = ?l2b(ensure_cookie_auth_secret()), - UserSalt = couch_util:get_value(<<"salt">>, UserProps2), - CurrentTime = make_cookie_time(), + {Secret, UserSalt, CurrentTime} = prepare_cookie_values(UserName, Password, UserProps), Cookie = cookie_auth_cookie(Req, ?b2l(UserName), <<Secret/binary, UserSalt/binary>>, CurrentTime), % TODO document the "next" feature in Futon {Code, Headers} = case couch_httpd:qs_value(Req, "next", nil) of @@ -288,8 +318,8 @@ handle_session_req(#httpd{method='POST', mochi_req=MochiReq}=Req) -> send_json(Req#httpd{req_body=ReqBody}, Code, Headers, {[ {ok, true}, - {name, couch_util:get_value(<<"name">>, UserProps2, null)}, - {roles, couch_util:get_value(<<"roles">>, UserProps2, [])} + {name, couch_util:get_value(<<"name">>, UserProps, null)}, + {roles, couch_util:get_value(<<"roles">>, UserProps, [])} ]}); _Else -> % clear the session |