feat(commands): add webauthn device commands (#3671)

pull/4209/head
James Elliott 2022-10-19 18:17:55 +11:00 committed by GitHub
parent 52102eea8c
commit 24e41aed84
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 575 additions and 7 deletions

View File

@ -62,4 +62,5 @@ authelia storage user --help
* [authelia storage](authelia_storage.md) - Manage the Authelia storage * [authelia storage](authelia_storage.md) - Manage the Authelia storage
* [authelia storage user identifiers](authelia_storage_user_identifiers.md) - Manage user opaque identifiers * [authelia storage user identifiers](authelia_storage_user_identifiers.md) - Manage user opaque identifiers
* [authelia storage user totp](authelia_storage_user_totp.md) - Manage TOTP configurations * [authelia storage user totp](authelia_storage_user_totp.md) - Manage TOTP configurations
* [authelia storage user webauthn](authelia_storage_user_webauthn.md) - Manage Webauthn devices

View File

@ -0,0 +1,65 @@
---
title: "authelia storage user webauthn"
description: "Reference for the authelia storage user webauthn command."
lead: ""
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia storage user webauthn
Manage Webauthn devices
### Synopsis
Manage Webauthn devices.
This subcommand allows interacting with Webauthn devices.
### Examples
```
authelia storage user webauthn --help
```
### Options
```
-h, --help help for webauthn
```
### Options inherited from parent commands
```
-c, --config strings configuration files to load (default [configuration.yml])
--encryption-key string the storage encryption key to use
--mysql.database string the MySQL database name (default "authelia")
--mysql.host string the MySQL hostname
--mysql.password string the MySQL password
--mysql.port int the MySQL port (default 3306)
--mysql.username string the MySQL username (default "authelia")
--postgres.database string the PostgreSQL database name (default "authelia")
--postgres.host string the PostgreSQL hostname
--postgres.password string the PostgreSQL password
--postgres.port int the PostgreSQL port (default 5432)
--postgres.schema string the PostgreSQL schema name (default "public")
--postgres.ssl.certificate string the PostgreSQL ssl certificate file location
--postgres.ssl.key string the PostgreSQL ssl key file location
--postgres.ssl.mode string the PostgreSQL ssl mode (default "disable")
--postgres.ssl.root_certificate string the PostgreSQL ssl root certificate file location
--postgres.username string the PostgreSQL username (default "authelia")
--sqlite.path string the SQLite database path
```
### SEE ALSO
* [authelia storage user](authelia_storage_user.md) - Manages user settings
* [authelia storage user webauthn delete](authelia_storage_user_webauthn_delete.md) - Delete a WebAuthn device
* [authelia storage user webauthn list](authelia_storage_user_webauthn_list.md) - List WebAuthn devices

View File

@ -0,0 +1,78 @@
---
title: "authelia storage user webauthn delete"
description: "Reference for the authelia storage user webauthn delete command."
lead: ""
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia storage user webauthn delete
Delete a WebAuthn device
### Synopsis
Delete a WebAuthn device.
This subcommand allows deleting a WebAuthn device directly from the database.
```
authelia storage user webauthn delete [username] [flags]
```
### Examples
```
authelia storage user webauthn delete john --all
authelia storage user webauthn delete john --all --config config.yml
authelia storage user webauthn delete john --all --encryption-key b3453fde-ecc2-4a1f-9422-2707ddbed495 --postgres.host postgres --postgres.password autheliapw
authelia storage user webauthn delete john --description Primary
authelia storage user webauthn delete john --description Primary --config config.yml
authelia storage user webauthn delete john --description Primary --encryption-key b3453fde-ecc2-4a1f-9422-2707ddbed495 --postgres.host postgres --postgres.password autheliapw
authelia storage user webauthn delete --kid abc123
authelia storage user webauthn delete --kid abc123 --config config.yml
authelia storage user webauthn delete --kid abc123 --encryption-key b3453fde-ecc2-4a1f-9422-2707ddbed495 --postgres.host postgres --postgres.password autheliapw
```
### Options
```
--all delete all of the users webauthn devices
--description string delete a users webauthn device by description
-h, --help help for delete
--kid string delete a users webauthn device by key id
```
### Options inherited from parent commands
```
-c, --config strings configuration files to load (default [configuration.yml])
--encryption-key string the storage encryption key to use
--mysql.database string the MySQL database name (default "authelia")
--mysql.host string the MySQL hostname
--mysql.password string the MySQL password
--mysql.port int the MySQL port (default 3306)
--mysql.username string the MySQL username (default "authelia")
--postgres.database string the PostgreSQL database name (default "authelia")
--postgres.host string the PostgreSQL hostname
--postgres.password string the PostgreSQL password
--postgres.port int the PostgreSQL port (default 5432)
--postgres.schema string the PostgreSQL schema name (default "public")
--postgres.ssl.certificate string the PostgreSQL ssl certificate file location
--postgres.ssl.key string the PostgreSQL ssl key file location
--postgres.ssl.mode string the PostgreSQL ssl mode (default "disable")
--postgres.ssl.root_certificate string the PostgreSQL ssl root certificate file location
--postgres.username string the PostgreSQL username (default "authelia")
--sqlite.path string the SQLite database path
```
### SEE ALSO
* [authelia storage user webauthn](authelia_storage_user_webauthn.md) - Manage Webauthn devices

View File

@ -0,0 +1,72 @@
---
title: "authelia storage user webauthn list"
description: "Reference for the authelia storage user webauthn list command."
lead: ""
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia storage user webauthn list
List WebAuthn devices
### Synopsis
List WebAuthn devices.
This subcommand allows listing WebAuthn devices.
```
authelia storage user webauthn list [username] [flags]
```
### Examples
```
authelia storage user webauthn list
authelia storage user webauthn list john
authelia storage user webauthn list --config config.yml
authelia storage user webauthn list john --config config.yml
authelia storage user webauthn list --encryption-key b3453fde-ecc2-4a1f-9422-2707ddbed495 --postgres.host postgres --postgres.password autheliapw
authelia storage user webauthn list john --encryption-key b3453fde-ecc2-4a1f-9422-2707ddbed495 --postgres.host postgres --postgres.password autheliapw
```
### Options
```
-h, --help help for list
```
### Options inherited from parent commands
```
-c, --config strings configuration files to load (default [configuration.yml])
--encryption-key string the storage encryption key to use
--mysql.database string the MySQL database name (default "authelia")
--mysql.host string the MySQL hostname
--mysql.password string the MySQL password
--mysql.port int the MySQL port (default 3306)
--mysql.username string the MySQL username (default "authelia")
--postgres.database string the PostgreSQL database name (default "authelia")
--postgres.host string the PostgreSQL hostname
--postgres.password string the PostgreSQL password
--postgres.port int the PostgreSQL port (default 5432)
--postgres.schema string the PostgreSQL schema name (default "public")
--postgres.ssl.certificate string the PostgreSQL ssl certificate file location
--postgres.ssl.key string the PostgreSQL ssl key file location
--postgres.ssl.mode string the PostgreSQL ssl mode (default "disable")
--postgres.ssl.root_certificate string the PostgreSQL ssl root certificate file location
--postgres.username string the PostgreSQL username (default "authelia")
--sqlite.path string the SQLite database path
```
### SEE ALSO
* [authelia storage user webauthn](authelia_storage_user_webauthn.md) - Manage Webauthn devices

View File

@ -176,6 +176,43 @@ This subcommand allows manually adding an opaque identifier for a user to the da
authelia storage user identifiers add john --identifier f0919359-9d15-4e15-bcba-83b41620a073 --config config.yml authelia storage user identifiers add john --identifier f0919359-9d15-4e15-bcba-83b41620a073 --config config.yml
authelia storage user identifiers add john --identifier f0919359-9d15-4e15-bcba-83b41620a073 --encryption-key b3453fde-ecc2-4a1f-9422-2707ddbed495 --postgres.host postgres --postgres.password autheliapw` authelia storage user identifiers add john --identifier f0919359-9d15-4e15-bcba-83b41620a073 --encryption-key b3453fde-ecc2-4a1f-9422-2707ddbed495 --postgres.host postgres --postgres.password autheliapw`
cmdAutheliaStorageUserWebAuthnShort = "Manage Webauthn devices"
cmdAutheliaStorageUserWebAuthnLong = `Manage Webauthn devices.
This subcommand allows interacting with Webauthn devices.`
cmdAutheliaStorageUserWebAuthnExample = `authelia storage user webauthn --help`
cmdAutheliaStorageUserWebAuthnListShort = "List WebAuthn devices"
cmdAutheliaStorageUserWebAuthnListLong = `List WebAuthn devices.
This subcommand allows listing WebAuthn devices.`
cmdAutheliaStorageUserWebAuthnListExample = `authelia storage user webauthn list
authelia storage user webauthn list john
authelia storage user webauthn list --config config.yml
authelia storage user webauthn list john --config config.yml
authelia storage user webauthn list --encryption-key b3453fde-ecc2-4a1f-9422-2707ddbed495 --postgres.host postgres --postgres.password autheliapw
authelia storage user webauthn list john --encryption-key b3453fde-ecc2-4a1f-9422-2707ddbed495 --postgres.host postgres --postgres.password autheliapw`
cmdAutheliaStorageUserWebAuthnDeleteShort = "Delete a WebAuthn device"
cmdAutheliaStorageUserWebAuthnDeleteLong = `Delete a WebAuthn device.
This subcommand allows deleting a WebAuthn device directly from the database.`
cmdAutheliaStorageUserWebAuthnDeleteExample = `authelia storage user webauthn delete john --all
authelia storage user webauthn delete john --all --config config.yml
authelia storage user webauthn delete john --all --encryption-key b3453fde-ecc2-4a1f-9422-2707ddbed495 --postgres.host postgres --postgres.password autheliapw
authelia storage user webauthn delete john --description Primary
authelia storage user webauthn delete john --description Primary --config config.yml
authelia storage user webauthn delete john --description Primary --encryption-key b3453fde-ecc2-4a1f-9422-2707ddbed495 --postgres.host postgres --postgres.password autheliapw
authelia storage user webauthn delete --kid abc123
authelia storage user webauthn delete --kid abc123 --config config.yml
authelia storage user webauthn delete --kid abc123 --encryption-key b3453fde-ecc2-4a1f-9422-2707ddbed495 --postgres.host postgres --postgres.password autheliapw`
cmdAutheliaStorageUserTOTPShort = "Manage TOTP configurations" cmdAutheliaStorageUserTOTPShort = "Manage TOTP configurations"
cmdAutheliaStorageUserTOTPLong = `Manage TOTP configurations. cmdAutheliaStorageUserTOTPLong = `Manage TOTP configurations.

View File

@ -117,6 +117,7 @@ func newStorageUserCmd() (cmd *cobra.Command) {
cmd.AddCommand( cmd.AddCommand(
newStorageUserIdentifiersCmd(), newStorageUserIdentifiersCmd(),
newStorageUserTOTPCmd(), newStorageUserTOTPCmd(),
newStorageUserWebAuthnCmd(),
) )
return cmd return cmd
@ -211,6 +212,58 @@ func newStorageUserIdentifiersAddCmd() (cmd *cobra.Command) {
return cmd return cmd
} }
func newStorageUserWebAuthnCmd() (cmd *cobra.Command) {
cmd = &cobra.Command{
Use: "webauthn",
Short: cmdAutheliaStorageUserWebAuthnShort,
Long: cmdAutheliaStorageUserWebAuthnLong,
Example: cmdAutheliaStorageUserWebAuthnExample,
DisableAutoGenTag: true,
}
cmd.AddCommand(
newStorageUserWebAuthnListCmd(),
newStorageUserWebAuthnDeleteCmd(),
)
return cmd
}
func newStorageUserWebAuthnListCmd() (cmd *cobra.Command) {
cmd = &cobra.Command{
Use: "list [username]",
Short: cmdAutheliaStorageUserWebAuthnListShort,
Long: cmdAutheliaStorageUserWebAuthnListLong,
Example: cmdAutheliaStorageUserWebAuthnListExample,
RunE: storageWebAuthnListRunE,
Args: cobra.MaximumNArgs(1),
DisableAutoGenTag: true,
}
return cmd
}
func newStorageUserWebAuthnDeleteCmd() (cmd *cobra.Command) {
cmd = &cobra.Command{
Use: "delete [username]",
Short: cmdAutheliaStorageUserWebAuthnDeleteShort,
Long: cmdAutheliaStorageUserWebAuthnDeleteLong,
Example: cmdAutheliaStorageUserWebAuthnDeleteExample,
RunE: storageWebAuthnDeleteRunE,
Args: cobra.MaximumNArgs(1),
DisableAutoGenTag: true,
}
cmd.Flags().Bool("all", false, "delete all of the users webauthn devices")
cmd.Flags().String("description", "", "delete a users webauthn device by description")
cmd.Flags().String("kid", "", "delete a users webauthn device by key id")
return cmd
}
func newStorageUserTOTPCmd() (cmd *cobra.Command) { func newStorageUserTOTPCmd() (cmd *cobra.Command) {
cmd = &cobra.Command{ cmd = &cobra.Command{
Use: "totp", Use: "totp",

View File

@ -205,6 +205,187 @@ func storageSchemaEncryptionChangeKeyRunE(cmd *cobra.Command, args []string) (er
return nil return nil
} }
func storageWebAuthnListRunE(cmd *cobra.Command, args []string) (err error) {
if len(args) == 0 || args[0] == "" {
return storageWebAuthnListAllRunE(cmd, args)
}
var (
provider storage.Provider
ctx = context.Background()
)
provider = getStorageProvider()
defer func() {
_ = provider.Close()
}()
var devices []model.WebauthnDevice
user := args[0]
devices, err = provider.LoadWebauthnDevicesByUsername(ctx, user)
switch {
case len(devices) == 0 || (err != nil && errors.Is(err, storage.ErrNoWebauthnDevice)):
return fmt.Errorf("user '%s' has no webauthn devices", user)
case err != nil:
return fmt.Errorf("can't list devices for user '%s': %w", user, err)
default:
fmt.Printf("Webauthn Devices for user '%s':\n\n", user)
fmt.Printf("ID\tKID\tDescription\n")
for _, device := range devices {
fmt.Printf("%d\t%s\t%s", device.ID, device.KID, device.Description)
}
}
return nil
}
func storageWebAuthnListAllRunE(_ *cobra.Command, _ []string) (err error) {
var (
provider storage.Provider
ctx = context.Background()
)
provider = getStorageProvider()
defer func() {
_ = provider.Close()
}()
var devices []model.WebauthnDevice
limit := 10
output := strings.Builder{}
for page := 0; true; page++ {
if devices, err = provider.LoadWebauthnDevices(ctx, limit, page); err != nil {
return fmt.Errorf("failed to list devices: %w", err)
}
if page == 0 && len(devices) == 0 {
return errors.New("no webauthn devices in database")
}
for _, device := range devices {
output.WriteString(fmt.Sprintf("%d\t%s\t%s\t%s\n", device.ID, device.KID, device.Description, device.Username))
}
if len(devices) < limit {
break
}
}
fmt.Printf("Webauthn Devices:\n\nID\tKID\tDescription\tUsername\n")
fmt.Println(output.String())
return nil
}
func storageWebAuthnDeleteRunE(cmd *cobra.Command, args []string) (err error) {
var (
provider storage.Provider
ctx = context.Background()
)
provider = getStorageProvider()
defer func() {
_ = provider.Close()
}()
var (
all, byKID bool
description, kid, user string
)
if all, byKID, description, kid, user, err = storageWebAuthnDeleteGetAndValidateConfig(cmd, args); err != nil {
return err
}
if byKID {
if err = provider.DeleteWebauthnDevice(ctx, kid); err != nil {
return fmt.Errorf("failed to delete WebAuthn device with kid '%s': %w", kid, err)
}
fmt.Printf("Deleted WebAuthn device with kid '%s'", kid)
} else {
err = provider.DeleteWebauthnDeviceByUsername(ctx, user, description)
if all {
if err != nil {
return fmt.Errorf("failed to delete all WebAuthn devices with username '%s': %w", user, err)
}
fmt.Printf("Deleted all WebAuthn devices for user '%s'", user)
} else {
if err != nil {
return fmt.Errorf("failed to delete WebAuthn device with username '%s' and description '%s': %w", user, description, err)
}
fmt.Printf("Deleted WebAuthn device with username '%s' and description '%s'", user, description)
}
}
return nil
}
func storageWebAuthnDeleteGetAndValidateConfig(cmd *cobra.Command, args []string) (all, byKID bool, description, kid, user string, err error) {
if len(args) != 0 {
user = args[0]
}
flags := 0
if cmd.Flags().Changed("all") {
if all, err = cmd.Flags().GetBool("all"); err != nil {
return
}
flags++
}
if cmd.Flags().Changed("description") {
if description, err = cmd.Flags().GetString("description"); err != nil {
return
}
flags++
}
if byKID = cmd.Flags().Changed("kid"); byKID {
if kid, err = cmd.Flags().GetString("kid"); err != nil {
return
}
flags++
}
if flags > 1 {
err = fmt.Errorf("must only supply one of the flags --all, --description, and --kid but %d were specified", flags)
return
}
if flags == 0 {
err = fmt.Errorf("must supply one of the flags --all, --description, or --kid")
return
}
if !byKID && len(user) == 0 {
err = fmt.Errorf("must supply the username or the --kid flag")
return
}
return
}
func storageTOTPGenerateRunE(cmd *cobra.Command, args []string) (err error) { func storageTOTPGenerateRunE(cmd *cobra.Command, args []string) (err error) {
var ( var (
provider storage.Provider provider storage.Provider

View File

@ -166,6 +166,34 @@ func (mr *MockStorageMockRecorder) DeleteTOTPConfiguration(arg0, arg1 interface{
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteTOTPConfiguration", reflect.TypeOf((*MockStorage)(nil).DeleteTOTPConfiguration), arg0, arg1) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteTOTPConfiguration", reflect.TypeOf((*MockStorage)(nil).DeleteTOTPConfiguration), arg0, arg1)
} }
// DeleteWebauthnDevice mocks base method.
func (m *MockStorage) DeleteWebauthnDevice(arg0 context.Context, arg1 string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DeleteWebauthnDevice", arg0, arg1)
ret0, _ := ret[0].(error)
return ret0
}
// DeleteWebauthnDevice indicates an expected call of DeleteWebauthnDevice.
func (mr *MockStorageMockRecorder) DeleteWebauthnDevice(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteWebauthnDevice", reflect.TypeOf((*MockStorage)(nil).DeleteWebauthnDevice), arg0, arg1)
}
// DeleteWebauthnDeviceByUsername mocks base method.
func (m *MockStorage) DeleteWebauthnDeviceByUsername(arg0 context.Context, arg1, arg2 string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DeleteWebauthnDeviceByUsername", arg0, arg1, arg2)
ret0, _ := ret[0].(error)
return ret0
}
// DeleteWebauthnDeviceByUsername indicates an expected call of DeleteWebauthnDeviceByUsername.
func (mr *MockStorageMockRecorder) DeleteWebauthnDeviceByUsername(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteWebauthnDeviceByUsername", reflect.TypeOf((*MockStorage)(nil).DeleteWebauthnDeviceByUsername), arg0, arg1, arg2)
}
// FindIdentityVerification mocks base method. // FindIdentityVerification mocks base method.
func (m *MockStorage) FindIdentityVerification(arg0 context.Context, arg1 string) (bool, error) { func (m *MockStorage) FindIdentityVerification(arg0 context.Context, arg1 string) (bool, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()

View File

@ -39,6 +39,8 @@ type Provider interface {
SaveWebauthnDevice(ctx context.Context, device model.WebauthnDevice) (err error) SaveWebauthnDevice(ctx context.Context, device model.WebauthnDevice) (err error)
UpdateWebauthnDeviceSignIn(ctx context.Context, id int, rpid string, lastUsedAt *time.Time, signCount uint32, cloneWarning bool) (err error) UpdateWebauthnDeviceSignIn(ctx context.Context, id int, rpid string, lastUsedAt *time.Time, signCount uint32, cloneWarning bool) (err error)
DeleteWebauthnDevice(ctx context.Context, kid string) (err error)
DeleteWebauthnDeviceByUsername(ctx context.Context, username, description string) (err error)
LoadWebauthnDevices(ctx context.Context, limit, page int) (devices []model.WebauthnDevice, err error) LoadWebauthnDevices(ctx context.Context, limit, page int) (devices []model.WebauthnDevice, err error)
LoadWebauthnDevicesByUsername(ctx context.Context, username string) (devices []model.WebauthnDevice, err error) LoadWebauthnDevicesByUsername(ctx context.Context, username string) (devices []model.WebauthnDevice, err error)

View File

@ -56,6 +56,10 @@ func NewSQLProvider(config *schema.Configuration, name, driverName, dataSourceNa
sqlUpdateWebauthnDeviceRecordSignIn: fmt.Sprintf(queryFmtUpdateWebauthnDeviceRecordSignIn, tableWebauthnDevices), sqlUpdateWebauthnDeviceRecordSignIn: fmt.Sprintf(queryFmtUpdateWebauthnDeviceRecordSignIn, tableWebauthnDevices),
sqlUpdateWebauthnDeviceRecordSignInByUsername: fmt.Sprintf(queryFmtUpdateWebauthnDeviceRecordSignInByUsername, tableWebauthnDevices), sqlUpdateWebauthnDeviceRecordSignInByUsername: fmt.Sprintf(queryFmtUpdateWebauthnDeviceRecordSignInByUsername, tableWebauthnDevices),
sqlDeleteWebauthnDevice: fmt.Sprintf(queryFmtDeleteWebauthnDevice, tableWebauthnDevices),
sqlDeleteWebauthnDeviceByUsername: fmt.Sprintf(queryFmtDeleteWebauthnDeviceByUsername, tableWebauthnDevices),
sqlDeleteWebauthnDeviceByUsernameAndDescription: fmt.Sprintf(queryFmtDeleteWebauthnDeviceByUsernameAndDescription, tableWebauthnDevices),
sqlUpsertDuoDevice: fmt.Sprintf(queryFmtUpsertDuoDevice, tableDuoDevices), sqlUpsertDuoDevice: fmt.Sprintf(queryFmtUpsertDuoDevice, tableDuoDevices),
sqlDeleteDuoDevice: fmt.Sprintf(queryFmtDeleteDuoDevice, tableDuoDevices), sqlDeleteDuoDevice: fmt.Sprintf(queryFmtDeleteDuoDevice, tableDuoDevices),
sqlSelectDuoDevice: fmt.Sprintf(queryFmtSelectDuoDevice, tableDuoDevices), sqlSelectDuoDevice: fmt.Sprintf(queryFmtSelectDuoDevice, tableDuoDevices),
@ -169,6 +173,10 @@ type SQLProvider struct {
sqlUpdateWebauthnDeviceRecordSignIn string sqlUpdateWebauthnDeviceRecordSignIn string
sqlUpdateWebauthnDeviceRecordSignInByUsername string sqlUpdateWebauthnDeviceRecordSignInByUsername string
sqlDeleteWebauthnDevice string
sqlDeleteWebauthnDeviceByUsername string
sqlDeleteWebauthnDeviceByUsernameAndDescription string
// Table: duo_devices. // Table: duo_devices.
sqlUpsertDuoDevice string sqlUpsertDuoDevice string
sqlDeleteDuoDevice string sqlDeleteDuoDevice string
@ -841,6 +849,34 @@ func (p *SQLProvider) UpdateWebauthnDeviceSignIn(ctx context.Context, id int, rp
return nil return nil
} }
// DeleteWebauthnDevice deletes a registered Webauthn device.
func (p *SQLProvider) DeleteWebauthnDevice(ctx context.Context, kid string) (err error) {
if _, err = p.db.ExecContext(ctx, p.sqlDeleteWebauthnDevice, kid); err != nil {
return fmt.Errorf("error deleting webauthn device with kid '%s': %w", kid, err)
}
return nil
}
// DeleteWebauthnDeviceByUsername deletes registered Webauthn devices by username or username and description.
func (p *SQLProvider) DeleteWebauthnDeviceByUsername(ctx context.Context, username, description string) (err error) {
if len(username) == 0 {
return fmt.Errorf("error deleting webauthn device with username '%s' and description '%s': username must not be empty", username, description)
}
if len(description) == 0 {
if _, err = p.db.ExecContext(ctx, p.sqlDeleteWebauthnDeviceByUsername, username); err != nil {
return fmt.Errorf("error deleting webauthn devices for username '%s': %w", username, err)
}
} else {
if _, err = p.db.ExecContext(ctx, p.sqlDeleteWebauthnDeviceByUsernameAndDescription, username, description); err != nil {
return fmt.Errorf("error deleting webauthn device with username '%s' and description '%s': %w", username, description, err)
}
}
return nil
}
// LoadWebauthnDevices loads Webauthn device registrations. // LoadWebauthnDevices loads Webauthn device registrations.
func (p *SQLProvider) LoadWebauthnDevices(ctx context.Context, limit, page int) (devices []model.WebauthnDevice, err error) { func (p *SQLProvider) LoadWebauthnDevices(ctx context.Context, limit, page int) (devices []model.WebauthnDevice, err error) {
devices = make([]model.WebauthnDevice, 0, limit) devices = make([]model.WebauthnDevice, 0, limit)

View File

@ -61,6 +61,9 @@ func NewPostgreSQLProvider(config *schema.Configuration) (provider *PostgreSQLPr
provider.sqlUpdateWebauthnDevicePublicKeyByUsername = provider.db.Rebind(provider.sqlUpdateWebauthnDevicePublicKeyByUsername) provider.sqlUpdateWebauthnDevicePublicKeyByUsername = provider.db.Rebind(provider.sqlUpdateWebauthnDevicePublicKeyByUsername)
provider.sqlUpdateWebauthnDeviceRecordSignIn = provider.db.Rebind(provider.sqlUpdateWebauthnDeviceRecordSignIn) provider.sqlUpdateWebauthnDeviceRecordSignIn = provider.db.Rebind(provider.sqlUpdateWebauthnDeviceRecordSignIn)
provider.sqlUpdateWebauthnDeviceRecordSignInByUsername = provider.db.Rebind(provider.sqlUpdateWebauthnDeviceRecordSignInByUsername) provider.sqlUpdateWebauthnDeviceRecordSignInByUsername = provider.db.Rebind(provider.sqlUpdateWebauthnDeviceRecordSignInByUsername)
provider.sqlDeleteWebauthnDevice = provider.db.Rebind(provider.sqlDeleteWebauthnDevice)
provider.sqlDeleteWebauthnDeviceByUsername = provider.db.Rebind(provider.sqlDeleteWebauthnDeviceByUsername)
provider.sqlDeleteWebauthnDeviceByUsernameAndDescription = provider.db.Rebind(provider.sqlDeleteWebauthnDeviceByUsernameAndDescription)
provider.sqlSelectDuoDevice = provider.db.Rebind(provider.sqlSelectDuoDevice) provider.sqlSelectDuoDevice = provider.db.Rebind(provider.sqlSelectDuoDevice)
provider.sqlDeleteDuoDevice = provider.db.Rebind(provider.sqlDeleteDuoDevice) provider.sqlDeleteDuoDevice = provider.db.Rebind(provider.sqlDeleteDuoDevice)

View File

@ -165,6 +165,18 @@ const (
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
ON CONFLICT (username, description) ON CONFLICT (username, description)
DO UPDATE SET created_at = $1, last_used_at = $2, rpid = $3, kid = $6, public_key = $7, attestation_type = $8, transport = $9, aaguid = $10, sign_count = $11, clone_warning = $12;` DO UPDATE SET created_at = $1, last_used_at = $2, rpid = $3, kid = $6, public_key = $7, attestation_type = $8, transport = $9, aaguid = $10, sign_count = $11, clone_warning = $12;`
queryFmtDeleteWebauthnDevice = `
DELETE FROM %s
WHERE kid = ?;`
queryFmtDeleteWebauthnDeviceByUsername = `
DELETE FROM %s
WHERE username = ?;`
queryFmtDeleteWebauthnDeviceByUsernameAndDescription = `
DELETE FROM %s
WHERE username = ? AND description = ?;`
) )
const ( const (