Skip to content

Commit decdb57

Browse files
benashztomhjp
andauthored
Properly handle role.AliasNameSource migration (#135) (#136)
- set role.AliasNameSource to be the default if both it and its field value are unset instead of returning an error - add tests for the update operation Co-authored-by: Tom Proctor <[email protected]>
1 parent e2ded2a commit decdb57

File tree

2 files changed

+181
-3
lines changed

2 files changed

+181
-3
lines changed

path_role.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -315,14 +315,21 @@ func (b *kubeAuthBackend) pathRoleCreateUpdate(ctx context.Context, req *logical
315315
}
316316

317317
if source, ok := data.GetOk("alias_name_source"); ok {
318-
if err := validateAliasNameSource(source.(string)); err != nil {
319-
return logical.ErrorResponse(err.Error()), nil
318+
// migrate the role.AliasNameSource to be the default
319+
// if both it and the field value are unset
320+
if role.AliasNameSource == aliasNameSourceUnset && source.(string) == aliasNameSourceUnset {
321+
role.AliasNameSource = data.GetDefaultOrZero("alias_name_source").(string)
322+
} else {
323+
role.AliasNameSource = source.(string)
320324
}
321-
role.AliasNameSource = source.(string)
322325
} else if role.AliasNameSource == aliasNameSourceUnset {
323326
role.AliasNameSource = data.Get("alias_name_source").(string)
324327
}
325328

329+
if err := validateAliasNameSource(role.AliasNameSource); err != nil {
330+
return logical.ErrorResponse(err.Error()), nil
331+
}
332+
326333
// Store the entry.
327334
entry, err := logical.StorageEntryJSON("role/"+strings.ToLower(roleName), role)
328335
if err != nil {

path_role_test.go

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package kubeauth
22

33
import (
44
"context"
5+
"encoding/json"
56
"errors"
67
"fmt"
78
"testing"
@@ -311,3 +312,173 @@ func TestPath_Delete(t *testing.T) {
311312
t.Fatalf("Unexpected resp data: expected nil got %#v\n", resp.Data)
312313
}
313314
}
315+
316+
func TestPath_Update(t *testing.T) {
317+
testCases := map[string]struct {
318+
storageData map[string]interface{}
319+
requestData map[string]interface{}
320+
expected *roleStorageEntry
321+
wantErr error
322+
}{
323+
"default": {
324+
storageData: map[string]interface{}{
325+
"bound_service_account_names": []string{"name"},
326+
"bound_service_account_namespaces": []string{"namespace"},
327+
"policies": []string{"test"},
328+
"period": 1 * time.Second,
329+
"ttl": 1 * time.Second,
330+
"num_uses": 12,
331+
"max_ttl": 5 * time.Second,
332+
"alias_name_source": aliasNameSourceDefault,
333+
},
334+
requestData: map[string]interface{}{
335+
"alias_name_source": aliasNameSourceDefault,
336+
"policies": []string{"bar", "foo"},
337+
"period": "3s",
338+
},
339+
expected: &roleStorageEntry{
340+
TokenParams: tokenutil.TokenParams{
341+
TokenPolicies: []string{"bar", "foo"},
342+
TokenPeriod: 3 * time.Second,
343+
TokenTTL: 1 * time.Second,
344+
TokenMaxTTL: 5 * time.Second,
345+
TokenNumUses: 12,
346+
TokenBoundCIDRs: nil,
347+
},
348+
Policies: []string{"bar", "foo"},
349+
Period: 3 * time.Second,
350+
ServiceAccountNames: []string{"name"},
351+
ServiceAccountNamespaces: []string{"namespace"},
352+
TTL: 1 * time.Second,
353+
MaxTTL: 5 * time.Second,
354+
NumUses: 12,
355+
BoundCIDRs: nil,
356+
AliasNameSource: aliasNameSourceDefault,
357+
},
358+
wantErr: nil,
359+
},
360+
"migrate-alias-name-source": {
361+
storageData: map[string]interface{}{
362+
"bound_service_account_names": []string{"name"},
363+
"bound_service_account_namespaces": []string{"namespace"},
364+
"policies": []string{"test"},
365+
"period": 1 * time.Second,
366+
"ttl": 1 * time.Second,
367+
"num_uses": 12,
368+
"max_ttl": 5 * time.Second,
369+
},
370+
requestData: map[string]interface{}{
371+
"alias_name_source": aliasNameSourceUnset,
372+
},
373+
expected: &roleStorageEntry{
374+
TokenParams: tokenutil.TokenParams{
375+
TokenPolicies: []string{"test"},
376+
TokenPeriod: 1 * time.Second,
377+
TokenTTL: 1 * time.Second,
378+
TokenMaxTTL: 5 * time.Second,
379+
TokenNumUses: 12,
380+
TokenBoundCIDRs: nil,
381+
},
382+
Policies: []string{"test"},
383+
Period: 1 * time.Second,
384+
ServiceAccountNames: []string{"name"},
385+
ServiceAccountNamespaces: []string{"namespace"},
386+
TTL: 1 * time.Second,
387+
MaxTTL: 5 * time.Second,
388+
NumUses: 12,
389+
BoundCIDRs: nil,
390+
AliasNameSource: aliasNameSourceDefault,
391+
},
392+
wantErr: nil,
393+
},
394+
"invalid-alias-name-source": {
395+
storageData: map[string]interface{}{
396+
"bound_service_account_names": []string{"name"},
397+
"bound_service_account_namespaces": []string{"namespace"},
398+
"alias_name_source": aliasNameSourceDefault,
399+
},
400+
requestData: map[string]interface{}{
401+
"alias_name_source": "_invalid_",
402+
},
403+
wantErr: errInvalidAliasNameSource,
404+
},
405+
"invalid-alias-name-source-in-storage": {
406+
storageData: map[string]interface{}{
407+
"bound_service_account_names": []string{"name"},
408+
"bound_service_account_namespaces": []string{"namespace"},
409+
"alias_name_source": "_invalid_",
410+
},
411+
requestData: map[string]interface{}{},
412+
wantErr: errInvalidAliasNameSource,
413+
},
414+
"invalid-alias-name-source-migration": {
415+
storageData: map[string]interface{}{
416+
"bound_service_account_names": []string{"name"},
417+
"bound_service_account_namespaces": []string{"namespace"},
418+
"alias_name_source": aliasNameSourceUnset,
419+
},
420+
requestData: map[string]interface{}{
421+
"alias_name_source": "_invalid_",
422+
},
423+
wantErr: errInvalidAliasNameSource,
424+
},
425+
}
426+
427+
for name, tc := range testCases {
428+
t.Run(name, func(t *testing.T) {
429+
b, storage := getBackend(t)
430+
path := fmt.Sprintf("role/%s", name)
431+
432+
data, err := json.Marshal(tc.storageData)
433+
if err != nil {
434+
t.Fatal(err)
435+
}
436+
437+
entry := &logical.StorageEntry{
438+
Key: path,
439+
Value: data,
440+
SealWrap: false,
441+
}
442+
if err := storage.Put(context.Background(), entry); err != nil {
443+
t.Fatal(err)
444+
}
445+
446+
req := &logical.Request{
447+
Operation: logical.UpdateOperation,
448+
Path: path,
449+
Storage: storage,
450+
Data: tc.requestData,
451+
}
452+
453+
resp, err := b.HandleRequest(context.Background(), req)
454+
455+
if tc.wantErr != nil {
456+
var actual error
457+
if err != nil {
458+
actual = err
459+
} else if resp != nil && resp.IsError() {
460+
actual = resp.Error()
461+
} else {
462+
t.Fatalf("expected error")
463+
}
464+
465+
if tc.wantErr.Error() != actual.Error() {
466+
t.Fatalf("expected err %q, actual %q", tc.wantErr, actual)
467+
}
468+
} else {
469+
if err != nil || (resp != nil && resp.IsError()) {
470+
t.Fatalf("err:%s resp:%#v\n", err, resp)
471+
}
472+
473+
actual, err := b.(*kubeAuthBackend).role(context.Background(), storage, name)
474+
if err != nil {
475+
t.Fatal(err)
476+
}
477+
478+
if diff := deep.Equal(tc.expected, actual); diff != nil {
479+
t.Fatal(diff)
480+
}
481+
}
482+
})
483+
}
484+
}

0 commit comments

Comments
 (0)