1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +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
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
verb string
kind string
@ -19,8 +29,8 @@ type CanIOptions struct {
}
// NewCanI returns a new instance of operation access controller evaluator
func NewCanI(client dclient.Interface, kind, namespace, verb string) *CanIOptions {
return &CanIOptions{
func NewCanI(client dclient.Interface, kind, namespace, verb string) CanIOptions {
return &canIOptions{
namespace: namespace,
kind: kind,
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
// - If disallowed, the reason and evaluationError is available in the logs
// - 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 GVR from kind
gvr, err := o.client.Discovery().GetGVRFromKind(o.kind)

View file

@ -1,48 +1,92 @@
package auth
// import (
// "testing"
// "time"
import (
"testing"
// "github.com/golang/glog"
// "github.com/kyverno/kyverno/pkg/config"
// dclient "github.com/kyverno/kyverno/pkg/clients/dclient"
// "github.com/kyverno/kyverno/pkg/signal"
// )
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/stretchr/testify/assert"
)
// func Test_Auth_pass(t *testing.T) {
// // needs running cluster
// var kubeconfig string
// stopCh := signal.SetupSignalHandler()
// kubeconfig = "/Users/shivd/.kube/config"
// clientConfig, err := config.CreateClientConfig(kubeconfig)
// if err != nil {
// glog.Fatalf("Error building kubeconfig: %v\n", err)
// }
func TestNewCanI(t *testing.T) {
type args struct {
client dclient.Interface
kind string
namespace string
verb string
}
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
// // - client for all registered resources
// // - invalidate local cache of registered resource every 10 seconds
// client, err := dclient.NewClient(clientConfig, 10*time.Second, stopCh)
// if err != nil {
// glog.Fatalf("Error creating client: %v\n", err)
// }
// // Can i authenticate
// kind := "Deployment"
// namespace := "default"
// verb := "test"
// canI := NewCanI(client, kind, namespace, verb)
// ok, err := canI.RunAccessCheck()
// if err != nil {
// t.Error(err)
// }
// if ok {
// t.Log("allowed")
// } else {
// t.Log("notallowed")
// }
// t.FailNow()
// }
func TestCanIOptions_RunAccessCheck(t *testing.T) {
type fields struct {
namespace string
verb string
kind string
client dclient.Interface
}
tests := []struct {
name string
fields fields
want bool
wantErr bool
}{{
name: "deployments",
fields: fields{
client: dclient.NewEmptyFakeClient(),
kind: "Deployment",
namespace: "default",
verb: "test",
},
want: false,
wantErr: false,
}, {
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()
return &client{
client: fake.NewSimpleDynamicClientWithCustomListKinds(scheme, gvrToListKind, objects...),
kclient: kubefake.NewSimpleClientset(objects...),
client: fake.NewSimpleDynamicClientWithCustomListKinds(scheme, gvrToListKind, objects...),
kclient: kubefake.NewSimpleClientset(objects...),
discoveryClient: NewFakeDiscoveryClient(nil),
}
}