Skip to content

Commit

Permalink
Implemented token backend support for identity
Browse files Browse the repository at this point in the history
  • Loading branch information
michelvocks committed Apr 25, 2019
1 parent f6270ba commit 1ec7872
Show file tree
Hide file tree
Showing 4 changed files with 340 additions and 9 deletions.
1 change: 1 addition & 0 deletions api/auth_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,4 +272,5 @@ type TokenCreateRequest struct {
NumUses int `json:"num_uses"`
Renewable *bool `json:"renewable,omitempty"`
Type string `json:"type"`
EntityAlias string `json:"entity_alias"`
}
12 changes: 12 additions & 0 deletions command/token_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type TokenCreateCommand struct {
flagType string
flagMetadata map[string]string
flagPolicies []string
flagEntityAlias string
}

func (c *TokenCreateCommand) Synopsis() string {
Expand Down Expand Up @@ -176,6 +177,16 @@ func (c *TokenCreateCommand) Flags() *FlagSets {
"specified multiple times to attach multiple policies.",
})

f.StringVar(&StringVar{
Name: "entity-alias",
Target: &c.flagEntityAlias,
Default: "",
Usage: "Name of the entity alias to associate with during token creation. " +
"Only works in combination with -role argument and used entity alias " +
"must be listed in allowed entity aliases. If this has been specified, " +
"the entity will not be inherited from the parent.",
})

return set
}

Expand Down Expand Up @@ -224,6 +235,7 @@ func (c *TokenCreateCommand) Run(args []string) int {
ExplicitMaxTTL: c.flagExplicitMaxTTL.String(),
Period: c.flagPeriod.String(),
Type: c.flagType,
EntityAlias: c.flagEntityAlias,
}

var secret *api.Secret
Expand Down
93 changes: 84 additions & 9 deletions vault/token_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import (
"strings"
"time"

proto "github.com/golang/protobuf/proto"
"github.com/golang/protobuf/proto"
"github.com/hashicorp/errwrap"
log "github.com/hashicorp/go-hclog"
sockaddr "github.com/hashicorp/go-sockaddr"
"github.com/hashicorp/go-sockaddr"

metrics "github.com/armon/go-metrics"
multierror "github.com/hashicorp/go-multierror"
Expand Down Expand Up @@ -184,6 +184,11 @@ func (ts *TokenStore) paths() []*framework.Path {
Default: "service",
Description: "The type of token to generate, service or batch",
},

"allowed_entity_aliases": &framework.FieldSchema{
Type: framework.TypeStringSlice,
Description: "String or JSON list of allowed entity aliases. If set, specifies the entity aliases which are allowed to be used during token generation.",
},
},

Callbacks: map[logical.Operation]framework.OperationFunc{
Expand Down Expand Up @@ -614,6 +619,9 @@ type tsRoleEntry struct {

// The type of token this role should issue
TokenType logical.TokenType `json:"token_type" mapstructure:"token_type"`

// The set of allowed entity aliases used during token creation
AllowedEntityAliases []string `json:"allowed_entity_aliases" mapstructure:"allowed_entity_aliases" structs:"allowed_entity_aliases"`
}

type accessorEntry struct {
Expand Down Expand Up @@ -1822,11 +1830,11 @@ func (ts *TokenStore) handleTidy(ctx context.Context, req *logical.Request, data
}

var countAccessorList,
countCubbyholeKeys,
deletedCountAccessorEmptyToken,
deletedCountAccessorInvalidToken,
deletedCountInvalidTokenInAccessor,
deletedCountInvalidCubbyholeKey int64
countCubbyholeKeys,
deletedCountAccessorEmptyToken,
deletedCountAccessorInvalidToken,
deletedCountInvalidTokenInAccessor,
deletedCountInvalidCubbyholeKey int64

validCubbyholeKeys := make(map[string]bool)

Expand Down Expand Up @@ -2109,6 +2117,7 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque
NumUses int `mapstructure:"num_uses"`
Period string
Type string `mapstructure:"type"`
EntityAlias string
}
if err := mapstructure.WeakDecode(req.Data, &data); err != nil {
return logical.ErrorResponse(fmt.Sprintf(
Expand Down Expand Up @@ -2205,6 +2214,60 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque
logical.ErrInvalidRequest
}

// Verify the entity alias
overwriteEntityID := ""
if data.EntityAlias != "" {
// Parameter is only allowed in combination with token role
if role == nil {
return logical.ErrorResponse("'entity_alias' is only allowed in combination with token role"), logical.ErrInvalidRequest
}

// Get mount accessor which is required to lookup entity alias
mountValidationResp := ts.core.router.validateMountByAccessor("auth_token_")
if mountValidationResp == nil {
return logical.ErrorResponse("auth token mount accessor not found"), nil
}

// Verify that the alias exist
aliasByFactors, err := ts.core.identityStore.MemDBAliasByFactors(mountValidationResp.MountAccessor, data.EntityAlias, false, false)
if err != nil {
return logical.ErrorResponse(err.Error()), nil
}

switch {
case aliasByFactors == nil:
// Entity alias does not exist. Create a new entity and entity alias
newAlias := &logical.Alias{
Name: data.EntityAlias,
MountAccessor: mountValidationResp.MountAccessor,
MountType: mountValidationResp.MountType,
}

newEntity, err := ts.core.identityStore.CreateOrFetchEntity(ctx, newAlias)
if err != nil {
return logical.ErrorResponse(err.Error()), nil
}

// Set new entity id
overwriteEntityID = newEntity.ID
default:
// Verify that the specified entity alias is included in the allowed entity alias list
foundEntityAlias := false
for _, entityAlias := range role.AllowedEntityAliases {
if strings.Compare(entityAlias, data.EntityAlias) == 0 {
foundEntityAlias = true
}
}

if !foundEntityAlias {
return logical.ErrorResponse("invalid 'entity_alias' value"), logical.ErrInvalidRequest
}

// Set new entity id
overwriteEntityID = aliasByFactors.CanonicalID
}
}

// Setup the token entry
te := logical.TokenEntry{
Parent: req.ClientToken,
Expand Down Expand Up @@ -2427,9 +2490,14 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque
}

// At this point, it is clear whether the token is going to be an orphan or
// not. If the token is not going to be an orphan, inherit the parent's
// not. If setEntityID is set, the entity identifier will be overwritten.
// Otherwise, if the token is not going to be an orphan, inherit the parent's
// entity identifier into the child token.
if te.Parent != "" {
switch {
case overwriteEntityID != "":
// Overwrite the entity identifier
te.EntityID = overwriteEntityID
case te.Parent != "":
te.EntityID = parent.EntityID

// If the parent has bound CIDRs, copy those into the child. We don't
Expand Down Expand Up @@ -3135,6 +3203,13 @@ func (ts *TokenStore) tokenStoreRoleCreateUpdate(ctx context.Context, req *logic
}
}

allowedEntityAliasesRaw, ok := data.GetOk("allowed_entity_aliases")
if ok {
entry.AllowedEntityAliases = strutil.RemoveDuplicates(allowedEntityAliasesRaw.([]string), true)
} else if req.Operation == logical.CreateOperation {
entry.AllowedEntityAliases = strutil.RemoveDuplicates(data.Get("allowed_entity_aliases").([]string), true)
}

ns, err := namespace.FromContext(ctx)
if err != nil {
return nil, err
Expand Down
Loading

0 comments on commit 1ec7872

Please sign in to comment.