IAM: Change required permission in the app (#109894)

* Update required permissions

* Align tests
This commit is contained in:
Misi 2025-08-21 13:33:56 +02:00 committed by GitHub
parent 17438dcb6d
commit aade015d96
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 35 additions and 15 deletions

View File

@ -57,8 +57,8 @@ func newLegacyAccessClient(ac accesscontrol.AccessControl, store legacy.LegacyId
Resource: legacyiamv0.UserResourceInfo.GetName(),
Attr: "id",
Mapping: map[string]string{
utils.VerbCreate: accesscontrol.ActionOrgUsersWrite,
utils.VerbDelete: accesscontrol.ActionOrgUsersWrite,
utils.VerbCreate: accesscontrol.ActionUsersCreate,
utils.VerbDelete: accesscontrol.ActionUsersDelete,
utils.VerbGet: accesscontrol.ActionOrgUsersRead,
utils.VerbList: accesscontrol.ActionOrgUsersRead,
},

View File

@ -2,6 +2,7 @@ package iam
import (
"context"
"fmt"
"maps"
"strings"
@ -264,12 +265,24 @@ func (b *IdentityAccessManagementAPIBuilder) Validate(ctx context.Context, a adm
return nil
}
func (b *IdentityAccessManagementAPIBuilder) validateCreateUser(_ context.Context, a admission.Attributes, o admission.ObjectInterfaces) error {
func (b *IdentityAccessManagementAPIBuilder) validateCreateUser(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error {
userObj, ok := a.GetObject().(*iamv0.User)
if !ok {
return nil
}
requester, err := identity.GetRequester(ctx)
if err != nil {
return apierrors.NewBadRequest("no identity found")
}
// Temporary validation that the user is not trying to create a Grafana Admin without being a Grafana Admin.
if userObj.Spec.GrafanaAdmin && !requester.GetIsGrafanaAdmin() {
return apierrors.NewForbidden(legacyiamv0.UserResourceInfo.GroupResource(),
userObj.Name,
fmt.Errorf("only grafana admins can create grafana admins"))
}
if userObj.Spec.Login == "" && userObj.Spec.Email == "" {
return apierrors.NewBadRequest("user must have either login or email")
}

View File

@ -6,6 +6,7 @@ import (
"testing"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
@ -211,12 +212,13 @@ func TestIntegrationUsers(t *testing.T) {
}
func doUserCRUDTestsUsingTheNewAPIs(t *testing.T, helper *apis.K8sTestHelper) {
t.Run("should create user and delete it using the new APIs", func(t *testing.T) {
t.Run("should create user and delete it using the new APIs as a GrafanaAdmin", func(t *testing.T) {
ctx := context.Background()
userClient := helper.GetResourceClient(apis.ResourceClientArgs{
User: helper.Org1.Admin,
GVR: gvrUsers,
User: helper.Org1.Admin,
Namespace: helper.Namespacer(helper.Org1.Admin.Identity.GetOrgID()),
GVR: gvrUsers,
})
// Create the user
@ -253,31 +255,36 @@ func doUserCRUDTestsUsingTheNewAPIs(t *testing.T, helper *apis.K8sTestHelper) {
require.Equal(t, createdUID, fetched.GetName())
require.Equal(t, "default", fetched.GetNamespace())
err = userClient.Resource.Delete(ctx, createdUID, metav1.DeleteOptions{})
require.NoError(t, err)
// TODO: Uncomment when we know how to handle global scope (global.users:)
// err = userClient.Resource.Delete(ctx, createdUID, metav1.DeleteOptions{})
// require.NoError(t, err)
// Verify deletion
_, err = userClient.Resource.Get(ctx, createdUID, metav1.GetOptions{})
require.Error(t, err)
require.Contains(t, err.Error(), "not found")
// _, err = userClient.Resource.Get(ctx, createdUID, metav1.GetOptions{})
// require.Error(t, err)
// require.Contains(t, err.Error(), "not found")
})
t.Run("should not be able to create user when using a user with insufficient permissions", func(t *testing.T) {
for _, user := range []apis.User{
helper.OrgB.Admin, // Not a Grafana Admin
helper.Org1.Editor,
helper.Org1.Viewer,
} {
t.Run(fmt.Sprintf("with basic role: %s", user.Identity.GetOrgRole()), func(t *testing.T) {
t.Run(fmt.Sprintf("with basic role_%s", user.Identity.GetOrgRole()), func(t *testing.T) {
ctx := context.Background()
userClient := helper.GetResourceClient(apis.ResourceClientArgs{
User: user,
GVR: gvrUsers,
User: user,
Namespace: helper.Namespacer(helper.Org1.Admin.Identity.GetOrgID()),
GVR: gvrUsers,
})
// Create the user
_, err := userClient.Resource.Create(ctx, helper.LoadYAMLOrJSONFile("testdata/user-test-create-v0.yaml"), metav1.CreateOptions{})
require.Error(t, err)
require.Contains(t, err.Error(), "unauthorized request")
var statusErr *errors.StatusError
require.ErrorAs(t, err, &statusErr)
require.Equal(t, int32(403), statusErr.ErrStatus.Code)
})
}
})