summaryrefslogtreecommitdiff
path: root/internal/handlers/handler_firstfactor_test.go
diff options
context:
space:
mode:
authorJames Elliott <james-d-elliott@users.noreply.github.com>2021-11-29 14:09:14 +1100
committerGitHub <noreply@github.com>2021-11-29 14:09:14 +1100
commitbc3b0fda357cb8a3c0e592cfac0c1a9365ab78ef (patch)
tree547ae181489e6792d035d74bba27d4704b9fe3e6 /internal/handlers/handler_firstfactor_test.go
parentd45dac39b9e3694602642113d22d40640adc1675 (diff)
feat(regulator): enhance authentication logs (#2622)
This adds additional logging to the authentication logs such as type, remote IP, request method, redirect URL, and if the attempt was done during a ban. This also means we log attempts that occur when the attempt was blocked by the regulator for record keeping purposes, as well as record 2FA attempts which can be used to inform admins and later to regulate based on other factors. Fixes #116, Fixes #1293.
Diffstat (limited to 'internal/handlers/handler_firstfactor_test.go')
-rw-r--r--internal/handlers/handler_firstfactor_test.go49
1 files changed, 41 insertions, 8 deletions
diff --git a/internal/handlers/handler_firstfactor_test.go b/internal/handlers/handler_firstfactor_test.go
index bcfc5f34a..616eb1591 100644
--- a/internal/handlers/handler_firstfactor_test.go
+++ b/internal/handlers/handler_firstfactor_test.go
@@ -15,6 +15,7 @@ import (
"github.com/authelia/authelia/v4/internal/configuration/schema"
"github.com/authelia/authelia/v4/internal/mocks"
"github.com/authelia/authelia/v4/internal/models"
+ "github.com/authelia/authelia/v4/internal/regulation"
)
type FirstFactorSuite struct {
@@ -35,7 +36,7 @@ func (s *FirstFactorSuite) TestShouldFailIfBodyIsNil() {
FirstFactorPost(0, false)(s.mock.Ctx)
// No body
- assert.Equal(s.T(), "Unable to parse body: unexpected end of JSON input", s.mock.Hook.LastEntry().Message)
+ assert.Equal(s.T(), "Failed to parse 1FA request body: unable to parse body: unexpected end of JSON input", s.mock.Hook.LastEntry().Message)
s.mock.Assert401KO(s.T(), "Authentication failed. Check your credentials.")
}
@@ -46,7 +47,7 @@ func (s *FirstFactorSuite) TestShouldFailIfBodyIsInBadFormat() {
}`)
FirstFactorPost(0, false)(s.mock.Ctx)
- assert.Equal(s.T(), "Unable to validate body: password: non zero value required", s.mock.Hook.LastEntry().Message)
+ assert.Equal(s.T(), "Failed to parse 1FA request body: unable to validate body: password: non zero value required", s.mock.Hook.LastEntry().Message)
s.mock.Assert401KO(s.T(), "Authentication failed. Check your credentials.")
}
@@ -54,14 +55,17 @@ func (s *FirstFactorSuite) TestShouldFailIfUserProviderCheckPasswordFail() {
s.mock.UserProviderMock.
EXPECT().
CheckUserPassword(gomock.Eq("test"), gomock.Eq("hello")).
- Return(false, fmt.Errorf("Failed"))
+ Return(false, fmt.Errorf("failed"))
s.mock.StorageProviderMock.
EXPECT().
AppendAuthenticationLog(s.mock.Ctx, gomock.Eq(models.AuthenticationAttempt{
Username: "test",
Successful: false,
+ Banned: false,
Time: s.mock.Clock.Now(),
+ Type: regulation.AuthType1FA,
+ RemoteIP: models.NewIPAddressFromString("0.0.0.0"),
}))
s.mock.Ctx.Request.SetBodyString(`{
@@ -71,22 +75,51 @@ func (s *FirstFactorSuite) TestShouldFailIfUserProviderCheckPasswordFail() {
}`)
FirstFactorPost(0, false)(s.mock.Ctx)
- assert.Equal(s.T(), "error while checking password for user test: Failed", s.mock.Hook.LastEntry().Message)
+ assert.Equal(s.T(), "Unsuccessful 1FA authentication attempt by user 'test': failed", s.mock.Hook.LastEntry().Message)
s.mock.Assert401KO(s.T(), "Authentication failed. Check your credentials.")
}
+func (s *FirstFactorSuite) TestShouldCheckAuthenticationIsNotMarkedWhenProviderCheckPasswordError() {
+ s.mock.UserProviderMock.
+ EXPECT().
+ CheckUserPassword(gomock.Eq("test"), gomock.Eq("hello")).
+ Return(false, fmt.Errorf("invalid credentials"))
+
+ s.mock.StorageProviderMock.
+ EXPECT().
+ AppendAuthenticationLog(s.mock.Ctx, gomock.Eq(models.AuthenticationAttempt{
+ Username: "test",
+ Successful: false,
+ Banned: false,
+ Time: s.mock.Clock.Now(),
+ Type: regulation.AuthType1FA,
+ RemoteIP: models.NewIPAddressFromString("0.0.0.0"),
+ }))
+
+ s.mock.Ctx.Request.SetBodyString(`{
+ "username": "test",
+ "password": "hello",
+ "keepMeLoggedIn": true
+ }`)
+
+ FirstFactorPost(0, false)(s.mock.Ctx)
+}
+
func (s *FirstFactorSuite) TestShouldCheckAuthenticationIsMarkedWhenInvalidCredentials() {
s.mock.UserProviderMock.
EXPECT().
CheckUserPassword(gomock.Eq("test"), gomock.Eq("hello")).
- Return(false, fmt.Errorf("Invalid credentials"))
+ Return(false, nil)
s.mock.StorageProviderMock.
EXPECT().
AppendAuthenticationLog(s.mock.Ctx, gomock.Eq(models.AuthenticationAttempt{
Username: "test",
Successful: false,
+ Banned: false,
Time: s.mock.Clock.Now(),
+ Type: regulation.AuthType1FA,
+ RemoteIP: models.NewIPAddressFromString("0.0.0.0"),
}))
s.mock.Ctx.Request.SetBodyString(`{
@@ -112,7 +145,7 @@ func (s *FirstFactorSuite) TestShouldFailIfUserProviderGetDetailsFail() {
s.mock.UserProviderMock.
EXPECT().
GetDetails(gomock.Eq("test")).
- Return(nil, fmt.Errorf("Failed"))
+ Return(nil, fmt.Errorf("failed"))
s.mock.Ctx.Request.SetBodyString(`{
"username": "test",
@@ -121,7 +154,7 @@ func (s *FirstFactorSuite) TestShouldFailIfUserProviderGetDetailsFail() {
}`)
FirstFactorPost(0, false)(s.mock.Ctx)
- assert.Equal(s.T(), "error while retrieving details from user test: Failed", s.mock.Hook.LastEntry().Message)
+ assert.Equal(s.T(), "Could not obtain profile details during 1FA authentication for user 'test': failed", s.mock.Hook.LastEntry().Message)
s.mock.Assert401KO(s.T(), "Authentication failed. Check your credentials.")
}
@@ -143,7 +176,7 @@ func (s *FirstFactorSuite) TestShouldFailIfAuthenticationMarkFail() {
}`)
FirstFactorPost(0, false)(s.mock.Ctx)
- assert.Equal(s.T(), "unable to mark authentication: failed", s.mock.Hook.LastEntry().Message)
+ assert.Equal(s.T(), "Unable to mark 1FA authentication attempt by user 'test': failed", s.mock.Hook.LastEntry().Message)
s.mock.Assert401KO(s.T(), "Authentication failed. Check your credentials.")
}