Files
query-orchestration/api/queryAPI/adminHandlers_access_test.go
T
Jacob Mathison e3d9047143 Merged in jmathison/DEVOPS-722 (pull request #226)
DEVOPS-722 enforce team management visibility

* DEVOPS-722 enforce team management visibility

* DEVOPS-722 reduce admin user list complexity

* DEVOPS-722 cover admin access helpers

* DEVOPS-722 address team management PR feedback

* DEVOPS-722 fix admin access tests in CI

* DEVOPS-722 fix remaining admin PR feedback
2026-05-12 16:49:12 +00:00

633 lines
23 KiB
Go

package queryapi
import (
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"queryorchestration/internal/cognitoauth"
"queryorchestration/internal/usermanagement"
"github.com/labstack/echo/v4"
)
func TestAdminModeForRoles(t *testing.T) {
tests := []struct {
name string
roles []string
want adminTeamMode
}{
{name: "super admin wins", roles: []string{"user_admin", "super_admin"}, want: adminTeamModeSuperAdmin},
{name: "client admin maps to user admin", roles: []string{"client_admin"}, want: adminTeamModeUserAdmin},
{name: "auditor without higher role", roles: []string{"auditor"}, want: adminTeamModeAuditor},
{name: "unrecognized", roles: []string{"client_user"}, want: adminTeamModeNone},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := adminModeForRoles(tt.roles); got != tt.want {
t.Fatalf("adminModeForRoles(%v) = %s, want %s", tt.roles, got, tt.want)
}
})
}
}
func TestIsAAreteEmail(t *testing.T) {
tests := []struct {
email string
want bool
}{
{email: "person@aarete.com", want: true},
{email: "Person@AArete.com", want: true},
{email: "person@sub.aarete.com", want: false},
{email: "person@aarete.com.fake", want: false},
{email: "not-an-email", want: false},
}
for _, tt := range tests {
t.Run(tt.email, func(t *testing.T) {
if got := isAAreteEmail(tt.email); got != tt.want {
t.Fatalf("isAAreteEmail(%q) = %v, want %v", tt.email, got, tt.want)
}
})
}
}
func TestAdminTargetVisibilityAndMutation(t *testing.T) {
clientRoles := []string{"client_user"}
userAdminRoles := []string{"user_admin"}
auditorRoles := []string{"auditor"}
superAdminRoles := []string{"super_admin"}
tests := []struct {
name string
mode adminTeamMode
email string
roles []string
wantRead bool
wantMutate bool
}{
{name: "user admin can read and mutate client user", mode: adminTeamModeUserAdmin, email: "client@example.com", roles: clientRoles, wantRead: true, wantMutate: true},
{name: "user admin can read and mutate user admin", mode: adminTeamModeUserAdmin, email: "admin@example.com", roles: userAdminRoles, wantRead: true, wantMutate: true},
{name: "user admin cannot read or mutate aarete domain", mode: adminTeamModeUserAdmin, email: "person@aarete.com", roles: clientRoles, wantRead: false, wantMutate: false},
{name: "user admin cannot read or mutate auditor", mode: adminTeamModeUserAdmin, email: "auditor@example.com", roles: auditorRoles, wantRead: false, wantMutate: false},
{name: "user admin cannot read or mutate super admin", mode: adminTeamModeUserAdmin, email: "super@example.com", roles: superAdminRoles, wantRead: false, wantMutate: false},
{name: "auditor can read all", mode: adminTeamModeAuditor, email: "person@aarete.com", roles: superAdminRoles, wantRead: true, wantMutate: false},
{name: "super admin can read and mutate all", mode: adminTeamModeSuperAdmin, email: "person@aarete.com", roles: superAdminRoles, wantRead: true, wantMutate: true},
{name: "none cannot read or mutate", mode: adminTeamModeNone, email: "client@example.com", roles: clientRoles, wantRead: false, wantMutate: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := canAdminModeReadTarget(tt.mode, tt.email, tt.roles); got != tt.wantRead {
t.Fatalf("canAdminModeReadTarget() = %v, want %v", got, tt.wantRead)
}
if got := canAdminModeMutateTarget(tt.mode, tt.email, tt.roles); got != tt.wantMutate {
t.Fatalf("canAdminModeMutateTarget() = %v, want %v", got, tt.wantMutate)
}
})
}
}
func TestAdminCreatePermissions(t *testing.T) {
tests := []struct {
name string
mode adminTeamMode
email string
roles []string
want bool
}{
{name: "super admin can create all roles", mode: adminTeamModeSuperAdmin, email: "person@aarete.com", roles: []string{"super_admin"}, want: true},
{name: "user admin can create client user", mode: adminTeamModeUserAdmin, email: "client@example.com", roles: []string{"client_user"}, want: true},
{name: "user admin can create user admin", mode: adminTeamModeUserAdmin, email: "admin@example.com", roles: []string{"client_user", "user_admin"}, want: true},
{name: "user admin cannot create aarete domain", mode: adminTeamModeUserAdmin, email: "person@aarete.com", roles: []string{"client_user"}, want: false},
{name: "user admin cannot create auditor", mode: adminTeamModeUserAdmin, email: "auditor@example.com", roles: []string{"auditor"}, want: false},
{name: "auditor cannot create", mode: adminTeamModeAuditor, email: "client@example.com", roles: []string{"client_user"}, want: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := canAdminModeCreateUser(tt.mode, tt.email, tt.roles); got != tt.want {
t.Fatalf("canAdminModeCreateUser() = %v, want %v", got, tt.want)
}
})
}
}
func TestUserAdminCanAssignRoles(t *testing.T) {
tests := []struct {
name string
roles []string
want bool
}{
{name: "client user", roles: []string{"client_user"}, want: true},
{name: "user admin", roles: []string{"user_admin"}, want: true},
{name: "client user and user admin", roles: []string{"client_user", "user_admin"}, want: true},
{name: "auditor rejected", roles: []string{"auditor"}, want: false},
{name: "super admin rejected", roles: []string{"super_admin"}, want: false},
{name: "unknown role rejected", roles: []string{"custom_role"}, want: false},
{name: "mixed allowed and protected rejected", roles: []string{"client_user", "auditor"}, want: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := userAdminCanAssignRoles(tt.roles); got != tt.want {
t.Fatalf("userAdminCanAssignRoles(%v) = %v, want %v", tt.roles, got, tt.want)
}
})
}
}
func TestCanAdminModeAssignRequestedRoles(t *testing.T) {
auditorRoles := []string{"auditor"}
clientRoles := []string{"client_user"}
tests := []struct {
name string
mode adminTeamMode
roles *[]string
want bool
}{
{name: "nil roles allowed", mode: adminTeamModeUserAdmin, roles: nil, want: true},
{name: "user admin can assign client role", mode: adminTeamModeUserAdmin, roles: &clientRoles, want: true},
{name: "user admin cannot assign auditor role", mode: adminTeamModeUserAdmin, roles: &auditorRoles, want: false},
{name: "super admin can assign auditor role", mode: adminTeamModeSuperAdmin, roles: &auditorRoles, want: true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := canAdminModeAssignRequestedRoles(tt.mode, tt.roles); got != tt.want {
t.Fatalf("canAdminModeAssignRequestedRoles() = %v, want %v", got, tt.want)
}
})
}
}
func TestGetAdminTeamMode(t *testing.T) {
server := newAdminListPermitServer(t)
defer server.Close()
ctrl := NewControllers(&Services{}, &mockAuthConfig{})
permitConfig := &usermanagement.PermitConfig{
APIKey: "test-api-key",
BaseURL: server.URL,
}
t.Run("disabled auth acts as super admin", func(t *testing.T) {
t.Setenv("DISABLE_AUTH", "true")
ctx, _ := newAdminAccessTestContext(http.MethodGet)
if got := ctrl.getAdminTeamMode(ctx, server.Client(), permitConfig); got != adminTeamModeSuperAdmin {
t.Fatalf("getAdminTeamMode() = %s, want %s", got, adminTeamModeSuperAdmin)
}
})
t.Run("permit subject roles determine mode", func(t *testing.T) {
t.Setenv("DISABLE_AUTH", "")
ctx, _ := newAdminAccessTestContext(http.MethodGet)
ctx.Set("user_claims", map[string]interface{}{"sub": "user-admin-sub"})
if got := ctrl.getAdminTeamMode(ctx, server.Client(), permitConfig); got != adminTeamModeUserAdmin {
t.Fatalf("getAdminTeamMode() = %s, want %s", got, adminTeamModeUserAdmin)
}
})
t.Run("context groups are used when subject is unavailable", func(t *testing.T) {
t.Setenv("DISABLE_AUTH", "")
ctx, _ := newAdminAccessTestContext(http.MethodGet)
ctx.Set("user_info", cognitoauth.UserInfo{Groups: []string{"auditor"}})
if got := ctrl.getAdminTeamMode(ctx, server.Client(), permitConfig); got != adminTeamModeAuditor {
t.Fatalf("getAdminTeamMode() = %s, want %s", got, adminTeamModeAuditor)
}
})
t.Run("no auth context has no admin mode", func(t *testing.T) {
t.Setenv("DISABLE_AUTH", "")
ctx, _ := newAdminAccessTestContext(http.MethodGet)
if got := ctrl.getAdminTeamMode(ctx, server.Client(), permitConfig); got != adminTeamModeNone {
t.Fatalf("getAdminTeamMode() = %s, want %s", got, adminTeamModeNone)
}
})
}
func TestGetAdminTargetAccess(t *testing.T) {
server := newAdminListPermitServer(t)
defer server.Close()
t.Setenv("DISABLE_AUTH", "false")
t.Setenv("PERMIT_IO_BASE_URL", server.URL)
ctrl := NewControllers(&Services{}, &mockAuthConfig{})
t.Run("loads target roles and caller mode", func(t *testing.T) {
ctx, _ := newAdminAccessTestContext(http.MethodGet)
ctx.Set("user_claims", map[string]interface{}{"sub": "user-admin-sub"})
cognitoUser := &usermanagement.CognitoUserResponse{
SubjectID: "client-sub",
Email: "client@example.com",
}
access := ctrl.getAdminTargetAccess(ctx, UserEmail(cognitoUser.Email), cognitoUser)
if access.mode != adminTeamModeUserAdmin {
t.Fatalf("getAdminTargetAccess().mode = %s, want %s", access.mode, adminTeamModeUserAdmin)
}
if !access.roleLookupOK {
t.Fatalf("getAdminTargetAccess().roleLookupOK = false, want true")
}
if len(access.roles) != 1 || access.roles[0] != "client_user" {
t.Fatalf("getAdminTargetAccess().roles = %v, want [client_user]", access.roles)
}
if !access.canRead(cognitoUser.Email) {
t.Fatalf("adminTargetAccess.canRead() = false, want true")
}
if !access.canMutate(cognitoUser.Email) {
t.Fatalf("adminTargetAccess.canMutate() = false, want true")
}
})
t.Run("user admin fail closes when target role lookup fails", func(t *testing.T) {
ctx, _ := newAdminAccessTestContext(http.MethodPatch)
ctx.Set("user_claims", map[string]interface{}{"sub": "user-admin-sub"})
cognitoUser := &usermanagement.CognitoUserResponse{
SubjectID: "role-error-sub",
Email: "client@example.com",
}
access := ctrl.getAdminTargetAccess(ctx, UserEmail(cognitoUser.Email), cognitoUser)
if access.mode != adminTeamModeUserAdmin {
t.Fatalf("getAdminTargetAccess().mode = %s, want %s", access.mode, adminTeamModeUserAdmin)
}
if access.roleLookupOK {
t.Fatalf("getAdminTargetAccess().roleLookupOK = true, want false")
}
if access.canRead(cognitoUser.Email) {
t.Fatalf("adminTargetAccess.canRead() = true, want false")
}
if access.canMutate(cognitoUser.Email) {
t.Fatalf("adminTargetAccess.canMutate() = true, want false")
}
})
}
func TestAdminUserErrorResponses(t *testing.T) {
ctx, rec := newAdminAccessTestContext(http.MethodPatch)
if err := adminUserForbidden(ctx); err != nil {
t.Fatalf("adminUserForbidden() error = %v", err)
}
if rec.Code != http.StatusForbidden {
t.Fatalf("adminUserForbidden() status = %d, want %d", rec.Code, http.StatusForbidden)
}
if !strings.Contains(rec.Body.String(), "Insufficient permissions") {
t.Fatalf("adminUserForbidden() body = %q, want permissions message", rec.Body.String())
}
ctx, rec = newAdminAccessTestContext(http.MethodGet)
if err := adminUserNotFound(ctx, "hidden@example.com"); err != nil {
t.Fatalf("adminUserNotFound() error = %v", err)
}
if rec.Code != http.StatusNotFound {
t.Fatalf("adminUserNotFound() status = %d, want %d", rec.Code, http.StatusNotFound)
}
if !strings.Contains(rec.Body.String(), "User not found: hidden@example.com") {
t.Fatalf("adminUserNotFound() body = %q, want not found message", rec.Body.String())
}
}
func TestAdminUserListPaginationAndPage(t *testing.T) {
pageInput := int32(2)
pageSizeInput := int32(2)
page, pageSize := adminUserListPagination(ListAdminUsersParams{
Page: &pageInput,
PageSize: &pageSizeInput,
})
if page != 2 || pageSize != 2 {
t.Fatalf("adminUserListPagination() = (%d, %d), want (2, 2)", page, pageSize)
}
tooLargePageSize := int32(100)
_, defaultedPageSize := adminUserListPagination(ListAdminUsersParams{PageSize: &tooLargePageSize})
if defaultedPageSize != 50 {
t.Fatalf("adminUserListPagination() pageSize = %d, want default 50", defaultedPageSize)
}
users := []AdminUserDetails{
{CognitoSubjectId: "sub-1"},
{CognitoSubjectId: "sub-2"},
{CognitoSubjectId: "sub-3"},
}
pageUsers, hasMore := paginateAdminUsers(users, 1, 2)
if len(pageUsers) != 2 || !hasMore {
t.Fatalf("paginateAdminUsers() = %d users, hasMore %v; want 2 users and hasMore true", len(pageUsers), hasMore)
}
pageUsers, hasMore = paginateAdminUsers(users, 2, 2)
if len(pageUsers) != 1 || hasMore {
t.Fatalf("paginateAdminUsers(page 2) = %d users, hasMore %v; want 1 user and hasMore false", len(pageUsers), hasMore)
}
}
func TestCollectAdminCognitoUsersStopsAtUserCap(t *testing.T) {
nextToken := "next"
_, err := collectAdminCognitoUsers(func(pageSize int, paginationToken *string) (*usermanagement.ListCognitoUsersResult, error) {
users := make([]usermanagement.CognitoUserResponse, pageSize+1)
for i := range users {
users[i] = usermanagement.CognitoUserResponse{SubjectID: "sub"}
}
return &usermanagement.ListCognitoUsersResult{Users: users, PaginationKey: &nextToken}, nil
})
if err == nil || !strings.Contains(err.Error(), "exceeded 6000 users") {
t.Fatalf("collectAdminCognitoUsers() error = %v, want user cap error", err)
}
}
func TestCollectAdminCognitoUsersStopsAtPageCap(t *testing.T) {
nextToken := "next"
_, err := collectAdminCognitoUsers(func(pageSize int, paginationToken *string) (*usermanagement.ListCognitoUsersResult, error) {
return &usermanagement.ListCognitoUsersResult{
Users: []usermanagement.CognitoUserResponse{{SubjectID: "sub"}},
PaginationKey: &nextToken,
}, nil
})
if err == nil || !strings.Contains(err.Error(), "exceeded 100 pages") {
t.Fatalf("collectAdminCognitoUsers() error = %v, want page cap error", err)
}
}
func TestVisibleAdminUsersAppliesDEVOPS722Visibility(t *testing.T) {
users := []usermanagement.CognitoUserResponse{
{SubjectID: "client-sub", Email: "client@example.com", FirstName: "Client", LastName: "User", Status: "CONFIRMED", Enabled: true},
{SubjectID: "user-admin-sub", Email: "admin@example.com", FirstName: "User", LastName: "Admin", Status: "CONFIRMED", Enabled: true},
{SubjectID: "aarete-sub", Email: "person@aarete.com", FirstName: "AArete", LastName: "User", Status: "CONFIRMED", Enabled: true},
{SubjectID: "auditor-sub", Email: "auditor@example.com", FirstName: "Audit", LastName: "User", Status: "CONFIRMED", Enabled: true},
{SubjectID: "super-sub", Email: "super@example.com", FirstName: "Super", LastName: "User", Status: "CONFIRMED", Enabled: true},
{SubjectID: "missing-role-sub", Email: "missing-role@example.com", FirstName: "Missing", LastName: "Role", Status: "CONFIRMED", Enabled: true},
}
rolesBySubject := map[string][]string{
"client-sub": {"client_user"},
"user-admin-sub": {"user_admin"},
"aarete-sub": {"client_user"},
"auditor-sub": {"auditor"},
"super-sub": {"super_admin"},
}
ctrl := NewControllers(&Services{}, &mockAuthConfig{})
userAdminVisible := ctrl.visibleAdminUsers(users, adminTeamModeUserAdmin, rolesBySubject)
assertVisibleSubjects(t, userAdminVisible, []string{"client-sub", "user-admin-sub"})
auditorVisible := ctrl.visibleAdminUsers(users, adminTeamModeAuditor, rolesBySubject)
assertVisibleSubjects(t, auditorVisible, []string{"client-sub", "user-admin-sub", "aarete-sub", "auditor-sub", "super-sub", "missing-role-sub"})
superAdminVisible := ctrl.visibleAdminUsers(users, adminTeamModeSuperAdmin, rolesBySubject)
assertVisibleSubjects(t, superAdminVisible, []string{"client-sub", "user-admin-sub", "aarete-sub", "auditor-sub", "super-sub", "missing-role-sub"})
}
func TestAdminRoleAssignmentsByUserGroupsRoles(t *testing.T) {
got := adminRoleAssignmentsByUser([]usermanagement.RoleAssignment{
{User: "sub-1", Role: "client_user", Tenant: "default"},
{User: "sub-1", Role: "user_admin", Tenant: "default"},
{User: "sub-2", Role: "auditor", Tenant: "default"},
{User: "", Role: "super_admin", Tenant: "default"},
{User: "sub-3", Role: "", Tenant: "default"},
})
assertVisibleRoleMap(t, got, map[string][]string{
"sub-1": {"client_user", "user_admin"},
"sub-2": {"auditor"},
})
}
func TestAdminUserDetailsRolesMarshalAsEmptyArray(t *testing.T) {
detail := adminUserDetailsFromCognito(usermanagement.CognitoUserResponse{
SubjectID: "sub-without-roles",
Email: "client@example.com",
}, nil)
body, err := json.Marshal(detail)
if err != nil {
t.Fatalf("marshal admin user details: %v", err)
}
if strings.Contains(string(body), `"roles":null`) {
t.Fatalf("admin user details marshaled roles as null: %s", body)
}
if !strings.Contains(string(body), `"roles":[]`) {
t.Fatalf("admin user details missing empty roles array: %s", body)
}
}
func TestUpdateUserRolesInPermitEmptyArrayClearsRoles(t *testing.T) {
var deletedRoles []string
mux := http.NewServeMux()
mux.HandleFunc("/v2/api-key/scope", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(map[string]string{
"organization_id": "test-org",
"project_id": "test-project",
"environment_id": "test-env",
}); err != nil {
t.Fatalf("encode scope response: %v", err)
}
})
mux.HandleFunc("/v2/facts/test-project/test-env/role_assignments", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
switch r.Method {
case http.MethodGet:
if err := json.NewEncoder(w).Encode([]map[string]string{
{"role": "client_user", "user": "target-sub", "tenant": "default"},
{"role": "user_admin", "user": "target-sub", "tenant": "default"},
}); err != nil {
t.Fatalf("encode role assignments: %v", err)
}
case http.MethodDelete:
var assignment usermanagement.RoleAssignment
if err := json.NewDecoder(r.Body).Decode(&assignment); err != nil {
t.Fatalf("decode delete role assignment: %v", err)
}
deletedRoles = append(deletedRoles, assignment.Role)
w.WriteHeader(http.StatusNoContent)
default:
t.Fatalf("unexpected method %s", r.Method)
}
})
roleServer := httptest.NewServer(mux)
defer roleServer.Close()
ctrl := NewControllers(&Services{}, &mockAuthConfig{})
ctx, _ := newAdminAccessTestContext(http.MethodPatch)
emptyRoles := []string{}
ctrl.updateUserRolesInPermit(
ctx,
UserEmail("target@example.com"),
AdminUserUpdate{Roles: &emptyRoles},
cognitoauth.UserInfo{Email: "admin@example.com"},
"target-sub",
roleServer.Client(),
&usermanagement.PermitConfig{APIKey: "test-api-key", BaseURL: roleServer.URL},
)
assertVisibleRoleMap(t, map[string][]string{"deleted": deletedRoles}, map[string][]string{
"deleted": {"client_user", "user_admin"},
})
}
func TestUpdateUserRolesInPermitAddsAndRemovesRoles(t *testing.T) {
var assignedRoles []string
var deletedRoles []string
mux := http.NewServeMux()
mux.HandleFunc("/v2/api-key/scope", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(map[string]string{
"organization_id": "test-org",
"project_id": "test-project",
"environment_id": "test-env",
}); err != nil {
t.Fatalf("encode scope response: %v", err)
}
})
mux.HandleFunc("/v2/facts/test-project/test-env/role_assignments", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
switch r.Method {
case http.MethodGet:
if err := json.NewEncoder(w).Encode([]map[string]string{
{"role": "client_user", "user": "target-sub", "tenant": "default"},
{"role": "user_admin", "user": "target-sub", "tenant": "default"},
}); err != nil {
t.Fatalf("encode role assignments: %v", err)
}
case http.MethodPost:
var assignment usermanagement.RoleAssignment
if err := json.NewDecoder(r.Body).Decode(&assignment); err != nil {
t.Fatalf("decode assign role assignment: %v", err)
}
assignedRoles = append(assignedRoles, assignment.Role)
w.WriteHeader(http.StatusCreated)
case http.MethodDelete:
var assignment usermanagement.RoleAssignment
if err := json.NewDecoder(r.Body).Decode(&assignment); err != nil {
t.Fatalf("decode delete role assignment: %v", err)
}
deletedRoles = append(deletedRoles, assignment.Role)
w.WriteHeader(http.StatusNoContent)
default:
t.Fatalf("unexpected method %s", r.Method)
}
})
roleServer := httptest.NewServer(mux)
defer roleServer.Close()
ctrl := NewControllers(&Services{}, &mockAuthConfig{})
ctx, _ := newAdminAccessTestContext(http.MethodPatch)
requestedRoles := []string{"client_user", "auditor"}
ctrl.updateUserRolesInPermit(
ctx,
UserEmail("target@example.com"),
AdminUserUpdate{Roles: &requestedRoles},
cognitoauth.UserInfo{Email: "admin@example.com"},
"target-sub",
roleServer.Client(),
&usermanagement.PermitConfig{APIKey: "test-api-key", BaseURL: roleServer.URL},
)
assertVisibleRoleMap(t, map[string][]string{
"assigned": assignedRoles,
"deleted": deletedRoles,
}, map[string][]string{
"assigned": {"auditor"},
"deleted": {"user_admin"},
})
}
func newAdminListPermitServer(t *testing.T) *httptest.Server {
t.Helper()
mux := http.NewServeMux()
mux.HandleFunc("/v2/api-key/scope", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(map[string]string{
"organization_id": "test-org",
"project_id": "test-project",
"environment_id": "test-env",
}); err != nil {
t.Fatalf("encode scope response: %v", err)
}
})
mux.HandleFunc("/v2/facts/test-project/test-env/role_assignments", func(w http.ResponseWriter, r *http.Request) {
user := r.URL.Query().Get("user")
if user == "role-error-sub" {
http.Error(w, "permit unavailable", http.StatusInternalServerError)
return
}
roleByUser := map[string]string{
"client-sub": "client_user",
"user-admin-sub": "user_admin",
"aarete-sub": "client_user",
"auditor-sub": "auditor",
"super-sub": "super_admin",
}
role := roleByUser[user]
assignments := []map[string]string{}
if role != "" {
assignments = append(assignments, map[string]string{"role": role, "user": user, "tenant": "default"})
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(assignments); err != nil {
t.Fatalf("encode role assignments: %v", err)
}
})
return httptest.NewServer(mux)
}
func newAdminAccessTestContext(method string) (echo.Context, *httptest.ResponseRecorder) {
e := echo.New()
req := httptest.NewRequest(method, "/admin/users", nil)
rec := httptest.NewRecorder()
return e.NewContext(req, rec), rec
}
func assertVisibleSubjects(t *testing.T, users []AdminUserDetails, want []string) {
t.Helper()
got := make([]string, 0, len(users))
for _, user := range users {
got = append(got, user.CognitoSubjectId)
}
if len(got) != len(want) {
t.Fatalf("visible subjects = %v, want %v", got, want)
}
for i := range want {
if got[i] != want[i] {
t.Fatalf("visible subjects = %v, want %v", got, want)
}
}
}
func assertVisibleRoleMap(t *testing.T, got map[string][]string, want map[string][]string) {
t.Helper()
if len(got) != len(want) {
t.Fatalf("role map = %v, want %v", got, want)
}
for subject, wantRoles := range want {
gotRoles, ok := got[subject]
if !ok {
t.Fatalf("role map missing subject %q: %v", subject, got)
}
if len(gotRoles) != len(wantRoles) {
t.Fatalf("role map[%q] = %v, want %v", subject, gotRoles, wantRoles)
}
for i := range wantRoles {
if gotRoles[i] != wantRoles[i] {
t.Fatalf("role map[%q] = %v, want %v", subject, gotRoles, wantRoles)
}
}
}
}