1
0
mirror of https://github.com/0rangebananaspy/authelia.git synced 2024-09-14 22:47:21 +07:00
authelia/internal/handlers/handler_register_duo_device.go
Philipp Staiger 01b77384f9
feat(duo): multi device selection ()
Allow users to select and save the preferred duo device and method, depending on availability in the duo account. A default enrollment URL is provided and adjusted if returned by the duo API. This allows auto-enrollment if enabled by the administrator.

Closes . Closes .
2021-12-01 14:32:58 +11:00

121 lines
4.0 KiB
Go

package handlers
import (
"fmt"
"net/url"
"strings"
"github.com/authelia/authelia/v4/internal/duo"
"github.com/authelia/authelia/v4/internal/middlewares"
"github.com/authelia/authelia/v4/internal/models"
"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 {
return func(ctx *middlewares.AutheliaCtx) {
userSession := ctx.GetSession()
values := url.Values{}
values.Set("username", userSession.Username)
ctx.Logger.Debugf("Starting Duo PreAuth for %s", userSession.Username)
result, message, devices, enrollURL, err := DuoPreAuth(ctx, duoAPI)
if err != nil {
ctx.Error(fmt.Errorf("duo PreAuth API errored: %s", err), messageMFAValidationFailed)
return
}
if result == auth {
if devices == nil {
ctx.Logger.Debugf("No applicable device/method available for Duo user %s", userSession.Username)
if err := ctx.SetJSONBody(DuoDevicesResponse{Result: enroll}); err != nil {
ctx.Error(fmt.Errorf("unable to set JSON body in response"), messageMFAValidationFailed)
}
return
}
if err := ctx.SetJSONBody(DuoDevicesResponse{Result: auth, Devices: devices}); err != nil {
ctx.Error(fmt.Errorf("unable to set JSON body in response"), messageMFAValidationFailed)
}
return
}
if result == allow {
ctx.Logger.Debugf("Device selection not possible for user %s, because Duo authentication was bypassed - Defaults to Auto Push", userSession.Username)
if err := ctx.SetJSONBody(DuoDevicesResponse{Result: allow}); err != nil {
ctx.Error(fmt.Errorf("unable to set JSON body in response"), messageMFAValidationFailed)
}
return
}
if result == enroll {
ctx.Logger.Debugf("Duo user: %s not enrolled", userSession.Username)
if err := ctx.SetJSONBody(DuoDevicesResponse{Result: enroll, EnrollURL: enrollURL}); err != nil {
ctx.Error(fmt.Errorf("unable to set JSON body in response"), messageMFAValidationFailed)
}
return
}
if result == deny {
ctx.Logger.Debugf("Duo User not allowed to authenticate: %s", userSession.Username)
if err := ctx.SetJSONBody(DuoDevicesResponse{Result: deny}); err != nil {
ctx.Error(fmt.Errorf("unable to set JSON body in response"), messageMFAValidationFailed)
}
return
}
ctx.Error(fmt.Errorf("duo PreAuth API errored for %s: %s - %s", userSession.Username, result, message), messageMFAValidationFailed)
}
}
// SecondFactorDuoDevicePost update the user preferences regarding Duo device and method.
func SecondFactorDuoDevicePost(ctx *middlewares.AutheliaCtx) {
device := DuoDeviceBody{}
err := ctx.ParseBody(&device)
if err != nil {
ctx.Error(err, messageMFAValidationFailed)
return
}
if !utils.IsStringInSlice(device.Method, duo.PossibleMethods) {
ctx.Error(fmt.Errorf("unknown method '%s', it should be one of %s", device.Method, strings.Join(duo.PossibleMethods, ", ")), messageMFAValidationFailed)
return
}
userSession := ctx.GetSession()
ctx.Logger.Debugf("Save new preferred Duo device and method of user %s to %s using %s", userSession.Username, device.Device, device.Method)
err = ctx.Providers.StorageProvider.SavePreferredDuoDevice(ctx, models.DuoDevice{Username: userSession.Username, Device: device.Device, Method: device.Method})
if err != nil {
ctx.Error(fmt.Errorf("unable to save new preferred Duo device and method: %s", err), messageMFAValidationFailed)
return
}
ctx.ReplyOK()
}
// SecondFactorDuoDeviceDelete deletes the useres preferred Duo device and method.
func SecondFactorDuoDeviceDelete(ctx *middlewares.AutheliaCtx) {
userSession := ctx.GetSession()
ctx.Logger.Debugf("Deleting preferred Duo device and method of user %s", userSession.Username)
err := ctx.Providers.StorageProvider.DeletePreferredDuoDevice(ctx, userSession.Username)
if err != nil {
ctx.Error(fmt.Errorf("unable to delete preferred Duo device and method: %s", err), messageMFAValidationFailed)
return
}
ctx.ReplyOK()
}