package nomad import ( "testing" lru "github.com/hashicorp/golang-lru" "github.com/hashicorp/nomad/acl" "github.com/hashicorp/nomad/ci" "github.com/hashicorp/nomad/helper/uuid" "github.com/hashicorp/nomad/nomad/mock" "github.com/hashicorp/nomad/nomad/state" "github.com/hashicorp/nomad/nomad/structs" "github.com/hashicorp/nomad/testutil" "github.com/stretchr/testify/assert" ) func TestResolveACLToken(t *testing.T) { ci.Parallel(t) // Create mock state store and cache state := state.TestStateStore(t) cache, err := lru.New2Q(16) assert.Nil(t, err) // Create a policy / token policy := mock.ACLPolicy() policy2 := mock.ACLPolicy() token := mock.ACLToken() token.Policies = []string{policy.Name, policy2.Name} token2 := mock.ACLToken() token2.Type = structs.ACLManagementToken token2.Policies = nil err = state.UpsertACLPolicies(structs.MsgTypeTestSetup, 100, []*structs.ACLPolicy{policy, policy2}) assert.Nil(t, err) err = state.UpsertACLTokens(structs.MsgTypeTestSetup, 110, []*structs.ACLToken{token, token2}) assert.Nil(t, err) snap, err := state.Snapshot() assert.Nil(t, err) // Attempt resolution of blank token. Should return anonymous policy aclObj, err := resolveTokenFromSnapshotCache(snap, cache, "") assert.Nil(t, err) assert.NotNil(t, aclObj) // Attempt resolution of unknown token. Should fail. randID := uuid.Generate() aclObj, err = resolveTokenFromSnapshotCache(snap, cache, randID) assert.Equal(t, structs.ErrTokenNotFound, err) assert.Nil(t, aclObj) // Attempt resolution of management token. Should get singleton. aclObj, err = resolveTokenFromSnapshotCache(snap, cache, token2.SecretID) assert.Nil(t, err) assert.NotNil(t, aclObj) assert.Equal(t, true, aclObj.IsManagement()) if aclObj != acl.ManagementACL { t.Fatalf("expected singleton") } // Attempt resolution of client token aclObj, err = resolveTokenFromSnapshotCache(snap, cache, token.SecretID) assert.Nil(t, err) assert.NotNil(t, aclObj) // Check that the ACL object is sane assert.Equal(t, false, aclObj.IsManagement()) allowed := aclObj.AllowNamespaceOperation("default", acl.NamespaceCapabilityListJobs) assert.Equal(t, true, allowed) allowed = aclObj.AllowNamespaceOperation("other", acl.NamespaceCapabilityListJobs) assert.Equal(t, false, allowed) // Resolve the same token again, should get cache value aclObj2, err := resolveTokenFromSnapshotCache(snap, cache, token.SecretID) assert.Nil(t, err) assert.NotNil(t, aclObj2) if aclObj != aclObj2 { t.Fatalf("expected cached value") } // Bust the cache by upserting the policy err = state.UpsertACLPolicies(structs.MsgTypeTestSetup, 120, []*structs.ACLPolicy{policy}) assert.Nil(t, err) snap, err = state.Snapshot() assert.Nil(t, err) // Resolve the same token again, should get different value aclObj3, err := resolveTokenFromSnapshotCache(snap, cache, token.SecretID) assert.Nil(t, err) assert.NotNil(t, aclObj3) if aclObj == aclObj3 { t.Fatalf("unexpected cached value") } } func TestResolveACLToken_LeaderToken(t *testing.T) { ci.Parallel(t) assert := assert.New(t) s1, _, cleanupS1 := TestACLServer(t, nil) defer cleanupS1() testutil.WaitForLeader(t, s1.RPC) leaderAcl := s1.getLeaderAcl() assert.NotEmpty(leaderAcl) token, err := s1.ResolveToken(leaderAcl) assert.Nil(err) if assert.NotNil(token) { assert.True(token.IsManagement()) } } func TestResolveSecretToken(t *testing.T) { ci.Parallel(t) s1, _, cleanupS1 := TestACLServer(t, nil) defer cleanupS1() testutil.WaitForLeader(t, s1.RPC) state := s1.State() leaderToken := s1.getLeaderAcl() assert.NotEmpty(t, leaderToken) token := mock.ACLToken() err := state.UpsertACLTokens(structs.MsgTypeTestSetup, 110, []*structs.ACLToken{token}) assert.Nil(t, err) respToken, err := s1.ResolveSecretToken(token.SecretID) assert.Nil(t, err) if assert.NotNil(t, respToken) { assert.NotEmpty(t, respToken.AccessorID) } }