1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-31 03:45:17 +00:00

refactor: add auth interface and unit tests (#4518)

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>
This commit is contained in:
Charles-Edouard Brétéché 2022-09-07 08:54:34 +02:00 committed by GitHub
parent 92e223b7ff
commit 2c86416900
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 104 additions and 49 deletions

View file

@ -11,7 +11,17 @@ import (
) )
// CanIOptions provides utility to check if user has authorization for the given operation // CanIOptions provides utility to check if user has authorization for the given operation
type CanIOptions struct { type CanIOptions interface {
// RunAccessCheck checks if the caller can perform the operation
// - operation is a combination of namespace, kind, verb
// - can only evaluate a single verb
// - group version resource is determined from the kind using the discovery client REST mapper
// - If disallowed, the reason and evaluationError is available in the logs
// - each can generates a SelfSubjectAccessReview resource and response is evaluated for permissions
RunAccessCheck() (bool, error)
}
type canIOptions struct {
namespace string namespace string
verb string verb string
kind string kind string
@ -19,8 +29,8 @@ type CanIOptions struct {
} }
// NewCanI returns a new instance of operation access controller evaluator // NewCanI returns a new instance of operation access controller evaluator
func NewCanI(client dclient.Interface, kind, namespace, verb string) *CanIOptions { func NewCanI(client dclient.Interface, kind, namespace, verb string) CanIOptions {
return &CanIOptions{ return &canIOptions{
namespace: namespace, namespace: namespace,
kind: kind, kind: kind,
verb: verb, verb: verb,
@ -34,7 +44,7 @@ func NewCanI(client dclient.Interface, kind, namespace, verb string) *CanIOption
// - group version resource is determined from the kind using the discovery client REST mapper // - group version resource is determined from the kind using the discovery client REST mapper
// - If disallowed, the reason and evaluationError is available in the logs // - If disallowed, the reason and evaluationError is available in the logs
// - each can generates a SelfSubjectAccessReview resource and response is evaluated for permissions // - each can generates a SelfSubjectAccessReview resource and response is evaluated for permissions
func (o *CanIOptions) RunAccessCheck() (bool, error) { func (o *canIOptions) RunAccessCheck() (bool, error) {
// get GroupVersionResource from RESTMapper // get GroupVersionResource from RESTMapper
// get GVR from kind // get GVR from kind
gvr, err := o.client.Discovery().GetGVRFromKind(o.kind) gvr, err := o.client.Discovery().GetGVRFromKind(o.kind)

View file

@ -1,48 +1,92 @@
package auth package auth
// import ( import (
// "testing" "testing"
// "time"
// "github.com/golang/glog" "github.com/kyverno/kyverno/pkg/clients/dclient"
// "github.com/kyverno/kyverno/pkg/config" "github.com/stretchr/testify/assert"
// dclient "github.com/kyverno/kyverno/pkg/clients/dclient" )
// "github.com/kyverno/kyverno/pkg/signal"
// )
// func Test_Auth_pass(t *testing.T) { func TestNewCanI(t *testing.T) {
// // needs running cluster type args struct {
// var kubeconfig string client dclient.Interface
// stopCh := signal.SetupSignalHandler() kind string
// kubeconfig = "/Users/shivd/.kube/config" namespace string
// clientConfig, err := config.CreateClientConfig(kubeconfig) verb string
// if err != nil { }
// glog.Fatalf("Error building kubeconfig: %v\n", err) tests := []struct {
// } name string
args args
}{{
name: "deployments",
args: args{
client: dclient.NewEmptyFakeClient(),
kind: "Deployment",
namespace: "default",
verb: "test",
},
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := NewCanI(tt.args.client, tt.args.kind, tt.args.namespace, tt.args.verb)
assert.NotNil(t, got)
})
}
}
// // DYNAMIC CLIENT func TestCanIOptions_RunAccessCheck(t *testing.T) {
// // - client for all registered resources type fields struct {
// // - invalidate local cache of registered resource every 10 seconds namespace string
// client, err := dclient.NewClient(clientConfig, 10*time.Second, stopCh) verb string
// if err != nil { kind string
// glog.Fatalf("Error creating client: %v\n", err) client dclient.Interface
// } }
tests := []struct {
// // Can i authenticate name string
fields fields
// kind := "Deployment" want bool
// namespace := "default" wantErr bool
// verb := "test" }{{
// canI := NewCanI(client, kind, namespace, verb) name: "deployments",
// ok, err := canI.RunAccessCheck() fields: fields{
// if err != nil { client: dclient.NewEmptyFakeClient(),
// t.Error(err) kind: "Deployment",
// } namespace: "default",
// if ok { verb: "test",
// t.Log("allowed") },
// } else { want: false,
// t.Log("notallowed") wantErr: false,
// } }, {
// t.FailNow() name: "unknown",
fields: fields{
// } client: dclient.NewEmptyFakeClient(),
kind: "Unknown",
namespace: "default",
verb: "test",
},
want: false,
wantErr: true,
}, {
name: "v2 pods",
fields: fields{
client: dclient.NewEmptyFakeClient(),
kind: "v2/Pod",
namespace: "default",
verb: "test",
},
want: false,
wantErr: true,
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
o := NewCanI(tt.fields.client, tt.fields.kind, tt.fields.namespace, tt.fields.verb)
got, err := o.RunAccessCheck()
if tt.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, tt.want, got)
}
})
}
}

View file

@ -31,8 +31,9 @@ func NewEmptyFakeClient() Interface {
scheme := runtime.NewScheme() scheme := runtime.NewScheme()
return &client{ return &client{
client: fake.NewSimpleDynamicClientWithCustomListKinds(scheme, gvrToListKind, objects...), client: fake.NewSimpleDynamicClientWithCustomListKinds(scheme, gvrToListKind, objects...),
kclient: kubefake.NewSimpleClientset(objects...), kclient: kubefake.NewSimpleClientset(objects...),
discoveryClient: NewFakeDiscoveryClient(nil),
} }
} }