From 705c5b4c1cfe5b1b8a1acf0d5550c5badfa8c3e2 Mon Sep 17 00:00:00 2001
From: Badlop
Here you can edit access restrictions, manage users, create backups, manage the database, enable/disable ports listened for, view server -statistics,…
Examples: +statistics,…
The access rule configure determines what accounts can access the Web Admin and modify it. +The access rule webadmin_view is to grant only view access: those accounts can browse the Web Admin with read-only access.
Example configurations:
http://example.org:5280/admin/server/example.com/
you can only
administer the virtual host example.com.
+The account ‘reviewer@example.com’ can browse that vhost in read-only mode.
{acl, admins, {user, "admin", "example.net"}}. {host_config, "example.com", [{acl, admins, {user, "admin", "example.com"}}]}. +{host_config, "example.com", [{acl, viewers, {user, "reviewer", "example.com"}}]}. + {access, configure, [{allow, admins}]}. +{access, webadmin_view, [{allow, viewers}]}. {hosts, ["example.org"]}. diff --git a/doc/guide.tex b/doc/guide.tex index 455f6e912..47d93968d 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -4675,7 +4675,10 @@ Here you can edit access restrictions, manage users, create backups, manage the database, enable/disable ports listened for, view server statistics,\ldots -Examples: +The access rule \term{configure} determines what accounts can access the Web Admin and modify it. +The access rule \term{webadmin\_view} is to grant only view access: those accounts can browse the Web Admin with read-only access. + +Example configurations: \begin{itemize} \item You can serve the Web Admin on the same port as the \ind{protocols!XEP-0025: HTTP Polling}HTTP Polling interface. In this example @@ -4689,10 +4692,14 @@ Examples: URL). If you log in with `\jid{admin@example.com}' on \\ \verb|http://example.org:5280/admin/server/example.com/| you can only administer the virtual host \jid{example.com}. + The account `\jid{reviewer@example.com}' can browse that vhost in read-only mode. \begin{verbatim} {acl, admins, {user, "admin", "example.net"}}. {host_config, "example.com", [{acl, admins, {user, "admin", "example.com"}}]}. +{host_config, "example.com", [{acl, viewers, {user, "reviewer", "example.com"}}]}. + {access, configure, [{allow, admins}]}. +{access, webadmin_view, [{allow, viewers}]}. {hosts, ["example.org"]}. diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index 9f6301526..a5d407445 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -50,29 +50,38 @@ %%%================================== %%%% get_acl_access -%% @spec (Path::[string()]) -> {HostOfRule, AccessRule} +%% @spec (Path::[string()]) -> {HostOfRule, [AccessRule]} %% All accounts can access those URLs -get_acl_rule([]) -> {"localhost", all}; -get_acl_rule(["style.css"]) -> {"localhost", all}; -get_acl_rule(["logo.png"]) -> {"localhost", all}; -get_acl_rule(["logo-fill.png"]) -> {"localhost", all}; -get_acl_rule(["favicon.ico"]) -> {"localhost", all}; -get_acl_rule(["additions.js"]) -> {"localhost", all}; +get_acl_rule([],_) -> {"localhost", [all]}; +get_acl_rule(["style.css"],_) -> {"localhost", [all]}; +get_acl_rule(["logo.png"],_) -> {"localhost", [all]}; +get_acl_rule(["logo-fill.png"],_) -> {"localhost", [all]}; +get_acl_rule(["favicon.ico"],_) -> {"localhost", [all]}; +get_acl_rule(["additions.js"],_) -> {"localhost", [all]}; %% This page only displays vhosts that the user is admin: -get_acl_rule(["vhosts"]) -> {"localhost", all}; +get_acl_rule(["vhosts"],_) -> {"localhost", [all]}; %% The pages of a vhost are only accesible if the user is admin of that vhost: -get_acl_rule(["server", VHost | _RPath]) -> {VHost, configure}; +get_acl_rule(["server", VHost | _RPath], 'GET') -> {VHost, [configure, webadmin_view]}; +get_acl_rule(["server", VHost | _RPath], 'POST') -> {VHost, [configure]}; %% Default rule: only global admins can access any other random page -get_acl_rule(_RPath) -> {global, configure}. +get_acl_rule(_RPath, 'GET') -> {global, [configure, webadmin_view]}; +get_acl_rule(_RPath, 'POST') -> {global, [configure]}. + +is_acl_match(Host, Rules, Jid) -> + lists:any( + fun(Rule) -> + allow == acl:match_rule(Host, Rule, Jid) + end, + Rules). %%%================================== %%%% Menu Items Access -get_jid(Auth, HostHTTP) -> - case get_auth_admin(Auth, HostHTTP, []) of +get_jid(Auth, HostHTTP, Method) -> + case get_auth_admin(Auth, HostHTTP, [], Method) of {ok, {User, Server}} -> jlib:make_jid(User, Server, ""); {unauthorized, Error} -> @@ -119,8 +128,8 @@ is_allowed_path(BasePath, {Path, _, _}, JID) -> is_allowed_path(["admin" | Path], JID) -> is_allowed_path(Path, JID); is_allowed_path(Path, JID) -> - {HostOfRule, AccessRule} = get_acl_rule(Path), - allow == acl:match_rule(HostOfRule, AccessRule, JID). + {HostOfRule, AccessRule} = get_acl_rule(Path, 'GET'), + is_acl_match(HostOfRule, AccessRule, JID). %% @spec(Path) -> URL %% where Path = [string()] @@ -163,13 +172,13 @@ process(["doc", LocalFile], _Request) -> end end; -process(["server", SHost | RPath] = Path, #request{auth = Auth, lang = Lang, host = HostHTTP} = Request) -> +process(["server", SHost | RPath] = Path, #request{auth = Auth, lang = Lang, host = HostHTTP, method = Method} = Request) -> Host = jlib:nameprep(SHost), case lists:member(Host, ?MYHOSTS) of true -> - case get_auth_admin(Auth, HostHTTP, Path) of + case get_auth_admin(Auth, HostHTTP, Path, Method) of {ok, {User, Server}} -> - AJID = get_jid(Auth, HostHTTP), + AJID = get_jid(Auth, HostHTTP, Method), process_admin(Host, Request#request{path = RPath, auth = {auth_jid, Auth, AJID}, us = {User, Server}}); @@ -189,10 +198,10 @@ process(["server", SHost | RPath] = Path, #request{auth = Auth, lang = Lang, hos ejabberd_web:error(not_found) end; -process(RPath, #request{auth = Auth, lang = Lang, host = HostHTTP} = Request) -> - case get_auth_admin(Auth, HostHTTP, RPath) of +process(RPath, #request{auth = Auth, lang = Lang, host = HostHTTP, method = Method} = Request) -> + case get_auth_admin(Auth, HostHTTP, RPath, Method) of {ok, {User, Server}} -> - AJID = get_jid(Auth, HostHTTP), + AJID = get_jid(Auth, HostHTTP, Method), process_admin(global, Request#request{path = RPath, auth = {auth_jid, Auth, AJID}, us = {User, Server}}); @@ -209,10 +218,10 @@ process(RPath, #request{auth = Auth, lang = Lang, host = HostHTTP} = Request) -> ejabberd_web:make_xhtml([?XCT("h1", "Unauthorized")])} end. -get_auth_admin(Auth, HostHTTP, RPath) -> +get_auth_admin(Auth, HostHTTP, RPath, Method) -> case Auth of {SJID, Pass} -> - {HostOfRule, AccessRule} = get_acl_rule(RPath), + {HostOfRule, AccessRule} = get_acl_rule(RPath, Method), case jlib:string_to_jid(SJID) of error -> {unauthorized, "badformed-jid"}; @@ -229,11 +238,11 @@ get_auth_admin(Auth, HostHTTP, RPath) -> get_auth_account(HostOfRule, AccessRule, User, Server, Pass) -> case ejabberd_auth:check_password(User, Server, Pass) of true -> - case acl:match_rule(HostOfRule, AccessRule, + case is_acl_match(HostOfRule, AccessRule, jlib:make_jid(User, Server, "")) of - deny -> + false -> {unauthorized, "unprivileged-account"}; - allow -> + true -> {ok, {User, Server}} end; false -> @@ -1427,7 +1436,7 @@ list_vhosts(Lang, JID) -> Hosts = ?MYHOSTS, HostsAllowed = lists:filter( fun(Host) -> - allow == acl:match_rule(Host, configure, JID) + is_acl_match(Host, [configure, webadmin_view], JID) end, Hosts ),