250 lines
7.6 KiB
Go
250 lines
7.6 KiB
Go
|
|
//go:build e2e
|
||
|
|
|
||
|
|
package e2e
|
||
|
|
|
||
|
|
import (
|
||
|
|
"encoding/json"
|
||
|
|
"fmt"
|
||
|
|
"net/http"
|
||
|
|
"os"
|
||
|
|
"testing"
|
||
|
|
|
||
|
|
"github.com/stretchr/testify/require"
|
||
|
|
)
|
||
|
|
|
||
|
|
func TestPermission_Catalog(t *testing.T) {
|
||
|
|
c := NewClient(t)
|
||
|
|
env := c.DoExpectOK(t, http.MethodGet, "/api/v1/permissions/catalog?tree=true", nil, true)
|
||
|
|
var data struct {
|
||
|
|
Tree []map[string]any `json:"tree"`
|
||
|
|
}
|
||
|
|
require.NoError(t, json.Unmarshal(env.Data, &data))
|
||
|
|
require.NotEmpty(t, data.Tree)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestPermission_Me(t *testing.T) {
|
||
|
|
c := NewClient(t)
|
||
|
|
env := c.DoExpectOK(t, http.MethodGet, "/api/v1/permissions/me?include_tree=true", nil, true)
|
||
|
|
var data struct {
|
||
|
|
UID string `json:"uid"`
|
||
|
|
TenantID string `json:"tenant_id"`
|
||
|
|
Roles []string `json:"roles"`
|
||
|
|
Permissions map[string]string `json:"permissions"`
|
||
|
|
Tree []map[string]any `json:"tree"`
|
||
|
|
}
|
||
|
|
require.NoError(t, json.Unmarshal(env.Data, &data))
|
||
|
|
require.Equal(t, c.Fixture.UID, data.UID)
|
||
|
|
require.Equal(t, c.Fixture.TenantID, data.TenantID)
|
||
|
|
require.Contains(t, data.Roles, c.Fixture.RoleKey)
|
||
|
|
require.NotEmpty(t, data.Permissions)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestPermission_RoleCRUD(t *testing.T) {
|
||
|
|
c := NewClient(t)
|
||
|
|
|
||
|
|
createEnv := c.DoExpectOK(t, http.MethodPost, "/api/v1/permissions/roles", map[string]string{
|
||
|
|
"key": "e2e_custom_role",
|
||
|
|
"display_name": "E2E Custom",
|
||
|
|
"status": "open",
|
||
|
|
}, true)
|
||
|
|
var role struct {
|
||
|
|
ID string `json:"id"`
|
||
|
|
Key string `json:"key"`
|
||
|
|
}
|
||
|
|
require.NoError(t, json.Unmarshal(createEnv.Data, &role))
|
||
|
|
require.Equal(t, "e2e_custom_role", role.Key)
|
||
|
|
require.NotEmpty(t, role.ID)
|
||
|
|
|
||
|
|
listEnv := c.DoExpectOK(t, http.MethodGet, "/api/v1/permissions/roles", nil, true)
|
||
|
|
var list struct {
|
||
|
|
Roles []struct {
|
||
|
|
Key string `json:"key"`
|
||
|
|
} `json:"roles"`
|
||
|
|
}
|
||
|
|
require.NoError(t, json.Unmarshal(listEnv.Data, &list))
|
||
|
|
found := false
|
||
|
|
for _, r := range list.Roles {
|
||
|
|
if r.Key == "e2e_custom_role" {
|
||
|
|
found = true
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
require.True(t, found, "created role should appear in list")
|
||
|
|
|
||
|
|
patchEnv := c.DoExpectOK(t, http.MethodPatch, "/api/v1/permissions/roles/"+role.ID, map[string]string{
|
||
|
|
"display_name": "E2E Custom Renamed",
|
||
|
|
}, true)
|
||
|
|
var patched struct {
|
||
|
|
DisplayName string `json:"display_name"`
|
||
|
|
}
|
||
|
|
require.NoError(t, json.Unmarshal(patchEnv.Data, &patched))
|
||
|
|
require.Equal(t, "E2E Custom Renamed", patched.DisplayName)
|
||
|
|
|
||
|
|
c.DoExpectOK(t, http.MethodDelete, "/api/v1/permissions/roles/"+role.ID, nil, true)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestPermission_RolePermissions(t *testing.T) {
|
||
|
|
c := NewClient(t)
|
||
|
|
permissionID := firstCatalogPermissionID(t, c)
|
||
|
|
|
||
|
|
createEnv := c.DoExpectOK(t, http.MethodPost, "/api/v1/permissions/roles", map[string]string{
|
||
|
|
"key": "e2e_role_permissions",
|
||
|
|
"display_name": "E2E Role Permissions",
|
||
|
|
}, true)
|
||
|
|
var role struct {
|
||
|
|
ID string `json:"id"`
|
||
|
|
}
|
||
|
|
require.NoError(t, json.Unmarshal(createEnv.Data, &role))
|
||
|
|
require.NotEmpty(t, role.ID)
|
||
|
|
|
||
|
|
c.DoExpectOK(t, http.MethodPut, "/api/v1/permissions/roles/"+role.ID+"/permissions", map[string][]string{
|
||
|
|
"permission_ids": {permissionID},
|
||
|
|
}, true)
|
||
|
|
|
||
|
|
listEnv := c.DoExpectOK(t, http.MethodGet, "/api/v1/permissions/roles/"+role.ID+"/permissions", nil, true)
|
||
|
|
var list struct {
|
||
|
|
Permissions []struct {
|
||
|
|
ID string `json:"id"`
|
||
|
|
} `json:"permissions"`
|
||
|
|
}
|
||
|
|
require.NoError(t, json.Unmarshal(listEnv.Data, &list))
|
||
|
|
require.NotEmpty(t, list.Permissions)
|
||
|
|
found := false
|
||
|
|
for _, p := range list.Permissions {
|
||
|
|
if p.ID == permissionID {
|
||
|
|
found = true
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
require.True(t, found, "role should include requested permission")
|
||
|
|
|
||
|
|
c.DoExpectOK(t, http.MethodDelete, "/api/v1/permissions/roles/"+role.ID, nil, true)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestPermission_AssignUserRole(t *testing.T) {
|
||
|
|
c := NewClient(t)
|
||
|
|
|
||
|
|
createEnv := c.DoExpectOK(t, http.MethodPost, "/api/v1/permissions/roles", map[string]string{
|
||
|
|
"key": "e2e_assign_role",
|
||
|
|
"display_name": "E2E Assign",
|
||
|
|
}, true)
|
||
|
|
var role struct {
|
||
|
|
ID string `json:"id"`
|
||
|
|
}
|
||
|
|
require.NoError(t, json.Unmarshal(createEnv.Data, &role))
|
||
|
|
|
||
|
|
c.DoExpectOK(t, http.MethodPost, "/api/v1/permissions/users/"+c.Fixture.UID+"/roles", map[string]string{
|
||
|
|
"role_id": role.ID,
|
||
|
|
}, true)
|
||
|
|
|
||
|
|
listEnv := c.DoExpectOK(t, http.MethodGet, "/api/v1/permissions/users/"+c.Fixture.UID+"/roles", nil, true)
|
||
|
|
var list struct {
|
||
|
|
UserRoles []struct {
|
||
|
|
RoleID string `json:"role_id"`
|
||
|
|
} `json:"user_roles"`
|
||
|
|
}
|
||
|
|
require.NoError(t, json.Unmarshal(listEnv.Data, &list))
|
||
|
|
found := false
|
||
|
|
for _, r := range list.UserRoles {
|
||
|
|
if r.RoleID == role.ID {
|
||
|
|
found = true
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
require.True(t, found)
|
||
|
|
|
||
|
|
c.DoExpectOK(t, http.MethodDelete, "/api/v1/permissions/users/"+c.Fixture.UID+"/roles/"+role.ID, nil, true)
|
||
|
|
c.DoExpectOK(t, http.MethodDelete, "/api/v1/permissions/roles/"+role.ID, nil, true)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestPermission_RoleMappingCRUD(t *testing.T) {
|
||
|
|
c := NewClient(t)
|
||
|
|
roleKey := "e2e_mapping_role"
|
||
|
|
externalKey := fmt.Sprintf("e2e-group-%s", c.Fixture.UID)
|
||
|
|
|
||
|
|
createEnv := c.DoExpectOK(t, http.MethodPost, "/api/v1/permissions/roles", map[string]string{
|
||
|
|
"key": roleKey,
|
||
|
|
"display_name": "E2E Mapping Role",
|
||
|
|
}, true)
|
||
|
|
var role struct {
|
||
|
|
ID string `json:"id"`
|
||
|
|
}
|
||
|
|
require.NoError(t, json.Unmarshal(createEnv.Data, &role))
|
||
|
|
require.NotEmpty(t, role.ID)
|
||
|
|
|
||
|
|
upsertEnv := c.DoExpectOK(t, http.MethodPut, "/api/v1/permissions/role-mappings", map[string]string{
|
||
|
|
"external_source": "zitadel",
|
||
|
|
"external_key": externalKey,
|
||
|
|
"internal_role_key": roleKey,
|
||
|
|
}, true)
|
||
|
|
var mapping struct {
|
||
|
|
ID string `json:"id"`
|
||
|
|
ExternalSource string `json:"external_source"`
|
||
|
|
ExternalKey string `json:"external_key"`
|
||
|
|
InternalRoleID string `json:"internal_role_id"`
|
||
|
|
InternalRoleKey string `json:"internal_role_key"`
|
||
|
|
}
|
||
|
|
require.NoError(t, json.Unmarshal(upsertEnv.Data, &mapping))
|
||
|
|
require.NotEmpty(t, mapping.ID)
|
||
|
|
require.Equal(t, "zitadel", mapping.ExternalSource)
|
||
|
|
require.Equal(t, externalKey, mapping.ExternalKey)
|
||
|
|
require.Equal(t, role.ID, mapping.InternalRoleID)
|
||
|
|
require.Equal(t, roleKey, mapping.InternalRoleKey)
|
||
|
|
|
||
|
|
listEnv := c.DoExpectOK(t, http.MethodGet, "/api/v1/permissions/role-mappings?source=zitadel", nil, true)
|
||
|
|
var list struct {
|
||
|
|
Mappings []struct {
|
||
|
|
ExternalKey string `json:"external_key"`
|
||
|
|
} `json:"mappings"`
|
||
|
|
}
|
||
|
|
require.NoError(t, json.Unmarshal(listEnv.Data, &list))
|
||
|
|
found := false
|
||
|
|
for _, item := range list.Mappings {
|
||
|
|
if item.ExternalKey == externalKey {
|
||
|
|
found = true
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
require.True(t, found, "created role mapping should appear in list")
|
||
|
|
|
||
|
|
c.DoExpectOK(t, http.MethodDelete, "/api/v1/permissions/role-mappings", map[string]string{
|
||
|
|
"external_source": "zitadel",
|
||
|
|
"external_key": externalKey,
|
||
|
|
}, true)
|
||
|
|
c.DoExpectOK(t, http.MethodDelete, "/api/v1/permissions/roles/"+role.ID, nil, true)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestPermission_CasbinRBAC(t *testing.T) {
|
||
|
|
if os.Getenv("E2E_CASBIN") != "1" {
|
||
|
|
t.Skip("set E2E_CASBIN=1 and use e2e.casbin.yaml to enable Casbin enforcement")
|
||
|
|
}
|
||
|
|
|
||
|
|
owner := NewClient(t)
|
||
|
|
reloadEnv := owner.DoExpectOK(t, http.MethodPost, "/api/v1/permissions/policy/reload", nil, true)
|
||
|
|
var reload struct {
|
||
|
|
Tenant string `json:"tenant"`
|
||
|
|
TS int64 `json:"ts"`
|
||
|
|
}
|
||
|
|
require.NoError(t, json.Unmarshal(reloadEnv.Data, &reload))
|
||
|
|
require.Equal(t, owner.Fixture.TenantID, reload.Tenant)
|
||
|
|
require.Positive(t, reload.TS)
|
||
|
|
|
||
|
|
noRole := NewNoRoleClient(t)
|
||
|
|
denied := noRole.DoExpectHTTP(t, http.MethodGet, "/api/v1/permissions/roles", nil, true, http.StatusForbidden)
|
||
|
|
require.NotEqual(t, int64(successCode), denied.Code)
|
||
|
|
}
|
||
|
|
|
||
|
|
func firstCatalogPermissionID(t *testing.T, c *Client) string {
|
||
|
|
t.Helper()
|
||
|
|
env := c.DoExpectOK(t, http.MethodGet, "/api/v1/permissions/catalog?tree=false", nil, true)
|
||
|
|
var data struct {
|
||
|
|
List []struct {
|
||
|
|
ID string `json:"id"`
|
||
|
|
} `json:"list"`
|
||
|
|
}
|
||
|
|
require.NoError(t, json.Unmarshal(env.Data, &data))
|
||
|
|
require.NotEmpty(t, data.List)
|
||
|
|
require.NotEmpty(t, data.List[0].ID)
|
||
|
|
return data.List[0].ID
|
||
|
|
}
|