Skip to content

Commit

Permalink
Merge pull request #14320 from hashicorp/f-gh-13120-sso-umbrella-merg…
Browse files Browse the repository at this point in the history
…ed-main

acl: add token expiration and ACL role functionality
  • Loading branch information
jrasell committed Aug 30, 2022
2 parents f1b62f5 + bf46203 commit 54e4341
Show file tree
Hide file tree
Showing 63 changed files with 8,214 additions and 444 deletions.
224 changes: 211 additions & 13 deletions api/acl.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,96 @@ func (a *ACLTokens) ExchangeOneTimeToken(secret string, q *WriteOptions) (*ACLTo
return resp.Token, wm, nil
}

var (
// errMissingACLRoleID is the generic errors to use when a call is missing
// the required ACL Role ID parameter.
errMissingACLRoleID = errors.New("missing ACL role ID")
)

// ACLRoles is used to query the ACL Role endpoints.
type ACLRoles struct {
client *Client
}

// ACLRoles returns a new handle on the ACL roles API client.
func (c *Client) ACLRoles() *ACLRoles {
return &ACLRoles{client: c}
}

// List is used to detail all the ACL roles currently stored within state.
func (a *ACLRoles) List(q *QueryOptions) ([]*ACLRoleListStub, *QueryMeta, error) {
var resp []*ACLRoleListStub
qm, err := a.client.query("/v1/acl/roles", &resp, q)
if err != nil {
return nil, nil, err
}
return resp, qm, nil
}

// Create is used to create an ACL role.
func (a *ACLRoles) Create(role *ACLRole, w *WriteOptions) (*ACLRole, *WriteMeta, error) {
if role.ID != "" {
return nil, nil, errors.New("cannot specify ACL role ID")
}
var resp ACLRole
wm, err := a.client.write("/v1/acl/role", role, &resp, w)
if err != nil {
return nil, nil, err
}
return &resp, wm, nil
}

// Update is used to update an existing ACL role.
func (a *ACLRoles) Update(role *ACLRole, w *WriteOptions) (*ACLRole, *WriteMeta, error) {
if role.ID == "" {
return nil, nil, errMissingACLRoleID
}
var resp ACLRole
wm, err := a.client.write("/v1/acl/role/"+role.ID, role, &resp, w)
if err != nil {
return nil, nil, err
}
return &resp, wm, nil
}

// Delete is used to delete an ACL role.
func (a *ACLRoles) Delete(roleID string, w *WriteOptions) (*WriteMeta, error) {
if roleID == "" {
return nil, errMissingACLRoleID
}
wm, err := a.client.delete("/v1/acl/role/"+roleID, nil, nil, w)
if err != nil {
return nil, err
}
return wm, nil
}

// Get is used to look up an ACL role.
func (a *ACLRoles) Get(roleID string, q *QueryOptions) (*ACLRole, *QueryMeta, error) {
if roleID == "" {
return nil, nil, errMissingACLRoleID
}
var resp ACLRole
qm, err := a.client.query("/v1/acl/role/"+roleID, &resp, q)
if err != nil {
return nil, nil, err
}
return &resp, qm, nil
}

// GetByName is used to look up an ACL role using its name.
func (a *ACLRoles) GetByName(roleName string, q *QueryOptions) (*ACLRole, *QueryMeta, error) {
if roleName == "" {
return nil, nil, errors.New("missing ACL role name")
}
var resp ACLRole
qm, err := a.client.query("/v1/acl/role/name/"+roleName, &resp, q)
if err != nil {
return nil, nil, err
}
return &resp, qm, nil
}

// ACLPolicyListStub is used to for listing ACL policies
type ACLPolicyListStub struct {
Name string
Expand Down Expand Up @@ -231,24 +321,62 @@ type JobACL struct {

// ACLToken represents a client token which is used to Authenticate
type ACLToken struct {
AccessorID string
SecretID string
Name string
Type string
Policies []string
Global bool
CreateTime time.Time
AccessorID string
SecretID string
Name string
Type string
Policies []string

// Roles represents the ACL roles that this token is tied to. The token
// will inherit the permissions of all policies detailed within the role.
Roles []*ACLTokenRoleLink

Global bool
CreateTime time.Time

// ExpirationTime represents the point after which a token should be
// considered revoked and is eligible for destruction. The zero value of
// time.Time does not respect json omitempty directives, so we must use a
// pointer.
ExpirationTime *time.Time `json:",omitempty"`

// ExpirationTTL is a convenience field for helping set ExpirationTime to a
// value of CreateTime+ExpirationTTL. This can only be set during token
// creation. This is a string version of a time.Duration like "2m".
ExpirationTTL time.Duration `json:",omitempty"`

CreateIndex uint64
ModifyIndex uint64
}

// ACLTokenRoleLink is used to link an ACL token to an ACL role. The ACL token
// can therefore inherit all the ACL policy permissions that the ACL role
// contains.
type ACLTokenRoleLink struct {

// ID is the ACLRole.ID UUID. This field is immutable and represents the
// absolute truth for the link.
ID string

// Name is the human friendly identifier for the ACL role and is a
// convenience field for operators.
Name string
}

type ACLTokenListStub struct {
AccessorID string
Name string
Type string
Policies []string
Global bool
CreateTime time.Time
AccessorID string
Name string
Type string
Policies []string
Roles []*ACLTokenRoleLink
Global bool
CreateTime time.Time

// ExpirationTime represents the point after which a token should be
// considered revoked and is eligible for destruction. A nil value
// indicates no expiration has been set on the token.
ExpirationTime *time.Time `json:"expiration_time,omitempty"`

CreateIndex uint64
ModifyIndex uint64
}
Expand Down Expand Up @@ -277,3 +405,73 @@ type OneTimeTokenExchangeResponse struct {
type BootstrapRequest struct {
BootstrapSecret string
}

// ACLRole is an abstraction for the ACL system which allows the grouping of
// ACL policies into a single object. ACL tokens can be created and linked to
// a role; the token then inherits all the permissions granted by the policies.
type ACLRole struct {

// ID is an internally generated UUID for this role and is controlled by
// Nomad. It can be used after role creation to update the existing role.
ID string

// Name is unique across the entire set of federated clusters and is
// supplied by the operator on role creation. The name can be modified by
// updating the role and including the Nomad generated ID. This update will
// not affect tokens created and linked to this role. This is a required
// field.
Name string

// Description is a human-readable, operator set description that can
// provide additional context about the role. This is an optional field.
Description string

// Policies is an array of ACL policy links. Although currently policies
// can only be linked using their name, in the future we will want to add
// IDs also and thus allow operators to specify either a name, an ID, or
// both. At least one entry is required.
Policies []*ACLRolePolicyLink

CreateIndex uint64
ModifyIndex uint64
}

// ACLRolePolicyLink is used to link a policy to an ACL role. We use a struct
// rather than a list of strings as in the future we will want to add IDs to
// policies and then link via these.
type ACLRolePolicyLink struct {

// Name is the ACLPolicy.Name value which will be linked to the ACL role.
Name string
}

// ACLRoleListStub is the stub object returned when performing a listing of ACL
// roles. While it might not currently be different to the full response
// object, it allows us to future-proof the RPC in the event the ACLRole object
// grows over time.
type ACLRoleListStub struct {

// ID is an internally generated UUID for this role and is controlled by
// Nomad.
ID string

// Name is unique across the entire set of federated clusters and is
// supplied by the operator on role creation. The name can be modified by
// updating the role and including the Nomad generated ID. This update will
// not affect tokens created and linked to this role. This is a required
// field.
Name string

// Description is a human-readable, operator set description that can
// provide additional context about the role. This is an operational field.
Description string

// Policies is an array of ACL policy links. Although currently policies
// can only be linked using their name, in the future we will want to add
// IDs also and thus allow operators to specify either a name, an ID, or
// both.
Policies []*ACLRolePolicyLink

CreateIndex uint64
ModifyIndex uint64
}
Loading

0 comments on commit 54e4341

Please sign in to comment.