08f50f7dbf
This PR adds a check that makes sure we don't insert a duplicate default ACL auth method for a given type.
256 lines
8.3 KiB
Go
256 lines
8.3 KiB
Go
package state
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/hashicorp/go-memdb"
|
|
"github.com/hashicorp/nomad/ci"
|
|
"github.com/hashicorp/nomad/nomad/mock"
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
|
"github.com/shoenig/test/must"
|
|
)
|
|
|
|
func TestStateStore_UpsertACLAuthMethods(t *testing.T) {
|
|
ci.Parallel(t)
|
|
testState := testStateStore(t)
|
|
|
|
// Create mock auth methods
|
|
mockedACLAuthMethods := []*structs.ACLAuthMethod{mock.ACLAuthMethod(), mock.ACLAuthMethod()}
|
|
|
|
must.NoError(t, testState.UpsertACLAuthMethods(10, mockedACLAuthMethods))
|
|
|
|
// Check that the index for the table was modified as expected.
|
|
initialIndex, err := testState.Index(TableACLAuthMethods)
|
|
must.NoError(t, err)
|
|
must.Eq(t, 10, initialIndex)
|
|
|
|
// List all the auth methods in the table, so we can perform a number of
|
|
// tests on the return array.
|
|
ws := memdb.NewWatchSet()
|
|
iter, err := testState.GetACLAuthMethods(ws)
|
|
must.NoError(t, err)
|
|
|
|
// Count how many table entries we have, to ensure it is the expected
|
|
// number.
|
|
var count int
|
|
|
|
for raw := iter.Next(); raw != nil; raw = iter.Next() {
|
|
count++
|
|
|
|
// Ensure the create and modify indexes are populated correctly.
|
|
authMethod := raw.(*structs.ACLAuthMethod)
|
|
must.Eq(t, 10, authMethod.CreateIndex)
|
|
must.Eq(t, 10, authMethod.ModifyIndex)
|
|
}
|
|
must.Eq(t, 2, count)
|
|
|
|
// Try writing the same auth methods to state which should not result in an
|
|
// update to the table index.
|
|
must.NoError(t, testState.UpsertACLAuthMethods(20, mockedACLAuthMethods))
|
|
reInsertActualIndex, err := testState.Index(TableACLAuthMethods)
|
|
must.NoError(t, err)
|
|
must.Eq(t, 10, reInsertActualIndex)
|
|
|
|
// Make a change to the auth methods and ensure this update is accepted and
|
|
// the table index is updated.
|
|
updatedMockedAuthMethod1 := mockedACLAuthMethods[0].Copy()
|
|
updatedMockedAuthMethod1.Type = "new type"
|
|
updatedMockedAuthMethod1.SetHash()
|
|
updatedMockedAuthMethod2 := mockedACLAuthMethods[1].Copy()
|
|
updatedMockedAuthMethod2.Type = "yet another new type"
|
|
updatedMockedAuthMethod2.SetHash()
|
|
must.NoError(t, testState.UpsertACLAuthMethods(20, []*structs.ACLAuthMethod{
|
|
updatedMockedAuthMethod1, updatedMockedAuthMethod2,
|
|
}))
|
|
|
|
// Check that the index for the table was modified as expected.
|
|
updatedIndex, err := testState.Index(TableACLAuthMethods)
|
|
must.NoError(t, err)
|
|
must.Eq(t, 20, updatedIndex)
|
|
|
|
// List the ACL auth methods in state.
|
|
iter, err = testState.GetACLAuthMethods(ws)
|
|
must.NoError(t, err)
|
|
|
|
// Count how many table entries we have, to ensure it is the expected
|
|
// number.
|
|
count = 0
|
|
|
|
for raw := iter.Next(); raw != nil; raw = iter.Next() {
|
|
count++
|
|
|
|
// Ensure the create and modify indexes are populated correctly.
|
|
aclAuthMethod := raw.(*structs.ACLAuthMethod)
|
|
must.Eq(t, 10, aclAuthMethod.CreateIndex)
|
|
must.Eq(t, 20, aclAuthMethod.ModifyIndex)
|
|
}
|
|
must.Eq(t, 2, count, must.Sprintf("incorrect number of ACL auth methods found"))
|
|
|
|
// Try adding a new auth method, which has a name clash with an existing
|
|
// entry.
|
|
dup := mock.ACLAuthMethod()
|
|
dup.Name = mockedACLAuthMethods[0].Name
|
|
dup.Type = mockedACLAuthMethods[0].Type
|
|
|
|
err = testState.UpsertACLAuthMethods(50, []*structs.ACLAuthMethod{dup})
|
|
must.NoError(t, err)
|
|
|
|
// Get all the ACL auth methods from state.
|
|
iter, err = testState.GetACLAuthMethods(ws)
|
|
must.NoError(t, err)
|
|
|
|
// Count how many table entries we have, to ensure it is the expected
|
|
// number.
|
|
count = 0
|
|
|
|
for raw := iter.Next(); raw != nil; raw = iter.Next() {
|
|
count++
|
|
}
|
|
must.Eq(t, 2, count, must.Sprintf("incorrect number of ACL auth methods found"))
|
|
}
|
|
|
|
func TestStateStore_DeleteACLAuthMethods(t *testing.T) {
|
|
ci.Parallel(t)
|
|
testState := testStateStore(t)
|
|
|
|
// Generate some mocked ACL auth methods for testing and upsert these
|
|
// straight into state.
|
|
mockedACLAuthMethods := []*structs.ACLAuthMethod{mock.ACLAuthMethod(), mock.ACLAuthMethod()}
|
|
must.NoError(t, testState.UpsertACLAuthMethods(10, mockedACLAuthMethods))
|
|
|
|
// Try and delete a method using a name that doesn't exist. This should
|
|
// return an error and not change the index for the table.
|
|
err := testState.DeleteACLAuthMethods(20, []string{"not-a-method"})
|
|
must.EqError(t, err, "ACL auth method not found")
|
|
|
|
tableIndex, err := testState.Index(TableACLAuthMethods)
|
|
must.NoError(t, err)
|
|
must.Eq(t, 10, tableIndex)
|
|
|
|
// Delete one of the previously upserted auth methods. This should succeed
|
|
// and modify the table index.
|
|
err = testState.DeleteACLAuthMethods(20, []string{mockedACLAuthMethods[0].Name})
|
|
must.NoError(t, err)
|
|
|
|
tableIndex, err = testState.Index(TableACLAuthMethods)
|
|
must.NoError(t, err)
|
|
must.Eq(t, 20, tableIndex)
|
|
|
|
// List the ACL auth methods and ensure we now only have one present and
|
|
// that it is the one we expect.
|
|
ws := memdb.NewWatchSet()
|
|
iter, err := testState.GetACLAuthMethods(ws)
|
|
must.NoError(t, err)
|
|
|
|
var aclAuthMethods []*structs.ACLAuthMethod
|
|
|
|
for raw := iter.Next(); raw != nil; raw = iter.Next() {
|
|
aclAuthMethods = append(aclAuthMethods, raw.(*structs.ACLAuthMethod))
|
|
}
|
|
|
|
must.Len(t, 1, aclAuthMethods, must.Sprintf("incorrect number of auth methods found"))
|
|
must.True(t, aclAuthMethods[0].Equal(mockedACLAuthMethods[1]))
|
|
|
|
// Delete the final remaining auth method. This should succeed and modify
|
|
// the table index.
|
|
err = testState.DeleteACLAuthMethods(30, []string{mockedACLAuthMethods[1].Name})
|
|
must.NoError(t, err)
|
|
|
|
tableIndex, err = testState.Index(TableACLAuthMethods)
|
|
must.NoError(t, err)
|
|
must.Eq(t, 30, tableIndex)
|
|
|
|
// List the auth methods and ensure we have zero entries.
|
|
iter, err = testState.GetACLAuthMethods(ws)
|
|
must.NoError(t, err)
|
|
|
|
aclAuthMethods = []*structs.ACLAuthMethod{}
|
|
|
|
for raw := iter.Next(); raw != nil; raw = iter.Next() {
|
|
aclAuthMethods = append(aclAuthMethods, raw.(*structs.ACLAuthMethod))
|
|
}
|
|
must.Len(t, 0, aclAuthMethods, must.Sprintf("incorrect number of ACL roles found"))
|
|
}
|
|
|
|
func TestStateStore_GetACLAuthMethods(t *testing.T) {
|
|
ci.Parallel(t)
|
|
testState := testStateStore(t)
|
|
|
|
// Generate a some mocked ACL auth methods for testing and upsert these
|
|
// straight into state.
|
|
mockedACLAuthMethods := []*structs.ACLAuthMethod{mock.ACLAuthMethod(), mock.ACLAuthMethod()}
|
|
must.NoError(t, testState.UpsertACLAuthMethods(10, mockedACLAuthMethods))
|
|
|
|
// List the auth methods and ensure they are exactly as we expect.
|
|
ws := memdb.NewWatchSet()
|
|
iter, err := testState.GetACLAuthMethods(ws)
|
|
must.NoError(t, err)
|
|
|
|
var aclAuthMethods []*structs.ACLAuthMethod
|
|
|
|
for raw := iter.Next(); raw != nil; raw = iter.Next() {
|
|
aclAuthMethods = append(aclAuthMethods, raw.(*structs.ACLAuthMethod))
|
|
}
|
|
|
|
expected := mockedACLAuthMethods
|
|
for i := range expected {
|
|
expected[i].CreateIndex = 10
|
|
expected[i].ModifyIndex = 10
|
|
}
|
|
|
|
must.SliceContainsAll(t, aclAuthMethods, expected)
|
|
}
|
|
|
|
func TestStateStore_GetACLAuthMethodByName(t *testing.T) {
|
|
ci.Parallel(t)
|
|
testState := testStateStore(t)
|
|
|
|
// Generate a some mocked ACL auth methods for testing and upsert these
|
|
// straight into state.
|
|
mockedACLAuthMethods := []*structs.ACLAuthMethod{mock.ACLAuthMethod(), mock.ACLAuthMethod()}
|
|
must.NoError(t, testState.UpsertACLAuthMethods(10, mockedACLAuthMethods))
|
|
|
|
ws := memdb.NewWatchSet()
|
|
|
|
// Try reading an auth method that does not exist.
|
|
authMethod, err := testState.GetACLAuthMethodByName(ws, "not-a-method")
|
|
must.NoError(t, err)
|
|
must.Nil(t, authMethod)
|
|
|
|
// Read the two ACL roles that we should find.
|
|
authMethod, err = testState.GetACLAuthMethodByName(ws, mockedACLAuthMethods[0].Name)
|
|
must.NoError(t, err)
|
|
must.Equal(t, mockedACLAuthMethods[0], authMethod)
|
|
|
|
authMethod, err = testState.GetACLAuthMethodByName(ws, mockedACLAuthMethods[1].Name)
|
|
must.NoError(t, err)
|
|
must.Equal(t, mockedACLAuthMethods[1], authMethod)
|
|
}
|
|
|
|
func TestStateStore_GetDefaultACLAuthMethodByType(t *testing.T) {
|
|
ci.Parallel(t)
|
|
testState := testStateStore(t)
|
|
|
|
// Generate 2 auth methods, make one of them default
|
|
am1 := mock.ACLAuthMethod()
|
|
am1.Default = true
|
|
am2 := mock.ACLAuthMethod()
|
|
|
|
// upsert
|
|
mockedACLAuthMethods := []*structs.ACLAuthMethod{am1, am2}
|
|
must.NoError(t, testState.UpsertACLAuthMethods(10, mockedACLAuthMethods))
|
|
|
|
// Get the default method for OIDC
|
|
ws := memdb.NewWatchSet()
|
|
defaultOIDCMethod, err := testState.GetDefaultACLAuthMethodByType(ws, "OIDC")
|
|
must.NoError(t, err)
|
|
|
|
must.True(t, defaultOIDCMethod.Default)
|
|
must.Eq(t, am1, defaultOIDCMethod)
|
|
|
|
// Get the default method for jwt (should not return anything)
|
|
defaultJWTMethod, err := testState.GetDefaultACLAuthMethodByType(ws, "JWT")
|
|
must.NoError(t, err)
|
|
must.Nil(t, defaultJWTMethod)
|
|
}
|