mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-30 18:17:55 +00:00
Add bound cidrs to tokens in AppRole (#4680)
This commit is contained in:
committed by
Jeff Mitchell
parent
bd99c43e9c
commit
b3a711d717
@@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/hashicorp/errwrap"
|
"github.com/hashicorp/errwrap"
|
||||||
"github.com/hashicorp/vault/helper/cidrutil"
|
"github.com/hashicorp/vault/helper/cidrutil"
|
||||||
|
"github.com/hashicorp/vault/helper/parseutil"
|
||||||
"github.com/hashicorp/vault/logical"
|
"github.com/hashicorp/vault/logical"
|
||||||
"github.com/hashicorp/vault/logical/framework"
|
"github.com/hashicorp/vault/logical/framework"
|
||||||
)
|
)
|
||||||
@@ -160,7 +161,7 @@ func (b *backend) pathLoginUpdate(ctx context.Context, req *logical.Request, dat
|
|||||||
|
|
||||||
// Ensure that the CIDRs on the secret ID are still a subset of that of
|
// Ensure that the CIDRs on the secret ID are still a subset of that of
|
||||||
// role's
|
// role's
|
||||||
err = verifyCIDRRoleSecretIDSubset(entry.CIDRList, role.BoundCIDRList)
|
err = verifyCIDRRoleSecretIDSubset(entry.CIDRList, role.SecretIDBoundCIDRs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -228,7 +229,7 @@ func (b *backend) pathLoginUpdate(ctx context.Context, req *logical.Request, dat
|
|||||||
|
|
||||||
// Ensure that the CIDRs on the secret ID are still a subset of that of
|
// Ensure that the CIDRs on the secret ID are still a subset of that of
|
||||||
// role's
|
// role's
|
||||||
err = verifyCIDRRoleSecretIDSubset(entry.CIDRList, role.BoundCIDRList)
|
err = verifyCIDRRoleSecretIDSubset(entry.CIDRList, role.SecretIDBoundCIDRs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -250,17 +251,22 @@ func (b *backend) pathLoginUpdate(ctx context.Context, req *logical.Request, dat
|
|||||||
metadata = entry.Metadata
|
metadata = entry.Metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(role.BoundCIDRList) != 0 {
|
if len(role.SecretIDBoundCIDRs) != 0 {
|
||||||
if req.Connection == nil || req.Connection.RemoteAddr == "" {
|
if req.Connection == nil || req.Connection.RemoteAddr == "" {
|
||||||
return nil, fmt.Errorf("failed to get connection information")
|
return nil, fmt.Errorf("failed to get connection information")
|
||||||
}
|
}
|
||||||
|
belongs, err := cidrutil.IPBelongsToCIDRBlocksSlice(req.Connection.RemoteAddr, role.SecretIDBoundCIDRs)
|
||||||
belongs, err := cidrutil.IPBelongsToCIDRBlocksSlice(req.Connection.RemoteAddr, role.BoundCIDRList)
|
|
||||||
if err != nil || !belongs {
|
if err != nil || !belongs {
|
||||||
return logical.ErrorResponse(errwrap.Wrapf(fmt.Sprintf("source address %q unauthorized by CIDR restrictions on the role: {{err}}", req.Connection.RemoteAddr), err).Error()), nil
|
return logical.ErrorResponse(errwrap.Wrapf(fmt.Sprintf("source address %q unauthorized by CIDR restrictions on the role: {{err}}", req.Connection.RemoteAddr), err).Error()), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse the CIDRs we should be binding the token to.
|
||||||
|
tokenBoundCIDRs, err := parseutil.ParseAddrs(role.TokenBoundCIDRs)
|
||||||
|
if err != nil {
|
||||||
|
return logical.ErrorResponse(err.Error()), nil
|
||||||
|
}
|
||||||
|
|
||||||
// For some reason, if metadata was set to nil while processing secret ID
|
// For some reason, if metadata was set to nil while processing secret ID
|
||||||
// binding, ensure that it is initialized again to avoid a panic.
|
// binding, ensure that it is initialized again to avoid a panic.
|
||||||
if metadata == nil {
|
if metadata == nil {
|
||||||
@@ -286,6 +292,7 @@ func (b *backend) pathLoginUpdate(ctx context.Context, req *logical.Request, dat
|
|||||||
Alias: &logical.Alias{
|
Alias: &logical.Alias{
|
||||||
Name: role.RoleID,
|
Name: role.RoleID,
|
||||||
},
|
},
|
||||||
|
BoundCIDRs: tokenBoundCIDRs,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &logical.Response{
|
return &logical.Response{
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package approle
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -55,12 +56,20 @@ type roleStorageEntry struct {
|
|||||||
// A constraint, if set, requires 'secret_id' credential to be presented during login
|
// A constraint, if set, requires 'secret_id' credential to be presented during login
|
||||||
BindSecretID bool `json:"bind_secret_id" mapstructure:"bind_secret_id"`
|
BindSecretID bool `json:"bind_secret_id" mapstructure:"bind_secret_id"`
|
||||||
|
|
||||||
// A constraint, if set, specifies the CIDR blocks from which logins should be allowed
|
// Deprecated: A constraint, if set, specifies the CIDR blocks from which logins should be allowed,
|
||||||
|
// please use SecretIDBoundCIDRs instead.
|
||||||
BoundCIDRListOld string `json:"bound_cidr_list,omitempty"`
|
BoundCIDRListOld string `json:"bound_cidr_list,omitempty"`
|
||||||
|
|
||||||
// A constraint, if set, specifies the CIDR blocks from which logins should be allowed
|
// Deprecated: A constraint, if set, specifies the CIDR blocks from which logins should be allowed,
|
||||||
|
// please use SecretIDBoundCIDRs instead.
|
||||||
BoundCIDRList []string `json:"bound_cidr_list_list" mapstructure:"bound_cidr_list"`
|
BoundCIDRList []string `json:"bound_cidr_list_list" mapstructure:"bound_cidr_list"`
|
||||||
|
|
||||||
|
// A constraint, if set, specifies the CIDR blocks from which logins should be allowed
|
||||||
|
SecretIDBoundCIDRs []string `json:"secret_id_bound_cidrs" mapstructure:"secret_id_bound_cidrs"`
|
||||||
|
|
||||||
|
// A constraint, if set, specifies the CIDR blocks from which token use should be allowed
|
||||||
|
TokenBoundCIDRs []string `json:"token_bound_cidrs" mapstructure:"token_bound_cidrs"`
|
||||||
|
|
||||||
// Period, if set, indicates that the token generated using this role
|
// Period, if set, indicates that the token generated using this role
|
||||||
// should never expire. The token should be renewed within the duration
|
// should never expire. The token should be renewed within the duration
|
||||||
// specified by this value. The renewal duration will be fixed if the
|
// specified by this value. The renewal duration will be fixed if the
|
||||||
@@ -125,10 +134,21 @@ func rolePaths(b *backend) []*framework.Path {
|
|||||||
Default: true,
|
Default: true,
|
||||||
Description: "Impose secret_id to be presented when logging in using this role. Defaults to 'true'.",
|
Description: "Impose secret_id to be presented when logging in using this role. Defaults to 'true'.",
|
||||||
},
|
},
|
||||||
|
// Deprecated
|
||||||
"bound_cidr_list": &framework.FieldSchema{
|
"bound_cidr_list": &framework.FieldSchema{
|
||||||
|
Type: framework.TypeCommaStringSlice,
|
||||||
|
Description: `Deprecated: Please use "secret_id_bound_cidrs" instead. Comma separated string or list
|
||||||
|
of CIDR blocks. If set, specifies the blocks of IP addresses which can perform the login operation.`,
|
||||||
|
},
|
||||||
|
"secret_id_bound_cidrs": &framework.FieldSchema{
|
||||||
Type: framework.TypeCommaStringSlice,
|
Type: framework.TypeCommaStringSlice,
|
||||||
Description: `Comma separated string or list of CIDR blocks. If set, specifies the blocks of
|
Description: `Comma separated string or list of CIDR blocks. If set, specifies the blocks of
|
||||||
IP addresses which can perform the login operation.`,
|
IP addresses which can perform the login operation.`,
|
||||||
|
},
|
||||||
|
"token_bound_cidrs": &framework.FieldSchema{
|
||||||
|
Type: framework.TypeCommaStringSlice,
|
||||||
|
Description: `Comma separated string or list of CIDR blocks. If set, specifies the blocks of
|
||||||
|
IP addresses which can use the returned token.`,
|
||||||
},
|
},
|
||||||
"policies": &framework.FieldSchema{
|
"policies": &framework.FieldSchema{
|
||||||
Type: framework.TypeCommaStringSlice,
|
Type: framework.TypeCommaStringSlice,
|
||||||
@@ -231,18 +251,60 @@ can only be set during role creation and once set, it can't be reset later.`,
|
|||||||
},
|
},
|
||||||
"bound_cidr_list": &framework.FieldSchema{
|
"bound_cidr_list": &framework.FieldSchema{
|
||||||
Type: framework.TypeCommaStringSlice,
|
Type: framework.TypeCommaStringSlice,
|
||||||
Description: `Comma separated string or list of CIDR blocks. If set, specifies the blocks of
|
Description: `Deprecated: Please use "secret_id_bound_cidrs" instead. Comma separated string or list
|
||||||
IP addresses which can perform the login operation.`,
|
of CIDR blocks. If set, specifies the blocks of IP addresses which can perform the login operation.`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Callbacks: map[logical.Operation]framework.OperationFunc{
|
Callbacks: map[logical.Operation]framework.OperationFunc{
|
||||||
logical.UpdateOperation: b.pathRoleBoundCIDRListUpdate,
|
logical.UpdateOperation: b.pathRoleBoundCIDRUpdate,
|
||||||
logical.ReadOperation: b.pathRoleBoundCIDRListRead,
|
logical.ReadOperation: b.pathRoleBoundCIDRListRead,
|
||||||
logical.DeleteOperation: b.pathRoleBoundCIDRListDelete,
|
logical.DeleteOperation: b.pathRoleBoundCIDRListDelete,
|
||||||
},
|
},
|
||||||
HelpSynopsis: strings.TrimSpace(roleHelp["role-bound-cidr-list"][0]),
|
HelpSynopsis: strings.TrimSpace(roleHelp["role-bound-cidr-list"][0]),
|
||||||
HelpDescription: strings.TrimSpace(roleHelp["role-bound-cidr-list"][1]),
|
HelpDescription: strings.TrimSpace(roleHelp["role-bound-cidr-list"][1]),
|
||||||
},
|
},
|
||||||
|
&framework.Path{
|
||||||
|
Pattern: "role/" + framework.GenericNameRegex("role_name") + "/secret-id-bound-cidrs$",
|
||||||
|
Fields: map[string]*framework.FieldSchema{
|
||||||
|
"role_name": &framework.FieldSchema{
|
||||||
|
Type: framework.TypeString,
|
||||||
|
Description: "Name of the role.",
|
||||||
|
},
|
||||||
|
"secret_id_bound_cidrs": &framework.FieldSchema{
|
||||||
|
Type: framework.TypeCommaStringSlice,
|
||||||
|
Description: `Comma separated string or list of CIDR blocks. If set, specifies the blocks of
|
||||||
|
IP addresses which can perform the login operation.`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Callbacks: map[logical.Operation]framework.OperationFunc{
|
||||||
|
logical.UpdateOperation: b.pathRoleBoundCIDRUpdate,
|
||||||
|
logical.ReadOperation: b.pathRoleSecretIDBoundCIDRRead,
|
||||||
|
logical.DeleteOperation: b.pathRoleSecretIDBoundCIDRDelete,
|
||||||
|
},
|
||||||
|
HelpSynopsis: strings.TrimSpace(roleHelp["secret-id-bound-cidrs"][0]),
|
||||||
|
HelpDescription: strings.TrimSpace(roleHelp["secret-id-bound-cidrs"][1]),
|
||||||
|
},
|
||||||
|
&framework.Path{
|
||||||
|
Pattern: "role/" + framework.GenericNameRegex("role_name") + "/token-bound-cidrs$",
|
||||||
|
Fields: map[string]*framework.FieldSchema{
|
||||||
|
"role_name": &framework.FieldSchema{
|
||||||
|
Type: framework.TypeString,
|
||||||
|
Description: "Name of the role.",
|
||||||
|
},
|
||||||
|
"token_bound_cidrs": &framework.FieldSchema{
|
||||||
|
Type: framework.TypeCommaStringSlice,
|
||||||
|
Description: `Comma separated string or list of CIDR blocks. If set, specifies the blocks of
|
||||||
|
IP addresses which can use the returned token.`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Callbacks: map[logical.Operation]framework.OperationFunc{
|
||||||
|
logical.UpdateOperation: b.pathRoleBoundCIDRUpdate,
|
||||||
|
logical.ReadOperation: b.pathRoleTokenBoundCIDRRead,
|
||||||
|
logical.DeleteOperation: b.pathRoleTokenBoundCIDRDelete,
|
||||||
|
},
|
||||||
|
HelpSynopsis: strings.TrimSpace(roleHelp["token-bound-cidrs"][0]),
|
||||||
|
HelpDescription: strings.TrimSpace(roleHelp["token-bound-cidrs"][1]),
|
||||||
|
},
|
||||||
&framework.Path{
|
&framework.Path{
|
||||||
Pattern: "role/" + framework.GenericNameRegex("role_name") + "/bind-secret-id$",
|
Pattern: "role/" + framework.GenericNameRegex("role_name") + "/bind-secret-id$",
|
||||||
Fields: map[string]*framework.FieldSchema{
|
Fields: map[string]*framework.FieldSchema{
|
||||||
@@ -662,6 +724,8 @@ func validateRoleConstraints(role *roleStorageEntry) error {
|
|||||||
switch {
|
switch {
|
||||||
case role.BindSecretID:
|
case role.BindSecretID:
|
||||||
case len(role.BoundCIDRList) != 0:
|
case len(role.BoundCIDRList) != 0:
|
||||||
|
case len(role.SecretIDBoundCIDRs) != 0:
|
||||||
|
case len(role.TokenBoundCIDRs) != 0:
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("at least one constraint should be enabled on the role")
|
return fmt.Errorf("at least one constraint should be enabled on the role")
|
||||||
}
|
}
|
||||||
@@ -749,11 +813,17 @@ func (b *backend) roleEntry(ctx context.Context, s logical.Storage, roleName str
|
|||||||
needsUpgrade := false
|
needsUpgrade := false
|
||||||
|
|
||||||
if role.BoundCIDRListOld != "" {
|
if role.BoundCIDRListOld != "" {
|
||||||
role.BoundCIDRList = strings.Split(role.BoundCIDRListOld, ",")
|
role.SecretIDBoundCIDRs = strutil.ParseDedupAndSortStrings(role.BoundCIDRListOld, ",")
|
||||||
role.BoundCIDRListOld = ""
|
role.BoundCIDRListOld = ""
|
||||||
needsUpgrade = true
|
needsUpgrade = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(role.BoundCIDRList) != 0 {
|
||||||
|
role.SecretIDBoundCIDRs = role.BoundCIDRList
|
||||||
|
role.BoundCIDRList = nil
|
||||||
|
needsUpgrade = true
|
||||||
|
}
|
||||||
|
|
||||||
if role.SecretIDPrefix == "" {
|
if role.SecretIDPrefix == "" {
|
||||||
role.SecretIDPrefix = secretIDPrefix
|
role.SecretIDPrefix = secretIDPrefix
|
||||||
needsUpgrade = true
|
needsUpgrade = true
|
||||||
@@ -847,14 +917,26 @@ func (b *backend) pathRoleCreateUpdate(ctx context.Context, req *logical.Request
|
|||||||
role.BindSecretID = data.Get("bind_secret_id").(bool)
|
role.BindSecretID = data.Get("bind_secret_id").(bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
if boundCIDRListRaw, ok := data.GetOk("bound_cidr_list"); ok {
|
if boundCIDRListRaw, ok := data.GetFirst("secret_id_bound_cidrs", "bound_cidr_list"); ok {
|
||||||
role.BoundCIDRList = boundCIDRListRaw.([]string)
|
role.SecretIDBoundCIDRs = boundCIDRListRaw.([]string)
|
||||||
} else if req.Operation == logical.CreateOperation {
|
|
||||||
role.BoundCIDRList = data.Get("bound_cidr_list").([]string)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(role.BoundCIDRList) != 0 {
|
if len(role.SecretIDBoundCIDRs) != 0 {
|
||||||
valid, err := cidrutil.ValidateCIDRListSlice(role.BoundCIDRList)
|
valid, err := cidrutil.ValidateCIDRListSlice(role.SecretIDBoundCIDRs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errwrap.Wrapf("failed to validate CIDR blocks: {{err}}", err)
|
||||||
|
}
|
||||||
|
if !valid {
|
||||||
|
return logical.ErrorResponse("invalid CIDR blocks"), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if boundCIDRListRaw, ok := data.GetOk("token_bound_cidrs"); ok {
|
||||||
|
role.TokenBoundCIDRs = boundCIDRListRaw.([]string)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(role.TokenBoundCIDRs) != 0 {
|
||||||
|
valid, err := cidrutil.ValidateCIDRListSlice(role.TokenBoundCIDRs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errwrap.Wrapf("failed to validate CIDR blocks: {{err}}", err)
|
return nil, errwrap.Wrapf("failed to validate CIDR blocks: {{err}}", err)
|
||||||
}
|
}
|
||||||
@@ -956,7 +1038,11 @@ func (b *backend) pathRoleRead(ctx context.Context, req *logical.Request, data *
|
|||||||
|
|
||||||
respData := map[string]interface{}{
|
respData := map[string]interface{}{
|
||||||
"bind_secret_id": role.BindSecretID,
|
"bind_secret_id": role.BindSecretID,
|
||||||
"bound_cidr_list": role.BoundCIDRList,
|
// TODO - remove this deprecated field in future versions,
|
||||||
|
// and its associated warning below.
|
||||||
|
"bound_cidr_list": role.SecretIDBoundCIDRs,
|
||||||
|
"secret_id_bound_cidrs": role.SecretIDBoundCIDRs,
|
||||||
|
"token_bound_cidrs": role.TokenBoundCIDRs,
|
||||||
"period": role.Period / time.Second,
|
"period": role.Period / time.Second,
|
||||||
"policies": role.Policies,
|
"policies": role.Policies,
|
||||||
"secret_id_num_uses": role.SecretIDNumUses,
|
"secret_id_num_uses": role.SecretIDNumUses,
|
||||||
@@ -978,6 +1064,7 @@ func (b *backend) pathRoleRead(ctx context.Context, req *logical.Request, data *
|
|||||||
if err := validateRoleConstraints(role); err != nil {
|
if err := validateRoleConstraints(role); err != nil {
|
||||||
resp.AddWarning("Role does not have any constraints set on it. Updates to this role will require a constraint to be set")
|
resp.AddWarning("Role does not have any constraints set on it. Updates to this role will require a constraint to be set")
|
||||||
}
|
}
|
||||||
|
resp.AddWarning(`The "bound_cidr_list" parameter is deprecated and will be removed in favor of "secret_id_bound_cidrs".`)
|
||||||
|
|
||||||
// For sanity, verify that the index still exists. If the index is missing,
|
// For sanity, verify that the index still exists. If the index is missing,
|
||||||
// add one and return a warning so it can be reported.
|
// add one and return a warning so it can be reported.
|
||||||
@@ -1312,7 +1399,7 @@ func (b *backend) pathRoleSecretIDAccessorDestroyUpdateDelete(ctx context.Contex
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *backend) pathRoleBoundCIDRListUpdate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
func (b *backend) pathRoleBoundCIDRUpdate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||||
roleName := data.Get("role_name").(string)
|
roleName := data.Get("role_name").(string)
|
||||||
if roleName == "" {
|
if roleName == "" {
|
||||||
return logical.ErrorResponse("missing role_name"), nil
|
return logical.ErrorResponse("missing role_name"), nil
|
||||||
@@ -1331,12 +1418,18 @@ func (b *backend) pathRoleBoundCIDRListUpdate(ctx context.Context, req *logical.
|
|||||||
return nil, logical.ErrUnsupportedPath
|
return nil, logical.ErrUnsupportedPath
|
||||||
}
|
}
|
||||||
|
|
||||||
role.BoundCIDRList = data.Get("bound_cidr_list").([]string)
|
var cidrs []string
|
||||||
if len(role.BoundCIDRList) == 0 {
|
if cidrsIfc, ok := data.GetFirst("secret_id_bound_cidrs", "bound_cidr_list"); ok {
|
||||||
|
cidrs = cidrsIfc.([]string)
|
||||||
|
role.SecretIDBoundCIDRs = cidrs
|
||||||
|
} else if cidrsIfc, ok := data.GetOk("token_bound_cidrs"); ok {
|
||||||
|
cidrs = cidrsIfc.([]string)
|
||||||
|
role.TokenBoundCIDRs = cidrs
|
||||||
|
}
|
||||||
|
if len(cidrs) == 0 {
|
||||||
return logical.ErrorResponse("missing bound_cidr_list"), nil
|
return logical.ErrorResponse("missing bound_cidr_list"), nil
|
||||||
}
|
}
|
||||||
|
valid, err := cidrutil.ValidateCIDRListSlice(cidrs)
|
||||||
valid, err := cidrutil.ValidateCIDRListSlice(role.BoundCIDRList)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errwrap.Wrapf("failed to validate CIDR blocks: {{err}}", err)
|
return nil, errwrap.Wrapf("failed to validate CIDR blocks: {{err}}", err)
|
||||||
}
|
}
|
||||||
@@ -1347,7 +1440,19 @@ func (b *backend) pathRoleBoundCIDRListUpdate(ctx context.Context, req *logical.
|
|||||||
return nil, b.setRoleEntry(ctx, req.Storage, role.name, role, "")
|
return nil, b.setRoleEntry(ctx, req.Storage, role.name, role, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *backend) pathRoleSecretIDBoundCIDRRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||||
|
return b.pathRoleFieldRead(ctx, req, data, "secret_id_bound_cidrs")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *backend) pathRoleTokenBoundCIDRRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||||
|
return b.pathRoleFieldRead(ctx, req, data, "token_bound_cidrs")
|
||||||
|
}
|
||||||
|
|
||||||
func (b *backend) pathRoleBoundCIDRListRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
func (b *backend) pathRoleBoundCIDRListRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||||
|
return b.pathRoleFieldRead(ctx, req, data, "bound_cidr_list")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *backend) pathRoleFieldRead(ctx context.Context, req *logical.Request, data *framework.FieldData, fieldName string) (*logical.Response, error) {
|
||||||
roleName := data.Get("role_name").(string)
|
roleName := data.Get("role_name").(string)
|
||||||
if roleName == "" {
|
if roleName == "" {
|
||||||
return logical.ErrorResponse("missing role_name"), nil
|
return logical.ErrorResponse("missing role_name"), nil
|
||||||
@@ -1363,16 +1468,36 @@ func (b *backend) pathRoleBoundCIDRListRead(ctx context.Context, req *logical.Re
|
|||||||
}
|
}
|
||||||
if role == nil {
|
if role == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
} else {
|
||||||
|
switch fieldName {
|
||||||
|
case "secret_id_bound_cidrs":
|
||||||
return &logical.Response{
|
return &logical.Response{
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"secret_id_bound_cidrs": role.SecretIDBoundCIDRs,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
case "token_bound_cidrs":
|
||||||
|
return &logical.Response{
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"token_bound_cidrs": role.TokenBoundCIDRs,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
case "bound_cidr_list":
|
||||||
|
resp := &logical.Response{
|
||||||
Data: map[string]interface{}{
|
Data: map[string]interface{}{
|
||||||
"bound_cidr_list": role.BoundCIDRList,
|
"bound_cidr_list": role.BoundCIDRList,
|
||||||
},
|
},
|
||||||
}, nil
|
}
|
||||||
|
resp.AddWarning(`The "bound_cidr_list" parameter is deprecated and will be removed. Please use "secret_id_bound_cidrs" instead.`)
|
||||||
|
return resp, nil
|
||||||
|
default:
|
||||||
|
// shouldn't occur IRL
|
||||||
|
return nil, errors.New("unrecognized field provided: " + fieldName)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *backend) pathRoleBoundCIDRListDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
func (b *backend) pathRoleBoundCIDRDelete(ctx context.Context, req *logical.Request, data *framework.FieldData, fieldName string) (*logical.Response, error) {
|
||||||
roleName := data.Get("role_name").(string)
|
roleName := data.Get("role_name").(string)
|
||||||
if roleName == "" {
|
if roleName == "" {
|
||||||
return logical.ErrorResponse("missing role_name"), nil
|
return logical.ErrorResponse("missing role_name"), nil
|
||||||
@@ -1391,9 +1516,27 @@ func (b *backend) pathRoleBoundCIDRListDelete(ctx context.Context, req *logical.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Deleting a field implies setting the value to it's default value.
|
// Deleting a field implies setting the value to it's default value.
|
||||||
|
switch fieldName {
|
||||||
|
case "bound_cidr_list":
|
||||||
role.BoundCIDRList = data.GetDefaultOrZero("bound_cidr_list").([]string)
|
role.BoundCIDRList = data.GetDefaultOrZero("bound_cidr_list").([]string)
|
||||||
|
case "secret_id_bound_cidrs":
|
||||||
|
role.SecretIDBoundCIDRs = data.GetDefaultOrZero("secret_id_bound_cidrs").([]string)
|
||||||
|
case "token_bound_cidrs":
|
||||||
|
role.TokenBoundCIDRs = data.GetDefaultOrZero("token_bound_cidrs").([]string)
|
||||||
|
}
|
||||||
|
return nil, b.setRoleEntry(ctx, req.Storage, roleName, role, "")
|
||||||
|
}
|
||||||
|
|
||||||
return nil, b.setRoleEntry(ctx, req.Storage, role.name, role, "")
|
func (b *backend) pathRoleBoundCIDRListDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||||
|
return b.pathRoleBoundCIDRDelete(ctx, req, data, "bound_cidr_list")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *backend) pathRoleSecretIDBoundCIDRDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||||
|
return b.pathRoleBoundCIDRDelete(ctx, req, data, "secret_id_bound_cidrs")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *backend) pathRoleTokenBoundCIDRDelete(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||||
|
return b.pathRoleBoundCIDRDelete(ctx, req, data, "token_bound_cidrs")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *backend) pathRoleBindSecretIDUpdate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
func (b *backend) pathRoleBindSecretIDUpdate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||||
@@ -2137,7 +2280,7 @@ func (b *backend) handleRoleSecretIDCommon(ctx context.Context, req *logical.Req
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that the CIDRs on the secret ID are a subset of that of role's
|
// Ensure that the CIDRs on the secret ID are a subset of that of role's
|
||||||
if err := verifyCIDRRoleSecretIDSubset(secretIDCIDRs, role.BoundCIDRList); err != nil {
|
if err := verifyCIDRRoleSecretIDSubset(secretIDCIDRs, role.SecretIDBoundCIDRs); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2266,11 +2409,25 @@ configured using the parameters of this endpoint.`,
|
|||||||
The value of 'secret_id' can be retrieved using 'role/<role_name>/secret-id' endpoint.`,
|
The value of 'secret_id' can be retrieved using 'role/<role_name>/secret-id' endpoint.`,
|
||||||
},
|
},
|
||||||
"role-bound-cidr-list": {
|
"role-bound-cidr-list": {
|
||||||
|
`Deprecated: Comma separated list of CIDR blocks, if set, specifies blocks of IP
|
||||||
|
addresses which can perform the login operation`,
|
||||||
|
`During login, the IP address of the client will be checked to see if it
|
||||||
|
belongs to the CIDR blocks specified. If CIDR blocks were set and if the
|
||||||
|
IP is not encompassed by it, login fails`,
|
||||||
|
},
|
||||||
|
"secret-id-bound-cidrs": {
|
||||||
`Comma separated list of CIDR blocks, if set, specifies blocks of IP
|
`Comma separated list of CIDR blocks, if set, specifies blocks of IP
|
||||||
addresses which can perform the login operation`,
|
addresses which can perform the login operation`,
|
||||||
`During login, the IP address of the client will be checked to see if it
|
`During login, the IP address of the client will be checked to see if it
|
||||||
belongs to the CIDR blocks specified. If CIDR blocks were set and if the
|
belongs to the CIDR blocks specified. If CIDR blocks were set and if the
|
||||||
IP is not encompassed by it, login fails`,
|
IP is not encompassed by it, login fails`,
|
||||||
|
},
|
||||||
|
"token-bound-cidrs": {
|
||||||
|
`Comma separated string or list of CIDR blocks. If set, specifies the blocks of
|
||||||
|
IP addresses which can use the returned token.`,
|
||||||
|
`During use of the returned token, the IP address of the client will be checked to see if it
|
||||||
|
belongs to the CIDR blocks specified. If CIDR blocks were set and if the
|
||||||
|
IP is not encompassed by it, token use fails`,
|
||||||
},
|
},
|
||||||
"role-policies": {
|
"role-policies": {
|
||||||
"Policies of the role.",
|
"Policies of the role.",
|
||||||
|
|||||||
@@ -243,10 +243,10 @@ func TestAppRole_UpgradeBoundCIDRList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expected := []string{"127.0.0.1/18", "192.178.1.2/24"}
|
expected := []string{"127.0.0.1/18", "192.178.1.2/24"}
|
||||||
actual := resp.Data["bound_cidr_list"].([]string)
|
actual := resp.Data["secret_id_bound_cidrs"].([]string)
|
||||||
|
|
||||||
if !reflect.DeepEqual(expected, actual) {
|
if !reflect.DeepEqual(expected, actual) {
|
||||||
t.Fatalf("bad: bound_cidr_list; expected: %#v\nactual: %#v\n", expected, actual)
|
t.Fatalf("bad: secret_id_bound_cidrs; expected: %#v\nactual: %#v\n", expected, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modify the storage entry of the role to hold the old style string typed bound_cidr_list
|
// Modify the storage entry of the role to hold the old style string typed bound_cidr_list
|
||||||
@@ -519,7 +519,7 @@ func TestAppRole_RoleReadSetIndex(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if the warning is being returned
|
// Check if the warning is being returned
|
||||||
if !strings.Contains(resp.Warnings[0], "Role identifier was missing an index back to role name.") {
|
if !strings.Contains(resp.Warnings[1], "Role identifier was missing an index back to role name.") {
|
||||||
t.Fatalf("bad: expected a warning in the response")
|
t.Fatalf("bad: expected a warning in the response")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1128,7 +1128,7 @@ func TestAppRole_RoleCRUD(t *testing.T) {
|
|||||||
"token_ttl": 400,
|
"token_ttl": 400,
|
||||||
"token_max_ttl": 500,
|
"token_max_ttl": 500,
|
||||||
"token_num_uses": 600,
|
"token_num_uses": 600,
|
||||||
"bound_cidr_list": "127.0.0.1/32,127.0.0.1/16",
|
"secret_id_bound_cidrs": "127.0.0.1/32,127.0.0.1/16",
|
||||||
}
|
}
|
||||||
roleReq := &logical.Request{
|
roleReq := &logical.Request{
|
||||||
Operation: logical.CreateOperation,
|
Operation: logical.CreateOperation,
|
||||||
@@ -1156,7 +1156,9 @@ func TestAppRole_RoleCRUD(t *testing.T) {
|
|||||||
"token_ttl": 400,
|
"token_ttl": 400,
|
||||||
"token_max_ttl": 500,
|
"token_max_ttl": 500,
|
||||||
"token_num_uses": 600,
|
"token_num_uses": 600,
|
||||||
"bound_cidr_list": []string{"127.0.0.1/32", "127.0.0.1/16"},
|
"secret_id_bound_cidrs": []string{"127.0.0.1/32", "127.0.0.1/16"},
|
||||||
|
"bound_cidr_list": []string{"127.0.0.1/32", "127.0.0.1/16"}, // returned for backwards compatibility
|
||||||
|
"token_bound_cidrs": []string{},
|
||||||
}
|
}
|
||||||
|
|
||||||
var expectedStruct roleStorageEntry
|
var expectedStruct roleStorageEntry
|
||||||
@@ -1591,6 +1593,221 @@ func TestAppRole_RoleCRUD(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAppRole_RoleWithTokenBoundCIDRsCRUD(t *testing.T) {
|
||||||
|
var resp *logical.Response
|
||||||
|
var err error
|
||||||
|
b, storage := createBackendWithStorage(t)
|
||||||
|
|
||||||
|
roleData := map[string]interface{}{
|
||||||
|
"policies": "p,q,r,s",
|
||||||
|
"secret_id_num_uses": 10,
|
||||||
|
"secret_id_ttl": 300,
|
||||||
|
"token_ttl": 400,
|
||||||
|
"token_max_ttl": 500,
|
||||||
|
"token_num_uses": 600,
|
||||||
|
"secret_id_bound_cidrs": "127.0.0.1/32,127.0.0.1/16",
|
||||||
|
"token_bound_cidrs": "127.0.0.1/32,127.0.0.1/16",
|
||||||
|
}
|
||||||
|
roleReq := &logical.Request{
|
||||||
|
Operation: logical.CreateOperation,
|
||||||
|
Path: "role/role1",
|
||||||
|
Storage: storage,
|
||||||
|
Data: roleData,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err = b.HandleRequest(context.Background(), roleReq)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
roleReq.Operation = logical.ReadOperation
|
||||||
|
resp, err = b.HandleRequest(context.Background(), roleReq)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[string]interface{}{
|
||||||
|
"bind_secret_id": true,
|
||||||
|
"policies": []string{"p", "q", "r", "s"},
|
||||||
|
"secret_id_num_uses": 10,
|
||||||
|
"secret_id_ttl": 300,
|
||||||
|
"token_ttl": 400,
|
||||||
|
"token_max_ttl": 500,
|
||||||
|
"token_num_uses": 600,
|
||||||
|
"token_bound_cidrs": []string{"127.0.0.1/32", "127.0.0.1/16"},
|
||||||
|
"secret_id_bound_cidrs": []string{"127.0.0.1/32", "127.0.0.1/16"},
|
||||||
|
"bound_cidr_list": []string{"127.0.0.1/32", "127.0.0.1/16"}, // provided for backwards compatibility
|
||||||
|
}
|
||||||
|
|
||||||
|
var expectedStruct roleStorageEntry
|
||||||
|
err = mapstructure.Decode(expected, &expectedStruct)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var actualStruct roleStorageEntry
|
||||||
|
err = mapstructure.Decode(resp.Data, &actualStruct)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedStruct.RoleID = actualStruct.RoleID
|
||||||
|
if !reflect.DeepEqual(expectedStruct, actualStruct) {
|
||||||
|
t.Fatalf("bad:\nexpected:%#v\nactual:%#v\n", expectedStruct, actualStruct)
|
||||||
|
}
|
||||||
|
|
||||||
|
roleData = map[string]interface{}{
|
||||||
|
"role_id": "test_role_id",
|
||||||
|
"policies": "a,b,c,d",
|
||||||
|
"secret_id_num_uses": 100,
|
||||||
|
"secret_id_ttl": 3000,
|
||||||
|
"token_ttl": 4000,
|
||||||
|
"token_max_ttl": 5000,
|
||||||
|
}
|
||||||
|
roleReq.Data = roleData
|
||||||
|
roleReq.Operation = logical.UpdateOperation
|
||||||
|
|
||||||
|
resp, err = b.HandleRequest(context.Background(), roleReq)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
roleReq.Operation = logical.ReadOperation
|
||||||
|
resp, err = b.HandleRequest(context.Background(), roleReq)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
expected = map[string]interface{}{
|
||||||
|
"policies": []string{"a", "b", "c", "d"},
|
||||||
|
"secret_id_num_uses": 100,
|
||||||
|
"secret_id_ttl": 3000,
|
||||||
|
"token_ttl": 4000,
|
||||||
|
"token_max_ttl": 5000,
|
||||||
|
}
|
||||||
|
err = mapstructure.Decode(expected, &expectedStruct)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = mapstructure.Decode(resp.Data, &actualStruct)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(expectedStruct, actualStruct) {
|
||||||
|
t.Fatalf("bad:\nexpected:%#v\nactual:%#v\n", expectedStruct, actualStruct)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RUD for secret-id-bound-cidrs field
|
||||||
|
roleReq.Path = "role/role1/secret-id-bound-cidrs"
|
||||||
|
roleReq.Operation = logical.ReadOperation
|
||||||
|
resp, err = b.HandleRequest(context.Background(), roleReq)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||||
|
}
|
||||||
|
if resp.Data["secret_id_bound_cidrs"].([]string)[0] != "127.0.0.1/32" ||
|
||||||
|
resp.Data["secret_id_bound_cidrs"].([]string)[1] != "127.0.0.1/16" {
|
||||||
|
t.Fatalf("bad: secret_id_bound_cidrs: expected:127.0.0.1/32,127.0.0.1/16 actual:%d\n", resp.Data["secret_id_bound_cidrs"].(int))
|
||||||
|
}
|
||||||
|
|
||||||
|
roleReq.Data = map[string]interface{}{"secret_id_bound_cidrs": []string{"127.0.0.1/20"}}
|
||||||
|
roleReq.Operation = logical.UpdateOperation
|
||||||
|
resp, err = b.HandleRequest(context.Background(), roleReq)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
roleReq.Operation = logical.ReadOperation
|
||||||
|
resp, err = b.HandleRequest(context.Background(), roleReq)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.Data["secret_id_bound_cidrs"].([]string)[0] != "127.0.0.1/20" {
|
||||||
|
t.Fatalf("bad: secret_id_bound_cidrs: expected:127.0.0.1/20 actual:%s\n", resp.Data["secret_id_bound_cidrs"].([]string)[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
roleReq.Operation = logical.DeleteOperation
|
||||||
|
resp, err = b.HandleRequest(context.Background(), roleReq)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
roleReq.Operation = logical.ReadOperation
|
||||||
|
resp, err = b.HandleRequest(context.Background(), roleReq)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(resp.Data["secret_id_bound_cidrs"].([]string)) != 0 {
|
||||||
|
t.Fatalf("expected value to be reset")
|
||||||
|
}
|
||||||
|
|
||||||
|
// RUD for token-bound-cidrs field
|
||||||
|
roleReq.Path = "role/role1/token-bound-cidrs"
|
||||||
|
roleReq.Operation = logical.ReadOperation
|
||||||
|
resp, err = b.HandleRequest(context.Background(), roleReq)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||||
|
}
|
||||||
|
if resp.Data["token_bound_cidrs"].([]string)[0] != "127.0.0.1/32" ||
|
||||||
|
resp.Data["token_bound_cidrs"].([]string)[1] != "127.0.0.1/16" {
|
||||||
|
t.Fatalf("bad: token_bound_cidrs: expected:127.0.0.1/32,127.0.0.1/16 actual:%d\n", resp.Data["token_bound_cidrs"].(int))
|
||||||
|
}
|
||||||
|
|
||||||
|
roleReq.Data = map[string]interface{}{"token_bound_cidrs": []string{"127.0.0.1/20"}}
|
||||||
|
roleReq.Operation = logical.UpdateOperation
|
||||||
|
resp, err = b.HandleRequest(context.Background(), roleReq)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
roleReq.Operation = logical.ReadOperation
|
||||||
|
resp, err = b.HandleRequest(context.Background(), roleReq)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.Data["token_bound_cidrs"].([]string)[0] != "127.0.0.1/20" {
|
||||||
|
t.Fatalf("bad: token_bound_cidrs: expected:127.0.0.1/20 actual:%s\n", resp.Data["token_bound_cidrs"].([]string)[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
roleReq.Operation = logical.DeleteOperation
|
||||||
|
resp, err = b.HandleRequest(context.Background(), roleReq)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
roleReq.Operation = logical.ReadOperation
|
||||||
|
resp, err = b.HandleRequest(context.Background(), roleReq)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(resp.Data["token_bound_cidrs"].([]string)) != 0 {
|
||||||
|
t.Fatalf("expected value to be reset")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete test for role
|
||||||
|
roleReq.Path = "role/role1"
|
||||||
|
roleReq.Operation = logical.DeleteOperation
|
||||||
|
resp, err = b.HandleRequest(context.Background(), roleReq)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
roleReq.Operation = logical.ReadOperation
|
||||||
|
resp, err = b.HandleRequest(context.Background(), roleReq)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp != nil {
|
||||||
|
t.Fatalf("expected a nil response")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func createRole(t *testing.T, b *backend, s logical.Storage, roleName, policies string) {
|
func createRole(t *testing.T, b *backend, s logical.Storage, roleName, policies string) {
|
||||||
roleData := map[string]interface{}{
|
roleData := map[string]interface{}{
|
||||||
"policies": policies,
|
"policies": policies,
|
||||||
|
|||||||
@@ -80,6 +80,19 @@ func (d *FieldData) GetDefaultOrZero(k string) interface{} {
|
|||||||
return schema.DefaultOrZero()
|
return schema.DefaultOrZero()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetFirst gets the value for the given field names, in order from first
|
||||||
|
// to last. This can be useful for fields with a current name, and one or
|
||||||
|
// more deprecated names. The second return value will be false if the keys
|
||||||
|
// are invalid or the keys are not set at all.
|
||||||
|
func (d *FieldData) GetFirst(k ...string) (interface{}, bool) {
|
||||||
|
for _, v := range k {
|
||||||
|
if result, ok := d.GetOk(v); ok {
|
||||||
|
return result, ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
// GetOk gets the value for the given field. The second return value
|
// GetOk gets the value for the given field. The second return value
|
||||||
// will be false if the key is invalid or the key is not set at all.
|
// will be false if the key is invalid or the key is not set at all.
|
||||||
func (d *FieldData) GetOk(k string) (interface{}, bool) {
|
func (d *FieldData) GetOk(k string) (interface{}, bool) {
|
||||||
|
|||||||
@@ -642,3 +642,37 @@ func TestFieldDataGet_Error(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFieldDataGetFirst(t *testing.T) {
|
||||||
|
data := &FieldData{
|
||||||
|
Raw: map[string]interface{}{
|
||||||
|
"foo": "bar",
|
||||||
|
"fizz": "buzz",
|
||||||
|
},
|
||||||
|
Schema: map[string]*FieldSchema{
|
||||||
|
"foo": {Type: TypeNameString},
|
||||||
|
"fizz": {Type: TypeNameString},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result, ok := data.GetFirst("foo", "fizz")
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("should have found value for foo")
|
||||||
|
}
|
||||||
|
if result.(string) != "bar" {
|
||||||
|
t.Fatal("should have gotten bar for foo")
|
||||||
|
}
|
||||||
|
|
||||||
|
result, ok = data.GetFirst("fizz", "foo")
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("should have found value for fizz")
|
||||||
|
}
|
||||||
|
if result.(string) != "buzz" {
|
||||||
|
t.Fatal("should have gotten buzz for fizz")
|
||||||
|
}
|
||||||
|
|
||||||
|
result, ok = data.GetFirst("cats")
|
||||||
|
if ok {
|
||||||
|
t.Fatal("shouldn't have gotten anything for cats")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -69,9 +69,12 @@ enabled while creating or updating a role.
|
|||||||
- `role_name` `(string: <required>)` - Name of the AppRole.
|
- `role_name` `(string: <required>)` - Name of the AppRole.
|
||||||
- `bind_secret_id` `(bool: true)` - Require `secret_id` to be presented when
|
- `bind_secret_id` `(bool: true)` - Require `secret_id` to be presented when
|
||||||
logging in using this AppRole.
|
logging in using this AppRole.
|
||||||
- `bound_cidr_list` `(array: [])` - Comma-separated string or list of CIDR
|
- `secret_id_bound_cidrs` `(array: [])` - Comma-separated string or list of CIDR
|
||||||
blocks; if set, specifies blocks of IP addresses which can perform the login
|
blocks; if set, specifies blocks of IP addresses which can perform the login
|
||||||
operation.
|
operation.
|
||||||
|
- `token_bound_cidrs` `(array: [])` - Comma-separated string or list of CIDR
|
||||||
|
blocks; if set, specifies blocks of IP addresses which can use the auth tokens
|
||||||
|
generated by this role.
|
||||||
- `policies` `(array: [])` - Comma-separated list of policies set on tokens
|
- `policies` `(array: [])` - Comma-separated list of policies set on tokens
|
||||||
issued via this AppRole.
|
issued via this AppRole.
|
||||||
- `secret_id_num_uses` `(integer: 0)` - Number of times any particular SecretID
|
- `secret_id_num_uses` `(integer: 0)` - Number of times any particular SecretID
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ credentials for login. The `bind_secret_id` constraint requires `secret_id` to
|
|||||||
be presented at the login endpoint. Going forward, this auth method can support
|
be presented at the login endpoint. Going forward, this auth method can support
|
||||||
more constraint parameters to support varied set of Apps. Some constraints will
|
more constraint parameters to support varied set of Apps. Some constraints will
|
||||||
not require a credential, but still enforce constraints for login. For
|
not require a credential, but still enforce constraints for login. For
|
||||||
example, `bound_cidr_list` will only allow requests coming from IP addresses
|
example, `secret_id_bound_cidrs` will only allow logins coming from IP addresses
|
||||||
belonging to configured CIDR blocks on the AppRole.
|
belonging to configured CIDR blocks on the AppRole.
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|||||||
Reference in New Issue
Block a user