2022-10-30 08:52:49 +00:00
package handlers
import (
2022-11-19 05:48:47 +00:00
"encoding/json"
"errors"
2022-12-31 07:27:43 +00:00
"fmt"
2023-02-11 15:47:03 +00:00
"net/url"
2022-11-19 05:48:47 +00:00
"strconv"
"github.com/valyala/fasthttp"
2022-10-30 08:52:49 +00:00
"github.com/authelia/authelia/v4/internal/middlewares"
2022-12-31 07:27:43 +00:00
"github.com/authelia/authelia/v4/internal/model"
2022-11-19 05:48:47 +00:00
"github.com/authelia/authelia/v4/internal/regulation"
2023-01-25 11:03:30 +00:00
"github.com/authelia/authelia/v4/internal/session"
2022-12-12 01:21:27 +00:00
"github.com/authelia/authelia/v4/internal/storage"
2022-10-30 08:52:49 +00:00
)
2023-04-11 04:40:09 +00:00
func getWebAuthnDeviceIDFromContext ( ctx * middlewares . AutheliaCtx ) ( int , error ) {
2022-11-19 05:48:47 +00:00
deviceIDStr , ok := ctx . UserValue ( "deviceID" ) . ( string )
if ! ok {
ctx . SetStatusCode ( fasthttp . StatusBadRequest )
return 0 , errors . New ( "Invalid device ID type" )
}
deviceID , err := strconv . Atoi ( deviceIDStr )
if err != nil {
ctx . Error ( err , messageOperationFailed )
ctx . SetStatusCode ( fasthttp . StatusBadRequest )
return 0 , err
}
return deviceID , nil
}
2023-04-11 04:40:09 +00:00
// WebAuthnDevicesGET returns all devices registered for the current user.
func WebAuthnDevicesGET ( ctx * middlewares . AutheliaCtx ) {
2023-01-25 11:03:30 +00:00
var (
userSession session . UserSession
2023-02-11 15:47:03 +00:00
origin * url . URL
2023-01-25 11:03:30 +00:00
err error
)
if userSession , err = ctx . GetSession ( ) ; err != nil {
ctx . Logger . WithError ( err ) . Error ( "Error occurred retrieving user session" )
ctx . ReplyForbidden ( )
2022-10-30 08:52:49 +00:00
2023-01-25 11:03:30 +00:00
return
}
2023-02-11 15:47:03 +00:00
if origin , err = ctx . GetOrigin ( ) ; err != nil {
ctx . Logger . WithError ( err ) . Error ( "Error occurred retrieving origin" )
ctx . ReplyForbidden ( )
return
}
2023-04-11 04:40:09 +00:00
devices , err := ctx . Providers . StorageProvider . LoadWebAuthnDevicesByUsername ( ctx , origin . Hostname ( ) , userSession . Username )
2022-10-30 08:52:49 +00:00
2023-04-11 04:40:09 +00:00
if err != nil && err != storage . ErrNoWebAuthnDevice {
2022-10-30 08:52:49 +00:00
ctx . Error ( err , messageOperationFailed )
return
}
if err = ctx . SetJSONBody ( devices ) ; err != nil {
ctx . Error ( err , messageOperationFailed )
return
}
}
2022-11-19 05:48:47 +00:00
2023-04-11 04:40:09 +00:00
// WebAuthnDevicePUT updates the description for a specific device for the current user.
func WebAuthnDevicePUT ( ctx * middlewares . AutheliaCtx ) {
2022-12-31 07:27:43 +00:00
var (
2023-04-11 04:40:09 +00:00
bodyJSON bodyEditWebAuthnDeviceRequest
2022-11-19 05:48:47 +00:00
2023-01-25 11:03:30 +00:00
id int
2023-04-11 04:40:09 +00:00
device * model . WebAuthnDevice
2023-01-25 11:03:30 +00:00
userSession session . UserSession
err error
2022-12-31 07:27:43 +00:00
)
2022-11-19 05:48:47 +00:00
2023-01-25 11:03:30 +00:00
if userSession , err = ctx . GetSession ( ) ; err != nil {
ctx . Logger . WithError ( err ) . Error ( "Error occurred retrieving user session" )
ctx . ReplyForbidden ( )
return
}
2022-11-19 05:48:47 +00:00
2022-12-31 07:27:43 +00:00
if err = json . Unmarshal ( ctx . PostBody ( ) , & bodyJSON ) ; err != nil {
2023-04-11 04:40:09 +00:00
ctx . Logger . Errorf ( "Unable to parse %s update request data for user '%s': %+v" , regulation . AuthTypeWebAuthn , userSession . Username , err )
2022-11-19 05:48:47 +00:00
ctx . SetStatusCode ( fasthttp . StatusBadRequest )
ctx . Error ( err , messageOperationFailed )
return
}
2023-04-11 04:40:09 +00:00
if id , err = getWebAuthnDeviceIDFromContext ( ctx ) ; err != nil {
2022-12-31 07:27:43 +00:00
return
}
2023-04-11 04:40:09 +00:00
if device , err = ctx . Providers . StorageProvider . LoadWebAuthnDeviceByID ( ctx , id ) ; err != nil {
2022-12-31 07:27:43 +00:00
ctx . Error ( err , messageOperationFailed )
return
}
2023-01-25 11:03:30 +00:00
if device . Username != userSession . Username {
ctx . Error ( fmt . Errorf ( "user '%s' tried to delete device with id '%d' which belongs to '%s" , userSession . Username , device . ID , device . Username ) , messageOperationFailed )
2022-11-19 05:48:47 +00:00
return
}
2023-04-11 04:40:09 +00:00
if err = ctx . Providers . StorageProvider . UpdateWebAuthnDeviceDescription ( ctx , userSession . Username , id , bodyJSON . Description ) ; err != nil {
2022-11-19 05:48:47 +00:00
ctx . Error ( err , messageOperationFailed )
return
}
}
2023-04-11 04:40:09 +00:00
// WebAuthnDeviceDELETE deletes a specific device for the current user.
func WebAuthnDeviceDELETE ( ctx * middlewares . AutheliaCtx ) {
2022-12-31 07:27:43 +00:00
var (
2023-01-25 11:03:30 +00:00
id int
2023-04-11 04:40:09 +00:00
device * model . WebAuthnDevice
2023-01-25 11:03:30 +00:00
userSession session . UserSession
err error
2022-12-31 07:27:43 +00:00
)
2022-11-19 05:48:47 +00:00
2023-04-11 04:40:09 +00:00
if id , err = getWebAuthnDeviceIDFromContext ( ctx ) ; err != nil {
2022-12-31 07:27:43 +00:00
return
}
2023-04-11 04:40:09 +00:00
if device , err = ctx . Providers . StorageProvider . LoadWebAuthnDeviceByID ( ctx , id ) ; err != nil {
2022-12-31 07:27:43 +00:00
ctx . Error ( err , messageOperationFailed )
2022-11-19 05:48:47 +00:00
return
}
2023-01-25 11:03:30 +00:00
if userSession , err = ctx . GetSession ( ) ; err != nil {
ctx . Logger . WithError ( err ) . Error ( "Error occurred retrieving user session" )
ctx . ReplyForbidden ( )
return
}
2022-12-31 07:27:43 +00:00
2023-01-25 11:03:30 +00:00
if device . Username != userSession . Username {
ctx . Error ( fmt . Errorf ( "user '%s' tried to delete device with id '%d' which belongs to '%s" , userSession . Username , device . ID , device . Username ) , messageOperationFailed )
2022-12-31 07:27:43 +00:00
return
}
2023-04-11 04:40:09 +00:00
if err = ctx . Providers . StorageProvider . DeleteWebAuthnDevice ( ctx , device . KID . String ( ) ) ; err != nil {
2022-11-19 05:48:47 +00:00
ctx . Error ( err , messageOperationFailed )
return
}
2022-12-31 07:27:43 +00:00
ctx . ReplyOK ( )
2022-11-19 05:48:47 +00:00
}