diff --git a/go.mod b/go.mod index c2f120287..2d0bf9511 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/fasthttp/session/v2 v2.5.0 github.com/fsnotify/fsnotify v1.6.0 github.com/go-asn1-ber/asn1-ber v1.5.4 - github.com/go-crypt/crypt v0.2.7 + github.com/go-crypt/crypt v0.2.9 github.com/go-ldap/ldap/v3 v3.4.5-0.20230521105649-cdb0754f6668 github.com/go-rod/rod v0.113.0 github.com/go-sql-driver/mysql v1.7.1 @@ -70,7 +70,7 @@ require ( github.com/ecordell/optgen v0.0.6 // indirect github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect - github.com/go-crypt/x v0.2.0 // indirect + github.com/go-crypt/x v0.2.1 // indirect github.com/go-redis/redis/v8 v8.11.5 // indirect github.com/go-webauthn/revoke v0.1.9 // indirect github.com/golang/glog v1.0.0 // indirect diff --git a/go.sum b/go.sum index a63bc64e2..a154b870f 100644 --- a/go.sum +++ b/go.sum @@ -132,8 +132,14 @@ github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-crypt/crypt v0.2.7 h1:Ir6E59c1wrskJhpJXMqaynHA2xAxpGN7nQXlLkbpzR0= github.com/go-crypt/crypt v0.2.7/go.mod h1:ulieouNs4qwFCq4wF61oyTQYXAXSoOv995EU4hcHwMU= +github.com/go-crypt/crypt v0.2.8 h1:nI4HYMSHpXi68N5/LrhZCV8gDqLcIwtnHs8Xkuipooo= +github.com/go-crypt/crypt v0.2.8/go.mod h1:JjzdTYE2mArb6nBoIvvpF7o46/rK/1pfmlArCRMTFUk= +github.com/go-crypt/crypt v0.2.9 h1:5gWWTId2Qyqs9ROIsegt5pnqo9wUSRLbhpkR6JSftjg= +github.com/go-crypt/crypt v0.2.9/go.mod h1:JjzdTYE2mArb6nBoIvvpF7o46/rK/1pfmlArCRMTFUk= github.com/go-crypt/x v0.2.0 h1:rHMiKRAu6kFc+xAnQywDb3iHGpvrFbIGXnP3IfCZ+2U= github.com/go-crypt/x v0.2.0/go.mod h1:uLo5o+Cc8nvahDASQpntR1g3ZMUoq2LM/859PkhykC4= +github.com/go-crypt/x v0.2.1 h1:OGw78Bswme9lffCOX6tyuC280ouU5391glsvThMtM5U= +github.com/go-crypt/x v0.2.1/go.mod h1:Q/y9rms7yw4/1CavBlNGn0Itg4HqwNpe1N9FX0TxXrc= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= diff --git a/internal/authentication/file_user_provider.go b/internal/authentication/file_user_provider.go index 270ddd50e..bf63fd3fd 100644 --- a/internal/authentication/file_user_provider.go +++ b/internal/authentication/file_user_provider.go @@ -23,7 +23,7 @@ import ( type FileUserProvider struct { config *schema.FileAuthenticationBackend hash algorithm.Hash - database *FileUserDatabase + database FileUserDatabase mutex *sync.Mutex timeoutReload time.Time } @@ -34,7 +34,7 @@ func NewFileUserProvider(config *schema.FileAuthenticationBackend) (provider *Fi config: config, mutex: &sync.Mutex{}, timeoutReload: time.Now().Add(-1 * time.Second), - database: NewFileUserDatabase(config.Path, config.Search.Email, config.Search.CaseInsensitive), + database: NewYAMLUserDatabase(config.Path, config.Search.Email, config.Search.CaseInsensitive), } } @@ -138,7 +138,7 @@ func (p *FileUserProvider) StartupCheck() (err error) { } if p.database == nil { - p.database = NewFileUserDatabase(p.config.Path, p.config.Search.Email, p.config.Search.CaseInsensitive) + p.database = NewYAMLUserDatabase(p.config.Path, p.config.Search.Email, p.config.Search.CaseInsensitive) } if err = p.database.Load(); err != nil { @@ -197,10 +197,6 @@ func NewFileCryptoHashFromConfig(config schema.Password) (hash algorithm.Hash, e return nil, fmt.Errorf("failed to initialize hash settings: %w", err) } - if err = hash.Validate(); err != nil { - return nil, fmt.Errorf("failed to validate hash settings: %w", err) - } - return hash, nil } diff --git a/internal/authentication/file_user_provider_database.go b/internal/authentication/file_user_provider_database.go index 509f025e0..f5c526096 100644 --- a/internal/authentication/file_user_provider_database.go +++ b/internal/authentication/file_user_provider_database.go @@ -12,9 +12,16 @@ import ( "gopkg.in/yaml.v3" ) -// NewFileUserDatabase creates a new FileUserDatabase. -func NewFileUserDatabase(filePath string, searchEmail, searchCI bool) (database *FileUserDatabase) { - return &FileUserDatabase{ +type FileUserDatabase interface { + Save() (err error) + Load() (err error) + GetUserDetails(username string) (user DatabaseUserDetails, err error) + SetUserDetails(username string, details *DatabaseUserDetails) +} + +// NewYAMLUserDatabase creates a new YAMLUserDatabase. +func NewYAMLUserDatabase(filePath string, searchEmail, searchCI bool) (database *YAMLUserDatabase) { + return &YAMLUserDatabase{ RWMutex: &sync.RWMutex{}, Path: filePath, Users: map[string]DatabaseUserDetails{}, @@ -25,8 +32,8 @@ func NewFileUserDatabase(filePath string, searchEmail, searchCI bool) (database } } -// FileUserDatabase is a user details database that is concurrency safe database and can be reloaded. -type FileUserDatabase struct { +// YAMLUserDatabase is a user details database that is concurrency safe database and can be reloaded. +type YAMLUserDatabase struct { *sync.RWMutex Path string @@ -39,7 +46,7 @@ type FileUserDatabase struct { } // Save the database to disk. -func (m *FileUserDatabase) Save() (err error) { +func (m *YAMLUserDatabase) Save() (err error) { m.RLock() defer m.RUnlock() @@ -52,7 +59,7 @@ func (m *FileUserDatabase) Save() (err error) { } // Load the database from disk. -func (m *FileUserDatabase) Load() (err error) { +func (m *YAMLUserDatabase) Load() (err error) { yml := &DatabaseModel{Users: map[string]UserDetailsModel{}} if err = yml.Read(m.Path); err != nil { @@ -71,7 +78,7 @@ func (m *FileUserDatabase) Load() (err error) { } // LoadAliases performs the loading of alias information from the database. -func (m *FileUserDatabase) LoadAliases() (err error) { +func (m *YAMLUserDatabase) LoadAliases() (err error) { if m.SearchEmail || m.SearchCI { for k, user := range m.Users { if m.SearchEmail && user.Email != "" { @@ -91,7 +98,7 @@ func (m *FileUserDatabase) LoadAliases() (err error) { return nil } -func (m *FileUserDatabase) loadAlias(k string) (err error) { +func (m *YAMLUserDatabase) loadAlias(k string) (err error) { u := strings.ToLower(k) if u != k { @@ -113,7 +120,7 @@ func (m *FileUserDatabase) loadAlias(k string) (err error) { return nil } -func (m *FileUserDatabase) loadAliasEmail(k string, user DatabaseUserDetails) (err error) { +func (m *YAMLUserDatabase) loadAliasEmail(k string, user DatabaseUserDetails) (err error) { e := strings.ToLower(user.Email) var duplicates []string @@ -145,7 +152,7 @@ func (m *FileUserDatabase) loadAliasEmail(k string, user DatabaseUserDetails) (e // GetUserDetails get a DatabaseUserDetails given a username as a value type where the username must be the users actual // username. -func (m *FileUserDatabase) GetUserDetails(username string) (user DatabaseUserDetails, err error) { +func (m *YAMLUserDatabase) GetUserDetails(username string) (user DatabaseUserDetails, err error) { m.RLock() defer m.RUnlock() @@ -172,7 +179,7 @@ func (m *FileUserDatabase) GetUserDetails(username string) (user DatabaseUserDet } // SetUserDetails sets the DatabaseUserDetails for a given user. -func (m *FileUserDatabase) SetUserDetails(username string, details *DatabaseUserDetails) { +func (m *YAMLUserDatabase) SetUserDetails(username string, details *DatabaseUserDetails) { if details == nil { return } @@ -184,8 +191,8 @@ func (m *FileUserDatabase) SetUserDetails(username string, details *DatabaseUser m.Unlock() } -// ToDatabaseModel converts the FileUserDatabase into the DatabaseModel for saving. -func (m *FileUserDatabase) ToDatabaseModel() (model *DatabaseModel) { +// ToDatabaseModel converts the YAMLUserDatabase into the DatabaseModel for saving. +func (m *YAMLUserDatabase) ToDatabaseModel() (model *DatabaseModel) { model = &DatabaseModel{ Users: map[string]UserDetailsModel{}, } @@ -236,8 +243,8 @@ type DatabaseModel struct { Users map[string]UserDetailsModel `yaml:"users" valid:"required"` } -// ReadToFileUserDatabase reads the DatabaseModel into a FileUserDatabase. -func (m *DatabaseModel) ReadToFileUserDatabase(db *FileUserDatabase) (err error) { +// ReadToFileUserDatabase reads the DatabaseModel into a YAMLUserDatabase. +func (m *DatabaseModel) ReadToFileUserDatabase(db *YAMLUserDatabase) (err error) { users := map[string]DatabaseUserDetails{} var udm *DatabaseUserDetails diff --git a/internal/authentication/file_user_provider_database_mock_test.go b/internal/authentication/file_user_provider_database_mock_test.go new file mode 100644 index 000000000..26e1e3a68 --- /dev/null +++ b/internal/authentication/file_user_provider_database_mock_test.go @@ -0,0 +1,89 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/authelia/authelia/v4/internal/authentication (interfaces: FileUserDatabase) + +// Package authentication is a generated GoMock package. +package authentication + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" +) + +// MockFileUserDatabase is a mock of FileUserDatabase interface. +type MockFileUserDatabase struct { + ctrl *gomock.Controller + recorder *MockFileUserDatabaseMockRecorder +} + +// MockFileUserDatabaseMockRecorder is the mock recorder for MockFileUserDatabase. +type MockFileUserDatabaseMockRecorder struct { + mock *MockFileUserDatabase +} + +// NewMockFileUserDatabase creates a new mock instance. +func NewMockFileUserDatabase(ctrl *gomock.Controller) *MockFileUserDatabase { + mock := &MockFileUserDatabase{ctrl: ctrl} + mock.recorder = &MockFileUserDatabaseMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockFileUserDatabase) EXPECT() *MockFileUserDatabaseMockRecorder { + return m.recorder +} + +// GetUserDetails mocks base method. +func (m *MockFileUserDatabase) GetUserDetails(arg0 string) (DatabaseUserDetails, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUserDetails", arg0) + ret0, _ := ret[0].(DatabaseUserDetails) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUserDetails indicates an expected call of GetUserDetails. +func (mr *MockFileUserDatabaseMockRecorder) GetUserDetails(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserDetails", reflect.TypeOf((*MockFileUserDatabase)(nil).GetUserDetails), arg0) +} + +// Load mocks base method. +func (m *MockFileUserDatabase) Load() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Load") + ret0, _ := ret[0].(error) + return ret0 +} + +// Load indicates an expected call of Load. +func (mr *MockFileUserDatabaseMockRecorder) Load() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Load", reflect.TypeOf((*MockFileUserDatabase)(nil).Load)) +} + +// Save mocks base method. +func (m *MockFileUserDatabase) Save() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Save") + ret0, _ := ret[0].(error) + return ret0 +} + +// Save indicates an expected call of Save. +func (mr *MockFileUserDatabaseMockRecorder) Save() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Save", reflect.TypeOf((*MockFileUserDatabase)(nil).Save)) +} + +// SetUserDetails mocks base method. +func (m *MockFileUserDatabase) SetUserDetails(arg0 string, arg1 *DatabaseUserDetails) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetUserDetails", arg0, arg1) +} + +// SetUserDetails indicates an expected call of SetUserDetails. +func (mr *MockFileUserDatabaseMockRecorder) SetUserDetails(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUserDetails", reflect.TypeOf((*MockFileUserDatabase)(nil).SetUserDetails), arg0, arg1) +} diff --git a/internal/authentication/file_user_provider_hash_mock_test.go b/internal/authentication/file_user_provider_hash_mock_test.go new file mode 100644 index 000000000..fb78a32c4 --- /dev/null +++ b/internal/authentication/file_user_provider_hash_mock_test.go @@ -0,0 +1,93 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/go-crypt/crypt/algorithm (interfaces: Hash) + +// Package authentication is a generated GoMock package. +package authentication + +import ( + reflect "reflect" + + algorithm "github.com/go-crypt/crypt/algorithm" + gomock "github.com/golang/mock/gomock" +) + +// MockHash is a mock of Hash interface. +type MockHash struct { + ctrl *gomock.Controller + recorder *MockHashMockRecorder +} + +// MockHashMockRecorder is the mock recorder for MockHash. +type MockHashMockRecorder struct { + mock *MockHash +} + +// NewMockHash creates a new mock instance. +func NewMockHash(ctrl *gomock.Controller) *MockHash { + mock := &MockHash{ctrl: ctrl} + mock.recorder = &MockHashMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockHash) EXPECT() *MockHashMockRecorder { + return m.recorder +} + +// Hash mocks base method. +func (m *MockHash) Hash(arg0 string) (algorithm.Digest, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Hash", arg0) + ret0, _ := ret[0].(algorithm.Digest) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Hash indicates an expected call of Hash. +func (mr *MockHashMockRecorder) Hash(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Hash", reflect.TypeOf((*MockHash)(nil).Hash), arg0) +} + +// HashWithSalt mocks base method. +func (m *MockHash) HashWithSalt(arg0 string, arg1 []byte) (algorithm.Digest, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HashWithSalt", arg0, arg1) + ret0, _ := ret[0].(algorithm.Digest) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// HashWithSalt indicates an expected call of HashWithSalt. +func (mr *MockHashMockRecorder) HashWithSalt(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HashWithSalt", reflect.TypeOf((*MockHash)(nil).HashWithSalt), arg0, arg1) +} + +// MustHash mocks base method. +func (m *MockHash) MustHash(arg0 string) algorithm.Digest { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "MustHash", arg0) + ret0, _ := ret[0].(algorithm.Digest) + return ret0 +} + +// MustHash indicates an expected call of MustHash. +func (mr *MockHashMockRecorder) MustHash(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MustHash", reflect.TypeOf((*MockHash)(nil).MustHash), arg0) +} + +// Validate mocks base method. +func (m *MockHash) Validate() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Validate") + ret0, _ := ret[0].(error) + return ret0 +} + +// Validate indicates an expected call of Validate. +func (mr *MockHashMockRecorder) Validate() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Validate", reflect.TypeOf((*MockHash)(nil).Validate)) +} diff --git a/internal/authentication/file_user_provider_test.go b/internal/authentication/file_user_provider_test.go index 208edcd59..e1078acc0 100644 --- a/internal/authentication/file_user_provider_test.go +++ b/internal/authentication/file_user_provider_test.go @@ -14,6 +14,7 @@ import ( "github.com/go-crypt/crypt/algorithm/bcrypt" "github.com/go-crypt/crypt/algorithm/pbkdf2" "github.com/go-crypt/crypt/algorithm/scrypt" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -129,7 +130,7 @@ func TestShouldReloadDatabase(t *testing.T) { provider.config.Path = p - provider.database = NewFileUserDatabase(p, provider.config.Search.Email, provider.config.Search.CaseInsensitive) + provider.database = NewYAMLUserDatabase(p, provider.config.Search.Email, provider.config.Search.CaseInsensitive) }, false, "", @@ -306,7 +307,10 @@ func TestShouldUpdatePasswordHashingAlgorithmToArgon2id(t *testing.T) { assert.NoError(t, provider.StartupCheck()) - assert.True(t, strings.HasPrefix(provider.database.Users["harry"].Digest.Encode(), "$6$")) + db, ok := provider.database.(*YAMLUserDatabase) + require.True(t, ok) + + assert.True(t, strings.HasPrefix(db.Users["harry"].Digest.Encode(), "$6$")) err := provider.UpdatePassword("harry", "newpassword") assert.NoError(t, err) @@ -315,10 +319,10 @@ func TestShouldUpdatePasswordHashingAlgorithmToArgon2id(t *testing.T) { assert.NoError(t, provider.StartupCheck()) - ok, err := provider.CheckUserPassword("harry", "newpassword") + ok, err = provider.CheckUserPassword("harry", "newpassword") assert.NoError(t, err) assert.True(t, ok) - assert.True(t, strings.HasPrefix(provider.database.Users["harry"].Digest.Encode(), "$argon2id$")) + assert.True(t, strings.HasPrefix(db.Users["harry"].Digest.Encode(), "$argon2id$")) }) } @@ -333,7 +337,10 @@ func TestShouldUpdatePasswordHashingAlgorithmToSHA512(t *testing.T) { assert.NoError(t, provider.StartupCheck()) - assert.True(t, strings.HasPrefix(provider.database.Users["john"].Digest.Encode(), "$argon2id$")) + db, ok := provider.database.(*YAMLUserDatabase) + require.True(t, ok) + + assert.True(t, strings.HasPrefix(db.Users["john"].Digest.Encode(), "$argon2id$")) err := provider.UpdatePassword("john", "newpassword") assert.NoError(t, err) @@ -342,10 +349,10 @@ func TestShouldUpdatePasswordHashingAlgorithmToSHA512(t *testing.T) { assert.NoError(t, provider.StartupCheck()) - ok, err := provider.CheckUserPassword("john", "newpassword") + ok, err = provider.CheckUserPassword("john", "newpassword") assert.NoError(t, err) assert.True(t, ok) - assert.True(t, strings.HasPrefix(provider.database.Users["john"].Digest.Encode(), "$6$")) + assert.True(t, strings.HasPrefix(db.Users["john"].Digest.Encode(), "$6$")) }) } @@ -657,6 +664,58 @@ func TestNewFileCryptoHashFromConfig(t *testing.T) { } } +func TestHashError(t *testing.T) { + WithDatabase(t, UserDatabaseContent, func(path string) { + config := DefaultFileAuthenticationBackendConfiguration + config.Search.CaseInsensitive = true + config.Path = path + + provider := NewFileUserProvider(&config) + + assert.NoError(t, provider.StartupCheck()) + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mock := NewMockHash(ctrl) + provider.hash = mock + + mock.EXPECT().Hash("apple123").Return(nil, fmt.Errorf("failed to mock hash")) + + assert.EqualError(t, provider.UpdatePassword("john", "apple123"), "failed to mock hash") + }) +} + +func TestDatabaseError(t *testing.T) { + WithDatabase(t, UserDatabaseContent, func(path string) { + db := NewYAMLUserDatabase(path, false, false) + assert.NoError(t, db.Load()) + + config := DefaultFileAuthenticationBackendConfiguration + config.Search.CaseInsensitive = true + config.Path = path + + provider := NewFileUserProvider(&config) + + assert.NoError(t, provider.StartupCheck()) + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mock := NewMockFileUserDatabase(ctrl) + + provider.database = mock + + gomock.InOrder( + mock.EXPECT().GetUserDetails("john").Return(db.GetUserDetails("john")), + mock.EXPECT().SetUserDetails("john", gomock.Any()), + mock.EXPECT().Save().Return(fmt.Errorf("failed to mock save")), + ) + + assert.EqualError(t, provider.UpdatePassword("john", "apple123"), "failed to mock save") + }) +} + var ( DefaultFileAuthenticationBackendConfiguration = schema.FileAuthenticationBackend{ Path: "", diff --git a/internal/authentication/gen.go b/internal/authentication/gen.go index 18547d606..8fe2c052d 100644 --- a/internal/authentication/gen.go +++ b/internal/authentication/gen.go @@ -5,3 +5,5 @@ package authentication //go:generate mockgen -package authentication -destination ldap_client_mock.go -mock_names LDAPClient=MockLDAPClient github.com/authelia/authelia/v4/internal/authentication LDAPClient //go:generate mockgen -package authentication -destination ldap_client_factory_mock.go -mock_names LDAPClientFactory=MockLDAPClientFactory github.com/authelia/authelia/v4/internal/authentication LDAPClientFactory +//go:generate mockgen -package authentication -destination file_user_provider_database_mock_test.go -mock_names FileUserDatabase=MockFileUserDatabase github.com/authelia/authelia/v4/internal/authentication FileUserDatabase +//go:generate mockgen -package authentication -destination file_user_provider_hash_mock_test.go -mock_names Hash=MockHash github.com/go-crypt/crypt/algorithm Hash diff --git a/internal/middlewares/authelia_context_test.go b/internal/middlewares/authelia_context_test.go index bd8d0a50e..13095d3a0 100644 --- a/internal/middlewares/authelia_context_test.go +++ b/internal/middlewares/authelia_context_test.go @@ -154,6 +154,8 @@ func TestIssuerURL(t *testing.T) { func TestShouldCallNextWithAutheliaCtx(t *testing.T) { ctrl := gomock.NewController(t) + defer ctrl.Finish() + ctx := &fasthttp.RequestCtx{} configuration := schema.Configuration{} userProvider := mocks.NewMockUserProvider(ctrl)