1
16
17 package options
18
19 import (
20 "fmt"
21 "reflect"
22 "strings"
23 "testing"
24 "time"
25
26 "github.com/google/go-cmp/cmp"
27 "github.com/spf13/pflag"
28
29 utilerrors "k8s.io/apimachinery/pkg/util/errors"
30 "k8s.io/apimachinery/pkg/util/wait"
31 "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes"
32 )
33
34 func TestAuthzValidate(t *testing.T) {
35 examplePolicyFile := "../../auth/authorizer/abac/example_policy_file.jsonl"
36
37 testCases := []struct {
38 name string
39 modes []string
40 policyFile string
41 webhookConfigFile string
42 webhookRetryBackoff *wait.Backoff
43 expectErr bool
44 expectErrorSubString string
45 }{
46 {
47 name: "Unknown modes should return errors",
48 modes: []string{"DoesNotExist"},
49 expectErr: true,
50 expectErrorSubString: "is not a valid mode",
51 },
52 {
53 name: "At least one authorizationMode is necessary",
54 modes: []string{},
55 expectErr: true,
56 expectErrorSubString: "at least one authorization-mode must be passed",
57 },
58 {
59 name: "ModeAlwaysAllow specified more than once",
60 modes: []string{modes.ModeAlwaysAllow, modes.ModeAlwaysAllow},
61 expectErr: true,
62 expectErrorSubString: "has mode specified more than once",
63 },
64 {
65 name: "ModeAlwaysAllow and ModeAlwaysDeny should return without authorizationPolicyFile",
66 modes: []string{modes.ModeAlwaysAllow, modes.ModeAlwaysDeny},
67 expectErr: false,
68 },
69 {
70 name: "ModeABAC requires a policy file",
71 modes: []string{modes.ModeAlwaysAllow, modes.ModeAlwaysDeny, modes.ModeABAC},
72 expectErr: true,
73 expectErrorSubString: "authorization-mode ABAC's authorization policy file not passed",
74 },
75 {
76 name: "Authorization Policy file cannot be used without ModeABAC",
77 modes: []string{modes.ModeAlwaysAllow, modes.ModeAlwaysDeny},
78 policyFile: examplePolicyFile,
79 webhookConfigFile: "",
80 expectErr: true,
81 expectErrorSubString: "cannot specify --authorization-policy-file without mode ABAC",
82 },
83 {
84 name: "ModeABAC should not error if a valid policy path is provided",
85 modes: []string{modes.ModeAlwaysAllow, modes.ModeAlwaysDeny, modes.ModeABAC},
86 policyFile: examplePolicyFile,
87 webhookConfigFile: "",
88 expectErr: false,
89 },
90 {
91 name: "ModeWebhook requires a config file",
92 modes: []string{modes.ModeWebhook},
93 expectErr: true,
94 expectErrorSubString: "authorization-mode Webhook's authorization config file not passed",
95 },
96 {
97 name: "Cannot provide webhook config file without ModeWebhook",
98 modes: []string{modes.ModeAlwaysAllow},
99 webhookConfigFile: "authz_webhook_config.yaml",
100 expectErr: true,
101 expectErrorSubString: "cannot specify --authorization-webhook-config-file without mode Webhook",
102 },
103 {
104 name: "ModeWebhook should not error if a valid config file is provided",
105 modes: []string{modes.ModeWebhook},
106 webhookConfigFile: "authz_webhook_config.yaml",
107 expectErr: false,
108 },
109 {
110 name: "ModeWebhook should error if an invalid number of webhook retry attempts is provided",
111 modes: []string{modes.ModeWebhook},
112 webhookConfigFile: "authz_webhook_config.yaml",
113 webhookRetryBackoff: &wait.Backoff{Steps: 0},
114 expectErr: true,
115 expectErrorSubString: "number of webhook retry attempts must be greater than 0",
116 },
117 }
118
119 for _, testcase := range testCases {
120 t.Run(testcase.name, func(t *testing.T) {
121 options := NewBuiltInAuthorizationOptions()
122 options.Modes = testcase.modes
123 options.WebhookConfigFile = testcase.webhookConfigFile
124 options.WebhookRetryBackoff = testcase.webhookRetryBackoff
125 options.PolicyFile = testcase.policyFile
126
127 errs := options.Validate()
128 if len(errs) > 0 && !testcase.expectErr {
129 t.Errorf("got unexpected err %v", errs)
130 }
131 if testcase.expectErr && len(errs) == 0 {
132 t.Errorf("should return an error")
133 }
134 if len(errs) > 0 && testcase.expectErr {
135 if !strings.Contains(utilerrors.NewAggregate(errs).Error(), testcase.expectErrorSubString) {
136 t.Errorf("exepected to found error: %s, but no error found", testcase.expectErrorSubString)
137 }
138 }
139 })
140 }
141 }
142
143 func TestBuiltInAuthorizationOptionsAddFlags(t *testing.T) {
144 var args = []string{
145 fmt.Sprintf("--authorization-mode=%s,%s,%s,%s", modes.ModeAlwaysAllow, modes.ModeAlwaysDeny, modes.ModeABAC, modes.ModeWebhook),
146 "--authorization-policy-file=policy_file.json",
147 "--authorization-webhook-config-file=webhook_config_file.yaml",
148 "--authorization-webhook-version=v1",
149 "--authorization-webhook-cache-authorized-ttl=60s",
150 "--authorization-webhook-cache-unauthorized-ttl=30s",
151 }
152
153 expected := &BuiltInAuthorizationOptions{
154 Modes: []string{modes.ModeAlwaysAllow, modes.ModeAlwaysDeny, modes.ModeABAC, modes.ModeWebhook},
155 PolicyFile: "policy_file.json",
156 WebhookConfigFile: "webhook_config_file.yaml",
157 WebhookVersion: "v1",
158 WebhookCacheAuthorizedTTL: 60 * time.Second,
159 WebhookCacheUnauthorizedTTL: 30 * time.Second,
160 WebhookRetryBackoff: &wait.Backoff{
161 Duration: 500 * time.Millisecond,
162 Factor: 1.5,
163 Jitter: 0.2,
164 Steps: 5,
165 },
166 }
167
168 opts := NewBuiltInAuthorizationOptions()
169 pf := pflag.NewFlagSet("test-builtin-authorization-opts", pflag.ContinueOnError)
170 opts.AddFlags(pf)
171
172 if err := pf.Parse(args); err != nil {
173 t.Fatal(err)
174 }
175
176 if !opts.AreLegacyFlagsSet() {
177 t.Fatal("legacy flags should have been configured")
178 }
179
180
181 opts.AreLegacyFlagsSet = nil
182
183 if !reflect.DeepEqual(opts, expected) {
184 t.Error(cmp.Diff(opts, expected))
185 }
186 }
187
View as plain text