IAM: Add the implementation of the Update User API (#112054)

* wip

* Add validate, wire mutate, add tests

* Address copilot's feedback

* Address feedback
This commit is contained in:
Misi
2025-10-13 10:00:18 +02:00
committed by GitHub
parent 85174e3313
commit bd1dbb68ba
21 changed files with 820 additions and 22 deletions
+71
View File
@@ -6,6 +6,7 @@ import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
"github.com/grafana/authlib/types"
iamv0alpha1 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1"
"github.com/grafana/grafana/pkg/apimachinery/identity"
)
@@ -27,5 +28,75 @@ func ValidateOnCreate(ctx context.Context, obj *iamv0alpha1.User) error {
return apierrors.NewBadRequest("user must have either login or email")
}
err = validateRole(obj)
if err != nil {
return err
}
return nil
}
func validateRole(obj *iamv0alpha1.User) error {
if obj.Spec.Role == "" {
return apierrors.NewBadRequest("role is required")
}
if !identity.RoleType(obj.Spec.Role).IsValid() {
return apierrors.NewBadRequest(fmt.Sprintf("invalid role '%s'", obj.Spec.Role))
}
return nil
}
func ValidateOnUpdate(ctx context.Context, oldObj, newObj *iamv0alpha1.User) error {
requester, err := identity.GetRequester(ctx)
if err != nil {
return apierrors.NewUnauthorized("no identity found")
}
isGrafanaAdmin := requester.GetIsGrafanaAdmin()
isServiceUser := requester.IsIdentityType(types.TypeAccessPolicy)
if !isGrafanaAdmin {
if newObj.Spec.Disabled != oldObj.Spec.Disabled {
return apierrors.NewForbidden(iamv0alpha1.UserResourceInfo.GroupResource(),
newObj.Name,
fmt.Errorf("only grafana admins can disable or enable a user"))
}
if newObj.Spec.GrafanaAdmin != oldObj.Spec.GrafanaAdmin {
return apierrors.NewForbidden(iamv0alpha1.UserResourceInfo.GroupResource(),
newObj.Name,
fmt.Errorf("only grafana admins can change grafana admin status"))
}
}
if !newObj.Spec.Provisioned && oldObj.Spec.Provisioned {
return apierrors.NewForbidden(iamv0alpha1.UserResourceInfo.GroupResource(),
newObj.Name,
fmt.Errorf("provisioned user cannot be un-provisioned"))
}
if !isServiceUser {
if newObj.Spec.Provisioned && !oldObj.Spec.Provisioned {
return apierrors.NewForbidden(iamv0alpha1.UserResourceInfo.GroupResource(),
newObj.Name,
fmt.Errorf("only service users can provision a user"))
}
if newObj.Spec.EmailVerified && !oldObj.Spec.EmailVerified {
return apierrors.NewForbidden(iamv0alpha1.UserResourceInfo.GroupResource(),
newObj.Name,
fmt.Errorf("only service users can verify email"))
}
}
if newObj.Spec.Login == "" && newObj.Spec.Email == "" {
return apierrors.NewBadRequest("user must have either login or email")
}
err = validateRole(newObj)
if err != nil {
return err
}
return nil
}