2019-04-25 04:52:08 +07:00
package handlers
import (
"fmt"
"time"
2019-12-24 09:14:52 +07:00
"github.com/authelia/authelia/internal/authentication"
"github.com/authelia/authelia/internal/middlewares"
"github.com/authelia/authelia/internal/regulation"
"github.com/authelia/authelia/internal/session"
2019-04-25 04:52:08 +07:00
)
// FirstFactorPost is the handler performing the first factory.
2020-05-05 02:39:25 +07:00
//nolint:gocyclo // TODO: Consider refactoring time permitting.
2019-04-25 04:52:08 +07:00
func FirstFactorPost ( ctx * middlewares . AutheliaCtx ) {
bodyJSON := firstFactorRequestBody { }
err := ctx . ParseBody ( & bodyJSON )
if err != nil {
2020-05-06 04:27:38 +07:00
handleAuthenticationUnauthorized ( ctx , err , authenticationFailedMessage )
2019-04-25 04:52:08 +07:00
return
}
bannedUntil , err := ctx . Providers . Regulator . Regulate ( bodyJSON . Username )
2019-11-30 23:49:52 +07:00
if err != nil {
if err == regulation . ErrUserIsBanned {
2020-05-06 04:27:38 +07:00
handleAuthenticationUnauthorized ( ctx , fmt . Errorf ( "User %s is banned until %s" , bodyJSON . Username , bannedUntil ) , userBannedMessage )
2019-11-30 23:49:52 +07:00
return
}
2020-05-06 02:35:32 +07:00
2020-05-06 04:27:38 +07:00
handleAuthenticationUnauthorized ( ctx , fmt . Errorf ( "Unable to regulate authentication: %s" , err . Error ( ) ) , authenticationFailedMessage )
2020-05-06 02:35:32 +07:00
2019-04-25 04:52:08 +07:00
return
}
userPasswordOk , err := ctx . Providers . UserProvider . CheckUserPassword ( bodyJSON . Username , bodyJSON . Password )
if err != nil {
2019-11-25 03:27:59 +07:00
ctx . Logger . Debugf ( "Mark authentication attempt made by user %s" , bodyJSON . Username )
2020-04-22 10:33:14 +07:00
ctx . Providers . Regulator . Mark ( bodyJSON . Username , false ) //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting.
2019-11-25 03:27:59 +07:00
2020-05-06 04:27:38 +07:00
handleAuthenticationUnauthorized ( ctx , fmt . Errorf ( "Error while checking password for user %s: %s" , bodyJSON . Username , err . Error ( ) ) , authenticationFailedMessage )
2020-05-06 02:35:32 +07:00
2019-04-25 04:52:08 +07:00
return
}
if ! userPasswordOk {
2019-11-30 23:49:52 +07:00
ctx . Logger . Debugf ( "Mark authentication attempt made by user %s" , bodyJSON . Username )
2020-04-22 10:33:14 +07:00
ctx . Providers . Regulator . Mark ( bodyJSON . Username , false ) //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting.
2019-11-30 23:49:52 +07:00
2020-05-06 04:27:38 +07:00
handleAuthenticationUnauthorized ( ctx , fmt . Errorf ( "Credentials are wrong for user %s" , bodyJSON . Username ) , authenticationFailedMessage )
2019-11-17 02:50:58 +07:00
ctx . ReplyError ( fmt . Errorf ( "Credentials are wrong for user %s" , bodyJSON . Username ) , authenticationFailedMessage )
2020-05-06 02:35:32 +07:00
2019-04-25 04:52:08 +07:00
return
}
ctx . Logger . Debugf ( "Credentials validation of user %s is ok" , bodyJSON . Username )
2019-11-30 21:33:45 +07:00
ctx . Logger . Debugf ( "Mark authentication attempt made by user %s" , bodyJSON . Username )
err = ctx . Providers . Regulator . Mark ( bodyJSON . Username , true )
if err != nil {
2020-05-06 04:27:38 +07:00
handleAuthenticationUnauthorized ( ctx , fmt . Errorf ( "Unable to mark authentication: %s" , err . Error ( ) ) , authenticationFailedMessage )
2019-11-30 21:33:45 +07:00
return
}
2019-04-25 04:52:08 +07:00
// Reset all values from previous session before regenerating the cookie.
err = ctx . SaveSession ( session . NewDefaultUserSession ( ) )
if err != nil {
2020-05-06 04:27:38 +07:00
handleAuthenticationUnauthorized ( ctx , fmt . Errorf ( "Unable to reset the session for user %s: %s" , bodyJSON . Username , err . Error ( ) ) , authenticationFailedMessage )
2019-04-25 04:52:08 +07:00
return
}
err = ctx . Providers . SessionProvider . RegenerateSession ( ctx . RequestCtx )
if err != nil {
2020-05-06 04:27:38 +07:00
handleAuthenticationUnauthorized ( ctx , fmt . Errorf ( "Unable to regenerate session for user %s: %s" , bodyJSON . Username , err . Error ( ) ) , authenticationFailedMessage )
2019-04-25 04:52:08 +07:00
return
}
2020-04-04 06:11:33 +07:00
// Check if bodyJSON.KeepMeLoggedIn can be deref'd and derive the value based on the configuration and JSON data
keepMeLoggedIn := ctx . Providers . SessionProvider . RememberMe != 0 && 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 )
2019-04-25 04:52:08 +07:00
if err != nil {
2020-05-06 04:27:38 +07:00
handleAuthenticationUnauthorized ( ctx , fmt . Errorf ( "Unable to update expiration timer for user %s: %s" , bodyJSON . Username , err . Error ( ) ) , authenticationFailedMessage )
2019-04-25 04:52:08 +07:00
return
}
}
// Get the details of the given user from the user provider.
userDetails , err := ctx . Providers . UserProvider . GetDetails ( bodyJSON . Username )
if err != nil {
2020-05-06 04:27:38 +07:00
handleAuthenticationUnauthorized ( ctx , fmt . Errorf ( "Error while retrieving details from user %s: %s" , bodyJSON . Username , err . Error ( ) ) , authenticationFailedMessage )
2019-04-25 04:52:08 +07:00
return
}
2019-11-17 02:50:58 +07:00
ctx . Logger . Tracef ( "Details for user %s => groups: %s, emails %s" , bodyJSON . Username , userDetails . Groups , userDetails . Emails )
2019-04-25 04:52:08 +07:00
// And set those information in the new session.
userSession := ctx . GetSession ( )
2020-03-15 14:10:25 +07:00
userSession . Username = userDetails . Username
2019-04-25 04:52:08 +07:00
userSession . Groups = userDetails . Groups
userSession . Emails = userDetails . Emails
userSession . AuthenticationLevel = authentication . OneFactor
userSession . LastActivity = time . Now ( ) . Unix ( )
2020-04-04 06:11:33 +07:00
userSession . KeepMeLoggedIn = keepMeLoggedIn
2020-05-05 02:39:25 +07:00
refresh , refreshInterval := getProfileRefreshSettings ( ctx . Configuration . AuthenticationBackend )
2020-05-06 02:35:32 +07:00
2020-05-05 02:39:25 +07:00
if refresh {
userSession . RefreshTTL = ctx . Clock . Now ( ) . Add ( refreshInterval )
}
2020-05-06 02:35:32 +07:00
2019-04-25 04:52:08 +07:00
err = ctx . SaveSession ( userSession )
if err != nil {
2020-05-06 04:27:38 +07:00
handleAuthenticationUnauthorized ( ctx , fmt . Errorf ( "Unable to save session of user %s" , bodyJSON . Username ) , authenticationFailedMessage )
2019-04-25 04:52:08 +07:00
return
}
2020-02-05 04:18:02 +07:00
Handle1FAResponse ( ctx , bodyJSON . TargetURL , userSession . Username , userSession . Groups )
2019-04-25 04:52:08 +07:00
}