ListPolicies and GetPolicy work w/o management token
This commit is contained in:
parent
c559f6652f
commit
377e63dc60
3
dev/acls/default-ns.hcl
Normal file
3
dev/acls/default-ns.hcl
Normal file
|
@ -0,0 +1,3 @@
|
|||
namespace "default" {
|
||||
policy = "write"
|
||||
}
|
3
dev/acls/node-read.hcl
Normal file
3
dev/acls/node-read.hcl
Normal file
|
@ -0,0 +1,3 @@
|
|||
node {
|
||||
policy = "read"
|
||||
}
|
|
@ -121,12 +121,36 @@ func (a *ACL) ListPolicies(args *structs.ACLPolicyListRequest, reply *structs.AC
|
|||
defer metrics.MeasureSince([]string{"nomad", "acl", "list_policies"}, time.Now())
|
||||
|
||||
// Check management level permissions
|
||||
if acl, err := a.srv.ResolveToken(args.AuthToken); err != nil {
|
||||
acl, err := a.srv.ResolveToken(args.AuthToken)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if acl == nil || !acl.IsManagement() {
|
||||
} else if acl == nil {
|
||||
return structs.ErrPermissionDenied
|
||||
}
|
||||
|
||||
// If it is not a management token determine the policies that may be listed
|
||||
mgt := acl.IsManagement()
|
||||
var policies map[string]struct{}
|
||||
if !mgt {
|
||||
snap, err := a.srv.fsm.State().Snapshot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
token, err := snap.ACLTokenBySecretID(nil, args.AuthToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if token == nil {
|
||||
return structs.ErrTokenNotFound
|
||||
}
|
||||
|
||||
policies = make(map[string]struct{}, len(token.Policies))
|
||||
for _, p := range token.Policies {
|
||||
policies[p] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// Setup the blocking query
|
||||
opts := blockingOptions{
|
||||
queryOpts: &args.QueryOptions,
|
||||
|
@ -152,7 +176,9 @@ func (a *ACL) ListPolicies(args *structs.ACLPolicyListRequest, reply *structs.AC
|
|||
break
|
||||
}
|
||||
policy := raw.(*structs.ACLPolicy)
|
||||
reply.Policies = append(reply.Policies, policy.Stub())
|
||||
if _, ok := policies[policy.Name]; ok || mgt {
|
||||
reply.Policies = append(reply.Policies, policy.Stub())
|
||||
}
|
||||
}
|
||||
|
||||
// Use the last index that affected the policy table
|
||||
|
@ -183,12 +209,42 @@ func (a *ACL) GetPolicy(args *structs.ACLPolicySpecificRequest, reply *structs.S
|
|||
defer metrics.MeasureSince([]string{"nomad", "acl", "get_policy"}, time.Now())
|
||||
|
||||
// Check management level permissions
|
||||
if acl, err := a.srv.ResolveToken(args.AuthToken); err != nil {
|
||||
acl, err := a.srv.ResolveToken(args.AuthToken)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if acl == nil || !acl.IsManagement() {
|
||||
} else if acl == nil {
|
||||
return structs.ErrPermissionDenied
|
||||
}
|
||||
|
||||
// If it is not a management token determine if it can get this policy
|
||||
mgt := acl.IsManagement()
|
||||
if !mgt {
|
||||
snap, err := a.srv.fsm.State().Snapshot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
token, err := snap.ACLTokenBySecretID(nil, args.AuthToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if token == nil {
|
||||
return structs.ErrTokenNotFound
|
||||
}
|
||||
|
||||
found := false
|
||||
for _, p := range token.Policies {
|
||||
if p == args.Name {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return structs.ErrPermissionDenied
|
||||
}
|
||||
}
|
||||
|
||||
// Setup the blocking query
|
||||
opts := blockingOptions{
|
||||
queryOpts: &args.QueryOptions,
|
||||
|
|
|
@ -28,6 +28,11 @@ func TestACLEndpoint_GetPolicy(t *testing.T) {
|
|||
policy := mock.ACLPolicy()
|
||||
s1.fsm.State().UpsertACLPolicies(1000, []*structs.ACLPolicy{policy})
|
||||
|
||||
// Create a token with one the policy
|
||||
token := mock.ACLToken()
|
||||
token.Policies = []string{policy.Name}
|
||||
s1.fsm.State().UpsertACLTokens(1001, []*structs.ACLToken{token})
|
||||
|
||||
// Lookup the policy
|
||||
get := &structs.ACLPolicySpecificRequest{
|
||||
Name: policy.Name,
|
||||
|
@ -50,6 +55,21 @@ func TestACLEndpoint_GetPolicy(t *testing.T) {
|
|||
}
|
||||
assert.Equal(t, uint64(1000), resp.Index)
|
||||
assert.Nil(t, resp.Policy)
|
||||
|
||||
// Lookup the policy with the token
|
||||
get = &structs.ACLPolicySpecificRequest{
|
||||
Name: policy.Name,
|
||||
QueryOptions: structs.QueryOptions{
|
||||
Region: "global",
|
||||
AuthToken: token.SecretID,
|
||||
},
|
||||
}
|
||||
var resp2 structs.SingleACLPolicyResponse
|
||||
if err := msgpackrpc.CallWithCodec(codec, "ACL.GetPolicy", get, &resp2); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
assert.EqualValues(t, 1000, resp2.Index)
|
||||
assert.Equal(t, policy, resp2.Policy)
|
||||
}
|
||||
|
||||
func TestACLEndpoint_GetPolicy_Blocking(t *testing.T) {
|
||||
|
@ -290,6 +310,7 @@ func TestACLEndpoint_GetPolicies_Blocking(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestACLEndpoint_ListPolicies(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
t.Parallel()
|
||||
s1, root := testACLServer(t, nil)
|
||||
defer s1.Shutdown()
|
||||
|
@ -304,6 +325,11 @@ func TestACLEndpoint_ListPolicies(t *testing.T) {
|
|||
p2.Name = "aaaabbbb-3350-4b4b-d185-0e1992ed43e9"
|
||||
s1.fsm.State().UpsertACLPolicies(1000, []*structs.ACLPolicy{p1, p2})
|
||||
|
||||
// Create a token with one of those policies
|
||||
token := mock.ACLToken()
|
||||
token.Policies = []string{p1.Name}
|
||||
s1.fsm.State().UpsertACLTokens(1001, []*structs.ACLToken{token})
|
||||
|
||||
// Lookup the policies
|
||||
get := &structs.ACLPolicyListRequest{
|
||||
QueryOptions: structs.QueryOptions{
|
||||
|
@ -315,8 +341,8 @@ func TestACLEndpoint_ListPolicies(t *testing.T) {
|
|||
if err := msgpackrpc.CallWithCodec(codec, "ACL.ListPolicies", get, &resp); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
assert.Equal(t, uint64(1000), resp.Index)
|
||||
assert.Equal(t, 2, len(resp.Policies))
|
||||
assert.EqualValues(1000, resp.Index)
|
||||
assert.Len(resp.Policies, 2)
|
||||
|
||||
// Lookup the policies by prefix
|
||||
get = &structs.ACLPolicyListRequest{
|
||||
|
@ -330,8 +356,24 @@ func TestACLEndpoint_ListPolicies(t *testing.T) {
|
|||
if err := msgpackrpc.CallWithCodec(codec, "ACL.ListPolicies", get, &resp2); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
assert.Equal(t, uint64(1000), resp2.Index)
|
||||
assert.Equal(t, 1, len(resp2.Policies))
|
||||
assert.EqualValues(1000, resp2.Index)
|
||||
assert.Len(resp2.Policies, 1)
|
||||
|
||||
// List policies using the created token
|
||||
get = &structs.ACLPolicyListRequest{
|
||||
QueryOptions: structs.QueryOptions{
|
||||
Region: "global",
|
||||
AuthToken: token.SecretID,
|
||||
},
|
||||
}
|
||||
var resp3 structs.ACLPolicyListResponse
|
||||
if err := msgpackrpc.CallWithCodec(codec, "ACL.ListPolicies", get, &resp3); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
assert.EqualValues(1000, resp3.Index)
|
||||
if assert.Len(resp3.Policies, 1) {
|
||||
assert.Equal(resp3.Policies[0].Name, p1.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestACLEndpoint_ListPolicies_Blocking(t *testing.T) {
|
||||
|
|
|
@ -26,7 +26,7 @@ The table below shows this endpoint's support for
|
|||
|
||||
| Blocking Queries | Consistency Modes | ACL Required |
|
||||
| ---------------- | ----------------- | ------------ |
|
||||
| `YES` | `all` | `management` |
|
||||
| `YES` | `all` | `management` for all policies.<br>Output when given a non-management token will be limited to the policies on the token itself |
|
||||
|
||||
|
||||
### Sample Request
|
||||
|
@ -110,7 +110,7 @@ The table below shows this endpoint's support for
|
|||
|
||||
| Blocking Queries | Consistency Modes | ACL Required |
|
||||
| ---------------- | ----------------- | ------------ |
|
||||
| `YES` | `all` | `management` |
|
||||
| `YES` | `all` | `management` or token with access to policy |
|
||||
|
||||
### Sample Request
|
||||
|
||||
|
|
Loading…
Reference in a new issue