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.
pull/6/head
Kubernetes Submit Queue 2017-01-11 13:31:43 -08:00 committed by GitHub
commit 330c922706
40 changed files with 302 additions and 202 deletions

View File

@ -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(
"//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",

View File

@ -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() ||

View File

@ -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

View File

@ -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
} }
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
}

View File

@ -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(
"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(
"//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(
], ],
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",
],
)

View File

@ -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
} }
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
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

47
pkg/api/rest/meta.go Normal file
View File

@ -0,0 +1,47 @@
/*
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
}

85
pkg/api/rest/meta_test.go Normal file
View File

@ -0,0 +1,85 @@
/*
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")
}
}

View File

@ -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 {

View File

@ -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",
], ],
) )

View File

@ -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 {
// 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 = ""
} }

View File

@ -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",
], ],
) )

View File

@ -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 {
// 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 = ""
} }

View File

@ -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",
], ],
) )

View File

@ -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) {
} }
} }
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

View File

@ -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()

View File

@ -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"))
} }

View File

@ -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"],
) )

View File

@ -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",
], ],
) )

View File

@ -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")
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
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
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

View File

@ -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",
], ],

View File

@ -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 {
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
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
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

View File

@ -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(
"//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",

View File

@ -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 (
"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
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
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)},

View File

@ -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",
], ],
) )

View File

@ -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")
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
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
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

View File

@ -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",
], ],

View File

@ -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 {
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
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
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

View File

@ -0,0 +1,56 @@
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"],
)

View File

@ -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)
}
}
}

View File

@ -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(
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",
], ],

View File

@ -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",

View File

@ -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 {
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) {
// 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) {
// 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)
} }
} }

View File

@ -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
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,
), ),
} }

View File

@ -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) {
}, },
} }
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 {

View File

@ -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 {
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,
), ),
} }

View File

@ -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) {
}, },
} }
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)