mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
54694c4fca
* [MISC] Ignore errcheck recommendations for legacy code Some of this is likely intended to stay how it is, some could use refactoring, for now we will mark is and ignore it from the linter to be potentially addressed in the future. * [MISC] Ensure files are gofmt-ed
243 lines
6.7 KiB
Go
243 lines
6.7 KiB
Go
package handlers
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/authelia/authelia/internal/mocks"
|
|
"github.com/authelia/authelia/internal/storage"
|
|
|
|
"github.com/golang/mock/gomock"
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/suite"
|
|
)
|
|
|
|
type FetchSuite struct {
|
|
suite.Suite
|
|
mock *mocks.MockAutheliaCtx
|
|
}
|
|
|
|
func (s *FetchSuite) SetupTest() {
|
|
s.mock = mocks.NewMockAutheliaCtx(s.T())
|
|
// Set the initial user session.
|
|
userSession := s.mock.Ctx.GetSession()
|
|
userSession.Username = "john"
|
|
userSession.AuthenticationLevel = 1
|
|
s.mock.Ctx.SaveSession(userSession) //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting.
|
|
}
|
|
|
|
func (s *FetchSuite) TearDownTest() {
|
|
s.mock.Close()
|
|
}
|
|
|
|
func setPreferencesExpectations(preferences UserPreferences, provider *storage.MockProvider) {
|
|
provider.
|
|
EXPECT().
|
|
LoadPreferred2FAMethod(gomock.Eq("john")).
|
|
Return(preferences.Method, nil)
|
|
|
|
if preferences.HasU2F {
|
|
u2fData := []byte("abc")
|
|
provider.
|
|
EXPECT().
|
|
LoadU2FDeviceHandle(gomock.Eq("john")).
|
|
Return(u2fData, u2fData, nil)
|
|
} else {
|
|
provider.
|
|
EXPECT().
|
|
LoadU2FDeviceHandle(gomock.Eq("john")).
|
|
Return(nil, nil, storage.ErrNoU2FDeviceHandle)
|
|
}
|
|
|
|
if preferences.HasTOTP {
|
|
totpSecret := "secret"
|
|
provider.
|
|
EXPECT().
|
|
LoadTOTPSecret(gomock.Eq("john")).
|
|
Return(totpSecret, nil)
|
|
} else {
|
|
provider.
|
|
EXPECT().
|
|
LoadTOTPSecret(gomock.Eq("john")).
|
|
Return("", storage.ErrNoTOTPSecret)
|
|
}
|
|
}
|
|
|
|
func TestMethodSetToU2F(t *testing.T) {
|
|
table := []UserPreferences{
|
|
{
|
|
Method: "totp",
|
|
},
|
|
{
|
|
Method: "u2f",
|
|
HasU2F: true,
|
|
HasTOTP: true,
|
|
},
|
|
{
|
|
Method: "u2f",
|
|
HasU2F: true,
|
|
HasTOTP: false,
|
|
},
|
|
{
|
|
Method: "mobile_push",
|
|
HasU2F: false,
|
|
HasTOTP: false,
|
|
},
|
|
}
|
|
|
|
for _, expectedPreferences := range table {
|
|
mock := mocks.NewMockAutheliaCtx(t)
|
|
// Set the initial user session.
|
|
userSession := mock.Ctx.GetSession()
|
|
userSession.Username = "john"
|
|
userSession.AuthenticationLevel = 1
|
|
mock.Ctx.SaveSession(userSession) //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting.
|
|
|
|
setPreferencesExpectations(expectedPreferences, mock.StorageProviderMock)
|
|
UserInfoGet(mock.Ctx)
|
|
|
|
actualPreferences := UserPreferences{}
|
|
mock.GetResponseData(t, &actualPreferences)
|
|
|
|
t.Run("expected method", func(t *testing.T) {
|
|
assert.Equal(t, expectedPreferences.Method, actualPreferences.Method)
|
|
})
|
|
|
|
t.Run("registered u2f", func(t *testing.T) {
|
|
assert.Equal(t, expectedPreferences.HasU2F, actualPreferences.HasU2F)
|
|
})
|
|
|
|
t.Run("registered totp", func(t *testing.T) {
|
|
assert.Equal(t, expectedPreferences.HasTOTP, actualPreferences.HasTOTP)
|
|
})
|
|
mock.Close()
|
|
}
|
|
}
|
|
|
|
func (s *FetchSuite) TestShouldGetDefaultPreferenceIfNotInDB() {
|
|
s.mock.StorageProviderMock.
|
|
EXPECT().
|
|
LoadPreferred2FAMethod(gomock.Eq("john")).
|
|
Return("", nil)
|
|
|
|
s.mock.StorageProviderMock.
|
|
EXPECT().
|
|
LoadU2FDeviceHandle(gomock.Eq("john")).
|
|
Return(nil, nil, storage.ErrNoU2FDeviceHandle)
|
|
|
|
s.mock.StorageProviderMock.
|
|
EXPECT().
|
|
LoadTOTPSecret(gomock.Eq("john")).
|
|
Return("", storage.ErrNoTOTPSecret)
|
|
|
|
UserInfoGet(s.mock.Ctx)
|
|
s.mock.Assert200OK(s.T(), UserPreferences{Method: "totp"})
|
|
}
|
|
|
|
func (s *FetchSuite) TestShouldReturnError500WhenStorageFailsToLoad() {
|
|
s.mock.StorageProviderMock.EXPECT().
|
|
LoadPreferred2FAMethod(gomock.Eq("john")).
|
|
Return("", fmt.Errorf("Failure"))
|
|
|
|
s.mock.StorageProviderMock.
|
|
EXPECT().
|
|
LoadU2FDeviceHandle(gomock.Eq("john"))
|
|
|
|
s.mock.StorageProviderMock.
|
|
EXPECT().
|
|
LoadTOTPSecret(gomock.Eq("john"))
|
|
|
|
UserInfoGet(s.mock.Ctx)
|
|
|
|
s.mock.Assert200KO(s.T(), "Operation failed.")
|
|
assert.Equal(s.T(), "Unable to load user information", s.mock.Hook.LastEntry().Message)
|
|
assert.Equal(s.T(), logrus.ErrorLevel, s.mock.Hook.LastEntry().Level)
|
|
}
|
|
|
|
func TestFetchSuite(t *testing.T) {
|
|
suite.Run(t, &FetchSuite{})
|
|
}
|
|
|
|
type SaveSuite struct {
|
|
suite.Suite
|
|
mock *mocks.MockAutheliaCtx
|
|
}
|
|
|
|
func (s *SaveSuite) SetupTest() {
|
|
s.mock = mocks.NewMockAutheliaCtx(s.T())
|
|
// Set the initial user session.
|
|
userSession := s.mock.Ctx.GetSession()
|
|
userSession.Username = "john"
|
|
userSession.AuthenticationLevel = 1
|
|
s.mock.Ctx.SaveSession(userSession) //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting.
|
|
}
|
|
|
|
func (s *SaveSuite) TearDownTest() {
|
|
s.mock.Close()
|
|
}
|
|
|
|
func (s *SaveSuite) TestShouldReturnError500WhenNoBodyProvided() {
|
|
s.mock.Ctx.Request.SetBody(nil)
|
|
MethodPreferencePost(s.mock.Ctx)
|
|
|
|
s.mock.Assert200KO(s.T(), "Operation failed.")
|
|
assert.Equal(s.T(), "Unable to parse body: unexpected end of JSON input", s.mock.Hook.LastEntry().Message)
|
|
assert.Equal(s.T(), logrus.ErrorLevel, s.mock.Hook.LastEntry().Level)
|
|
}
|
|
|
|
func (s *SaveSuite) TestShouldReturnError500WhenMalformedBodyProvided() {
|
|
s.mock.Ctx.Request.SetBody([]byte("{\"method\":\"abc\""))
|
|
MethodPreferencePost(s.mock.Ctx)
|
|
|
|
s.mock.Assert200KO(s.T(), "Operation failed.")
|
|
assert.Equal(s.T(), "Unable to parse body: unexpected end of JSON input", s.mock.Hook.LastEntry().Message)
|
|
assert.Equal(s.T(), logrus.ErrorLevel, s.mock.Hook.LastEntry().Level)
|
|
}
|
|
|
|
func (s *SaveSuite) TestShouldReturnError500WhenBadBodyProvided() {
|
|
s.mock.Ctx.Request.SetBody([]byte("{\"weird_key\":\"abc\"}"))
|
|
MethodPreferencePost(s.mock.Ctx)
|
|
|
|
s.mock.Assert200KO(s.T(), "Operation failed.")
|
|
assert.Equal(s.T(), "Unable to validate body: method: non zero value required", s.mock.Hook.LastEntry().Message)
|
|
assert.Equal(s.T(), logrus.ErrorLevel, s.mock.Hook.LastEntry().Level)
|
|
}
|
|
|
|
func (s *SaveSuite) TestShouldReturnError500WhenBadMethodProvided() {
|
|
s.mock.Ctx.Request.SetBody([]byte("{\"method\":\"abc\"}"))
|
|
MethodPreferencePost(s.mock.Ctx)
|
|
|
|
s.mock.Assert200KO(s.T(), "Operation failed.")
|
|
assert.Equal(s.T(), "Unknown method 'abc', it should be one of totp, u2f, mobile_push", s.mock.Hook.LastEntry().Message)
|
|
assert.Equal(s.T(), logrus.ErrorLevel, s.mock.Hook.LastEntry().Level)
|
|
}
|
|
|
|
func (s *SaveSuite) TestShouldReturnError500WhenDatabaseFailsToSave() {
|
|
s.mock.Ctx.Request.SetBody([]byte("{\"method\":\"u2f\"}"))
|
|
s.mock.StorageProviderMock.EXPECT().
|
|
SavePreferred2FAMethod(gomock.Eq("john"), gomock.Eq("u2f")).
|
|
Return(fmt.Errorf("Failure"))
|
|
|
|
MethodPreferencePost(s.mock.Ctx)
|
|
|
|
s.mock.Assert200KO(s.T(), "Operation failed.")
|
|
assert.Equal(s.T(), "Unable to save new preferred 2FA method: Failure", s.mock.Hook.LastEntry().Message)
|
|
assert.Equal(s.T(), logrus.ErrorLevel, s.mock.Hook.LastEntry().Level)
|
|
}
|
|
|
|
func (s *SaveSuite) TestShouldReturn200WhenMethodIsSuccessfullySaved() {
|
|
s.mock.Ctx.Request.SetBody([]byte("{\"method\":\"u2f\"}"))
|
|
s.mock.StorageProviderMock.EXPECT().
|
|
SavePreferred2FAMethod(gomock.Eq("john"), gomock.Eq("u2f")).
|
|
Return(nil)
|
|
|
|
MethodPreferencePost(s.mock.Ctx)
|
|
|
|
assert.Equal(s.T(), 200, s.mock.Ctx.Response.StatusCode())
|
|
}
|
|
|
|
func TestSaveSuite(t *testing.T) {
|
|
suite.Run(t, &SaveSuite{})
|
|
}
|