diff --git a/internal/handlers/handler_checks_safe_redirection.go b/internal/handlers/handler_checks_safe_redirection.go index a9fe93605..83b7918dd 100644 --- a/internal/handlers/handler_checks_safe_redirection.go +++ b/internal/handlers/handler_checks_safe_redirection.go @@ -8,8 +8,8 @@ import ( "github.com/authelia/authelia/v4/internal/utils" ) -// CheckSafeRedirection handler checking whether the redirection to a given URL provided in body is safe. -func CheckSafeRedirection(ctx *middlewares.AutheliaCtx) { +// CheckSafeRedirectionPOST handler checking whether the redirection to a given URL provided in body is safe. +func CheckSafeRedirectionPOST(ctx *middlewares.AutheliaCtx) { userSession := ctx.GetSession() if userSession.AuthenticationLevel == authentication.NotAuthenticated { diff --git a/internal/handlers/handler_checks_safe_redirection_test.go b/internal/handlers/handler_checks_safe_redirection_test.go index acae2b0c9..807588deb 100644 --- a/internal/handlers/handler_checks_safe_redirection_test.go +++ b/internal/handlers/handler_checks_safe_redirection_test.go @@ -24,7 +24,7 @@ func TestCheckSafeRedirection_ForbiddenCall(t *testing.T) { URI: "http://myapp.example.com", }) - CheckSafeRedirection(mock.Ctx) + CheckSafeRedirectionPOST(mock.Ctx) assert.Equal(t, 401, mock.Ctx.Response.StatusCode()) } @@ -40,7 +40,7 @@ func TestCheckSafeRedirection_UnsafeRedirection(t *testing.T) { URI: "http://myapp.com", }) - CheckSafeRedirection(mock.Ctx) + CheckSafeRedirectionPOST(mock.Ctx) mock.Assert200OK(t, checkURIWithinDomainResponseBody{ OK: false, }) @@ -58,7 +58,7 @@ func TestCheckSafeRedirection_SafeRedirection(t *testing.T) { URI: "https://myapp.example.com", }) - CheckSafeRedirection(mock.Ctx) + CheckSafeRedirectionPOST(mock.Ctx) mock.Assert200OK(t, checkURIWithinDomainResponseBody{ OK: true, }) diff --git a/internal/handlers/handler_configuration.go b/internal/handlers/handler_configuration.go index d053b56e5..fec29c4ad 100644 --- a/internal/handlers/handler_configuration.go +++ b/internal/handlers/handler_configuration.go @@ -4,8 +4,8 @@ import ( "github.com/authelia/authelia/v4/internal/middlewares" ) -// ConfigurationGet get the configuration accessible to authenticated users. -func ConfigurationGet(ctx *middlewares.AutheliaCtx) { +// ConfigurationGET get the configuration accessible to authenticated users. +func ConfigurationGET(ctx *middlewares.AutheliaCtx) { body := configurationBody{ AvailableMethods: make(MethodList, 0, 3), } diff --git a/internal/handlers/handler_configuration_test.go b/internal/handlers/handler_configuration_test.go index f1f11e080..480f80e2c 100644 --- a/internal/handlers/handler_configuration_test.go +++ b/internal/handlers/handler_configuration_test.go @@ -49,7 +49,7 @@ func (s *SecondFactorAvailableMethodsFixture) TestShouldHaveAllConfiguredMethods s.mock.Ctx.Providers.Authorizer = authorization.NewAuthorizer(&s.mock.Ctx.Configuration) - ConfigurationGet(s.mock.Ctx) + ConfigurationGET(s.mock.Ctx) s.mock.Assert200OK(s.T(), configurationBody{ AvailableMethods: []string{"totp", "webauthn", "mobile_push"}, @@ -77,7 +77,7 @@ func (s *SecondFactorAvailableMethodsFixture) TestShouldRemoveTOTPFromAvailableM s.mock.Ctx.Providers.Authorizer = authorization.NewAuthorizer(&s.mock.Ctx.Configuration) - ConfigurationGet(s.mock.Ctx) + ConfigurationGET(s.mock.Ctx) s.mock.Assert200OK(s.T(), configurationBody{ AvailableMethods: []string{"webauthn", "mobile_push"}, @@ -105,7 +105,7 @@ func (s *SecondFactorAvailableMethodsFixture) TestShouldRemoveWebauthnFromAvaila s.mock.Ctx.Providers.Authorizer = authorization.NewAuthorizer(&s.mock.Ctx.Configuration) - ConfigurationGet(s.mock.Ctx) + ConfigurationGET(s.mock.Ctx) s.mock.Assert200OK(s.T(), configurationBody{ AvailableMethods: []string{"totp", "mobile_push"}, @@ -133,7 +133,7 @@ func (s *SecondFactorAvailableMethodsFixture) TestShouldRemoveDuoFromAvailableMe s.mock.Ctx.Providers.Authorizer = authorization.NewAuthorizer(&s.mock.Ctx.Configuration) - ConfigurationGet(s.mock.Ctx) + ConfigurationGET(s.mock.Ctx) s.mock.Assert200OK(s.T(), configurationBody{ AvailableMethods: []string{"totp", "webauthn"}, @@ -161,7 +161,7 @@ func (s *SecondFactorAvailableMethodsFixture) TestShouldRemoveAllMethodsWhenNoTw s.mock.Ctx.Providers.Authorizer = authorization.NewAuthorizer(&s.mock.Ctx.Configuration) - ConfigurationGet(s.mock.Ctx) + ConfigurationGET(s.mock.Ctx) s.mock.Assert200OK(s.T(), configurationBody{ AvailableMethods: []string{}, @@ -189,7 +189,7 @@ func (s *SecondFactorAvailableMethodsFixture) TestShouldRemoveAllMethodsWhenAllD s.mock.Ctx.Providers.Authorizer = authorization.NewAuthorizer(&s.mock.Ctx.Configuration) - ConfigurationGet(s.mock.Ctx) + ConfigurationGET(s.mock.Ctx) s.mock.Assert200OK(s.T(), configurationBody{ AvailableMethods: []string{}, diff --git a/internal/handlers/handler_firstfactor.go b/internal/handlers/handler_firstfactor.go index ca5b05690..97d90aeaf 100644 --- a/internal/handlers/handler_firstfactor.go +++ b/internal/handlers/handler_firstfactor.go @@ -10,9 +10,9 @@ import ( "github.com/authelia/authelia/v4/internal/session" ) -// FirstFactorPost is the handler performing the first factory. +// FirstFactorPOST is the handler performing the first factory. //nolint:gocyclo // TODO: Consider refactoring time permitting. -func FirstFactorPost(delayFunc middlewares.TimingAttackDelayFunc) middlewares.RequestHandler { +func FirstFactorPOST(delayFunc middlewares.TimingAttackDelayFunc) middlewares.RequestHandler { return func(ctx *middlewares.AutheliaCtx) { var successful bool diff --git a/internal/handlers/handler_firstfactor_test.go b/internal/handlers/handler_firstfactor_test.go index 4255992cd..55499f320 100644 --- a/internal/handlers/handler_firstfactor_test.go +++ b/internal/handlers/handler_firstfactor_test.go @@ -31,7 +31,7 @@ func (s *FirstFactorSuite) TearDownTest() { } func (s *FirstFactorSuite) TestShouldFailIfBodyIsNil() { - FirstFactorPost(nil)(s.mock.Ctx) + FirstFactorPOST(nil)(s.mock.Ctx) // No body. assert.Equal(s.T(), "Failed to parse 1FA request body: unable to parse body: unexpected end of JSON input", s.mock.Hook.LastEntry().Message) @@ -43,7 +43,7 @@ func (s *FirstFactorSuite) TestShouldFailIfBodyIsInBadFormat() { s.mock.Ctx.Request.SetBodyString(`{ "username": "test" }`) - FirstFactorPost(nil)(s.mock.Ctx) + FirstFactorPOST(nil)(s.mock.Ctx) 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.") @@ -71,7 +71,7 @@ func (s *FirstFactorSuite) TestShouldFailIfUserProviderCheckPasswordFail() { "password": "hello", "keepMeLoggedIn": true }`) - FirstFactorPost(nil)(s.mock.Ctx) + FirstFactorPOST(nil)(s.mock.Ctx) 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.") @@ -100,7 +100,7 @@ func (s *FirstFactorSuite) TestShouldCheckAuthenticationIsNotMarkedWhenProviderC "keepMeLoggedIn": true }`) - FirstFactorPost(nil)(s.mock.Ctx) + FirstFactorPOST(nil)(s.mock.Ctx) } func (s *FirstFactorSuite) TestShouldCheckAuthenticationIsMarkedWhenInvalidCredentials() { @@ -126,7 +126,7 @@ func (s *FirstFactorSuite) TestShouldCheckAuthenticationIsMarkedWhenInvalidCrede "keepMeLoggedIn": true }`) - FirstFactorPost(nil)(s.mock.Ctx) + FirstFactorPOST(nil)(s.mock.Ctx) } func (s *FirstFactorSuite) TestShouldFailIfUserProviderGetDetailsFail() { @@ -150,7 +150,7 @@ func (s *FirstFactorSuite) TestShouldFailIfUserProviderGetDetailsFail() { "password": "hello", "keepMeLoggedIn": true }`) - FirstFactorPost(nil)(s.mock.Ctx) + FirstFactorPOST(nil)(s.mock.Ctx) 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.") @@ -172,7 +172,7 @@ func (s *FirstFactorSuite) TestShouldFailIfAuthenticationMarkFail() { "password": "hello", "keepMeLoggedIn": true }`) - FirstFactorPost(nil)(s.mock.Ctx) + FirstFactorPOST(nil)(s.mock.Ctx) 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.") @@ -203,7 +203,7 @@ func (s *FirstFactorSuite) TestShouldAuthenticateUserWithRememberMeChecked() { "password": "hello", "keepMeLoggedIn": true }`) - FirstFactorPost(nil)(s.mock.Ctx) + FirstFactorPOST(nil)(s.mock.Ctx) // Respond with 200. assert.Equal(s.T(), 200, s.mock.Ctx.Response.StatusCode()) @@ -244,7 +244,7 @@ func (s *FirstFactorSuite) TestShouldAuthenticateUserWithRememberMeUnchecked() { "requestMethod": "GET", "keepMeLoggedIn": false }`) - FirstFactorPost(nil)(s.mock.Ctx) + FirstFactorPOST(nil)(s.mock.Ctx) // Respond with 200. assert.Equal(s.T(), 200, s.mock.Ctx.Response.StatusCode()) @@ -288,7 +288,7 @@ func (s *FirstFactorSuite) TestShouldSaveUsernameFromAuthenticationBackendInSess "requestMethod": "GET", "keepMeLoggedIn": true }`) - FirstFactorPost(nil)(s.mock.Ctx) + FirstFactorPOST(nil)(s.mock.Ctx) // Respond with 200. assert.Equal(s.T(), 200, s.mock.Ctx.Response.StatusCode()) @@ -358,7 +358,7 @@ func (s *FirstFactorRedirectionSuite) TestShouldRedirectToDefaultURLWhenNoTarget "requestMethod": "GET", "keepMeLoggedIn": false }`) - FirstFactorPost(nil)(s.mock.Ctx) + FirstFactorPOST(nil)(s.mock.Ctx) // Respond with 200. s.mock.Assert200OK(s.T(), redirectResponse{Redirect: "https://default.local"}) @@ -379,7 +379,7 @@ func (s *FirstFactorRedirectionSuite) TestShouldRedirectToDefaultURLWhenURLIsUns "targetURL": "http://notsafe.local" }`) - FirstFactorPost(nil)(s.mock.Ctx) + FirstFactorPOST(nil)(s.mock.Ctx) // Respond with 200. s.mock.Assert200OK(s.T(), redirectResponse{Redirect: "https://default.local"}) @@ -402,7 +402,7 @@ func (s *FirstFactorRedirectionSuite) TestShouldReply200WhenNoTargetURLProvidedA "keepMeLoggedIn": false }`) - FirstFactorPost(nil)(s.mock.Ctx) + FirstFactorPOST(nil)(s.mock.Ctx) // Respond with 200. s.mock.Assert200OK(s.T(), nil) @@ -434,7 +434,7 @@ func (s *FirstFactorRedirectionSuite) TestShouldReply200WhenUnsafeTargetURLProvi "keepMeLoggedIn": false }`) - FirstFactorPost(nil)(s.mock.Ctx) + FirstFactorPOST(nil)(s.mock.Ctx) // Respond with 200. s.mock.Assert200OK(s.T(), nil) diff --git a/internal/handlers/handler_health.go b/internal/handlers/handler_health.go index 13fd4af08..b67c90e02 100644 --- a/internal/handlers/handler_health.go +++ b/internal/handlers/handler_health.go @@ -4,7 +4,7 @@ import ( "github.com/authelia/authelia/v4/internal/middlewares" ) -// HealthGet can be used by health checks. -func HealthGet(ctx *middlewares.AutheliaCtx) { +// HealthGET can be used by health checks. +func HealthGET(ctx *middlewares.AutheliaCtx) { ctx.ReplyOK() } diff --git a/internal/handlers/handler_logout.go b/internal/handlers/handler_logout.go index 007ef0244..b00f1d72a 100644 --- a/internal/handlers/handler_logout.go +++ b/internal/handlers/handler_logout.go @@ -16,8 +16,8 @@ type logoutResponseBody struct { SafeTargetURL bool `json:"safeTargetURL"` } -// LogoutPost is the handler logging out the user attached to the given cookie. -func LogoutPost(ctx *middlewares.AutheliaCtx) { +// LogoutPOST is the handler logging out the user attached to the given cookie. +func LogoutPOST(ctx *middlewares.AutheliaCtx) { body := logoutBody{} responseBody := logoutResponseBody{SafeTargetURL: false} diff --git a/internal/handlers/handler_logout_test.go b/internal/handlers/handler_logout_test.go index b8ab630eb..1b14f2e1a 100644 --- a/internal/handlers/handler_logout_test.go +++ b/internal/handlers/handler_logout_test.go @@ -30,7 +30,7 @@ func (s *LogoutSuite) TearDownTest() { } func (s *LogoutSuite) TestShouldDestroySession() { - LogoutPost(s.mock.Ctx) + LogoutPOST(s.mock.Ctx) b := s.mock.Ctx.Response.Header.PeekCookie("authelia_session") // Reset the cookie, meaning it resets the value and expires the cookie by setting diff --git a/internal/handlers/handler_register_duo_device.go b/internal/handlers/handler_register_duo_device.go index 4d613aa96..8182cbdce 100644 --- a/internal/handlers/handler_register_duo_device.go +++ b/internal/handlers/handler_register_duo_device.go @@ -11,8 +11,8 @@ import ( "github.com/authelia/authelia/v4/internal/utils" ) -// SecondFactorDuoDevicesGet handler for retrieving available devices and capabilities from duo api. -func SecondFactorDuoDevicesGet(duoAPI duo.API) middlewares.RequestHandler { +// DuoDevicesGET handler for retrieving available devices and capabilities from duo api. +func DuoDevicesGET(duoAPI duo.API) middlewares.RequestHandler { return func(ctx *middlewares.AutheliaCtx) { userSession := ctx.GetSession() values := url.Values{} @@ -78,8 +78,8 @@ func SecondFactorDuoDevicesGet(duoAPI duo.API) middlewares.RequestHandler { } } -// SecondFactorDuoDevicePost update the user preferences regarding Duo device and method. -func SecondFactorDuoDevicePost(ctx *middlewares.AutheliaCtx) { +// DuoDevicePOST update the user preferences regarding Duo device and method. +func DuoDevicePOST(ctx *middlewares.AutheliaCtx) { device := DuoDeviceBody{} err := ctx.ParseBody(&device) diff --git a/internal/handlers/handler_register_duo_device_test.go b/internal/handlers/handler_register_duo_device_test.go index f55696834..cd77e8a39 100644 --- a/internal/handlers/handler_register_duo_device_test.go +++ b/internal/handlers/handler_register_duo_device_test.go @@ -40,7 +40,7 @@ func (s *RegisterDuoDeviceSuite) TestShouldCallDuoAPIAndFail() { duoMock.EXPECT().PreAuthCall(s.mock.Ctx, gomock.Eq(values)).Return(nil, fmt.Errorf("Connnection error")) - SecondFactorDuoDevicesGet(duoMock)(s.mock.Ctx) + DuoDevicesGET(duoMock)(s.mock.Ctx) s.mock.Assert200KO(s.T(), "Authentication failed, please retry later.") assert.Equal(s.T(), "duo PreAuth API errored: Connnection error", s.mock.Hook.LastEntry().Message) @@ -70,7 +70,7 @@ func (s *RegisterDuoDeviceSuite) TestShouldRespondWithSelection() { duoMock.EXPECT().PreAuthCall(s.mock.Ctx, gomock.Eq(values)).Return(&response, nil) - SecondFactorDuoDevicesGet(duoMock)(s.mock.Ctx) + DuoDevicesGET(duoMock)(s.mock.Ctx) s.mock.Assert200OK(s.T(), DuoDevicesResponse{Result: auth, Devices: apiDevices}) } @@ -86,7 +86,7 @@ func (s *RegisterDuoDeviceSuite) TestShouldRespondWithAllowOnBypass() { duoMock.EXPECT().PreAuthCall(s.mock.Ctx, gomock.Eq(values)).Return(&response, nil) - SecondFactorDuoDevicesGet(duoMock)(s.mock.Ctx) + DuoDevicesGET(duoMock)(s.mock.Ctx) s.mock.Assert200OK(s.T(), DuoDevicesResponse{Result: allow}) } @@ -105,7 +105,7 @@ func (s *RegisterDuoDeviceSuite) TestShouldRespondWithEnroll() { duoMock.EXPECT().PreAuthCall(s.mock.Ctx, gomock.Eq(values)).Return(&response, nil) - SecondFactorDuoDevicesGet(duoMock)(s.mock.Ctx) + DuoDevicesGET(duoMock)(s.mock.Ctx) s.mock.Assert200OK(s.T(), DuoDevicesResponse{Result: enroll, EnrollURL: enrollURL}) } @@ -121,7 +121,7 @@ func (s *RegisterDuoDeviceSuite) TestShouldRespondWithDeny() { duoMock.EXPECT().PreAuthCall(s.mock.Ctx, gomock.Eq(values)).Return(&response, nil) - SecondFactorDuoDevicesGet(duoMock)(s.mock.Ctx) + DuoDevicesGET(duoMock)(s.mock.Ctx) s.mock.Assert200OK(s.T(), DuoDevicesResponse{Result: deny}) } @@ -132,7 +132,7 @@ func (s *RegisterDuoDeviceSuite) TestShouldRespondOK() { SavePreferredDuoDevice(gomock.Eq(s.mock.Ctx), gomock.Eq(model.DuoDevice{Username: "john", Device: "1234567890123456", Method: "push"})). Return(nil) - SecondFactorDuoDevicePost(s.mock.Ctx) + DuoDevicePOST(s.mock.Ctx) assert.Equal(s.T(), 200, s.mock.Ctx.Response.StatusCode()) } @@ -140,7 +140,7 @@ func (s *RegisterDuoDeviceSuite) TestShouldRespondOK() { func (s *RegisterDuoDeviceSuite) TestShouldRespondKOOnInvalidMethod() { s.mock.Ctx.Request.SetBodyString("{\"device\":\"1234567890123456\", \"method\":\"testfailure\"}") - SecondFactorDuoDevicePost(s.mock.Ctx) + DuoDevicePOST(s.mock.Ctx) s.mock.Assert200KO(s.T(), "Authentication failed, please retry later.") assert.Equal(s.T(), logrus.ErrorLevel, s.mock.Hook.LastEntry().Level) @@ -149,7 +149,7 @@ func (s *RegisterDuoDeviceSuite) TestShouldRespondKOOnInvalidMethod() { func (s *RegisterDuoDeviceSuite) TestShouldRespondKOOnEmptyMethod() { s.mock.Ctx.Request.SetBodyString("{\"device\":\"1234567890123456\", \"method\":\"\"}") - SecondFactorDuoDevicePost(s.mock.Ctx) + DuoDevicePOST(s.mock.Ctx) s.mock.Assert200KO(s.T(), "Authentication failed, please retry later.") assert.Equal(s.T(), "unable to validate body: method: non zero value required", s.mock.Hook.LastEntry().Message) @@ -159,7 +159,7 @@ func (s *RegisterDuoDeviceSuite) TestShouldRespondKOOnEmptyMethod() { func (s *RegisterDuoDeviceSuite) TestShouldRespondKOOnEmptyDevice() { s.mock.Ctx.Request.SetBodyString("{\"device\":\"\", \"method\":\"push\"}") - SecondFactorDuoDevicePost(s.mock.Ctx) + DuoDevicePOST(s.mock.Ctx) s.mock.Assert200KO(s.T(), "Authentication failed, please retry later.") assert.Equal(s.T(), "unable to validate body: device: non zero value required", s.mock.Hook.LastEntry().Message) diff --git a/internal/handlers/handler_register_totp.go b/internal/handlers/handler_register_totp.go index b4275b232..ae6326584 100644 --- a/internal/handlers/handler_register_totp.go +++ b/internal/handlers/handler_register_totp.go @@ -26,8 +26,8 @@ func isTokenUserValidFor2FARegistration(ctx *middlewares.AutheliaCtx, username s return ctx.GetSession().Username == username } -// SecondFactorTOTPIdentityStart the handler for initiating the identity validation. -var SecondFactorTOTPIdentityStart = middlewares.IdentityVerificationStart(middlewares.IdentityVerificationStartArgs{ +// TOTPIdentityStart the handler for initiating the identity validation. +var TOTPIdentityStart = middlewares.IdentityVerificationStart(middlewares.IdentityVerificationStartArgs{ MailTitle: "Register your mobile", MailButtonContent: "Register", TargetEndpoint: "/one-time-password/register", @@ -35,7 +35,7 @@ var SecondFactorTOTPIdentityStart = middlewares.IdentityVerificationStart(middle IdentityRetrieverFunc: identityRetrieverFromSession, }, nil) -func secondFactorTOTPIdentityFinish(ctx *middlewares.AutheliaCtx, username string) { +func totpIdentityFinish(ctx *middlewares.AutheliaCtx, username string) { var ( config *model.TOTPConfiguration err error @@ -62,9 +62,9 @@ func secondFactorTOTPIdentityFinish(ctx *middlewares.AutheliaCtx, username strin } } -// SecondFactorTOTPIdentityFinish the handler for finishing the identity validation. -var SecondFactorTOTPIdentityFinish = middlewares.IdentityVerificationFinish( +// TOTPIdentityFinish the handler for finishing the identity validation. +var TOTPIdentityFinish = middlewares.IdentityVerificationFinish( middlewares.IdentityVerificationFinishArgs{ ActionClaim: ActionTOTPRegistration, IsTokenUserValidFunc: isTokenUserValidFor2FARegistration, - }, secondFactorTOTPIdentityFinish) + }, totpIdentityFinish) diff --git a/internal/handlers/handler_register_webauthn.go b/internal/handlers/handler_register_webauthn.go index 70b6dcb80..60f89d254 100644 --- a/internal/handlers/handler_register_webauthn.go +++ b/internal/handlers/handler_register_webauthn.go @@ -12,8 +12,8 @@ import ( "github.com/authelia/authelia/v4/internal/regulation" ) -// SecondFactorWebauthnIdentityStart the handler for initiating the identity validation. -var SecondFactorWebauthnIdentityStart = middlewares.IdentityVerificationStart(middlewares.IdentityVerificationStartArgs{ +// WebauthnIdentityStart the handler for initiating the identity validation. +var WebauthnIdentityStart = middlewares.IdentityVerificationStart(middlewares.IdentityVerificationStartArgs{ MailTitle: "Register your key", MailButtonContent: "Register", TargetEndpoint: "/webauthn/register", @@ -21,8 +21,8 @@ var SecondFactorWebauthnIdentityStart = middlewares.IdentityVerificationStart(mi IdentityRetrieverFunc: identityRetrieverFromSession, }, nil) -// SecondFactorWebauthnIdentityFinish the handler for finishing the identity validation. -var SecondFactorWebauthnIdentityFinish = middlewares.IdentityVerificationFinish( +// WebauthnIdentityFinish the handler for finishing the identity validation. +var WebauthnIdentityFinish = middlewares.IdentityVerificationFinish( middlewares.IdentityVerificationFinishArgs{ ActionClaim: ActionWebauthnRegistration, IsTokenUserValidFunc: isTokenUserValidFor2FARegistration, @@ -81,8 +81,8 @@ func SecondFactorWebauthnAttestationGET(ctx *middlewares.AutheliaCtx, _ string) } } -// SecondFactorWebauthnAttestationPOST processes the attestation challenge response from the client. -func SecondFactorWebauthnAttestationPOST(ctx *middlewares.AutheliaCtx) { +// WebauthnAttestationPOST processes the attestation challenge response from the client. +func WebauthnAttestationPOST(ctx *middlewares.AutheliaCtx) { var ( err error w *webauthn.WebAuthn diff --git a/internal/handlers/handler_reset_password_step2.go b/internal/handlers/handler_reset_password_step2.go index 7950f7b07..69a77caf1 100644 --- a/internal/handlers/handler_reset_password_step2.go +++ b/internal/handlers/handler_reset_password_step2.go @@ -9,8 +9,8 @@ import ( "github.com/authelia/authelia/v4/internal/utils" ) -// ResetPasswordPost handler for resetting passwords. -func ResetPasswordPost(ctx *middlewares.AutheliaCtx) { +// ResetPasswordPOST handler for resetting passwords. +func ResetPasswordPOST(ctx *middlewares.AutheliaCtx) { userSession := ctx.GetSession() // Those checks unsure that the identity verification process has been initiated and completed successfully diff --git a/internal/handlers/handler_sign_duo.go b/internal/handlers/handler_sign_duo.go index 880ffdb25..6099b65a4 100644 --- a/internal/handlers/handler_sign_duo.go +++ b/internal/handlers/handler_sign_duo.go @@ -12,8 +12,8 @@ import ( "github.com/authelia/authelia/v4/internal/utils" ) -// SecondFactorDuoPost handler for sending a push notification via duo api. -func SecondFactorDuoPost(duoAPI duo.API) middlewares.RequestHandler { +// DuoPOST handler for sending a push notification via duo api. +func DuoPOST(duoAPI duo.API) middlewares.RequestHandler { return func(ctx *middlewares.AutheliaCtx) { var ( requestBody signDuoRequestBody diff --git a/internal/handlers/handler_sign_duo_test.go b/internal/handlers/handler_sign_duo_test.go index 524a3066b..8cae6ce6f 100644 --- a/internal/handlers/handler_sign_duo_test.go +++ b/internal/handlers/handler_sign_duo_test.go @@ -58,7 +58,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldEnroll() { s.Require().NoError(err) s.mock.Ctx.Request.SetBody(bodyBytes) - SecondFactorDuoPost(duoMock)(s.mock.Ctx) + DuoPOST(duoMock)(s.mock.Ctx) s.mock.Assert200OK(s.T(), DuoSignResponse{ Result: enroll, @@ -117,7 +117,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldAutoSelect() { s.Require().NoError(err) s.mock.Ctx.Request.SetBody(bodyBytes) - SecondFactorDuoPost(duoMock)(s.mock.Ctx) + DuoPOST(duoMock)(s.mock.Ctx) assert.Equal(s.T(), 200, s.mock.Ctx.Response.StatusCode()) } @@ -146,7 +146,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldDenyAutoSelect() { s.Require().NoError(err) s.mock.Ctx.Request.SetBody(bodyBytes) - SecondFactorDuoPost(duoMock)(s.mock.Ctx) + DuoPOST(duoMock)(s.mock.Ctx) s.mock.Assert200OK(s.T(), DuoSignResponse{ Result: deny, @@ -166,7 +166,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldFailAutoSelect() { s.Require().NoError(err) s.mock.Ctx.Request.SetBody(bodyBytes) - SecondFactorDuoPost(duoMock)(s.mock.Ctx) + DuoPOST(duoMock)(s.mock.Ctx) s.mock.Assert401KO(s.T(), "Authentication failed, please retry later.") } @@ -195,7 +195,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldDeleteOldDeviceAndEnroll() { s.Require().NoError(err) s.mock.Ctx.Request.SetBody(bodyBytes) - SecondFactorDuoPost(duoMock)(s.mock.Ctx) + DuoPOST(duoMock)(s.mock.Ctx) s.mock.Assert200OK(s.T(), DuoSignResponse{ Result: enroll, @@ -229,7 +229,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldDeleteOldDeviceAndCallPreauthAPIWit s.Require().NoError(err) s.mock.Ctx.Request.SetBody(bodyBytes) - SecondFactorDuoPost(duoMock)(s.mock.Ctx) + DuoPOST(duoMock)(s.mock.Ctx) s.mock.Assert200OK(s.T(), DuoSignResponse{ Result: enroll, @@ -267,7 +267,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldUseOldDeviceAndSelect() { s.Require().NoError(err) s.mock.Ctx.Request.SetBody(bodyBytes) - SecondFactorDuoPost(duoMock)(s.mock.Ctx) + DuoPOST(duoMock)(s.mock.Ctx) s.mock.Assert200OK(s.T(), DuoDevicesResponse{Result: auth, Devices: apiDevices}) } @@ -323,7 +323,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldUseInvalidMethodAndAutoSelect() { s.Require().NoError(err) s.mock.Ctx.Request.SetBody(bodyBytes) - SecondFactorDuoPost(duoMock)(s.mock.Ctx) + DuoPOST(duoMock)(s.mock.Ctx) assert.Equal(s.T(), 200, s.mock.Ctx.Response.StatusCode()) } @@ -346,7 +346,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldCallDuoPreauthAPIAndAllowAccess() { s.Require().NoError(err) s.mock.Ctx.Request.SetBody(bodyBytes) - SecondFactorDuoPost(duoMock)(s.mock.Ctx) + DuoPOST(duoMock)(s.mock.Ctx) assert.Equal(s.T(), 200, s.mock.Ctx.Response.StatusCode()) } @@ -376,7 +376,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldCallDuoPreauthAPIAndDenyAccess() { s.Require().NoError(err) s.mock.Ctx.Request.SetBody(bodyBytes) - SecondFactorDuoPost(duoMock)(s.mock.Ctx) + DuoPOST(duoMock)(s.mock.Ctx) assert.Equal(s.T(), 401, s.mock.Ctx.Response.StatusCode()) } @@ -394,7 +394,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldCallDuoPreauthAPIAndFail() { s.Require().NoError(err) s.mock.Ctx.Request.SetBody(bodyBytes) - SecondFactorDuoPost(duoMock)(s.mock.Ctx) + DuoPOST(duoMock)(s.mock.Ctx) s.mock.Assert401KO(s.T(), "Authentication failed, please retry later.") } @@ -446,7 +446,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldCallDuoAPIAndDenyAccess() { s.Require().NoError(err) s.mock.Ctx.Request.SetBody(bodyBytes) - SecondFactorDuoPost(duoMock)(s.mock.Ctx) + DuoPOST(duoMock)(s.mock.Ctx) assert.Equal(s.T(), 401, s.mock.Ctx.Response.StatusCode()) } @@ -477,7 +477,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldCallDuoAPIAndFail() { s.Require().NoError(err) s.mock.Ctx.Request.SetBody(bodyBytes) - SecondFactorDuoPost(duoMock)(s.mock.Ctx) + DuoPOST(duoMock)(s.mock.Ctx) s.mock.Assert401KO(s.T(), "Authentication failed, please retry later.") } @@ -525,7 +525,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldRedirectUserToDefaultURL() { s.Require().NoError(err) s.mock.Ctx.Request.SetBody(bodyBytes) - SecondFactorDuoPost(duoMock)(s.mock.Ctx) + DuoPOST(duoMock)(s.mock.Ctx) s.mock.Assert200OK(s.T(), redirectResponse{ Redirect: testRedirectionURL, }) @@ -572,7 +572,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldNotReturnRedirectURL() { s.Require().NoError(err) s.mock.Ctx.Request.SetBody(bodyBytes) - SecondFactorDuoPost(duoMock)(s.mock.Ctx) + DuoPOST(duoMock)(s.mock.Ctx) s.mock.Assert200OK(s.T(), nil) } @@ -619,7 +619,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldRedirectUserToSafeTargetURL() { s.Require().NoError(err) s.mock.Ctx.Request.SetBody(bodyBytes) - SecondFactorDuoPost(duoMock)(s.mock.Ctx) + DuoPOST(duoMock)(s.mock.Ctx) s.mock.Assert200OK(s.T(), redirectResponse{ Redirect: "https://mydomain.local", }) @@ -668,7 +668,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldNotRedirectToUnsafeURL() { s.Require().NoError(err) s.mock.Ctx.Request.SetBody(bodyBytes) - SecondFactorDuoPost(duoMock)(s.mock.Ctx) + DuoPOST(duoMock)(s.mock.Ctx) s.mock.Assert200OK(s.T(), nil) } @@ -718,7 +718,7 @@ func (s *SecondFactorDuoPostSuite) TestShouldRegenerateSessionForPreventingSessi r := regexp.MustCompile("^authelia_session=(.*); path=") res := r.FindAllStringSubmatch(string(s.mock.Ctx.Response.Header.PeekCookie("authelia_session")), -1) - SecondFactorDuoPost(duoMock)(s.mock.Ctx) + DuoPOST(duoMock)(s.mock.Ctx) s.mock.Assert200OK(s.T(), nil) s.Assert().NotEqual( diff --git a/internal/handlers/handler_sign_totp.go b/internal/handlers/handler_sign_totp.go index 348925b86..12ba13fd8 100644 --- a/internal/handlers/handler_sign_totp.go +++ b/internal/handlers/handler_sign_totp.go @@ -5,8 +5,8 @@ import ( "github.com/authelia/authelia/v4/internal/regulation" ) -// SecondFactorTOTPPost validate the TOTP passcode provided by the user. -func SecondFactorTOTPPost(ctx *middlewares.AutheliaCtx) { +// TimeBasedOneTimePasswordPOST validate the TOTP passcode provided by the user. +func TimeBasedOneTimePasswordPOST(ctx *middlewares.AutheliaCtx) { requestBody := signTOTPRequestBody{} if err := ctx.ParseBody(&requestBody); err != nil { diff --git a/internal/handlers/handler_sign_totp_test.go b/internal/handlers/handler_sign_totp_test.go index 44f00d257..762434ac0 100644 --- a/internal/handlers/handler_sign_totp_test.go +++ b/internal/handlers/handler_sign_totp_test.go @@ -65,7 +65,7 @@ func (s *HandlerSignTOTPSuite) TestShouldRedirectUserToDefaultURL() { s.Require().NoError(err) s.mock.Ctx.Request.SetBody(bodyBytes) - SecondFactorTOTPPost(s.mock.Ctx) + TimeBasedOneTimePasswordPOST(s.mock.Ctx) s.mock.Assert200OK(s.T(), redirectResponse{ Redirect: testRedirectionURL, }) @@ -103,7 +103,7 @@ func (s *HandlerSignTOTPSuite) TestShouldFailWhenTOTPSignInInfoFailsToUpdate() { s.Require().NoError(err) s.mock.Ctx.Request.SetBody(bodyBytes) - SecondFactorTOTPPost(s.mock.Ctx) + TimeBasedOneTimePasswordPOST(s.mock.Ctx) s.mock.Assert401KO(s.T(), "Authentication failed, please retry later.") } @@ -137,7 +137,7 @@ func (s *HandlerSignTOTPSuite) TestShouldNotReturnRedirectURL() { s.Require().NoError(err) s.mock.Ctx.Request.SetBody(bodyBytes) - SecondFactorTOTPPost(s.mock.Ctx) + TimeBasedOneTimePasswordPOST(s.mock.Ctx) s.mock.Assert200OK(s.T(), nil) } @@ -173,7 +173,7 @@ func (s *HandlerSignTOTPSuite) TestShouldRedirectUserToSafeTargetURL() { s.Require().NoError(err) s.mock.Ctx.Request.SetBody(bodyBytes) - SecondFactorTOTPPost(s.mock.Ctx) + TimeBasedOneTimePasswordPOST(s.mock.Ctx) s.mock.Assert200OK(s.T(), redirectResponse{ Redirect: "https://mydomain.local", }) @@ -211,7 +211,7 @@ func (s *HandlerSignTOTPSuite) TestShouldNotRedirectToUnsafeURL() { s.Require().NoError(err) s.mock.Ctx.Request.SetBody(bodyBytes) - SecondFactorTOTPPost(s.mock.Ctx) + TimeBasedOneTimePasswordPOST(s.mock.Ctx) s.mock.Assert200OK(s.T(), nil) } @@ -250,7 +250,7 @@ func (s *HandlerSignTOTPSuite) TestShouldRegenerateSessionForPreventingSessionFi r := regexp.MustCompile("^authelia_session=(.*); path=") res := r.FindAllStringSubmatch(string(s.mock.Ctx.Response.Header.PeekCookie("authelia_session")), -1) - SecondFactorTOTPPost(s.mock.Ctx) + TimeBasedOneTimePasswordPOST(s.mock.Ctx) s.mock.Assert200OK(s.T(), nil) s.Assert().NotEqual( diff --git a/internal/handlers/handler_sign_webauthn.go b/internal/handlers/handler_sign_webauthn.go index 5564851a6..bd1709959 100644 --- a/internal/handlers/handler_sign_webauthn.go +++ b/internal/handlers/handler_sign_webauthn.go @@ -11,8 +11,8 @@ import ( "github.com/authelia/authelia/v4/internal/regulation" ) -// SecondFactorWebauthnAssertionGET handler starts the assertion ceremony. -func SecondFactorWebauthnAssertionGET(ctx *middlewares.AutheliaCtx) { +// WebauthnAssertionGET handler starts the assertion ceremony. +func WebauthnAssertionGET(ctx *middlewares.AutheliaCtx) { var ( w *webauthn.WebAuthn user *model.WebauthnUser @@ -78,8 +78,8 @@ func SecondFactorWebauthnAssertionGET(ctx *middlewares.AutheliaCtx) { } } -// SecondFactorWebauthnAssertionPOST handler completes the assertion ceremony after verifying the challenge. -func SecondFactorWebauthnAssertionPOST(ctx *middlewares.AutheliaCtx) { +// WebauthnAssertionPOST handler completes the assertion ceremony after verifying the challenge. +func WebauthnAssertionPOST(ctx *middlewares.AutheliaCtx) { var ( err error w *webauthn.WebAuthn diff --git a/internal/handlers/handler_state.go b/internal/handlers/handler_state.go index 8a014773d..086750fea 100644 --- a/internal/handlers/handler_state.go +++ b/internal/handlers/handler_state.go @@ -4,8 +4,8 @@ import ( "github.com/authelia/authelia/v4/internal/middlewares" ) -// StateGet is the handler serving the user state. -func StateGet(ctx *middlewares.AutheliaCtx) { +// StateGET is the handler serving the user state. +func StateGET(ctx *middlewares.AutheliaCtx) { userSession := ctx.GetSession() stateResponse := StateResponse{ Username: userSession.Username, diff --git a/internal/handlers/handler_state_test.go b/internal/handlers/handler_state_test.go index ebec3cd04..9e56bbe40 100644 --- a/internal/handlers/handler_state_test.go +++ b/internal/handlers/handler_state_test.go @@ -32,7 +32,7 @@ func (s *StateGetSuite) TestShouldReturnUsernameFromSession() { err := s.mock.Ctx.SaveSession(userSession) require.NoError(s.T(), err) - StateGet(s.mock.Ctx) + StateGET(s.mock.Ctx) type Response struct { Status string @@ -62,7 +62,7 @@ func (s *StateGetSuite) TestShouldReturnAuthenticationLevelFromSession() { err := s.mock.Ctx.SaveSession(userSession) require.NoError(s.T(), err) - StateGet(s.mock.Ctx) + StateGET(s.mock.Ctx) type Response struct { Status string diff --git a/internal/handlers/handler_user_info.go b/internal/handlers/handler_user_info.go index e11a098c9..4b95b3e6f 100644 --- a/internal/handlers/handler_user_info.go +++ b/internal/handlers/handler_user_info.go @@ -72,8 +72,8 @@ func UserInfoGET(ctx *middlewares.AutheliaCtx) { } } -// MethodPreferencePost update the user preferences regarding 2FA method. -func MethodPreferencePost(ctx *middlewares.AutheliaCtx) { +// MethodPreferencePOST update the user preferences regarding 2FA method. +func MethodPreferencePOST(ctx *middlewares.AutheliaCtx) { bodyJSON := preferred2FAMethodBody{} err := ctx.ParseBody(&bodyJSON) diff --git a/internal/handlers/handler_user_info_test.go b/internal/handlers/handler_user_info_test.go index d2fd256a7..e4d0fa659 100644 --- a/internal/handlers/handler_user_info_test.go +++ b/internal/handlers/handler_user_info_test.go @@ -390,7 +390,7 @@ func (s *SaveSuite) TearDownTest() { func (s *SaveSuite) TestShouldReturnError500WhenNoBodyProvided() { s.mock.Ctx.Request.SetBody(nil) - MethodPreferencePost(s.mock.Ctx) + 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) @@ -399,7 +399,7 @@ func (s *SaveSuite) TestShouldReturnError500WhenNoBodyProvided() { func (s *SaveSuite) TestShouldReturnError500WhenMalformedBodyProvided() { s.mock.Ctx.Request.SetBody([]byte("{\"method\":\"abc\"")) - MethodPreferencePost(s.mock.Ctx) + 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) @@ -408,7 +408,7 @@ func (s *SaveSuite) TestShouldReturnError500WhenMalformedBodyProvided() { func (s *SaveSuite) TestShouldReturnError500WhenBadBodyProvided() { s.mock.Ctx.Request.SetBody([]byte("{\"weird_key\":\"abc\"}")) - MethodPreferencePost(s.mock.Ctx) + 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) @@ -417,7 +417,7 @@ func (s *SaveSuite) TestShouldReturnError500WhenBadBodyProvided() { func (s *SaveSuite) TestShouldReturnError500WhenBadMethodProvided() { s.mock.Ctx.Request.SetBody([]byte("{\"method\":\"abc\"}")) - MethodPreferencePost(s.mock.Ctx) + MethodPreferencePOST(s.mock.Ctx) s.mock.Assert200KO(s.T(), "Operation failed.") assert.Equal(s.T(), "unknown or unavailable method 'abc', it should be one of totp, webauthn", s.mock.Hook.LastEntry().Message) @@ -430,7 +430,7 @@ func (s *SaveSuite) TestShouldReturnError500WhenDatabaseFailsToSave() { SavePreferred2FAMethod(s.mock.Ctx, gomock.Eq("john"), gomock.Eq("webauthn")). Return(fmt.Errorf("Failure")) - MethodPreferencePost(s.mock.Ctx) + 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) @@ -443,7 +443,7 @@ func (s *SaveSuite) TestShouldReturn200WhenMethodIsSuccessfullySaved() { SavePreferred2FAMethod(s.mock.Ctx, gomock.Eq("john"), gomock.Eq("webauthn")). Return(nil) - MethodPreferencePost(s.mock.Ctx) + MethodPreferencePOST(s.mock.Ctx) assert.Equal(s.T(), 200, s.mock.Ctx.Response.StatusCode()) } diff --git a/internal/handlers/handler_user_totp.go b/internal/handlers/handler_user_totp.go index fbf133756..ee80cc7c8 100644 --- a/internal/handlers/handler_user_totp.go +++ b/internal/handlers/handler_user_totp.go @@ -9,8 +9,8 @@ import ( "github.com/authelia/authelia/v4/internal/storage" ) -// UserTOTPGet returns the users TOTP configuration. -func UserTOTPGet(ctx *middlewares.AutheliaCtx) { +// UserTOTPInfoGET returns the users TOTP configuration. +func UserTOTPInfoGET(ctx *middlewares.AutheliaCtx) { userSession := ctx.GetSession() config, err := ctx.Providers.StorageProvider.LoadTOTPConfiguration(ctx, userSession.Username) diff --git a/internal/handlers/handler_verify.go b/internal/handlers/handler_verify.go index 2d22a5169..7bf8d7187 100644 --- a/internal/handlers/handler_verify.go +++ b/internal/handlers/handler_verify.go @@ -440,8 +440,8 @@ func verifyAuth(ctx *middlewares.AutheliaCtx, targetURL *url.URL, refreshProfile return } -// VerifyGet returns the handler verifying if a request is allowed to go through. -func VerifyGet(cfg schema.AuthenticationBackendConfiguration) middlewares.RequestHandler { +// VerifyGET returns the handler verifying if a request is allowed to go through. +func VerifyGET(cfg schema.AuthenticationBackendConfiguration) middlewares.RequestHandler { refreshProfile, refreshProfileInterval := getProfileRefreshSettings(cfg) return func(ctx *middlewares.AutheliaCtx) { diff --git a/internal/handlers/handler_verify_test.go b/internal/handlers/handler_verify_test.go index 8f10edb26..088197a4c 100644 --- a/internal/handlers/handler_verify_test.go +++ b/internal/handlers/handler_verify_test.go @@ -196,7 +196,7 @@ func (s *BasicAuthorizationSuite) TestShouldNotBeAbleToParseBasicAuth() { mock.Ctx.Request.Header.Set("Proxy-Authorization", "Basic am9objpaaaaaaaaaaaaaaaa") mock.Ctx.Request.Header.Set("X-Original-URL", "https://test.example.com") - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) assert.Equal(s.T(), 401, mock.Ctx.Response.StatusCode()) } @@ -219,7 +219,7 @@ func (s *BasicAuthorizationSuite) TestShouldApplyDefaultPolicy() { Groups: []string{"dev", "admins"}, }, nil) - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) assert.Equal(s.T(), 403, mock.Ctx.Response.StatusCode()) } @@ -242,7 +242,7 @@ func (s *BasicAuthorizationSuite) TestShouldApplyPolicyOfBypassDomain() { Groups: []string{"dev", "admins"}, }, nil) - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) assert.Equal(s.T(), 200, mock.Ctx.Response.StatusCode()) } @@ -265,7 +265,7 @@ func (s *BasicAuthorizationSuite) TestShouldApplyPolicyOfOneFactorDomain() { Groups: []string{"dev", "admins"}, }, nil) - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) assert.Equal(s.T(), 200, mock.Ctx.Response.StatusCode()) } @@ -288,7 +288,7 @@ func (s *BasicAuthorizationSuite) TestShouldApplyPolicyOfTwoFactorDomain() { Groups: []string{"dev", "admins"}, }, nil) - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) assert.Equal(s.T(), 401, mock.Ctx.Response.StatusCode()) } @@ -311,7 +311,7 @@ func (s *BasicAuthorizationSuite) TestShouldApplyPolicyOfDenyDomain() { Groups: []string{"dev", "admins"}, }, nil) - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) assert.Equal(s.T(), 403, mock.Ctx.Response.StatusCode()) } @@ -335,7 +335,7 @@ func (s *BasicAuthorizationSuite) TestShouldVerifyAuthBasicArgOk() { Groups: []string{"dev", "admins"}, }, nil) - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) assert.Equal(s.T(), 200, mock.Ctx.Response.StatusCode()) } @@ -347,7 +347,7 @@ func (s *BasicAuthorizationSuite) TestShouldVerifyAuthBasicArgFailingNoHeader() mock.Ctx.QueryArgs().Add("auth", "basic") mock.Ctx.Request.Header.Set("X-Original-URL", "https://one-factor.example.com") - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) assert.Equal(s.T(), 401, mock.Ctx.Response.StatusCode()) assert.Equal(s.T(), "Unauthorized", string(mock.Ctx.Response.Body())) @@ -363,7 +363,7 @@ func (s *BasicAuthorizationSuite) TestShouldVerifyAuthBasicArgFailingEmptyHeader mock.Ctx.Request.Header.Set("Authorization", "") mock.Ctx.Request.Header.Set("X-Original-URL", "https://one-factor.example.com") - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) assert.Equal(s.T(), 401, mock.Ctx.Response.StatusCode()) assert.Equal(s.T(), "Unauthorized", string(mock.Ctx.Response.Body())) @@ -383,7 +383,7 @@ func (s *BasicAuthorizationSuite) TestShouldVerifyAuthBasicArgFailingWrongPasswo CheckUserPassword(gomock.Eq("john"), gomock.Eq("password")). Return(false, nil) - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) assert.Equal(s.T(), 401, mock.Ctx.Response.StatusCode()) assert.Equal(s.T(), "Unauthorized", string(mock.Ctx.Response.Body())) @@ -399,7 +399,7 @@ func (s *BasicAuthorizationSuite) TestShouldVerifyAuthBasicArgFailingWrongHeader mock.Ctx.Request.Header.Set("Proxy-Authorization", "Basic am9objpwYXNzd29yZA==") mock.Ctx.Request.Header.Set("X-Original-URL", "https://one-factor.example.com") - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) assert.Equal(s.T(), 401, mock.Ctx.Response.StatusCode()) assert.Equal(s.T(), "Unauthorized", string(mock.Ctx.Response.Body())) @@ -422,7 +422,7 @@ func TestShouldVerifyWrongCredentialsInBasicAuth(t *testing.T) { mock.Ctx.Request.Header.Set("Proxy-Authorization", "Basic am9objp3cm9uZ3Bhc3M=") mock.Ctx.Request.Header.Set("X-Original-URL", "https://test.example.com") - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) expStatus, actualStatus := 401, mock.Ctx.Response.StatusCode() assert.Equal(t, expStatus, actualStatus, "URL=%s -> StatusCode=%d != ExpectedStatusCode=%d", "https://test.example.com", actualStatus, expStatus) @@ -439,7 +439,7 @@ func TestShouldVerifyFailingPasswordCheckingInBasicAuth(t *testing.T) { mock.Ctx.Request.Header.Set("Proxy-Authorization", "Basic am9objp3cm9uZ3Bhc3M=") mock.Ctx.Request.Header.Set("X-Original-URL", "https://test.example.com") - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) expStatus, actualStatus := 401, mock.Ctx.Response.StatusCode() assert.Equal(t, expStatus, actualStatus, "URL=%s -> StatusCode=%d != ExpectedStatusCode=%d", "https://test.example.com", actualStatus, expStatus) @@ -460,7 +460,7 @@ func TestShouldVerifyFailingDetailsFetchingInBasicAuth(t *testing.T) { mock.Ctx.Request.Header.Set("Proxy-Authorization", "Basic am9objpwYXNzd29yZA==") mock.Ctx.Request.Header.Set("X-Original-URL", "https://test.example.com") - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) expStatus, actualStatus := 401, mock.Ctx.Response.StatusCode() assert.Equal(t, expStatus, actualStatus, "URL=%s -> StatusCode=%d != ExpectedStatusCode=%d", "https://test.example.com", actualStatus, expStatus) @@ -484,7 +484,7 @@ func TestShouldNotCrashOnEmptyEmail(t *testing.T) { mock.Ctx.Request.Header.Set("X-Original-URL", "https://bypass.example.com") - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) expStatus, actualStatus := 200, mock.Ctx.Response.StatusCode() assert.Equal(t, expStatus, actualStatus, "URL=%s -> StatusCode=%d != ExpectedStatusCode=%d", @@ -545,7 +545,7 @@ func TestShouldVerifyAuthorizationsUsingSessionCookie(t *testing.T) { mock.Ctx.Request.Header.Set("X-Original-URL", testCase.URL) - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) expStatus, actualStatus := testCase.ExpectedStatusCode, mock.Ctx.Response.StatusCode() assert.Equal(t, expStatus, actualStatus, "URL=%s -> AuthLevel=%d, StatusCode=%d != ExpectedStatusCode=%d", testCase.URL, testCase.AuthenticationLevel, actualStatus, expStatus) @@ -584,7 +584,7 @@ func TestShouldDestroySessionWhenInactiveForTooLong(t *testing.T) { mock.Ctx.Request.Header.Set("X-Original-URL", "https://two-factor.example.com") - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) // The session has been destroyed. newUserSession := mock.Ctx.GetSession() @@ -617,7 +617,7 @@ func TestShouldDestroySessionWhenInactiveForTooLongUsingDurationNotation(t *test mock.Ctx.Request.Header.Set("X-Original-URL", "https://two-factor.example.com") - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) // The session has been destroyed. newUserSession := mock.Ctx.GetSession() @@ -646,7 +646,7 @@ func TestShouldKeepSessionWhenUserCheckedRememberMeAndIsInactiveForTooLong(t *te mock.Ctx.Request.Header.Set("X-Original-URL", "https://two-factor.example.com") - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) // Check the session is still active. newUserSession := mock.Ctx.GetSession() @@ -679,7 +679,7 @@ func TestShouldKeepSessionWhenInactivityTimeoutHasNotBeenExceeded(t *testing.T) mock.Ctx.Request.Header.Set("X-Original-URL", "https://two-factor.example.com") - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) // The session has been destroyed. newUserSession := mock.Ctx.GetSession() @@ -718,7 +718,7 @@ func TestShouldRedirectWhenSessionInactiveForTooLongAndRDParamProvided(t *testin mock.Ctx.Request.Header.Set("X-Original-URL", "https://two-factor.example.com") mock.Ctx.Request.Header.Set("X-Forwarded-Method", "GET") mock.Ctx.Request.Header.Set("Accept", "text/html; charset=utf-8") - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) assert.Equal(t, "Found", string(mock.Ctx.Response.Body())) @@ -738,7 +738,7 @@ func TestShouldRedirectWithCorrectStatusCodeBasedOnRequestMethod(t *testing.T) { mock.Ctx.Request.Header.Set("X-Forwarded-Method", "GET") mock.Ctx.Request.Header.Set("Accept", "text/html; charset=utf-8") - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) assert.Equal(t, "Found", string(mock.Ctx.Response.Body())) @@ -749,7 +749,7 @@ func TestShouldRedirectWithCorrectStatusCodeBasedOnRequestMethod(t *testing.T) { mock.Ctx.Request.Header.Set("X-Forwarded-Method", "POST") mock.Ctx.Request.Header.Set("Accept", "text/html; charset=utf-8") - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) assert.Equal(t, "See Other", string(mock.Ctx.Response.Body())) @@ -777,7 +777,7 @@ func TestShouldUpdateInactivityTimestampEvenWhenHittingForbiddenResources(t *tes mock.Ctx.Request.Header.Set("X-Original-URL", "https://deny.example.com") - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) // The resource if forbidden. assert.Equal(t, 403, mock.Ctx.Response.StatusCode()) @@ -806,7 +806,7 @@ func TestShouldURLEncodeRedirectionURLParameter(t *testing.T) { mock.Ctx.Request.SetHost("mydomain.com") mock.Ctx.Request.SetRequestURI("/?rd=https://auth.mydomain.com") - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) assert.Equal(t, "Found", string(mock.Ctx.Response.Body())) @@ -889,7 +889,7 @@ func TestShouldNotRefreshUserGroupsFromBackend(t *testing.T) { cfg := verifyGetCfg cfg.RefreshInterval = "disable" - verifyGet := VerifyGet(cfg) + verifyGet := VerifyGET(cfg) mock.UserProviderMock.EXPECT().GetDetails("john").Times(0) @@ -973,7 +973,7 @@ func TestShouldNotRefreshUserGroupsFromBackendWhenDisabled(t *testing.T) { config := verifyGetCfg config.RefreshInterval = schema.ProfileRefreshDisabled - VerifyGet(config)(mock.Ctx) + VerifyGET(config)(mock.Ctx) assert.Equal(t, 200, mock.Ctx.Response.StatusCode()) // Session time should NOT have been updated, it should still have a refresh TTL 1 minute in the past. @@ -1016,7 +1016,7 @@ func TestShouldDestroySessionWhenUserNotExist(t *testing.T) { mock.Ctx.Request.Header.Set("X-Original-URL", "https://two-factor.example.com") - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) assert.Equal(t, 200, mock.Ctx.Response.StatusCode()) // Session time should NOT have been updated, it should still have a refresh TTL 1 minute in the past. @@ -1031,7 +1031,7 @@ func TestShouldDestroySessionWhenUserNotExist(t *testing.T) { mock.UserProviderMock.EXPECT().GetDetails("john").Return(nil, authentication.ErrUserNotFound).Times(1) - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) assert.Equal(t, 401, mock.Ctx.Response.StatusCode()) @@ -1056,7 +1056,7 @@ func TestShouldGetRemovedUserGroupsFromBackend(t *testing.T) { }, } - verifyGet := VerifyGet(verifyGetCfg) + verifyGet := VerifyGET(verifyGetCfg) mock.UserProviderMock.EXPECT().GetDetails("john").Return(user, nil).Times(2) @@ -1127,7 +1127,7 @@ func TestShouldGetAddedUserGroupsFromBackend(t *testing.T) { mock.UserProviderMock.EXPECT().GetDetails("john").Return(user, nil).Times(1) - verifyGet := VerifyGet(verifyGetCfg) + verifyGet := VerifyGET(verifyGetCfg) mock.Clock.Set(time.Now()) @@ -1180,7 +1180,7 @@ func TestShouldGetAddedUserGroupsFromBackend(t *testing.T) { ) mock.Ctx.Request.Header.Set("X-Original-URL", "https://grafana.example.com") - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) assert.Equal(t, 200, mock.Ctx.Response.StatusCode()) // Check admin group is removed from the session. @@ -1212,7 +1212,7 @@ func TestShouldCheckValidSessionUsernameHeaderAndReturn200(t *testing.T) { mock.Ctx.Request.Header.Set("X-Original-URL", "https://one-factor.example.com") mock.Ctx.Request.Header.SetBytesK(headerSessionUsername, testUsername) - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) assert.Equal(t, expectedStatusCode, mock.Ctx.Response.StatusCode()) assert.Equal(t, "", string(mock.Ctx.Response.Body())) @@ -1236,7 +1236,7 @@ func TestShouldCheckInvalidSessionUsernameHeaderAndReturn401(t *testing.T) { mock.Ctx.Request.Header.Set("X-Original-URL", "https://one-factor.example.com") mock.Ctx.Request.Header.SetBytesK(headerSessionUsername, "root") - VerifyGet(verifyGetCfg)(mock.Ctx) + VerifyGET(verifyGetCfg)(mock.Ctx) assert.Equal(t, expectedStatusCode, mock.Ctx.Response.StatusCode()) assert.Equal(t, "Unauthorized", string(mock.Ctx.Response.Body())) diff --git a/internal/middlewares/require_first_factor.go b/internal/middlewares/require_first_factor.go index 4b9869000..cd104583d 100644 --- a/internal/middlewares/require_first_factor.go +++ b/internal/middlewares/require_first_factor.go @@ -4,8 +4,8 @@ import ( "github.com/authelia/authelia/v4/internal/authentication" ) -// RequireFirstFactor check if user has enough permissions to execute the next handler. -func RequireFirstFactor(next RequestHandler) RequestHandler { +// Require1FA check if user has enough permissions to execute the next handler. +func Require1FA(next RequestHandler) RequestHandler { return func(ctx *AutheliaCtx) { if ctx.GetSession().AuthenticationLevel < authentication.OneFactor { ctx.ReplyForbidden() diff --git a/internal/server/handlers.go b/internal/server/handlers.go index 1beb151ac..6a89445e6 100644 --- a/internal/server/handlers.go +++ b/internal/server/handlers.go @@ -2,36 +2,61 @@ package server import ( "net" + "os" + "strconv" "strings" + "time" + duoapi "github.com/duosecurity/duo_api_golang" + "github.com/fasthttp/router" "github.com/valyala/fasthttp" + "github.com/valyala/fasthttp/expvarhandler" + "github.com/valyala/fasthttp/pprofhandler" + "github.com/authelia/authelia/v4/internal/configuration/schema" + "github.com/authelia/authelia/v4/internal/duo" "github.com/authelia/authelia/v4/internal/handlers" "github.com/authelia/authelia/v4/internal/logging" + "github.com/authelia/authelia/v4/internal/middlewares" + "github.com/authelia/authelia/v4/internal/oidc" + "github.com/authelia/authelia/v4/internal/utils" ) // Replacement for the default error handler in fasthttp. -func handlerErrors(ctx *fasthttp.RequestCtx, err error) { +func handlerError() func(ctx *fasthttp.RequestCtx, err error) { logger := logging.Logger() - switch e := err.(type) { - case *fasthttp.ErrSmallBuffer: - logger.Tracef("Request was too large to handle from client %s. Response Code %d.", ctx.RemoteIP().String(), fasthttp.StatusRequestHeaderFieldsTooLarge) - ctx.Error("request header too large", fasthttp.StatusRequestHeaderFieldsTooLarge) - case *net.OpError: - if e.Timeout() { - // TODO: Add X-Forwarded-For Check here. - logger.Tracef("Request timeout occurred while handling from client %s: %s. Response Code %d.", ctx.RemoteIP().String(), ctx.RequestURI(), fasthttp.StatusRequestTimeout) - ctx.Error("request timeout", fasthttp.StatusRequestTimeout) - } else { - // TODO: Add X-Forwarded-For Check here. - logger.Tracef("An unknown error occurred while handling a request from client %s: %s. Response Code %d.", ctx.RemoteIP().String(), ctx.RequestURI(), fasthttp.StatusBadRequest) + headerXForwardedFor := []byte(fasthttp.HeaderXForwardedFor) + + getRemoteIP := func(ctx *fasthttp.RequestCtx) string { + if hdr := ctx.Request.Header.PeekBytes(headerXForwardedFor); hdr != nil { + ips := strings.Split(string(hdr), ",") + + if len(ips) > 0 { + return strings.Trim(ips[0], " ") + } + } + + return ctx.RemoteIP().String() + } + + return func(ctx *fasthttp.RequestCtx, err error) { + switch e := err.(type) { + case *fasthttp.ErrSmallBuffer: + logger.Tracef("Request was too large to handle from client %s. Response Code %d.", getRemoteIP(ctx), fasthttp.StatusRequestHeaderFieldsTooLarge) + ctx.Error("request header too large", fasthttp.StatusRequestHeaderFieldsTooLarge) + case *net.OpError: + if e.Timeout() { + logger.Tracef("Request timeout occurred while handling from client %s: %s. Response Code %d.", getRemoteIP(ctx), ctx.RequestURI(), fasthttp.StatusRequestTimeout) + ctx.Error("request timeout", fasthttp.StatusRequestTimeout) + } else { + logger.Tracef("An unknown error occurred while handling a request from client %s: %s. Response Code %d.", getRemoteIP(ctx), ctx.RequestURI(), fasthttp.StatusBadRequest) + ctx.Error("error when parsing request", fasthttp.StatusBadRequest) + } + default: + logger.Tracef("An unknown error occurred while handling a request from client %s: %s. Response Code %d.", getRemoteIP(ctx), ctx.RequestURI(), fasthttp.StatusBadRequest) ctx.Error("error when parsing request", fasthttp.StatusBadRequest) } - default: - // TODO: Add X-Forwarded-For Check here. - logger.Tracef("An unknown error occurred while handling a request from client %s: %s. Response Code %d.", ctx.RemoteIP().String(), ctx.RequestURI(), fasthttp.StatusBadRequest) - ctx.Error("error when parsing request", fasthttp.StatusBadRequest) } } @@ -54,3 +79,229 @@ func handlerNotFound(next fasthttp.RequestHandler) fasthttp.RequestHandler { func handlerMethodNotAllowed(ctx *fasthttp.RequestCtx) { handlers.SetStatusCodeResponse(ctx, fasthttp.StatusMethodNotAllowed) } + +func getHandler(config schema.Configuration, providers middlewares.Providers) fasthttp.RequestHandler { + rememberMe := strconv.FormatBool(config.Session.RememberMeDuration != schema.RememberMeDisabled) + resetPassword := strconv.FormatBool(!config.AuthenticationBackend.DisableResetPassword) + + resetPasswordCustomURL := config.AuthenticationBackend.PasswordReset.CustomURL.String() + + duoSelfEnrollment := f + if config.DuoAPI != nil { + duoSelfEnrollment = strconv.FormatBool(config.DuoAPI.EnableSelfEnrollment) + } + + https := config.Server.TLS.Key != "" && config.Server.TLS.Certificate != "" + + serveIndexHandler := ServeTemplatedFile(embeddedAssets, indexFile, config.Server.AssetPath, duoSelfEnrollment, rememberMe, resetPassword, resetPasswordCustomURL, config.Session.Name, config.Theme, https) + serveSwaggerHandler := ServeTemplatedFile(swaggerAssets, indexFile, config.Server.AssetPath, duoSelfEnrollment, rememberMe, resetPassword, resetPasswordCustomURL, config.Session.Name, config.Theme, https) + serveSwaggerAPIHandler := ServeTemplatedFile(swaggerAssets, apiFile, config.Server.AssetPath, duoSelfEnrollment, rememberMe, resetPassword, resetPasswordCustomURL, config.Session.Name, config.Theme, https) + + handlerPublicHTML := newPublicHTMLEmbeddedHandler() + handlerLocales := newLocalesEmbeddedHandler() + + middleware := middlewares.AutheliaMiddleware(config, providers) + + policyCORSPublicGET := middlewares.NewCORSPolicyBuilder(). + WithAllowedMethods("OPTIONS", "GET"). + WithAllowedOrigins("*"). + Build() + + r := router.New() + + // Static Assets. + r.GET("/", middleware(serveIndexHandler)) + + for _, f := range rootFiles { + r.GET("/"+f, handlerPublicHTML) + } + + r.GET("/favicon.ico", middlewares.AssetOverrideMiddleware(config.Server.AssetPath, 0, handlerPublicHTML)) + r.GET("/static/media/logo.png", middlewares.AssetOverrideMiddleware(config.Server.AssetPath, 2, handlerPublicHTML)) + r.GET("/static/{filepath:*}", handlerPublicHTML) + + // Locales. + r.GET("/locales/{language:[a-z]{1,3}}-{variant:[a-z0-9-]+}/{namespace:[a-z]+}.json", middlewares.AssetOverrideMiddleware(config.Server.AssetPath, 0, handlerLocales)) + r.GET("/locales/{language:[a-z]{1,3}}/{namespace:[a-z]+}.json", middlewares.AssetOverrideMiddleware(config.Server.AssetPath, 0, handlerLocales)) + + // Swagger. + r.GET("/api/", middleware(serveSwaggerHandler)) + r.OPTIONS("/api/", policyCORSPublicGET.HandleOPTIONS) + r.GET("/api/"+apiFile, policyCORSPublicGET.Middleware(middleware(serveSwaggerAPIHandler))) + r.OPTIONS("/api/"+apiFile, policyCORSPublicGET.HandleOPTIONS) + + for _, file := range swaggerFiles { + r.GET("/api/"+file, handlerPublicHTML) + } + + r.GET("/api/health", middleware(handlers.HealthGET)) + r.GET("/api/state", middleware(handlers.StateGET)) + + r.GET("/api/configuration", middleware(middlewares.Require1FA(handlers.ConfigurationGET))) + + r.GET("/api/configuration/password-policy", middleware(handlers.PasswordPolicyConfigurationGet)) + + r.GET("/api/verify", middleware(handlers.VerifyGET(config.AuthenticationBackend))) + r.HEAD("/api/verify", middleware(handlers.VerifyGET(config.AuthenticationBackend))) + + r.POST("/api/checks/safe-redirection", middleware(handlers.CheckSafeRedirectionPOST)) + + delayFunc := middlewares.TimingAttackDelay(10, 250, 85, time.Second) + + r.POST("/api/firstfactor", middleware(handlers.FirstFactorPOST(delayFunc))) + r.POST("/api/logout", middleware(handlers.LogoutPOST)) + + // Only register endpoints if forgot password is not disabled. + if !config.AuthenticationBackend.DisableResetPassword && + config.AuthenticationBackend.PasswordReset.CustomURL.String() == "" { + // Password reset related endpoints. + r.POST("/api/reset-password/identity/start", middleware(handlers.ResetPasswordIdentityStart)) + r.POST("/api/reset-password/identity/finish", middleware(handlers.ResetPasswordIdentityFinish)) + r.POST("/api/reset-password", middleware(handlers.ResetPasswordPOST)) + } + + // Information about the user. + r.GET("/api/user/info", middleware(middlewares.Require1FA(handlers.UserInfoGET))) + r.POST("/api/user/info", middleware(middlewares.Require1FA(handlers.UserInfoPOST))) + r.POST("/api/user/info/2fa_method", middleware(middlewares.Require1FA(handlers.MethodPreferencePOST))) + + if !config.TOTP.Disable { + // TOTP related endpoints. + r.GET("/api/user/info/totp", middleware(middlewares.Require1FA(handlers.UserTOTPInfoGET))) + r.POST("/api/secondfactor/totp/identity/start", middleware(middlewares.Require1FA(handlers.TOTPIdentityStart))) + r.POST("/api/secondfactor/totp/identity/finish", middleware(middlewares.Require1FA(handlers.TOTPIdentityFinish))) + r.POST("/api/secondfactor/totp", middleware(middlewares.Require1FA(handlers.TimeBasedOneTimePasswordPOST))) + } + + if !config.Webauthn.Disable { + // Webauthn Endpoints. + r.POST("/api/secondfactor/webauthn/identity/start", middleware(middlewares.Require1FA(handlers.WebauthnIdentityStart))) + r.POST("/api/secondfactor/webauthn/identity/finish", middleware(middlewares.Require1FA(handlers.WebauthnIdentityFinish))) + r.POST("/api/secondfactor/webauthn/attestation", middleware(middlewares.Require1FA(handlers.WebauthnAttestationPOST))) + + r.GET("/api/secondfactor/webauthn/assertion", middleware(middlewares.Require1FA(handlers.WebauthnAssertionGET))) + r.POST("/api/secondfactor/webauthn/assertion", middleware(middlewares.Require1FA(handlers.WebauthnAssertionPOST))) + } + + // Configure DUO api endpoint only if configuration exists. + if config.DuoAPI != nil { + var duoAPI duo.API + if os.Getenv("ENVIRONMENT") == dev { + duoAPI = duo.NewDuoAPI(duoapi.NewDuoApi( + config.DuoAPI.IntegrationKey, + config.DuoAPI.SecretKey, + config.DuoAPI.Hostname, "", duoapi.SetInsecure())) + } else { + duoAPI = duo.NewDuoAPI(duoapi.NewDuoApi( + config.DuoAPI.IntegrationKey, + config.DuoAPI.SecretKey, + config.DuoAPI.Hostname, "")) + } + + r.GET("/api/secondfactor/duo_devices", middleware(middlewares.Require1FA(handlers.DuoDevicesGET(duoAPI)))) + r.POST("/api/secondfactor/duo", middleware(middlewares.Require1FA(handlers.DuoPOST(duoAPI)))) + r.POST("/api/secondfactor/duo_device", middleware(middlewares.Require1FA(handlers.DuoDevicePOST))) + } + + if config.Server.EnablePprof { + r.GET("/debug/pprof/{name?}", pprofhandler.PprofHandler) + } + + if config.Server.EnableExpvars { + r.GET("/debug/vars", expvarhandler.ExpvarHandler) + } + + if providers.OpenIDConnect.Fosite != nil { + r.GET("/api/oidc/consent", middleware(handlers.OpenIDConnectConsentGET)) + r.POST("/api/oidc/consent", middleware(handlers.OpenIDConnectConsentPOST)) + + allowedOrigins := utils.StringSliceFromURLs(config.IdentityProviders.OIDC.CORS.AllowedOrigins) + + r.OPTIONS(oidc.WellKnownOpenIDConfigurationPath, policyCORSPublicGET.HandleOPTIONS) + r.GET(oidc.WellKnownOpenIDConfigurationPath, policyCORSPublicGET.Middleware(middleware(handlers.OpenIDConnectConfigurationWellKnownGET))) + + r.OPTIONS(oidc.WellKnownOAuthAuthorizationServerPath, policyCORSPublicGET.HandleOPTIONS) + r.GET(oidc.WellKnownOAuthAuthorizationServerPath, policyCORSPublicGET.Middleware(middleware(handlers.OAuthAuthorizationServerWellKnownGET))) + + r.OPTIONS(oidc.JWKsPath, policyCORSPublicGET.HandleOPTIONS) + r.GET(oidc.JWKsPath, policyCORSPublicGET.Middleware(middleware(handlers.JSONWebKeySetGET))) + + // TODO (james-d-elliott): Remove in GA. This is a legacy implementation of the above endpoint. + r.OPTIONS("/api/oidc/jwks", policyCORSPublicGET.HandleOPTIONS) + r.GET("/api/oidc/jwks", policyCORSPublicGET.Middleware(middleware(handlers.JSONWebKeySetGET))) + + policyCORSAuthorization := middlewares.NewCORSPolicyBuilder(). + WithAllowedMethods("OPTIONS", "GET"). + WithAllowedOrigins(allowedOrigins...). + WithEnabled(utils.IsStringInSlice(oidc.AuthorizationEndpoint, config.IdentityProviders.OIDC.CORS.Endpoints)). + Build() + + r.OPTIONS(oidc.AuthorizationPath, policyCORSAuthorization.HandleOnlyOPTIONS) + r.GET(oidc.AuthorizationPath, middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectAuthorizationGET))) + + // TODO (james-d-elliott): Remove in GA. This is a legacy endpoint. + r.OPTIONS("/api/oidc/authorize", policyCORSAuthorization.HandleOnlyOPTIONS) + r.GET("/api/oidc/authorize", middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectAuthorizationGET))) + + policyCORSToken := middlewares.NewCORSPolicyBuilder(). + WithAllowCredentials(true). + WithAllowedMethods("OPTIONS", "POST"). + WithAllowedOrigins(allowedOrigins...). + WithEnabled(utils.IsStringInSlice(oidc.TokenEndpoint, config.IdentityProviders.OIDC.CORS.Endpoints)). + Build() + + r.OPTIONS(oidc.TokenPath, policyCORSToken.HandleOPTIONS) + r.POST(oidc.TokenPath, policyCORSToken.Middleware(middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectTokenPOST)))) + + policyCORSUserinfo := middlewares.NewCORSPolicyBuilder(). + WithAllowCredentials(true). + WithAllowedMethods("OPTIONS", "GET", "POST"). + WithAllowedOrigins(allowedOrigins...). + WithEnabled(utils.IsStringInSlice(oidc.UserinfoEndpoint, config.IdentityProviders.OIDC.CORS.Endpoints)). + Build() + + r.OPTIONS(oidc.UserinfoPath, policyCORSUserinfo.HandleOPTIONS) + r.GET(oidc.UserinfoPath, policyCORSUserinfo.Middleware(middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectUserinfo)))) + r.POST(oidc.UserinfoPath, policyCORSUserinfo.Middleware(middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectUserinfo)))) + + policyCORSIntrospection := middlewares.NewCORSPolicyBuilder(). + WithAllowCredentials(true). + WithAllowedMethods("OPTIONS", "POST"). + WithAllowedOrigins(allowedOrigins...). + WithEnabled(utils.IsStringInSlice(oidc.IntrospectionEndpoint, config.IdentityProviders.OIDC.CORS.Endpoints)). + Build() + + r.OPTIONS(oidc.IntrospectionPath, policyCORSIntrospection.HandleOPTIONS) + r.POST(oidc.IntrospectionPath, policyCORSIntrospection.Middleware(middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthIntrospectionPOST)))) + + // TODO (james-d-elliott): Remove in GA. This is a legacy implementation of the above endpoint. + r.OPTIONS("/api/oidc/introspect", policyCORSIntrospection.HandleOPTIONS) + r.POST("/api/oidc/introspect", policyCORSIntrospection.Middleware(middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthIntrospectionPOST)))) + + policyCORSRevocation := middlewares.NewCORSPolicyBuilder(). + WithAllowCredentials(true). + WithAllowedMethods("OPTIONS", "POST"). + WithAllowedOrigins(allowedOrigins...). + WithEnabled(utils.IsStringInSlice(oidc.RevocationEndpoint, config.IdentityProviders.OIDC.CORS.Endpoints)). + Build() + + r.OPTIONS(oidc.RevocationPath, policyCORSRevocation.HandleOPTIONS) + r.POST(oidc.RevocationPath, policyCORSRevocation.Middleware(middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthRevocationPOST)))) + + // TODO (james-d-elliott): Remove in GA. This is a legacy implementation of the above endpoint. + r.OPTIONS("/api/oidc/revoke", policyCORSRevocation.HandleOPTIONS) + r.POST("/api/oidc/revoke", policyCORSRevocation.Middleware(middleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthRevocationPOST)))) + } + + r.NotFound = handlerNotFound(middleware(serveIndexHandler)) + + r.HandleMethodNotAllowed = true + r.MethodNotAllowed = handlerMethodNotAllowed + + handler := middlewares.LogRequestMiddleware(r.Handler) + if config.Server.Path != "" { + handler = middlewares.StripPathMiddleware(config.Server.Path, handler) + } + + return handler +} diff --git a/internal/server/server.go b/internal/server/server.go index 985fd5b20..a17777a0a 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -6,285 +6,27 @@ import ( "net" "os" "strconv" - "time" - duoapi "github.com/duosecurity/duo_api_golang" - "github.com/fasthttp/router" "github.com/valyala/fasthttp" - "github.com/valyala/fasthttp/expvarhandler" - "github.com/valyala/fasthttp/pprofhandler" "github.com/authelia/authelia/v4/internal/configuration/schema" - "github.com/authelia/authelia/v4/internal/duo" - "github.com/authelia/authelia/v4/internal/handlers" "github.com/authelia/authelia/v4/internal/logging" "github.com/authelia/authelia/v4/internal/middlewares" - "github.com/authelia/authelia/v4/internal/oidc" - "github.com/authelia/authelia/v4/internal/utils" ) -// TODO: move to its own file and rename configuration -> config. -func registerRoutes(configuration schema.Configuration, providers middlewares.Providers) fasthttp.RequestHandler { - rememberMe := strconv.FormatBool(configuration.Session.RememberMeDuration != schema.RememberMeDisabled) - resetPassword := strconv.FormatBool(!configuration.AuthenticationBackend.DisableResetPassword) - - resetPasswordCustomURL := configuration.AuthenticationBackend.PasswordReset.CustomURL.String() - - duoSelfEnrollment := f - if configuration.DuoAPI != nil { - duoSelfEnrollment = strconv.FormatBool(configuration.DuoAPI.EnableSelfEnrollment) - } - - https := configuration.Server.TLS.Key != "" && configuration.Server.TLS.Certificate != "" - - serveIndexHandler := ServeTemplatedFile(embeddedAssets, indexFile, configuration.Server.AssetPath, duoSelfEnrollment, rememberMe, resetPassword, resetPasswordCustomURL, configuration.Session.Name, configuration.Theme, https) - serveSwaggerHandler := ServeTemplatedFile(swaggerAssets, indexFile, configuration.Server.AssetPath, duoSelfEnrollment, rememberMe, resetPassword, resetPasswordCustomURL, configuration.Session.Name, configuration.Theme, https) - serveSwaggerAPIHandler := ServeTemplatedFile(swaggerAssets, apiFile, configuration.Server.AssetPath, duoSelfEnrollment, rememberMe, resetPassword, resetPasswordCustomURL, configuration.Session.Name, configuration.Theme, https) - - handlerPublicHTML := newPublicHTMLEmbeddedHandler() - handlerLocales := newLocalesEmbeddedHandler() - - autheliaMiddleware := middlewares.AutheliaMiddleware(configuration, providers) - - policyCORSPublicGET := middlewares.NewCORSPolicyBuilder(). - WithAllowedMethods("OPTIONS", "GET"). - WithAllowedOrigins("*"). - Build() - - r := router.New() - - // Static Assets. - r.GET("/", autheliaMiddleware(serveIndexHandler)) - - for _, f := range rootFiles { - r.GET("/"+f, handlerPublicHTML) - } - - r.GET("/favicon.ico", middlewares.AssetOverrideMiddleware(configuration.Server.AssetPath, 0, handlerPublicHTML)) - r.GET("/static/media/logo.png", middlewares.AssetOverrideMiddleware(configuration.Server.AssetPath, 2, handlerPublicHTML)) - r.GET("/static/{filepath:*}", handlerPublicHTML) - - // Locales. - r.GET("/locales/{language:[a-z]{1,3}}-{variant:[a-z0-9-]+}/{namespace:[a-z]+}.json", middlewares.AssetOverrideMiddleware(configuration.Server.AssetPath, 0, handlerLocales)) - r.GET("/locales/{language:[a-z]{1,3}}/{namespace:[a-z]+}.json", middlewares.AssetOverrideMiddleware(configuration.Server.AssetPath, 0, handlerLocales)) - - // Swagger. - r.GET("/api/", autheliaMiddleware(serveSwaggerHandler)) - r.OPTIONS("/api/", policyCORSPublicGET.HandleOPTIONS) - r.GET("/api/"+apiFile, policyCORSPublicGET.Middleware(autheliaMiddleware(serveSwaggerAPIHandler))) - r.OPTIONS("/api/"+apiFile, policyCORSPublicGET.HandleOPTIONS) - - for _, file := range swaggerFiles { - r.GET("/api/"+file, handlerPublicHTML) - } - - r.GET("/api/health", autheliaMiddleware(handlers.HealthGet)) - r.GET("/api/state", autheliaMiddleware(handlers.StateGet)) - - r.GET("/api/configuration", autheliaMiddleware( - middlewares.RequireFirstFactor(handlers.ConfigurationGet))) - - r.GET("/api/configuration/password-policy", autheliaMiddleware(handlers.PasswordPolicyConfigurationGet)) - - r.GET("/api/verify", autheliaMiddleware(handlers.VerifyGet(configuration.AuthenticationBackend))) - r.HEAD("/api/verify", autheliaMiddleware(handlers.VerifyGet(configuration.AuthenticationBackend))) - - r.POST("/api/checks/safe-redirection", autheliaMiddleware(handlers.CheckSafeRedirection)) - - r.POST("/api/firstfactor", autheliaMiddleware(handlers.FirstFactorPost(middlewares.TimingAttackDelay(10, 250, 85, time.Second)))) - r.POST("/api/logout", autheliaMiddleware(handlers.LogoutPost)) - - // Only register endpoints if forgot password is not disabled. - if !configuration.AuthenticationBackend.DisableResetPassword && - configuration.AuthenticationBackend.PasswordReset.CustomURL.String() == "" { - // Password reset related endpoints. - r.POST("/api/reset-password/identity/start", autheliaMiddleware( - handlers.ResetPasswordIdentityStart)) - r.POST("/api/reset-password/identity/finish", autheliaMiddleware( - handlers.ResetPasswordIdentityFinish)) - r.POST("/api/reset-password", autheliaMiddleware( - handlers.ResetPasswordPost)) - } - - // Information about the user. - r.GET("/api/user/info", autheliaMiddleware( - middlewares.RequireFirstFactor(handlers.UserInfoGET))) - r.POST("/api/user/info", autheliaMiddleware( - middlewares.RequireFirstFactor(handlers.UserInfoPOST))) - r.POST("/api/user/info/2fa_method", autheliaMiddleware( - middlewares.RequireFirstFactor(handlers.MethodPreferencePost))) - - if !configuration.TOTP.Disable { - // TOTP related endpoints. - r.GET("/api/user/info/totp", autheliaMiddleware( - middlewares.RequireFirstFactor(handlers.UserTOTPGet))) - - r.POST("/api/secondfactor/totp/identity/start", autheliaMiddleware( - middlewares.RequireFirstFactor(handlers.SecondFactorTOTPIdentityStart))) - r.POST("/api/secondfactor/totp/identity/finish", autheliaMiddleware( - middlewares.RequireFirstFactor(handlers.SecondFactorTOTPIdentityFinish))) - r.POST("/api/secondfactor/totp", autheliaMiddleware( - middlewares.RequireFirstFactor(handlers.SecondFactorTOTPPost))) - } - - if !configuration.Webauthn.Disable { - // Webauthn Endpoints. - r.POST("/api/secondfactor/webauthn/identity/start", autheliaMiddleware( - middlewares.RequireFirstFactor(handlers.SecondFactorWebauthnIdentityStart))) - r.POST("/api/secondfactor/webauthn/identity/finish", autheliaMiddleware( - middlewares.RequireFirstFactor(handlers.SecondFactorWebauthnIdentityFinish))) - r.POST("/api/secondfactor/webauthn/attestation", autheliaMiddleware( - middlewares.RequireFirstFactor(handlers.SecondFactorWebauthnAttestationPOST))) - - r.GET("/api/secondfactor/webauthn/assertion", autheliaMiddleware( - middlewares.RequireFirstFactor(handlers.SecondFactorWebauthnAssertionGET))) - r.POST("/api/secondfactor/webauthn/assertion", autheliaMiddleware( - middlewares.RequireFirstFactor(handlers.SecondFactorWebauthnAssertionPOST))) - } - - // Configure DUO api endpoint only if configuration exists. - if configuration.DuoAPI != nil { - var duoAPI duo.API - if os.Getenv("ENVIRONMENT") == dev { - duoAPI = duo.NewDuoAPI(duoapi.NewDuoApi( - configuration.DuoAPI.IntegrationKey, - configuration.DuoAPI.SecretKey, - configuration.DuoAPI.Hostname, "", duoapi.SetInsecure())) - } else { - duoAPI = duo.NewDuoAPI(duoapi.NewDuoApi( - configuration.DuoAPI.IntegrationKey, - configuration.DuoAPI.SecretKey, - configuration.DuoAPI.Hostname, "")) - } - - r.GET("/api/secondfactor/duo_devices", autheliaMiddleware( - middlewares.RequireFirstFactor(handlers.SecondFactorDuoDevicesGet(duoAPI)))) - - r.POST("/api/secondfactor/duo", autheliaMiddleware( - middlewares.RequireFirstFactor(handlers.SecondFactorDuoPost(duoAPI)))) - - r.POST("/api/secondfactor/duo_device", autheliaMiddleware( - middlewares.RequireFirstFactor(handlers.SecondFactorDuoDevicePost))) - } - - if configuration.Server.EnablePprof { - r.GET("/debug/pprof/{name?}", pprofhandler.PprofHandler) - } - - if configuration.Server.EnableExpvars { - r.GET("/debug/vars", expvarhandler.ExpvarHandler) - } - - if providers.OpenIDConnect.Fosite != nil { - r.GET("/api/oidc/consent", autheliaMiddleware(handlers.OpenIDConnectConsentGET)) - r.POST("/api/oidc/consent", autheliaMiddleware(handlers.OpenIDConnectConsentPOST)) - - allowedOrigins := utils.StringSliceFromURLs(configuration.IdentityProviders.OIDC.CORS.AllowedOrigins) - - r.OPTIONS(oidc.WellKnownOpenIDConfigurationPath, policyCORSPublicGET.HandleOPTIONS) - r.GET(oidc.WellKnownOpenIDConfigurationPath, policyCORSPublicGET.Middleware(autheliaMiddleware(handlers.OpenIDConnectConfigurationWellKnownGET))) - - r.OPTIONS(oidc.WellKnownOAuthAuthorizationServerPath, policyCORSPublicGET.HandleOPTIONS) - r.GET(oidc.WellKnownOAuthAuthorizationServerPath, policyCORSPublicGET.Middleware(autheliaMiddleware(handlers.OAuthAuthorizationServerWellKnownGET))) - - r.OPTIONS(oidc.JWKsPath, policyCORSPublicGET.HandleOPTIONS) - r.GET(oidc.JWKsPath, policyCORSPublicGET.Middleware(autheliaMiddleware(handlers.JSONWebKeySetGET))) - - // TODO (james-d-elliott): Remove in GA. This is a legacy implementation of the above endpoint. - r.OPTIONS("/api/oidc/jwks", policyCORSPublicGET.HandleOPTIONS) - r.GET("/api/oidc/jwks", policyCORSPublicGET.Middleware(autheliaMiddleware(handlers.JSONWebKeySetGET))) - - policyCORSAuthorization := middlewares.NewCORSPolicyBuilder(). - WithAllowedMethods("OPTIONS", "GET"). - WithAllowedOrigins(allowedOrigins...). - WithEnabled(utils.IsStringInSlice(oidc.AuthorizationEndpoint, configuration.IdentityProviders.OIDC.CORS.Endpoints)). - Build() - - r.OPTIONS(oidc.AuthorizationPath, policyCORSAuthorization.HandleOnlyOPTIONS) - r.GET(oidc.AuthorizationPath, autheliaMiddleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectAuthorizationGET))) - - // TODO (james-d-elliott): Remove in GA. This is a legacy endpoint. - r.OPTIONS("/api/oidc/authorize", policyCORSAuthorization.HandleOnlyOPTIONS) - r.GET("/api/oidc/authorize", autheliaMiddleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectAuthorizationGET))) - - policyCORSToken := middlewares.NewCORSPolicyBuilder(). - WithAllowCredentials(true). - WithAllowedMethods("OPTIONS", "POST"). - WithAllowedOrigins(allowedOrigins...). - WithEnabled(utils.IsStringInSlice(oidc.TokenEndpoint, configuration.IdentityProviders.OIDC.CORS.Endpoints)). - Build() - - r.OPTIONS(oidc.TokenPath, policyCORSToken.HandleOPTIONS) - r.POST(oidc.TokenPath, policyCORSToken.Middleware(autheliaMiddleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectTokenPOST)))) - - policyCORSUserinfo := middlewares.NewCORSPolicyBuilder(). - WithAllowCredentials(true). - WithAllowedMethods("OPTIONS", "GET", "POST"). - WithAllowedOrigins(allowedOrigins...). - WithEnabled(utils.IsStringInSlice(oidc.UserinfoEndpoint, configuration.IdentityProviders.OIDC.CORS.Endpoints)). - Build() - - r.OPTIONS(oidc.UserinfoPath, policyCORSUserinfo.HandleOPTIONS) - r.GET(oidc.UserinfoPath, policyCORSUserinfo.Middleware(autheliaMiddleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectUserinfo)))) - r.POST(oidc.UserinfoPath, policyCORSUserinfo.Middleware(autheliaMiddleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OpenIDConnectUserinfo)))) - - policyCORSIntrospection := middlewares.NewCORSPolicyBuilder(). - WithAllowCredentials(true). - WithAllowedMethods("OPTIONS", "POST"). - WithAllowedOrigins(allowedOrigins...). - WithEnabled(utils.IsStringInSlice(oidc.IntrospectionEndpoint, configuration.IdentityProviders.OIDC.CORS.Endpoints)). - Build() - - r.OPTIONS(oidc.IntrospectionPath, policyCORSIntrospection.HandleOPTIONS) - r.POST(oidc.IntrospectionPath, policyCORSIntrospection.Middleware(autheliaMiddleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthIntrospectionPOST)))) - - // TODO (james-d-elliott): Remove in GA. This is a legacy implementation of the above endpoint. - r.OPTIONS("/api/oidc/introspect", policyCORSIntrospection.HandleOPTIONS) - r.POST("/api/oidc/introspect", policyCORSIntrospection.Middleware(autheliaMiddleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthIntrospectionPOST)))) - - policyCORSRevocation := middlewares.NewCORSPolicyBuilder(). - WithAllowCredentials(true). - WithAllowedMethods("OPTIONS", "POST"). - WithAllowedOrigins(allowedOrigins...). - WithEnabled(utils.IsStringInSlice(oidc.RevocationEndpoint, configuration.IdentityProviders.OIDC.CORS.Endpoints)). - Build() - - r.OPTIONS(oidc.RevocationPath, policyCORSRevocation.HandleOPTIONS) - r.POST(oidc.RevocationPath, policyCORSRevocation.Middleware(autheliaMiddleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthRevocationPOST)))) - - // TODO (james-d-elliott): Remove in GA. This is a legacy implementation of the above endpoint. - r.OPTIONS("/api/oidc/revoke", policyCORSRevocation.HandleOPTIONS) - r.POST("/api/oidc/revoke", policyCORSRevocation.Middleware(autheliaMiddleware(middlewares.NewHTTPToAutheliaHandlerAdaptor(handlers.OAuthRevocationPOST)))) - } - - r.NotFound = handlerNotFound(autheliaMiddleware(serveIndexHandler)) - - r.HandleMethodNotAllowed = true - r.MethodNotAllowed = handlerMethodNotAllowed - - handler := middlewares.LogRequestMiddleware(r.Handler) - if configuration.Server.Path != "" { - handler = middlewares.StripPathMiddleware(configuration.Server.Path, handler) - } - - return handler -} - // CreateServer Create Authelia's internal webserver with the given configuration and providers. -func CreateServer(configuration schema.Configuration, providers middlewares.Providers) (*fasthttp.Server, net.Listener) { - handler := registerRoutes(configuration, providers) - +func CreateServer(config schema.Configuration, providers middlewares.Providers) (*fasthttp.Server, net.Listener) { server := &fasthttp.Server{ - ErrorHandler: handlerErrors, - Handler: handler, + ErrorHandler: handlerError(), + Handler: getHandler(config, providers), NoDefaultServerHeader: true, - ReadBufferSize: configuration.Server.ReadBufferSize, - WriteBufferSize: configuration.Server.WriteBufferSize, + ReadBufferSize: config.Server.ReadBufferSize, + WriteBufferSize: config.Server.WriteBufferSize, } logger := logging.Logger() - address := net.JoinHostPort(configuration.Server.Host, strconv.Itoa(configuration.Server.Port)) + address := net.JoinHostPort(config.Server.Host, strconv.Itoa(config.Server.Port)) var ( listener net.Listener @@ -293,17 +35,17 @@ func CreateServer(configuration schema.Configuration, providers middlewares.Prov connectionScheme string ) - if configuration.Server.TLS.Certificate != "" && configuration.Server.TLS.Key != "" { + if config.Server.TLS.Certificate != "" && config.Server.TLS.Key != "" { connectionType, connectionScheme = "TLS", schemeHTTPS - if err = server.AppendCert(configuration.Server.TLS.Certificate, configuration.Server.TLS.Key); err != nil { + if err = server.AppendCert(config.Server.TLS.Certificate, config.Server.TLS.Key); err != nil { logger.Fatalf("unable to load certificate: %v", err) } - if len(configuration.Server.TLS.ClientCertificates) > 0 { + if len(config.Server.TLS.ClientCertificates) > 0 { caCertPool := x509.NewCertPool() - for _, path := range configuration.Server.TLS.ClientCertificates { + for _, path := range config.Server.TLS.ClientCertificates { cert, err := os.ReadFile(path) if err != nil { logger.Fatalf("Cannot read client TLS certificate %s: %s", path, err) @@ -329,15 +71,15 @@ func CreateServer(configuration schema.Configuration, providers middlewares.Prov } } - if err = writeHealthCheckEnv(configuration.Server.DisableHealthcheck, connectionScheme, configuration.Server.Host, - configuration.Server.Path, configuration.Server.Port); err != nil { + if err = writeHealthCheckEnv(config.Server.DisableHealthcheck, connectionScheme, config.Server.Host, + config.Server.Path, config.Server.Port); err != nil { logger.Fatalf("Could not configure healthcheck: %v", err) } - if configuration.Server.Path == "" { + if config.Server.Path == "" { logger.Infof("Initializing server for %s connections on '%s' path '/'", connectionType, listener.Addr().String()) } else { - logger.Infof("Initializing server for %s connections on '%s' paths '/' and '%s'", connectionType, listener.Addr().String(), configuration.Server.Path) + logger.Infof("Initializing server for %s connections on '%s' paths '/' and '%s'", connectionType, listener.Addr().String(), config.Server.Path) } return server, listener