blob: 890bb57b0912287a6c6e9cffcd576d7cf5b38a91 [file] [log] [blame] [edit]
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package aws
import (
"context"
"strings"
"testing"
"github.com/hashicorp/vault/sdk/logical"
"github.com/stretchr/testify/require"
)
func TestNormalizeDisplayName_NormRequired(t *testing.T) {
invalidNames := map[string]string{
"^#$test name\nshould be normalized)(*": "___test_name_should_be_normalized___",
"^#$test name1 should be normalized)(*": "___test_name1_should_be_normalized___",
"^#$test name should be normalized)(*": "___test_name__should_be_normalized___",
"^#$test name__should be normalized)(*": "___test_name__should_be_normalized___",
}
for k, v := range invalidNames {
normalizedName := normalizeDisplayName(k)
if normalizedName != v {
t.Fatalf(
"normalizeDisplayName does not normalize AWS name correctly: %s should resolve to %s",
k,
normalizedName)
}
}
}
func TestNormalizeDisplayName_NormNotRequired(t *testing.T) {
validNames := []string{
"test_name_should_normalize_to_itself@example.com",
"test1_name_should_normalize_to_itself@example.com",
"UPPERlower0123456789-_,.@example.com",
}
for _, n := range validNames {
normalizedName := normalizeDisplayName(n)
if normalizedName != n {
t.Fatalf(
"normalizeDisplayName erroneously normalizes valid names: expected %s but normalized to %s",
n,
normalizedName)
}
}
}
func TestGenUsername(t *testing.T) {
type testCase struct {
name string
policy string
userType string
UsernameTemplate string
expectedError string
expectedRegex string
expectedLength int
}
tests := map[string]testCase{
"Truncated to 64. No warnings expected": {
name: "name1",
policy: "policy1",
userType: "iam_user",
UsernameTemplate: defaultUserNameTemplate,
expectedError: "",
expectedRegex: `^vault-name1-policy1-[0-9]+-[a-zA-Z0-9]+`,
expectedLength: 64,
},
"Truncated to 32. No warnings expected": {
name: "name1",
policy: "policy1",
userType: "sts",
UsernameTemplate: defaultUserNameTemplate,
expectedError: "",
expectedRegex: `^vault-[0-9]+-[a-zA-Z0-9]+`,
expectedLength: 32,
},
"Too long. Error expected — IAM": {
name: "this---is---a---very---long---name",
policy: "long------policy------name",
userType: "assume_role",
UsernameTemplate: `{{ if (eq .Type "IAM") }}{{ printf "%s-%s-%s-%s" (.DisplayName) (.PolicyName) (unix_time) (random 20) }}{{ end }}`,
expectedError: "the username generated by the template exceeds the IAM username length limits of 64 chars",
expectedRegex: "",
expectedLength: 64,
},
"Too long. Error expected — STS": {
name: "this---is---a---very---long---name",
policy: "long------policy------name",
userType: "sts",
UsernameTemplate: `{{ if (eq .Type "STS") }}{{ printf "%s-%s-%s-%s" (.DisplayName) (.PolicyName) (unix_time) (random 20) }}{{ end }}`,
expectedError: "the username generated by the template exceeds the STS username length limits of 32 chars",
expectedRegex: "",
expectedLength: 32,
},
}
for testDescription, testCase := range tests {
t.Run(testDescription, func(t *testing.T) {
testUsername, err := genUsername(testCase.name, testCase.policy, testCase.userType, testCase.UsernameTemplate)
if err != nil && !strings.Contains(err.Error(), testCase.expectedError) {
t.Fatalf("expected an error %s; instead received %s", testCase.expectedError, err)
}
if err == nil {
require.Regexp(t, testCase.expectedRegex, testUsername)
if len(testUsername) > testCase.expectedLength {
t.Fatalf("expected username to be of length %d, got %d", testCase.expectedLength, len(testUsername))
}
}
})
}
}
func TestReadConfig_DefaultTemplate(t *testing.T) {
config := logical.TestBackendConfig()
config.StorageView = &logical.InmemStorage{}
b := Backend(config)
if err := b.Setup(context.Background(), config); err != nil {
t.Fatal(err)
}
testTemplate := ""
configData := map[string]interface{}{
"connection_uri": "test_uri",
"username": "guest",
"password": "guest",
"username_template": testTemplate,
}
configReq := &logical.Request{
Operation: logical.UpdateOperation,
Path: "config/root",
Storage: config.StorageView,
Data: configData,
}
resp, err := b.HandleRequest(context.Background(), configReq)
if err != nil || (resp != nil && resp.IsError()) {
t.Fatalf("bad: resp: %#v\nerr:%s", resp, err)
}
if resp != nil {
t.Fatal("expected a nil response")
}
configResult, err := readConfig(context.Background(), config.StorageView)
if err != nil {
t.Fatalf("expected err to be nil; got %s", err)
}
// No template provided, config set to defaultUsernameTemplate
if configResult.UsernameTemplate != defaultUserNameTemplate {
t.Fatalf(
"expected template %s; got %s",
defaultUserNameTemplate,
configResult.UsernameTemplate,
)
}
}
func TestReadConfig_CustomTemplate(t *testing.T) {
config := logical.TestBackendConfig()
config.StorageView = &logical.InmemStorage{}
b := Backend(config)
if err := b.Setup(context.Background(), config); err != nil {
t.Fatal(err)
}
testTemplate := "`foo-{{ .DisplayName }}`"
configData := map[string]interface{}{
"connection_uri": "test_uri",
"username": "guest",
"password": "guest",
"username_template": testTemplate,
}
configReq := &logical.Request{
Operation: logical.UpdateOperation,
Path: "config/root",
Storage: config.StorageView,
Data: configData,
}
resp, err := b.HandleRequest(context.Background(), configReq)
if err != nil || (resp != nil && resp.IsError()) {
t.Fatalf("bad: resp: %#v\nerr:%s", resp, err)
}
if resp != nil {
t.Fatal("expected a nil response")
}
configResult, err := readConfig(context.Background(), config.StorageView)
if err != nil {
t.Fatalf("expected err to be nil; got %s", err)
}
if configResult.UsernameTemplate != testTemplate {
t.Fatalf(
"expected template %s; got %s",
testTemplate,
configResult.UsernameTemplate,
)
}
}