Commit 330c9227 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #39729 from sttts/sttts-split-server-side-rbac-validation

Automatic merge from submit-queue Split out server-only code from api packages shared with the client Fixes staging/copy.sh.
parents 12e8271c 4a1d5077
...@@ -29,11 +29,9 @@ go_library( ...@@ -29,11 +29,9 @@ go_library(
deps = [ deps = [
"//pkg/api/resource:go_default_library", "//pkg/api/resource:go_default_library",
"//pkg/fields:go_default_library", "//pkg/fields:go_default_library",
"//pkg/genericapiserver/api/request:go_default_library",
"//pkg/util/intstr:go_default_library", "//pkg/util/intstr:go_default_library",
"//pkg/util/labels:go_default_library", "//pkg/util/labels:go_default_library",
"//pkg/util/rand:go_default_library", "//pkg/util/rand:go_default_library",
"//pkg/util/uuid:go_default_library",
"//vendor:github.com/davecgh/go-spew/spew", "//vendor:github.com/davecgh/go-spew/spew",
"//vendor:k8s.io/apimachinery/pkg/api/meta", "//vendor:k8s.io/apimachinery/pkg/api/meta",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
...@@ -88,8 +86,6 @@ go_test( ...@@ -88,8 +86,6 @@ go_test(
"//pkg/apis/batch/v2alpha1:go_default_library", "//pkg/apis/batch/v2alpha1:go_default_library",
"//pkg/apis/extensions:go_default_library", "//pkg/apis/extensions:go_default_library",
"//pkg/apis/extensions/v1beta1:go_default_library", "//pkg/apis/extensions/v1beta1:go_default_library",
"//pkg/genericapiserver/api/request:go_default_library",
"//pkg/util/uuid:go_default_library",
"//vendor:github.com/davecgh/go-spew/spew", "//vendor:github.com/davecgh/go-spew/spew",
"//vendor:github.com/gogo/protobuf/proto", "//vendor:github.com/gogo/protobuf/proto",
"//vendor:github.com/golang/protobuf/proto", "//vendor:github.com/golang/protobuf/proto",
......
...@@ -22,23 +22,8 @@ import ( ...@@ -22,23 +22,8 @@ import (
"k8s.io/apimachinery/pkg/conversion" "k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
"k8s.io/kubernetes/pkg/util/uuid"
) )
// FillObjectMetaSystemFields populates fields that are managed by the system on ObjectMeta.
func FillObjectMetaSystemFields(ctx genericapirequest.Context, meta *ObjectMeta) {
meta.CreationTimestamp = metav1.Now()
// allows admission controllers to assign a UID earlier in the request processing
// to support tracking resources pending creation.
uid, found := genericapirequest.UIDFrom(ctx)
if !found {
uid = uuid.NewUUID()
}
meta.UID = uid
meta.SelfLink = ""
}
// HasObjectMetaSystemFieldValues returns true if fields that are managed by the system on ObjectMeta have values. // HasObjectMetaSystemFieldValues returns true if fields that are managed by the system on ObjectMeta have values.
func HasObjectMetaSystemFieldValues(meta *ObjectMeta) bool { func HasObjectMetaSystemFieldValues(meta *ObjectMeta) bool {
return !meta.CreationTimestamp.Time.IsZero() || return !meta.CreationTimestamp.Time.IsZero() ||
......
...@@ -28,45 +28,10 @@ import ( ...@@ -28,45 +28,10 @@ import (
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
"k8s.io/kubernetes/pkg/util/uuid"
) )
var _ meta.Object = &api.ObjectMeta{} var _ meta.Object = &api.ObjectMeta{}
// TestFillObjectMetaSystemFields validates that system populated fields are set on an object
func TestFillObjectMetaSystemFields(t *testing.T) {
ctx := genericapirequest.NewDefaultContext()
resource := api.ObjectMeta{}
api.FillObjectMetaSystemFields(ctx, &resource)
if resource.CreationTimestamp.Time.IsZero() {
t.Errorf("resource.CreationTimestamp is zero")
} else if len(resource.UID) == 0 {
t.Errorf("resource.UID missing")
}
// verify we can inject a UID
uid := uuid.NewUUID()
ctx = genericapirequest.WithUID(ctx, uid)
resource = api.ObjectMeta{}
api.FillObjectMetaSystemFields(ctx, &resource)
if resource.UID != uid {
t.Errorf("resource.UID expected: %v, actual: %v", uid, resource.UID)
}
}
// TestHasObjectMetaSystemFieldValues validates that true is returned if and only if all fields are populated
func TestHasObjectMetaSystemFieldValues(t *testing.T) {
ctx := genericapirequest.NewDefaultContext()
resource := api.ObjectMeta{}
if api.HasObjectMetaSystemFieldValues(&resource) {
t.Errorf("the resource does not have all fields yet populated, but incorrectly reports it does")
}
api.FillObjectMetaSystemFields(ctx, &resource)
if !api.HasObjectMetaSystemFieldValues(&resource) {
t.Errorf("the resource does have all fields populated, but incorrectly reports it does not")
}
}
func getObjectMetaAndOwnerReferences() (objectMeta api.ObjectMeta, metaOwnerReferences []metav1.OwnerReference) { func getObjectMetaAndOwnerReferences() (objectMeta api.ObjectMeta, metaOwnerReferences []metav1.OwnerReference) {
fuzz.New().NilChance(.5).NumElements(1, 5).Fuzz(&objectMeta) fuzz.New().NilChance(.5).NumElements(1, 5).Fuzz(&objectMeta)
references := objectMeta.OwnerReferences references := objectMeta.OwnerReferences
......
...@@ -21,7 +21,6 @@ import ( ...@@ -21,7 +21,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/api/resource" "k8s.io/kubernetes/pkg/api/resource"
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
) )
// Returns string version of ResourceName. // Returns string version of ResourceName.
...@@ -228,13 +227,3 @@ func PodRequestsAndLimits(pod *Pod) (reqs map[ResourceName]resource.Quantity, li ...@@ -228,13 +227,3 @@ func PodRequestsAndLimits(pod *Pod) (reqs map[ResourceName]resource.Quantity, li
} }
return return
} }
// ValidNamespace returns false if the namespace on the context differs from the resource. If the resource has no namespace, it is set to the value in the context.
// TODO(sttts): move into pkg/genericapiserver/api
func ValidNamespace(ctx genericapirequest.Context, resource *ObjectMeta) bool {
ns, ok := genericapirequest.NamespaceFrom(ctx)
if len(resource.Namespace) == 0 {
resource.Namespace = ns
}
return ns == resource.Namespace && ok
}
...@@ -5,6 +5,7 @@ licenses(["notice"]) ...@@ -5,6 +5,7 @@ licenses(["notice"])
load( load(
"@io_bazel_rules_go//go:def.bzl", "@io_bazel_rules_go//go:def.bzl",
"go_library", "go_library",
"go_test",
) )
go_library( go_library(
...@@ -14,6 +15,7 @@ go_library( ...@@ -14,6 +15,7 @@ go_library(
"delete.go", "delete.go",
"doc.go", "doc.go",
"export.go", "export.go",
"meta.go",
"rest.go", "rest.go",
"types.go", "types.go",
"update.go", "update.go",
...@@ -25,6 +27,7 @@ go_library( ...@@ -25,6 +27,7 @@ go_library(
"//pkg/api/validation/genericvalidation:go_default_library", "//pkg/api/validation/genericvalidation:go_default_library",
"//pkg/api/validation/path:go_default_library", "//pkg/api/validation/path:go_default_library",
"//pkg/genericapiserver/api/request:go_default_library", "//pkg/genericapiserver/api/request:go_default_library",
"//pkg/util/uuid:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/api/meta", "//vendor:k8s.io/apimachinery/pkg/api/meta",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/runtime", "//vendor:k8s.io/apimachinery/pkg/runtime",
...@@ -49,3 +52,15 @@ filegroup( ...@@ -49,3 +52,15 @@ filegroup(
], ],
tags = ["automanaged"], tags = ["automanaged"],
) )
go_test(
name = "go_default_test",
srcs = ["meta_test.go"],
library = ":go_default_library",
tags = ["automanaged"],
deps = [
"//pkg/api:go_default_library",
"//pkg/genericapiserver/api/request:go_default_library",
"//pkg/util/uuid:go_default_library",
],
)
...@@ -23,7 +23,7 @@ import ( ...@@ -23,7 +23,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/validation/genericvalidation" "k8s.io/kubernetes/pkg/api/validation/genericvalidation"
path "k8s.io/kubernetes/pkg/api/validation/path" "k8s.io/kubernetes/pkg/api/validation/path"
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request" genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
) )
...@@ -61,7 +61,7 @@ func BeforeCreate(strategy RESTCreateStrategy, ctx genericapirequest.Context, ob ...@@ -61,7 +61,7 @@ func BeforeCreate(strategy RESTCreateStrategy, ctx genericapirequest.Context, ob
} }
if strategy.NamespaceScoped() { if strategy.NamespaceScoped() {
if !api.ValidNamespace(ctx, objectMeta) { if !ValidNamespace(ctx, objectMeta) {
return errors.NewBadRequest("the namespace of the provided object does not match the namespace sent on the request") return errors.NewBadRequest("the namespace of the provided object does not match the namespace sent on the request")
} }
} else { } else {
...@@ -70,7 +70,7 @@ func BeforeCreate(strategy RESTCreateStrategy, ctx genericapirequest.Context, ob ...@@ -70,7 +70,7 @@ func BeforeCreate(strategy RESTCreateStrategy, ctx genericapirequest.Context, ob
objectMeta.DeletionTimestamp = nil objectMeta.DeletionTimestamp = nil
objectMeta.DeletionGracePeriodSeconds = nil objectMeta.DeletionGracePeriodSeconds = nil
strategy.PrepareForCreate(ctx, obj) strategy.PrepareForCreate(ctx, obj)
api.FillObjectMetaSystemFields(ctx, objectMeta) FillObjectMetaSystemFields(ctx, objectMeta)
api.GenerateName(strategy, objectMeta) api.GenerateName(strategy, objectMeta)
// ClusterName is ignored and should not be saved // ClusterName is ignored and should not be saved
......
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package rest
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/api"
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
"k8s.io/kubernetes/pkg/util/uuid"
)
// FillObjectMetaSystemFields populates fields that are managed by the system on ObjectMeta.
func FillObjectMetaSystemFields(ctx genericapirequest.Context, meta *api.ObjectMeta) {
meta.CreationTimestamp = metav1.Now()
// allows admission controllers to assign a UID earlier in the request processing
// to support tracking resources pending creation.
uid, found := genericapirequest.UIDFrom(ctx)
if !found {
uid = uuid.NewUUID()
}
meta.UID = uid
meta.SelfLink = ""
}
// ValidNamespace returns false if the namespace on the context differs from the resource. If the resource has no namespace, it is set to the value in the context.
// TODO(sttts): move into pkg/genericapiserver/api
func ValidNamespace(ctx genericapirequest.Context, resource *api.ObjectMeta) bool {
ns, ok := genericapirequest.NamespaceFrom(ctx)
if len(resource.Namespace) == 0 {
resource.Namespace = ns
}
return ns == resource.Namespace && ok
}
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package rest
import (
"testing"
"k8s.io/kubernetes/pkg/api"
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
"k8s.io/kubernetes/pkg/util/uuid"
)
// TestFillObjectMetaSystemFields validates that system populated fields are set on an object
func TestFillObjectMetaSystemFields(t *testing.T) {
ctx := genericapirequest.NewDefaultContext()
resource := api.ObjectMeta{}
FillObjectMetaSystemFields(ctx, &resource)
if resource.CreationTimestamp.Time.IsZero() {
t.Errorf("resource.CreationTimestamp is zero")
} else if len(resource.UID) == 0 {
t.Errorf("resource.UID missing")
}
// verify we can inject a UID
uid := uuid.NewUUID()
ctx = genericapirequest.WithUID(ctx, uid)
resource = api.ObjectMeta{}
FillObjectMetaSystemFields(ctx, &resource)
if resource.UID != uid {
t.Errorf("resource.UID expected: %v, actual: %v", uid, resource.UID)
}
}
// TestHasObjectMetaSystemFieldValues validates that true is returned if and only if all fields are populated
func TestHasObjectMetaSystemFieldValues(t *testing.T) {
ctx := genericapirequest.NewDefaultContext()
resource := api.ObjectMeta{}
if api.HasObjectMetaSystemFieldValues(&resource) {
t.Errorf("the resource does not have all fields yet populated, but incorrectly reports it does")
}
FillObjectMetaSystemFields(ctx, &resource)
if !api.HasObjectMetaSystemFieldValues(&resource) {
t.Errorf("the resource does have all fields populated, but incorrectly reports it does not")
}
}
// TestValidNamespace validates that namespace rules are enforced on a resource prior to create or update
func TestValidNamespace(t *testing.T) {
ctx := genericapirequest.NewDefaultContext()
namespace, _ := genericapirequest.NamespaceFrom(ctx)
resource := api.ReplicationController{}
if !ValidNamespace(ctx, &resource.ObjectMeta) {
t.Fatalf("expected success")
}
if namespace != resource.Namespace {
t.Fatalf("expected resource to have the default namespace assigned during validation")
}
resource = api.ReplicationController{ObjectMeta: api.ObjectMeta{Namespace: "other"}}
if ValidNamespace(ctx, &resource.ObjectMeta) {
t.Fatalf("Expected error that resource and context errors do not match because resource has different namespace")
}
ctx = genericapirequest.NewContext()
if ValidNamespace(ctx, &resource.ObjectMeta) {
t.Fatalf("Expected error that resource and context errors do not match since context has no namespace")
}
ctx = genericapirequest.NewContext()
ns := genericapirequest.NamespaceValue(ctx)
if ns != "" {
t.Fatalf("Expected the empty string")
}
}
...@@ -81,7 +81,7 @@ func BeforeUpdate(strategy RESTUpdateStrategy, ctx genericapirequest.Context, ob ...@@ -81,7 +81,7 @@ func BeforeUpdate(strategy RESTUpdateStrategy, ctx genericapirequest.Context, ob
return kerr return kerr
} }
if strategy.NamespaceScoped() { if strategy.NamespaceScoped() {
if !api.ValidNamespace(ctx, objectMeta) { if !ValidNamespace(ctx, objectMeta) {
return errors.NewBadRequest("the namespace of the provided object does not match the namespace sent on the request") return errors.NewBadRequest("the namespace of the provided object does not match the namespace sent on the request")
} }
} else { } else {
......
...@@ -22,7 +22,6 @@ go_library( ...@@ -22,7 +22,6 @@ go_library(
"//vendor:k8s.io/apimachinery/pkg/conversion", "//vendor:k8s.io/apimachinery/pkg/conversion",
"//vendor:k8s.io/apimachinery/pkg/runtime", "//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apimachinery/pkg/runtime/schema", "//vendor:k8s.io/apimachinery/pkg/runtime/schema",
"//vendor:k8s.io/apiserver/pkg/authentication/user",
], ],
) )
......
...@@ -19,10 +19,13 @@ package v0 ...@@ -19,10 +19,13 @@ package v0
import ( import (
"k8s.io/apimachinery/pkg/conversion" "k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/authentication/user"
api "k8s.io/kubernetes/pkg/apis/abac" api "k8s.io/kubernetes/pkg/apis/abac"
) )
// allAuthenticated matches k8s.io/apiserver/pkg/authentication/user.AllAuthenticated,
// but we don't want an client library (which must include types), depending on a server library
const allAuthenticated = "system:authenticated"
func addConversionFuncs(scheme *runtime.Scheme) error { func addConversionFuncs(scheme *runtime.Scheme) error {
return scheme.AddConversionFuncs( return scheme.AddConversionFuncs(
func(in *Policy, out *api.Policy, s conversion.Scope) error { func(in *Policy, out *api.Policy, s conversion.Scope) error {
...@@ -35,11 +38,11 @@ func addConversionFuncs(scheme *runtime.Scheme) error { ...@@ -35,11 +38,11 @@ func addConversionFuncs(scheme *runtime.Scheme) error {
// In v0, unspecified user and group matches all authenticated subjects // In v0, unspecified user and group matches all authenticated subjects
if len(in.User) == 0 && len(in.Group) == 0 { if len(in.User) == 0 && len(in.Group) == 0 {
out.Spec.Group = user.AllAuthenticated out.Spec.Group = allAuthenticated
} }
// In v0, user or group of * matches all authenticated subjects // In v0, user or group of * matches all authenticated subjects
if in.User == "*" || in.Group == "*" { if in.User == "*" || in.Group == "*" {
out.Spec.Group = user.AllAuthenticated out.Spec.Group = allAuthenticated
out.Spec.User = "" out.Spec.User = ""
} }
......
...@@ -26,7 +26,6 @@ go_library( ...@@ -26,7 +26,6 @@ go_library(
"//vendor:k8s.io/apimachinery/pkg/conversion", "//vendor:k8s.io/apimachinery/pkg/conversion",
"//vendor:k8s.io/apimachinery/pkg/runtime", "//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apimachinery/pkg/runtime/schema", "//vendor:k8s.io/apimachinery/pkg/runtime/schema",
"//vendor:k8s.io/apiserver/pkg/authentication/user",
], ],
) )
......
...@@ -19,10 +19,13 @@ package v1beta1 ...@@ -19,10 +19,13 @@ package v1beta1
import ( import (
"k8s.io/apimachinery/pkg/conversion" "k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/authentication/user"
api "k8s.io/kubernetes/pkg/apis/abac" api "k8s.io/kubernetes/pkg/apis/abac"
) )
// allAuthenticated matches k8s.io/apiserver/pkg/authentication/user.AllAuthenticated,
// but we don't want an client library (which must include types), depending on a server library
const allAuthenticated = "system:authenticated"
func addConversionFuncs(scheme *runtime.Scheme) error { func addConversionFuncs(scheme *runtime.Scheme) error {
return scheme.AddConversionFuncs( return scheme.AddConversionFuncs(
func(in *Policy, out *api.Policy, s conversion.Scope) error { func(in *Policy, out *api.Policy, s conversion.Scope) error {
...@@ -33,7 +36,7 @@ func addConversionFuncs(scheme *runtime.Scheme) error { ...@@ -33,7 +36,7 @@ func addConversionFuncs(scheme *runtime.Scheme) error {
// In v1beta1, * user or group maps to all authenticated subjects // In v1beta1, * user or group maps to all authenticated subjects
if in.Spec.User == "*" || in.Spec.Group == "*" { if in.Spec.User == "*" || in.Spec.Group == "*" {
out.Spec.Group = user.AllAuthenticated out.Spec.Group = allAuthenticated
out.Spec.User = "" out.Spec.User = ""
} }
......
...@@ -10,41 +10,25 @@ load( ...@@ -10,41 +10,25 @@ load(
go_library( go_library(
name = "go_default_library", name = "go_default_library",
srcs = [ srcs = ["validation.go"],
"policy_comparator.go",
"rulevalidation.go",
"validation.go",
],
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//pkg/api/errors:go_default_library",
"//pkg/api/validation:go_default_library", "//pkg/api/validation:go_default_library",
"//pkg/api/validation/path:go_default_library", "//pkg/api/validation/path:go_default_library",
"//pkg/apis/rbac:go_default_library", "//pkg/apis/rbac:go_default_library",
"//pkg/genericapiserver/api/request:go_default_library",
"//pkg/serviceaccount:go_default_library",
"//vendor:github.com/golang/glog",
"//vendor:k8s.io/apimachinery/pkg/util/errors",
"//vendor:k8s.io/apimachinery/pkg/util/validation/field", "//vendor:k8s.io/apimachinery/pkg/util/validation/field",
"//vendor:k8s.io/apiserver/pkg/authentication/user",
], ],
) )
go_test( go_test(
name = "go_default_test", name = "go_default_test",
srcs = [ srcs = ["validation_test.go"],
"policy_comparator_test.go",
"rulevalidation_test.go",
"validation_test.go",
],
library = ":go_default_library", library = ":go_default_library",
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/apis/rbac:go_default_library", "//pkg/apis/rbac:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/util/diff",
"//vendor:k8s.io/apimachinery/pkg/util/validation/field", "//vendor:k8s.io/apimachinery/pkg/util/validation/field",
"//vendor:k8s.io/apiserver/pkg/authentication/user",
], ],
) )
......
...@@ -20,7 +20,7 @@ import ( ...@@ -20,7 +20,7 @@ import (
"testing" "testing"
"k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apimachinery/pkg/util/validation/field"
api "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/rbac" "k8s.io/kubernetes/pkg/apis/rbac"
) )
...@@ -293,31 +293,6 @@ func TestValidateRoleBindingUpdate(t *testing.T) { ...@@ -293,31 +293,6 @@ func TestValidateRoleBindingUpdate(t *testing.T) {
} }
} }
func TestNonResourceURLCovers(t *testing.T) {
tests := []struct {
owner string
requested string
want bool
}{
{"*", "/api", true},
{"/api", "/api", true},
{"/apis", "/api", false},
{"/api/v1", "/api", false},
{"/api/v1", "/api/v1", true},
{"/api/*", "/api/v1", true},
{"/api/*", "/api", false},
{"/api/*/*", "/api/v1", false},
{"/*/v1/*", "/api/v1", false},
}
for _, tc := range tests {
got := nonResourceURLCovers(tc.owner, tc.requested)
if got != tc.want {
t.Errorf("nonResourceURLCovers(%q, %q): want=(%t), got=(%t)", tc.owner, tc.requested, tc.want, got)
}
}
}
type ValidateRoleTest struct { type ValidateRoleTest struct {
role rbac.Role role rbac.Role
wantErr bool wantErr bool
......
...@@ -43,33 +43,6 @@ func TestNamespaceContext(t *testing.T) { ...@@ -43,33 +43,6 @@ func TestNamespaceContext(t *testing.T) {
} }
} }
// TestValidNamespace validates that namespace rules are enforced on a resource prior to create or update
func TestValidNamespace(t *testing.T) {
ctx := genericapirequest.NewDefaultContext()
namespace, _ := genericapirequest.NamespaceFrom(ctx)
resource := api.ReplicationController{}
if !api.ValidNamespace(ctx, &resource.ObjectMeta) {
t.Fatalf("expected success")
}
if namespace != resource.Namespace {
t.Fatalf("expected resource to have the default namespace assigned during validation")
}
resource = api.ReplicationController{ObjectMeta: api.ObjectMeta{Namespace: "other"}}
if api.ValidNamespace(ctx, &resource.ObjectMeta) {
t.Fatalf("Expected error that resource and context errors do not match because resource has different namespace")
}
ctx = genericapirequest.NewContext()
if api.ValidNamespace(ctx, &resource.ObjectMeta) {
t.Fatalf("Expected error that resource and context errors do not match since context has no namespace")
}
ctx = genericapirequest.NewContext()
ns := genericapirequest.NamespaceValue(ctx)
if ns != "" {
t.Fatalf("Expected the empty string")
}
}
//TestUserContext validates that a userinfo can be get/set on a context object //TestUserContext validates that a userinfo can be get/set on a context object
func TestUserContext(t *testing.T) { func TestUserContext(t *testing.T) {
ctx := genericapirequest.NewContext() ctx := genericapirequest.NewContext()
......
...@@ -381,7 +381,7 @@ func (rs *REST) Update(ctx genericapirequest.Context, name string, objInfo rest. ...@@ -381,7 +381,7 @@ func (rs *REST) Update(ctx genericapirequest.Context, name string, objInfo rest.
} }
service := obj.(*api.Service) service := obj.(*api.Service)
if !api.ValidNamespace(ctx, &service.ObjectMeta) { if !rest.ValidNamespace(ctx, &service.ObjectMeta) {
return nil, false, errors.NewConflict(api.Resource("services"), service.Namespace, fmt.Errorf("Service.Namespace does not match the provided context")) return nil, false, errors.NewConflict(api.Resource("services"), service.Namespace, fmt.Errorf("Service.Namespace does not match the provided context"))
} }
......
...@@ -36,6 +36,7 @@ filegroup( ...@@ -36,6 +36,7 @@ filegroup(
"//pkg/registry/rbac/rest:all-srcs", "//pkg/registry/rbac/rest:all-srcs",
"//pkg/registry/rbac/role:all-srcs", "//pkg/registry/rbac/role:all-srcs",
"//pkg/registry/rbac/rolebinding:all-srcs", "//pkg/registry/rbac/rolebinding:all-srcs",
"//pkg/registry/rbac/validation:all-srcs",
], ],
tags = ["automanaged"], tags = ["automanaged"],
) )
...@@ -15,9 +15,9 @@ go_library( ...@@ -15,9 +15,9 @@ go_library(
"//pkg/api/errors:go_default_library", "//pkg/api/errors:go_default_library",
"//pkg/api/rest:go_default_library", "//pkg/api/rest:go_default_library",
"//pkg/apis/rbac:go_default_library", "//pkg/apis/rbac:go_default_library",
"//pkg/apis/rbac/validation:go_default_library",
"//pkg/genericapiserver/api/request:go_default_library", "//pkg/genericapiserver/api/request:go_default_library",
"//pkg/registry/rbac:go_default_library", "//pkg/registry/rbac:go_default_library",
"//pkg/registry/rbac/validation:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/runtime", "//vendor:k8s.io/apimachinery/pkg/runtime",
], ],
) )
......
...@@ -22,9 +22,9 @@ import ( ...@@ -22,9 +22,9 @@ import (
"k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/rest" "k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/apis/rbac" "k8s.io/kubernetes/pkg/apis/rbac"
"k8s.io/kubernetes/pkg/apis/rbac/validation"
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request" genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
rbacregistry "k8s.io/kubernetes/pkg/registry/rbac" rbacregistry "k8s.io/kubernetes/pkg/registry/rbac"
rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
) )
var groupResource = rbac.Resource("clusterroles") var groupResource = rbac.Resource("clusterroles")
...@@ -32,10 +32,10 @@ var groupResource = rbac.Resource("clusterroles") ...@@ -32,10 +32,10 @@ var groupResource = rbac.Resource("clusterroles")
type Storage struct { type Storage struct {
rest.StandardStorage rest.StandardStorage
ruleResolver validation.AuthorizationRuleResolver ruleResolver rbacregistryvalidation.AuthorizationRuleResolver
} }
func NewStorage(s rest.StandardStorage, ruleResolver validation.AuthorizationRuleResolver) *Storage { func NewStorage(s rest.StandardStorage, ruleResolver rbacregistryvalidation.AuthorizationRuleResolver) *Storage {
return &Storage{s, ruleResolver} return &Storage{s, ruleResolver}
} }
...@@ -46,7 +46,7 @@ func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object) (run ...@@ -46,7 +46,7 @@ func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object) (run
clusterRole := obj.(*rbac.ClusterRole) clusterRole := obj.(*rbac.ClusterRole)
rules := clusterRole.Rules rules := clusterRole.Rules
if err := validation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil { if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
return nil, errors.NewForbidden(groupResource, clusterRole.Name, err) return nil, errors.NewForbidden(groupResource, clusterRole.Name, err)
} }
return s.StandardStorage.Create(ctx, obj) return s.StandardStorage.Create(ctx, obj)
...@@ -61,7 +61,7 @@ func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.Up ...@@ -61,7 +61,7 @@ func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.Up
clusterRole := obj.(*rbac.ClusterRole) clusterRole := obj.(*rbac.ClusterRole)
rules := clusterRole.Rules rules := clusterRole.Rules
if err := validation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil { if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
return nil, errors.NewForbidden(groupResource, clusterRole.Name, err) return nil, errors.NewForbidden(groupResource, clusterRole.Name, err)
} }
return obj, nil return obj, nil
......
...@@ -15,9 +15,9 @@ go_library( ...@@ -15,9 +15,9 @@ go_library(
"//pkg/api/errors:go_default_library", "//pkg/api/errors:go_default_library",
"//pkg/api/rest:go_default_library", "//pkg/api/rest:go_default_library",
"//pkg/apis/rbac:go_default_library", "//pkg/apis/rbac:go_default_library",
"//pkg/apis/rbac/validation:go_default_library",
"//pkg/genericapiserver/api/request:go_default_library", "//pkg/genericapiserver/api/request:go_default_library",
"//pkg/registry/rbac:go_default_library", "//pkg/registry/rbac:go_default_library",
"//pkg/registry/rbac/validation:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/runtime", "//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apiserver/pkg/authorization/authorizer", "//vendor:k8s.io/apiserver/pkg/authorization/authorizer",
], ],
......
...@@ -23,9 +23,9 @@ import ( ...@@ -23,9 +23,9 @@ import (
"k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/rest" "k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/apis/rbac" "k8s.io/kubernetes/pkg/apis/rbac"
"k8s.io/kubernetes/pkg/apis/rbac/validation"
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request" genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
rbacregistry "k8s.io/kubernetes/pkg/registry/rbac" rbacregistry "k8s.io/kubernetes/pkg/registry/rbac"
rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
) )
var groupResource = rbac.Resource("clusterrolebindings") var groupResource = rbac.Resource("clusterrolebindings")
...@@ -35,10 +35,10 @@ type Storage struct { ...@@ -35,10 +35,10 @@ type Storage struct {
authorizer authorizer.Authorizer authorizer authorizer.Authorizer
ruleResolver validation.AuthorizationRuleResolver ruleResolver rbacregistryvalidation.AuthorizationRuleResolver
} }
func NewStorage(s rest.StandardStorage, authorizer authorizer.Authorizer, ruleResolver validation.AuthorizationRuleResolver) *Storage { func NewStorage(s rest.StandardStorage, authorizer authorizer.Authorizer, ruleResolver rbacregistryvalidation.AuthorizationRuleResolver) *Storage {
return &Storage{s, authorizer, ruleResolver} return &Storage{s, authorizer, ruleResolver}
} }
...@@ -56,7 +56,7 @@ func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object) (run ...@@ -56,7 +56,7 @@ func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object) (run
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := validation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil { if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
return nil, errors.NewForbidden(groupResource, clusterRoleBinding.Name, err) return nil, errors.NewForbidden(groupResource, clusterRoleBinding.Name, err)
} }
return s.StandardStorage.Create(ctx, obj) return s.StandardStorage.Create(ctx, obj)
...@@ -80,7 +80,7 @@ func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.Up ...@@ -80,7 +80,7 @@ func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.Up
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := validation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil { if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
return nil, errors.NewForbidden(groupResource, clusterRoleBinding.Name, err) return nil, errors.NewForbidden(groupResource, clusterRoleBinding.Name, err)
} }
return obj, nil return obj, nil
......
...@@ -16,7 +16,6 @@ go_library( ...@@ -16,7 +16,6 @@ go_library(
"//pkg/api/rest:go_default_library", "//pkg/api/rest:go_default_library",
"//pkg/apis/rbac:go_default_library", "//pkg/apis/rbac:go_default_library",
"//pkg/apis/rbac/v1alpha1:go_default_library", "//pkg/apis/rbac/v1alpha1:go_default_library",
"//pkg/apis/rbac/validation:go_default_library",
"//pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion:go_default_library", "//pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion:go_default_library",
"//pkg/genericapiserver:go_default_library", "//pkg/genericapiserver:go_default_library",
"//pkg/registry/generic:go_default_library", "//pkg/registry/generic:go_default_library",
...@@ -32,6 +31,7 @@ go_library( ...@@ -32,6 +31,7 @@ go_library(
"//pkg/registry/rbac/rolebinding:go_default_library", "//pkg/registry/rbac/rolebinding:go_default_library",
"//pkg/registry/rbac/rolebinding/etcd:go_default_library", "//pkg/registry/rbac/rolebinding/etcd:go_default_library",
"//pkg/registry/rbac/rolebinding/policybased:go_default_library", "//pkg/registry/rbac/rolebinding/policybased:go_default_library",
"//pkg/registry/rbac/validation:go_default_library",
"//plugin/pkg/auth/authorizer/rbac/bootstrappolicy:go_default_library", "//plugin/pkg/auth/authorizer/rbac/bootstrappolicy:go_default_library",
"//vendor:github.com/golang/glog", "//vendor:github.com/golang/glog",
"//vendor:k8s.io/apimachinery/pkg/util/runtime", "//vendor:k8s.io/apimachinery/pkg/util/runtime",
......
...@@ -30,7 +30,6 @@ import ( ...@@ -30,7 +30,6 @@ import (
"k8s.io/kubernetes/pkg/api/rest" "k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/apis/rbac" "k8s.io/kubernetes/pkg/apis/rbac"
rbacapiv1alpha1 "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1" rbacapiv1alpha1 "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1"
rbacvalidation "k8s.io/kubernetes/pkg/apis/rbac/validation"
rbacclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion" rbacclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
"k8s.io/kubernetes/pkg/genericapiserver" "k8s.io/kubernetes/pkg/genericapiserver"
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
...@@ -46,6 +45,7 @@ import ( ...@@ -46,6 +45,7 @@ import (
"k8s.io/kubernetes/pkg/registry/rbac/rolebinding" "k8s.io/kubernetes/pkg/registry/rbac/rolebinding"
rolebindingetcd "k8s.io/kubernetes/pkg/registry/rbac/rolebinding/etcd" rolebindingetcd "k8s.io/kubernetes/pkg/registry/rbac/rolebinding/etcd"
rolebindingpolicybased "k8s.io/kubernetes/pkg/registry/rbac/rolebinding/policybased" rolebindingpolicybased "k8s.io/kubernetes/pkg/registry/rbac/rolebinding/policybased"
rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
"k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy" "k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy"
) )
...@@ -71,7 +71,7 @@ func (p RESTStorageProvider) v1alpha1Storage(apiResourceConfigSource genericapis ...@@ -71,7 +71,7 @@ func (p RESTStorageProvider) v1alpha1Storage(apiResourceConfigSource genericapis
once := new(sync.Once) once := new(sync.Once)
var ( var (
authorizationRuleResolver rbacvalidation.AuthorizationRuleResolver authorizationRuleResolver rbacregistryvalidation.AuthorizationRuleResolver
rolesStorage rest.StandardStorage rolesStorage rest.StandardStorage
roleBindingsStorage rest.StandardStorage roleBindingsStorage rest.StandardStorage
clusterRolesStorage rest.StandardStorage clusterRolesStorage rest.StandardStorage
...@@ -85,7 +85,7 @@ func (p RESTStorageProvider) v1alpha1Storage(apiResourceConfigSource genericapis ...@@ -85,7 +85,7 @@ func (p RESTStorageProvider) v1alpha1Storage(apiResourceConfigSource genericapis
clusterRolesStorage = clusterroleetcd.NewREST(restOptionsGetter) clusterRolesStorage = clusterroleetcd.NewREST(restOptionsGetter)
clusterRoleBindingsStorage = clusterrolebindingetcd.NewREST(restOptionsGetter) clusterRoleBindingsStorage = clusterrolebindingetcd.NewREST(restOptionsGetter)
authorizationRuleResolver = rbacvalidation.NewDefaultRuleResolver( authorizationRuleResolver = rbacregistryvalidation.NewDefaultRuleResolver(
role.AuthorizerAdapter{Registry: role.NewRegistry(rolesStorage)}, role.AuthorizerAdapter{Registry: role.NewRegistry(rolesStorage)},
rolebinding.AuthorizerAdapter{Registry: rolebinding.NewRegistry(roleBindingsStorage)}, rolebinding.AuthorizerAdapter{Registry: rolebinding.NewRegistry(roleBindingsStorage)},
clusterrole.AuthorizerAdapter{Registry: clusterrole.NewRegistry(clusterRolesStorage)}, clusterrole.AuthorizerAdapter{Registry: clusterrole.NewRegistry(clusterRolesStorage)},
......
...@@ -15,9 +15,9 @@ go_library( ...@@ -15,9 +15,9 @@ go_library(
"//pkg/api/errors:go_default_library", "//pkg/api/errors:go_default_library",
"//pkg/api/rest:go_default_library", "//pkg/api/rest:go_default_library",
"//pkg/apis/rbac:go_default_library", "//pkg/apis/rbac:go_default_library",
"//pkg/apis/rbac/validation:go_default_library",
"//pkg/genericapiserver/api/request:go_default_library", "//pkg/genericapiserver/api/request:go_default_library",
"//pkg/registry/rbac:go_default_library", "//pkg/registry/rbac:go_default_library",
"//pkg/registry/rbac/validation:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/runtime", "//vendor:k8s.io/apimachinery/pkg/runtime",
], ],
) )
......
...@@ -22,9 +22,9 @@ import ( ...@@ -22,9 +22,9 @@ import (
"k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/rest" "k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/apis/rbac" "k8s.io/kubernetes/pkg/apis/rbac"
"k8s.io/kubernetes/pkg/apis/rbac/validation"
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request" genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
rbacregistry "k8s.io/kubernetes/pkg/registry/rbac" rbacregistry "k8s.io/kubernetes/pkg/registry/rbac"
rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
) )
var groupResource = rbac.Resource("roles") var groupResource = rbac.Resource("roles")
...@@ -32,10 +32,10 @@ var groupResource = rbac.Resource("roles") ...@@ -32,10 +32,10 @@ var groupResource = rbac.Resource("roles")
type Storage struct { type Storage struct {
rest.StandardStorage rest.StandardStorage
ruleResolver validation.AuthorizationRuleResolver ruleResolver rbacregistryvalidation.AuthorizationRuleResolver
} }
func NewStorage(s rest.StandardStorage, ruleResolver validation.AuthorizationRuleResolver) *Storage { func NewStorage(s rest.StandardStorage, ruleResolver rbacregistryvalidation.AuthorizationRuleResolver) *Storage {
return &Storage{s, ruleResolver} return &Storage{s, ruleResolver}
} }
...@@ -46,7 +46,7 @@ func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object) (run ...@@ -46,7 +46,7 @@ func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object) (run
role := obj.(*rbac.Role) role := obj.(*rbac.Role)
rules := role.Rules rules := role.Rules
if err := validation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil { if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
return nil, errors.NewForbidden(groupResource, role.Name, err) return nil, errors.NewForbidden(groupResource, role.Name, err)
} }
return s.StandardStorage.Create(ctx, obj) return s.StandardStorage.Create(ctx, obj)
...@@ -61,7 +61,7 @@ func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.Up ...@@ -61,7 +61,7 @@ func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.Up
role := obj.(*rbac.Role) role := obj.(*rbac.Role)
rules := role.Rules rules := role.Rules
if err := validation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil { if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
return nil, errors.NewForbidden(groupResource, role.Name, err) return nil, errors.NewForbidden(groupResource, role.Name, err)
} }
return obj, nil return obj, nil
......
...@@ -15,9 +15,9 @@ go_library( ...@@ -15,9 +15,9 @@ go_library(
"//pkg/api/errors:go_default_library", "//pkg/api/errors:go_default_library",
"//pkg/api/rest:go_default_library", "//pkg/api/rest:go_default_library",
"//pkg/apis/rbac:go_default_library", "//pkg/apis/rbac:go_default_library",
"//pkg/apis/rbac/validation:go_default_library",
"//pkg/genericapiserver/api/request:go_default_library", "//pkg/genericapiserver/api/request:go_default_library",
"//pkg/registry/rbac:go_default_library", "//pkg/registry/rbac:go_default_library",
"//pkg/registry/rbac/validation:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/runtime", "//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apiserver/pkg/authorization/authorizer", "//vendor:k8s.io/apiserver/pkg/authorization/authorizer",
], ],
......
...@@ -23,9 +23,9 @@ import ( ...@@ -23,9 +23,9 @@ import (
"k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/rest" "k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/apis/rbac" "k8s.io/kubernetes/pkg/apis/rbac"
"k8s.io/kubernetes/pkg/apis/rbac/validation"
genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request" genericapirequest "k8s.io/kubernetes/pkg/genericapiserver/api/request"
rbacregistry "k8s.io/kubernetes/pkg/registry/rbac" rbacregistry "k8s.io/kubernetes/pkg/registry/rbac"
rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
) )
var groupResource = rbac.Resource("rolebindings") var groupResource = rbac.Resource("rolebindings")
...@@ -35,10 +35,10 @@ type Storage struct { ...@@ -35,10 +35,10 @@ type Storage struct {
authorizer authorizer.Authorizer authorizer authorizer.Authorizer
ruleResolver validation.AuthorizationRuleResolver ruleResolver rbacregistryvalidation.AuthorizationRuleResolver
} }
func NewStorage(s rest.StandardStorage, authorizer authorizer.Authorizer, ruleResolver validation.AuthorizationRuleResolver) *Storage { func NewStorage(s rest.StandardStorage, authorizer authorizer.Authorizer, ruleResolver rbacregistryvalidation.AuthorizationRuleResolver) *Storage {
return &Storage{s, authorizer, ruleResolver} return &Storage{s, authorizer, ruleResolver}
} }
...@@ -56,7 +56,7 @@ func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object) (run ...@@ -56,7 +56,7 @@ func (s *Storage) Create(ctx genericapirequest.Context, obj runtime.Object) (run
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := validation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil { if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
return nil, errors.NewForbidden(groupResource, roleBinding.Name, err) return nil, errors.NewForbidden(groupResource, roleBinding.Name, err)
} }
return s.StandardStorage.Create(ctx, obj) return s.StandardStorage.Create(ctx, obj)
...@@ -80,7 +80,7 @@ func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.Up ...@@ -80,7 +80,7 @@ func (s *Storage) Update(ctx genericapirequest.Context, name string, obj rest.Up
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := validation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil { if err := rbacregistryvalidation.ConfirmNoEscalation(ctx, s.ruleResolver, rules); err != nil {
return nil, errors.NewForbidden(groupResource, roleBinding.Name, err) return nil, errors.NewForbidden(groupResource, roleBinding.Name, err)
} }
return obj, nil return obj, nil
......
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = [
"policy_comparator_test.go",
"rule_test.go",
],
library = ":go_default_library",
tags = ["automanaged"],
deps = [
"//pkg/api:go_default_library",
"//pkg/apis/rbac:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/util/diff",
"//vendor:k8s.io/apiserver/pkg/authentication/user",
],
)
go_library(
name = "go_default_library",
srcs = [
"policy_comparator.go",
"rule.go",
],
tags = ["automanaged"],
deps = [
"//pkg/api/errors:go_default_library",
"//pkg/apis/rbac:go_default_library",
"//pkg/genericapiserver/api/request:go_default_library",
"//pkg/serviceaccount:go_default_library",
"//vendor:github.com/golang/glog",
"//vendor:k8s.io/apimachinery/pkg/util/errors",
"//vendor:k8s.io/apiserver/pkg/authentication/user",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)
...@@ -400,3 +400,28 @@ func rulesMatch(expectedRules, actualRules []rbac.PolicyRule) bool { ...@@ -400,3 +400,28 @@ func rulesMatch(expectedRules, actualRules []rbac.PolicyRule) bool {
return true return true
} }
func TestNonResourceURLCovers(t *testing.T) {
tests := []struct {
owner string
requested string
want bool
}{
{"*", "/api", true},
{"/api", "/api", true},
{"/apis", "/api", false},
{"/api/v1", "/api", false},
{"/api/v1", "/api/v1", true},
{"/api/*", "/api/v1", true},
{"/api/*", "/api", false},
{"/api/*/*", "/api/v1", false},
{"/*/v1/*", "/api/v1", false},
}
for _, tc := range tests {
got := nonResourceURLCovers(tc.owner, tc.requested)
if got != tc.want {
t.Errorf("nonResourceURLCovers(%q, %q): want=(%t), got=(%t)", tc.owner, tc.requested, tc.want, got)
}
}
}
...@@ -17,7 +17,7 @@ go_library( ...@@ -17,7 +17,7 @@ go_library(
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//pkg/apis/rbac:go_default_library", "//pkg/apis/rbac:go_default_library",
"//pkg/apis/rbac/validation:go_default_library", "//pkg/registry/rbac/validation:go_default_library",
"//vendor:github.com/golang/glog", "//vendor:github.com/golang/glog",
"//vendor:k8s.io/apimachinery/pkg/util/errors", "//vendor:k8s.io/apimachinery/pkg/util/errors",
"//vendor:k8s.io/apiserver/pkg/authentication/user", "//vendor:k8s.io/apiserver/pkg/authentication/user",
...@@ -36,7 +36,7 @@ go_test( ...@@ -36,7 +36,7 @@ go_test(
deps = [ deps = [
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/apis/rbac:go_default_library", "//pkg/apis/rbac:go_default_library",
"//pkg/apis/rbac/validation:go_default_library", "//pkg/registry/rbac/validation:go_default_library",
"//vendor:k8s.io/apiserver/pkg/authentication/user", "//vendor:k8s.io/apiserver/pkg/authentication/user",
"//vendor:k8s.io/apiserver/pkg/authorization/authorizer", "//vendor:k8s.io/apiserver/pkg/authorization/authorizer",
], ],
......
...@@ -37,7 +37,7 @@ go_test( ...@@ -37,7 +37,7 @@ go_test(
"//pkg/apis/rbac:go_default_library", "//pkg/apis/rbac:go_default_library",
"//pkg/apis/rbac/install:go_default_library", "//pkg/apis/rbac/install:go_default_library",
"//pkg/apis/rbac/v1alpha1:go_default_library", "//pkg/apis/rbac/v1alpha1:go_default_library",
"//pkg/apis/rbac/validation:go_default_library", "//pkg/registry/rbac/validation:go_default_library",
"//plugin/pkg/auth/authorizer/rbac/bootstrappolicy:go_default_library", "//plugin/pkg/auth/authorizer/rbac/bootstrappolicy:go_default_library",
"//vendor:github.com/ghodss/yaml", "//vendor:github.com/ghodss/yaml",
"//vendor:k8s.io/apimachinery/pkg/api/meta", "//vendor:k8s.io/apimachinery/pkg/api/meta",
......
...@@ -32,10 +32,10 @@ import ( ...@@ -32,10 +32,10 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
_ "k8s.io/kubernetes/pkg/api/install" _ "k8s.io/kubernetes/pkg/api/install"
"k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/api/v1"
rbac "k8s.io/kubernetes/pkg/apis/rbac" "k8s.io/kubernetes/pkg/apis/rbac"
_ "k8s.io/kubernetes/pkg/apis/rbac/install" _ "k8s.io/kubernetes/pkg/apis/rbac/install"
rbacv1alpha1 "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1" rbacv1alpha1 "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1"
rbacvalidation "k8s.io/kubernetes/pkg/apis/rbac/validation" rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
"k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy" "k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy"
) )
...@@ -67,13 +67,13 @@ func getSemanticRoles(roles []rbac.ClusterRole) semanticRoles { ...@@ -67,13 +67,13 @@ func getSemanticRoles(roles []rbac.ClusterRole) semanticRoles {
func TestCovers(t *testing.T) { func TestCovers(t *testing.T) {
semanticRoles := getSemanticRoles(bootstrappolicy.ClusterRoles()) semanticRoles := getSemanticRoles(bootstrappolicy.ClusterRoles())
if covers, miss := rbacvalidation.Covers(semanticRoles.admin.Rules, semanticRoles.edit.Rules); !covers { if covers, miss := rbacregistryvalidation.Covers(semanticRoles.admin.Rules, semanticRoles.edit.Rules); !covers {
t.Errorf("failed to cover: %#v", miss) t.Errorf("failed to cover: %#v", miss)
} }
if covers, miss := rbacvalidation.Covers(semanticRoles.admin.Rules, semanticRoles.view.Rules); !covers { if covers, miss := rbacregistryvalidation.Covers(semanticRoles.admin.Rules, semanticRoles.view.Rules); !covers {
t.Errorf("failed to cover: %#v", miss) t.Errorf("failed to cover: %#v", miss)
} }
if covers, miss := rbacvalidation.Covers(semanticRoles.edit.Rules, semanticRoles.view.Rules); !covers { if covers, miss := rbacregistryvalidation.Covers(semanticRoles.edit.Rules, semanticRoles.view.Rules); !covers {
t.Errorf("failed to cover: %#v", miss) t.Errorf("failed to cover: %#v", miss)
} }
} }
...@@ -91,17 +91,17 @@ func TestAdminEditRelationship(t *testing.T) { ...@@ -91,17 +91,17 @@ func TestAdminEditRelationship(t *testing.T) {
// confirm that the edit role doesn't already have extra powers // confirm that the edit role doesn't already have extra powers
for _, rule := range additionalAdminPowers { for _, rule := range additionalAdminPowers {
if covers, _ := rbacvalidation.Covers(semanticRoles.edit.Rules, []rbac.PolicyRule{rule}); covers { if covers, _ := rbacregistryvalidation.Covers(semanticRoles.edit.Rules, []rbac.PolicyRule{rule}); covers {
t.Errorf("edit has extra powers: %#v", rule) t.Errorf("edit has extra powers: %#v", rule)
} }
} }
semanticRoles.edit.Rules = append(semanticRoles.edit.Rules, additionalAdminPowers...) semanticRoles.edit.Rules = append(semanticRoles.edit.Rules, additionalAdminPowers...)
// at this point, we should have a two way covers relationship // at this point, we should have a two way covers relationship
if covers, miss := rbacvalidation.Covers(semanticRoles.admin.Rules, semanticRoles.edit.Rules); !covers { if covers, miss := rbacregistryvalidation.Covers(semanticRoles.admin.Rules, semanticRoles.edit.Rules); !covers {
t.Errorf("admin has lost rules for: %#v", miss) t.Errorf("admin has lost rules for: %#v", miss)
} }
if covers, miss := rbacvalidation.Covers(semanticRoles.edit.Rules, semanticRoles.admin.Rules); !covers { if covers, miss := rbacregistryvalidation.Covers(semanticRoles.edit.Rules, semanticRoles.admin.Rules); !covers {
t.Errorf("edit is missing rules for: %#v\nIf these should only be admin powers, add them to the list. Otherwise, add them to the edit role.", miss) t.Errorf("edit is missing rules for: %#v\nIf these should only be admin powers, add them to the list. Otherwise, add them to the edit role.", miss)
} }
} }
...@@ -136,17 +136,17 @@ func TestEditViewRelationship(t *testing.T) { ...@@ -136,17 +136,17 @@ func TestEditViewRelationship(t *testing.T) {
// confirm that the view role doesn't already have extra powers // confirm that the view role doesn't already have extra powers
for _, rule := range viewEscalatingNamespaceResources { for _, rule := range viewEscalatingNamespaceResources {
if covers, _ := rbacvalidation.Covers(semanticRoles.view.Rules, []rbac.PolicyRule{rule}); covers { if covers, _ := rbacregistryvalidation.Covers(semanticRoles.view.Rules, []rbac.PolicyRule{rule}); covers {
t.Errorf("view has extra powers: %#v", rule) t.Errorf("view has extra powers: %#v", rule)
} }
} }
semanticRoles.view.Rules = append(semanticRoles.view.Rules, viewEscalatingNamespaceResources...) semanticRoles.view.Rules = append(semanticRoles.view.Rules, viewEscalatingNamespaceResources...)
// at this point, we should have a two way covers relationship // at this point, we should have a two way covers relationship
if covers, miss := rbacvalidation.Covers(semanticRoles.edit.Rules, semanticRoles.view.Rules); !covers { if covers, miss := rbacregistryvalidation.Covers(semanticRoles.edit.Rules, semanticRoles.view.Rules); !covers {
t.Errorf("edit has lost rules for: %#v", miss) t.Errorf("edit has lost rules for: %#v", miss)
} }
if covers, miss := rbacvalidation.Covers(semanticRoles.view.Rules, semanticRoles.edit.Rules); !covers { if covers, miss := rbacregistryvalidation.Covers(semanticRoles.view.Rules, semanticRoles.edit.Rules); !covers {
t.Errorf("view is missing rules for: %#v\nIf these are escalating powers, add them to the list. Otherwise, add them to the view role.", miss) t.Errorf("view is missing rules for: %#v\nIf these are escalating powers, add them to the list. Otherwise, add them to the view role.", miss)
} }
} }
......
...@@ -24,7 +24,7 @@ import ( ...@@ -24,7 +24,7 @@ import (
"k8s.io/apiserver/pkg/authentication/user" "k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/kubernetes/pkg/apis/rbac" "k8s.io/kubernetes/pkg/apis/rbac"
"k8s.io/kubernetes/pkg/apis/rbac/validation" rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
) )
type RequestToRuleMapper interface { type RequestToRuleMapper interface {
...@@ -55,9 +55,9 @@ func (r *RBACAuthorizer) Authorize(requestAttributes authorizer.Attributes) (boo ...@@ -55,9 +55,9 @@ func (r *RBACAuthorizer) Authorize(requestAttributes authorizer.Attributes) (boo
return false, reason, nil return false, reason, nil
} }
func New(roles validation.RoleGetter, roleBindings validation.RoleBindingLister, clusterRoles validation.ClusterRoleGetter, clusterRoleBindings validation.ClusterRoleBindingLister) *RBACAuthorizer { func New(roles rbacregistryvalidation.RoleGetter, roleBindings rbacregistryvalidation.RoleBindingLister, clusterRoles rbacregistryvalidation.ClusterRoleGetter, clusterRoleBindings rbacregistryvalidation.ClusterRoleBindingLister) *RBACAuthorizer {
authorizer := &RBACAuthorizer{ authorizer := &RBACAuthorizer{
authorizationRuleResolver: validation.NewDefaultRuleResolver( authorizationRuleResolver: rbacregistryvalidation.NewDefaultRuleResolver(
roles, roleBindings, clusterRoles, clusterRoleBindings, roles, roleBindings, clusterRoles, clusterRoleBindings,
), ),
} }
......
...@@ -25,7 +25,7 @@ import ( ...@@ -25,7 +25,7 @@ import (
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/rbac" "k8s.io/kubernetes/pkg/apis/rbac"
"k8s.io/kubernetes/pkg/apis/rbac/validation" rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
) )
func newRule(verbs, apiGroups, resources, nonResourceURLs string) rbac.PolicyRule { func newRule(verbs, apiGroups, resources, nonResourceURLs string) rbac.PolicyRule {
...@@ -219,7 +219,7 @@ func TestAuthorizer(t *testing.T) { ...@@ -219,7 +219,7 @@ func TestAuthorizer(t *testing.T) {
}, },
} }
for i, tt := range tests { for i, tt := range tests {
ruleResolver, _ := validation.NewTestRuleResolver(tt.roles, tt.roleBindings, tt.clusterRoles, tt.clusterRoleBindings) ruleResolver, _ := rbacregistryvalidation.NewTestRuleResolver(tt.roles, tt.roleBindings, tt.clusterRoles, tt.clusterRoleBindings)
a := RBACAuthorizer{ruleResolver} a := RBACAuthorizer{ruleResolver}
for _, attr := range tt.shouldPass { for _, attr := range tt.shouldPass {
if authorized, _, _ := a.Authorize(attr); !authorized { if authorized, _, _ := a.Authorize(attr); !authorized {
......
...@@ -22,7 +22,7 @@ import ( ...@@ -22,7 +22,7 @@ import (
"k8s.io/apiserver/pkg/authentication/user" "k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/kubernetes/pkg/apis/rbac" "k8s.io/kubernetes/pkg/apis/rbac"
"k8s.io/kubernetes/pkg/apis/rbac/validation" rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
) )
type RoleToRuleMapper interface { type RoleToRuleMapper interface {
...@@ -34,17 +34,17 @@ type RoleToRuleMapper interface { ...@@ -34,17 +34,17 @@ type RoleToRuleMapper interface {
type SubjectAccessEvaluator struct { type SubjectAccessEvaluator struct {
superUser string superUser string
roleBindingLister validation.RoleBindingLister roleBindingLister rbacregistryvalidation.RoleBindingLister
clusterRoleBindingLister validation.ClusterRoleBindingLister clusterRoleBindingLister rbacregistryvalidation.ClusterRoleBindingLister
roleToRuleMapper RoleToRuleMapper roleToRuleMapper RoleToRuleMapper
} }
func NewSubjectAccessEvaluator(roles validation.RoleGetter, roleBindings validation.RoleBindingLister, clusterRoles validation.ClusterRoleGetter, clusterRoleBindings validation.ClusterRoleBindingLister, superUser string) *SubjectAccessEvaluator { func NewSubjectAccessEvaluator(roles rbacregistryvalidation.RoleGetter, roleBindings rbacregistryvalidation.RoleBindingLister, clusterRoles rbacregistryvalidation.ClusterRoleGetter, clusterRoleBindings rbacregistryvalidation.ClusterRoleBindingLister, superUser string) *SubjectAccessEvaluator {
subjectLocator := &SubjectAccessEvaluator{ subjectLocator := &SubjectAccessEvaluator{
superUser: superUser, superUser: superUser,
roleBindingLister: roleBindings, roleBindingLister: roleBindings,
clusterRoleBindingLister: clusterRoleBindings, clusterRoleBindingLister: clusterRoleBindings,
roleToRuleMapper: validation.NewDefaultRuleResolver( roleToRuleMapper: rbacregistryvalidation.NewDefaultRuleResolver(
roles, roleBindings, clusterRoles, clusterRoleBindings, roles, roleBindings, clusterRoles, clusterRoleBindings,
), ),
} }
......
...@@ -23,7 +23,7 @@ import ( ...@@ -23,7 +23,7 @@ import (
"k8s.io/apiserver/pkg/authentication/user" "k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/kubernetes/pkg/apis/rbac" "k8s.io/kubernetes/pkg/apis/rbac"
"k8s.io/kubernetes/pkg/apis/rbac/validation" rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
) )
func TestSubjectLocator(t *testing.T) { func TestSubjectLocator(t *testing.T) {
...@@ -136,7 +136,7 @@ func TestSubjectLocator(t *testing.T) { ...@@ -136,7 +136,7 @@ func TestSubjectLocator(t *testing.T) {
}, },
} }
for _, tt := range tests { for _, tt := range tests {
ruleResolver, lister := validation.NewTestRuleResolver(tt.roles, tt.roleBindings, tt.clusterRoles, tt.clusterRoleBindings) ruleResolver, lister := rbacregistryvalidation.NewTestRuleResolver(tt.roles, tt.roleBindings, tt.clusterRoles, tt.clusterRoleBindings)
a := SubjectAccessEvaluator{tt.superUser, lister, lister, ruleResolver} a := SubjectAccessEvaluator{tt.superUser, lister, lister, ruleResolver}
for i, action := range tt.actionsToSubjects { for i, action := range tt.actionsToSubjects {
actualSubjects, err := a.AllowedSubjects(action.action) actualSubjects, err := a.AllowedSubjects(action.action)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment