1
0
mirror of https://github.com/0rangebananaspy/authelia.git synced 2024-09-14 22:47:21 +07:00
authelia/internal/handlers/handler_firstfactor.go
James Elliott ce6bf74c8d
fix(server): incorrect remote ip logged in error handler ()
This fixes edge cases where the remote IP was not correctly logged. Generally this is not an issue as most errors do not hit this handler, but in instances where a transport error occurs this is important.
2022-04-08 14:13:47 +10:00

145 lines
4.6 KiB
Go

package handlers
import (
"errors"
"time"
"github.com/authelia/authelia/v4/internal/configuration/schema"
"github.com/authelia/authelia/v4/internal/middlewares"
"github.com/authelia/authelia/v4/internal/regulation"
"github.com/authelia/authelia/v4/internal/session"
)
// FirstFactorPOST is the handler performing the first factory.
//nolint:gocyclo // TODO: Consider refactoring time permitting.
func FirstFactorPOST(delayFunc middlewares.TimingAttackDelayFunc) middlewares.RequestHandler {
return func(ctx *middlewares.AutheliaCtx) {
var successful bool
requestTime := time.Now()
if delayFunc != nil {
defer delayFunc(ctx.Logger, requestTime, &successful)
}
bodyJSON := firstFactorRequestBody{}
if err := ctx.ParseBody(&bodyJSON); err != nil {
ctx.Logger.Errorf(logFmtErrParseRequestBody, regulation.AuthType1FA, err)
respondUnauthorized(ctx, messageAuthenticationFailed)
return
}
if bannedUntil, err := ctx.Providers.Regulator.Regulate(ctx, bodyJSON.Username); err != nil {
if errors.Is(err, regulation.ErrUserIsBanned) {
_ = markAuthenticationAttempt(ctx, false, &bannedUntil, bodyJSON.Username, regulation.AuthType1FA, nil)
respondUnauthorized(ctx, messageAuthenticationFailed)
return
}
ctx.Logger.Errorf(logFmtErrRegulationFail, regulation.AuthType1FA, bodyJSON.Username, err)
respondUnauthorized(ctx, messageAuthenticationFailed)
return
}
userPasswordOk, err := ctx.Providers.UserProvider.CheckUserPassword(bodyJSON.Username, bodyJSON.Password)
if err != nil {
_ = markAuthenticationAttempt(ctx, false, nil, bodyJSON.Username, regulation.AuthType1FA, err)
respondUnauthorized(ctx, messageAuthenticationFailed)
return
}
if !userPasswordOk {
_ = markAuthenticationAttempt(ctx, false, nil, bodyJSON.Username, regulation.AuthType1FA, nil)
respondUnauthorized(ctx, messageAuthenticationFailed)
return
}
if err = markAuthenticationAttempt(ctx, true, nil, bodyJSON.Username, regulation.AuthType1FA, nil); err != nil {
respondUnauthorized(ctx, messageAuthenticationFailed)
return
}
userSession := ctx.GetSession()
newSession := session.NewDefaultUserSession()
newSession.ConsentChallengeID = userSession.ConsentChallengeID
// Reset all values from previous session except OIDC workflow before regenerating the cookie.
if err = ctx.SaveSession(newSession); err != nil {
ctx.Logger.Errorf(logFmtErrSessionReset, regulation.AuthType1FA, bodyJSON.Username, err)
respondUnauthorized(ctx, messageAuthenticationFailed)
return
}
if err = ctx.Providers.SessionProvider.RegenerateSession(ctx.RequestCtx); err != nil {
ctx.Logger.Errorf(logFmtErrSessionRegenerate, regulation.AuthType1FA, bodyJSON.Username, err)
respondUnauthorized(ctx, messageAuthenticationFailed)
return
}
// Check if bodyJSON.KeepMeLoggedIn can be deref'd and derive the value based on the configuration and JSON data.
keepMeLoggedIn := ctx.Providers.SessionProvider.RememberMe != schema.RememberMeDisabled && bodyJSON.KeepMeLoggedIn != nil && *bodyJSON.KeepMeLoggedIn
// Set the cookie to expire if remember me is enabled and the user has asked us to.
if keepMeLoggedIn {
err = ctx.Providers.SessionProvider.UpdateExpiration(ctx.RequestCtx, ctx.Providers.SessionProvider.RememberMe)
if err != nil {
ctx.Logger.Errorf(logFmtErrSessionSave, "updated expiration", regulation.AuthType1FA, bodyJSON.Username, err)
respondUnauthorized(ctx, messageAuthenticationFailed)
return
}
}
// Get the details of the given user from the user provider.
userDetails, err := ctx.Providers.UserProvider.GetDetails(bodyJSON.Username)
if err != nil {
ctx.Logger.Errorf(logFmtErrObtainProfileDetails, regulation.AuthType1FA, bodyJSON.Username, err)
respondUnauthorized(ctx, messageAuthenticationFailed)
return
}
ctx.Logger.Tracef(logFmtTraceProfileDetails, bodyJSON.Username, userDetails.Groups, userDetails.Emails)
userSession.SetOneFactor(ctx.Clock.Now(), userDetails, keepMeLoggedIn)
if refresh, refreshInterval := getProfileRefreshSettings(ctx.Configuration.AuthenticationBackend); refresh {
userSession.RefreshTTL = ctx.Clock.Now().Add(refreshInterval)
}
if err = ctx.SaveSession(userSession); err != nil {
ctx.Logger.Errorf(logFmtErrSessionSave, "updated profile", regulation.AuthType1FA, bodyJSON.Username, err)
respondUnauthorized(ctx, messageAuthenticationFailed)
return
}
successful = true
if userSession.ConsentChallengeID != nil {
handleOIDCWorkflowResponse(ctx)
} else {
Handle1FAResponse(ctx, bodyJSON.TargetURL, bodyJSON.RequestMethod, userSession.Username, userSession.Groups)
}
}
}