mirror of
https://github.com/hashicorp/vault.git
synced 2026-02-03 23:11:11 +01:00
Update jwt to pull in groups claim delimiter pattern
This commit is contained in:
parent
b2ead22689
commit
cb58182900
8
vendor/github.com/hashicorp/vault-plugin-auth-jwt/path_config.go
generated
vendored
8
vendor/github.com/hashicorp/vault-plugin-auth-jwt/path_config.go
generated
vendored
@ -21,19 +21,19 @@ func pathConfig(b *jwtAuthBackend) *framework.Path {
|
||||
return &framework.Path{
|
||||
Pattern: `config`,
|
||||
Fields: map[string]*framework.FieldSchema{
|
||||
"oidc_discovery_url": &framework.FieldSchema{
|
||||
"oidc_discovery_url": {
|
||||
Type: framework.TypeString,
|
||||
Description: `OIDC Discovery URL, without any .well-known component (base path). Cannot be used with "jwt_validation_pubkeys".`,
|
||||
},
|
||||
"oidc_discovery_ca_pem": &framework.FieldSchema{
|
||||
"oidc_discovery_ca_pem": {
|
||||
Type: framework.TypeString,
|
||||
Description: "The CA certificate or chain of certificates, in PEM format, to use to validate conections to the OIDC Discovery URL. If not set, system certificates are used.",
|
||||
},
|
||||
"jwt_validation_pubkeys": &framework.FieldSchema{
|
||||
"jwt_validation_pubkeys": {
|
||||
Type: framework.TypeCommaStringSlice,
|
||||
Description: `A list of PEM-encoded public keys to use to authenticate signatures locally. Cannot be used with "oidc_discovery_url".`,
|
||||
},
|
||||
"bound_issuer": &framework.FieldSchema{
|
||||
"bound_issuer": {
|
||||
Type: framework.TypeString,
|
||||
Description: "The value against which to match the 'iss' claim in a JWT. Optional.",
|
||||
},
|
||||
|
||||
31
vendor/github.com/hashicorp/vault-plugin-auth-jwt/path_login.go
generated
vendored
31
vendor/github.com/hashicorp/vault-plugin-auth-jwt/path_login.go
generated
vendored
@ -19,11 +19,11 @@ func pathLogin(b *jwtAuthBackend) *framework.Path {
|
||||
return &framework.Path{
|
||||
Pattern: `login$`,
|
||||
Fields: map[string]*framework.FieldSchema{
|
||||
"role": &framework.FieldSchema{
|
||||
"role": {
|
||||
Type: framework.TypeLowerCaseString,
|
||||
Description: "The role to log in against.",
|
||||
},
|
||||
"jwt": &framework.FieldSchema{
|
||||
"jwt": {
|
||||
Type: framework.TypeString,
|
||||
Description: "The signed JWT to validate.",
|
||||
},
|
||||
@ -179,7 +179,32 @@ func (b *jwtAuthBackend) pathLogin(ctx context.Context, req *logical.Request, d
|
||||
|
||||
var groupAliases []*logical.Alias
|
||||
if role.GroupsClaim != "" {
|
||||
groupsClaimRaw, ok := allClaims[role.GroupsClaim]
|
||||
mapPath, err := parseClaimWithDelimiters(role.GroupsClaim, role.GroupsClaimDelimiterPattern)
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(errwrap.Wrapf("error parsing delimiters for groups claim: {{err}}", err).Error()), nil
|
||||
}
|
||||
if len(mapPath) < 1 {
|
||||
return logical.ErrorResponse("unexpected length 0 of claims path after parsing groups claim against delimiters"), nil
|
||||
}
|
||||
var claimKey string
|
||||
claimMap := allClaims
|
||||
for i, key := range mapPath {
|
||||
if i == len(mapPath)-1 {
|
||||
claimKey = key
|
||||
break
|
||||
}
|
||||
nextMapRaw, ok := claimMap[key]
|
||||
if !ok {
|
||||
return logical.ErrorResponse(fmt.Sprintf("map via key %q not found while navigating group claim delimiters", key)), nil
|
||||
}
|
||||
nextMap, ok := nextMapRaw.(map[string]interface{})
|
||||
if !ok {
|
||||
return logical.ErrorResponse(fmt.Sprintf("key %q does not reference a map while navigating group claim delimiters", key)), nil
|
||||
}
|
||||
claimMap = nextMap
|
||||
}
|
||||
|
||||
groupsClaimRaw, ok := claimMap[claimKey]
|
||||
if !ok {
|
||||
return logical.ErrorResponse(fmt.Sprintf("%q claim not found in token", role.GroupsClaim)), nil
|
||||
}
|
||||
|
||||
96
vendor/github.com/hashicorp/vault-plugin-auth-jwt/path_role.go
generated
vendored
96
vendor/github.com/hashicorp/vault-plugin-auth-jwt/path_role.go
generated
vendored
@ -7,6 +7,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
sockaddr "github.com/hashicorp/go-sockaddr"
|
||||
"github.com/hashicorp/vault/helper/parseutil"
|
||||
"github.com/hashicorp/vault/helper/policyutil"
|
||||
@ -30,52 +31,56 @@ func pathRole(b *jwtAuthBackend) *framework.Path {
|
||||
return &framework.Path{
|
||||
Pattern: "role/" + framework.GenericNameRegex("name"),
|
||||
Fields: map[string]*framework.FieldSchema{
|
||||
"name": &framework.FieldSchema{
|
||||
"name": {
|
||||
Type: framework.TypeLowerCaseString,
|
||||
Description: "Name of the role.",
|
||||
},
|
||||
"policies": &framework.FieldSchema{
|
||||
"policies": {
|
||||
Type: framework.TypeCommaStringSlice,
|
||||
Description: "List of policies on the role.",
|
||||
},
|
||||
"num_uses": &framework.FieldSchema{
|
||||
"num_uses": {
|
||||
Type: framework.TypeInt,
|
||||
Description: `Number of times issued tokens can be used`,
|
||||
},
|
||||
"ttl": &framework.FieldSchema{
|
||||
"ttl": {
|
||||
Type: framework.TypeDurationSecond,
|
||||
Description: `Duration in seconds after which the issued token should expire. Defaults
|
||||
to 0, in which case the value will fall back to the system/mount defaults.`,
|
||||
},
|
||||
"max_ttl": &framework.FieldSchema{
|
||||
"max_ttl": {
|
||||
Type: framework.TypeDurationSecond,
|
||||
Description: `Duration in seconds after which the issued token should not be allowed to
|
||||
be renewed. Defaults to 0, in which case the value will fall back to the system/mount defaults.`,
|
||||
},
|
||||
"period": &framework.FieldSchema{
|
||||
"period": {
|
||||
Type: framework.TypeDurationSecond,
|
||||
Description: `If set, indicates that the token generated using this role
|
||||
should never expire. The token should be renewed within the
|
||||
duration specified by this value. At each renewal, the token's
|
||||
TTL will be set to the value of this parameter.`,
|
||||
},
|
||||
"bound_subject": &framework.FieldSchema{
|
||||
"bound_subject": {
|
||||
Type: framework.TypeString,
|
||||
Description: `The 'sub' claim that is valid for login. Optional.`,
|
||||
},
|
||||
"bound_audiences": &framework.FieldSchema{
|
||||
"bound_audiences": {
|
||||
Type: framework.TypeCommaStringSlice,
|
||||
Description: `Comma-separated list of 'aud' claims that are valid for login; any match is sufficient`,
|
||||
},
|
||||
"user_claim": &framework.FieldSchema{
|
||||
"user_claim": {
|
||||
Type: framework.TypeString,
|
||||
Description: `The claim to use for the Identity entity alias name`,
|
||||
},
|
||||
"groups_claim": &framework.FieldSchema{
|
||||
"groups_claim": {
|
||||
Type: framework.TypeString,
|
||||
Description: `The claim to use for the Identity group alias names`,
|
||||
},
|
||||
"bound_cidrs": &framework.FieldSchema{
|
||||
"groups_claim_delimiter_pattern": {
|
||||
Type: framework.TypeString,
|
||||
Description: `A pattern of delimiters used to allow the groups_claim to live outside of the top-level JWT structure. For instance, a "groups_claim" of "meta/user.name/groups" with this field set to "//" will expect nested structures named "meta", "user.name", and "groups". If this field was set to "/./" the groups information would expect to be via nested structures of "meta", "user", "name", and "groups".`,
|
||||
},
|
||||
"bound_cidrs": {
|
||||
Type: framework.TypeCommaStringSlice,
|
||||
Description: `Comma-separated list of IP CIDRS that are allowed to
|
||||
authenticate against this role`,
|
||||
@ -114,11 +119,12 @@ type jwtRole struct {
|
||||
Period time.Duration `json:"period"`
|
||||
|
||||
// Role binding properties
|
||||
BoundAudiences []string `json:"bound_audiences"`
|
||||
BoundSubject string `json:"bound_subject"`
|
||||
BoundCIDRs []*sockaddr.SockAddrMarshaler `json:"bound_cidrs"`
|
||||
UserClaim string `json:"user_claim"`
|
||||
GroupsClaim string `json:"groups_claim"`
|
||||
BoundAudiences []string `json:"bound_audiences"`
|
||||
BoundSubject string `json:"bound_subject"`
|
||||
BoundCIDRs []*sockaddr.SockAddrMarshaler `json:"bound_cidrs"`
|
||||
UserClaim string `json:"user_claim"`
|
||||
GroupsClaim string `json:"groups_claim"`
|
||||
GroupsClaimDelimiterPattern string `json:"groups_claim_delimiter_pattern"`
|
||||
}
|
||||
|
||||
// role takes a storage backend and the name and returns the role's storage
|
||||
@ -176,16 +182,17 @@ func (b *jwtAuthBackend) pathRoleRead(ctx context.Context, req *logical.Request,
|
||||
// Create a map of data to be returned
|
||||
resp := &logical.Response{
|
||||
Data: map[string]interface{}{
|
||||
"policies": role.Policies,
|
||||
"num_uses": role.NumUses,
|
||||
"period": int64(role.Period.Seconds()),
|
||||
"ttl": int64(role.TTL.Seconds()),
|
||||
"max_ttl": int64(role.MaxTTL.Seconds()),
|
||||
"bound_audiences": role.BoundAudiences,
|
||||
"bound_subject": role.BoundSubject,
|
||||
"bound_cidrs": role.BoundCIDRs,
|
||||
"user_claim": role.UserClaim,
|
||||
"groups_claim": role.GroupsClaim,
|
||||
"policies": role.Policies,
|
||||
"num_uses": role.NumUses,
|
||||
"period": int64(role.Period.Seconds()),
|
||||
"ttl": int64(role.TTL.Seconds()),
|
||||
"max_ttl": int64(role.MaxTTL.Seconds()),
|
||||
"bound_audiences": role.BoundAudiences,
|
||||
"bound_subject": role.BoundSubject,
|
||||
"bound_cidrs": role.BoundCIDRs,
|
||||
"user_claim": role.UserClaim,
|
||||
"groups_claim": role.GroupsClaim,
|
||||
"groups_claim_delimiter_pattern": role.GroupsClaimDelimiterPattern,
|
||||
},
|
||||
}
|
||||
|
||||
@ -291,6 +298,17 @@ func (b *jwtAuthBackend) pathRoleCreateUpdate(ctx context.Context, req *logical.
|
||||
role.GroupsClaim = groupsClaim.(string)
|
||||
}
|
||||
|
||||
if groupsClaimDelimiterPattern, ok := data.GetOk("groups_claim_delimiter_pattern"); ok {
|
||||
role.GroupsClaimDelimiterPattern = groupsClaimDelimiterPattern.(string)
|
||||
}
|
||||
|
||||
// Validate claim/delims
|
||||
if role.GroupsClaim != "" {
|
||||
if _, err := parseClaimWithDelimiters(role.GroupsClaim, role.GroupsClaimDelimiterPattern); err != nil {
|
||||
return logical.ErrorResponse(errwrap.Wrapf("error validating delimiters for groups claim: {{err}}", err).Error()), nil
|
||||
}
|
||||
}
|
||||
|
||||
if len(role.BoundAudiences) == 0 &&
|
||||
len(role.BoundCIDRs) == 0 &&
|
||||
role.BoundSubject == "" {
|
||||
@ -322,6 +340,32 @@ func (b *jwtAuthBackend) pathRoleCreateUpdate(ctx context.Context, req *logical.
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// parseClaimWithDelimiters parses a given claim string and ensures that we can
|
||||
// separate it out into a "map path"
|
||||
func parseClaimWithDelimiters(claim, delimiters string) ([]string, error) {
|
||||
if delimiters == "" {
|
||||
return []string{claim}, nil
|
||||
}
|
||||
var ret []string
|
||||
for _, runeVal := range delimiters {
|
||||
idx := strings.IndexRune(claim, runeVal)
|
||||
switch idx {
|
||||
case -1:
|
||||
return nil, fmt.Errorf("could not find instance of %q delimiter in claim", string(runeVal))
|
||||
case 0:
|
||||
return nil, fmt.Errorf("instance of %q delimiter in claim is at beginning of claim string", string(runeVal))
|
||||
case len(claim) - 1:
|
||||
return nil, fmt.Errorf("instance of %q delimiter in claim is at end of claim string", string(runeVal))
|
||||
default:
|
||||
ret = append(ret, claim[:idx])
|
||||
claim = claim[idx+1:]
|
||||
}
|
||||
}
|
||||
ret = append(ret, claim)
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// roleStorageEntry stores all the options that are set on an role
|
||||
var roleHelp = map[string][2]string{
|
||||
"role-list": {
|
||||
|
||||
6
vendor/vendor.json
vendored
6
vendor/vendor.json
vendored
@ -1431,10 +1431,10 @@
|
||||
"revisionTime": "2018-10-12T20:41:23Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "nfHZ5lzZ2BUM97WnQ7acdnSEPQo=",
|
||||
"checksumSHA1": "tt3FtyjXgdBI9Mb43UL4LtOZmAk=",
|
||||
"path": "github.com/hashicorp/vault-plugin-auth-jwt",
|
||||
"revision": "bf8970c9734c5d1e9fbab23255456c8272ff354a",
|
||||
"revisionTime": "2018-10-15T15:58:27Z"
|
||||
"revision": "f428c77917331c1b87dae2dd37016bd1dd4c55da",
|
||||
"revisionTime": "2018-10-31T19:59:42Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "hrJZzU9iG2ixRu2hOdPgN7wa48c=",
|
||||
|
||||
@ -122,6 +122,13 @@ entities attempting to login. At least one of the bound values must be set.
|
||||
the set of groups to which the user belongs; this will be used as the names
|
||||
for the Identity group aliases created due to a successful login. The claim
|
||||
value must be a list of strings.
|
||||
- `groups_claim_delimiter_pattern` `(string: optional)` - A pattern of
|
||||
delimiters used to allow the `groups_claim` to live outside of the top-level
|
||||
JWT structure. For instance, a `groups_claim` of `meta/user.name/groups` with
|
||||
this field set to `//` will expect nested structures named `meta`,
|
||||
`user.name`, and `groups`. If this field was set to `/./` the groups
|
||||
information would expect to be via nested structures of `meta`, `user`,
|
||||
`name`, and `groups`.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user