Add templating coalesce function (#4492)

pull/4533/head
Jeff Mitchell 2 years ago committed by GitHub
parent 7105270cd5
commit 4542eef22b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -11,6 +11,12 @@ Canonical reference for changes, improvements, and bugfixes for Boundary.
the alias value. Crate an alias with
`boundary aliases create target -value example.boundary -destination-id ttcp_1234567890`
and connect to a target using an alias using `boundary connect example.boundary`
* templating: A new templating function `coalesce` can be used to match a
template against multiple possible values, returning the first non-empty
value. As an example, this can be used in a credential library to allow a
username value that might be comprised of a name or login name depending on
the auth method, e.g. `{{ coalesce .Account.Name .Account.LoginName}}`
([PR](https://github.com/hashicorp/boundary/pull/4492)))
### Added dependency

@ -1345,6 +1345,17 @@ func TestRepository_sshCertIssuingCredentialLibrary_retrieveCredential(t *testin
opts: []Option{WithKeyType(KeyTypeEcdsa), WithKeyBits(256)},
retOpts: []credential.Option{credential.WithTemplateData(template.Data{Account: template.Account{Email: util.Pointer("rise-of-the-template@foobar.com")}})},
},
{
name: "vault issue ec(256) cert with coalesce username",
username: `{{coalesce .Account.LoginName .Account.Name .Account.Email}}`,
expected: map[string]any{
"username": "name-that-name",
"valid_principals": []string{"name-that-name"},
},
vaulthPath: "ssh/issue/boundary",
opts: []Option{WithKeyType(KeyTypeEcdsa), WithKeyBits(256)},
retOpts: []credential.Option{credential.WithTemplateData(template.Data{Account: template.Account{Name: util.Pointer("name-that-name"), LoginName: util.Pointer(""), Email: util.Pointer("rise-of-the-template@foobar.com")}})},
},
{
name: "vault issue ec(384) cert with disallowed extension",
username: "username-10-because-789",

@ -10,6 +10,7 @@ import (
"fmt"
"hash"
"hash/fnv"
"log"
"net/http"
"slices"
"strings"
@ -599,8 +600,10 @@ func (v verifier) performAuthCheck(ctx context.Context) (
return
}
userData.Account.Name = util.Pointer(acct.GetName())
log.Println("account name", *userData.Account.Name)
userData.Account.Email = util.Pointer(acct.GetEmail())
userData.Account.LoginName = util.Pointer(acct.GetLoginName())
log.Println("account login name", *userData.Account.LoginName)
userData.Account.Subject = util.Pointer(acct.GetSubject())
}

@ -12,3 +12,14 @@ func truncateFrom(str, sep string) string {
before, _, _ := strings.Cut(str, sep)
return before
}
// coalesce will return the first non-empty string in the list of strings, and
// an empty string if all parameters are empty.
func coalesce(vals ...string) string {
for _, val := range vals {
if val != "" {
return val
}
}
return ""
}

@ -33,6 +33,7 @@ func New(ctx context.Context, raw string) (*Parsed, error) {
raw: raw,
funcMap: map[string]any{
"truncateFrom": truncateFrom,
"coalesce": coalesce,
},
}

@ -39,7 +39,7 @@ func TestErrors(t *testing.T) {
require.NotNil(parsed)
assert.Equal(ts, parsed.raw)
assert.NotNil(parsed.tmpl)
assert.Len(parsed.funcMap, 1)
assert.Len(parsed.funcMap, 2)
// Test out errors on the parsed value
@ -102,6 +102,8 @@ func TestGenerate(t *testing.T) {
{{ .Account.Subject }}
{{ .Account.Email }}
{{ truncateFrom .Account.Email "@" }}
{{ coalesce "" .Account.LoginName .Account.Name }}
{{ coalesce "" "" .Account.Name .Account.LoginName }}
`)
parsed, err := New(ctx, raw)
@ -128,6 +130,8 @@ accountLoginName
accountSubject
account@email.com
account
accountLoginName
accountName
`)
assert.Equal(exp, out)

@ -19,10 +19,11 @@ type Data struct {
// request to be from a different auth method, in which case it may not match
// what's in the Account struct.
type User struct {
Id *string
Name *string
FullName *string
Email *string
Id *string
Name *string
LoginName *string
FullName *string
Email *string
}
// Account contains account information. Not all fields will always be

@ -105,14 +105,21 @@ This value may not be populated, or it may be different from the account name us
- `{{.Account.Subject}}` - The account's subject, if a subject is used by that type of account.
- `{{.Account.Email}}` - The account's email, if email is used by that type of account.
Additionally, there is currently a single function that strips the rest of a string after a specified substring.
This function is useful for pulling a user or account name from an email address.
The following example turns `foo@example.com` into `foo`:
Additionally, there are a couple of useful functions:
The `trucateFrom` function strips the rest of a string after a specified
substring. This function is useful for pulling a user or account name from an
email address. The following example turns `foo@example.com` into `foo`:
`{{truncateFrom .Account.Email "@"}}`
The example above uses the account email, but it could be any other parameter.
The `coalesce` function chooses the first non-empty value out of the list. This
is useful when using account names/login names since only one may be populated:
`{{coalesce .Account.Name .Account.LoginName}}`
## Tutorial
Refer to the [SSH certificate injection with HCP Boundary](/boundary/tutorials/access-management/hcp-certificate-injection) tutorial to learn how to configure credential injection with SSH certificates using Vault.

Loading…
Cancel
Save