...

Source file src/k8s.io/kubernetes/pkg/auth/authorizer/abac/abac_test.go

Documentation: k8s.io/kubernetes/pkg/auth/authorizer/abac

     1  /*
     2  Copyright 2014 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package abac
    18  
    19  import (
    20  	"context"
    21  	"io/ioutil"
    22  	"os"
    23  	"reflect"
    24  	"testing"
    25  
    26  	"k8s.io/apimachinery/pkg/runtime"
    27  	"k8s.io/apiserver/pkg/authentication/user"
    28  	"k8s.io/apiserver/pkg/authorization/authorizer"
    29  	"k8s.io/kubernetes/pkg/apis/abac"
    30  	"k8s.io/kubernetes/pkg/apis/abac/v0"
    31  	"k8s.io/kubernetes/pkg/apis/abac/v1beta1"
    32  )
    33  
    34  func TestEmptyFile(t *testing.T) {
    35  	_, err := newWithContents(t, "")
    36  	if err != nil {
    37  		t.Errorf("unable to read policy file: %v", err)
    38  	}
    39  }
    40  
    41  func TestOneLineFileNoNewLine(t *testing.T) {
    42  	_, err := newWithContents(t, `{"user":"scheduler",  "readonly": true, "resource": "pods", "namespace":"ns1"}`)
    43  	if err != nil {
    44  		t.Errorf("unable to read policy file: %v", err)
    45  	}
    46  }
    47  
    48  func TestTwoLineFile(t *testing.T) {
    49  	_, err := newWithContents(t, `{"user":"scheduler",  "readonly": true, "resource": "pods"}
    50  {"user":"scheduler",  "readonly": true, "resource": "services"}
    51  `)
    52  	if err != nil {
    53  		t.Errorf("unable to read policy file: %v", err)
    54  	}
    55  }
    56  
    57  // Test the file that we will point users at as an example.
    58  func TestExampleFile(t *testing.T) {
    59  	_, err := NewFromFile("./example_policy_file.jsonl")
    60  	if err != nil {
    61  		t.Errorf("unable to read policy file: %v", err)
    62  	}
    63  }
    64  
    65  func TestAuthorizeV0(t *testing.T) {
    66  	a, err := newWithContents(t, `{                    "readonly": true, "resource": "events"   }
    67  {"user":"scheduler", "readonly": true, "resource": "pods"     }
    68  {"user":"scheduler",                   "resource": "bindings" }
    69  {"user":"kubelet",   "readonly": true, "resource": "bindings" }
    70  {"user":"kubelet",                     "resource": "events"   }
    71  {"user":"alice",                                              "namespace": "projectCaribou"}
    72  {"user":"bob",       "readonly": true,                        "namespace": "projectCaribou"}
    73  `)
    74  	if err != nil {
    75  		t.Fatalf("unable to read policy file: %v", err)
    76  	}
    77  
    78  	authenticatedGroup := []string{user.AllAuthenticated}
    79  
    80  	uScheduler := user.DefaultInfo{Name: "scheduler", UID: "uid1", Groups: authenticatedGroup}
    81  	uAlice := user.DefaultInfo{Name: "alice", UID: "uid3", Groups: authenticatedGroup}
    82  	uChuck := user.DefaultInfo{Name: "chuck", UID: "uid5", Groups: authenticatedGroup}
    83  
    84  	testCases := []struct {
    85  		User           user.DefaultInfo
    86  		Verb           string
    87  		Resource       string
    88  		NS             string
    89  		APIGroup       string
    90  		Path           string
    91  		ExpectDecision authorizer.Decision
    92  	}{
    93  		// Scheduler can read pods
    94  		{User: uScheduler, Verb: "list", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionAllow},
    95  		{User: uScheduler, Verb: "list", Resource: "pods", NS: "", ExpectDecision: authorizer.DecisionAllow},
    96  		// Scheduler cannot write pods
    97  		{User: uScheduler, Verb: "create", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
    98  		{User: uScheduler, Verb: "create", Resource: "pods", NS: "", ExpectDecision: authorizer.DecisionNoOpinion},
    99  		// Scheduler can write bindings
   100  		{User: uScheduler, Verb: "get", Resource: "bindings", NS: "ns1", ExpectDecision: authorizer.DecisionAllow},
   101  		{User: uScheduler, Verb: "get", Resource: "bindings", NS: "", ExpectDecision: authorizer.DecisionAllow},
   102  
   103  		// Alice can read and write anything in the right namespace.
   104  		{User: uAlice, Verb: "get", Resource: "pods", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
   105  		{User: uAlice, Verb: "get", Resource: "widgets", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
   106  		{User: uAlice, Verb: "get", Resource: "", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
   107  		{User: uAlice, Verb: "update", Resource: "pods", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
   108  		{User: uAlice, Verb: "update", Resource: "widgets", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
   109  		{User: uAlice, Verb: "update", Resource: "", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
   110  		{User: uAlice, Verb: "update", Resource: "foo", NS: "projectCaribou", APIGroup: "bar", ExpectDecision: authorizer.DecisionAllow},
   111  		// .. but not the wrong namespace.
   112  		{User: uAlice, Verb: "get", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
   113  		{User: uAlice, Verb: "get", Resource: "widgets", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
   114  		{User: uAlice, Verb: "get", Resource: "", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
   115  
   116  		// Chuck can read events, since anyone can.
   117  		{User: uChuck, Verb: "get", Resource: "events", NS: "ns1", ExpectDecision: authorizer.DecisionAllow},
   118  		{User: uChuck, Verb: "get", Resource: "events", NS: "", ExpectDecision: authorizer.DecisionAllow},
   119  		// Chuck can't do other things.
   120  		{User: uChuck, Verb: "update", Resource: "events", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
   121  		{User: uChuck, Verb: "get", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
   122  		{User: uChuck, Verb: "get", Resource: "floop", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
   123  		// Chunk can't access things with no kind or namespace
   124  		{User: uChuck, Verb: "get", Path: "/", Resource: "", NS: "", ExpectDecision: authorizer.DecisionNoOpinion},
   125  	}
   126  	for i, tc := range testCases {
   127  		attr := authorizer.AttributesRecord{
   128  			User:      &tc.User,
   129  			Verb:      tc.Verb,
   130  			Resource:  tc.Resource,
   131  			Namespace: tc.NS,
   132  			APIGroup:  tc.APIGroup,
   133  			Path:      tc.Path,
   134  
   135  			ResourceRequest: len(tc.NS) > 0 || len(tc.Resource) > 0,
   136  		}
   137  		decision, _, _ := a.Authorize(context.Background(), attr)
   138  		if tc.ExpectDecision != decision {
   139  			t.Logf("tc: %v -> attr %v", tc, attr)
   140  			t.Errorf("%d: Expected allowed=%v but actually allowed=%v\n\t%v",
   141  				i, tc.ExpectDecision, decision, tc)
   142  		}
   143  	}
   144  }
   145  
   146  func getResourceRules(infos []authorizer.ResourceRuleInfo) []authorizer.DefaultResourceRuleInfo {
   147  	rules := make([]authorizer.DefaultResourceRuleInfo, len(infos))
   148  	for i, info := range infos {
   149  		rules[i] = authorizer.DefaultResourceRuleInfo{
   150  			Verbs:         info.GetVerbs(),
   151  			APIGroups:     info.GetAPIGroups(),
   152  			Resources:     info.GetResources(),
   153  			ResourceNames: info.GetResourceNames(),
   154  		}
   155  	}
   156  	return rules
   157  }
   158  
   159  func getNonResourceRules(infos []authorizer.NonResourceRuleInfo) []authorizer.DefaultNonResourceRuleInfo {
   160  	rules := make([]authorizer.DefaultNonResourceRuleInfo, len(infos))
   161  	for i, info := range infos {
   162  		rules[i] = authorizer.DefaultNonResourceRuleInfo{
   163  			Verbs:           info.GetVerbs(),
   164  			NonResourceURLs: info.GetNonResourceURLs(),
   165  		}
   166  	}
   167  	return rules
   168  }
   169  
   170  func TestRulesFor(t *testing.T) {
   171  	a, err := newWithContents(t, `
   172  {                    "readonly": true, "resource": "events"   }
   173  {"user":"scheduler", "readonly": true, "resource": "pods"     }
   174  {"user":"scheduler",                   "resource": "bindings" }
   175  {"user":"kubelet",   "readonly": true, "resource": "pods"     }
   176  {"user":"kubelet",                     "resource": "events"   }
   177  {"user":"alice",                                              "namespace": "projectCaribou"}
   178  {"user":"bob",       "readonly": true,                        "namespace": "projectCaribou"}
   179  {"user":"bob",       "readonly": true,                                                     "nonResourcePath": "*"}
   180  {"group":"a",                          "resource": "bindings" }
   181  {"group":"b",        "readonly": true,                                                     "nonResourcePath": "*"}
   182  `)
   183  	if err != nil {
   184  		t.Fatalf("unable to read policy file: %v", err)
   185  	}
   186  
   187  	authenticatedGroup := []string{user.AllAuthenticated}
   188  
   189  	uScheduler := user.DefaultInfo{Name: "scheduler", UID: "uid1", Groups: authenticatedGroup}
   190  	uKubelet := user.DefaultInfo{Name: "kubelet", UID: "uid2", Groups: []string{"a", "b"}}
   191  	uAlice := user.DefaultInfo{Name: "alice", UID: "uid3", Groups: authenticatedGroup}
   192  	uBob := user.DefaultInfo{Name: "bob", UID: "uid4", Groups: authenticatedGroup}
   193  	uChuck := user.DefaultInfo{Name: "chuck", UID: "uid5", Groups: []string{"a", "b"}}
   194  
   195  	testCases := []struct {
   196  		User                   user.DefaultInfo
   197  		Namespace              string
   198  		ExpectResourceRules    []authorizer.DefaultResourceRuleInfo
   199  		ExpectNonResourceRules []authorizer.DefaultNonResourceRuleInfo
   200  	}{
   201  		{
   202  			User:      uScheduler,
   203  			Namespace: "ns1",
   204  			ExpectResourceRules: []authorizer.DefaultResourceRuleInfo{
   205  				{
   206  					Verbs:     []string{"get", "list", "watch"},
   207  					APIGroups: []string{"*"},
   208  					Resources: []string{"events"},
   209  				},
   210  				{
   211  					Verbs:     []string{"get", "list", "watch"},
   212  					APIGroups: []string{"*"},
   213  					Resources: []string{"pods"},
   214  				},
   215  				{
   216  					Verbs:     []string{"*"},
   217  					APIGroups: []string{"*"},
   218  					Resources: []string{"bindings"},
   219  				},
   220  			},
   221  			ExpectNonResourceRules: []authorizer.DefaultNonResourceRuleInfo{},
   222  		},
   223  		{
   224  			User:      uKubelet,
   225  			Namespace: "ns1",
   226  			ExpectResourceRules: []authorizer.DefaultResourceRuleInfo{
   227  				{
   228  					Verbs:     []string{"get", "list", "watch"},
   229  					APIGroups: []string{"*"},
   230  					Resources: []string{"pods"},
   231  				},
   232  				{
   233  					Verbs:     []string{"*"},
   234  					APIGroups: []string{"*"},
   235  					Resources: []string{"events"},
   236  				},
   237  				{
   238  					Verbs:     []string{"*"},
   239  					APIGroups: []string{"*"},
   240  					Resources: []string{"bindings"},
   241  				},
   242  				{
   243  					Verbs:     []string{"get", "list", "watch"},
   244  					APIGroups: []string{"*"},
   245  					Resources: []string{"*"},
   246  				},
   247  			},
   248  			ExpectNonResourceRules: []authorizer.DefaultNonResourceRuleInfo{
   249  				{
   250  					Verbs:           []string{"get", "list", "watch"},
   251  					NonResourceURLs: []string{"*"},
   252  				},
   253  			},
   254  		},
   255  		{
   256  			User:      uAlice,
   257  			Namespace: "projectCaribou",
   258  			ExpectResourceRules: []authorizer.DefaultResourceRuleInfo{
   259  				{
   260  					Verbs:     []string{"get", "list", "watch"},
   261  					APIGroups: []string{"*"},
   262  					Resources: []string{"events"},
   263  				},
   264  				{
   265  					Verbs:     []string{"*"},
   266  					APIGroups: []string{"*"},
   267  					Resources: []string{"*"},
   268  				},
   269  			},
   270  			ExpectNonResourceRules: []authorizer.DefaultNonResourceRuleInfo{},
   271  		},
   272  		{
   273  			User:      uBob,
   274  			Namespace: "projectCaribou",
   275  			ExpectResourceRules: []authorizer.DefaultResourceRuleInfo{
   276  				{
   277  					Verbs:     []string{"get", "list", "watch"},
   278  					APIGroups: []string{"*"},
   279  					Resources: []string{"events"},
   280  				},
   281  				{
   282  					Verbs:     []string{"get", "list", "watch"},
   283  					APIGroups: []string{"*"},
   284  					Resources: []string{"*"},
   285  				},
   286  				{
   287  					Verbs:     []string{"get", "list", "watch"},
   288  					APIGroups: []string{"*"},
   289  					Resources: []string{"*"},
   290  				},
   291  			},
   292  			ExpectNonResourceRules: []authorizer.DefaultNonResourceRuleInfo{
   293  				{
   294  					Verbs:           []string{"get", "list", "watch"},
   295  					NonResourceURLs: []string{"*"},
   296  				},
   297  			},
   298  		},
   299  		{
   300  			User:      uChuck,
   301  			Namespace: "ns1",
   302  			ExpectResourceRules: []authorizer.DefaultResourceRuleInfo{
   303  				{
   304  					Verbs:     []string{"*"},
   305  					APIGroups: []string{"*"},
   306  					Resources: []string{"bindings"},
   307  				},
   308  				{
   309  					Verbs:     []string{"get", "list", "watch"},
   310  					APIGroups: []string{"*"},
   311  					Resources: []string{"*"},
   312  				},
   313  			},
   314  			ExpectNonResourceRules: []authorizer.DefaultNonResourceRuleInfo{
   315  				{
   316  					Verbs:           []string{"get", "list", "watch"},
   317  					NonResourceURLs: []string{"*"},
   318  				},
   319  			},
   320  		},
   321  	}
   322  	for i, tc := range testCases {
   323  		attr := authorizer.AttributesRecord{
   324  			User:      &tc.User,
   325  			Namespace: tc.Namespace,
   326  		}
   327  		resourceRules, nonResourceRules, _, _ := a.RulesFor(attr.GetUser(), attr.GetNamespace())
   328  		actualResourceRules := getResourceRules(resourceRules)
   329  		if !reflect.DeepEqual(tc.ExpectResourceRules, actualResourceRules) {
   330  			t.Logf("tc: %v -> attr %v", tc, attr)
   331  			t.Errorf("%d: Expected: \n%#v\n but actual: \n%#v\n",
   332  				i, tc.ExpectResourceRules, actualResourceRules)
   333  		}
   334  		actualNonResourceRules := getNonResourceRules(nonResourceRules)
   335  		if !reflect.DeepEqual(tc.ExpectNonResourceRules, actualNonResourceRules) {
   336  			t.Logf("tc: %v -> attr %v", tc, attr)
   337  			t.Errorf("%d: Expected: \n%#v\n but actual: \n%#v\n",
   338  				i, tc.ExpectNonResourceRules, actualNonResourceRules)
   339  		}
   340  	}
   341  }
   342  
   343  func TestAuthorizeV1beta1(t *testing.T) {
   344  	a, err := newWithContents(t,
   345  		`
   346  		 # Comment line, after a blank line
   347  		 {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"*",         "readonly": true,                                                        "nonResourcePath": "/api"}}
   348  		 {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"*",                                                                                  "nonResourcePath": "/custom"}}
   349  		 {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"*",                                                                                  "nonResourcePath": "/root/*"}}
   350  		 {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"noresource",                                                                         "nonResourcePath": "*"}}
   351  		 {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"*",         "readonly": true, "resource": "events",   "namespace": "*"}}
   352  		 {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"scheduler", "readonly": true, "resource": "pods",     "namespace": "*"}}
   353  		 {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"scheduler",                   "resource": "bindings", "namespace": "*"}}
   354  		 {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"kubelet",   "readonly": true, "resource": "bindings", "namespace": "*"}}
   355  		 {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"kubelet",                     "resource": "events",   "namespace": "*"}}
   356  		 {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"alice",                       "resource": "*",        "namespace": "projectCaribou"}}
   357  		 {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"bob",       "readonly": true, "resource": "*",        "namespace": "projectCaribou"}}
   358  		 {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"debbie",                      "resource": "pods",     "namespace": "projectCaribou"}}
   359  		 {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"apigroupuser",                "resource": "*",        "namespace": "projectAnyGroup",   "apiGroup": "*"}}
   360  		 {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"apigroupuser",                "resource": "*",        "namespace": "projectEmptyGroup", "apiGroup": "" }}
   361  		 {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"apigroupuser",                "resource": "*",        "namespace": "projectXGroup",     "apiGroup": "x"}}`)
   362  
   363  	if err != nil {
   364  		t.Fatalf("unable to read policy file: %v", err)
   365  	}
   366  
   367  	authenticatedGroup := []string{user.AllAuthenticated}
   368  
   369  	uScheduler := user.DefaultInfo{Name: "scheduler", UID: "uid1", Groups: authenticatedGroup}
   370  	uAlice := user.DefaultInfo{Name: "alice", UID: "uid3", Groups: authenticatedGroup}
   371  	uChuck := user.DefaultInfo{Name: "chuck", UID: "uid5", Groups: authenticatedGroup}
   372  	uDebbie := user.DefaultInfo{Name: "debbie", UID: "uid6", Groups: authenticatedGroup}
   373  	uNoResource := user.DefaultInfo{Name: "noresource", UID: "uid7", Groups: authenticatedGroup}
   374  	uAPIGroup := user.DefaultInfo{Name: "apigroupuser", UID: "uid8", Groups: authenticatedGroup}
   375  
   376  	testCases := []struct {
   377  		User           user.DefaultInfo
   378  		Verb           string
   379  		Resource       string
   380  		APIGroup       string
   381  		NS             string
   382  		Path           string
   383  		ExpectDecision authorizer.Decision
   384  	}{
   385  		// Scheduler can read pods
   386  		{User: uScheduler, Verb: "list", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionAllow},
   387  		{User: uScheduler, Verb: "list", Resource: "pods", NS: "", ExpectDecision: authorizer.DecisionAllow},
   388  		// Scheduler cannot write pods
   389  		{User: uScheduler, Verb: "create", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
   390  		{User: uScheduler, Verb: "create", Resource: "pods", NS: "", ExpectDecision: authorizer.DecisionNoOpinion},
   391  		// Scheduler can write bindings
   392  		{User: uScheduler, Verb: "get", Resource: "bindings", NS: "ns1", ExpectDecision: authorizer.DecisionAllow},
   393  		{User: uScheduler, Verb: "get", Resource: "bindings", NS: "", ExpectDecision: authorizer.DecisionAllow},
   394  
   395  		// Alice can read and write anything in the right namespace.
   396  		{User: uAlice, Verb: "get", Resource: "pods", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
   397  		{User: uAlice, Verb: "get", Resource: "widgets", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
   398  		{User: uAlice, Verb: "get", Resource: "", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
   399  		{User: uAlice, Verb: "update", Resource: "pods", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
   400  		{User: uAlice, Verb: "update", Resource: "widgets", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
   401  		{User: uAlice, Verb: "update", Resource: "", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
   402  		// .. but not the wrong namespace.
   403  		{User: uAlice, Verb: "get", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
   404  		{User: uAlice, Verb: "get", Resource: "widgets", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
   405  		{User: uAlice, Verb: "get", Resource: "", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
   406  
   407  		// Debbie can write to pods in the right namespace
   408  		{User: uDebbie, Verb: "update", Resource: "pods", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
   409  
   410  		// Chuck can read events, since anyone can.
   411  		{User: uChuck, Verb: "get", Resource: "events", NS: "ns1", ExpectDecision: authorizer.DecisionAllow},
   412  		{User: uChuck, Verb: "get", Resource: "events", NS: "", ExpectDecision: authorizer.DecisionAllow},
   413  		// Chuck can't do other things.
   414  		{User: uChuck, Verb: "update", Resource: "events", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
   415  		{User: uChuck, Verb: "get", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
   416  		{User: uChuck, Verb: "get", Resource: "floop", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
   417  		// Chuck can't access things with no resource or namespace
   418  		{User: uChuck, Verb: "get", Path: "/", Resource: "", NS: "", ExpectDecision: authorizer.DecisionNoOpinion},
   419  		// but can access /api
   420  		{User: uChuck, Verb: "get", Path: "/api", Resource: "", NS: "", ExpectDecision: authorizer.DecisionAllow},
   421  		// though he cannot write to it
   422  		{User: uChuck, Verb: "create", Path: "/api", Resource: "", NS: "", ExpectDecision: authorizer.DecisionNoOpinion},
   423  		// while he can write to /custom
   424  		{User: uChuck, Verb: "update", Path: "/custom", Resource: "", NS: "", ExpectDecision: authorizer.DecisionAllow},
   425  		// he cannot get "/root"
   426  		{User: uChuck, Verb: "get", Path: "/root", Resource: "", NS: "", ExpectDecision: authorizer.DecisionNoOpinion},
   427  		// but can get any subpath
   428  		{User: uChuck, Verb: "get", Path: "/root/", Resource: "", NS: "", ExpectDecision: authorizer.DecisionAllow},
   429  		{User: uChuck, Verb: "get", Path: "/root/test/1/2/3", Resource: "", NS: "", ExpectDecision: authorizer.DecisionAllow},
   430  
   431  		// the user "noresource" can get any non-resource request
   432  		{User: uNoResource, Verb: "get", Path: "", Resource: "", NS: "", ExpectDecision: authorizer.DecisionAllow},
   433  		{User: uNoResource, Verb: "get", Path: "/", Resource: "", NS: "", ExpectDecision: authorizer.DecisionAllow},
   434  		{User: uNoResource, Verb: "get", Path: "/foo/bar/baz", Resource: "", NS: "", ExpectDecision: authorizer.DecisionAllow},
   435  		// but cannot get any request where IsResourceRequest() == true
   436  		{User: uNoResource, Verb: "get", Path: "/", Resource: "", NS: "bar", ExpectDecision: authorizer.DecisionNoOpinion},
   437  		{User: uNoResource, Verb: "get", Path: "/foo/bar/baz", Resource: "foo", NS: "bar", ExpectDecision: authorizer.DecisionNoOpinion},
   438  
   439  		// Test APIGroup matching
   440  		{User: uAPIGroup, Verb: "get", APIGroup: "x", Resource: "foo", NS: "projectAnyGroup", ExpectDecision: authorizer.DecisionAllow},
   441  		{User: uAPIGroup, Verb: "get", APIGroup: "x", Resource: "foo", NS: "projectEmptyGroup", ExpectDecision: authorizer.DecisionNoOpinion},
   442  		{User: uAPIGroup, Verb: "get", APIGroup: "x", Resource: "foo", NS: "projectXGroup", ExpectDecision: authorizer.DecisionAllow},
   443  	}
   444  	for i, tc := range testCases {
   445  		attr := authorizer.AttributesRecord{
   446  			User:            &tc.User,
   447  			Verb:            tc.Verb,
   448  			Resource:        tc.Resource,
   449  			APIGroup:        tc.APIGroup,
   450  			Namespace:       tc.NS,
   451  			ResourceRequest: len(tc.NS) > 0 || len(tc.Resource) > 0,
   452  			Path:            tc.Path,
   453  		}
   454  		// t.Logf("tc %2v: %v -> attr %v", i, tc, attr)
   455  		decision, _, _ := a.Authorize(context.Background(), attr)
   456  		if tc.ExpectDecision != decision {
   457  			t.Errorf("%d: Expected allowed=%v but actually allowed=%v, for case %+v & %+v",
   458  				i, tc.ExpectDecision, decision, tc, attr)
   459  		}
   460  	}
   461  }
   462  
   463  func TestSubjectMatches(t *testing.T) {
   464  	testCases := map[string]struct {
   465  		User        user.DefaultInfo
   466  		Policy      runtime.Object
   467  		ExpectMatch bool
   468  	}{
   469  		"v0 empty policy does not match unauthed user": {
   470  			User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}},
   471  			Policy: &v0.Policy{
   472  				User:  "",
   473  				Group: "",
   474  			},
   475  			ExpectMatch: false,
   476  		},
   477  		"v0 * user policy does not match unauthed user": {
   478  			User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}},
   479  			Policy: &v0.Policy{
   480  				User:  "*",
   481  				Group: "",
   482  			},
   483  			ExpectMatch: false,
   484  		},
   485  		"v0 * group policy does not match unauthed user": {
   486  			User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}},
   487  			Policy: &v0.Policy{
   488  				User:  "",
   489  				Group: "*",
   490  			},
   491  			ExpectMatch: false,
   492  		},
   493  		"v0 empty policy matches authed user": {
   494  			User: user.DefaultInfo{Name: "Foo", Groups: []string{user.AllAuthenticated}},
   495  			Policy: &v0.Policy{
   496  				User:  "",
   497  				Group: "",
   498  			},
   499  			ExpectMatch: true,
   500  		},
   501  		"v0 empty policy matches authed user with groups": {
   502  			User: user.DefaultInfo{Name: "Foo", Groups: []string{"a", "b", user.AllAuthenticated}},
   503  			Policy: &v0.Policy{
   504  				User:  "",
   505  				Group: "",
   506  			},
   507  			ExpectMatch: true,
   508  		},
   509  
   510  		"v0 user policy does not match unauthed user": {
   511  			User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}},
   512  			Policy: &v0.Policy{
   513  				User:  "Foo",
   514  				Group: "",
   515  			},
   516  			ExpectMatch: false,
   517  		},
   518  		"v0 user policy does not match different user": {
   519  			User: user.DefaultInfo{Name: "Bar", Groups: []string{user.AllAuthenticated}},
   520  			Policy: &v0.Policy{
   521  				User:  "Foo",
   522  				Group: "",
   523  			},
   524  			ExpectMatch: false,
   525  		},
   526  		"v0 user policy is case-sensitive": {
   527  			User: user.DefaultInfo{Name: "foo", Groups: []string{user.AllAuthenticated}},
   528  			Policy: &v0.Policy{
   529  				User:  "Foo",
   530  				Group: "",
   531  			},
   532  			ExpectMatch: false,
   533  		},
   534  		"v0 user policy does not match substring": {
   535  			User: user.DefaultInfo{Name: "FooBar", Groups: []string{user.AllAuthenticated}},
   536  			Policy: &v0.Policy{
   537  				User:  "Foo",
   538  				Group: "",
   539  			},
   540  			ExpectMatch: false,
   541  		},
   542  		"v0 user policy matches username": {
   543  			User: user.DefaultInfo{Name: "Foo", Groups: []string{user.AllAuthenticated}},
   544  			Policy: &v0.Policy{
   545  				User:  "Foo",
   546  				Group: "",
   547  			},
   548  			ExpectMatch: true,
   549  		},
   550  
   551  		"v0 group policy does not match unauthed user": {
   552  			User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}},
   553  			Policy: &v0.Policy{
   554  				User:  "",
   555  				Group: "Foo",
   556  			},
   557  			ExpectMatch: false,
   558  		},
   559  		"v0 group policy does not match user in different group": {
   560  			User: user.DefaultInfo{Name: "FooBar", Groups: []string{"B", user.AllAuthenticated}},
   561  			Policy: &v0.Policy{
   562  				User:  "",
   563  				Group: "A",
   564  			},
   565  			ExpectMatch: false,
   566  		},
   567  		"v0 group policy is case-sensitive": {
   568  			User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}},
   569  			Policy: &v0.Policy{
   570  				User:  "",
   571  				Group: "b",
   572  			},
   573  			ExpectMatch: false,
   574  		},
   575  		"v0 group policy does not match substring": {
   576  			User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "BBB", "C", user.AllAuthenticated}},
   577  			Policy: &v0.Policy{
   578  				User:  "",
   579  				Group: "B",
   580  			},
   581  			ExpectMatch: false,
   582  		},
   583  		"v0 group policy matches user in group": {
   584  			User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}},
   585  			Policy: &v0.Policy{
   586  				User:  "",
   587  				Group: "B",
   588  			},
   589  			ExpectMatch: true,
   590  		},
   591  
   592  		"v0 user and group policy requires user match": {
   593  			User: user.DefaultInfo{Name: "Bar", Groups: []string{"A", "B", "C", user.AllAuthenticated}},
   594  			Policy: &v0.Policy{
   595  				User:  "Foo",
   596  				Group: "B",
   597  			},
   598  			ExpectMatch: false,
   599  		},
   600  		"v0 user and group policy requires group match": {
   601  			User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}},
   602  			Policy: &v0.Policy{
   603  				User:  "Foo",
   604  				Group: "D",
   605  			},
   606  			ExpectMatch: false,
   607  		},
   608  		"v0 user and group policy matches": {
   609  			User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}},
   610  			Policy: &v0.Policy{
   611  				User:  "Foo",
   612  				Group: "B",
   613  			},
   614  			ExpectMatch: true,
   615  		},
   616  
   617  		"v1 empty policy does not match unauthed user": {
   618  			User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}},
   619  			Policy: &v1beta1.Policy{
   620  				Spec: v1beta1.PolicySpec{
   621  					User:  "",
   622  					Group: "",
   623  				},
   624  			},
   625  			ExpectMatch: false,
   626  		},
   627  		"v1 * user policy does not match unauthed user": {
   628  			User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}},
   629  			Policy: &v1beta1.Policy{
   630  				Spec: v1beta1.PolicySpec{
   631  					User:  "*",
   632  					Group: "",
   633  				},
   634  			},
   635  			ExpectMatch: false,
   636  		},
   637  		"v1 * group policy does not match unauthed user": {
   638  			User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}},
   639  			Policy: &v1beta1.Policy{
   640  				Spec: v1beta1.PolicySpec{
   641  					User:  "",
   642  					Group: "*",
   643  				},
   644  			},
   645  			ExpectMatch: false,
   646  		},
   647  		"v1 empty policy does not match authed user": {
   648  			User: user.DefaultInfo{Name: "Foo", Groups: []string{user.AllAuthenticated}},
   649  			Policy: &v1beta1.Policy{
   650  				Spec: v1beta1.PolicySpec{
   651  					User:  "",
   652  					Group: "",
   653  				},
   654  			},
   655  			ExpectMatch: false,
   656  		},
   657  		"v1 empty policy does not match authed user with groups": {
   658  			User: user.DefaultInfo{Name: "Foo", Groups: []string{"a", "b", user.AllAuthenticated}},
   659  			Policy: &v1beta1.Policy{
   660  				Spec: v1beta1.PolicySpec{
   661  					User:  "",
   662  					Group: "",
   663  				},
   664  			},
   665  			ExpectMatch: false,
   666  		},
   667  
   668  		"v1 user policy does not match unauthed user": {
   669  			User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}},
   670  			Policy: &v1beta1.Policy{
   671  				Spec: v1beta1.PolicySpec{
   672  					User:  "Foo",
   673  					Group: "",
   674  				},
   675  			},
   676  			ExpectMatch: false,
   677  		},
   678  		"v1 user policy does not match different user": {
   679  			User: user.DefaultInfo{Name: "Bar", Groups: []string{user.AllAuthenticated}},
   680  			Policy: &v1beta1.Policy{
   681  				Spec: v1beta1.PolicySpec{
   682  					User:  "Foo",
   683  					Group: "",
   684  				},
   685  			},
   686  			ExpectMatch: false,
   687  		},
   688  		"v1 user policy is case-sensitive": {
   689  			User: user.DefaultInfo{Name: "foo", Groups: []string{user.AllAuthenticated}},
   690  			Policy: &v1beta1.Policy{
   691  				Spec: v1beta1.PolicySpec{
   692  					User:  "Foo",
   693  					Group: "",
   694  				},
   695  			},
   696  			ExpectMatch: false,
   697  		},
   698  		"v1 user policy does not match substring": {
   699  			User: user.DefaultInfo{Name: "FooBar", Groups: []string{user.AllAuthenticated}},
   700  			Policy: &v1beta1.Policy{
   701  				Spec: v1beta1.PolicySpec{
   702  					User:  "Foo",
   703  					Group: "",
   704  				},
   705  			},
   706  			ExpectMatch: false,
   707  		},
   708  		"v1 user policy matches username": {
   709  			User: user.DefaultInfo{Name: "Foo", Groups: []string{user.AllAuthenticated}},
   710  			Policy: &v1beta1.Policy{
   711  				Spec: v1beta1.PolicySpec{
   712  					User:  "Foo",
   713  					Group: "",
   714  				},
   715  			},
   716  			ExpectMatch: true,
   717  		},
   718  
   719  		"v1 group policy does not match unauthed user": {
   720  			User: user.DefaultInfo{Name: "system:anonymous", Groups: []string{"system:unauthenticated"}},
   721  			Policy: &v1beta1.Policy{
   722  				Spec: v1beta1.PolicySpec{
   723  					User:  "",
   724  					Group: "Foo",
   725  				},
   726  			},
   727  			ExpectMatch: false,
   728  		},
   729  		"v1 group policy does not match user in different group": {
   730  			User: user.DefaultInfo{Name: "FooBar", Groups: []string{"B", user.AllAuthenticated}},
   731  			Policy: &v1beta1.Policy{
   732  				Spec: v1beta1.PolicySpec{
   733  					User:  "",
   734  					Group: "A",
   735  				},
   736  			},
   737  			ExpectMatch: false,
   738  		},
   739  		"v1 group policy is case-sensitive": {
   740  			User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}},
   741  			Policy: &v1beta1.Policy{
   742  				Spec: v1beta1.PolicySpec{
   743  					User:  "",
   744  					Group: "b",
   745  				},
   746  			},
   747  			ExpectMatch: false,
   748  		},
   749  		"v1 group policy does not match substring": {
   750  			User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "BBB", "C", user.AllAuthenticated}},
   751  			Policy: &v1beta1.Policy{
   752  				Spec: v1beta1.PolicySpec{
   753  					User:  "",
   754  					Group: "B",
   755  				},
   756  			},
   757  			ExpectMatch: false,
   758  		},
   759  		"v1 group policy matches user in group": {
   760  			User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}},
   761  			Policy: &v1beta1.Policy{
   762  				Spec: v1beta1.PolicySpec{
   763  					User:  "",
   764  					Group: "B",
   765  				},
   766  			},
   767  			ExpectMatch: true,
   768  		},
   769  
   770  		"v1 user and group policy requires user match": {
   771  			User: user.DefaultInfo{Name: "Bar", Groups: []string{"A", "B", "C", user.AllAuthenticated}},
   772  			Policy: &v1beta1.Policy{
   773  				Spec: v1beta1.PolicySpec{
   774  					User:  "Foo",
   775  					Group: "B",
   776  				},
   777  			},
   778  			ExpectMatch: false,
   779  		},
   780  		"v1 user and group policy requires group match": {
   781  			User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}},
   782  			Policy: &v1beta1.Policy{
   783  				Spec: v1beta1.PolicySpec{
   784  					User:  "Foo",
   785  					Group: "D",
   786  				},
   787  			},
   788  			ExpectMatch: false,
   789  		},
   790  		"v1 user and group policy matches": {
   791  			User: user.DefaultInfo{Name: "Foo", Groups: []string{"A", "B", "C", user.AllAuthenticated}},
   792  			Policy: &v1beta1.Policy{
   793  				Spec: v1beta1.PolicySpec{
   794  					User:  "Foo",
   795  					Group: "B",
   796  				},
   797  			},
   798  			ExpectMatch: true,
   799  		},
   800  	}
   801  
   802  	for k, tc := range testCases {
   803  		policy := &abac.Policy{}
   804  		if err := abac.Scheme.Convert(tc.Policy, policy, nil); err != nil {
   805  			t.Errorf("%s: error converting: %v", k, err)
   806  			continue
   807  		}
   808  		attr := authorizer.AttributesRecord{
   809  			User: &tc.User,
   810  		}
   811  		actualMatch := subjectMatches(*policy, attr.GetUser())
   812  		if tc.ExpectMatch != actualMatch {
   813  			t.Errorf("%v: Expected actorMatches=%v but actually got=%v",
   814  				k, tc.ExpectMatch, actualMatch)
   815  		}
   816  	}
   817  }
   818  
   819  func newWithContents(t *testing.T, contents string) (PolicyList, error) {
   820  	f, err := ioutil.TempFile("", "abac_test")
   821  	if err != nil {
   822  		t.Fatalf("unexpected error creating policyfile: %v", err)
   823  	}
   824  	f.Close()
   825  	defer os.Remove(f.Name())
   826  
   827  	if err := ioutil.WriteFile(f.Name(), []byte(contents), 0700); err != nil {
   828  		t.Fatalf("unexpected error writing policyfile: %v", err)
   829  	}
   830  
   831  	pl, err := NewFromFile(f.Name())
   832  	return pl, err
   833  }
   834  
   835  func TestPolicy(t *testing.T) {
   836  	tests := []struct {
   837  		policy  runtime.Object
   838  		attr    authorizer.Attributes
   839  		matches bool
   840  		name    string
   841  	}{
   842  		// v0 mismatches
   843  		{
   844  			policy: &v0.Policy{
   845  				Readonly: true,
   846  			},
   847  			attr: authorizer.AttributesRecord{
   848  				User: &user.DefaultInfo{
   849  					Name:   "foo",
   850  					Groups: []string{user.AllAuthenticated},
   851  				},
   852  				Verb: "create",
   853  			},
   854  			matches: false,
   855  			name:    "v0 read-only mismatch",
   856  		},
   857  		{
   858  			policy: &v0.Policy{
   859  				User: "foo",
   860  			},
   861  			attr: authorizer.AttributesRecord{
   862  				User: &user.DefaultInfo{
   863  					Name:   "bar",
   864  					Groups: []string{user.AllAuthenticated},
   865  				},
   866  			},
   867  			matches: false,
   868  			name:    "v0 user name mis-match",
   869  		},
   870  		{
   871  			policy: &v0.Policy{
   872  				Resource: "foo",
   873  			},
   874  			attr: authorizer.AttributesRecord{
   875  				User: &user.DefaultInfo{
   876  					Name:   "foo",
   877  					Groups: []string{user.AllAuthenticated},
   878  				},
   879  				Resource:        "bar",
   880  				ResourceRequest: true,
   881  			},
   882  			matches: false,
   883  			name:    "v0 resource mis-match",
   884  		},
   885  		{
   886  			policy: &v0.Policy{
   887  				User:      "foo",
   888  				Resource:  "foo",
   889  				Namespace: "foo",
   890  			},
   891  			attr: authorizer.AttributesRecord{
   892  				User: &user.DefaultInfo{
   893  					Name:   "foo",
   894  					Groups: []string{user.AllAuthenticated},
   895  				},
   896  				Resource:        "foo",
   897  				Namespace:       "foo",
   898  				ResourceRequest: true,
   899  			},
   900  			matches: true,
   901  			name:    "v0 namespace mis-match",
   902  		},
   903  
   904  		// v0 matches
   905  		{
   906  			policy: &v0.Policy{},
   907  			attr: authorizer.AttributesRecord{
   908  				User: &user.DefaultInfo{
   909  					Name:   "foo",
   910  					Groups: []string{user.AllAuthenticated},
   911  				},
   912  				ResourceRequest: true,
   913  			},
   914  			matches: true,
   915  			name:    "v0 null resource",
   916  		},
   917  		{
   918  			policy: &v0.Policy{
   919  				Readonly: true,
   920  			},
   921  			attr: authorizer.AttributesRecord{
   922  				User: &user.DefaultInfo{
   923  					Name:   "foo",
   924  					Groups: []string{user.AllAuthenticated},
   925  				},
   926  				Verb: "get",
   927  			},
   928  			matches: true,
   929  			name:    "v0 read-only match",
   930  		},
   931  		{
   932  			policy: &v0.Policy{
   933  				User: "foo",
   934  			},
   935  			attr: authorizer.AttributesRecord{
   936  				User: &user.DefaultInfo{
   937  					Name:   "foo",
   938  					Groups: []string{user.AllAuthenticated},
   939  				},
   940  			},
   941  			matches: true,
   942  			name:    "v0 user name match",
   943  		},
   944  		{
   945  			policy: &v0.Policy{
   946  				Resource: "foo",
   947  			},
   948  			attr: authorizer.AttributesRecord{
   949  				User: &user.DefaultInfo{
   950  					Name:   "foo",
   951  					Groups: []string{user.AllAuthenticated},
   952  				},
   953  				Resource:        "foo",
   954  				ResourceRequest: true,
   955  			},
   956  			matches: true,
   957  			name:    "v0 resource match",
   958  		},
   959  
   960  		// v1 mismatches
   961  		{
   962  			policy: &v1beta1.Policy{},
   963  			attr: authorizer.AttributesRecord{
   964  				User: &user.DefaultInfo{
   965  					Name:   "foo",
   966  					Groups: []string{user.AllAuthenticated},
   967  				},
   968  				ResourceRequest: true,
   969  			},
   970  			matches: false,
   971  			name:    "v1 null",
   972  		},
   973  		{
   974  			policy: &v1beta1.Policy{
   975  				Spec: v1beta1.PolicySpec{
   976  					User: "foo",
   977  				},
   978  			},
   979  			attr: authorizer.AttributesRecord{
   980  				User: &user.DefaultInfo{
   981  					Name:   "bar",
   982  					Groups: []string{user.AllAuthenticated},
   983  				},
   984  				ResourceRequest: true,
   985  			},
   986  			matches: false,
   987  			name:    "v1 user name mis-match",
   988  		},
   989  		{
   990  			policy: &v1beta1.Policy{
   991  				Spec: v1beta1.PolicySpec{
   992  					User:     "*",
   993  					Readonly: true,
   994  				},
   995  			},
   996  			attr: authorizer.AttributesRecord{
   997  				User: &user.DefaultInfo{
   998  					Name:   "foo",
   999  					Groups: []string{user.AllAuthenticated},
  1000  				},
  1001  				ResourceRequest: true,
  1002  			},
  1003  			matches: false,
  1004  			name:    "v1 read-only mismatch",
  1005  		},
  1006  		{
  1007  			policy: &v1beta1.Policy{
  1008  				Spec: v1beta1.PolicySpec{
  1009  					User:     "*",
  1010  					Resource: "foo",
  1011  				},
  1012  			},
  1013  			attr: authorizer.AttributesRecord{
  1014  				User: &user.DefaultInfo{
  1015  					Name:   "foo",
  1016  					Groups: []string{user.AllAuthenticated},
  1017  				},
  1018  				Resource:        "bar",
  1019  				ResourceRequest: true,
  1020  			},
  1021  			matches: false,
  1022  			name:    "v1 resource mis-match",
  1023  		},
  1024  		{
  1025  			policy: &v1beta1.Policy{
  1026  				Spec: v1beta1.PolicySpec{
  1027  					User:      "foo",
  1028  					Namespace: "barr",
  1029  					Resource:  "baz",
  1030  				},
  1031  			},
  1032  			attr: authorizer.AttributesRecord{
  1033  				User: &user.DefaultInfo{
  1034  					Name:   "foo",
  1035  					Groups: []string{user.AllAuthenticated},
  1036  				},
  1037  				Namespace:       "bar",
  1038  				Resource:        "baz",
  1039  				ResourceRequest: true,
  1040  			},
  1041  			matches: false,
  1042  			name:    "v1 namespace mis-match",
  1043  		},
  1044  		{
  1045  			policy: &v1beta1.Policy{
  1046  				Spec: v1beta1.PolicySpec{
  1047  					User:            "*",
  1048  					NonResourcePath: "/api",
  1049  				},
  1050  			},
  1051  			attr: authorizer.AttributesRecord{
  1052  				User: &user.DefaultInfo{
  1053  					Name:   "foo",
  1054  					Groups: []string{user.AllAuthenticated},
  1055  				},
  1056  				Path:            "/api2",
  1057  				ResourceRequest: false,
  1058  			},
  1059  			matches: false,
  1060  			name:    "v1 non-resource mis-match",
  1061  		},
  1062  		{
  1063  			policy: &v1beta1.Policy{
  1064  				Spec: v1beta1.PolicySpec{
  1065  					User:            "*",
  1066  					NonResourcePath: "/api/*",
  1067  				},
  1068  			},
  1069  			attr: authorizer.AttributesRecord{
  1070  				User: &user.DefaultInfo{
  1071  					Name:   "foo",
  1072  					Groups: []string{user.AllAuthenticated},
  1073  				},
  1074  				Path:            "/api2/foo",
  1075  				ResourceRequest: false,
  1076  			},
  1077  			matches: false,
  1078  			name:    "v1 non-resource wildcard subpath mis-match",
  1079  		},
  1080  
  1081  		// v1 matches
  1082  		{
  1083  			policy: &v1beta1.Policy{
  1084  				Spec: v1beta1.PolicySpec{
  1085  					User: "foo",
  1086  				},
  1087  			},
  1088  			attr: authorizer.AttributesRecord{
  1089  				User: &user.DefaultInfo{
  1090  					Name:   "foo",
  1091  					Groups: []string{user.AllAuthenticated},
  1092  				},
  1093  				ResourceRequest: true,
  1094  			},
  1095  			matches: true,
  1096  			name:    "v1 user match",
  1097  		},
  1098  		{
  1099  			policy: &v1beta1.Policy{
  1100  				Spec: v1beta1.PolicySpec{
  1101  					User: "*",
  1102  				},
  1103  			},
  1104  			attr: authorizer.AttributesRecord{
  1105  				User: &user.DefaultInfo{
  1106  					Name:   "foo",
  1107  					Groups: []string{user.AllAuthenticated},
  1108  				},
  1109  				ResourceRequest: true,
  1110  			},
  1111  			matches: true,
  1112  			name:    "v1 user wildcard match",
  1113  		},
  1114  		{
  1115  			policy: &v1beta1.Policy{
  1116  				Spec: v1beta1.PolicySpec{
  1117  					Group: "bar",
  1118  				},
  1119  			},
  1120  			attr: authorizer.AttributesRecord{
  1121  				User: &user.DefaultInfo{
  1122  					Name:   "foo",
  1123  					Groups: []string{"bar", user.AllAuthenticated},
  1124  				},
  1125  				ResourceRequest: true,
  1126  			},
  1127  			matches: true,
  1128  			name:    "v1 group match",
  1129  		},
  1130  		{
  1131  			policy: &v1beta1.Policy{
  1132  				Spec: v1beta1.PolicySpec{
  1133  					Group: "*",
  1134  				},
  1135  			},
  1136  			attr: authorizer.AttributesRecord{
  1137  				User: &user.DefaultInfo{
  1138  					Name:   "foo",
  1139  					Groups: []string{"bar", user.AllAuthenticated},
  1140  				},
  1141  				ResourceRequest: true,
  1142  			},
  1143  			matches: true,
  1144  			name:    "v1 group wildcard match",
  1145  		},
  1146  		{
  1147  			policy: &v1beta1.Policy{
  1148  				Spec: v1beta1.PolicySpec{
  1149  					User:     "*",
  1150  					Readonly: true,
  1151  				},
  1152  			},
  1153  			attr: authorizer.AttributesRecord{
  1154  				User: &user.DefaultInfo{
  1155  					Name:   "foo",
  1156  					Groups: []string{user.AllAuthenticated},
  1157  				},
  1158  				Verb:            "get",
  1159  				ResourceRequest: true,
  1160  			},
  1161  			matches: true,
  1162  			name:    "v1 read-only match",
  1163  		},
  1164  		{
  1165  			policy: &v1beta1.Policy{
  1166  				Spec: v1beta1.PolicySpec{
  1167  					User:     "*",
  1168  					Resource: "foo",
  1169  				},
  1170  			},
  1171  			attr: authorizer.AttributesRecord{
  1172  				User: &user.DefaultInfo{
  1173  					Name:   "foo",
  1174  					Groups: []string{user.AllAuthenticated},
  1175  				},
  1176  				Resource:        "foo",
  1177  				ResourceRequest: true,
  1178  			},
  1179  			matches: true,
  1180  			name:    "v1 resource match",
  1181  		},
  1182  		{
  1183  			policy: &v1beta1.Policy{
  1184  				Spec: v1beta1.PolicySpec{
  1185  					User:      "foo",
  1186  					Namespace: "bar",
  1187  					Resource:  "baz",
  1188  				},
  1189  			},
  1190  			attr: authorizer.AttributesRecord{
  1191  				User: &user.DefaultInfo{
  1192  					Name:   "foo",
  1193  					Groups: []string{user.AllAuthenticated},
  1194  				},
  1195  				Namespace:       "bar",
  1196  				Resource:        "baz",
  1197  				ResourceRequest: true,
  1198  			},
  1199  			matches: true,
  1200  			name:    "v1 namespace match",
  1201  		},
  1202  		{
  1203  			policy: &v1beta1.Policy{
  1204  				Spec: v1beta1.PolicySpec{
  1205  					User:            "*",
  1206  					NonResourcePath: "/api",
  1207  				},
  1208  			},
  1209  			attr: authorizer.AttributesRecord{
  1210  				User: &user.DefaultInfo{
  1211  					Name:   "foo",
  1212  					Groups: []string{user.AllAuthenticated},
  1213  				},
  1214  				Path:            "/api",
  1215  				ResourceRequest: false,
  1216  			},
  1217  			matches: true,
  1218  			name:    "v1 non-resource match",
  1219  		},
  1220  		{
  1221  			policy: &v1beta1.Policy{
  1222  				Spec: v1beta1.PolicySpec{
  1223  					User:            "*",
  1224  					NonResourcePath: "*",
  1225  				},
  1226  			},
  1227  			attr: authorizer.AttributesRecord{
  1228  				User: &user.DefaultInfo{
  1229  					Name:   "foo",
  1230  					Groups: []string{user.AllAuthenticated},
  1231  				},
  1232  				Path:            "/api",
  1233  				ResourceRequest: false,
  1234  			},
  1235  			matches: true,
  1236  			name:    "v1 non-resource wildcard match",
  1237  		},
  1238  		{
  1239  			policy: &v1beta1.Policy{
  1240  				Spec: v1beta1.PolicySpec{
  1241  					User:            "*",
  1242  					NonResourcePath: "/api/*",
  1243  				},
  1244  			},
  1245  			attr: authorizer.AttributesRecord{
  1246  				User: &user.DefaultInfo{
  1247  					Name:   "foo",
  1248  					Groups: []string{user.AllAuthenticated},
  1249  				},
  1250  				Path:            "/api/foo",
  1251  				ResourceRequest: false,
  1252  			},
  1253  			matches: true,
  1254  			name:    "v1 non-resource wildcard subpath match",
  1255  		},
  1256  	}
  1257  	for _, test := range tests {
  1258  		policy := &abac.Policy{}
  1259  		if err := abac.Scheme.Convert(test.policy, policy, nil); err != nil {
  1260  			t.Errorf("%s: error converting: %v", test.name, err)
  1261  			continue
  1262  		}
  1263  		matches := matches(*policy, test.attr)
  1264  		if test.matches != matches {
  1265  			t.Errorf("%s: expected: %t, saw: %t", test.name, test.matches, matches)
  1266  			continue
  1267  		}
  1268  	}
  1269  }
  1270  

View as plain text