예제 #1
0
func (m *VirtualStorage) createRole(ctx kapi.Context, obj runtime.Object, allowEscalation bool) (*authorizationapi.Role, error) {
	if err := rest.BeforeCreate(m.CreateStrategy, ctx, obj); err != nil {
		return nil, err
	}

	role := obj.(*authorizationapi.Role)
	if !allowEscalation {
		if err := rulevalidation.ConfirmNoEscalation(ctx, authorizationapi.Resource("role"), role.Name, m.RuleResolver, authorizationinterfaces.NewLocalRoleAdapter(role)); err != nil {
			return nil, err
		}
	}

	policy, err := m.EnsurePolicy(ctx)
	if err != nil {
		return nil, err
	}
	if _, exists := policy.Roles[role.Name]; exists {
		return nil, kapierrors.NewAlreadyExists(authorizationapi.Resource("role"), role.Name)
	}

	role.ResourceVersion = policy.ResourceVersion
	policy.Roles[role.Name] = role
	policy.LastModified = unversioned.Now()

	if err := m.PolicyStorage.UpdatePolicy(ctx, policy); err != nil {
		return nil, err
	}

	return role, nil
}
예제 #2
0
func (m *VirtualStorage) confirmNoEscalation(ctx kapi.Context, roleBinding *authorizationapi.RoleBinding) error {
	modifyingRole, err := m.RuleResolver.GetRole(authorizationinterfaces.NewLocalRoleBindingAdapter(roleBinding))
	if err != nil {
		return err
	}

	return rulevalidation.ConfirmNoEscalation(ctx, authorizationapi.Resource("rolebinding"), roleBinding.Name, m.RuleResolver, modifyingRole)
}
예제 #3
0
func (m *VirtualStorage) updateRole(ctx kapi.Context, name string, objInfo rest.UpdatedObjectInfo, allowEscalation bool) (*authorizationapi.Role, bool, error) {
	old, err := m.Get(ctx, name)
	if err != nil {
		return nil, false, err
	}

	obj, err := objInfo.UpdatedObject(ctx, old)
	if err != nil {
		return nil, false, err
	}

	role, ok := obj.(*authorizationapi.Role)
	if !ok {
		return nil, false, kapierrors.NewBadRequest(fmt.Sprintf("obj is not a role: %#v", obj))
	}

	if err := rest.BeforeUpdate(m.UpdateStrategy, ctx, obj, old); err != nil {
		return nil, false, err
	}

	if !allowEscalation {
		if err := rulevalidation.ConfirmNoEscalation(ctx, authorizationapi.Resource("role"), role.Name, m.RuleResolver, authorizationinterfaces.NewLocalRoleAdapter(role)); err != nil {
			return nil, false, err
		}
	}

	policy, err := m.PolicyStorage.GetPolicy(ctx, authorizationapi.PolicyName)
	if err != nil && kapierrors.IsNotFound(err) {
		return nil, false, kapierrors.NewNotFound(authorizationapi.Resource("role"), role.Name)
	}
	if err != nil {
		return nil, false, err
	}

	oldRole, exists := policy.Roles[role.Name]
	if !exists {
		return nil, false, kapierrors.NewNotFound(authorizationapi.Resource("role"), role.Name)
	}

	// non-mutating change
	if kapi.Semantic.DeepEqual(oldRole, role) {
		return role, false, nil
	}

	role.ResourceVersion = policy.ResourceVersion
	policy.Roles[role.Name] = role
	policy.LastModified = unversioned.Now()

	if err := m.PolicyStorage.UpdatePolicy(ctx, policy); err != nil {
		return nil, false, err
	}
	return role, false, nil
}
예제 #4
0
func (m *VirtualStorage) createRole(ctx kapi.Context, obj runtime.Object, allowEscalation bool) (*authorizationapi.Role, error) {
	// Copy object before passing to BeforeCreate, since it mutates
	objCopy, err := kapi.Scheme.DeepCopy(obj)
	if err != nil {
		return nil, err
	}
	obj = objCopy.(runtime.Object)

	if err := rest.BeforeCreate(m.CreateStrategy, ctx, obj); err != nil {
		return nil, err
	}

	role := obj.(*authorizationapi.Role)
	if !allowEscalation {
		if err := rulevalidation.ConfirmNoEscalation(ctx, m.Resource, role.Name, m.RuleResolver, m.CachedRuleResolver, authorizationinterfaces.NewLocalRoleAdapter(role)); err != nil {
			return nil, err
		}
	}

	if err := kclient.RetryOnConflict(kclient.DefaultRetry, func() error {
		policy, err := m.EnsurePolicy(ctx)
		if err != nil {
			return err
		}
		if _, exists := policy.Roles[role.Name]; exists {
			return kapierrors.NewAlreadyExists(m.Resource, role.Name)
		}

		role.ResourceVersion = policy.ResourceVersion
		policy.Roles[role.Name] = role
		policy.LastModified = unversioned.Now()

		return m.PolicyStorage.UpdatePolicy(ctx, policy)
	}); err != nil {
		return nil, err
	}

	return role, nil
}
예제 #5
0
func (m *VirtualStorage) updateRole(ctx kapi.Context, name string, objInfo rest.UpdatedObjectInfo, allowEscalation bool) (*authorizationapi.Role, bool, error) {
	var updatedRole *authorizationapi.Role
	var roleConflicted = false

	// Retry if the policy update hits a conflict
	if err := kclient.RetryOnConflict(kclient.DefaultRetry, func() error {
		policy, err := m.PolicyStorage.GetPolicy(ctx, authorizationapi.PolicyName)
		if kapierrors.IsNotFound(err) {
			return kapierrors.NewNotFound(m.Resource, name)
		}
		if err != nil {
			return err
		}

		oldRole, exists := policy.Roles[name]
		if !exists {
			return kapierrors.NewNotFound(m.Resource, name)
		}

		obj, err := objInfo.UpdatedObject(ctx, oldRole)
		if err != nil {
			return err
		}

		role, ok := obj.(*authorizationapi.Role)
		if !ok {
			return kapierrors.NewBadRequest(fmt.Sprintf("obj is not a role: %#v", obj))
		}

		if len(role.ResourceVersion) == 0 && m.UpdateStrategy.AllowUnconditionalUpdate() {
			role.ResourceVersion = oldRole.ResourceVersion
		}

		if err := rest.BeforeUpdate(m.UpdateStrategy, ctx, obj, oldRole); err != nil {
			return err
		}

		if !allowEscalation {
			if err := rulevalidation.ConfirmNoEscalation(ctx, m.Resource, role.Name, m.RuleResolver, m.CachedRuleResolver, authorizationinterfaces.NewLocalRoleAdapter(role)); err != nil {
				return err
			}
		}

		// conflict detection
		if role.ResourceVersion != oldRole.ResourceVersion {
			// mark as a conflict err, but return an untyped error to escape the retry
			roleConflicted = true
			return errors.New(registry.OptimisticLockErrorMsg)
		}
		// non-mutating change
		if kapi.Semantic.DeepEqual(oldRole, role) {
			updatedRole = role
			return nil
		}

		role.ResourceVersion = policy.ResourceVersion
		policy.Roles[role.Name] = role
		policy.LastModified = unversioned.Now()

		if err := m.PolicyStorage.UpdatePolicy(ctx, policy); err != nil {
			return err
		}
		updatedRole = role
		return nil
	}); err != nil {
		if roleConflicted {
			// construct the typed conflict error
			return nil, false, kapierrors.NewConflict(authorizationapi.Resource("name"), name, err)
		}
		return nil, false, err
	}

	return updatedRole, false, nil
}