Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 101 additions & 1 deletion modules/mod_ginger_base/mod_ginger_base.erl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
-mod_title("Ginger Base").
-mod_description("Ginger Base").
-mod_prio(250).
-mod_depends([mod_content_groups, mod_acl_user_groups]).
-mod_depends([mod_content_groups, mod_acl_user_groups, mod_admin_identity]).

-mod_schema(13).

Expand Down Expand Up @@ -198,6 +198,32 @@ manage_schema(_Version, Context) ->
%%observe_acl_is_allowed(#acl_is_allowed{}, _Context) ->
%% undefined.


%% @doc Allow mod_admin_identity managers to impersonate other users
event(#postback{message={switch_user, [{id, Id}]}}, Context) ->
IsAdmin = z_acl:is_admin(Context),
CanSwitch = IsAdmin
orelse z_acl:is_allowed(use, mod_admin_identity, Context),
ImpersonationEnabled = is_impersonation_enabled(Context),
AdminAllowed = IsAdmin
andalso Id =/= 1,
RegularAllowed = ImpersonationEnabled
andalso CanSwitch
andalso Id =/= 1
andalso can_impersonate_user(Id, Context),
case AdminAllowed orelse RegularAllowed of
true ->
{ok, NewContext} = z_auth:switch_user(Id, Context),
Url = case z_acl:is_allowed(use, mod_admin, NewContext) of
true ->
z_dispatcher:url_for(admin, NewContext);
false ->
<<"/">>
end,
z_render:wire({redirect, [{location, Url}]}, NewContext);
false ->
z_render:growl_error(?__("You are not allowed to switch users.", Context), Context)
end;
%% @doc Handle the submit event of a new comment
event(#submit{message={newcomment, Args}, form=FormId}, Context) ->
ExtraActions = proplists:get_all_values(action, Args),
Expand Down Expand Up @@ -267,6 +293,80 @@ event(#postback{message={map_infobox, _Args}}, Context) ->
),
z_render:wire({script, [{script, JS}]}, Context).

can_impersonate_user(TargetId, Context) ->
case z_acl:user(Context) of
undefined ->
false;
TargetId ->
true;
SwitcherId when is_integer(SwitcherId) ->
AllowHorizontal = is_horizontal_impersonation_allowed(Context),
SudoContext = z_acl:sudo(Context),
SwitcherGroups = direct_user_groups(SwitcherId, SudoContext),
TargetGroups = direct_user_groups(TargetId, SudoContext),
case {SwitcherGroups, TargetGroups} of
{[], _} ->
false;
{_, []} ->
false;
_ ->
lists:all(
fun(TargetGroup) ->
group_impersonation_allowed(TargetGroup, SwitcherGroups, SudoContext, AllowHorizontal)
end,
TargetGroups)
end;
_ ->
false
end.

direct_user_groups(UserId, Context) ->
lists:usort(acl_user_groups_checks:has_user_groups(UserId, Context)).

group_impersonation_allowed(TargetGroup, SwitcherGroups, Context, AllowHorizontal) ->
TargetPath = user_group_path(TargetGroup, Context),
TargetPath =/= [] andalso
lists:any(
fun(SwitcherGroup) ->
SwitcherPath = user_group_path(SwitcherGroup, Context),
path_allows(TargetPath, SwitcherPath, AllowHorizontal)
end,
SwitcherGroups).

user_group_path(GroupId, Context) ->
case mod_acl_user_groups:lookup(GroupId, Context) of
undefined ->
[GroupId];
Path when is_list(Path) ->
Path
end.

path_allows(TargetPath, SwitcherPath, AllowHorizontal) when is_list(TargetPath), is_list(SwitcherPath) ->
case lists:suffix(TargetPath, SwitcherPath) of
true when AllowHorizontal ->
true;
true ->
length(SwitcherPath) > length(TargetPath);
false ->
false
end.

is_impersonation_enabled(Context) ->
case m_config:get_value(mod_ginger_base, activate_impersonation, Context) of
undefined ->
false;
Value ->
z_utils:is_true(Value)
end.

is_horizontal_impersonation_allowed(Context) ->
case m_config:get_value(mod_ginger_base, allow_horizontal_impersonation, Context) of
undefined ->
false;
Value ->
z_utils:is_true(Value)
end.

%% @doc When a resource is persisted in the admin, update granularity for
%% granular date fields.
observe_admin_rscform(#admin_rscform{}, Post, _Context) ->
Expand Down
4 changes: 3 additions & 1 deletion modules/mod_ginger_base/support/ginger_config.erl
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,7 @@ get_config() ->
{mod_l10n, timezone, <<"Europe/Berlin">>},
%% Allow ginger-embed elements
{site, html_elt_extra, <<"embed,iframe,object,script,ginger-embed">>},
{site, html_attr_extra, <<"data,allowfullscreen,flashvars,frameborder,scrolling,async,defer,data-rdf">>}
{site, html_attr_extra, <<"data,allowfullscreen,flashvars,frameborder,scrolling,async,defer,data-rdf">>},
{mod_ginger_base, activate_impersonation, false},
{mod_ginger_base, allow_horizontal_impersonation, false}
].
29 changes: 29 additions & 0 deletions modules/mod_ginger_base/templates/_admin_edit_basics_user.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<fieldset class="form">


{% if m.acl.is_allowed.use.mod_admin_identity or id == m.acl.user %}
<div class="col-md-6">
<div class="well">
<h4 style="margin-top: 0">{_ User actions _}</h4>
<div class="form-group">
{% button class="btn btn-default" action={dialog_set_username_password id=id} text=_"Set username / password" %}
</div>

{% if (m.acl.is_admin or m.acl.is_allowed.use.mod_admin_identity) and m.identity[id].is_user and id != m.acl.user and id != 1 %}
<div class="form-group">
{% button class="btn btn-default" action={confirm text=_"Click OK to log on as this user. You will be redirected to the home page if this user has no rights to access the admin system." postback={switch_user id=id} delegate=`mod_ginger_base`} text=_"Log on as this user" %}
</div>
{% endif %}

{% if id /= 1 %}
<div>
{% button class="btn btn-default" text=_"Delete Username" action={dialog_delete_username id=id on_success={slide_fade_out target=#tr.id}} %}
</div>
{% endif %}
</div>
</div>
{% endif %}

{% all include "_admin_edit_basics_user_extra.tpl" %}

</fieldset>