From 3c4660bbf3f8fb2cb93a4cff9dec5cf8e99964ae Mon Sep 17 00:00:00 2001 From: Prabhat Khera <91852476+prabhat-org@users.noreply.github.com> Date: Mon, 25 Sep 2023 09:08:26 +1300 Subject: [PATCH] fix(permissions): non admin access to view users [EE-5825] (#10352) * fix non admin access to view users * review comments and fix tests --- api/http/handler/users/user_list.go | 26 ++++++++++++++++++- .../AccessControlPanelDetails.tsx | 12 +++------ .../users/teams/ListView/ListView.tsx | 2 +- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/api/http/handler/users/user_list.go b/api/http/handler/users/user_list.go index b77dc6620..5a6871991 100644 --- a/api/http/handler/users/user_list.go +++ b/api/http/handler/users/user_list.go @@ -31,7 +31,7 @@ func (handler *Handler) userList(w http.ResponseWriter, r *http.Request) *httper return httperror.InternalServerError("Unable to retrieve info from request context", err) } - if !securityContext.IsAdmin { + if !securityContext.IsAdmin && !securityContext.IsTeamLeader { return httperror.Forbidden("Permission denied to access users list", err) } @@ -42,6 +42,9 @@ func (handler *Handler) userList(w http.ResponseWriter, r *http.Request) *httper endpointID, _ := request.RetrieveNumericQueryParameter(r, "environmentId", true) if endpointID == 0 { + if securityContext.IsAdmin { + sanitizeUsers(users) + } return response.JSON(w, users) } @@ -60,6 +63,9 @@ func (handler *Handler) userList(w http.ResponseWriter, r *http.Request) *httper for _, user := range users { // the users who have the endpoint authorization if _, ok := user.EndpointAuthorizations[endpoint.ID]; ok { + if securityContext.IsAdmin { + sanitizeUser(&user) + } canAccessEndpoint = append(canAccessEndpoint, user) continue } @@ -71,9 +77,27 @@ func (handler *Handler) userList(w http.ResponseWriter, r *http.Request) *httper } if security.AuthorizedEndpointAccess(endpoint, endpointGroup, user.ID, teamMemberships) { + if securityContext.IsAdmin { + sanitizeUser(&user) + } canAccessEndpoint = append(canAccessEndpoint, user) } } return response.JSON(w, canAccessEndpoint) } + +func sanitizeUser(user *portainer.User) { + user.Password = "" + user.EndpointAuthorizations = nil + user.ThemeSettings = portainer.UserThemeSettings{} + user.PortainerAuthorizations = nil + user.UserTheme = "" + user.TokenIssueAt = 0 +} + +func sanitizeUsers(users []portainer.User) { + for i := range users { + sanitizeUser(&users[i]) + } +} diff --git a/app/react/portainer/access-control/AccessControlPanel/AccessControlPanelDetails.tsx b/app/react/portainer/access-control/AccessControlPanel/AccessControlPanelDetails.tsx index 584ba873d..3201959cc 100644 --- a/app/react/portainer/access-control/AccessControlPanel/AccessControlPanelDetails.tsx +++ b/app/react/portainer/access-control/AccessControlPanel/AccessControlPanelDetails.tsx @@ -8,7 +8,6 @@ import { UserId } from '@/portainer/users/types'; import { TeamId } from '@/react/portainer/users/teams/types'; import { useTeams } from '@/react/portainer/users/teams/queries'; import { useUsers } from '@/portainer/users/queries'; -import { useCurrentUser } from '@/react/hooks/useUser'; import { pluralize } from '@/portainer/helpers/strings'; import { Link } from '@@/Link'; @@ -31,8 +30,6 @@ export function AccessControlPanelDetails({ resourceControl, resourceType, }: Props) { - const { isAdmin } = useCurrentUser(); - const inheritanceMessage = getInheritanceMessage( resourceType, resourceControl @@ -44,10 +41,7 @@ export function AccessControlPanelDetails({ TeamAccesses: restrictedToTeams = [], } = resourceControl || {}; - const users = useAuthorizedUsers( - restrictedToUsers.map((ra) => ra.UserId), - isAdmin - ); + const users = useAuthorizedUsers(restrictedToUsers.map((ra) => ra.UserId)); const teams = useAuthorizedTeams(restrictedToTeams.map((ra) => ra.TeamId)); const teamsLength = teams.data ? teams.data.length : 0; @@ -62,8 +56,8 @@ export function AccessControlPanelDetails({ )} you are not part of`; } - const userMessage = isAdmin - ? (users.data && users.data.join(', ')) || '' + const userMessage = users.data + ? users.data.join(', ') : `${restrictedToUsers.length} ${pluralize( restrictedToUsers.length, 'user' diff --git a/app/react/portainer/users/teams/ListView/ListView.tsx b/app/react/portainer/users/teams/ListView/ListView.tsx index 6c45119cf..01bc181bc 100644 --- a/app/react/portainer/users/teams/ListView/ListView.tsx +++ b/app/react/portainer/users/teams/ListView/ListView.tsx @@ -18,7 +18,7 @@ export function ListView() { <> <PageHeader title="Teams" breadcrumbs={[{ label: 'Teams management' }]} /> - {usersQuery.data && teamsQuery.data && ( + {isAdmin && usersQuery.data && teamsQuery.data && ( <CreateTeamForm users={usersQuery.data} teams={teamsQuery.data} /> )}