Skip to content

Commit

Permalink
Let allowed_users template mix templated and non-templated parts (#10388
Browse files Browse the repository at this point in the history
)
  • Loading branch information
phihos committed Oct 17, 2021
1 parent 8d438a9 commit b635927
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 1 deletion.
76 changes: 76 additions & 0 deletions builtin/logical/ssh/backend_test.go
Expand Up @@ -31,6 +31,7 @@ const (
testIP = "127.0.0.1"
testUserName = "vaultssh"
testAdminUser = "vaultssh"
testCaKeyType = "ca"
testOTPKeyType = "otp"
testDynamicKeyType = "dynamic"
testCIDRList = "127.0.0.1/32"
Expand Down Expand Up @@ -318,6 +319,24 @@ func TestBackend_allowed_users(t *testing.T) {
}
}

func TestBackend_allowed_users_template(t *testing.T) {
testAllowedUsersTemplate(t,
"{{ identity.entity.metadata.ssh_username }}",
testUserName, map[string]string{
"ssh_username": testUserName,
},
)
}

func TestBackend_allowed_users_template_with_static_prefix(t *testing.T) {
testAllowedUsersTemplate(t,
"ssh-{{ identity.entity.metadata.ssh_username }}",
"ssh-"+testUserName, map[string]string{
"ssh_username": testUserName,
},
)
}

func newTestingFactory(t *testing.T) func(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) {
return func(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) {
defaultLeaseTTLVal := 2 * time.Minute
Expand Down Expand Up @@ -1614,6 +1633,63 @@ func getSshCaTestCluster(t *testing.T, userIdentity string) (*vault.TestCluster,
return cluster, userpassToken
}

func testAllowedUsersTemplate(t *testing.T, testAllowedUsersTemplate string,
expectedValidPrincipal string, testEntityMetadata map[string]string) {
cluster, userpassToken := getSshCaTestCluster(t, testUserName)
defer cluster.Cleanup()
client := cluster.Cores[0].Client

// set metadata "ssh_username" to userpass username
tokenLookupResponse, err := client.Logical().Write("/auth/token/lookup", map[string]interface{}{
"token": userpassToken,
})
if err != nil {
t.Fatal(err)
}
entityID := tokenLookupResponse.Data["entity_id"].(string)
_, err = client.Logical().Write("/identity/entity/id/"+entityID, map[string]interface{}{
"metadata": testEntityMetadata,
})
if err != nil {
t.Fatal(err)
}

_, err = client.Logical().Write("ssh/roles/my-role", map[string]interface{}{
"key_type": testCaKeyType,
"allow_user_certificates": true,
"allowed_users": testAllowedUsersTemplate,
"allowed_users_template": true,
})
if err != nil {
t.Fatal(err)
}

// sign SSH key as userpass user
client.SetToken(userpassToken)
signResponse, err := client.Logical().Write("ssh/sign/my-role", map[string]interface{}{
"public_key": testCAPublicKey,
"valid_principals": expectedValidPrincipal,
})
if err != nil {
t.Fatal(err)
}

// check for the expected valid principals of certificate
signedKey := signResponse.Data["signed_key"].(string)
key, _ := base64.StdEncoding.DecodeString(strings.Split(signedKey, " ")[1])
parsedKey, err := ssh.ParsePublicKey(key)
if err != nil {
t.Fatal(err)
}
actualPrincipals := parsedKey.(*ssh.Certificate).ValidPrincipals
if actualPrincipals[0] != expectedValidPrincipal {
t.Fatal(
fmt.Sprintf("incorrect ValidPrincipals: %v should be %v",
actualPrincipals, []string{expectedValidPrincipal}),
)
}
}

func configCaStep(caPublicKey, caPrivateKey string) logicaltest.TestStep {
return logicaltest.TestStep{
Operation: logical.UpdateOperation,
Expand Down
2 changes: 1 addition & 1 deletion builtin/logical/ssh/path_sign.go
Expand Up @@ -220,7 +220,7 @@ func (b *backend) calculateValidPrincipals(data *framework.FieldData, req *logic
for _, principal := range strutil.RemoveDuplicates(strutil.ParseStringSlice(principalsAllowedByRole, ","), false) {
if role.AllowedUsersTemplate {
// Look for templating markers {{ .* }}
matched, _ := regexp.MatchString(`^{{.+?}}$`, principal)
matched, _ := regexp.MatchString(`{{.+?}}`, principal)
if matched {
if req.EntityID != "" {
// Retrieve principal based on template + entityID from request.
Expand Down

0 comments on commit b635927

Please sign in to comment.