You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by kx...@apache.org on 2015/11/10 00:10:58 UTC
couch commit: updated refs/heads/master to a5aa4e1
Repository: couchdb-couch
Updated Branches:
refs/heads/master 853177ca4 -> a5aa4e17c
Improve checks for db admin/member
- Use lists:member/2 to check if user name is in list
- Throw forbidden error if user is authenticated on db membership check
- Normalize terminology readers vs members
- Make checks more Erlang-ish
COUCHDB-2534
Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/a5aa4e17
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/a5aa4e17
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/a5aa4e17
Branch: refs/heads/master
Commit: a5aa4e17c3593a484ee8665d8b4272be05bedfe9
Parents: 853177c
Author: Alexander Shorin <kx...@apache.org>
Authored: Tue Jan 6 05:12:39 2015 +0300
Committer: Alexander Shorin <kx...@apache.org>
Committed: Mon Nov 9 22:53:24 2015 +0300
----------------------------------------------------------------------
src/couch_db.erl | 114 +++++++++++++++++++++++++++++---------------------
1 file changed, 66 insertions(+), 48 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/a5aa4e17/src/couch_db.erl
----------------------------------------------------------------------
diff --git a/src/couch_db.erl b/src/couch_db.erl
index 4c0cd34..36c13af 100644
--- a/src/couch_db.erl
+++ b/src/couch_db.erl
@@ -415,66 +415,84 @@ get_design_docs(#db{id_tree = IdBtree}) ->
{ok, _, Docs} = couch_btree:fold(IdBtree, FoldFun, [], KeyOpts),
{ok, Docs}.
-check_is_admin(#db{} = Db) ->
+
+check_is_admin(#db{user_ctx=UserCtx}=Db) ->
case is_admin(Db) of
- true ->
- ok;
+ true -> ok;
false ->
- throw({unauthorized, <<"You are not a db or server admin.">>})
+ Reason = <<"You are not a db or server admin.">>,
+ throw_security_error(UserCtx, Reason)
end.
-is_admin(Db) ->
+check_is_member(#db{user_ctx=UserCtx}=Db) ->
+ case is_member(Db) of
+ true -> ok;
+ false -> throw_security_error(UserCtx)
+ end.
+
+is_admin(#db{user_ctx=UserCtx}=Db) ->
case couch_db_plugin:check_is_admin(Db) of
- true ->
- true;
+ true -> true;
false ->
- is_admin_int(Db)
+ {Admins} = get_admins(Db),
+ is_authorized(UserCtx, Admins)
end.
-is_admin_int(#db{user_ctx = #user_ctx{name = Name, roles = Roles}} = Db) ->
- {Admins} = get_admins(Db),
- AdminRoles = [<<"_admin">> | couch_util:get_value(<<"roles">>, Admins, [])],
- AdminNames = couch_util:get_value(<<"names">>, Admins,[]),
- case AdminRoles -- Roles of
- AdminRoles -> % same list, not an admin role
- case AdminNames -- [Name] of
- AdminNames -> % same names, not an admin
- false;
- _ ->
- true
- end;
- _ ->
- true
+is_member(#db{user_ctx=UserCtx}=Db) ->
+ case is_admin(Db) of
+ true -> true;
+ false ->
+ case is_public_db(Db) of
+ true -> true;
+ false ->
+ {Members} = get_members(Db),
+ is_authorized(UserCtx, Members)
+ end
end.
-check_is_member(#db{user_ctx=#user_ctx{name=Name,roles=Roles}=UserCtx}=Db) ->
- case (catch check_is_admin(Db)) of
- ok -> ok;
- _ ->
- {Members} = get_members(Db),
- ReaderRoles = couch_util:get_value(<<"roles">>, Members,[]),
- WithAdminRoles = [<<"_admin">> | ReaderRoles],
- ReaderNames = couch_util:get_value(<<"names">>, Members,[]),
- case ReaderRoles ++ ReaderNames of
- [] -> ok; % no readers == public access
- _Else ->
- case WithAdminRoles -- Roles of
- WithAdminRoles -> % same list, not an reader role
- case ReaderNames -- [Name] of
- ReaderNames -> % same names, not a reader
- couch_log:debug("Not a reader: UserCtx ~p"
- " vs Names ~p Roles ~p",
- [UserCtx, ReaderNames, WithAdminRoles]),
- throw({unauthorized, <<"You are not authorized to access this db.">>});
- _ ->
- ok
- end;
- _ ->
- ok
- end
- end
+is_public_db(#db{}=Db) ->
+ {Members} = get_members(Db),
+ Names = couch_util:get_value(<<"names">>, Members, []),
+ Roles = couch_util:get_value(<<"roles">>, Members, []),
+ Names =:= [] andalso Roles =:= [].
+
+is_authorized(#user_ctx{name=UserName,roles=UserRoles}, Security) ->
+ Names = couch_util:get_value(<<"names">>, Security, []),
+ Roles = couch_util:get_value(<<"roles">>, Security, []),
+ case check_security(roles, UserRoles, [<<"_admin">> | Roles]) of
+ true -> true;
+ false -> check_security(names, UserName, Names)
end.
+check_security(roles, [], _) ->
+ false;
+check_security(roles, UserRoles, Roles) ->
+ UserRolesSet = ordsets:from_list(UserRoles),
+ RolesSet = ordsets:from_list(Roles),
+ not ordsets:is_disjoint(UserRolesSet, RolesSet);
+check_security(names, _, []) ->
+ false;
+check_security(names, null, _) ->
+ false;
+check_security(names, UserName, Names) ->
+ lists:member(UserName, Names).
+
+throw_security_error(#user_ctx{name=null}=UserCtx) ->
+ Reason = <<"You are not authorized to access this db.">>,
+ throw_security_error(UserCtx, Reason);
+throw_security_error(#user_ctx{name=_}=UserCtx) ->
+ Reason = <<"You are not allowed to access this db.">>,
+ throw_security_error(UserCtx, Reason).
+throw_security_error(#user_ctx{}=UserCtx, Reason) ->
+ Error = security_error_type(UserCtx),
+ throw({Error, Reason}).
+
+security_error_type(#user_ctx{name=null}) ->
+ unauthorized;
+security_error_type(#user_ctx{name=_}) ->
+ forbidden.
+
+
get_admins(#db{security=SecProps}) ->
couch_util:get_value(<<"admins">>, SecProps, {[]}).