Skip to content

Commit

Permalink
Added listing of app and group secrets
Browse files Browse the repository at this point in the history
  • Loading branch information
vishalnayak committed Jun 5, 2016
1 parent 38d1764 commit b1549d8
Show file tree
Hide file tree
Showing 4 changed files with 257 additions and 20 deletions.
127 changes: 126 additions & 1 deletion builtin/credential/appgroup/path_app.go
Expand Up @@ -242,7 +242,7 @@ func appPaths(b *backend) []*framework.Path {
HelpDescription: strings.TrimSpace(appHelp["app-selector-id"][1]),
},
&framework.Path{
Pattern: "app/" + framework.GenericNameRegex("app_name") + "/secret-id$",
Pattern: "app/" + framework.GenericNameRegex("app_name") + "/secret-id/?$",
Fields: map[string]*framework.FieldSchema{
"app_name": &framework.FieldSchema{
Type: framework.TypeString,
Expand All @@ -251,10 +251,30 @@ func appPaths(b *backend) []*framework.Path {
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.ReadOperation: b.pathAppSecretIDRead,
logical.ListOperation: b.pathAppSecretIDList,
},
HelpSynopsis: strings.TrimSpace(appHelp["app-secret-id"][0]),
HelpDescription: strings.TrimSpace(appHelp["app-secret-id"][1]),
},
&framework.Path{
Pattern: "app/" + framework.GenericNameRegex("app_name") + "/secret-id/" + framework.GenericNameRegex("secret_id_hmac"),
Fields: map[string]*framework.FieldSchema{
"app_name": &framework.FieldSchema{
Type: framework.TypeString,
Description: "Name of the App.",
},
"secret_id_hmac": &framework.FieldSchema{
Type: framework.TypeString,
Description: "HMAC of the secret ID",
},
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.ReadOperation: b.pathAppSecretIDHMACRead,
logical.DeleteOperation: b.pathAppSecretIDHMACDelete,
},
HelpSynopsis: strings.TrimSpace(appHelp["app-secret-id-hmac"][0]),
HelpDescription: strings.TrimSpace(appHelp["app-secret-id-hmac"][1]),
},
&framework.Path{
Pattern: "app/" + framework.GenericNameRegex("app_name") + "/custom-secret-id$",
Fields: map[string]*framework.FieldSchema{
Expand Down Expand Up @@ -299,6 +319,34 @@ func (b *backend) pathAppList(
return logical.ListResponse(apps), nil
}

// pathAppSecretIDList is used to list all the Apps registered with the backend.
func (b *backend) pathAppSecretIDList(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
appName := data.Get("app_name").(string)
if appName == "" {
return logical.ErrorResponse("missing app_name"), nil
}

app, err := b.appEntry(req.Storage, strings.ToLower(appName))
if err != nil {
return nil, err
}
if app == nil {
return logical.ErrorResponse(fmt.Sprintf("app %s does not exist", appName)), nil
}

// Get the "custom" lock
lock := b.secretIDLock("")
lock.RLock()
defer lock.RUnlock()

secrets, err := req.Storage.List(fmt.Sprintf("secret_id/%s/", b.salt.SaltID(app.SelectorID)))
if err != nil {
return nil, err
}

return logical.ListResponse(secrets), nil
}

// setAppEntry grabs a write lock and stores the options on an App into the storage
func (b *backend) setAppEntry(s logical.Storage, appName string, app *appStorageEntry) error {
b.appLock.Lock()
Expand Down Expand Up @@ -491,6 +539,74 @@ func (b *backend) pathAppBindSecretIDUpdate(req *logical.Request, data *framewor
}
}

func (b *backend) pathAppSecretIDHMACRead(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
appName := data.Get("app_name").(string)
if appName == "" {
return logical.ErrorResponse("missing app_name"), nil
}

hashedSecretID := data.Get("secret_id_hmac").(string)
if hashedSecretID == "" {
return logical.ErrorResponse("missing secret_id_hmac"), nil
}

app, err := b.appEntry(req.Storage, strings.ToLower(appName))
if err != nil {
return nil, err
}
if app == nil {
return nil, fmt.Errorf("app %s does not exist", appName)
}

entryIndex := fmt.Sprintf("secret_id/%s/%s", b.salt.SaltID(app.SelectorID), hashedSecretID)

lock := b.secretIDLock(hashedSecretID)
lock.RLock()
defer lock.RUnlock()

result := secretIDStorageEntry{}
if entry, err := req.Storage.Get(entryIndex); err != nil {
return nil, err
} else if entry == nil {
return nil, nil
} else if err := entry.DecodeJSON(&result); err != nil {
return nil, err
}

respData := structs.New(result).Map()
return &logical.Response{
Data: respData,
}, nil
}

func (b *backend) pathAppSecretIDHMACDelete(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
appName := data.Get("app_name").(string)
if appName == "" {
return logical.ErrorResponse("missing app_name"), nil
}

hashedSecretID := data.Get("secret_id_hmac").(string)
if hashedSecretID == "" {
return logical.ErrorResponse("missing secret_id_hmac"), nil
}

app, err := b.appEntry(req.Storage, strings.ToLower(appName))
if err != nil {
return nil, err
}
if app == nil {
return nil, fmt.Errorf("app %s does not exist", appName)
}

entryIndex := fmt.Sprintf("secret_id/%s/%s", b.salt.SaltID(app.SelectorID), hashedSecretID)

lock := b.secretIDLock(hashedSecretID)
lock.Lock()
defer lock.Unlock()

return nil, req.Storage.Delete(entryIndex)
}

func (b *backend) pathAppBindSecretIDRead(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
appName := data.Get("app_name").(string)
if appName == "" {
Expand Down Expand Up @@ -955,6 +1071,15 @@ that are generated against the App using 'app/<app_name>/secret-id' or
'app/<app_name>/custom-secret-id' endpoints.`,
``,
},
"app-secret-id-hmac": {
"Read or delete a issued secret_id",
`This is particularly useful to clean-up the non-expiring 'secret_id's.
The list operation on the 'app/<app_name>/secret-id' endpoint will return
the HMACed 'secret_id's. This endpoint can be used to read the properties
of the secret. If the 'secret_idnum_uses' field in the response is 0, it represents
a non-expiring 'secret_id'. The same endpoint can be invoked again to delete
it.`,
},
"app-token-ttl": {
`Duration in seconds, the lifetime of the token issued by using the SecretID that
is generated against this App, before which the token needs to be renewed.`,
Expand Down
118 changes: 117 additions & 1 deletion builtin/credential/appgroup/path_group.go
Expand Up @@ -281,7 +281,7 @@ addition to those, a set of policies can be assigned using this.
HelpDescription: strings.TrimSpace(groupHelp["group-selector-id"][1]),
},
&framework.Path{
Pattern: "group/" + framework.GenericNameRegex("group_name") + "/secret-id$",
Pattern: "group/" + framework.GenericNameRegex("group_name") + "/secret-id/?$",
Fields: map[string]*framework.FieldSchema{
"group_name": &framework.FieldSchema{
Type: framework.TypeString,
Expand All @@ -290,6 +290,26 @@ addition to those, a set of policies can be assigned using this.
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.ReadOperation: b.pathGroupSecretIDRead,
logical.ListOperation: b.pathGroupSecretIDList,
},
HelpSynopsis: strings.TrimSpace(groupHelp["group-secret-id"][0]),
HelpDescription: strings.TrimSpace(groupHelp["group-secret-id"][1]),
},
&framework.Path{
Pattern: "group/" + framework.GenericNameRegex("group_name") + "/secret-id/" + framework.GenericNameRegex("secret_id_hmac"),
Fields: map[string]*framework.FieldSchema{
"group_name": &framework.FieldSchema{
Type: framework.TypeString,
Description: "Name of the Group.",
},
"secret_id_hmac": &framework.FieldSchema{
Type: framework.TypeString,
Description: "HMAC of the secret ID",
},
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.ReadOperation: b.pathGroupSecretIDHMACRead,
logical.DeleteOperation: b.pathGroupSecretIDHMACDelete,
},
HelpSynopsis: strings.TrimSpace(groupHelp["group-secret-id"][0]),
HelpDescription: strings.TrimSpace(groupHelp["group-secret-id"][1]),
Expand Down Expand Up @@ -338,6 +358,34 @@ func (b *backend) pathGroupList(
return logical.ListResponse(groups), nil
}

// pathGroupSecretIDList is used to list all the Apps registered with the backend.
func (b *backend) pathGroupSecretIDList(
req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
// Get the "custom" lock
lock := b.secretIDLock("")
lock.RLock()
defer lock.RUnlock()

groupName := data.Get("group_name").(string)
if groupName == "" {
return logical.ErrorResponse("missing group_name"), nil
}

group, err := b.appEntry(req.Storage, strings.ToLower(groupName))
if err != nil {
return nil, err
}
if group == nil {
return logical.ErrorResponse(fmt.Sprintf("group %s does not exist", groupName)), nil
}

secrets, err := req.Storage.List(fmt.Sprintf("secret_id/%s", b.salt.SaltID(group.SelectorID)))
if err != nil {
return nil, err
}
return logical.ListResponse(secrets), nil
}

// setAppEntry grabs a write lock and stores the options on a Group into the storage
func (b *backend) setGroupEntry(s logical.Storage, groupName string, group *groupStorageEntry) error {
b.groupLock.Lock()
Expand Down Expand Up @@ -586,6 +634,74 @@ func (b *backend) pathGroupBindSecretIDUpdate(req *logical.Request, data *framew
}
}

func (b *backend) pathGroupSecretIDHMACRead(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
groupName := data.Get("group_name").(string)
if groupName == "" {
return logical.ErrorResponse("missing group_name"), nil
}

hashedSecretID := data.Get("secret_id_hmac").(string)
if hashedSecretID == "" {
return logical.ErrorResponse("missing secret_id_hmac"), nil
}

group, err := b.groupEntry(req.Storage, strings.ToLower(groupName))
if err != nil {
return nil, err
}
if group == nil {
return nil, fmt.Errorf("group %s does not exist", groupName)
}

entryIndex := fmt.Sprintf("secret_id/%s/%s", b.salt.SaltID(group.SelectorID), hashedSecretID)

lock := b.secretIDLock(hashedSecretID)
lock.RLock()
defer lock.RUnlock()

result := secretIDStorageEntry{}
if entry, err := req.Storage.Get(entryIndex); err != nil {
return nil, err
} else if entry == nil {
return nil, nil
} else if err := entry.DecodeJSON(&result); err != nil {
return nil, err
}

respData := structs.New(result).Map()
return &logical.Response{
Data: respData,
}, nil
}

func (b *backend) pathGroupSecretIDHMACDelete(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
groupName := data.Get("group_name").(string)
if groupName == "" {
return logical.ErrorResponse("missing group_name"), nil
}

hashedSecretID := data.Get("secret_id_hmac").(string)
if hashedSecretID == "" {
return logical.ErrorResponse("missing secret_id_hmac"), nil
}

group, err := b.groupEntry(req.Storage, strings.ToLower(groupName))
if err != nil {
return nil, err
}
if group == nil {
return nil, fmt.Errorf("group %s does not exist", groupName)
}

entryIndex := fmt.Sprintf("secret_id/%s/%s", b.salt.SaltID(group.SelectorID), hashedSecretID)

lock := b.secretIDLock(hashedSecretID)
lock.Lock()
defer lock.Unlock()

return nil, req.Storage.Delete(entryIndex)
}

func (b *backend) pathGroupBindSecretIDRead(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
groupName := data.Get("group_name").(string)
if groupName == "" {
Expand Down
4 changes: 1 addition & 3 deletions builtin/credential/appgroup/path_supergroup.go
Expand Up @@ -2,7 +2,6 @@ package appgroup

import (
"fmt"
"log"
"strings"
"time"

Expand Down Expand Up @@ -162,7 +161,7 @@ addition to those, a set of policies can be assigned using this.
func (b *backend) setSuperGroupEntry(s logical.Storage, superGroupName string, superGroup *superGroupStorageEntry) error {
b.superGroupLock.Lock()
defer b.superGroupLock.Unlock()
log.Printf("reading supergroup: %s\n", superGroupName)

entry, err := logical.StorageEntryJSON("supergroup/"+strings.ToLower(superGroupName), superGroup)
if err != nil {
return err
Expand Down Expand Up @@ -197,7 +196,6 @@ func (b *backend) superGroupEntry(s logical.Storage, superGroupName string) (*su
b.superGroupLock.RLock()
defer b.superGroupLock.RUnlock()

log.Printf("reading supergroup: %s\n", superGroupName)
if entry, err := s.Get("supergroup/" + strings.ToLower(superGroupName)); err != nil {
return nil, err
} else if entry == nil {
Expand Down

0 comments on commit b1549d8

Please sign in to comment.