diff --git a/api/http/handler/users/user_list.go b/api/http/handler/users/user_list.go
index 1e5810133..4535dc73a 100644
--- a/api/http/handler/users/user_list.go
+++ b/api/http/handler/users/user_list.go
@@ -26,23 +26,24 @@ import (
// @failure 500 "Server error"
// @router /users [get]
func (handler *Handler) userList(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
- securityContext, err := security.RetrieveRestrictedRequestContext(r)
+ users, err := handler.DataStore.User().ReadAll()
if err != nil {
- return httperror.InternalServerError("Unable to retrieve info from request context", err)
+ return httperror.InternalServerError("Unable to retrieve users from the database", err)
}
- if !securityContext.IsAdmin {
- return httperror.Forbidden("Permission denied to access users list", err)
+ securityContext, err := security.RetrieveRestrictedRequestContext(r)
+ if err != nil {
+ return httperror.InternalServerError("Unable to retrieve info from request context", err)
}
- users, err := handler.DataStore.User().ReadAll()
- if err != nil {
- return httperror.InternalServerError("Unable to retrieve users from the database", err)
+ availableUsers := security.FilterUsers(users, securityContext)
+ for i := range availableUsers {
+ hideFields(&availableUsers[i])
}
endpointID, _ := request.RetrieveNumericQueryParameter(r, "environmentId", true)
if endpointID == 0 {
- return response.JSON(w, users)
+ return response.JSON(w, availableUsers)
}
// filter out users who do not have access to the specific endpoint
@@ -57,7 +58,7 @@ func (handler *Handler) userList(w http.ResponseWriter, r *http.Request) *httper
}
canAccessEndpoint := make([]portainer.User, 0)
- for _, user := range users {
+ for _, user := range availableUsers {
// the users who have the endpoint authorization
if _, ok := user.EndpointAuthorizations[endpoint.ID]; ok {
canAccessEndpoint = append(canAccessEndpoint, user)
diff --git a/api/http/handler/users/user_list_test.go b/api/http/handler/users/user_list_test.go
index 261857c38..094c59530 100644
--- a/api/http/handler/users/user_list_test.go
+++ b/api/http/handler/users/user_list_test.go
@@ -111,14 +111,28 @@ func Test_userList(t *testing.T) {
}
})
- t.Run("standard user cannot list users", func(t *testing.T) {
+ t.Run("standard user cannot list amdin users", func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/users", nil)
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", jwt))
rr := httptest.NewRecorder()
h.ServeHTTP(rr, req)
- is.Equal(http.StatusForbidden, rr.Code)
+ is.Equal(http.StatusOK, rr.Code)
+
+ body, err := io.ReadAll(rr.Body)
+ is.NoError(err, "ReadAll should not return error")
+
+ var resp []portainer.User
+ err = json.Unmarshal(body, &resp)
+ is.NoError(err, "response should be list json")
+
+ is.Len(resp, 2)
+ if len(resp) > 0 {
+ for _, user := range resp {
+ is.NotEqual(portainer.AdministratorRole, user.Role)
+ }
+ }
})
// Case 2: the user is under an environment group and the environment group has endpoint access.
diff --git a/app/react/portainer/access-control/AccessControlPanel/AccessControlPaneDetails.test.tsx b/app/react/portainer/access-control/AccessControlPanel/AccessControlPaneDetails.test.tsx
index 9970da4d9..dd78df8af 100644
--- a/app/react/portainer/access-control/AccessControlPanel/AccessControlPaneDetails.test.tsx
+++ b/app/react/portainer/access-control/AccessControlPanel/AccessControlPaneDetails.test.tsx
@@ -4,7 +4,6 @@ import { createMockTeams, createMockUsers } from '@/react-tools/test-mocks';
import { renderWithQueryClient } from '@/react-tools/test-utils';
import { rest, server } from '@/setup-tests/server';
import { Role } from '@/portainer/users/types';
-import { withUserProvider } from '@/react/test-utils/withUserProvider';
import {
ResourceControlOwnership,
@@ -144,9 +143,11 @@ async function renderComponent(
resourceType: ResourceControlType = ResourceControlType.Container,
resourceControl?: ResourceControlViewModel
) {
- const WithUser = withUserProvider(AccessControlPanelDetails);
const queries = renderWithQueryClient(
-
Authorized users | -{userMessage} | ++ {users.data && users.data.join(', ')} + |
Authorized teams | -{teamsMessage} | ++ {teams.data && teams.data.join(', ')} + |