Skip to content

Commit

Permalink
Add identity templating helper to sdk/framework (#8088)
Browse files Browse the repository at this point in the history
* Add identity templating helper to sdk/framework

* Cleanup a bit

* Fix length issue when groups/aliases are filtered due to ns

* review feedback
  • Loading branch information
briankassouf authored Jan 6, 2020
1 parent e8c1ef5 commit 5fc424d
Show file tree
Hide file tree
Showing 26 changed files with 1,827 additions and 432 deletions.
81 changes: 81 additions & 0 deletions helper/identity/identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

proto "github.com/golang/protobuf/proto"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/vault/sdk/logical"
)

func (g *Group) Clone() (*Group, error) {
Expand Down Expand Up @@ -63,3 +64,83 @@ func (p *Alias) Clone() (*Alias, error) {

return &clonedAlias, nil
}

// ToSDKAlias converts the provided alias to an SDK compatible alias.
func ToSDKAlias(a *Alias) *logical.Alias {
if a == nil {
return nil
}
metadata := make(map[string]string, len(a.Metadata))
for k, v := range a.Metadata {
metadata[k] = v
}

return &logical.Alias{
Name: a.Name,
ID: a.ID,
MountAccessor: a.MountAccessor,
MountType: a.MountType,
Metadata: metadata,
NamespaceID: a.NamespaceID,
}
}

// ToSDKEntity converts the provided entity to an SDK compatible entity.
func ToSDKEntity(e *Entity) *logical.Entity {
if e == nil {
return nil
}

aliases := make([]*logical.Alias, len(e.Aliases))

for i, a := range e.Aliases {
aliases[i] = ToSDKAlias(a)
}

metadata := make(map[string]string, len(e.Metadata))
for k, v := range e.Metadata {
metadata[k] = v
}

return &logical.Entity{
ID: e.ID,
Name: e.Name,
Disabled: e.Disabled,
Aliases: aliases,
Metadata: metadata,
NamespaceID: e.NamespaceID,
}
}

// ToSDKGroup converts the provided group to an SDK compatible group.
func ToSDKGroup(g *Group) *logical.Group {
if g == nil {
return nil
}

metadata := make(map[string]string, len(g.Metadata))
for k, v := range g.Metadata {
metadata[k] = v
}

return &logical.Group{
ID: g.ID,
Name: g.Name,
Metadata: metadata,
NamespaceID: g.NamespaceID,
}
}

// ToSDKGroups converts the provided group list to an SDK compatible group list.
func ToSDKGroups(groups []*Group) []*logical.Group {
if groups == nil {
return nil
}

ret := make([]*logical.Group, len(groups))

for i, g := range groups {
ret[i] = ToSDKGroup(g)
}
return ret
}
57 changes: 57 additions & 0 deletions sdk/framework/identity.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package framework

import (
"errors"

"github.com/hashicorp/errwrap"
"github.com/hashicorp/vault/sdk/helper/identitytpl"
"github.com/hashicorp/vault/sdk/logical"
)

// PopulateIdentityTemplate takes a template string, an entity ID, and an
// instance of system view. It will query system view for information about the
// entity and use the resulting identity information to populate the template
// string.
func PopulateIdentityTemplate(tpl string, entityID string, sysView logical.SystemView) (string, error) {
entity, err := sysView.EntityInfo(entityID)
if err != nil {
return "", err
}
if entity == nil {
return "", errors.New("no entity found")
}

groups, err := sysView.GroupsForEntity(entityID)
if err != nil {
return "", err
}

input := identitytpl.PopulateStringInput{
String: tpl,
Entity: entity,
Groups: groups,
Mode: identitytpl.ACLTemplating,
}

_, out, err := identitytpl.PopulateString(input)
if err != nil {
return "", err
}

return out, nil
}

// ValidateIdentityTemplate takes a template string and returns if the string is
// a valid identity template.
func ValidateIdentityTemplate(tpl string) (bool, error) {
hasTemplating, _, err := identitytpl.PopulateString(identitytpl.PopulateStringInput{
Mode: identitytpl.ACLTemplating,
ValidityCheckOnly: true,
String: tpl,
})
if err != nil {
return false, errwrap.Wrapf("failed to validate policy templating: {{err}}", err)
}

return hasTemplating, nil
}
100 changes: 100 additions & 0 deletions sdk/framework/identity_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package framework

import (
"testing"

"github.com/hashicorp/vault/sdk/logical"
)

func TestIdentityTemplating(t *testing.T) {
sysView := &logical.StaticSystemView{
EntityVal: &logical.Entity{
ID: "test-id",
Name: "test",
Aliases: []*logical.Alias{
{
ID: "alias-id",
Name: "test alias",
MountAccessor: "test_mount",
MountType: "secret",
Metadata: map[string]string{
"alias-metadata": "alias-metadata-value",
},
},
},
Metadata: map[string]string{
"entity-metadata": "entity-metadata-value",
},
},
GroupsVal: []*logical.Group{
{
ID: "group1-id",
Name: "group1",
Metadata: map[string]string{
"group-metadata": "group-metadata-value",
},
},
},
}

tCases := []struct {
tpl string
expected string
}{
{
tpl: "{{identity.entity.id}}",
expected: "test-id",
},
{
tpl: "{{identity.entity.name}}",
expected: "test",
},
{
tpl: "{{identity.entity.metadata.entity-metadata}}",
expected: "entity-metadata-value",
},
{
tpl: "{{identity.entity.aliases.test_mount.id}}",
expected: "alias-id",
},
{
tpl: "{{identity.entity.aliases.test_mount.id}}",
expected: "alias-id",
},
{
tpl: "{{identity.entity.aliases.test_mount.name}}",
expected: "test alias",
},
{
tpl: "{{identity.entity.aliases.test_mount.metadata.alias-metadata}}",
expected: "alias-metadata-value",
},
{
tpl: "{{identity.groups.ids.group1-id.name}}",
expected: "group1",
},
{
tpl: "{{identity.groups.names.group1.id}}",
expected: "group1-id",
},
{
tpl: "{{identity.groups.names.group1.metadata.group-metadata}}",
expected: "group-metadata-value",
},
{
tpl: "{{identity.groups.ids.group1-id.metadata.group-metadata}}",
expected: "group-metadata-value",
},
}

for _, tCase := range tCases {
out, err := PopulateIdentityTemplate(tCase.tpl, "test", sysView)
if err != nil {
t.Fatal(err)
}

if out != tCase.expected {
t.Fatalf("got %q, expected %q", out, tCase.expected)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package identity
package identitytpl

import (
"encoding/json"
Expand All @@ -9,7 +9,7 @@ import (
"time"

"github.com/hashicorp/errwrap"
"github.com/hashicorp/vault/helper/namespace"
"github.com/hashicorp/vault/sdk/logical"
)

var (
Expand All @@ -27,9 +27,9 @@ const (
type PopulateStringInput struct {
String string
ValidityCheckOnly bool
Entity *Entity
Groups []*Group
Namespace *namespace.Namespace
Entity *logical.Entity
Groups []*logical.Group
NamespaceID string
Mode int // processing mode, ACLTemplate or JSONTemplating
Now time.Time // optional, defaults to current time

Expand Down Expand Up @@ -165,7 +165,7 @@ func PopulateString(p PopulateStringInput) (bool, string, error) {

func performTemplating(input string, p *PopulateStringInput) (string, error) {

performAliasTemplating := func(trimmed string, alias *Alias) (string, error) {
performAliasTemplating := func(trimmed string, alias *logical.Alias) (string, error) {
switch {
case trimmed == "id":
return p.templateHandler(alias.ID)
Expand Down Expand Up @@ -210,7 +210,7 @@ func performTemplating(input string, p *PopulateStringInput) (string, error) {
if len(split) != 2 {
return "", errors.New("invalid alias selector")
}
var alias *Alias
var alias *logical.Alias
for _, a := range p.Entity.Aliases {
if split[0] == a.MountAccessor {
alias = a
Expand All @@ -223,7 +223,7 @@ func performTemplating(input string, p *PopulateStringInput) (string, error) {
}

// An empty alias is sufficient for generating defaults
alias = &Alias{Metadata: make(map[string]string)}
alias = &logical.Alias{Metadata: make(map[string]string)}
}
return performAliasTemplating(split[1], alias)
}
Expand Down Expand Up @@ -254,17 +254,16 @@ func performTemplating(input string, p *PopulateStringInput) (string, error) {
if len(accessorSplit) != 2 {
return "", errors.New("invalid groups accessor")
}
var found *Group
var found *logical.Group
for _, group := range p.Groups {
var compare string
if ids {
compare = group.ID
} else {
if p.Namespace != nil && group.NamespaceID == p.Namespace.ID {
compare = group.Name
} else {
if p.NamespaceID != "" && group.NamespaceID != p.NamespaceID {
continue
}
compare = group.Name
}

if compare == accessorSplit[0] {
Expand Down
Loading

0 comments on commit 5fc424d

Please sign in to comment.