core: updates to password policy generator (#11596)

* core: fix bug in password policies not using namespaces

* Add changelog
This commit is contained in:
Jason O'Donnell 2021-05-13 09:55:46 -04:00 committed by GitHub
parent 3f242a4432
commit 502cf3b212
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 89 additions and 39 deletions

3
changelog/11596.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:bug
core (enterprise): Fix plugins mounted in namespaces being unable to use password policies
```

View File

@ -336,11 +336,11 @@ func (d dynamicSystemView) GeneratePasswordFromPolicy(ctx context.Context, polic
// Ensure there's a timeout on the context of some sort
if _, hasTimeout := ctx.Deadline(); !hasTimeout {
var cancel func()
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second)
ctx, cancel = context.WithTimeout(ctx, 1*time.Second)
defer cancel()
}
policyCfg, err := retrievePasswordPolicy(ctx, d.core.systemBarrierView, policyName)
policyCfg, err := d.retrievePasswordPolicy(ctx, policyName)
if err != nil {
return "", fmt.Errorf("failed to retrieve password policy: %w", err)
}

View File

@ -2,7 +2,7 @@ package vault
import (
"context"
"encoding/json"
"encoding/base64"
"fmt"
"reflect"
"sort"
@ -16,6 +16,22 @@ import (
"github.com/hashicorp/vault/sdk/logical"
)
var testPolicyName = "testpolicy"
var rawTestPasswordPolicy = `
length = 20
rule "charset" {
charset = "abcdefghijklmnopqrstuvwxyz"
min_chars = 1
}
rule "charset" {
charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
min_chars = 1
}
rule "charset" {
charset = "0123456789"
min_chars = 1
}`
func TestIdentity_BackendTemplating(t *testing.T) {
var err error
coreConfig := &CoreConfig{
@ -157,47 +173,45 @@ func TestIdentity_BackendTemplating(t *testing.T) {
}
func TestDynamicSystemView_GeneratePasswordFromPolicy_successful(t *testing.T) {
policyName := "testpolicy"
rawPolicy := map[string]interface{}{
"policy": `length = 20
rule "charset" {
charset = "abcdefghijklmnopqrstuvwxyz"
min_chars = 1
}
rule "charset" {
charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
min_chars = 1
}
rule "charset" {
charset = "0123456789"
min_chars = 1
}`,
var err error
coreConfig := &CoreConfig{
DisableMlock: true,
DisableCache: true,
Logger: log.NewNullLogger(),
CredentialBackends: map[string]logical.Factory{},
}
marshalledPolicy, err := json.Marshal(rawPolicy)
cluster := NewTestCluster(t, coreConfig, &TestClusterOptions{})
cluster.Start()
defer cluster.Cleanup()
core := cluster.Cores[0].Core
TestWaitActive(t, core)
b64Policy := base64.StdEncoding.EncodeToString([]byte(rawTestPasswordPolicy))
path := fmt.Sprintf("sys/policies/password/%s", testPolicyName)
req := logical.TestRequest(t, logical.CreateOperation, path)
req.ClientToken = cluster.RootToken
req.Data["policy"] = b64Policy
_, err = core.HandleRequest(namespace.RootContext(nil), req)
if err != nil {
t.Fatalf("Unable to set up test: unable to marshal raw policy to JSON: %s", err)
t.Fatalf("err: %v", err)
}
testStorage := fakeBarrier{
getEntry: &logical.StorageEntry{
Key: getPasswordPolicyKey(policyName),
Value: marshalledPolicy,
},
}
dsv := dynamicSystemView{
core: &Core{
systemBarrierView: NewBarrierView(testStorage, "sys/"),
},
}
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
ctx = namespace.RootContext(ctx)
dsv := dynamicSystemView{core: cluster.Cores[0].Core}
runeset := map[rune]bool{}
runesFound := []rune{}
for i := 0; i < 100; i++ {
actual, err := dsv.GeneratePasswordFromPolicy(ctx, policyName)
actual, err := dsv.GeneratePasswordFromPolicy(ctx, testPolicyName)
if err != nil {
t.Fatalf("no error expected, but got: %s", err)
}
@ -220,12 +234,6 @@ rule "charset" {
}
}
type runes []rune
func (r runes) Len() int { return len(r) }
func (r runes) Less(i, j int) bool { return r[i] < r[j] }
func (r runes) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
func TestDynamicSystemView_GeneratePasswordFromPolicy_failed(t *testing.T) {
type testCase struct {
policyName string
@ -282,6 +290,12 @@ func TestDynamicSystemView_GeneratePasswordFromPolicy_failed(t *testing.T) {
}
}
type runes []rune
func (r runes) Len() int { return len(r) }
func (r runes) Less(i, j int) bool { return r[i] < r[j] }
func (r runes) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
type fakeBarrier struct {
getEntry *logical.StorageEntry
getErr error

View File

@ -0,0 +1,33 @@
// +build !enterprise
package vault
import (
"context"
"encoding/json"
"fmt"
)
const (
passwordPolicySubPath = "password_policy/"
)
// retrievePasswordPolicy retrieves a password policy from the logical storage
func (d dynamicSystemView) retrievePasswordPolicy(ctx context.Context, policyName string) (*passwordPolicyConfig, error) {
storage := d.core.systemBarrierView.SubView(passwordPolicySubPath)
entry, err := storage.Get(ctx, policyName)
if err != nil {
return nil, err
}
if entry == nil {
return nil, nil
}
policyCfg := &passwordPolicyConfig{}
err = json.Unmarshal(entry.Value, &policyCfg)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal stored data: %w", err)
}
return policyCfg, nil
}