2019-12-07 11:18:22 +00:00
package handlers
import (
"fmt"
"strings"
"sync"
2020-04-05 12:37:21 +00:00
"github.com/sirupsen/logrus"
2021-08-11 01:04:35 +00:00
"github.com/authelia/authelia/v4/internal/authentication"
"github.com/authelia/authelia/v4/internal/middlewares"
"github.com/authelia/authelia/v4/internal/storage"
"github.com/authelia/authelia/v4/internal/utils"
2019-12-07 11:18:22 +00:00
)
2020-06-21 13:40:37 +00:00
func loadInfo ( username string , storageProvider storage . Provider , userInfo * UserInfo , logger * logrus . Entry ) [ ] error {
2019-12-07 11:18:22 +00:00
var wg sync . WaitGroup
2020-05-05 19:35:32 +00:00
2019-12-07 11:18:22 +00:00
wg . Add ( 3 )
errors := make ( [ ] error , 0 )
2020-05-05 19:35:32 +00:00
2019-12-07 11:18:22 +00:00
go func ( ) {
defer wg . Done ( )
2020-05-05 19:35:32 +00:00
2020-01-21 00:10:00 +00:00
method , err := storageProvider . LoadPreferred2FAMethod ( username )
2019-12-07 11:18:22 +00:00
if err != nil {
errors = append ( errors , err )
logger . Error ( err )
2020-05-05 19:35:32 +00:00
2019-12-07 11:18:22 +00:00
return
}
2020-05-05 19:35:32 +00:00
2019-12-07 11:18:22 +00:00
if method == "" {
2020-06-21 13:40:37 +00:00
userInfo . Method = authentication . PossibleMethods [ 0 ]
2019-12-07 11:18:22 +00:00
} else {
2020-06-21 13:40:37 +00:00
userInfo . Method = method
2019-12-07 11:18:22 +00:00
}
} ( )
go func ( ) {
defer wg . Done ( )
2020-05-05 19:35:32 +00:00
2020-01-21 00:10:00 +00:00
_ , _ , err := storageProvider . LoadU2FDeviceHandle ( username )
2019-12-07 11:18:22 +00:00
if err != nil {
if err == storage . ErrNoU2FDeviceHandle {
return
}
2020-05-05 19:35:32 +00:00
2019-12-07 11:18:22 +00:00
errors = append ( errors , err )
logger . Error ( err )
2020-05-05 19:35:32 +00:00
2019-12-07 11:18:22 +00:00
return
}
2020-05-05 19:35:32 +00:00
2020-06-21 13:40:37 +00:00
userInfo . HasU2F = true
2019-12-07 11:18:22 +00:00
} ( )
go func ( ) {
defer wg . Done ( )
2020-05-05 19:35:32 +00:00
2020-01-21 00:10:00 +00:00
_ , err := storageProvider . LoadTOTPSecret ( username )
2019-12-07 11:18:22 +00:00
if err != nil {
if err == storage . ErrNoTOTPSecret {
return
}
2020-05-05 19:35:32 +00:00
2019-12-07 11:18:22 +00:00
errors = append ( errors , err )
logger . Error ( err )
2020-05-05 19:35:32 +00:00
2019-12-07 11:18:22 +00:00
return
}
2020-05-05 19:35:32 +00:00
2020-06-21 13:40:37 +00:00
userInfo . HasTOTP = true
2019-12-07 11:18:22 +00:00
} ( )
wg . Wait ( )
2020-05-05 19:35:32 +00:00
2019-12-07 11:18:22 +00:00
return errors
}
2020-01-21 00:10:00 +00:00
// UserInfoGet get the info related to the user identified by the session.
2019-12-07 11:18:22 +00:00
func UserInfoGet ( ctx * middlewares . AutheliaCtx ) {
userSession := ctx . GetSession ( )
2020-06-21 13:40:37 +00:00
userInfo := UserInfo { }
errors := loadInfo ( userSession . Username , ctx . Providers . StorageProvider , & userInfo , ctx . Logger )
2019-12-07 11:18:22 +00:00
if len ( errors ) > 0 {
2021-09-17 05:53:40 +00:00
ctx . Error ( fmt . Errorf ( "unable to load user information" ) , messageOperationFailed )
2019-12-07 11:18:22 +00:00
return
}
2020-05-05 19:35:32 +00:00
2020-06-21 13:40:37 +00:00
userInfo . DisplayName = userSession . DisplayName
2020-12-16 01:47:31 +00:00
err := ctx . SetJSONBody ( userInfo )
if err != nil {
ctx . Logger . Errorf ( "Unable to set user info response in body: %s" , err )
}
2019-12-07 11:18:22 +00:00
}
2020-04-20 21:03:38 +00:00
// MethodBody the selected 2FA method.
2019-12-07 11:18:22 +00:00
type MethodBody struct {
Method string ` json:"method" valid:"required" `
}
// MethodPreferencePost update the user preferences regarding 2FA method.
func MethodPreferencePost ( ctx * middlewares . AutheliaCtx ) {
bodyJSON := MethodBody { }
2020-05-05 19:35:32 +00:00
2019-12-07 11:18:22 +00:00
err := ctx . ParseBody ( & bodyJSON )
if err != nil {
2021-07-22 03:52:37 +00:00
ctx . Error ( err , messageOperationFailed )
2019-12-07 11:18:22 +00:00
return
}
if ! utils . IsStringInSlice ( bodyJSON . Method , authentication . PossibleMethods ) {
2021-09-17 05:53:40 +00:00
ctx . Error ( fmt . Errorf ( "unknown method '%s', it should be one of %s" , bodyJSON . Method , strings . Join ( authentication . PossibleMethods , ", " ) ) , messageOperationFailed )
2019-12-07 11:18:22 +00:00
return
}
userSession := ctx . GetSession ( )
2020-01-05 23:03:16 +00:00
ctx . Logger . Debugf ( "Save new preferred 2FA method of user %s to %s" , userSession . Username , bodyJSON . Method )
err = ctx . Providers . StorageProvider . SavePreferred2FAMethod ( userSession . Username , bodyJSON . Method )
2019-12-07 11:18:22 +00:00
if err != nil {
2021-09-17 05:53:40 +00:00
ctx . Error ( fmt . Errorf ( "unable to save new preferred 2FA method: %s" , err ) , messageOperationFailed )
2019-12-07 11:18:22 +00:00
return
}
ctx . ReplyOK ( )
}