refactor(commands): command context (#4539)
This moves a lot of machinery for commands into a context.Context with other struct values. This allows for PreRunE's to reliably load the configuration and avoids use of global vars.pull/4614/head^2
parent
0732e60e16
commit
e3e31e3cbc
|
@ -26,6 +26,7 @@ body:
|
||||||
description: What version(s) of Authelia can you reproduce this bug on?
|
description: What version(s) of Authelia can you reproduce this bug on?
|
||||||
multiple: true
|
multiple: true
|
||||||
options:
|
options:
|
||||||
|
- v4.37.5
|
||||||
- v4.37.4
|
- v4.37.4
|
||||||
- v4.37.3
|
- v4.37.3
|
||||||
- v4.37.2
|
- v4.37.2
|
||||||
|
|
|
@ -232,9 +232,9 @@ Example:
|
||||||
```yaml
|
```yaml
|
||||||
{{ if contains (env "DOMAIN") "https://" }}
|
{{ if contains (env "DOMAIN") "https://" }}
|
||||||
default_redirection_url: '{{ env "DOMAIN" }}'
|
default_redirection_url: '{{ env "DOMAIN" }}'
|
||||||
{{ else}}
|
{{ else }}
|
||||||
default_redirection_url: 'https://{{ env "DOMAIN" }}'
|
default_redirection_url: 'https://{{ env "DOMAIN" }}'
|
||||||
{{ end }}
|
{{ end }}
|
||||||
```
|
```
|
||||||
|
|
||||||
##### hasPrefix
|
##### hasPrefix
|
||||||
|
@ -246,7 +246,7 @@ Example:
|
||||||
```yaml
|
```yaml
|
||||||
{{ if hasPrefix (env "DOMAIN") "https://" }}
|
{{ if hasPrefix (env "DOMAIN") "https://" }}
|
||||||
default_redirection_url: '{{ env "DOMAIN" }}'
|
default_redirection_url: '{{ env "DOMAIN" }}'
|
||||||
{{ else}}
|
{{ else }}
|
||||||
default_redirection_url: 'https://{{ env "DOMAIN" }}'
|
default_redirection_url: 'https://{{ env "DOMAIN" }}'
|
||||||
{{ end }}
|
{{ end }}
|
||||||
```
|
```
|
||||||
|
@ -260,7 +260,7 @@ Example:
|
||||||
```yaml
|
```yaml
|
||||||
{{ if hasSuffix (env "DOMAIN") "/" }}
|
{{ if hasSuffix (env "DOMAIN") "/" }}
|
||||||
default_redirection_url: 'https://{{ env "DOMAIN" }}'
|
default_redirection_url: 'https://{{ env "DOMAIN" }}'
|
||||||
{{ else}}
|
{{ else }}
|
||||||
default_redirection_url: 'https://{{ env "DOMAIN" }}/'
|
default_redirection_url: 'https://{{ env "DOMAIN" }}/'
|
||||||
{{ end }}
|
{{ end }}
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
title: "Versioning Policy"
|
title: "Versioning Policy"
|
||||||
description: "The Authelia Versioning Policy which is important reading for administrators"
|
description: "The Authelia Versioning Policy which is important reading for administrators"
|
||||||
date: 2022-12-21T16:46:42+11:00
|
date: 2022-12-21T20:48:14+11:00
|
||||||
draft: false
|
draft: false
|
||||||
images: []
|
images: []
|
||||||
aliases:
|
aliases:
|
||||||
|
|
|
@ -41,8 +41,8 @@ authelia --config /etc/authelia/config/
|
||||||
### Options
|
### Options
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
--config.experimental.filters strings Applies filters in order to the configuration file before the YAML parser. Options are 'template', 'expand-env'
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
-h, --help help for authelia
|
-h, --help help for authelia
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -51,7 +51,6 @@ authelia --config /etc/authelia/config/
|
||||||
* [authelia access-control](authelia_access-control.md) - Helpers for the access control system
|
* [authelia access-control](authelia_access-control.md) - Helpers for the access control system
|
||||||
* [authelia build-info](authelia_build-info.md) - Show the build information of Authelia
|
* [authelia build-info](authelia_build-info.md) - Show the build information of Authelia
|
||||||
* [authelia crypto](authelia_crypto.md) - Perform cryptographic operations
|
* [authelia crypto](authelia_crypto.md) - Perform cryptographic operations
|
||||||
* [authelia hash-password](authelia_hash-password.md) - Hash a password to be used in file-based users database
|
|
||||||
* [authelia storage](authelia_storage.md) - Manage the Authelia storage
|
* [authelia storage](authelia_storage.md) - Manage the Authelia storage
|
||||||
* [authelia validate-config](authelia_validate-config.md) - Check a configuration against the internal configuration validation mechanisms
|
* [authelia validate-config](authelia_validate-config.md) - Check a configuration against the internal configuration validation mechanisms
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,13 @@ authelia access-control --help
|
||||||
-h, --help help for access-control
|
-h, --help help for access-control
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia](authelia.md) - authelia untagged-unknown-dirty (master, unknown)
|
* [authelia](authelia.md) - authelia untagged-unknown-dirty (master, unknown)
|
||||||
|
|
|
@ -53,7 +53,6 @@ authelia access-control check-policy --config config.yml --url https://example.c
|
||||||
### Options
|
### Options
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
|
||||||
--groups strings the groups of the subject
|
--groups strings the groups of the subject
|
||||||
-h, --help help for check-policy
|
-h, --help help for check-policy
|
||||||
--ip string the ip of the subject
|
--ip string the ip of the subject
|
||||||
|
@ -63,6 +62,13 @@ authelia access-control check-policy --config config.yml --url https://example.c
|
||||||
--verbose enables verbose output
|
--verbose enables verbose output
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia access-control](authelia_access-control.md) - Helpers for the access control system
|
* [authelia access-control](authelia_access-control.md) - Helpers for the access control system
|
||||||
|
|
|
@ -45,6 +45,13 @@ authelia build-info
|
||||||
-h, --help help for build-info
|
-h, --help help for build-info
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia](authelia.md) - authelia untagged-unknown-dirty (master, unknown)
|
* [authelia](authelia.md) - authelia untagged-unknown-dirty (master, unknown)
|
||||||
|
|
|
@ -34,6 +34,13 @@ authelia crypto --help
|
||||||
-h, --help help for crypto
|
-h, --help help for crypto
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia](authelia.md) - authelia untagged-unknown-dirty (master, unknown)
|
* [authelia](authelia.md) - authelia untagged-unknown-dirty (master, unknown)
|
||||||
|
|
|
@ -34,6 +34,13 @@ authelia crypto certificate --help
|
||||||
-h, --help help for certificate
|
-h, --help help for certificate
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia crypto](authelia_crypto.md) - Perform cryptographic operations
|
* [authelia crypto](authelia_crypto.md) - Perform cryptographic operations
|
||||||
|
|
|
@ -34,6 +34,13 @@ authelia crypto certificate ecdsa --help
|
||||||
-h, --help help for ecdsa
|
-h, --help help for ecdsa
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia crypto certificate](authelia_crypto_certificate.md) - Perform certificate cryptographic operations
|
* [authelia crypto certificate](authelia_crypto_certificate.md) - Perform certificate cryptographic operations
|
||||||
|
|
|
@ -36,7 +36,7 @@ authelia crypto certificate ecdsa generate --help
|
||||||
|
|
||||||
```
|
```
|
||||||
--ca create the certificate as a certificate authority certificate
|
--ca create the certificate as a certificate authority certificate
|
||||||
-c, --common-name string certificate common name
|
-n, --common-name string certificate common name
|
||||||
--country strings certificate country
|
--country strings certificate country
|
||||||
-b, --curve string Sets the elliptic curve which can be P224, P256, P384, or P521 (default "P256")
|
-b, --curve string Sets the elliptic curve which can be P224, P256, P384, or P521 (default "P256")
|
||||||
-d, --directory string directory where the generated keys, certificates, etc will be stored
|
-d, --directory string directory where the generated keys, certificates, etc will be stored
|
||||||
|
@ -59,6 +59,13 @@ authelia crypto certificate ecdsa generate --help
|
||||||
-s, --street-address strings certificate street address
|
-s, --street-address strings certificate street address
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia crypto certificate ecdsa](authelia_crypto_certificate_ecdsa.md) - Perform ECDSA certificate cryptographic operations
|
* [authelia crypto certificate ecdsa](authelia_crypto_certificate_ecdsa.md) - Perform ECDSA certificate cryptographic operations
|
||||||
|
|
|
@ -35,7 +35,7 @@ authelia crypto certificate ecdsa request --help
|
||||||
### Options
|
### Options
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --common-name string certificate common name
|
-n, --common-name string certificate common name
|
||||||
--country strings certificate country
|
--country strings certificate country
|
||||||
-b, --curve string Sets the elliptic curve which can be P224, P256, P384, or P521 (default "P256")
|
-b, --curve string Sets the elliptic curve which can be P224, P256, P384, or P521 (default "P256")
|
||||||
-d, --directory string directory where the generated keys, certificates, etc will be stored
|
-d, --directory string directory where the generated keys, certificates, etc will be stored
|
||||||
|
@ -54,6 +54,13 @@ authelia crypto certificate ecdsa request --help
|
||||||
-s, --street-address strings certificate street address
|
-s, --street-address strings certificate street address
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia crypto certificate ecdsa](authelia_crypto_certificate_ecdsa.md) - Perform ECDSA certificate cryptographic operations
|
* [authelia crypto certificate ecdsa](authelia_crypto_certificate_ecdsa.md) - Perform ECDSA certificate cryptographic operations
|
||||||
|
|
|
@ -34,6 +34,13 @@ authelia crypto certificate ed25519 --help
|
||||||
-h, --help help for ed25519
|
-h, --help help for ed25519
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia crypto certificate](authelia_crypto_certificate.md) - Perform certificate cryptographic operations
|
* [authelia crypto certificate](authelia_crypto_certificate.md) - Perform certificate cryptographic operations
|
||||||
|
|
|
@ -36,7 +36,7 @@ authelia crypto certificate ed25519 request --help
|
||||||
|
|
||||||
```
|
```
|
||||||
--ca create the certificate as a certificate authority certificate
|
--ca create the certificate as a certificate authority certificate
|
||||||
-c, --common-name string certificate common name
|
-n, --common-name string certificate common name
|
||||||
--country strings certificate country
|
--country strings certificate country
|
||||||
-d, --directory string directory where the generated keys, certificates, etc will be stored
|
-d, --directory string directory where the generated keys, certificates, etc will be stored
|
||||||
--duration duration duration of time the certificate is valid for (default 8760h0m0s)
|
--duration duration duration of time the certificate is valid for (default 8760h0m0s)
|
||||||
|
@ -58,6 +58,13 @@ authelia crypto certificate ed25519 request --help
|
||||||
-s, --street-address strings certificate street address
|
-s, --street-address strings certificate street address
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia crypto certificate ed25519](authelia_crypto_certificate_ed25519.md) - Perform Ed25519 certificate cryptographic operations
|
* [authelia crypto certificate ed25519](authelia_crypto_certificate_ed25519.md) - Perform Ed25519 certificate cryptographic operations
|
||||||
|
|
|
@ -35,7 +35,7 @@ authelia crypto certificate ed25519 request --help
|
||||||
### Options
|
### Options
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --common-name string certificate common name
|
-n, --common-name string certificate common name
|
||||||
--country strings certificate country
|
--country strings certificate country
|
||||||
-d, --directory string directory where the generated keys, certificates, etc will be stored
|
-d, --directory string directory where the generated keys, certificates, etc will be stored
|
||||||
--duration duration duration of time the certificate is valid for (default 8760h0m0s)
|
--duration duration duration of time the certificate is valid for (default 8760h0m0s)
|
||||||
|
@ -53,6 +53,13 @@ authelia crypto certificate ed25519 request --help
|
||||||
-s, --street-address strings certificate street address
|
-s, --street-address strings certificate street address
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia crypto certificate ed25519](authelia_crypto_certificate_ed25519.md) - Perform Ed25519 certificate cryptographic operations
|
* [authelia crypto certificate ed25519](authelia_crypto_certificate_ed25519.md) - Perform Ed25519 certificate cryptographic operations
|
||||||
|
|
|
@ -34,6 +34,13 @@ authelia crypto certificate rsa --help
|
||||||
-h, --help help for rsa
|
-h, --help help for rsa
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia crypto certificate](authelia_crypto_certificate.md) - Perform certificate cryptographic operations
|
* [authelia crypto certificate](authelia_crypto_certificate.md) - Perform certificate cryptographic operations
|
||||||
|
|
|
@ -37,7 +37,7 @@ authelia crypto certificate rsa generate --help
|
||||||
```
|
```
|
||||||
-b, --bits int number of RSA bits for the certificate (default 2048)
|
-b, --bits int number of RSA bits for the certificate (default 2048)
|
||||||
--ca create the certificate as a certificate authority certificate
|
--ca create the certificate as a certificate authority certificate
|
||||||
-c, --common-name string certificate common name
|
-n, --common-name string certificate common name
|
||||||
--country strings certificate country
|
--country strings certificate country
|
||||||
-d, --directory string directory where the generated keys, certificates, etc will be stored
|
-d, --directory string directory where the generated keys, certificates, etc will be stored
|
||||||
--duration duration duration of time the certificate is valid for (default 8760h0m0s)
|
--duration duration duration of time the certificate is valid for (default 8760h0m0s)
|
||||||
|
@ -59,6 +59,13 @@ authelia crypto certificate rsa generate --help
|
||||||
-s, --street-address strings certificate street address
|
-s, --street-address strings certificate street address
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia crypto certificate rsa](authelia_crypto_certificate_rsa.md) - Perform RSA certificate cryptographic operations
|
* [authelia crypto certificate rsa](authelia_crypto_certificate_rsa.md) - Perform RSA certificate cryptographic operations
|
||||||
|
|
|
@ -36,7 +36,7 @@ authelia crypto certificate rsa request --help
|
||||||
|
|
||||||
```
|
```
|
||||||
-b, --bits int number of RSA bits for the certificate (default 2048)
|
-b, --bits int number of RSA bits for the certificate (default 2048)
|
||||||
-c, --common-name string certificate common name
|
-n, --common-name string certificate common name
|
||||||
--country strings certificate country
|
--country strings certificate country
|
||||||
-d, --directory string directory where the generated keys, certificates, etc will be stored
|
-d, --directory string directory where the generated keys, certificates, etc will be stored
|
||||||
--duration duration duration of time the certificate is valid for (default 8760h0m0s)
|
--duration duration duration of time the certificate is valid for (default 8760h0m0s)
|
||||||
|
@ -54,6 +54,13 @@ authelia crypto certificate rsa request --help
|
||||||
-s, --street-address strings certificate street address
|
-s, --street-address strings certificate street address
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia crypto certificate rsa](authelia_crypto_certificate_rsa.md) - Perform RSA certificate cryptographic operations
|
* [authelia crypto certificate rsa](authelia_crypto_certificate_rsa.md) - Perform RSA certificate cryptographic operations
|
||||||
|
|
|
@ -34,6 +34,13 @@ authelia crypto hash --help
|
||||||
-h, --help help for hash
|
-h, --help help for hash
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia crypto](authelia_crypto.md) - Perform cryptographic operations
|
* [authelia crypto](authelia_crypto.md) - Perform cryptographic operations
|
||||||
|
|
|
@ -37,7 +37,6 @@ authelia crypto hash generate --help
|
||||||
### Options
|
### Options
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
|
||||||
-h, --help help for generate
|
-h, --help help for generate
|
||||||
--no-confirm skip the password confirmation prompt
|
--no-confirm skip the password confirmation prompt
|
||||||
--password string manually supply the password rather than using the terminal prompt
|
--password string manually supply the password rather than using the terminal prompt
|
||||||
|
@ -47,6 +46,13 @@ authelia crypto hash generate --help
|
||||||
--random.length int sets the character length for the random string (default 72)
|
--random.length int sets the character length for the random string (default 72)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia crypto hash](authelia_crypto_hash.md) - Perform cryptographic hash operations
|
* [authelia crypto hash](authelia_crypto_hash.md) - Perform cryptographic hash operations
|
||||||
|
|
|
@ -48,13 +48,14 @@ authelia crypto hash generate argon2 --help
|
||||||
### Options inherited from parent commands
|
### Options inherited from parent commands
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
--no-confirm skip the password confirmation prompt
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--password string manually supply the password rather than using the terminal prompt
|
--no-confirm skip the password confirmation prompt
|
||||||
--random uses a randomly generated password
|
--password string manually supply the password rather than using the terminal prompt
|
||||||
--random.characters string sets the explicit characters for the random string
|
--random uses a randomly generated password
|
||||||
--random.charset string sets the charset for the random password, options are 'ascii', 'alphanumeric', 'alphabetic', 'numeric', 'numeric-hex', and 'rfc3986' (default "alphanumeric")
|
--random.characters string sets the explicit characters for the random string
|
||||||
--random.length int sets the character length for the random string (default 72)
|
--random.charset string sets the charset for the random password, options are 'ascii', 'alphanumeric', 'alphabetic', 'numeric', 'numeric-hex', and 'rfc3986' (default "alphanumeric")
|
||||||
|
--random.length int sets the character length for the random string (default 72)
|
||||||
```
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
|
@ -43,13 +43,14 @@ authelia crypto hash generate bcrypt --help
|
||||||
### Options inherited from parent commands
|
### Options inherited from parent commands
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
--no-confirm skip the password confirmation prompt
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--password string manually supply the password rather than using the terminal prompt
|
--no-confirm skip the password confirmation prompt
|
||||||
--random uses a randomly generated password
|
--password string manually supply the password rather than using the terminal prompt
|
||||||
--random.characters string sets the explicit characters for the random string
|
--random uses a randomly generated password
|
||||||
--random.charset string sets the charset for the random password, options are 'ascii', 'alphanumeric', 'alphabetic', 'numeric', 'numeric-hex', and 'rfc3986' (default "alphanumeric")
|
--random.characters string sets the explicit characters for the random string
|
||||||
--random.length int sets the character length for the random string (default 72)
|
--random.charset string sets the charset for the random password, options are 'ascii', 'alphanumeric', 'alphabetic', 'numeric', 'numeric-hex', and 'rfc3986' (default "alphanumeric")
|
||||||
|
--random.length int sets the character length for the random string (default 72)
|
||||||
```
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
|
@ -44,13 +44,14 @@ authelia crypto hash generate pbkdf2 --help
|
||||||
### Options inherited from parent commands
|
### Options inherited from parent commands
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
--no-confirm skip the password confirmation prompt
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--password string manually supply the password rather than using the terminal prompt
|
--no-confirm skip the password confirmation prompt
|
||||||
--random uses a randomly generated password
|
--password string manually supply the password rather than using the terminal prompt
|
||||||
--random.characters string sets the explicit characters for the random string
|
--random uses a randomly generated password
|
||||||
--random.charset string sets the charset for the random password, options are 'ascii', 'alphanumeric', 'alphabetic', 'numeric', 'numeric-hex', and 'rfc3986' (default "alphanumeric")
|
--random.characters string sets the explicit characters for the random string
|
||||||
--random.length int sets the character length for the random string (default 72)
|
--random.charset string sets the charset for the random password, options are 'ascii', 'alphanumeric', 'alphabetic', 'numeric', 'numeric-hex', and 'rfc3986' (default "alphanumeric")
|
||||||
|
--random.length int sets the character length for the random string (default 72)
|
||||||
```
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
|
@ -46,13 +46,14 @@ authelia crypto hash generate scrypt --help
|
||||||
### Options inherited from parent commands
|
### Options inherited from parent commands
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
--no-confirm skip the password confirmation prompt
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--password string manually supply the password rather than using the terminal prompt
|
--no-confirm skip the password confirmation prompt
|
||||||
--random uses a randomly generated password
|
--password string manually supply the password rather than using the terminal prompt
|
||||||
--random.characters string sets the explicit characters for the random string
|
--random uses a randomly generated password
|
||||||
--random.charset string sets the charset for the random password, options are 'ascii', 'alphanumeric', 'alphabetic', 'numeric', 'numeric-hex', and 'rfc3986' (default "alphanumeric")
|
--random.characters string sets the explicit characters for the random string
|
||||||
--random.length int sets the character length for the random string (default 72)
|
--random.charset string sets the charset for the random password, options are 'ascii', 'alphanumeric', 'alphabetic', 'numeric', 'numeric-hex', and 'rfc3986' (default "alphanumeric")
|
||||||
|
--random.length int sets the character length for the random string (default 72)
|
||||||
```
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
|
@ -44,13 +44,14 @@ authelia crypto hash generate sha2crypt --help
|
||||||
### Options inherited from parent commands
|
### Options inherited from parent commands
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
--no-confirm skip the password confirmation prompt
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--password string manually supply the password rather than using the terminal prompt
|
--no-confirm skip the password confirmation prompt
|
||||||
--random uses a randomly generated password
|
--password string manually supply the password rather than using the terminal prompt
|
||||||
--random.characters string sets the explicit characters for the random string
|
--random uses a randomly generated password
|
||||||
--random.charset string sets the charset for the random password, options are 'ascii', 'alphanumeric', 'alphabetic', 'numeric', 'numeric-hex', and 'rfc3986' (default "alphanumeric")
|
--random.characters string sets the explicit characters for the random string
|
||||||
--random.length int sets the character length for the random string (default 72)
|
--random.charset string sets the charset for the random password, options are 'ascii', 'alphanumeric', 'alphabetic', 'numeric', 'numeric-hex', and 'rfc3986' (default "alphanumeric")
|
||||||
|
--random.length int sets the character length for the random string (default 72)
|
||||||
```
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
|
@ -40,6 +40,13 @@ authelia crypto hash validate '$5$rounds=500000$WFjMpdCQxIkbNl0k$M0qZaZoK8Gwdh8C
|
||||||
--password string manually supply the password rather than using the terminal prompt
|
--password string manually supply the password rather than using the terminal prompt
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia crypto hash](authelia_crypto_hash.md) - Perform cryptographic hash operations
|
* [authelia crypto hash](authelia_crypto_hash.md) - Perform cryptographic hash operations
|
||||||
|
|
|
@ -34,6 +34,13 @@ authelia crypto pair --help
|
||||||
-h, --help help for pair
|
-h, --help help for pair
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia crypto](authelia_crypto.md) - Perform cryptographic operations
|
* [authelia crypto](authelia_crypto.md) - Perform cryptographic operations
|
||||||
|
|
|
@ -38,6 +38,13 @@ authelia crypto pair ecdsa --help
|
||||||
-h, --help help for ecdsa
|
-h, --help help for ecdsa
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia crypto pair](authelia_crypto_pair.md) - Perform key pair cryptographic operations
|
* [authelia crypto pair](authelia_crypto_pair.md) - Perform key pair cryptographic operations
|
||||||
|
|
|
@ -43,6 +43,13 @@ authelia crypto pair ecdsa generate --help
|
||||||
--pkcs8 force PKCS #8 ASN.1 format
|
--pkcs8 force PKCS #8 ASN.1 format
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia crypto pair ecdsa](authelia_crypto_pair_ecdsa.md) - Perform ECDSA key pair cryptographic operations
|
* [authelia crypto pair ecdsa](authelia_crypto_pair_ecdsa.md) - Perform ECDSA key pair cryptographic operations
|
||||||
|
|
|
@ -38,6 +38,13 @@ authelia crypto pair ed25519 --help
|
||||||
-h, --help help for ed25519
|
-h, --help help for ed25519
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia crypto pair](authelia_crypto_pair.md) - Perform key pair cryptographic operations
|
* [authelia crypto pair](authelia_crypto_pair.md) - Perform key pair cryptographic operations
|
||||||
|
|
|
@ -42,6 +42,13 @@ authelia crypto pair ed25519 generate --help
|
||||||
--pkcs8 force PKCS #8 ASN.1 format
|
--pkcs8 force PKCS #8 ASN.1 format
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia crypto pair ed25519](authelia_crypto_pair_ed25519.md) - Perform Ed25519 key pair cryptographic operations
|
* [authelia crypto pair ed25519](authelia_crypto_pair_ed25519.md) - Perform Ed25519 key pair cryptographic operations
|
||||||
|
|
|
@ -38,6 +38,13 @@ authelia crypto pair rsa --help
|
||||||
-h, --help help for rsa
|
-h, --help help for rsa
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia crypto pair](authelia_crypto_pair.md) - Perform key pair cryptographic operations
|
* [authelia crypto pair](authelia_crypto_pair.md) - Perform key pair cryptographic operations
|
||||||
|
|
|
@ -43,6 +43,13 @@ authelia crypto pair rsa generate --help
|
||||||
--pkcs8 force PKCS #8 ASN.1 format
|
--pkcs8 force PKCS #8 ASN.1 format
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia crypto pair rsa](authelia_crypto_pair_rsa.md) - Perform RSA key pair cryptographic operations
|
* [authelia crypto pair rsa](authelia_crypto_pair_rsa.md) - Perform RSA key pair cryptographic operations
|
||||||
|
|
|
@ -44,11 +44,18 @@ authelia crypto rand --characters 0123456789ABCDEF
|
||||||
|
|
||||||
```
|
```
|
||||||
--characters string sets the explicit characters for the random string
|
--characters string sets the explicit characters for the random string
|
||||||
-c, --charset string sets the charset for the random password, options are 'ascii', 'alphanumeric', 'alphabetic', 'numeric', 'numeric-hex', and 'rfc3986' (default "alphanumeric")
|
-x, --charset string sets the charset for the random password, options are 'ascii', 'alphanumeric', 'alphabetic', 'numeric', 'numeric-hex', and 'rfc3986' (default "alphanumeric")
|
||||||
-h, --help help for rand
|
-h, --help help for rand
|
||||||
-n, --length int sets the character length for the random string (default 72)
|
-n, --length int sets the character length for the random string (default 72)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia crypto](authelia_crypto.md) - Perform cryptographic operations
|
* [authelia crypto](authelia_crypto.md) - Perform cryptographic operations
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
---
|
|
||||||
title: "authelia hash-password"
|
|
||||||
description: "Reference for the authelia hash-password command."
|
|
||||||
lead: ""
|
|
||||||
date: 2022-06-15T17:51:47+10:00
|
|
||||||
draft: false
|
|
||||||
images: []
|
|
||||||
menu:
|
|
||||||
reference:
|
|
||||||
parent: "cli-authelia"
|
|
||||||
weight: 905
|
|
||||||
toc: true
|
|
||||||
---
|
|
||||||
|
|
||||||
## authelia hash-password
|
|
||||||
|
|
||||||
Hash a password to be used in file-based users database
|
|
||||||
|
|
||||||
### Synopsis
|
|
||||||
|
|
||||||
Hash a password to be used in file-based users database.
|
|
||||||
|
|
||||||
```
|
|
||||||
authelia hash-password [flags] -- [password]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Examples
|
|
||||||
|
|
||||||
```
|
|
||||||
authelia hash-password -- 'mypass'
|
|
||||||
authelia hash-password --sha512 -- 'mypass'
|
|
||||||
authelia hash-password --iterations=4 -- 'mypass'
|
|
||||||
authelia hash-password --memory=128 -- 'mypass'
|
|
||||||
authelia hash-password --parallelism=1 -- 'mypass'
|
|
||||||
authelia hash-password --key-length=64 -- 'mypass'
|
|
||||||
```
|
|
||||||
|
|
||||||
### Options
|
|
||||||
|
|
||||||
```
|
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
|
||||||
-h, --help help for hash-password
|
|
||||||
-i, --iterations int set the number of hashing iterations (default 3)
|
|
||||||
-k, --key-length int [argon2id] set the key length param (default 32)
|
|
||||||
-m, --memory int [argon2id] set the amount of memory param (in MB) (default 65536)
|
|
||||||
--no-confirm skip the password confirmation prompt
|
|
||||||
-p, --parallelism int [argon2id] set the parallelism param (default 4)
|
|
||||||
-l, --salt-length int set the auto-generated salt length (default 16)
|
|
||||||
-z, --sha512 use sha512 as the algorithm (changes iterations to 50000, change with -i)
|
|
||||||
```
|
|
||||||
|
|
||||||
### SEE ALSO
|
|
||||||
|
|
||||||
* [authelia](authelia.md) - authelia untagged-unknown-dirty (master, unknown)
|
|
||||||
|
|
|
@ -33,7 +33,6 @@ authelia storage --help
|
||||||
### Options
|
### Options
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
-h, --help help for storage
|
-h, --help help for storage
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
|
@ -54,6 +53,13 @@ authelia storage --help
|
||||||
--sqlite.path string the SQLite database path
|
--sqlite.path string the SQLite database path
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [authelia](authelia.md) - authelia untagged-unknown-dirty (master, unknown)
|
* [authelia](authelia.md) - authelia untagged-unknown-dirty (master, unknown)
|
||||||
|
|
|
@ -38,6 +38,7 @@ authelia storage encryption --help
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
--mysql.host string the MySQL hostname
|
--mysql.host string the MySQL hostname
|
||||||
|
|
|
@ -44,6 +44,7 @@ authelia storage encryption change-key --encryption-key b3453fde-ecc2-4a1f-9422-
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
--mysql.host string the MySQL hostname
|
--mysql.host string the MySQL hostname
|
||||||
|
|
|
@ -46,6 +46,7 @@ authelia storage encryption check --verbose --encryption-key b3453fde-ecc2-4a1f-
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
--mysql.host string the MySQL hostname
|
--mysql.host string the MySQL hostname
|
||||||
|
|
|
@ -38,6 +38,7 @@ authelia storage migrate --help
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
--mysql.host string the MySQL hostname
|
--mysql.host string the MySQL hostname
|
||||||
|
|
|
@ -47,6 +47,7 @@ authelia storage migrate down --target 20 --encryption-key b3453fde-ecc2-4a1f-94
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
--mysql.host string the MySQL hostname
|
--mysql.host string the MySQL hostname
|
||||||
|
|
|
@ -44,6 +44,7 @@ authelia storage migrate history --encryption-key b3453fde-ecc2-4a1f-9422-2707dd
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
--mysql.host string the MySQL hostname
|
--mysql.host string the MySQL hostname
|
||||||
|
|
|
@ -45,6 +45,7 @@ authelia storage migrate list-down --encryption-key b3453fde-ecc2-4a1f-9422-2707
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
--mysql.host string the MySQL hostname
|
--mysql.host string the MySQL hostname
|
||||||
|
|
|
@ -45,6 +45,7 @@ authelia storage migrate list-up --encryption-key b3453fde-ecc2-4a1f-9422-2707dd
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
--mysql.host string the MySQL hostname
|
--mysql.host string the MySQL hostname
|
||||||
|
|
|
@ -47,6 +47,7 @@ authelia storage migrate up --encryption-key b3453fde-ecc2-4a1f-9422-2707ddbed49
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
--mysql.host string the MySQL hostname
|
--mysql.host string the MySQL hostname
|
||||||
|
|
|
@ -44,6 +44,7 @@ authelia storage schema-info --encryption-key b3453fde-ecc2-4a1f-9422-2707ddbed4
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
--mysql.host string the MySQL hostname
|
--mysql.host string the MySQL hostname
|
||||||
|
|
|
@ -38,6 +38,7 @@ authelia storage user --help
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
--mysql.host string the MySQL hostname
|
--mysql.host string the MySQL hostname
|
||||||
|
|
|
@ -38,6 +38,7 @@ authelia storage user identifiers --help
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
--mysql.host string the MySQL hostname
|
--mysql.host string the MySQL hostname
|
||||||
|
|
|
@ -47,6 +47,7 @@ authelia storage user identifiers add john --identifier f0919359-9d15-4e15-bcba-
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
--mysql.host string the MySQL hostname
|
--mysql.host string the MySQL hostname
|
||||||
|
|
|
@ -46,6 +46,7 @@ authelia storage user identifiers export --file export.yaml --encryption-key b34
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
--mysql.host string the MySQL hostname
|
--mysql.host string the MySQL hostname
|
||||||
|
|
|
@ -49,6 +49,7 @@ authelia storage user identifiers generate --users john,mary --services openid -
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
--mysql.host string the MySQL hostname
|
--mysql.host string the MySQL hostname
|
||||||
|
|
|
@ -49,6 +49,7 @@ authelia storage user identifiers import --file export.yaml --encryption-key b34
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
--mysql.host string the MySQL hostname
|
--mysql.host string the MySQL hostname
|
||||||
|
|
|
@ -38,6 +38,7 @@ authelia storage user totp --help
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
--mysql.host string the MySQL hostname
|
--mysql.host string the MySQL hostname
|
||||||
|
|
|
@ -44,6 +44,7 @@ authelia storage user totp delete john --encryption-key b3453fde-ecc2-4a1f-9422-
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
--mysql.host string the MySQL hostname
|
--mysql.host string the MySQL hostname
|
||||||
|
|
|
@ -47,6 +47,7 @@ authelia storage user totp export --format png --dir ./totp-qr --encryption-key
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
--mysql.host string the MySQL hostname
|
--mysql.host string the MySQL hostname
|
||||||
|
|
|
@ -56,6 +56,7 @@ authelia storage user totp generate john --algorithm SHA512 --config config.yml
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
--mysql.host string the MySQL hostname
|
--mysql.host string the MySQL hostname
|
||||||
|
|
|
@ -38,6 +38,7 @@ authelia storage user webauthn --help
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
--mysql.host string the MySQL hostname
|
--mysql.host string the MySQL hostname
|
||||||
|
|
|
@ -53,6 +53,7 @@ authelia storage user webauthn delete --kid abc123 --encryption-key b3453fde-ecc
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
--mysql.host string the MySQL hostname
|
--mysql.host string the MySQL hostname
|
||||||
|
|
|
@ -47,6 +47,7 @@ authelia storage user webauthn list john --encryption-key b3453fde-ecc2-4a1f-942
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
--encryption-key string the storage encryption key to use
|
--encryption-key string the storage encryption key to use
|
||||||
--mysql.database string the MySQL database name (default "authelia")
|
--mysql.database string the MySQL database name (default "authelia")
|
||||||
--mysql.host string the MySQL hostname
|
--mysql.host string the MySQL hostname
|
||||||
|
|
|
@ -37,8 +37,14 @@ authelia validate-config --config config.yml
|
||||||
### Options
|
### Options
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --config strings configuration files to load (default [configuration.yml])
|
-h, --help help for validate-config
|
||||||
-h, --help help for validate-config
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
-c, --config strings configuration files to load (default [configuration.yml])
|
||||||
|
--config.experimental.filters strings applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'
|
||||||
```
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
|
@ -8,5 +8,5 @@
|
||||||
{{ else }}
|
{{ else }}
|
||||||
{{ errorf "No valid text variable or Inner content given"}}
|
{{ errorf "No valid text variable or Inner content given"}}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ end}}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -10,12 +10,10 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/authelia/authelia/v4/internal/authorization"
|
"github.com/authelia/authelia/v4/internal/authorization"
|
||||||
"github.com/authelia/authelia/v4/internal/configuration"
|
|
||||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
|
||||||
"github.com/authelia/authelia/v4/internal/configuration/validator"
|
"github.com/authelia/authelia/v4/internal/configuration/validator"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newAccessControlCommand() (cmd *cobra.Command) {
|
func newAccessControlCommand(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "access-control",
|
Use: "access-control",
|
||||||
Short: cmdAutheliaAccessControlShort,
|
Short: cmdAutheliaAccessControlShort,
|
||||||
|
@ -26,25 +24,26 @@ func newAccessControlCommand() (cmd *cobra.Command) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.AddCommand(
|
cmd.AddCommand(
|
||||||
newAccessControlCheckCommand(),
|
newAccessControlCheckCommand(ctx),
|
||||||
)
|
)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAccessControlCheckCommand() (cmd *cobra.Command) {
|
func newAccessControlCheckCommand(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "check-policy",
|
Use: "check-policy",
|
||||||
Short: cmdAutheliaAccessControlCheckPolicyShort,
|
Short: cmdAutheliaAccessControlCheckPolicyShort,
|
||||||
Long: cmdAutheliaAccessControlCheckPolicyLong,
|
Long: cmdAutheliaAccessControlCheckPolicyLong,
|
||||||
Example: cmdAutheliaAccessControlCheckPolicyExample,
|
Example: cmdAutheliaAccessControlCheckPolicyExample,
|
||||||
RunE: accessControlCheckRunE,
|
PreRunE: ctx.ChainRunE(
|
||||||
|
ctx.ConfigLoadRunE,
|
||||||
|
),
|
||||||
|
RunE: ctx.AccessControlCheckRunE,
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdWithConfigFlags(cmd, false, []string{"configuration.yml"})
|
|
||||||
|
|
||||||
cmd.Flags().String("url", "", "the url of the object")
|
cmd.Flags().String("url", "", "the url of the object")
|
||||||
cmd.Flags().String("method", "GET", "the HTTP method of the object")
|
cmd.Flags().String("method", "GET", "the HTTP method of the object")
|
||||||
cmd.Flags().String("username", "", "the username of the subject")
|
cmd.Flags().String("username", "", "the username of the subject")
|
||||||
|
@ -55,36 +54,14 @@ func newAccessControlCheckCommand() (cmd *cobra.Command) {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func accessControlCheckRunE(cmd *cobra.Command, _ []string) (err error) {
|
func (ctx *CmdCtx) AccessControlCheckRunE(cmd *cobra.Command, _ []string) (err error) {
|
||||||
configs, err := cmd.Flags().GetStringSlice(cmdFlagNameConfig)
|
validator.ValidateAccessControl(ctx.config, ctx.cconfig.validator)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
sources := make([]configuration.Source, len(configs)+2)
|
if ctx.cconfig.validator.HasErrors() || ctx.cconfig.validator.HasWarnings() {
|
||||||
|
|
||||||
for i, path := range configs {
|
|
||||||
sources[i] = configuration.NewYAMLFileSource(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
sources[0+len(configs)] = configuration.NewEnvironmentSource(configuration.DefaultEnvPrefix, configuration.DefaultEnvDelimiter)
|
|
||||||
sources[1+len(configs)] = configuration.NewSecretsSource(configuration.DefaultEnvPrefix, configuration.DefaultEnvDelimiter)
|
|
||||||
|
|
||||||
val := schema.NewStructValidator()
|
|
||||||
|
|
||||||
accessControlConfig := &schema.Configuration{}
|
|
||||||
|
|
||||||
if _, err = configuration.LoadAdvanced(val, "access_control", &accessControlConfig.AccessControl, sources...); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
validator.ValidateAccessControl(accessControlConfig, val)
|
|
||||||
|
|
||||||
if val.HasErrors() || val.HasWarnings() {
|
|
||||||
return errors.New("your configuration has errors")
|
return errors.New("your configuration has errors")
|
||||||
}
|
}
|
||||||
|
|
||||||
authorizer := authorization.NewAuthorizer(accessControlConfig)
|
authorizer := authorization.NewAuthorizer(ctx.config)
|
||||||
|
|
||||||
subject, object, err := getSubjectAndObjectFromFlags(cmd)
|
subject, object, err := getSubjectAndObjectFromFlags(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -94,7 +71,7 @@ func accessControlCheckRunE(cmd *cobra.Command, _ []string) (err error) {
|
||||||
results := authorizer.GetRuleMatchResults(subject, object)
|
results := authorizer.GetRuleMatchResults(subject, object)
|
||||||
|
|
||||||
if len(results) == 0 {
|
if len(results) == 0 {
|
||||||
fmt.Printf("\nThe default policy '%s' will be applied to ALL requests as no rules are configured.\n\n", accessControlConfig.AccessControl.DefaultPolicy)
|
fmt.Printf("\nThe default policy '%s' will be applied to ALL requests as no rules are configured.\n\n", ctx.config.AccessControl.DefaultPolicy)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -104,7 +81,7 @@ func accessControlCheckRunE(cmd *cobra.Command, _ []string) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
accessControlCheckWriteOutput(object, subject, results, accessControlConfig.AccessControl.DefaultPolicy, verbose)
|
accessControlCheckWriteOutput(object, subject, results, ctx.config.AccessControl.DefaultPolicy, verbose)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,13 +9,13 @@ import (
|
||||||
"github.com/authelia/authelia/v4/internal/utils"
|
"github.com/authelia/authelia/v4/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newBuildInfoCmd() (cmd *cobra.Command) {
|
func newBuildInfoCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "build-info",
|
Use: "build-info",
|
||||||
Short: cmdAutheliaBuildInfoShort,
|
Short: cmdAutheliaBuildInfoShort,
|
||||||
Long: cmdAutheliaBuildInfoLong,
|
Long: cmdAutheliaBuildInfoLong,
|
||||||
Example: cmdAutheliaBuildInfoExample,
|
Example: cmdAutheliaBuildInfoExample,
|
||||||
RunE: cmdBuildInfoRunE,
|
RunE: ctx.BuildInfoRunE,
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
|
@ -24,7 +24,8 @@ func newBuildInfoCmd() (cmd *cobra.Command) {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdBuildInfoRunE(_ *cobra.Command, _ []string) (err error) {
|
// BuildInfoRunE is the RunE for the authelia build-info command.
|
||||||
|
func (ctx *CmdCtx) BuildInfoRunE(_ *cobra.Command, _ []string) (err error) {
|
||||||
_, err = fmt.Printf(fmtAutheliaBuild, utils.BuildTag, utils.BuildState, utils.BuildBranch, utils.BuildCommit,
|
_, err = fmt.Printf(fmtAutheliaBuild, utils.BuildTag, utils.BuildState, utils.BuildBranch, utils.BuildCommit,
|
||||||
utils.BuildNumber, runtime.GOOS, runtime.GOARCH, utils.BuildDate, utils.BuildExtra)
|
utils.BuildNumber, runtime.GOOS, runtime.GOARCH, utils.BuildDate, utils.BuildExtra)
|
||||||
|
|
||||||
|
|
|
@ -1,113 +0,0 @@
|
||||||
package commands
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
|
|
||||||
"github.com/authelia/authelia/v4/internal/configuration"
|
|
||||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
|
||||||
"github.com/authelia/authelia/v4/internal/configuration/validator"
|
|
||||||
"github.com/authelia/authelia/v4/internal/logging"
|
|
||||||
)
|
|
||||||
|
|
||||||
// cmdWithConfigFlags is used for commands which require access to the configuration to add the flag to the command.
|
|
||||||
func cmdWithConfigFlags(cmd *cobra.Command, persistent bool, configs []string) {
|
|
||||||
if persistent {
|
|
||||||
cmd.PersistentFlags().StringSliceP(cmdFlagNameConfig, "c", configs, "configuration files to load")
|
|
||||||
} else {
|
|
||||||
cmd.Flags().StringSliceP(cmdFlagNameConfig, "c", configs, "configuration files to load")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var config *schema.Configuration
|
|
||||||
|
|
||||||
func newCmdWithConfigPreRun(ensureConfigExists, validateKeys, validateConfiguration bool) func(cmd *cobra.Command, args []string) {
|
|
||||||
return func(cmd *cobra.Command, _ []string) {
|
|
||||||
var (
|
|
||||||
logger *logrus.Logger
|
|
||||||
err error
|
|
||||||
|
|
||||||
configs, filterNames []string
|
|
||||||
|
|
||||||
filters []configuration.FileFilter
|
|
||||||
)
|
|
||||||
|
|
||||||
logger = logging.Logger()
|
|
||||||
|
|
||||||
if configs, err = cmd.Flags().GetStringSlice(cmdFlagNameConfig); err != nil {
|
|
||||||
logger.Fatalf("Error reading flags: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if filterNames, err = cmd.Flags().GetStringSlice(cmdFlagNameConfigExpFilters); err != nil {
|
|
||||||
logger.Fatalf("Error reading flags: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if filters, err = configuration.NewFileFilters(filterNames); err != nil {
|
|
||||||
logger.Fatalf("Error occurred loading configuration: flag '--%s' is invalid: %v", cmdFlagNameConfigExpFilters, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ensureConfigExists && len(configs) == 1 {
|
|
||||||
created, err := configuration.EnsureConfigurationExists(configs[0])
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if created {
|
|
||||||
logger.Warnf("Configuration did not exist so a default one has been generated at %s, you will need to configure this", configs[0])
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
val *schema.StructValidator
|
|
||||||
)
|
|
||||||
|
|
||||||
config, val, err = loadConfig(configs, validateKeys, validateConfiguration, filters...)
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatalf("Error occurred loading configuration: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
warnings := val.Warnings()
|
|
||||||
if len(warnings) != 0 {
|
|
||||||
for _, warning := range warnings {
|
|
||||||
logger.Warnf("Configuration: %+v", warning)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
errs := val.Errors()
|
|
||||||
if len(errs) != 0 {
|
|
||||||
for _, err := range errs {
|
|
||||||
logger.Errorf("Configuration: %+v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Fatalf("Can't continue due to the errors loading the configuration")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadConfig(configs []string, validateKeys, validateConfiguration bool, filters ...configuration.FileFilter) (c *schema.Configuration, val *schema.StructValidator, err error) {
|
|
||||||
var keys []string
|
|
||||||
|
|
||||||
val = schema.NewStructValidator()
|
|
||||||
|
|
||||||
if keys, c, err = configuration.Load(val,
|
|
||||||
configuration.NewDefaultSourcesFiltered(
|
|
||||||
configs,
|
|
||||||
filters,
|
|
||||||
configuration.DefaultEnvPrefix,
|
|
||||||
configuration.DefaultEnvDelimiter)...); err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if validateKeys {
|
|
||||||
validator.ValidateKeys(keys, configuration.DefaultEnvPrefix, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
if validateConfiguration {
|
|
||||||
validator.ValidateConfiguration(c, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
return c, val, nil
|
|
||||||
}
|
|
|
@ -463,18 +463,6 @@ This subcommand allows generating an %s key pair.`
|
||||||
cmdAutheliaCryptoPairECDSAGenerateExample = `authelia crypto pair ecdsa generate --help`
|
cmdAutheliaCryptoPairECDSAGenerateExample = `authelia crypto pair ecdsa generate --help`
|
||||||
|
|
||||||
cmdAutheliaCryptoPairEd25519GenerateExample = `authelia crypto pair ed25519 generate --help`
|
cmdAutheliaCryptoPairEd25519GenerateExample = `authelia crypto pair ed25519 generate --help`
|
||||||
|
|
||||||
cmdAutheliaHashPasswordShort = "Hash a password to be used in file-based users database"
|
|
||||||
|
|
||||||
cmdAutheliaHashPasswordLong = `Hash a password to be used in file-based users database.`
|
|
||||||
|
|
||||||
//nolint:gosec // This is an example.
|
|
||||||
cmdAutheliaHashPasswordExample = `authelia hash-password -- 'mypass'
|
|
||||||
authelia hash-password --sha512 -- 'mypass'
|
|
||||||
authelia hash-password --iterations=4 -- 'mypass'
|
|
||||||
authelia hash-password --memory=128 -- 'mypass'
|
|
||||||
authelia hash-password --parallelism=1 -- 'mypass'
|
|
||||||
authelia hash-password --key-length=64 -- 'mypass'`
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -544,8 +532,8 @@ const (
|
||||||
cmdFlagNameKeySize = "key-size"
|
cmdFlagNameKeySize = "key-size"
|
||||||
cmdFlagNameSaltSize = "salt-size"
|
cmdFlagNameSaltSize = "salt-size"
|
||||||
cmdFlagNameProfile = "profile"
|
cmdFlagNameProfile = "profile"
|
||||||
cmdFlagNameSHA512 = "sha512"
|
|
||||||
cmdFlagNameConfig = "config"
|
cmdFlagNameConfig = "config"
|
||||||
|
|
||||||
cmdFlagNameConfigExpFilters = "config.experimental.filters"
|
cmdFlagNameConfigExpFilters = "config.experimental.filters"
|
||||||
|
|
||||||
|
@ -598,7 +586,6 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
cmdUseHashPassword = "hash-password [flags] -- [password]"
|
|
||||||
cmdUseHash = "hash"
|
cmdUseHash = "hash"
|
||||||
cmdUseHashArgon2 = "argon2"
|
cmdUseHashArgon2 = "argon2"
|
||||||
cmdUseHashSHA2Crypt = "sha2crypt"
|
cmdUseHashSHA2Crypt = "sha2crypt"
|
||||||
|
@ -627,7 +614,8 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errNoStorageProvider = errors.New("no storage provider configured")
|
errStorageSchemaOutdated = errors.New("storage schema outdated")
|
||||||
|
errStorageSchemaIncompatible = errors.New("storage schema incompatible")
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -0,0 +1,365 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/x509"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
"golang.org/x/sync/errgroup"
|
||||||
|
|
||||||
|
"github.com/authelia/authelia/v4/internal/authentication"
|
||||||
|
"github.com/authelia/authelia/v4/internal/authorization"
|
||||||
|
"github.com/authelia/authelia/v4/internal/configuration"
|
||||||
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||||
|
"github.com/authelia/authelia/v4/internal/configuration/validator"
|
||||||
|
"github.com/authelia/authelia/v4/internal/logging"
|
||||||
|
"github.com/authelia/authelia/v4/internal/metrics"
|
||||||
|
"github.com/authelia/authelia/v4/internal/middlewares"
|
||||||
|
"github.com/authelia/authelia/v4/internal/notification"
|
||||||
|
"github.com/authelia/authelia/v4/internal/ntp"
|
||||||
|
"github.com/authelia/authelia/v4/internal/oidc"
|
||||||
|
"github.com/authelia/authelia/v4/internal/regulation"
|
||||||
|
"github.com/authelia/authelia/v4/internal/session"
|
||||||
|
"github.com/authelia/authelia/v4/internal/templates"
|
||||||
|
"github.com/authelia/authelia/v4/internal/totp"
|
||||||
|
"github.com/authelia/authelia/v4/internal/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewCmdCtx returns a new CmdCtx.
|
||||||
|
func NewCmdCtx() *CmdCtx {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
|
||||||
|
group, ctx := errgroup.WithContext(ctx)
|
||||||
|
|
||||||
|
return &CmdCtx{
|
||||||
|
Context: ctx,
|
||||||
|
cancel: cancel,
|
||||||
|
group: group,
|
||||||
|
log: logging.Logger(),
|
||||||
|
config: &schema.Configuration{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CmdCtx is a context.Context used for the root command.
|
||||||
|
type CmdCtx struct {
|
||||||
|
context.Context
|
||||||
|
|
||||||
|
cancel context.CancelFunc
|
||||||
|
group *errgroup.Group
|
||||||
|
|
||||||
|
log *logrus.Logger
|
||||||
|
|
||||||
|
config *schema.Configuration
|
||||||
|
providers middlewares.Providers
|
||||||
|
trusted *x509.CertPool
|
||||||
|
|
||||||
|
cconfig *CmdCtxConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCmdCtxConfig returns a new CmdCtxConfig.
|
||||||
|
func NewCmdCtxConfig() *CmdCtxConfig {
|
||||||
|
return &CmdCtxConfig{
|
||||||
|
validator: schema.NewStructValidator(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CmdCtxConfig is the configuration for the CmdCtx.
|
||||||
|
type CmdCtxConfig struct {
|
||||||
|
defaults configuration.Source
|
||||||
|
sources []configuration.Source
|
||||||
|
keys []string
|
||||||
|
validator *schema.StructValidator
|
||||||
|
}
|
||||||
|
|
||||||
|
// CobraRunECmd describes a function that can be used as a *cobra.Command RunE, PreRunE, or PostRunE.
|
||||||
|
type CobraRunECmd func(cmd *cobra.Command, args []string) (err error)
|
||||||
|
|
||||||
|
// CheckSchemaVersion is a utility function which checks the schema version.
|
||||||
|
func (ctx *CmdCtx) CheckSchemaVersion() (err error) {
|
||||||
|
if ctx.providers.StorageProvider == nil {
|
||||||
|
return fmt.Errorf("storage not loaded")
|
||||||
|
}
|
||||||
|
|
||||||
|
var version, latest int
|
||||||
|
|
||||||
|
if version, err = ctx.providers.StorageProvider.SchemaVersion(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if latest, err = ctx.providers.StorageProvider.SchemaLatestVersion(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case version > latest:
|
||||||
|
return fmt.Errorf("%w: version %d is not compatible with this version of the binary as the latest compatible version is %d", errStorageSchemaIncompatible, version, latest)
|
||||||
|
case version < latest:
|
||||||
|
return fmt.Errorf("%w: version %d is outdated please migrate to version %d in order to use this command or use an older binary", errStorageSchemaOutdated, version, latest)
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadTrustedCertificates loads the trusted certificates into the CmdCtx.
|
||||||
|
func (ctx *CmdCtx) LoadTrustedCertificates() (warns, errs []error) {
|
||||||
|
ctx.trusted, warns, errs = utils.NewX509CertPool(ctx.config.CertificatesDirectory)
|
||||||
|
|
||||||
|
return warns, errs
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadProviders loads all providers into the CmdCtx.
|
||||||
|
func (ctx *CmdCtx) LoadProviders() (warns, errs []error) {
|
||||||
|
// TODO: Adjust this so the CertPool can be used like a provider.
|
||||||
|
if warns, errs = ctx.LoadTrustedCertificates(); len(warns) != 0 || len(errs) != 0 {
|
||||||
|
return warns, errs
|
||||||
|
}
|
||||||
|
|
||||||
|
storage := getStorageProvider(ctx)
|
||||||
|
|
||||||
|
providers := middlewares.Providers{
|
||||||
|
Authorizer: authorization.NewAuthorizer(ctx.config),
|
||||||
|
NTP: ntp.NewProvider(&ctx.config.NTP),
|
||||||
|
PasswordPolicy: middlewares.NewPasswordPolicyProvider(ctx.config.PasswordPolicy),
|
||||||
|
Regulator: regulation.NewRegulator(ctx.config.Regulation, storage, utils.RealClock{}),
|
||||||
|
SessionProvider: session.NewProvider(ctx.config.Session, ctx.trusted),
|
||||||
|
StorageProvider: storage,
|
||||||
|
TOTP: totp.NewTimeBasedProvider(ctx.config.TOTP),
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case ctx.config.AuthenticationBackend.File != nil:
|
||||||
|
providers.UserProvider = authentication.NewFileUserProvider(ctx.config.AuthenticationBackend.File)
|
||||||
|
case ctx.config.AuthenticationBackend.LDAP != nil:
|
||||||
|
providers.UserProvider = authentication.NewLDAPUserProvider(ctx.config.AuthenticationBackend, ctx.trusted)
|
||||||
|
}
|
||||||
|
|
||||||
|
if providers.Templates, err = templates.New(templates.Config{EmailTemplatesPath: ctx.config.Notifier.TemplatePath}); err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case ctx.config.Notifier.SMTP != nil:
|
||||||
|
providers.Notifier = notification.NewSMTPNotifier(ctx.config.Notifier.SMTP, ctx.trusted, providers.Templates)
|
||||||
|
case ctx.config.Notifier.FileSystem != nil:
|
||||||
|
providers.Notifier = notification.NewFileNotifier(*ctx.config.Notifier.FileSystem)
|
||||||
|
}
|
||||||
|
|
||||||
|
if providers.OpenIDConnect, err = oidc.NewOpenIDConnectProvider(ctx.config.IdentityProviders.OIDC, storage); err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.config.Telemetry.Metrics.Enabled {
|
||||||
|
providers.Metrics = metrics.NewPrometheus()
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.providers = providers
|
||||||
|
|
||||||
|
return warns, errs
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChainRunE runs multiple CobraRunECmd funcs one after the other returning errors.
|
||||||
|
func (ctx *CmdCtx) ChainRunE(cmdRunEs ...CobraRunECmd) CobraRunECmd {
|
||||||
|
return func(cmd *cobra.Command, args []string) (err error) {
|
||||||
|
for _, cmdRunE := range cmdRunEs {
|
||||||
|
if err = cmdRunE(cmd, args); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigSetFlagsMapRunE adds a command line source with flags mapping.
|
||||||
|
func (ctx *CmdCtx) ConfigSetFlagsMapRunE(flags *pflag.FlagSet, flagsMap map[string]string, includeInvalidKeys, includeUnchangedKeys bool) (err error) {
|
||||||
|
if ctx.cconfig == nil {
|
||||||
|
ctx.cconfig = NewCmdCtxConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.cconfig.sources = append(ctx.cconfig.sources, configuration.NewCommandLineSourceWithMapping(flags, flagsMap, includeInvalidKeys, includeUnchangedKeys))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigSetDefaultsRunE adds a defaults configuration source.
|
||||||
|
func (ctx *CmdCtx) ConfigSetDefaultsRunE(defaults map[string]any) CobraRunECmd {
|
||||||
|
return func(cmd *cobra.Command, args []string) (err error) {
|
||||||
|
if ctx.cconfig == nil {
|
||||||
|
ctx.cconfig = NewCmdCtxConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.cconfig.defaults = configuration.NewMapSource(defaults)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigValidateKeysRunE validates the configuration (keys).
|
||||||
|
func (ctx *CmdCtx) ConfigValidateKeysRunE(_ *cobra.Command, _ []string) (err error) {
|
||||||
|
if ctx.cconfig == nil {
|
||||||
|
return fmt.Errorf("config validate keys must be used with ConfigLoadRunE")
|
||||||
|
}
|
||||||
|
|
||||||
|
validator.ValidateKeys(ctx.cconfig.keys, configuration.DefaultEnvPrefix, ctx.cconfig.validator)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigValidateRunE validates the configuration (structure).
|
||||||
|
func (ctx *CmdCtx) ConfigValidateRunE(_ *cobra.Command, _ []string) (err error) {
|
||||||
|
validator.ValidateConfiguration(ctx.config, ctx.cconfig.validator)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigValidateLogRunE logs the warnings and errors detected during the validations that have ran.
|
||||||
|
func (ctx *CmdCtx) ConfigValidateLogRunE(_ *cobra.Command, _ []string) (err error) {
|
||||||
|
warnings := ctx.cconfig.validator.Warnings()
|
||||||
|
if len(warnings) != 0 {
|
||||||
|
for _, warning := range warnings {
|
||||||
|
ctx.log.Warnf("Configuration: %+v", warning)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errs := ctx.cconfig.validator.Errors()
|
||||||
|
if len(errs) != 0 {
|
||||||
|
for _, err = range errs {
|
||||||
|
ctx.log.Errorf("Configuration: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.log.Fatalf("Can't continue due to the errors loading the configuration")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigValidateSectionPasswordRunE validates the configuration (structure, password section).
|
||||||
|
func (ctx *CmdCtx) ConfigValidateSectionPasswordRunE(cmd *cobra.Command, _ []string) (err error) {
|
||||||
|
if ctx.config.AuthenticationBackend.File == nil {
|
||||||
|
return fmt.Errorf("password configuration was not initialized")
|
||||||
|
}
|
||||||
|
|
||||||
|
val := &schema.StructValidator{}
|
||||||
|
|
||||||
|
validator.ValidatePasswordConfiguration(&ctx.config.AuthenticationBackend.File.Password, val)
|
||||||
|
|
||||||
|
errs := val.Errors()
|
||||||
|
|
||||||
|
if len(errs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, e := range errs {
|
||||||
|
if i == 0 {
|
||||||
|
err = e
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fmt.Errorf("%v, %w", err, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("errors occurred validating the password configuration: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigEnsureExistsRunE logs the warnings and errors detected during the validations that have ran.
|
||||||
|
func (ctx *CmdCtx) ConfigEnsureExistsRunE(cmd *cobra.Command, _ []string) (err error) {
|
||||||
|
var (
|
||||||
|
configs []string
|
||||||
|
created bool
|
||||||
|
)
|
||||||
|
|
||||||
|
if configs, _, err = loadEnvCLIStringSliceValue(cmd, "", cmdFlagNameConfig); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(configs) != 1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if created, err = configuration.EnsureConfigurationExists(configs[0]); err != nil {
|
||||||
|
ctx.log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if created {
|
||||||
|
ctx.log.Warnf("Configuration did not exist so a default one has been generated at %s, you will need to configure this", configs[0])
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigLoadRunE loads the configuration into the CmdCtx.
|
||||||
|
func (ctx *CmdCtx) ConfigLoadRunE(cmd *cobra.Command, _ []string) (err error) {
|
||||||
|
var (
|
||||||
|
configs, filterNames []string
|
||||||
|
|
||||||
|
filters []configuration.FileFilter
|
||||||
|
)
|
||||||
|
|
||||||
|
if configs, _, err = loadEnvCLIStringSliceValue(cmd, "", cmdFlagNameConfig); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if filterNames, _, err = loadEnvCLIStringSliceValue(cmd, "", cmdFlagNameConfigExpFilters); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if filters, err = configuration.NewFileFilters(filterNames); err != nil {
|
||||||
|
return fmt.Errorf("error occurred loading configuration: flag '--%s' is invalid: %w", cmdFlagNameConfigExpFilters, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.cconfig == nil {
|
||||||
|
ctx.cconfig = NewCmdCtxConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.cconfig.keys, err = configuration.LoadAdvanced(
|
||||||
|
ctx.cconfig.validator,
|
||||||
|
"",
|
||||||
|
ctx.config,
|
||||||
|
configuration.NewDefaultSourcesWithDefaults(
|
||||||
|
configs,
|
||||||
|
filters,
|
||||||
|
configuration.DefaultEnvPrefix,
|
||||||
|
configuration.DefaultEnvDelimiter,
|
||||||
|
ctx.cconfig.defaults,
|
||||||
|
ctx.cconfig.sources...)...); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadEnvCLIStringSliceValue(cmd *cobra.Command, envKey, flagName string) (value []string, explicit bool, err error) { //nolint:unparam
|
||||||
|
if cmd.Flags().Changed(flagName) {
|
||||||
|
value, err = cmd.Flags().GetStringSlice(flagName)
|
||||||
|
|
||||||
|
return value, true, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
env string
|
||||||
|
ok bool
|
||||||
|
)
|
||||||
|
|
||||||
|
if envKey != "" {
|
||||||
|
env, ok = os.LookupEnv(envKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case ok && env != "":
|
||||||
|
return strings.Split(env, ","), true, nil
|
||||||
|
default:
|
||||||
|
value, err = cmd.Flags().GetStringSlice(flagName)
|
||||||
|
|
||||||
|
return value, false, err
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,7 +15,7 @@ import (
|
||||||
"github.com/authelia/authelia/v4/internal/utils"
|
"github.com/authelia/authelia/v4/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newCryptoCmd() (cmd *cobra.Command) {
|
func newCryptoCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: cmdUseCrypto,
|
Use: cmdUseCrypto,
|
||||||
Short: cmdAutheliaCryptoShort,
|
Short: cmdAutheliaCryptoShort,
|
||||||
|
@ -27,47 +27,35 @@ func newCryptoCmd() (cmd *cobra.Command) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.AddCommand(
|
cmd.AddCommand(
|
||||||
newCryptoRandCmd(),
|
newCryptoRandCmd(ctx),
|
||||||
newCryptoCertificateCmd(),
|
newCryptoCertificateCmd(ctx),
|
||||||
newCryptoHashCmd(),
|
newCryptoHashCmd(ctx),
|
||||||
newCryptoPairCmd(),
|
newCryptoPairCmd(ctx),
|
||||||
)
|
)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCryptoRandCmd() (cmd *cobra.Command) {
|
func newCryptoRandCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: cmdUseRand,
|
Use: cmdUseRand,
|
||||||
Short: cmdAutheliaCryptoRandShort,
|
Short: cmdAutheliaCryptoRandShort,
|
||||||
Long: cmdAutheliaCryptoRandLong,
|
Long: cmdAutheliaCryptoRandLong,
|
||||||
Example: cmdAutheliaCryptoRandExample,
|
Example: cmdAutheliaCryptoRandExample,
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
RunE: func(cmd *cobra.Command, args []string) (err error) {
|
RunE: ctx.CryptoRandRunE,
|
||||||
var (
|
|
||||||
random string
|
|
||||||
)
|
|
||||||
|
|
||||||
if random, err = flagsGetRandomCharacters(cmd.Flags(), cmdFlagNameLength, cmdFlagNameCharSet, cmdFlagNameCharacters); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Random Value: %s\n", random)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Flags().StringP(cmdFlagNameCharSet, "c", cmdFlagValueCharSet, cmdFlagUsageCharset)
|
cmd.Flags().StringP(cmdFlagNameCharSet, "x", cmdFlagValueCharSet, cmdFlagUsageCharset)
|
||||||
cmd.Flags().String(cmdFlagNameCharacters, "", cmdFlagUsageCharacters)
|
cmd.Flags().String(cmdFlagNameCharacters, "", cmdFlagUsageCharacters)
|
||||||
cmd.Flags().IntP(cmdFlagNameLength, "n", 72, cmdFlagUsageLength)
|
cmd.Flags().IntP(cmdFlagNameLength, "n", 72, cmdFlagUsageLength)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCryptoCertificateCmd() (cmd *cobra.Command) {
|
func newCryptoCertificateCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: cmdUseCertificate,
|
Use: cmdUseCertificate,
|
||||||
Short: cmdAutheliaCryptoCertificateShort,
|
Short: cmdAutheliaCryptoCertificateShort,
|
||||||
|
@ -79,15 +67,15 @@ func newCryptoCertificateCmd() (cmd *cobra.Command) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.AddCommand(
|
cmd.AddCommand(
|
||||||
newCryptoCertificateSubCmd(cmdUseRSA),
|
newCryptoCertificateSubCmd(ctx, cmdUseRSA),
|
||||||
newCryptoCertificateSubCmd(cmdUseECDSA),
|
newCryptoCertificateSubCmd(ctx, cmdUseECDSA),
|
||||||
newCryptoCertificateSubCmd(cmdUseEd25519),
|
newCryptoCertificateSubCmd(ctx, cmdUseEd25519),
|
||||||
)
|
)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCryptoCertificateSubCmd(use string) (cmd *cobra.Command) {
|
func newCryptoCertificateSubCmd(ctx *CmdCtx, use string) (cmd *cobra.Command) {
|
||||||
useFmt := fmtCryptoCertificateUse(use)
|
useFmt := fmtCryptoCertificateUse(use)
|
||||||
|
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
|
@ -100,16 +88,16 @@ func newCryptoCertificateSubCmd(use string) (cmd *cobra.Command) {
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.AddCommand(newCryptoGenerateCmd(cmdUseCertificate, use), newCryptoCertificateRequestCmd(use))
|
cmd.AddCommand(newCryptoGenerateCmd(ctx, cmdUseCertificate, use), newCryptoCertificateRequestCmd(ctx, use))
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCryptoCertificateRequestCmd(algorithm string) (cmd *cobra.Command) {
|
func newCryptoCertificateRequestCmd(ctx *CmdCtx, algorithm string) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: cmdUseRequest,
|
Use: cmdUseRequest,
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
RunE: cryptoCertificateRequestRunE,
|
RunE: ctx.CryptoCertificateRequestRunE,
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
}
|
}
|
||||||
|
@ -141,7 +129,7 @@ func newCryptoCertificateRequestCmd(algorithm string) (cmd *cobra.Command) {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCryptoPairCmd() (cmd *cobra.Command) {
|
func newCryptoPairCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: cmdUsePair,
|
Use: cmdUsePair,
|
||||||
Short: cmdAutheliaCryptoPairShort,
|
Short: cmdAutheliaCryptoPairShort,
|
||||||
|
@ -153,15 +141,15 @@ func newCryptoPairCmd() (cmd *cobra.Command) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.AddCommand(
|
cmd.AddCommand(
|
||||||
newCryptoPairSubCmd(cmdUseRSA),
|
newCryptoPairSubCmd(ctx, cmdUseRSA),
|
||||||
newCryptoPairSubCmd(cmdUseECDSA),
|
newCryptoPairSubCmd(ctx, cmdUseECDSA),
|
||||||
newCryptoPairSubCmd(cmdUseEd25519),
|
newCryptoPairSubCmd(ctx, cmdUseEd25519),
|
||||||
)
|
)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCryptoPairSubCmd(use string) (cmd *cobra.Command) {
|
func newCryptoPairSubCmd(ctx *CmdCtx, use string) (cmd *cobra.Command) {
|
||||||
var (
|
var (
|
||||||
example, useFmt string
|
example, useFmt string
|
||||||
)
|
)
|
||||||
|
@ -183,21 +171,21 @@ func newCryptoPairSubCmd(use string) (cmd *cobra.Command) {
|
||||||
Long: fmt.Sprintf(cmdAutheliaCryptoPairSubLong, useFmt, useFmt),
|
Long: fmt.Sprintf(cmdAutheliaCryptoPairSubLong, useFmt, useFmt),
|
||||||
Example: example,
|
Example: example,
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
RunE: cryptoGenerateRunE,
|
RunE: ctx.CryptoGenerateRunE,
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.AddCommand(newCryptoGenerateCmd(cmdUsePair, use))
|
cmd.AddCommand(newCryptoGenerateCmd(ctx, cmdUsePair, use))
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCryptoGenerateCmd(category, algorithm string) (cmd *cobra.Command) {
|
func newCryptoGenerateCmd(ctx *CmdCtx, category, algorithm string) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: cmdUseGenerate,
|
Use: cmdUseGenerate,
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
RunE: cryptoGenerateRunE,
|
RunE: ctx.CryptoGenerateRunE,
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
}
|
}
|
||||||
|
@ -253,7 +241,23 @@ func newCryptoGenerateCmd(category, algorithm string) (cmd *cobra.Command) {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func cryptoGenerateRunE(cmd *cobra.Command, args []string) (err error) {
|
// CryptoRandRunE is the RunE for the authelia crypto rand command.
|
||||||
|
func (ctx *CmdCtx) CryptoRandRunE(cmd *cobra.Command, args []string) (err error) {
|
||||||
|
var (
|
||||||
|
random string
|
||||||
|
)
|
||||||
|
|
||||||
|
if random, err = flagsGetRandomCharacters(cmd.Flags(), cmdFlagNameLength, cmdFlagNameCharSet, cmdFlagNameCharacters); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Random Value: %s\n", random)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CryptoGenerateRunE is the RunE for the authelia crypto [pair|certificate] [rsa|ecdsa|ed25519] commands.
|
||||||
|
func (ctx *CmdCtx) CryptoGenerateRunE(cmd *cobra.Command, args []string) (err error) {
|
||||||
var (
|
var (
|
||||||
privateKey any
|
privateKey any
|
||||||
)
|
)
|
||||||
|
@ -263,13 +267,14 @@ func cryptoGenerateRunE(cmd *cobra.Command, args []string) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.Parent().Parent().Use == cmdUseCertificate {
|
if cmd.Parent().Parent().Use == cmdUseCertificate {
|
||||||
return cryptoCertificateGenerateRunE(cmd, args, privateKey)
|
return ctx.CryptoCertificateGenerateRunE(cmd, args, privateKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
return cryptoPairGenerateRunE(cmd, args, privateKey)
|
return ctx.CryptoPairGenerateRunE(cmd, args, privateKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cryptoCertificateRequestRunE(cmd *cobra.Command, _ []string) (err error) {
|
// CryptoCertificateRequestRunE is the RunE for the authelia crypto certificate request command.
|
||||||
|
func (ctx *CmdCtx) CryptoCertificateRequestRunE(cmd *cobra.Command, _ []string) (err error) {
|
||||||
var (
|
var (
|
||||||
privateKey any
|
privateKey any
|
||||||
)
|
)
|
||||||
|
@ -340,7 +345,8 @@ func cryptoCertificateRequestRunE(cmd *cobra.Command, _ []string) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func cryptoCertificateGenerateRunE(cmd *cobra.Command, _ []string, privateKey any) (err error) {
|
// CryptoCertificateGenerateRunE is the RunE for the authelia crypto certificate [rsa|ecdsa|ed25519] commands.
|
||||||
|
func (ctx *CmdCtx) CryptoCertificateGenerateRunE(cmd *cobra.Command, _ []string, privateKey any) (err error) {
|
||||||
var (
|
var (
|
||||||
template, caCertificate, parent *x509.Certificate
|
template, caCertificate, parent *x509.Certificate
|
||||||
publicKey, caPrivateKey, signatureKey any
|
publicKey, caPrivateKey, signatureKey any
|
||||||
|
@ -432,7 +438,8 @@ func cryptoCertificateGenerateRunE(cmd *cobra.Command, _ []string, privateKey an
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func cryptoPairGenerateRunE(cmd *cobra.Command, _ []string, privateKey any) (err error) {
|
// CryptoPairGenerateRunE is the RunE for the authelia crypto pair [rsa|ecdsa|ed25519] commands.
|
||||||
|
func (ctx *CmdCtx) CryptoPairGenerateRunE(cmd *cobra.Command, _ []string, privateKey any) (err error) {
|
||||||
var (
|
var (
|
||||||
privateKeyPath, publicKeyPath string
|
privateKeyPath, publicKeyPath string
|
||||||
pkcs8 bool
|
pkcs8 bool
|
||||||
|
|
|
@ -7,69 +7,13 @@ import (
|
||||||
"github.com/go-crypt/crypt"
|
"github.com/go-crypt/crypt"
|
||||||
"github.com/go-crypt/crypt/algorithm"
|
"github.com/go-crypt/crypt/algorithm"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/pflag"
|
|
||||||
|
|
||||||
"github.com/authelia/authelia/v4/internal/authentication"
|
"github.com/authelia/authelia/v4/internal/authentication"
|
||||||
"github.com/authelia/authelia/v4/internal/configuration"
|
"github.com/authelia/authelia/v4/internal/configuration"
|
||||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||||
"github.com/authelia/authelia/v4/internal/configuration/validator"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func newHashPasswordCmd() (cmd *cobra.Command) {
|
func newCryptoHashCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
|
||||||
Use: cmdUseHashPassword,
|
|
||||||
Short: cmdAutheliaHashPasswordShort,
|
|
||||||
Long: cmdAutheliaHashPasswordLong,
|
|
||||||
Example: cmdAutheliaHashPasswordExample,
|
|
||||||
Args: cobra.MaximumNArgs(1),
|
|
||||||
RunE: cmdHashPasswordRunE,
|
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
cmdFlagConfig(cmd)
|
|
||||||
|
|
||||||
cmd.Flags().BoolP(cmdFlagNameSHA512, "z", false, fmt.Sprintf("use sha512 as the algorithm (changes iterations to %d, change with -i)", schema.DefaultPasswordConfig.SHA2Crypt.Iterations))
|
|
||||||
cmd.Flags().IntP(cmdFlagNameIterations, "i", schema.DefaultPasswordConfig.Argon2.Iterations, "set the number of hashing iterations")
|
|
||||||
cmd.Flags().IntP(cmdFlagNameMemory, "m", schema.DefaultPasswordConfig.Argon2.Memory, "[argon2id] set the amount of memory param (in MB)")
|
|
||||||
cmd.Flags().IntP(cmdFlagNameParallelism, "p", schema.DefaultPasswordConfig.Argon2.Parallelism, "[argon2id] set the parallelism param")
|
|
||||||
cmd.Flags().IntP("key-length", "k", schema.DefaultPasswordConfig.Argon2.KeyLength, "[argon2id] set the key length param")
|
|
||||||
cmd.Flags().IntP("salt-length", "l", schema.DefaultPasswordConfig.Argon2.SaltLength, "set the auto-generated salt length")
|
|
||||||
cmd.Flags().Bool(cmdFlagNameNoConfirm, false, "skip the password confirmation prompt")
|
|
||||||
|
|
||||||
return cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdHashPasswordRunE(cmd *cobra.Command, args []string) (err error) {
|
|
||||||
var (
|
|
||||||
flagsMap map[string]string
|
|
||||||
sha512 bool
|
|
||||||
)
|
|
||||||
|
|
||||||
if sha512, err = cmd.Flags().GetBool(cmdFlagNameSHA512); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case sha512:
|
|
||||||
flagsMap = map[string]string{
|
|
||||||
cmdFlagNameIterations: prefixFilePassword + ".sha2crypt.iterations",
|
|
||||||
"salt-length": prefixFilePassword + ".sha2crypt.salt_length",
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
flagsMap = map[string]string{
|
|
||||||
cmdFlagNameIterations: prefixFilePassword + ".argon2.iterations",
|
|
||||||
"key-length": prefixFilePassword + ".argon2.key_length",
|
|
||||||
"salt-length": prefixFilePassword + ".argon2.salt_length",
|
|
||||||
cmdFlagNameParallelism: prefixFilePassword + ".argon2.parallelism",
|
|
||||||
cmdFlagNameMemory: prefixFilePassword + ".argon2.memory",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmdCryptoHashGenerateFinish(cmd, args, flagsMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newCryptoHashCmd() (cmd *cobra.Command) {
|
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: cmdUseHash,
|
Use: cmdUseHash,
|
||||||
Short: cmdAutheliaCryptoHashShort,
|
Short: cmdAutheliaCryptoHashShort,
|
||||||
|
@ -81,270 +25,15 @@ func newCryptoHashCmd() (cmd *cobra.Command) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.AddCommand(
|
cmd.AddCommand(
|
||||||
newCryptoHashValidateCmd(),
|
newCryptoHashValidateCmd(ctx),
|
||||||
newCryptoHashGenerateCmd(),
|
newCryptoHashGenerateCmd(ctx),
|
||||||
)
|
)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCryptoHashGenerateCmd() (cmd *cobra.Command) {
|
func newCryptoHashGenerateCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
defaults := map[string]any{
|
||||||
Use: cmdUseGenerate,
|
|
||||||
Short: cmdAutheliaCryptoHashGenerateShort,
|
|
||||||
Long: cmdAutheliaCryptoHashGenerateLong,
|
|
||||||
Example: cmdAutheliaCryptoHashGenerateExample,
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
return cmdCryptoHashGenerateFinish(cmd, args, map[string]string{})
|
|
||||||
},
|
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
cmdFlagConfig(cmd)
|
|
||||||
cmdFlagPassword(cmd, true)
|
|
||||||
cmdFlagRandomPassword(cmd)
|
|
||||||
|
|
||||||
for _, use := range []string{cmdUseHashArgon2, cmdUseHashSHA2Crypt, cmdUseHashPBKDF2, cmdUseHashBCrypt, cmdUseHashSCrypt} {
|
|
||||||
cmd.AddCommand(newCryptoHashGenerateSubCmd(use))
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
func newCryptoHashGenerateSubCmd(use string) (cmd *cobra.Command) {
|
|
||||||
useFmt := fmtCryptoHashUse(use)
|
|
||||||
|
|
||||||
cmd = &cobra.Command{
|
|
||||||
Use: use,
|
|
||||||
Short: fmt.Sprintf(fmtCmdAutheliaCryptoHashGenerateSubShort, useFmt),
|
|
||||||
Long: fmt.Sprintf(fmtCmdAutheliaCryptoHashGenerateSubLong, useFmt, useFmt),
|
|
||||||
Example: fmt.Sprintf(fmtCmdAutheliaCryptoHashGenerateSubExample, use),
|
|
||||||
Args: cobra.NoArgs,
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
switch use {
|
|
||||||
case cmdUseHashArgon2:
|
|
||||||
cmdFlagIterations(cmd, schema.DefaultPasswordConfig.Argon2.Iterations)
|
|
||||||
cmdFlagParallelism(cmd, schema.DefaultPasswordConfig.Argon2.Parallelism)
|
|
||||||
cmdFlagKeySize(cmd, schema.DefaultPasswordConfig.Argon2.KeyLength)
|
|
||||||
cmdFlagSaltSize(cmd, schema.DefaultPasswordConfig.Argon2.SaltLength)
|
|
||||||
|
|
||||||
cmd.Flags().StringP(cmdFlagNameVariant, "v", schema.DefaultPasswordConfig.Argon2.Variant, "variant, options are 'argon2id', 'argon2i', and 'argon2d'")
|
|
||||||
cmd.Flags().IntP(cmdFlagNameMemory, "m", schema.DefaultPasswordConfig.Argon2.Memory, "memory in kibibytes")
|
|
||||||
cmd.Flags().String(cmdFlagNameProfile, "", "profile to use, options are low-memory and recommended")
|
|
||||||
|
|
||||||
cmd.RunE = cryptoHashGenerateArgon2RunE
|
|
||||||
case cmdUseHashSHA2Crypt:
|
|
||||||
cmdFlagIterations(cmd, schema.DefaultPasswordConfig.SHA2Crypt.Iterations)
|
|
||||||
cmdFlagSaltSize(cmd, schema.DefaultPasswordConfig.SHA2Crypt.SaltLength)
|
|
||||||
|
|
||||||
cmd.Flags().StringP(cmdFlagNameVariant, "v", schema.DefaultPasswordConfig.SHA2Crypt.Variant, "variant, options are sha256 and sha512")
|
|
||||||
|
|
||||||
cmd.RunE = cryptoHashGenerateSHA2CryptRunE
|
|
||||||
case cmdUseHashPBKDF2:
|
|
||||||
cmdFlagIterations(cmd, schema.DefaultPasswordConfig.PBKDF2.Iterations)
|
|
||||||
cmdFlagSaltSize(cmd, schema.DefaultPasswordConfig.PBKDF2.SaltLength)
|
|
||||||
|
|
||||||
cmd.Flags().StringP(cmdFlagNameVariant, "v", schema.DefaultPasswordConfig.PBKDF2.Variant, "variant, options are 'sha1', 'sha224', 'sha256', 'sha384', and 'sha512'")
|
|
||||||
|
|
||||||
cmd.RunE = cryptoHashGeneratePBKDF2RunE
|
|
||||||
case cmdUseHashBCrypt:
|
|
||||||
cmd.Flags().StringP(cmdFlagNameVariant, "v", schema.DefaultPasswordConfig.BCrypt.Variant, "variant, options are 'standard' and 'sha256'")
|
|
||||||
cmd.Flags().IntP(cmdFlagNameCost, "i", schema.DefaultPasswordConfig.BCrypt.Cost, "hashing cost")
|
|
||||||
|
|
||||||
cmd.RunE = cryptoHashGenerateBCryptRunE
|
|
||||||
case cmdUseHashSCrypt:
|
|
||||||
cmdFlagIterations(cmd, schema.DefaultPasswordConfig.SCrypt.Iterations)
|
|
||||||
cmdFlagKeySize(cmd, schema.DefaultPasswordConfig.SCrypt.KeyLength)
|
|
||||||
cmdFlagSaltSize(cmd, schema.DefaultPasswordConfig.SCrypt.SaltLength)
|
|
||||||
cmdFlagParallelism(cmd, schema.DefaultPasswordConfig.SCrypt.Parallelism)
|
|
||||||
|
|
||||||
cmd.Flags().IntP(cmdFlagNameBlockSize, "r", schema.DefaultPasswordConfig.SCrypt.BlockSize, "block size")
|
|
||||||
|
|
||||||
cmd.RunE = cryptoHashGenerateSCryptRunE
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
func cryptoHashGenerateArgon2RunE(cmd *cobra.Command, args []string) (err error) {
|
|
||||||
flagsMap := map[string]string{
|
|
||||||
cmdFlagNameVariant: prefixFilePassword + ".argon2.variant",
|
|
||||||
cmdFlagNameIterations: prefixFilePassword + ".argon2.iterations",
|
|
||||||
cmdFlagNameMemory: prefixFilePassword + ".argon2.memory",
|
|
||||||
cmdFlagNameParallelism: prefixFilePassword + ".argon2.parallelism",
|
|
||||||
cmdFlagNameKeySize: prefixFilePassword + ".argon2.key_length",
|
|
||||||
cmdFlagNameSaltSize: prefixFilePassword + ".argon2.salt_length",
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmdCryptoHashGenerateFinish(cmd, args, flagsMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
func cryptoHashGenerateSHA2CryptRunE(cmd *cobra.Command, args []string) (err error) {
|
|
||||||
flagsMap := map[string]string{
|
|
||||||
cmdFlagNameVariant: prefixFilePassword + ".sha2crypt.variant",
|
|
||||||
cmdFlagNameIterations: prefixFilePassword + ".sha2crypt.iterations",
|
|
||||||
cmdFlagNameSaltSize: prefixFilePassword + ".sha2crypt.salt_length",
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmdCryptoHashGenerateFinish(cmd, args, flagsMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
func cryptoHashGeneratePBKDF2RunE(cmd *cobra.Command, args []string) (err error) {
|
|
||||||
flagsMap := map[string]string{
|
|
||||||
cmdFlagNameVariant: prefixFilePassword + ".pbkdf2.variant",
|
|
||||||
cmdFlagNameIterations: prefixFilePassword + ".pbkdf2.iterations",
|
|
||||||
cmdFlagNameKeySize: prefixFilePassword + ".pbkdf2.key_length",
|
|
||||||
cmdFlagNameSaltSize: prefixFilePassword + ".pbkdf2.salt_length",
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmdCryptoHashGenerateFinish(cmd, args, flagsMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
func cryptoHashGenerateBCryptRunE(cmd *cobra.Command, args []string) (err error) {
|
|
||||||
flagsMap := map[string]string{
|
|
||||||
cmdFlagNameVariant: prefixFilePassword + ".bcrypt.variant",
|
|
||||||
cmdFlagNameCost: prefixFilePassword + ".bcrypt.cost",
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmdCryptoHashGenerateFinish(cmd, args, flagsMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
func cryptoHashGenerateSCryptRunE(cmd *cobra.Command, args []string) (err error) {
|
|
||||||
flagsMap := map[string]string{
|
|
||||||
cmdFlagNameIterations: prefixFilePassword + ".scrypt.iterations",
|
|
||||||
cmdFlagNameBlockSize: prefixFilePassword + ".scrypt.block_size",
|
|
||||||
cmdFlagNameParallelism: prefixFilePassword + ".scrypt.parallelism",
|
|
||||||
cmdFlagNameKeySize: prefixFilePassword + ".scrypt.key_length",
|
|
||||||
cmdFlagNameSaltSize: prefixFilePassword + ".scrypt.salt_length",
|
|
||||||
}
|
|
||||||
|
|
||||||
return cmdCryptoHashGenerateFinish(cmd, args, flagsMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newCryptoHashValidateCmd() (cmd *cobra.Command) {
|
|
||||||
cmd = &cobra.Command{
|
|
||||||
Use: fmt.Sprintf(cmdUseFmtValidate, cmdUseValidate),
|
|
||||||
Short: cmdAutheliaCryptoHashValidateShort,
|
|
||||||
Long: cmdAutheliaCryptoHashValidateLong,
|
|
||||||
Example: cmdAutheliaCryptoHashValidateExample,
|
|
||||||
Args: cobra.ExactArgs(1),
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) (err error) {
|
|
||||||
var (
|
|
||||||
password string
|
|
||||||
valid bool
|
|
||||||
)
|
|
||||||
|
|
||||||
if password, _, err = cmdCryptoHashGetPassword(cmd, args, false, false); err != nil {
|
|
||||||
return fmt.Errorf("error occurred trying to obtain the password: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(password) == 0 {
|
|
||||||
return fmt.Errorf("no password provided")
|
|
||||||
}
|
|
||||||
|
|
||||||
if valid, err = crypt.CheckPassword(password, args[0]); err != nil {
|
|
||||||
return fmt.Errorf("error occurred trying to validate the password against the digest: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case valid:
|
|
||||||
fmt.Println("The password matches the digest.")
|
|
||||||
default:
|
|
||||||
fmt.Println("The password does not match the digest.")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
cmdFlagPassword(cmd, false)
|
|
||||||
|
|
||||||
return cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdCryptoHashGenerateFinish(cmd *cobra.Command, args []string, flagsMap map[string]string) (err error) {
|
|
||||||
var (
|
|
||||||
algName string
|
|
||||||
configs []string
|
|
||||||
|
|
||||||
c schema.Password
|
|
||||||
)
|
|
||||||
|
|
||||||
if configs, err = cmd.Flags().GetStringSlice(cmdFlagNameConfig); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip config if the flag wasn't set and the default is non-existent.
|
|
||||||
if !cmd.Flags().Changed(cmdFlagNameConfig) {
|
|
||||||
configs = configFilterExisting(configs)
|
|
||||||
}
|
|
||||||
|
|
||||||
legacy := cmd.Use == cmdUseHashPassword
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case cmd.Use == cmdUseGenerate:
|
|
||||||
break
|
|
||||||
case legacy:
|
|
||||||
if sha512, _ := cmd.Flags().GetBool(cmdFlagNameSHA512); sha512 {
|
|
||||||
algName = cmdUseHashSHA2Crypt
|
|
||||||
} else {
|
|
||||||
algName = cmdUseHashArgon2
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
algName = cmd.Use
|
|
||||||
}
|
|
||||||
|
|
||||||
if c, err = cmdCryptoHashGetConfig(algName, configs, cmd.Flags(), flagsMap); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if legacy && algName == cmdUseHashArgon2 && cmd.Flags().Changed(cmdFlagNameMemory) {
|
|
||||||
c.Argon2.Memory *= 1024
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
hash algorithm.Hash
|
|
||||||
digest algorithm.Digest
|
|
||||||
password string
|
|
||||||
random bool
|
|
||||||
)
|
|
||||||
|
|
||||||
if password, random, err = cmdCryptoHashGetPassword(cmd, args, legacy, !legacy); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(password) == 0 {
|
|
||||||
return fmt.Errorf("no password provided")
|
|
||||||
}
|
|
||||||
|
|
||||||
if hash, err = authentication.NewFileCryptoHashFromConfig(c); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if digest, err = hash.Hash(password); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if random {
|
|
||||||
fmt.Printf("Random Password: %s\n", password)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Digest: %s\n", digest.Encode())
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdCryptoHashGetConfig(algorithm string, configs []string, flags *pflag.FlagSet, flagsMap map[string]string) (c schema.Password, err error) {
|
|
||||||
mapDefaults := map[string]interface{}{
|
|
||||||
prefixFilePassword + ".algorithm": schema.DefaultPasswordConfig.Algorithm,
|
prefixFilePassword + ".algorithm": schema.DefaultPasswordConfig.Algorithm,
|
||||||
prefixFilePassword + ".argon2.variant": schema.DefaultPasswordConfig.Argon2.Variant,
|
prefixFilePassword + ".argon2.variant": schema.DefaultPasswordConfig.Argon2.Variant,
|
||||||
prefixFilePassword + ".argon2.iterations": schema.DefaultPasswordConfig.Argon2.Iterations,
|
prefixFilePassword + ".argon2.iterations": schema.DefaultPasswordConfig.Argon2.Iterations,
|
||||||
|
@ -367,44 +56,246 @@ func cmdCryptoHashGetConfig(algorithm string, configs []string, flags *pflag.Fla
|
||||||
prefixFilePassword + ".scrypt.salt_length": schema.DefaultPasswordConfig.SCrypt.SaltLength,
|
prefixFilePassword + ".scrypt.salt_length": schema.DefaultPasswordConfig.SCrypt.SaltLength,
|
||||||
}
|
}
|
||||||
|
|
||||||
sources := configuration.NewDefaultSourcesWithDefaults(
|
cmd = &cobra.Command{
|
||||||
configs,
|
Use: cmdUseGenerate,
|
||||||
nil,
|
Short: cmdAutheliaCryptoHashGenerateShort,
|
||||||
configuration.DefaultEnvPrefix, configuration.DefaultEnvDelimiter,
|
Long: cmdAutheliaCryptoHashGenerateLong,
|
||||||
configuration.NewMapSource(mapDefaults),
|
Example: cmdAutheliaCryptoHashGenerateExample,
|
||||||
configuration.NewCommandLineSourceWithMapping(flags, flagsMap, false, false),
|
PreRunE: ctx.ChainRunE(
|
||||||
|
ctx.ConfigSetDefaultsRunE(defaults),
|
||||||
|
ctx.CryptoHashGenerateMapFlagsPreRunE,
|
||||||
|
ctx.ConfigLoadRunE,
|
||||||
|
ctx.ConfigValidateSectionPasswordRunE,
|
||||||
|
),
|
||||||
|
RunE: ctx.CryptoHashGenerateRunE,
|
||||||
|
|
||||||
|
DisableAutoGenTag: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdFlagPassword(cmd, true)
|
||||||
|
cmdFlagRandomPassword(cmd)
|
||||||
|
|
||||||
|
for _, use := range []string{cmdUseHashArgon2, cmdUseHashSHA2Crypt, cmdUseHashPBKDF2, cmdUseHashBCrypt, cmdUseHashSCrypt} {
|
||||||
|
cmd.AddCommand(newCryptoHashGenerateSubCmd(ctx, use))
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCryptoHashGenerateSubCmd(ctx *CmdCtx, use string) (cmd *cobra.Command) {
|
||||||
|
defaults := map[string]any{
|
||||||
|
prefixFilePassword + ".algorithm": schema.DefaultPasswordConfig.Algorithm,
|
||||||
|
prefixFilePassword + ".argon2.variant": schema.DefaultPasswordConfig.Argon2.Variant,
|
||||||
|
prefixFilePassword + ".argon2.iterations": schema.DefaultPasswordConfig.Argon2.Iterations,
|
||||||
|
prefixFilePassword + ".argon2.memory": schema.DefaultPasswordConfig.Argon2.Memory,
|
||||||
|
prefixFilePassword + ".argon2.parallelism": schema.DefaultPasswordConfig.Argon2.Parallelism,
|
||||||
|
prefixFilePassword + ".argon2.key_length": schema.DefaultPasswordConfig.Argon2.KeyLength,
|
||||||
|
prefixFilePassword + ".argon2.salt_length": schema.DefaultPasswordConfig.Argon2.SaltLength,
|
||||||
|
prefixFilePassword + ".sha2crypt.variant": schema.DefaultPasswordConfig.SHA2Crypt.Variant,
|
||||||
|
prefixFilePassword + ".sha2crypt.iterations": schema.DefaultPasswordConfig.SHA2Crypt.Iterations,
|
||||||
|
prefixFilePassword + ".sha2crypt.salt_length": schema.DefaultPasswordConfig.SHA2Crypt.SaltLength,
|
||||||
|
prefixFilePassword + ".pbkdf2.variant": schema.DefaultPasswordConfig.PBKDF2.Variant,
|
||||||
|
prefixFilePassword + ".pbkdf2.iterations": schema.DefaultPasswordConfig.PBKDF2.Iterations,
|
||||||
|
prefixFilePassword + ".pbkdf2.salt_length": schema.DefaultPasswordConfig.PBKDF2.SaltLength,
|
||||||
|
prefixFilePassword + ".bcrypt.variant": schema.DefaultPasswordConfig.BCrypt.Variant,
|
||||||
|
prefixFilePassword + ".bcrypt.cost": schema.DefaultPasswordConfig.BCrypt.Cost,
|
||||||
|
prefixFilePassword + ".scrypt.iterations": schema.DefaultPasswordConfig.SCrypt.Iterations,
|
||||||
|
prefixFilePassword + ".scrypt.block_size": schema.DefaultPasswordConfig.SCrypt.BlockSize,
|
||||||
|
prefixFilePassword + ".scrypt.parallelism": schema.DefaultPasswordConfig.SCrypt.Parallelism,
|
||||||
|
prefixFilePassword + ".scrypt.key_length": schema.DefaultPasswordConfig.SCrypt.KeyLength,
|
||||||
|
prefixFilePassword + ".scrypt.salt_length": schema.DefaultPasswordConfig.SCrypt.SaltLength,
|
||||||
|
}
|
||||||
|
|
||||||
|
useFmt := fmtCryptoHashUse(use)
|
||||||
|
|
||||||
|
cmd = &cobra.Command{
|
||||||
|
Use: use,
|
||||||
|
Short: fmt.Sprintf(fmtCmdAutheliaCryptoHashGenerateSubShort, useFmt),
|
||||||
|
Long: fmt.Sprintf(fmtCmdAutheliaCryptoHashGenerateSubLong, useFmt, useFmt),
|
||||||
|
Example: fmt.Sprintf(fmtCmdAutheliaCryptoHashGenerateSubExample, use),
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
PersistentPreRunE: ctx.ChainRunE(
|
||||||
|
ctx.ConfigSetDefaultsRunE(defaults),
|
||||||
|
ctx.CryptoHashGenerateMapFlagsPreRunE,
|
||||||
|
ctx.ConfigLoadRunE,
|
||||||
|
ctx.ConfigValidateSectionPasswordRunE,
|
||||||
|
),
|
||||||
|
RunE: ctx.CryptoHashGenerateRunE,
|
||||||
|
|
||||||
|
DisableAutoGenTag: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
switch use {
|
||||||
|
case cmdUseHashArgon2:
|
||||||
|
cmdFlagIterations(cmd, schema.DefaultPasswordConfig.Argon2.Iterations)
|
||||||
|
cmdFlagParallelism(cmd, schema.DefaultPasswordConfig.Argon2.Parallelism)
|
||||||
|
cmdFlagKeySize(cmd, schema.DefaultPasswordConfig.Argon2.KeyLength)
|
||||||
|
cmdFlagSaltSize(cmd, schema.DefaultPasswordConfig.Argon2.SaltLength)
|
||||||
|
|
||||||
|
cmd.Flags().StringP(cmdFlagNameVariant, "v", schema.DefaultPasswordConfig.Argon2.Variant, "variant, options are 'argon2id', 'argon2i', and 'argon2d'")
|
||||||
|
cmd.Flags().IntP(cmdFlagNameMemory, "m", schema.DefaultPasswordConfig.Argon2.Memory, "memory in kibibytes")
|
||||||
|
cmd.Flags().String(cmdFlagNameProfile, "", "profile to use, options are low-memory and recommended")
|
||||||
|
case cmdUseHashSHA2Crypt:
|
||||||
|
cmdFlagIterations(cmd, schema.DefaultPasswordConfig.SHA2Crypt.Iterations)
|
||||||
|
cmdFlagSaltSize(cmd, schema.DefaultPasswordConfig.SHA2Crypt.SaltLength)
|
||||||
|
|
||||||
|
cmd.Flags().StringP(cmdFlagNameVariant, "v", schema.DefaultPasswordConfig.SHA2Crypt.Variant, "variant, options are sha256 and sha512")
|
||||||
|
cmd.PreRunE = ctx.ChainRunE()
|
||||||
|
case cmdUseHashPBKDF2:
|
||||||
|
cmdFlagIterations(cmd, schema.DefaultPasswordConfig.PBKDF2.Iterations)
|
||||||
|
cmdFlagSaltSize(cmd, schema.DefaultPasswordConfig.PBKDF2.SaltLength)
|
||||||
|
|
||||||
|
cmd.Flags().StringP(cmdFlagNameVariant, "v", schema.DefaultPasswordConfig.PBKDF2.Variant, "variant, options are 'sha1', 'sha224', 'sha256', 'sha384', and 'sha512'")
|
||||||
|
case cmdUseHashBCrypt:
|
||||||
|
cmd.Flags().StringP(cmdFlagNameVariant, "v", schema.DefaultPasswordConfig.BCrypt.Variant, "variant, options are 'standard' and 'sha256'")
|
||||||
|
cmd.Flags().IntP(cmdFlagNameCost, "i", schema.DefaultPasswordConfig.BCrypt.Cost, "hashing cost")
|
||||||
|
case cmdUseHashSCrypt:
|
||||||
|
cmdFlagIterations(cmd, schema.DefaultPasswordConfig.SCrypt.Iterations)
|
||||||
|
cmdFlagKeySize(cmd, schema.DefaultPasswordConfig.SCrypt.KeyLength)
|
||||||
|
cmdFlagSaltSize(cmd, schema.DefaultPasswordConfig.SCrypt.SaltLength)
|
||||||
|
cmdFlagParallelism(cmd, schema.DefaultPasswordConfig.SCrypt.Parallelism)
|
||||||
|
|
||||||
|
cmd.Flags().IntP(cmdFlagNameBlockSize, "r", schema.DefaultPasswordConfig.SCrypt.BlockSize, "block size")
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCryptoHashValidateCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
|
cmd = &cobra.Command{
|
||||||
|
Use: fmt.Sprintf(cmdUseFmtValidate, cmdUseValidate),
|
||||||
|
Short: cmdAutheliaCryptoHashValidateShort,
|
||||||
|
Long: cmdAutheliaCryptoHashValidateLong,
|
||||||
|
Example: cmdAutheliaCryptoHashValidateExample,
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
RunE: ctx.CryptoHashValidateRunE,
|
||||||
|
|
||||||
|
DisableAutoGenTag: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdFlagPassword(cmd, false)
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
// CryptoHashValidateRunE is the RunE for the authelia crypto hash validate command.
|
||||||
|
func (ctx *CmdCtx) CryptoHashValidateRunE(cmd *cobra.Command, args []string) (err error) {
|
||||||
|
var (
|
||||||
|
password string
|
||||||
|
valid bool
|
||||||
)
|
)
|
||||||
|
|
||||||
if algorithm != "" {
|
if password, _, err = cmdCryptoHashGetPassword(cmd, args, false, false); err != nil {
|
||||||
alg := map[string]interface{}{prefixFilePassword + ".algorithm": algorithm}
|
return fmt.Errorf("error occurred trying to obtain the password: %w", err)
|
||||||
|
|
||||||
sources = append(sources, configuration.NewMapSource(alg))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val := schema.NewStructValidator()
|
if len(password) == 0 {
|
||||||
|
return fmt.Errorf("no password provided")
|
||||||
if _, err = configuration.LoadAdvanced(val, prefixFilePassword, &c, sources...); err != nil {
|
|
||||||
return schema.Password{}, fmt.Errorf("error occurred loading configuration: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
validator.ValidatePasswordConfiguration(&c, val)
|
if valid, err = crypt.CheckPassword(password, args[0]); err != nil {
|
||||||
|
return fmt.Errorf("error occurred trying to validate the password against the digest: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
errs := val.Errors()
|
switch {
|
||||||
|
case valid:
|
||||||
|
fmt.Println("The password matches the digest.")
|
||||||
|
default:
|
||||||
|
fmt.Println("The password does not match the digest.")
|
||||||
|
}
|
||||||
|
|
||||||
if len(errs) != 0 {
|
return nil
|
||||||
for i, e := range errs {
|
}
|
||||||
if i == 0 {
|
|
||||||
err = e
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
err = fmt.Errorf("%v, %w", err, e)
|
// CryptoHashGenerateMapFlagsPreRunE is the RunE which configures the flags map configuration source for the
|
||||||
|
// authelia crypto hash generate commands.
|
||||||
|
func (ctx *CmdCtx) CryptoHashGenerateMapFlagsPreRunE(cmd *cobra.Command, args []string) (err error) {
|
||||||
|
var flagsMap map[string]string
|
||||||
|
|
||||||
|
switch cmd.Use {
|
||||||
|
case cmdUseHashArgon2:
|
||||||
|
flagsMap = map[string]string{
|
||||||
|
cmdFlagNameVariant: prefixFilePassword + ".argon2.variant",
|
||||||
|
cmdFlagNameIterations: prefixFilePassword + ".argon2.iterations",
|
||||||
|
cmdFlagNameMemory: prefixFilePassword + ".argon2.memory",
|
||||||
|
cmdFlagNameParallelism: prefixFilePassword + ".argon2.parallelism",
|
||||||
|
cmdFlagNameKeySize: prefixFilePassword + ".argon2.key_length",
|
||||||
|
cmdFlagNameSaltSize: prefixFilePassword + ".argon2.salt_length",
|
||||||
|
}
|
||||||
|
case cmdUseHashSHA2Crypt:
|
||||||
|
flagsMap = map[string]string{
|
||||||
|
cmdFlagNameVariant: prefixFilePassword + ".sha2crypt.variant",
|
||||||
|
cmdFlagNameIterations: prefixFilePassword + ".sha2crypt.iterations",
|
||||||
|
cmdFlagNameSaltSize: prefixFilePassword + ".sha2crypt.salt_length",
|
||||||
|
}
|
||||||
|
case cmdUseHashPBKDF2:
|
||||||
|
flagsMap = map[string]string{
|
||||||
|
cmdFlagNameVariant: prefixFilePassword + ".pbkdf2.variant",
|
||||||
|
cmdFlagNameIterations: prefixFilePassword + ".pbkdf2.iterations",
|
||||||
|
cmdFlagNameKeySize: prefixFilePassword + ".pbkdf2.key_length",
|
||||||
|
cmdFlagNameSaltSize: prefixFilePassword + ".pbkdf2.salt_length",
|
||||||
|
}
|
||||||
|
case cmdUseHashBCrypt:
|
||||||
|
flagsMap = map[string]string{
|
||||||
|
cmdFlagNameVariant: prefixFilePassword + ".bcrypt.variant",
|
||||||
|
cmdFlagNameCost: prefixFilePassword + ".bcrypt.cost",
|
||||||
|
}
|
||||||
|
case cmdUseHashSCrypt:
|
||||||
|
flagsMap = map[string]string{
|
||||||
|
cmdFlagNameIterations: prefixFilePassword + ".scrypt.iterations",
|
||||||
|
cmdFlagNameBlockSize: prefixFilePassword + ".scrypt.block_size",
|
||||||
|
cmdFlagNameParallelism: prefixFilePassword + ".scrypt.parallelism",
|
||||||
|
cmdFlagNameKeySize: prefixFilePassword + ".scrypt.key_length",
|
||||||
|
cmdFlagNameSaltSize: prefixFilePassword + ".scrypt.salt_length",
|
||||||
}
|
}
|
||||||
|
|
||||||
return schema.Password{}, fmt.Errorf("errors occurred validating the password configuration: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return c, nil
|
if flagsMap != nil {
|
||||||
|
ctx.cconfig.sources = append(ctx.cconfig.sources, configuration.NewCommandLineSourceWithMapping(cmd.Flags(), flagsMap, false, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CryptoHashGenerateRunE is the RunE for the authelia crypto hash generate commands.
|
||||||
|
func (ctx *CmdCtx) CryptoHashGenerateRunE(cmd *cobra.Command, args []string) (err error) {
|
||||||
|
var (
|
||||||
|
hash algorithm.Hash
|
||||||
|
digest algorithm.Digest
|
||||||
|
password string
|
||||||
|
random bool
|
||||||
|
)
|
||||||
|
|
||||||
|
if password, random, err = cmdCryptoHashGetPassword(cmd, args, false, true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(password) == 0 {
|
||||||
|
return fmt.Errorf("no password provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch cmd.Use {
|
||||||
|
case cmdUseGenerate:
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
ctx.config.AuthenticationBackend.File.Password.Algorithm = cmd.Use
|
||||||
|
}
|
||||||
|
|
||||||
|
if hash, err = authentication.NewFileCryptoHashFromConfig(ctx.config.AuthenticationBackend.File.Password); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if digest, err = hash.Hash(password); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if random {
|
||||||
|
fmt.Printf("Random Password: %s\n", password)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Digest: %s\n", digest.Encode())
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdCryptoHashGetPassword(cmd *cobra.Command, args []string, useArgs, useRandom bool) (password string, random bool, err error) {
|
func cmdCryptoHashGetPassword(cmd *cobra.Command, args []string, useArgs, useRandom bool) (password string, random bool, err error) {
|
||||||
|
@ -430,18 +321,15 @@ func cmdCryptoHashGetPassword(cmd *cobra.Command, args []string, useArgs, useRan
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
data []byte
|
|
||||||
noConfirm bool
|
noConfirm bool
|
||||||
)
|
)
|
||||||
|
|
||||||
if data, err = termReadPasswordWithPrompt("Enter Password: ", "password"); err != nil {
|
if password, err = termReadPasswordWithPrompt("Enter Password: ", "password"); err != nil {
|
||||||
err = fmt.Errorf("failed to read the password from the terminal: %w", err)
|
err = fmt.Errorf("failed to read the password from the terminal: %w", err)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
password = string(data)
|
|
||||||
|
|
||||||
if cmd.Use == fmt.Sprintf(cmdUseFmtValidate, cmdUseValidate) {
|
if cmd.Use == fmt.Sprintf(cmdUseFmtValidate, cmdUseValidate) {
|
||||||
fmt.Println("")
|
fmt.Println("")
|
||||||
|
|
||||||
|
@ -449,11 +337,13 @@ func cmdCryptoHashGetPassword(cmd *cobra.Command, args []string, useArgs, useRan
|
||||||
}
|
}
|
||||||
|
|
||||||
if noConfirm, err = cmd.Flags().GetBool(cmdFlagNameNoConfirm); err == nil && !noConfirm {
|
if noConfirm, err = cmd.Flags().GetBool(cmdFlagNameNoConfirm); err == nil && !noConfirm {
|
||||||
if data, err = termReadPasswordWithPrompt("Confirm Password: ", ""); err != nil {
|
var confirm string
|
||||||
|
|
||||||
|
if confirm, err = termReadPasswordWithPrompt("Confirm Password: ", ""); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if password != string(data) {
|
if password != confirm {
|
||||||
fmt.Println("")
|
fmt.Println("")
|
||||||
|
|
||||||
err = fmt.Errorf("the password did not match the confirmation password")
|
err = fmt.Errorf("the password did not match the confirmation password")
|
||||||
|
@ -467,10 +357,6 @@ func cmdCryptoHashGetPassword(cmd *cobra.Command, args []string, useArgs, useRan
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdFlagConfig(cmd *cobra.Command) {
|
|
||||||
cmd.PersistentFlags().StringSliceP(cmdFlagNameConfig, "c", []string{"configuration.yml"}, "configuration files to load")
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdFlagPassword(cmd *cobra.Command, noConfirm bool) {
|
func cmdFlagPassword(cmd *cobra.Command, noConfirm bool) {
|
||||||
cmd.PersistentFlags().String(cmdFlagNamePassword, "", "manually supply the password rather than using the terminal prompt")
|
cmd.PersistentFlags().String(cmdFlagNamePassword, "", "manually supply the password rather than using the terminal prompt")
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ import (
|
||||||
func cmdFlagsCryptoCertificateCommon(cmd *cobra.Command) {
|
func cmdFlagsCryptoCertificateCommon(cmd *cobra.Command) {
|
||||||
cmd.Flags().String(cmdFlagNameSignature, "SHA256", "signature algorithm for the certificate")
|
cmd.Flags().String(cmdFlagNameSignature, "SHA256", "signature algorithm for the certificate")
|
||||||
|
|
||||||
cmd.Flags().StringP(cmdFlagNameCommonName, "c", "", "certificate common name")
|
cmd.Flags().StringP(cmdFlagNameCommonName, "n", "", "certificate common name")
|
||||||
cmd.Flags().StringSliceP(cmdFlagNameOrganization, "o", []string{"Authelia"}, "certificate organization")
|
cmd.Flags().StringSliceP(cmdFlagNameOrganization, "o", []string{"Authelia"}, "certificate organization")
|
||||||
cmd.Flags().StringSlice(cmdFlagNameOrganizationalUnit, nil, "certificate organizational unit")
|
cmd.Flags().StringSlice(cmdFlagNameOrganizationalUnit, nil, "certificate organizational unit")
|
||||||
cmd.Flags().StringSlice(cmdFlagNameCountry, nil, "certificate country")
|
cmd.Flags().StringSlice(cmdFlagNameCountry, nil, "certificate country")
|
||||||
|
|
|
@ -6,3 +6,6 @@ import (
|
||||||
|
|
||||||
// ErrStdinIsNotTerminal is returned when Stdin is not an interactive terminal.
|
// ErrStdinIsNotTerminal is returned when Stdin is not an interactive terminal.
|
||||||
var ErrStdinIsNotTerminal = errors.New("stdin is not a terminal")
|
var ErrStdinIsNotTerminal = errors.New("stdin is not a terminal")
|
||||||
|
|
||||||
|
// ErrConfirmationMismatch is returned when user input does not match the confirmation prompt.
|
||||||
|
var ErrConfirmationMismatch = errors.New("user input didn't match the confirmation prompt")
|
||||||
|
|
|
@ -1,115 +1,121 @@
|
||||||
package commands
|
package commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/x509"
|
"encoding/base32"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/authelia/authelia/v4/internal/authentication"
|
"github.com/spf13/pflag"
|
||||||
"github.com/authelia/authelia/v4/internal/authorization"
|
|
||||||
"github.com/authelia/authelia/v4/internal/metrics"
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||||
"github.com/authelia/authelia/v4/internal/middlewares"
|
"github.com/authelia/authelia/v4/internal/model"
|
||||||
"github.com/authelia/authelia/v4/internal/notification"
|
|
||||||
"github.com/authelia/authelia/v4/internal/ntp"
|
|
||||||
"github.com/authelia/authelia/v4/internal/oidc"
|
|
||||||
"github.com/authelia/authelia/v4/internal/regulation"
|
|
||||||
"github.com/authelia/authelia/v4/internal/session"
|
|
||||||
"github.com/authelia/authelia/v4/internal/storage"
|
"github.com/authelia/authelia/v4/internal/storage"
|
||||||
"github.com/authelia/authelia/v4/internal/templates"
|
|
||||||
"github.com/authelia/authelia/v4/internal/totp"
|
|
||||||
"github.com/authelia/authelia/v4/internal/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func getStorageProvider() (provider storage.Provider) {
|
func getStorageProvider(ctx *CmdCtx) (provider storage.Provider) {
|
||||||
switch {
|
switch {
|
||||||
case config.Storage.Local == nil:
|
case ctx.config.Storage.PostgreSQL != nil:
|
||||||
return getStorageProviderWithPool(nil)
|
return storage.NewPostgreSQLProvider(ctx.config, ctx.trusted)
|
||||||
default:
|
case ctx.config.Storage.MySQL != nil:
|
||||||
caCertPool, _, _ := utils.NewX509CertPool(config.CertificatesDirectory)
|
return storage.NewMySQLProvider(ctx.config, ctx.trusted)
|
||||||
|
case ctx.config.Storage.Local != nil:
|
||||||
return getStorageProviderWithPool(caCertPool)
|
return storage.NewSQLiteProvider(ctx.config)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getStorageProviderWithPool(caCertPool *x509.CertPool) (provider storage.Provider) {
|
|
||||||
switch {
|
|
||||||
case config.Storage.PostgreSQL != nil:
|
|
||||||
return storage.NewPostgreSQLProvider(config, caCertPool)
|
|
||||||
case config.Storage.MySQL != nil:
|
|
||||||
return storage.NewMySQLProvider(config, caCertPool)
|
|
||||||
case config.Storage.Local != nil:
|
|
||||||
return storage.NewSQLiteProvider(config)
|
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getProviders() (providers middlewares.Providers, warnings []error, errors []error) {
|
func containsIdentifier(identifier model.UserOpaqueIdentifier, identifiers []model.UserOpaqueIdentifier) bool {
|
||||||
// TODO: Adjust this so the CertPool can be used like a provider.
|
for i := 0; i < len(identifiers); i++ {
|
||||||
caCertPool, warnings, errors := utils.NewX509CertPool(config.CertificatesDirectory)
|
if identifier.Service == identifiers[i].Service && identifier.SectorID == identifiers[i].SectorID && identifier.Username == identifiers[i].Username {
|
||||||
if len(warnings) != 0 || len(errors) != 0 {
|
return true
|
||||||
return providers, warnings, errors
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
storageProvider := getStorageProviderWithPool(caCertPool)
|
return false
|
||||||
|
}
|
||||||
var (
|
|
||||||
userProvider authentication.UserProvider
|
func storageWrapCheckSchemaErr(err error) error {
|
||||||
err error
|
switch {
|
||||||
)
|
case errors.Is(err, errStorageSchemaIncompatible):
|
||||||
|
return fmt.Errorf("command requires the use of a compatibe schema version: %w", err)
|
||||||
switch {
|
case errors.Is(err, errStorageSchemaOutdated):
|
||||||
case config.AuthenticationBackend.File != nil:
|
return fmt.Errorf("command requires the use of a up to date schema version: %w", err)
|
||||||
userProvider = authentication.NewFileUserProvider(config.AuthenticationBackend.File)
|
default:
|
||||||
case config.AuthenticationBackend.LDAP != nil:
|
return err
|
||||||
userProvider = authentication.NewLDAPUserProvider(config.AuthenticationBackend, caCertPool)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
templatesProvider, err := templates.New(templates.Config{EmailTemplatesPath: config.Notifier.TemplatePath})
|
func storageTOTPGenerateRunEOptsFromFlags(flags *pflag.FlagSet) (force bool, filename, secret string, err error) {
|
||||||
if err != nil {
|
if force, err = flags.GetBool("force"); err != nil {
|
||||||
errors = append(errors, err)
|
return force, filename, secret, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var notifier notification.Notifier
|
if filename, err = flags.GetString("path"); err != nil {
|
||||||
|
return force, filename, secret, err
|
||||||
switch {
|
}
|
||||||
case config.Notifier.SMTP != nil:
|
|
||||||
notifier = notification.NewSMTPNotifier(config.Notifier.SMTP, caCertPool, templatesProvider)
|
if secret, err = flags.GetString("secret"); err != nil {
|
||||||
case config.Notifier.FileSystem != nil:
|
return force, filename, secret, err
|
||||||
notifier = notification.NewFileNotifier(*config.Notifier.FileSystem)
|
}
|
||||||
}
|
|
||||||
|
secretLength := base32.StdEncoding.WithPadding(base32.NoPadding).DecodedLen(len(secret))
|
||||||
ntpProvider := ntp.NewProvider(&config.NTP)
|
if secret != "" && secretLength < schema.TOTPSecretSizeMinimum {
|
||||||
|
return force, filename, secret, fmt.Errorf("decoded length of the base32 secret must have "+
|
||||||
clock := utils.RealClock{}
|
"a length of more than %d but '%s' has a decoded length of %d", schema.TOTPSecretSizeMinimum, secret, secretLength)
|
||||||
authorizer := authorization.NewAuthorizer(config)
|
}
|
||||||
sessionProvider := session.NewProvider(config.Session, caCertPool)
|
|
||||||
regulator := regulation.NewRegulator(config.Regulation, storageProvider, clock)
|
return force, filename, secret, nil
|
||||||
|
}
|
||||||
oidcProvider, err := oidc.NewOpenIDConnectProvider(config.IdentityProviders.OIDC, storageProvider)
|
|
||||||
if err != nil {
|
func storageWebauthnDeleteRunEOptsFromFlags(flags *pflag.FlagSet, args []string) (all, byKID bool, description, kid, user string, err error) {
|
||||||
errors = append(errors, err)
|
if len(args) != 0 {
|
||||||
}
|
user = args[0]
|
||||||
|
}
|
||||||
totpProvider := totp.NewTimeBasedProvider(config.TOTP)
|
|
||||||
|
f := 0
|
||||||
ppolicyProvider := middlewares.NewPasswordPolicyProvider(config.PasswordPolicy)
|
|
||||||
|
if flags.Changed(cmdFlagNameAll) {
|
||||||
var metricsProvider metrics.Provider
|
if all, err = flags.GetBool(cmdFlagNameAll); err != nil {
|
||||||
if config.Telemetry.Metrics.Enabled {
|
return
|
||||||
metricsProvider = metrics.NewPrometheus()
|
}
|
||||||
}
|
|
||||||
|
f++
|
||||||
return middlewares.Providers{
|
}
|
||||||
Authorizer: authorizer,
|
|
||||||
UserProvider: userProvider,
|
if flags.Changed(cmdFlagNameDescription) {
|
||||||
Regulator: regulator,
|
if description, err = flags.GetString(cmdFlagNameDescription); err != nil {
|
||||||
OpenIDConnect: oidcProvider,
|
return
|
||||||
StorageProvider: storageProvider,
|
}
|
||||||
Metrics: metricsProvider,
|
|
||||||
NTP: ntpProvider,
|
f++
|
||||||
Notifier: notifier,
|
}
|
||||||
SessionProvider: sessionProvider,
|
|
||||||
Templates: templatesProvider,
|
if byKID = flags.Changed(cmdFlagNameKeyID); byKID {
|
||||||
TOTP: totpProvider,
|
if kid, err = flags.GetString(cmdFlagNameKeyID); err != nil {
|
||||||
PasswordPolicy: ppolicyProvider,
|
return
|
||||||
}, warnings, errors
|
}
|
||||||
|
|
||||||
|
f++
|
||||||
|
}
|
||||||
|
|
||||||
|
if f > 1 {
|
||||||
|
err = fmt.Errorf("must only supply one of the flags --all, --description, and --kid but %d were specified", f)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if f == 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
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetStorageProvider(t *testing.T) {
|
func TestGetStorageProvider(t *testing.T) {
|
||||||
config = &schema.Configuration{}
|
assert.Nil(t, getStorageProvider(NewCmdCtx()))
|
||||||
|
|
||||||
assert.Nil(t, getStorageProvider())
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package commands
|
package commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
@ -11,15 +10,11 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/fsnotify/fsnotify"
|
"github.com/fsnotify/fsnotify"
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
"golang.org/x/sync/errgroup"
|
|
||||||
|
|
||||||
"github.com/authelia/authelia/v4/internal/authentication"
|
"github.com/authelia/authelia/v4/internal/authentication"
|
||||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
|
||||||
"github.com/authelia/authelia/v4/internal/logging"
|
"github.com/authelia/authelia/v4/internal/logging"
|
||||||
"github.com/authelia/authelia/v4/internal/middlewares"
|
|
||||||
"github.com/authelia/authelia/v4/internal/model"
|
"github.com/authelia/authelia/v4/internal/model"
|
||||||
"github.com/authelia/authelia/v4/internal/server"
|
"github.com/authelia/authelia/v4/internal/server"
|
||||||
"github.com/authelia/authelia/v4/internal/utils"
|
"github.com/authelia/authelia/v4/internal/utils"
|
||||||
|
@ -27,6 +22,8 @@ import (
|
||||||
|
|
||||||
// NewRootCmd returns a new Root Cmd.
|
// NewRootCmd returns a new Root Cmd.
|
||||||
func NewRootCmd() (cmd *cobra.Command) {
|
func NewRootCmd() (cmd *cobra.Command) {
|
||||||
|
ctx := NewCmdCtx()
|
||||||
|
|
||||||
version := utils.Version()
|
version := utils.Version()
|
||||||
|
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
|
@ -36,68 +33,70 @@ func NewRootCmd() (cmd *cobra.Command) {
|
||||||
Example: cmdAutheliaExample,
|
Example: cmdAutheliaExample,
|
||||||
Version: version,
|
Version: version,
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
PreRun: newCmdWithConfigPreRun(true, true, true),
|
PreRunE: ctx.ChainRunE(
|
||||||
Run: cmdRootRun,
|
ctx.ConfigEnsureExistsRunE,
|
||||||
|
ctx.ConfigLoadRunE,
|
||||||
|
ctx.ConfigValidateKeysRunE,
|
||||||
|
ctx.ConfigValidateRunE,
|
||||||
|
ctx.ConfigValidateLogRunE,
|
||||||
|
),
|
||||||
|
RunE: ctx.RootRunE,
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdWithConfigFlags(cmd, false, []string{})
|
cmd.PersistentFlags().StringSliceP(cmdFlagNameConfig, "c", []string{"configuration.yml"}, "configuration files to load")
|
||||||
|
|
||||||
cmd.Flags().StringSlice(cmdFlagNameConfigExpFilters, nil, "Applies filters in order to the configuration file before the YAML parser. Options are 'template', 'expand-env'")
|
cmd.PersistentFlags().StringSlice(cmdFlagNameConfigExpFilters, nil, "applies filters in order to the configuration file before the YAML parser, options are 'template', 'expand-env'")
|
||||||
|
|
||||||
cmd.AddCommand(
|
cmd.AddCommand(
|
||||||
newAccessControlCommand(),
|
newAccessControlCommand(ctx),
|
||||||
newBuildInfoCmd(),
|
newBuildInfoCmd(ctx),
|
||||||
newCryptoCmd(),
|
newCryptoCmd(ctx),
|
||||||
newHashPasswordCmd(),
|
newStorageCmd(ctx),
|
||||||
newStorageCmd(),
|
newValidateConfigCmd(ctx),
|
||||||
newValidateConfigCmd(),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdRootRun(_ *cobra.Command, _ []string) {
|
func (ctx *CmdCtx) RootRunE(_ *cobra.Command, _ []string) (err error) {
|
||||||
logger := logging.Logger()
|
ctx.log.Infof("Authelia %s is starting", utils.Version())
|
||||||
|
|
||||||
logger.Infof("Authelia %s is starting", utils.Version())
|
|
||||||
|
|
||||||
if os.Getenv("ENVIRONMENT") == "dev" {
|
if os.Getenv("ENVIRONMENT") == "dev" {
|
||||||
logger.Info("===> Authelia is running in development mode. <===")
|
ctx.log.Info("===> Authelia is running in development mode. <===")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := logging.InitializeLogger(config.Log, true); err != nil {
|
if err = logging.InitializeLogger(ctx.config.Log, true); err != nil {
|
||||||
logger.Fatalf("Cannot initialize logger: %v", err)
|
ctx.log.Fatalf("Cannot initialize logger: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
providers, warnings, errors := getProviders()
|
warns, errs := ctx.LoadProviders()
|
||||||
if len(warnings) != 0 {
|
|
||||||
for _, err := range warnings {
|
if len(warns) != 0 {
|
||||||
logger.Warn(err)
|
for _, err = range warns {
|
||||||
|
ctx.log.Warn(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(errors) != 0 {
|
if len(errs) != 0 {
|
||||||
for _, err := range errors {
|
for _, err = range errs {
|
||||||
logger.Error(err)
|
ctx.log.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Fatalf("Errors occurred provisioning providers.")
|
ctx.log.Fatalf("Errors occurred provisioning providers.")
|
||||||
}
|
}
|
||||||
|
|
||||||
doStartupChecks(config, &providers, logger)
|
doStartupChecks(ctx)
|
||||||
|
|
||||||
runServices(config, providers, logger)
|
runServices(ctx)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:gocyclo // Complexity is required in this function.
|
//nolint:gocyclo // Complexity is required in this function.
|
||||||
func runServices(config *schema.Configuration, providers middlewares.Providers, log *logrus.Logger) {
|
func runServices(ctx *CmdCtx) {
|
||||||
ctx := context.Background()
|
defer ctx.cancel()
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
|
||||||
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
quit := make(chan os.Signal, 1)
|
quit := make(chan os.Signal, 1)
|
||||||
|
|
||||||
|
@ -105,26 +104,24 @@ func runServices(config *schema.Configuration, providers middlewares.Providers,
|
||||||
|
|
||||||
defer signal.Stop(quit)
|
defer signal.Stop(quit)
|
||||||
|
|
||||||
g, ctx := errgroup.WithContext(ctx)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
mainServer, metricsServer *fasthttp.Server
|
mainServer, metricsServer *fasthttp.Server
|
||||||
mainListener, metricsListener net.Listener
|
mainListener, metricsListener net.Listener
|
||||||
)
|
)
|
||||||
|
|
||||||
g.Go(func() (err error) {
|
ctx.group.Go(func() (err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
log.WithError(recoverErr(r)).Errorf("Critical error in server caught (recovered)")
|
ctx.log.WithError(recoverErr(r)).Errorf("Critical error in server caught (recovered)")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if mainServer, mainListener, err = server.CreateDefaultServer(*config, providers); err != nil {
|
if mainServer, mainListener, err = server.CreateDefaultServer(*ctx.config, ctx.providers); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = mainServer.Serve(mainListener); err != nil {
|
if err = mainServer.Serve(mainListener); err != nil {
|
||||||
log.WithError(err).Error("Server (main) returned error")
|
ctx.log.WithError(err).Error("Server (main) returned error")
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -132,23 +129,23 @@ func runServices(config *schema.Configuration, providers middlewares.Providers,
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
g.Go(func() (err error) {
|
ctx.group.Go(func() (err error) {
|
||||||
if providers.Metrics == nil {
|
if ctx.providers.Metrics == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
log.WithError(recoverErr(r)).Errorf("Critical error in metrics server caught (recovered)")
|
ctx.log.WithError(recoverErr(r)).Errorf("Critical error in metrics server caught (recovered)")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if metricsServer, metricsListener, err = server.CreateMetricsServer(config.Telemetry.Metrics); err != nil {
|
if metricsServer, metricsListener, err = server.CreateMetricsServer(ctx.config.Telemetry.Metrics); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = metricsServer.Serve(metricsListener); err != nil {
|
if err = metricsServer.Serve(metricsListener); err != nil {
|
||||||
log.WithError(err).Error("Server (metrics) returned error")
|
ctx.log.WithError(err).Error("Server (metrics) returned error")
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -156,10 +153,10 @@ func runServices(config *schema.Configuration, providers middlewares.Providers,
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if config.AuthenticationBackend.File != nil && config.AuthenticationBackend.File.Watch {
|
if ctx.config.AuthenticationBackend.File != nil && ctx.config.AuthenticationBackend.File.Watch {
|
||||||
provider := providers.UserProvider.(*authentication.FileUserProvider)
|
provider := ctx.providers.UserProvider.(*authentication.FileUserProvider)
|
||||||
if watcher, err := runServiceFileWatcher(g, log, config.AuthenticationBackend.File.Path, provider); err != nil {
|
if watcher, err := runServiceFileWatcher(ctx, ctx.config.AuthenticationBackend.File.Path, provider); err != nil {
|
||||||
log.WithError(err).Errorf("Error opening file watcher")
|
ctx.log.WithError(err).Errorf("Error opening file watcher")
|
||||||
} else {
|
} else {
|
||||||
defer watcher.Close()
|
defer watcher.Close()
|
||||||
}
|
}
|
||||||
|
@ -169,38 +166,38 @@ func runServices(config *schema.Configuration, providers middlewares.Providers,
|
||||||
case s := <-quit:
|
case s := <-quit:
|
||||||
switch s {
|
switch s {
|
||||||
case syscall.SIGINT:
|
case syscall.SIGINT:
|
||||||
log.Debugf("Shutdown started due to SIGINT")
|
ctx.log.Debugf("Shutdown started due to SIGINT")
|
||||||
case syscall.SIGQUIT:
|
case syscall.SIGQUIT:
|
||||||
log.Debugf("Shutdown started due to SIGQUIT")
|
ctx.log.Debugf("Shutdown started due to SIGQUIT")
|
||||||
}
|
}
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
log.Debugf("Shutdown started due to context completion")
|
ctx.log.Debugf("Shutdown started due to context completion")
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel()
|
ctx.cancel()
|
||||||
|
|
||||||
log.Infof("Shutting down")
|
ctx.log.Infof("Shutting down")
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if mainServer != nil {
|
if mainServer != nil {
|
||||||
if err = mainServer.Shutdown(); err != nil {
|
if err = mainServer.Shutdown(); err != nil {
|
||||||
log.WithError(err).Errorf("Error occurred shutting down the server")
|
ctx.log.WithError(err).Errorf("Error occurred shutting down the server")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if metricsServer != nil {
|
if metricsServer != nil {
|
||||||
if err = metricsServer.Shutdown(); err != nil {
|
if err = metricsServer.Shutdown(); err != nil {
|
||||||
log.WithError(err).Errorf("Error occurred shutting down the metrics server")
|
ctx.log.WithError(err).Errorf("Error occurred shutting down the metrics server")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = providers.StorageProvider.Close(); err != nil {
|
if err = ctx.providers.StorageProvider.Close(); err != nil {
|
||||||
log.WithError(err).Errorf("Error occurred closing the database connection")
|
ctx.log.WithError(err).Errorf("Error occurred closing the database connection")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = g.Wait(); err != nil {
|
if err = ctx.group.Wait(); err != nil {
|
||||||
log.WithError(err).Errorf("Error occurred waiting for shutdown")
|
ctx.log.WithError(err).Errorf("Error occurred waiting for shutdown")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,7 +207,7 @@ type ProviderReload interface {
|
||||||
Reload() (reloaded bool, err error)
|
Reload() (reloaded bool, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runServiceFileWatcher(g *errgroup.Group, log *logrus.Logger, path string, reload ProviderReload) (watcher *fsnotify.Watcher, err error) {
|
func runServiceFileWatcher(ctx *CmdCtx, path string, reload ProviderReload) (watcher *fsnotify.Watcher, err error) {
|
||||||
if watcher, err = fsnotify.NewWatcher(); err != nil {
|
if watcher, err = fsnotify.NewWatcher(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -223,7 +220,7 @@ func runServiceFileWatcher(g *errgroup.Group, log *logrus.Logger, path string, r
|
||||||
directory, filename = filepath.Dir(path), filepath.Base(path)
|
directory, filename = filepath.Dir(path), filepath.Base(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
g.Go(func() error {
|
ctx.group.Go(func() error {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-failed:
|
case <-failed:
|
||||||
|
@ -234,30 +231,30 @@ func runServiceFileWatcher(g *errgroup.Group, log *logrus.Logger, path string, r
|
||||||
}
|
}
|
||||||
|
|
||||||
if filename != filepath.Base(event.Name) {
|
if filename != filepath.Base(event.Name) {
|
||||||
log.WithField("file", event.Name).WithField("op", event.Op).Tracef("File modification detected to irrelevant file")
|
ctx.log.WithField("file", event.Name).WithField("op", event.Op).Tracef("File modification detected to irrelevant file")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case event.Op&fsnotify.Write == fsnotify.Write, event.Op&fsnotify.Create == fsnotify.Create:
|
case event.Op&fsnotify.Write == fsnotify.Write, event.Op&fsnotify.Create == fsnotify.Create:
|
||||||
log.WithField("file", event.Name).WithField("op", event.Op).Debug("File modification detected")
|
ctx.log.WithField("file", event.Name).WithField("op", event.Op).Debug("File modification detected")
|
||||||
|
|
||||||
switch reloaded, err := reload.Reload(); {
|
switch reloaded, err := reload.Reload(); {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
log.WithField("file", event.Name).WithField("op", event.Op).WithError(err).Error("Error occurred reloading file")
|
ctx.log.WithField("file", event.Name).WithField("op", event.Op).WithError(err).Error("Error occurred reloading file")
|
||||||
case reloaded:
|
case reloaded:
|
||||||
log.WithField("file", event.Name).Info("Reloaded file successfully")
|
ctx.log.WithField("file", event.Name).Info("Reloaded file successfully")
|
||||||
default:
|
default:
|
||||||
log.WithField("file", event.Name).Debug("Reload of file was triggered but it was skipped")
|
ctx.log.WithField("file", event.Name).Debug("Reload of file was triggered but it was skipped")
|
||||||
}
|
}
|
||||||
case event.Op&fsnotify.Remove == fsnotify.Remove:
|
case event.Op&fsnotify.Remove == fsnotify.Remove:
|
||||||
log.WithField("file", event.Name).WithField("op", event.Op).Debug("Remove of file was detected")
|
ctx.log.WithField("file", event.Name).WithField("op", event.Op).Debug("Remove of file was detected")
|
||||||
}
|
}
|
||||||
case err, ok := <-watcher.Errors:
|
case err, ok := <-watcher.Errors:
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
log.WithError(err).Errorf("Error while watching files")
|
ctx.log.WithError(err).Errorf("Error while watching files")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -268,53 +265,53 @@ func runServiceFileWatcher(g *errgroup.Group, log *logrus.Logger, path string, r
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.WithField("directory", directory).WithField("file", filename).Debug("Directory is being watched for changes to the file")
|
ctx.log.WithField("directory", directory).WithField("file", filename).Debug("Directory is being watched for changes to the file")
|
||||||
|
|
||||||
return watcher, nil
|
return watcher, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func doStartupChecks(config *schema.Configuration, providers *middlewares.Providers, log *logrus.Logger) {
|
func doStartupChecks(ctx *CmdCtx) {
|
||||||
var (
|
var (
|
||||||
failures []string
|
failures []string
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
if err = doStartupCheck(log, "storage", providers.StorageProvider, false); err != nil {
|
if err = doStartupCheck(ctx, "storage", ctx.providers.StorageProvider, false); err != nil {
|
||||||
log.Errorf("Failure running the storage provider startup check: %+v", err)
|
ctx.log.Errorf("Failure running the storage provider startup check: %+v", err)
|
||||||
|
|
||||||
failures = append(failures, "storage")
|
failures = append(failures, "storage")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = doStartupCheck(log, "user", providers.UserProvider, false); err != nil {
|
if err = doStartupCheck(ctx, "user", ctx.providers.UserProvider, false); err != nil {
|
||||||
log.Errorf("Failure running the user provider startup check: %+v", err)
|
ctx.log.Errorf("Failure running the user provider startup check: %+v", err)
|
||||||
|
|
||||||
failures = append(failures, "user")
|
failures = append(failures, "user")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = doStartupCheck(log, "notification", providers.Notifier, config.Notifier.DisableStartupCheck); err != nil {
|
if err = doStartupCheck(ctx, "notification", ctx.providers.Notifier, ctx.config.Notifier.DisableStartupCheck); err != nil {
|
||||||
log.Errorf("Failure running the notification provider startup check: %+v", err)
|
ctx.log.Errorf("Failure running the notification provider startup check: %+v", err)
|
||||||
|
|
||||||
failures = append(failures, "notification")
|
failures = append(failures, "notification")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !config.NTP.DisableStartupCheck && !providers.Authorizer.IsSecondFactorEnabled() {
|
if !ctx.config.NTP.DisableStartupCheck && !ctx.providers.Authorizer.IsSecondFactorEnabled() {
|
||||||
log.Debug("The NTP startup check was skipped due to there being no configured 2FA access control rules")
|
ctx.log.Debug("The NTP startup check was skipped due to there being no configured 2FA access control rules")
|
||||||
} else if err = doStartupCheck(log, "ntp", providers.NTP, config.NTP.DisableStartupCheck); err != nil {
|
} else if err = doStartupCheck(ctx, "ntp", ctx.providers.NTP, ctx.config.NTP.DisableStartupCheck); err != nil {
|
||||||
log.Errorf("Failure running the ntp provider startup check: %+v", err)
|
ctx.log.Errorf("Failure running the ntp provider startup check: %+v", err)
|
||||||
|
|
||||||
if !config.NTP.DisableFailure {
|
if !ctx.config.NTP.DisableFailure {
|
||||||
failures = append(failures, "ntp")
|
failures = append(failures, "ntp")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(failures) != 0 {
|
if len(failures) != 0 {
|
||||||
log.Fatalf("The following providers had fatal failures during startup: %s", strings.Join(failures, ", "))
|
ctx.log.Fatalf("The following providers had fatal failures during startup: %s", strings.Join(failures, ", "))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func doStartupCheck(logger *logrus.Logger, name string, provider model.StartupCheck, disabled bool) error {
|
func doStartupCheck(ctx *CmdCtx, name string, provider model.StartupCheck, disabled bool) error {
|
||||||
if disabled {
|
if disabled {
|
||||||
logger.Debugf("%s provider: startup check skipped as it is disabled", name)
|
ctx.log.Debugf("%s provider: startup check skipped as it is disabled", name)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,20 +9,23 @@ import (
|
||||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newStorageCmd() (cmd *cobra.Command) {
|
func newStorageCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "storage",
|
Use: "storage",
|
||||||
Short: cmdAutheliaStorageShort,
|
Short: cmdAutheliaStorageShort,
|
||||||
Long: cmdAutheliaStorageLong,
|
Long: cmdAutheliaStorageLong,
|
||||||
Example: cmdAutheliaStorageExample,
|
Example: cmdAutheliaStorageExample,
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
PersistentPreRunE: storagePersistentPreRunE,
|
PersistentPreRunE: ctx.ChainRunE(
|
||||||
|
ctx.ConfigStorageCommandLineConfigPersistentPreRunE,
|
||||||
|
ctx.ConfigLoadRunE,
|
||||||
|
ctx.ConfigValidateStoragePersistentPreRunE,
|
||||||
|
ctx.LoadProvidersStorageRunE,
|
||||||
|
),
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdWithConfigFlags(cmd, true, []string{"configuration.yml"})
|
|
||||||
|
|
||||||
cmd.PersistentFlags().String(cmdFlagNameEncryptionKey, "", "the storage encryption key to use")
|
cmd.PersistentFlags().String(cmdFlagNameEncryptionKey, "", "the storage encryption key to use")
|
||||||
|
|
||||||
cmd.PersistentFlags().String(cmdFlagNameSQLite3Path, "", "the SQLite database path")
|
cmd.PersistentFlags().String(cmdFlagNameSQLite3Path, "", "the SQLite database path")
|
||||||
|
@ -45,16 +48,16 @@ func newStorageCmd() (cmd *cobra.Command) {
|
||||||
cmd.PersistentFlags().String("postgres.ssl.key", "", "the PostgreSQL ssl key file location")
|
cmd.PersistentFlags().String("postgres.ssl.key", "", "the PostgreSQL ssl key file location")
|
||||||
|
|
||||||
cmd.AddCommand(
|
cmd.AddCommand(
|
||||||
newStorageMigrateCmd(),
|
newStorageMigrateCmd(ctx),
|
||||||
newStorageSchemaInfoCmd(),
|
newStorageSchemaInfoCmd(ctx),
|
||||||
newStorageEncryptionCmd(),
|
newStorageEncryptionCmd(ctx),
|
||||||
newStorageUserCmd(),
|
newStorageUserCmd(ctx),
|
||||||
)
|
)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageEncryptionCmd() (cmd *cobra.Command) {
|
func newStorageEncryptionCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "encryption",
|
Use: "encryption",
|
||||||
Short: cmdAutheliaStorageEncryptionShort,
|
Short: cmdAutheliaStorageEncryptionShort,
|
||||||
|
@ -65,20 +68,20 @@ func newStorageEncryptionCmd() (cmd *cobra.Command) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.AddCommand(
|
cmd.AddCommand(
|
||||||
newStorageEncryptionChangeKeyCmd(),
|
newStorageEncryptionChangeKeyCmd(ctx),
|
||||||
newStorageEncryptionCheckCmd(),
|
newStorageEncryptionCheckCmd(ctx),
|
||||||
)
|
)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageEncryptionCheckCmd() (cmd *cobra.Command) {
|
func newStorageEncryptionCheckCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "check",
|
Use: "check",
|
||||||
Short: cmdAutheliaStorageEncryptionCheckShort,
|
Short: cmdAutheliaStorageEncryptionCheckShort,
|
||||||
Long: cmdAutheliaStorageEncryptionCheckLong,
|
Long: cmdAutheliaStorageEncryptionCheckLong,
|
||||||
Example: cmdAutheliaStorageEncryptionCheckExample,
|
Example: cmdAutheliaStorageEncryptionCheckExample,
|
||||||
RunE: storageSchemaEncryptionCheckRunE,
|
RunE: ctx.StorageSchemaEncryptionCheckRunE,
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
}
|
}
|
||||||
|
@ -88,13 +91,13 @@ func newStorageEncryptionCheckCmd() (cmd *cobra.Command) {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageEncryptionChangeKeyCmd() (cmd *cobra.Command) {
|
func newStorageEncryptionChangeKeyCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "change-key",
|
Use: "change-key",
|
||||||
Short: cmdAutheliaStorageEncryptionChangeKeyShort,
|
Short: cmdAutheliaStorageEncryptionChangeKeyShort,
|
||||||
Long: cmdAutheliaStorageEncryptionChangeKeyLong,
|
Long: cmdAutheliaStorageEncryptionChangeKeyLong,
|
||||||
Example: cmdAutheliaStorageEncryptionChangeKeyExample,
|
Example: cmdAutheliaStorageEncryptionChangeKeyExample,
|
||||||
RunE: storageSchemaEncryptionChangeKeyRunE,
|
RunE: ctx.StorageSchemaEncryptionChangeKeyRunE,
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
}
|
}
|
||||||
|
@ -104,7 +107,7 @@ func newStorageEncryptionChangeKeyCmd() (cmd *cobra.Command) {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageUserCmd() (cmd *cobra.Command) {
|
func newStorageUserCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "user",
|
Use: "user",
|
||||||
Short: cmdAutheliaStorageUserShort,
|
Short: cmdAutheliaStorageUserShort,
|
||||||
|
@ -115,15 +118,15 @@ func newStorageUserCmd() (cmd *cobra.Command) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.AddCommand(
|
cmd.AddCommand(
|
||||||
newStorageUserIdentifiersCmd(),
|
newStorageUserIdentifiersCmd(ctx),
|
||||||
newStorageUserTOTPCmd(),
|
newStorageUserTOTPCmd(ctx),
|
||||||
newStorageUserWebAuthnCmd(),
|
newStorageUserWebAuthnCmd(ctx),
|
||||||
)
|
)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageUserIdentifiersCmd() (cmd *cobra.Command) {
|
func newStorageUserIdentifiersCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "identifiers",
|
Use: "identifiers",
|
||||||
Short: cmdAutheliaStorageUserIdentifiersShort,
|
Short: cmdAutheliaStorageUserIdentifiersShort,
|
||||||
|
@ -134,22 +137,22 @@ func newStorageUserIdentifiersCmd() (cmd *cobra.Command) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.AddCommand(
|
cmd.AddCommand(
|
||||||
newStorageUserIdentifiersExportCmd(),
|
newStorageUserIdentifiersExportCmd(ctx),
|
||||||
newStorageUserIdentifiersImportCmd(),
|
newStorageUserIdentifiersImportCmd(ctx),
|
||||||
newStorageUserIdentifiersGenerateCmd(),
|
newStorageUserIdentifiersGenerateCmd(ctx),
|
||||||
newStorageUserIdentifiersAddCmd(),
|
newStorageUserIdentifiersAddCmd(ctx),
|
||||||
)
|
)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageUserIdentifiersExportCmd() (cmd *cobra.Command) {
|
func newStorageUserIdentifiersExportCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "export",
|
Use: "export",
|
||||||
Short: cmdAutheliaStorageUserIdentifiersExportShort,
|
Short: cmdAutheliaStorageUserIdentifiersExportShort,
|
||||||
Long: cmdAutheliaStorageUserIdentifiersExportLong,
|
Long: cmdAutheliaStorageUserIdentifiersExportLong,
|
||||||
Example: cmdAutheliaStorageUserIdentifiersExportExample,
|
Example: cmdAutheliaStorageUserIdentifiersExportExample,
|
||||||
RunE: storageUserIdentifiersExport,
|
RunE: ctx.StorageUserIdentifiersExportRunE,
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
}
|
}
|
||||||
|
@ -159,13 +162,13 @@ func newStorageUserIdentifiersExportCmd() (cmd *cobra.Command) {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageUserIdentifiersImportCmd() (cmd *cobra.Command) {
|
func newStorageUserIdentifiersImportCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "import",
|
Use: "import",
|
||||||
Short: cmdAutheliaStorageUserIdentifiersImportShort,
|
Short: cmdAutheliaStorageUserIdentifiersImportShort,
|
||||||
Long: cmdAutheliaStorageUserIdentifiersImportLong,
|
Long: cmdAutheliaStorageUserIdentifiersImportLong,
|
||||||
Example: cmdAutheliaStorageUserIdentifiersImportExample,
|
Example: cmdAutheliaStorageUserIdentifiersImportExample,
|
||||||
RunE: storageUserIdentifiersImport,
|
RunE: ctx.StorageUserIdentifiersImportRunE,
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
}
|
}
|
||||||
|
@ -175,13 +178,13 @@ func newStorageUserIdentifiersImportCmd() (cmd *cobra.Command) {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageUserIdentifiersGenerateCmd() (cmd *cobra.Command) {
|
func newStorageUserIdentifiersGenerateCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "generate",
|
Use: "generate",
|
||||||
Short: cmdAutheliaStorageUserIdentifiersGenerateShort,
|
Short: cmdAutheliaStorageUserIdentifiersGenerateShort,
|
||||||
Long: cmdAutheliaStorageUserIdentifiersGenerateLong,
|
Long: cmdAutheliaStorageUserIdentifiersGenerateLong,
|
||||||
Example: cmdAutheliaStorageUserIdentifiersGenerateExample,
|
Example: cmdAutheliaStorageUserIdentifiersGenerateExample,
|
||||||
RunE: storageUserIdentifiersGenerate,
|
RunE: ctx.StorageUserIdentifiersGenerateRunE,
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
}
|
}
|
||||||
|
@ -193,14 +196,14 @@ func newStorageUserIdentifiersGenerateCmd() (cmd *cobra.Command) {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageUserIdentifiersAddCmd() (cmd *cobra.Command) {
|
func newStorageUserIdentifiersAddCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "add <username>",
|
Use: "add <username>",
|
||||||
Short: cmdAutheliaStorageUserIdentifiersAddShort,
|
Short: cmdAutheliaStorageUserIdentifiersAddShort,
|
||||||
Long: cmdAutheliaStorageUserIdentifiersAddLong,
|
Long: cmdAutheliaStorageUserIdentifiersAddLong,
|
||||||
Example: cmdAutheliaStorageUserIdentifiersAddExample,
|
Example: cmdAutheliaStorageUserIdentifiersAddExample,
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
RunE: storageUserIdentifiersAdd,
|
RunE: ctx.StorageUserIdentifiersAddRunE,
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
}
|
}
|
||||||
|
@ -212,7 +215,7 @@ func newStorageUserIdentifiersAddCmd() (cmd *cobra.Command) {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageUserWebAuthnCmd() (cmd *cobra.Command) {
|
func newStorageUserWebAuthnCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "webauthn",
|
Use: "webauthn",
|
||||||
Short: cmdAutheliaStorageUserWebAuthnShort,
|
Short: cmdAutheliaStorageUserWebAuthnShort,
|
||||||
|
@ -223,20 +226,20 @@ func newStorageUserWebAuthnCmd() (cmd *cobra.Command) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.AddCommand(
|
cmd.AddCommand(
|
||||||
newStorageUserWebAuthnListCmd(),
|
newStorageUserWebAuthnListCmd(ctx),
|
||||||
newStorageUserWebAuthnDeleteCmd(),
|
newStorageUserWebAuthnDeleteCmd(ctx),
|
||||||
)
|
)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageUserWebAuthnListCmd() (cmd *cobra.Command) {
|
func newStorageUserWebAuthnListCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "list [username]",
|
Use: "list [username]",
|
||||||
Short: cmdAutheliaStorageUserWebAuthnListShort,
|
Short: cmdAutheliaStorageUserWebAuthnListShort,
|
||||||
Long: cmdAutheliaStorageUserWebAuthnListLong,
|
Long: cmdAutheliaStorageUserWebAuthnListLong,
|
||||||
Example: cmdAutheliaStorageUserWebAuthnListExample,
|
Example: cmdAutheliaStorageUserWebAuthnListExample,
|
||||||
RunE: storageWebAuthnListRunE,
|
RunE: ctx.StorageWebauthnListRunE,
|
||||||
Args: cobra.MaximumNArgs(1),
|
Args: cobra.MaximumNArgs(1),
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
|
@ -245,13 +248,13 @@ func newStorageUserWebAuthnListCmd() (cmd *cobra.Command) {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageUserWebAuthnDeleteCmd() (cmd *cobra.Command) {
|
func newStorageUserWebAuthnDeleteCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "delete [username]",
|
Use: "delete [username]",
|
||||||
Short: cmdAutheliaStorageUserWebAuthnDeleteShort,
|
Short: cmdAutheliaStorageUserWebAuthnDeleteShort,
|
||||||
Long: cmdAutheliaStorageUserWebAuthnDeleteLong,
|
Long: cmdAutheliaStorageUserWebAuthnDeleteLong,
|
||||||
Example: cmdAutheliaStorageUserWebAuthnDeleteExample,
|
Example: cmdAutheliaStorageUserWebAuthnDeleteExample,
|
||||||
RunE: storageWebAuthnDeleteRunE,
|
RunE: ctx.StorageWebauthnDeleteRunE,
|
||||||
Args: cobra.MaximumNArgs(1),
|
Args: cobra.MaximumNArgs(1),
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
|
@ -264,7 +267,7 @@ func newStorageUserWebAuthnDeleteCmd() (cmd *cobra.Command) {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageUserTOTPCmd() (cmd *cobra.Command) {
|
func newStorageUserTOTPCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "totp",
|
Use: "totp",
|
||||||
Short: cmdAutheliaStorageUserTOTPShort,
|
Short: cmdAutheliaStorageUserTOTPShort,
|
||||||
|
@ -275,21 +278,21 @@ func newStorageUserTOTPCmd() (cmd *cobra.Command) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.AddCommand(
|
cmd.AddCommand(
|
||||||
newStorageUserTOTPGenerateCmd(),
|
newStorageUserTOTPGenerateCmd(ctx),
|
||||||
newStorageUserTOTPDeleteCmd(),
|
newStorageUserTOTPDeleteCmd(ctx),
|
||||||
newStorageUserTOTPExportCmd(),
|
newStorageUserTOTPExportCmd(ctx),
|
||||||
)
|
)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageUserTOTPGenerateCmd() (cmd *cobra.Command) {
|
func newStorageUserTOTPGenerateCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "generate <username>",
|
Use: "generate <username>",
|
||||||
Short: cmdAutheliaStorageUserTOTPGenerateShort,
|
Short: cmdAutheliaStorageUserTOTPGenerateShort,
|
||||||
Long: cmdAutheliaStorageUserTOTPGenerateLong,
|
Long: cmdAutheliaStorageUserTOTPGenerateLong,
|
||||||
Example: cmdAutheliaStorageUserTOTPGenerateExample,
|
Example: cmdAutheliaStorageUserTOTPGenerateExample,
|
||||||
RunE: storageTOTPGenerateRunE,
|
RunE: ctx.StorageTOTPGenerateRunE,
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
|
@ -307,13 +310,13 @@ func newStorageUserTOTPGenerateCmd() (cmd *cobra.Command) {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageUserTOTPDeleteCmd() (cmd *cobra.Command) {
|
func newStorageUserTOTPDeleteCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "delete <username>",
|
Use: "delete <username>",
|
||||||
Short: cmdAutheliaStorageUserTOTPDeleteShort,
|
Short: cmdAutheliaStorageUserTOTPDeleteShort,
|
||||||
Long: cmdAutheliaStorageUserTOTPDeleteLong,
|
Long: cmdAutheliaStorageUserTOTPDeleteLong,
|
||||||
Example: cmdAutheliaStorageUserTOTPDeleteExample,
|
Example: cmdAutheliaStorageUserTOTPDeleteExample,
|
||||||
RunE: storageTOTPDeleteRunE,
|
RunE: ctx.StorageTOTPDeleteRunE,
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
|
@ -322,13 +325,13 @@ func newStorageUserTOTPDeleteCmd() (cmd *cobra.Command) {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageUserTOTPExportCmd() (cmd *cobra.Command) {
|
func newStorageUserTOTPExportCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "export",
|
Use: "export",
|
||||||
Short: cmdAutheliaStorageUserTOTPExportShort,
|
Short: cmdAutheliaStorageUserTOTPExportShort,
|
||||||
Long: cmdAutheliaStorageUserTOTPExportLong,
|
Long: cmdAutheliaStorageUserTOTPExportLong,
|
||||||
Example: cmdAutheliaStorageUserTOTPExportExample,
|
Example: cmdAutheliaStorageUserTOTPExportExample,
|
||||||
RunE: storageTOTPExportRunE,
|
RunE: ctx.StorageTOTPExportRunE,
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
}
|
}
|
||||||
|
@ -339,13 +342,13 @@ func newStorageUserTOTPExportCmd() (cmd *cobra.Command) {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageSchemaInfoCmd() (cmd *cobra.Command) {
|
func newStorageSchemaInfoCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "schema-info",
|
Use: "schema-info",
|
||||||
Short: cmdAutheliaStorageSchemaInfoShort,
|
Short: cmdAutheliaStorageSchemaInfoShort,
|
||||||
Long: cmdAutheliaStorageSchemaInfoLong,
|
Long: cmdAutheliaStorageSchemaInfoLong,
|
||||||
Example: cmdAutheliaStorageSchemaInfoExample,
|
Example: cmdAutheliaStorageSchemaInfoExample,
|
||||||
RunE: storageSchemaInfoRunE,
|
RunE: ctx.StorageSchemaInfoRunE,
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
}
|
}
|
||||||
|
@ -354,7 +357,7 @@ func newStorageSchemaInfoCmd() (cmd *cobra.Command) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMigrationCmd returns a new Migration Cmd.
|
// NewMigrationCmd returns a new Migration Cmd.
|
||||||
func newStorageMigrateCmd() (cmd *cobra.Command) {
|
func newStorageMigrateCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "migrate",
|
Use: "migrate",
|
||||||
Short: cmdAutheliaStorageMigrateShort,
|
Short: cmdAutheliaStorageMigrateShort,
|
||||||
|
@ -366,22 +369,22 @@ func newStorageMigrateCmd() (cmd *cobra.Command) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.AddCommand(
|
cmd.AddCommand(
|
||||||
newStorageMigrateUpCmd(), newStorageMigrateDownCmd(),
|
newStorageMigrateUpCmd(ctx), newStorageMigrateDownCmd(ctx),
|
||||||
newStorageMigrateListUpCmd(), newStorageMigrateListDownCmd(),
|
newStorageMigrateListUpCmd(ctx), newStorageMigrateListDownCmd(ctx),
|
||||||
newStorageMigrateHistoryCmd(),
|
newStorageMigrateHistoryCmd(ctx),
|
||||||
)
|
)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageMigrateHistoryCmd() (cmd *cobra.Command) {
|
func newStorageMigrateHistoryCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "history",
|
Use: "history",
|
||||||
Short: cmdAutheliaStorageMigrateHistoryShort,
|
Short: cmdAutheliaStorageMigrateHistoryShort,
|
||||||
Long: cmdAutheliaStorageMigrateHistoryLong,
|
Long: cmdAutheliaStorageMigrateHistoryLong,
|
||||||
Example: cmdAutheliaStorageMigrateHistoryExample,
|
Example: cmdAutheliaStorageMigrateHistoryExample,
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
RunE: storageMigrateHistoryRunE,
|
RunE: ctx.StorageMigrateHistoryRunE,
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
}
|
}
|
||||||
|
@ -389,14 +392,14 @@ func newStorageMigrateHistoryCmd() (cmd *cobra.Command) {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageMigrateListUpCmd() (cmd *cobra.Command) {
|
func newStorageMigrateListUpCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "list-up",
|
Use: "list-up",
|
||||||
Short: cmdAutheliaStorageMigrateListUpShort,
|
Short: cmdAutheliaStorageMigrateListUpShort,
|
||||||
Long: cmdAutheliaStorageMigrateListUpLong,
|
Long: cmdAutheliaStorageMigrateListUpLong,
|
||||||
Example: cmdAutheliaStorageMigrateListUpExample,
|
Example: cmdAutheliaStorageMigrateListUpExample,
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
RunE: newStorageMigrateListRunE(true),
|
RunE: ctx.NewStorageMigrateListRunE(true),
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
}
|
}
|
||||||
|
@ -404,14 +407,14 @@ func newStorageMigrateListUpCmd() (cmd *cobra.Command) {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageMigrateListDownCmd() (cmd *cobra.Command) {
|
func newStorageMigrateListDownCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "list-down",
|
Use: "list-down",
|
||||||
Short: cmdAutheliaStorageMigrateListDownShort,
|
Short: cmdAutheliaStorageMigrateListDownShort,
|
||||||
Long: cmdAutheliaStorageMigrateListDownLong,
|
Long: cmdAutheliaStorageMigrateListDownLong,
|
||||||
Example: cmdAutheliaStorageMigrateListDownExample,
|
Example: cmdAutheliaStorageMigrateListDownExample,
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
RunE: newStorageMigrateListRunE(false),
|
RunE: ctx.NewStorageMigrateListRunE(false),
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
}
|
}
|
||||||
|
@ -419,14 +422,14 @@ func newStorageMigrateListDownCmd() (cmd *cobra.Command) {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageMigrateUpCmd() (cmd *cobra.Command) {
|
func newStorageMigrateUpCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: storageMigrateDirectionUp,
|
Use: storageMigrateDirectionUp,
|
||||||
Short: cmdAutheliaStorageMigrateUpShort,
|
Short: cmdAutheliaStorageMigrateUpShort,
|
||||||
Long: cmdAutheliaStorageMigrateUpLong,
|
Long: cmdAutheliaStorageMigrateUpLong,
|
||||||
Example: cmdAutheliaStorageMigrateUpExample,
|
Example: cmdAutheliaStorageMigrateUpExample,
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
RunE: newStorageMigrationRunE(true),
|
RunE: ctx.NewStorageMigrationRunE(true),
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
}
|
}
|
||||||
|
@ -436,14 +439,14 @@ func newStorageMigrateUpCmd() (cmd *cobra.Command) {
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageMigrateDownCmd() (cmd *cobra.Command) {
|
func newStorageMigrateDownCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: storageMigrateDirectionDown,
|
Use: storageMigrateDirectionDown,
|
||||||
Short: cmdAutheliaStorageMigrateDownShort,
|
Short: cmdAutheliaStorageMigrateDownShort,
|
||||||
Long: cmdAutheliaStorageMigrateDownLong,
|
Long: cmdAutheliaStorageMigrateDownLong,
|
||||||
Example: cmdAutheliaStorageMigrateDownExample,
|
Example: cmdAutheliaStorageMigrateDownExample,
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
RunE: newStorageMigrationRunE(false),
|
RunE: ctx.NewStorageMigrationRunE(false),
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
package commands
|
package commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/base32"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
|
@ -15,11 +13,8 @@ import (
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/pflag"
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
|
|
||||||
"github.com/authelia/authelia/v4/internal/configuration"
|
|
||||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
|
||||||
"github.com/authelia/authelia/v4/internal/configuration/validator"
|
"github.com/authelia/authelia/v4/internal/configuration/validator"
|
||||||
"github.com/authelia/authelia/v4/internal/model"
|
"github.com/authelia/authelia/v4/internal/model"
|
||||||
"github.com/authelia/authelia/v4/internal/storage"
|
"github.com/authelia/authelia/v4/internal/storage"
|
||||||
|
@ -27,28 +22,35 @@ import (
|
||||||
"github.com/authelia/authelia/v4/internal/utils"
|
"github.com/authelia/authelia/v4/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func storagePersistentPreRunE(cmd *cobra.Command, _ []string) (err error) {
|
// LoadProvidersStorageRunE is a special PreRunE that loads the storage provider into the CmdCtx.
|
||||||
var configs []string
|
func (ctx *CmdCtx) LoadProvidersStorageRunE(cmd *cobra.Command, args []string) (err error) {
|
||||||
|
switch warns, errs := ctx.LoadTrustedCertificates(); {
|
||||||
|
case len(errs) != 0:
|
||||||
|
err = fmt.Errorf("had the following errors loading the trusted certificates")
|
||||||
|
|
||||||
if configs, err = cmd.Flags().GetStringSlice(cmdFlagNameConfig); err != nil {
|
for _, e := range errs {
|
||||||
return err
|
err = fmt.Errorf("%+v: %w", err, e)
|
||||||
}
|
|
||||||
|
|
||||||
sources := make([]configuration.Source, 0, len(configs)+3)
|
|
||||||
|
|
||||||
if cmd.Flags().Changed(cmdFlagNameConfig) {
|
|
||||||
for _, configFile := range configs {
|
|
||||||
if _, err := os.Stat(configFile); os.IsNotExist(err) {
|
|
||||||
return fmt.Errorf("could not load the provided configuration file %s: %w", configFile, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
sources = append(sources, configuration.NewYAMLFileSource(configFile))
|
|
||||||
}
|
}
|
||||||
} else if _, err := os.Stat(configs[0]); err == nil {
|
|
||||||
sources = append(sources, configuration.NewYAMLFileSource(configs[0]))
|
|
||||||
}
|
|
||||||
|
|
||||||
mapping := map[string]string{
|
return err
|
||||||
|
case len(warns) != 0:
|
||||||
|
err = fmt.Errorf("had the following warnings loading the trusted certificates")
|
||||||
|
|
||||||
|
for _, e := range errs {
|
||||||
|
err = fmt.Errorf("%+v: %w", err, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
default:
|
||||||
|
ctx.providers.StorageProvider = getStorageProvider(ctx)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigStorageCommandLineConfigPersistentPreRunE configures the storage command mapping.
|
||||||
|
func (ctx *CmdCtx) ConfigStorageCommandLineConfigPersistentPreRunE(cmd *cobra.Command, _ []string) (err error) {
|
||||||
|
flagsMap := map[string]string{
|
||||||
cmdFlagNameEncryptionKey: "storage.encryption_key",
|
cmdFlagNameEncryptionKey: "storage.encryption_key",
|
||||||
|
|
||||||
cmdFlagNameSQLite3Path: "storage.local.path",
|
cmdFlagNameSQLite3Path: "storage.local.path",
|
||||||
|
@ -77,75 +79,73 @@ func storagePersistentPreRunE(cmd *cobra.Command, _ []string) (err error) {
|
||||||
cmdFlagNameSecretSize: "totp.secret_size",
|
cmdFlagNameSecretSize: "totp.secret_size",
|
||||||
}
|
}
|
||||||
|
|
||||||
sources = append(sources, configuration.NewEnvironmentSource(configuration.DefaultEnvPrefix, configuration.DefaultEnvDelimiter))
|
return ctx.ConfigSetFlagsMapRunE(cmd.Flags(), flagsMap, true, false)
|
||||||
sources = append(sources, configuration.NewSecretsSource(configuration.DefaultEnvPrefix, configuration.DefaultEnvDelimiter))
|
}
|
||||||
sources = append(sources, configuration.NewCommandLineSourceWithMapping(cmd.Flags(), mapping, true, false))
|
|
||||||
|
|
||||||
val := schema.NewStructValidator()
|
// ConfigValidateStoragePersistentPreRunE validates the storage config before running commands using it.
|
||||||
|
func (ctx *CmdCtx) ConfigValidateStoragePersistentPreRunE(_ *cobra.Command, _ []string) (err error) {
|
||||||
|
if errs := ctx.cconfig.validator.Errors(); len(errs) != 0 {
|
||||||
|
var (
|
||||||
|
i int
|
||||||
|
e error
|
||||||
|
)
|
||||||
|
|
||||||
config = &schema.Configuration{}
|
for i, e = range errs {
|
||||||
|
if i == 0 {
|
||||||
|
err = e
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fmt.Errorf("%w, %v", err, e)
|
||||||
|
}
|
||||||
|
|
||||||
if _, err = configuration.LoadAdvanced(val, "", &config, sources...); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if val.HasErrors() {
|
validator.ValidateStorage(ctx.config.Storage, ctx.cconfig.validator)
|
||||||
var finalErr error
|
|
||||||
|
|
||||||
for i, err := range val.Errors() {
|
validator.ValidateTOTP(ctx.config, ctx.cconfig.validator)
|
||||||
|
|
||||||
|
if errs := ctx.cconfig.validator.Errors(); len(errs) != 0 {
|
||||||
|
var (
|
||||||
|
i int
|
||||||
|
e error
|
||||||
|
)
|
||||||
|
|
||||||
|
for i, e = range errs {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
finalErr = err
|
err = e
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
finalErr = fmt.Errorf("%w, %v", finalErr, err)
|
err = fmt.Errorf("%w, %v", err, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
return finalErr
|
return err
|
||||||
}
|
|
||||||
|
|
||||||
validator.ValidateStorage(config.Storage, val)
|
|
||||||
|
|
||||||
validator.ValidateTOTP(config, val)
|
|
||||||
|
|
||||||
if val.HasErrors() {
|
|
||||||
var finalErr error
|
|
||||||
|
|
||||||
for i, err := range val.Errors() {
|
|
||||||
if i == 0 {
|
|
||||||
finalErr = err
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
finalErr = fmt.Errorf("%w, %v", finalErr, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return finalErr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func storageSchemaEncryptionCheckRunE(cmd *cobra.Command, args []string) (err error) {
|
func (ctx *CmdCtx) StorageSchemaEncryptionCheckRunE(cmd *cobra.Command, args []string) (err error) {
|
||||||
var (
|
var (
|
||||||
provider storage.Provider
|
verbose bool
|
||||||
verbose bool
|
result storage.EncryptionValidationResult
|
||||||
result storage.EncryptionValidationResult
|
|
||||||
|
|
||||||
ctx = context.Background()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
provider = getStorageProvider()
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = provider.Close()
|
_ = ctx.providers.StorageProvider.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
if err = ctx.CheckSchemaVersion(); err != nil {
|
||||||
|
return storageWrapCheckSchemaErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
if verbose, err = cmd.Flags().GetBool(cmdFlagNameVerbose); err != nil {
|
if verbose, err = cmd.Flags().GetBool(cmdFlagNameVerbose); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if result, err = provider.SchemaEncryptionCheckKey(ctx, verbose); err != nil {
|
if result, err = ctx.providers.StorageProvider.SchemaEncryptionCheckKey(ctx, verbose); err != nil {
|
||||||
switch {
|
switch {
|
||||||
case errors.Is(err, storage.ErrSchemaEncryptionVersionUnsupported):
|
case errors.Is(err, storage.ErrSchemaEncryptionVersionUnsupported):
|
||||||
fmt.Printf("Storage Encryption Key Validation: FAILURE\n\n\tCause: The schema version doesn't support encryption.\n")
|
fmt.Printf("Storage Encryption Key Validation: FAILURE\n\n\tCause: The schema version doesn't support encryption.\n")
|
||||||
|
@ -183,26 +183,22 @@ func storageSchemaEncryptionCheckRunE(cmd *cobra.Command, args []string) (err er
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func storageSchemaEncryptionChangeKeyRunE(cmd *cobra.Command, args []string) (err error) {
|
// StorageSchemaEncryptionChangeKeyRunE is the RunE for the authelia storage encryption change-key command.
|
||||||
|
func (ctx *CmdCtx) StorageSchemaEncryptionChangeKeyRunE(cmd *cobra.Command, args []string) (err error) {
|
||||||
var (
|
var (
|
||||||
provider storage.Provider
|
key string
|
||||||
key string
|
version int
|
||||||
version int
|
|
||||||
|
|
||||||
ctx = context.Background()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
provider = getStorageProvider()
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = provider.Close()
|
_ = ctx.providers.StorageProvider.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err = checkStorageSchemaUpToDate(ctx, provider); err != nil {
|
if err = ctx.CheckSchemaVersion(); err != nil {
|
||||||
return err
|
return storageWrapCheckSchemaErr(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if version, err = provider.SchemaVersion(ctx); err != nil {
|
if version, err = ctx.providers.StorageProvider.SchemaVersion(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,7 +214,7 @@ func storageSchemaEncryptionChangeKeyRunE(cmd *cobra.Command, args []string) (er
|
||||||
}
|
}
|
||||||
|
|
||||||
if !useFlag || key == "" {
|
if !useFlag || key == "" {
|
||||||
if key, err = termReadPasswordStrWithPrompt("Enter New Storage Encryption Key: ", cmdFlagNameNewEncryptionKey); err != nil {
|
if key, err = termReadPasswordWithPrompt("Enter New Storage Encryption Key: ", cmdFlagNameNewEncryptionKey); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,7 +226,7 @@ func storageSchemaEncryptionChangeKeyRunE(cmd *cobra.Command, args []string) (er
|
||||||
return errors.New("the new encryption key must be at least 20 characters")
|
return errors.New("the new encryption key must be at least 20 characters")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = provider.SchemaEncryptionChangeKey(ctx, key); err != nil {
|
if err = ctx.providers.StorageProvider.SchemaEncryptionChangeKey(ctx, key); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,27 +235,25 @@ func storageSchemaEncryptionChangeKeyRunE(cmd *cobra.Command, args []string) (er
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func storageWebAuthnListRunE(cmd *cobra.Command, args []string) (err error) {
|
// StorageWebauthnListRunE is the RunE for the authelia storage user webauthn list command.
|
||||||
|
func (ctx *CmdCtx) StorageWebauthnListRunE(cmd *cobra.Command, args []string) (err error) {
|
||||||
if len(args) == 0 || args[0] == "" {
|
if len(args) == 0 || args[0] == "" {
|
||||||
return storageWebAuthnListAllRunE(cmd, args)
|
return ctx.StorageWebauthnListAllRunE(cmd, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
provider storage.Provider
|
|
||||||
ctx = context.Background()
|
|
||||||
)
|
|
||||||
|
|
||||||
provider = getStorageProvider()
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = provider.Close()
|
_ = ctx.providers.StorageProvider.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
if err = ctx.CheckSchemaVersion(); err != nil {
|
||||||
|
return storageWrapCheckSchemaErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
var devices []model.WebauthnDevice
|
var devices []model.WebauthnDevice
|
||||||
|
|
||||||
user := args[0]
|
user := args[0]
|
||||||
|
|
||||||
devices, err = provider.LoadWebauthnDevicesByUsername(ctx, user)
|
devices, err = ctx.providers.StorageProvider.LoadWebauthnDevicesByUsername(ctx, user)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case len(devices) == 0 || (err != nil && errors.Is(err, storage.ErrNoWebauthnDevice)):
|
case len(devices) == 0 || (err != nil && errors.Is(err, storage.ErrNoWebauthnDevice)):
|
||||||
|
@ -278,18 +272,16 @@ func storageWebAuthnListRunE(cmd *cobra.Command, args []string) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func storageWebAuthnListAllRunE(_ *cobra.Command, _ []string) (err error) {
|
// StorageWebauthnListAllRunE is the RunE for the authelia storage user webauthn list command when no args are specified.
|
||||||
var (
|
func (ctx *CmdCtx) StorageWebauthnListAllRunE(_ *cobra.Command, _ []string) (err error) {
|
||||||
provider storage.Provider
|
|
||||||
ctx = context.Background()
|
|
||||||
)
|
|
||||||
|
|
||||||
provider = getStorageProvider()
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = provider.Close()
|
_ = ctx.providers.StorageProvider.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
if err = ctx.CheckSchemaVersion(); err != nil {
|
||||||
|
return storageWrapCheckSchemaErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
var devices []model.WebauthnDevice
|
var devices []model.WebauthnDevice
|
||||||
|
|
||||||
limit := 10
|
limit := 10
|
||||||
|
@ -297,7 +289,7 @@ func storageWebAuthnListAllRunE(_ *cobra.Command, _ []string) (err error) {
|
||||||
output := strings.Builder{}
|
output := strings.Builder{}
|
||||||
|
|
||||||
for page := 0; true; page++ {
|
for page := 0; true; page++ {
|
||||||
if devices, err = provider.LoadWebauthnDevices(ctx, limit, page); err != nil {
|
if devices, err = ctx.providers.StorageProvider.LoadWebauthnDevices(ctx, limit, page); err != nil {
|
||||||
return fmt.Errorf("failed to list devices: %w", err)
|
return fmt.Errorf("failed to list devices: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,35 +312,33 @@ func storageWebAuthnListAllRunE(_ *cobra.Command, _ []string) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func storageWebAuthnDeleteRunE(cmd *cobra.Command, args []string) (err error) {
|
// StorageWebauthnDeleteRunE is the RunE for the authelia storage user webauthn delete command.
|
||||||
var (
|
func (ctx *CmdCtx) StorageWebauthnDeleteRunE(cmd *cobra.Command, args []string) (err error) {
|
||||||
provider storage.Provider
|
|
||||||
ctx = context.Background()
|
|
||||||
)
|
|
||||||
|
|
||||||
provider = getStorageProvider()
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = provider.Close()
|
_ = ctx.providers.StorageProvider.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
if err = ctx.CheckSchemaVersion(); err != nil {
|
||||||
|
return storageWrapCheckSchemaErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
all, byKID bool
|
all, byKID bool
|
||||||
description, kid, user string
|
description, kid, user string
|
||||||
)
|
)
|
||||||
|
|
||||||
if all, byKID, description, kid, user, err = storageWebAuthnDeleteGetAndValidateConfig(cmd, args); err != nil {
|
if all, byKID, description, kid, user, err = storageWebauthnDeleteRunEOptsFromFlags(cmd.Flags(), args); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if byKID {
|
if byKID {
|
||||||
if err = provider.DeleteWebauthnDevice(ctx, kid); err != nil {
|
if err = ctx.providers.StorageProvider.DeleteWebauthnDevice(ctx, kid); err != nil {
|
||||||
return fmt.Errorf("failed to delete WebAuthn device with kid '%s': %w", kid, err)
|
return fmt.Errorf("failed to delete WebAuthn device with kid '%s': %w", kid, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Deleted WebAuthn device with kid '%s'", kid)
|
fmt.Printf("Deleted WebAuthn device with kid '%s'", kid)
|
||||||
} else {
|
} else {
|
||||||
err = provider.DeleteWebauthnDeviceByUsername(ctx, user, description)
|
err = ctx.providers.StorageProvider.DeleteWebauthnDeviceByUsername(ctx, user, description)
|
||||||
|
|
||||||
if all {
|
if all {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -368,62 +358,9 @@ func storageWebAuthnDeleteRunE(cmd *cobra.Command, args []string) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func storageWebAuthnDeleteGetAndValidateConfig(cmd *cobra.Command, args []string) (all, byKID bool, description, kid, user string, err error) {
|
// StorageTOTPGenerateRunE is the RunE for the authelia storage user totp generate command.
|
||||||
if len(args) != 0 {
|
func (ctx *CmdCtx) StorageTOTPGenerateRunE(cmd *cobra.Command, args []string) (err error) {
|
||||||
user = args[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
flags := 0
|
|
||||||
|
|
||||||
if cmd.Flags().Changed(cmdFlagNameAll) {
|
|
||||||
if all, err = cmd.Flags().GetBool(cmdFlagNameAll); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
flags++
|
|
||||||
}
|
|
||||||
|
|
||||||
if cmd.Flags().Changed(cmdFlagNameDescription) {
|
|
||||||
if description, err = cmd.Flags().GetString(cmdFlagNameDescription); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
flags++
|
|
||||||
}
|
|
||||||
|
|
||||||
if byKID = cmd.Flags().Changed(cmdFlagNameKeyID); byKID {
|
|
||||||
if kid, err = cmd.Flags().GetString(cmdFlagNameKeyID); 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) {
|
|
||||||
var (
|
var (
|
||||||
provider storage.Provider
|
|
||||||
ctx = context.Background()
|
|
||||||
c *model.TOTPConfiguration
|
c *model.TOTPConfiguration
|
||||||
force bool
|
force bool
|
||||||
filename, secret string
|
filename, secret string
|
||||||
|
@ -431,25 +368,27 @@ func storageTOTPGenerateRunE(cmd *cobra.Command, args []string) (err error) {
|
||||||
img image.Image
|
img image.Image
|
||||||
)
|
)
|
||||||
|
|
||||||
provider = getStorageProvider()
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = provider.Close()
|
_ = ctx.providers.StorageProvider.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
if err = ctx.CheckSchemaVersion(); err != nil {
|
||||||
|
return storageWrapCheckSchemaErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
if force, filename, secret, err = storageTOTPGenerateRunEOptsFromFlags(cmd.Flags()); err != nil {
|
if force, filename, secret, err = storageTOTPGenerateRunEOptsFromFlags(cmd.Flags()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = provider.LoadTOTPConfiguration(ctx, args[0]); err == nil && !force {
|
if _, err = ctx.providers.StorageProvider.LoadTOTPConfiguration(ctx, args[0]); err == nil && !force {
|
||||||
return fmt.Errorf("%s already has a TOTP configuration, use --force to overwrite", args[0])
|
return fmt.Errorf("%s already has a TOTP configuration, use --force to overwrite", args[0])
|
||||||
} else if err != nil && !errors.Is(err, storage.ErrNoTOTPConfiguration) {
|
} else if err != nil && !errors.Is(err, storage.ErrNoTOTPConfiguration) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
totpProvider := totp.NewTimeBasedProvider(config.TOTP)
|
totpProvider := totp.NewTimeBasedProvider(ctx.config.TOTP)
|
||||||
|
|
||||||
if c, err = totpProvider.GenerateCustom(args[0], config.TOTP.Algorithm, secret, config.TOTP.Digits, config.TOTP.Period, config.TOTP.SecretSize); err != nil {
|
if c, err = totpProvider.GenerateCustom(args[0], ctx.config.TOTP.Algorithm, secret, ctx.config.TOTP.Digits, ctx.config.TOTP.Period, ctx.config.TOTP.SecretSize); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,7 +416,7 @@ func storageTOTPGenerateRunE(cmd *cobra.Command, args []string) (err error) {
|
||||||
extraInfo = fmt.Sprintf(" and saved it as a PNG image at the path '%s'", filename)
|
extraInfo = fmt.Sprintf(" and saved it as a PNG image at the path '%s'", filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = provider.SaveTOTPConfiguration(ctx, *c); err != nil {
|
if err = ctx.providers.StorageProvider.SaveTOTPConfiguration(ctx, *c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,47 +425,23 @@ func storageTOTPGenerateRunE(cmd *cobra.Command, args []string) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func storageTOTPGenerateRunEOptsFromFlags(flags *pflag.FlagSet) (force bool, filename, secret string, err error) {
|
// StorageTOTPDeleteRunE is the RunE for the authelia storage user totp delete command.
|
||||||
if force, err = flags.GetBool("force"); err != nil {
|
func (ctx *CmdCtx) StorageTOTPDeleteRunE(cmd *cobra.Command, args []string) (err error) {
|
||||||
return force, filename, secret, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if filename, err = flags.GetString("path"); err != nil {
|
|
||||||
return force, filename, secret, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if secret, err = flags.GetString("secret"); err != nil {
|
|
||||||
return force, filename, secret, err
|
|
||||||
}
|
|
||||||
|
|
||||||
secretLength := base32.StdEncoding.WithPadding(base32.NoPadding).DecodedLen(len(secret))
|
|
||||||
if secret != "" && secretLength < schema.TOTPSecretSizeMinimum {
|
|
||||||
return force, filename, secret, fmt.Errorf("decoded length of the base32 secret must have "+
|
|
||||||
"a length of more than %d but '%s' has a decoded length of %d", schema.TOTPSecretSizeMinimum, secret, secretLength)
|
|
||||||
}
|
|
||||||
|
|
||||||
return force, filename, secret, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func storageTOTPDeleteRunE(cmd *cobra.Command, args []string) (err error) {
|
|
||||||
var (
|
|
||||||
provider storage.Provider
|
|
||||||
ctx = context.Background()
|
|
||||||
)
|
|
||||||
|
|
||||||
user := args[0]
|
user := args[0]
|
||||||
|
|
||||||
provider = getStorageProvider()
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = provider.Close()
|
_ = ctx.providers.StorageProvider.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if _, err = provider.LoadTOTPConfiguration(ctx, user); err != nil {
|
if err = ctx.CheckSchemaVersion(); err != nil {
|
||||||
|
return storageWrapCheckSchemaErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = ctx.providers.StorageProvider.LoadTOTPConfiguration(ctx, user); err != nil {
|
||||||
return fmt.Errorf("can't delete configuration for user '%s': %+v", user, err)
|
return fmt.Errorf("can't delete configuration for user '%s': %+v", user, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = provider.DeleteTOTPConfiguration(ctx, user); err != nil {
|
if err = ctx.providers.StorageProvider.DeleteTOTPConfiguration(ctx, user); err != nil {
|
||||||
return fmt.Errorf("can't delete configuration for user '%s': %+v", user, err)
|
return fmt.Errorf("can't delete configuration for user '%s': %+v", user, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,34 +450,30 @@ func storageTOTPDeleteRunE(cmd *cobra.Command, args []string) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func storageTOTPExportRunE(cmd *cobra.Command, args []string) (err error) {
|
// StorageTOTPExportRunE is the RunE for the authelia storage user totp export command.
|
||||||
|
func (ctx *CmdCtx) StorageTOTPExportRunE(cmd *cobra.Command, args []string) (err error) {
|
||||||
var (
|
var (
|
||||||
provider storage.Provider
|
|
||||||
format, dir string
|
format, dir string
|
||||||
configurations []model.TOTPConfiguration
|
configurations []model.TOTPConfiguration
|
||||||
img image.Image
|
img image.Image
|
||||||
|
|
||||||
ctx = context.Background()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
provider = getStorageProvider()
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = provider.Close()
|
_ = ctx.providers.StorageProvider.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err = checkStorageSchemaUpToDate(ctx, provider); err != nil {
|
if err = ctx.CheckSchemaVersion(); err != nil {
|
||||||
return err
|
return storageWrapCheckSchemaErr(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if format, dir, err = storageTOTPExportGetConfigFromFlags(cmd); err != nil {
|
if format, dir, err = flagsGetTOTPExportOptions(cmd.Flags()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
limit := 10
|
limit := 10
|
||||||
|
|
||||||
for page := 0; true; page++ {
|
for page := 0; true; page++ {
|
||||||
if configurations, err = provider.LoadTOTPConfigurations(ctx, limit, page); err != nil {
|
if configurations, err = ctx.providers.StorageProvider.LoadTOTPConfigurations(ctx, limit, page); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -607,56 +518,18 @@ func storageTOTPExportRunE(cmd *cobra.Command, args []string) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func storageTOTPExportGetConfigFromFlags(cmd *cobra.Command) (format, dir string, err error) {
|
// StorageMigrateHistoryRunE is the RunE for the authelia storage migrate history command.
|
||||||
if format, err = cmd.Flags().GetString(cmdFlagNameFormat); err != nil {
|
func (ctx *CmdCtx) StorageMigrateHistoryRunE(_ *cobra.Command, _ []string) (err error) {
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if dir, err = cmd.Flags().GetString("dir"); err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch format {
|
|
||||||
case storageTOTPExportFormatCSV, storageTOTPExportFormatURI:
|
|
||||||
break
|
|
||||||
case storageTOTPExportFormatPNG:
|
|
||||||
if dir == "" {
|
|
||||||
dir = utils.RandomString(8, utils.CharSetAlphaNumeric, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = os.Stat(dir); !os.IsNotExist(err) {
|
|
||||||
return "", "", errors.New("output directory must not exist")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = os.MkdirAll(dir, 0700); err != nil {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return "", "", errors.New("format must be csv, uri, or png")
|
|
||||||
}
|
|
||||||
|
|
||||||
return format, dir, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func storageMigrateHistoryRunE(_ *cobra.Command, _ []string) (err error) {
|
|
||||||
var (
|
var (
|
||||||
provider storage.Provider
|
|
||||||
version int
|
version int
|
||||||
migrations []model.Migration
|
migrations []model.Migration
|
||||||
|
|
||||||
ctx = context.Background()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
provider = getStorageProvider()
|
|
||||||
if provider == nil {
|
|
||||||
return errNoStorageProvider
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = provider.Close()
|
_ = ctx.providers.StorageProvider.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if version, err = provider.SchemaVersion(ctx); err != nil {
|
if version, err = ctx.providers.StorageProvider.SchemaVersion(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -665,7 +538,7 @@ func storageMigrateHistoryRunE(_ *cobra.Command, _ []string) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if migrations, err = provider.SchemaMigrationHistory(ctx); err != nil {
|
if migrations, err = ctx.providers.StorageProvider.SchemaMigrationHistory(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -682,26 +555,23 @@ func storageMigrateHistoryRunE(_ *cobra.Command, _ []string) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageMigrateListRunE(up bool) func(cmd *cobra.Command, args []string) (err error) {
|
// NewStorageMigrateListRunE creates the RunE for the authelia storage migrate list command.
|
||||||
|
func (ctx *CmdCtx) NewStorageMigrateListRunE(up bool) func(cmd *cobra.Command, args []string) (err error) {
|
||||||
return func(cmd *cobra.Command, args []string) (err error) {
|
return func(cmd *cobra.Command, args []string) (err error) {
|
||||||
var (
|
var (
|
||||||
provider storage.Provider
|
|
||||||
ctx = context.Background()
|
|
||||||
migrations []model.SchemaMigration
|
migrations []model.SchemaMigration
|
||||||
directionStr string
|
directionStr string
|
||||||
)
|
)
|
||||||
|
|
||||||
provider = getStorageProvider()
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = provider.Close()
|
_ = ctx.providers.StorageProvider.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if up {
|
if up {
|
||||||
migrations, err = provider.SchemaMigrationsUp(ctx, 0)
|
migrations, err = ctx.providers.StorageProvider.SchemaMigrationsUp(ctx, 0)
|
||||||
directionStr = "Up"
|
directionStr = "Up"
|
||||||
} else {
|
} else {
|
||||||
migrations, err = provider.SchemaMigrationsDown(ctx, 0)
|
migrations, err = ctx.providers.StorageProvider.SchemaMigrationsDown(ctx, 0)
|
||||||
directionStr = "Down"
|
directionStr = "Down"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -723,19 +593,15 @@ func newStorageMigrateListRunE(up bool) func(cmd *cobra.Command, args []string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStorageMigrationRunE(up bool) func(cmd *cobra.Command, args []string) (err error) {
|
// NewStorageMigrationRunE creates the RunE for the authelia storage migrate command.
|
||||||
|
func (ctx *CmdCtx) NewStorageMigrationRunE(up bool) func(cmd *cobra.Command, args []string) (err error) {
|
||||||
return func(cmd *cobra.Command, args []string) (err error) {
|
return func(cmd *cobra.Command, args []string) (err error) {
|
||||||
var (
|
var (
|
||||||
provider storage.Provider
|
target int
|
||||||
target int
|
|
||||||
|
|
||||||
ctx = context.Background()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
provider = getStorageProvider()
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = provider.Close()
|
_ = ctx.providers.StorageProvider.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if target, err = cmd.Flags().GetInt(cmdFlagNameTarget); err != nil {
|
if target, err = cmd.Flags().GetInt(cmdFlagNameTarget); err != nil {
|
||||||
|
@ -746,68 +612,48 @@ func newStorageMigrationRunE(up bool) func(cmd *cobra.Command, args []string) (e
|
||||||
case up:
|
case up:
|
||||||
switch cmd.Flags().Changed(cmdFlagNameTarget) {
|
switch cmd.Flags().Changed(cmdFlagNameTarget) {
|
||||||
case true:
|
case true:
|
||||||
return provider.SchemaMigrate(ctx, true, target)
|
return ctx.providers.StorageProvider.SchemaMigrate(ctx, true, target)
|
||||||
default:
|
default:
|
||||||
return provider.SchemaMigrate(ctx, true, storage.SchemaLatest)
|
return ctx.providers.StorageProvider.SchemaMigrate(ctx, true, storage.SchemaLatest)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if !cmd.Flags().Changed(cmdFlagNameTarget) {
|
if !cmd.Flags().Changed(cmdFlagNameTarget) {
|
||||||
return errors.New("you must set a target version")
|
return errors.New("you must set a target version")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = storageMigrateDownConfirmDestroy(cmd); err != nil {
|
var confirmed bool
|
||||||
|
|
||||||
|
if confirmed, err = termReadConfirmation(cmd.Flags(), cmdFlagNameDestroyData, "Schema Down Migrations may DESTROY data, type 'DESTROY' and press return to continue: ", "DESTROY"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return provider.SchemaMigrate(ctx, false, target)
|
if !confirmed {
|
||||||
|
return errors.New("cancelling down migration due to user not accepting data destruction")
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.providers.StorageProvider.SchemaMigrate(ctx, false, target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func storageMigrateDownConfirmDestroy(cmd *cobra.Command) (err error) {
|
// StorageSchemaInfoRunE is the RunE for the authelia storage schema info command.
|
||||||
var destroy bool
|
func (ctx *CmdCtx) StorageSchemaInfoRunE(_ *cobra.Command, _ []string) (err error) {
|
||||||
|
|
||||||
if destroy, err = cmd.Flags().GetBool(cmdFlagNameDestroyData); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !destroy {
|
|
||||||
fmt.Printf("Schema Down Migrations may DESTROY data, type 'DESTROY' and press return to continue: ")
|
|
||||||
|
|
||||||
var text string
|
|
||||||
|
|
||||||
_, _ = fmt.Scanln(&text)
|
|
||||||
|
|
||||||
if text != "DESTROY" {
|
|
||||||
return errors.New("cancelling down migration due to user not accepting data destruction")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func storageSchemaInfoRunE(_ *cobra.Command, _ []string) (err error) {
|
|
||||||
var (
|
var (
|
||||||
upgradeStr, tablesStr string
|
upgradeStr, tablesStr string
|
||||||
|
|
||||||
provider storage.Provider
|
|
||||||
tables []string
|
tables []string
|
||||||
version, latest int
|
version, latest int
|
||||||
|
|
||||||
ctx = context.Background()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
provider = getStorageProvider()
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = provider.Close()
|
_ = ctx.providers.StorageProvider.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if version, err = provider.SchemaVersion(ctx); err != nil && err.Error() != "unknown schema state" {
|
if version, err = ctx.providers.StorageProvider.SchemaVersion(ctx); err != nil && err.Error() != "unknown schema state" {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if tables, err = provider.SchemaTables(ctx); err != nil {
|
if tables, err = ctx.providers.StorageProvider.SchemaTables(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -817,7 +663,7 @@ func storageSchemaInfoRunE(_ *cobra.Command, _ []string) (err error) {
|
||||||
tablesStr = strings.Join(tables, ", ")
|
tablesStr = strings.Join(tables, ", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
if latest, err = provider.SchemaLatestVersion(); err != nil {
|
if latest, err = ctx.providers.StorageProvider.SchemaLatestVersion(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -832,7 +678,7 @@ func storageSchemaInfoRunE(_ *cobra.Command, _ []string) (err error) {
|
||||||
result storage.EncryptionValidationResult
|
result storage.EncryptionValidationResult
|
||||||
)
|
)
|
||||||
|
|
||||||
switch result, err = provider.SchemaEncryptionCheckKey(ctx, false); {
|
switch result, err = ctx.providers.StorageProvider.SchemaEncryptionCheckKey(ctx, false); {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
if errors.Is(err, storage.ErrSchemaEncryptionVersionUnsupported) {
|
if errors.Is(err, storage.ErrSchemaEncryptionVersionUnsupported) {
|
||||||
encryption = "unsupported (schema version)"
|
encryption = "unsupported (schema version)"
|
||||||
|
@ -850,30 +696,9 @@ func storageSchemaInfoRunE(_ *cobra.Command, _ []string) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkStorageSchemaUpToDate(ctx context.Context, provider storage.Provider) (err error) {
|
// StorageUserIdentifiersExportRunE is the RunE for the authelia storage user identifiers export command.
|
||||||
var version, latest int
|
func (ctx *CmdCtx) StorageUserIdentifiersExportRunE(cmd *cobra.Command, _ []string) (err error) {
|
||||||
|
|
||||||
if version, err = provider.SchemaVersion(ctx); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if latest, err = provider.SchemaLatestVersion(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if version != latest {
|
|
||||||
return fmt.Errorf("schema is version %d which is outdated please migrate to version %d in order to use this command or use an older binary", version, latest)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func storageUserIdentifiersExport(cmd *cobra.Command, _ []string) (err error) {
|
|
||||||
var (
|
var (
|
||||||
provider storage.Provider
|
|
||||||
|
|
||||||
ctx = context.Background()
|
|
||||||
|
|
||||||
file string
|
file string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -890,7 +715,13 @@ func storageUserIdentifiersExport(cmd *cobra.Command, _ []string) (err error) {
|
||||||
return fmt.Errorf("error occurred opening '%s': %w", file, err)
|
return fmt.Errorf("error occurred opening '%s': %w", file, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
provider = getStorageProvider()
|
defer func() {
|
||||||
|
_ = ctx.providers.StorageProvider.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err = ctx.CheckSchemaVersion(); err != nil {
|
||||||
|
return storageWrapCheckSchemaErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
export model.UserOpaqueIdentifiersExport
|
export model.UserOpaqueIdentifiersExport
|
||||||
|
@ -898,7 +729,7 @@ func storageUserIdentifiersExport(cmd *cobra.Command, _ []string) (err error) {
|
||||||
data []byte
|
data []byte
|
||||||
)
|
)
|
||||||
|
|
||||||
if export.Identifiers, err = provider.LoadUserOpaqueIdentifiers(ctx); err != nil {
|
if export.Identifiers, err = ctx.providers.StorageProvider.LoadUserOpaqueIdentifiers(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -919,12 +750,9 @@ func storageUserIdentifiersExport(cmd *cobra.Command, _ []string) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func storageUserIdentifiersImport(cmd *cobra.Command, _ []string) (err error) {
|
// StorageUserIdentifiersImportRunE is the RunE for the authelia storage user identifiers import command.
|
||||||
|
func (ctx *CmdCtx) StorageUserIdentifiersImportRunE(cmd *cobra.Command, _ []string) (err error) {
|
||||||
var (
|
var (
|
||||||
provider storage.Provider
|
|
||||||
|
|
||||||
ctx = context.Background()
|
|
||||||
|
|
||||||
file string
|
file string
|
||||||
stat os.FileInfo
|
stat os.FileInfo
|
||||||
)
|
)
|
||||||
|
@ -958,10 +786,16 @@ func storageUserIdentifiersImport(cmd *cobra.Command, _ []string) (err error) {
|
||||||
return fmt.Errorf("can't import a file with no data")
|
return fmt.Errorf("can't import a file with no data")
|
||||||
}
|
}
|
||||||
|
|
||||||
provider = getStorageProvider()
|
defer func() {
|
||||||
|
_ = ctx.providers.StorageProvider.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err = ctx.CheckSchemaVersion(); err != nil {
|
||||||
|
return storageWrapCheckSchemaErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
for _, opaqueID := range export.Identifiers {
|
for _, opaqueID := range export.Identifiers {
|
||||||
if err = provider.SaveUserOpaqueIdentifier(ctx, opaqueID); err != nil {
|
if err = ctx.providers.StorageProvider.SaveUserOpaqueIdentifier(ctx, opaqueID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -971,41 +805,26 @@ func storageUserIdentifiersImport(cmd *cobra.Command, _ []string) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func containsIdentifier(identifier model.UserOpaqueIdentifier, identifiers []model.UserOpaqueIdentifier) bool {
|
// StorageUserIdentifiersGenerateRunE is the RunE for the authelia storage user identifiers generate command.
|
||||||
for i := 0; i < len(identifiers); i++ {
|
func (ctx *CmdCtx) StorageUserIdentifiersGenerateRunE(cmd *cobra.Command, _ []string) (err error) {
|
||||||
if identifier.Service == identifiers[i].Service && identifier.SectorID == identifiers[i].SectorID && identifier.Username == identifiers[i].Username {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func storageUserIdentifiersGenerate(cmd *cobra.Command, _ []string) (err error) {
|
|
||||||
var (
|
var (
|
||||||
provider storage.Provider
|
|
||||||
|
|
||||||
ctx = context.Background()
|
|
||||||
|
|
||||||
users, services, sectors []string
|
users, services, sectors []string
|
||||||
)
|
)
|
||||||
|
|
||||||
provider = getStorageProvider()
|
defer func() {
|
||||||
|
_ = ctx.providers.StorageProvider.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
identifiers, err := provider.LoadUserOpaqueIdentifiers(ctx)
|
if err = ctx.CheckSchemaVersion(); err != nil {
|
||||||
|
return storageWrapCheckSchemaErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
identifiers, err := ctx.providers.StorageProvider.LoadUserOpaqueIdentifiers(ctx)
|
||||||
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||||
return fmt.Errorf("can't load the existing identifiers: %w", err)
|
return fmt.Errorf("can't load the existing identifiers: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if users, err = cmd.Flags().GetStringSlice(cmdFlagNameUsers); err != nil {
|
if users, services, sectors, err = flagsGetUserIdentifiersGenerateOptions(cmd.Flags()); err != nil {
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if services, err = cmd.Flags().GetStringSlice(cmdFlagNameServices); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if sectors, err = cmd.Flags().GetStringSlice(cmdFlagNameSectors); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1043,7 +862,7 @@ func storageUserIdentifiersGenerate(cmd *cobra.Command, _ []string) (err error)
|
||||||
return fmt.Errorf("failed to generate a uuid: %w", err)
|
return fmt.Errorf("failed to generate a uuid: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = provider.SaveUserOpaqueIdentifier(ctx, identifier); err != nil {
|
if err = ctx.providers.StorageProvider.SaveUserOpaqueIdentifier(ctx, identifier); err != nil {
|
||||||
return fmt.Errorf("failed to save identifier: %w", err)
|
return fmt.Errorf("failed to save identifier: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1057,12 +876,9 @@ func storageUserIdentifiersGenerate(cmd *cobra.Command, _ []string) (err error)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func storageUserIdentifiersAdd(cmd *cobra.Command, args []string) (err error) {
|
// StorageUserIdentifiersAddRunE is the RunE for the authelia storage user identifiers add command.
|
||||||
|
func (ctx *CmdCtx) StorageUserIdentifiersAddRunE(cmd *cobra.Command, args []string) (err error) {
|
||||||
var (
|
var (
|
||||||
provider storage.Provider
|
|
||||||
|
|
||||||
ctx = context.Background()
|
|
||||||
|
|
||||||
service, sector string
|
service, sector string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1106,9 +922,15 @@ func storageUserIdentifiersAdd(cmd *cobra.Command, args []string) (err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
provider = getStorageProvider()
|
defer func() {
|
||||||
|
_ = ctx.providers.StorageProvider.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
if err = provider.SaveUserOpaqueIdentifier(ctx, opaqueID); err != nil {
|
if err = ctx.CheckSchemaVersion(); err != nil {
|
||||||
|
return storageWrapCheckSchemaErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = ctx.providers.StorageProvider.SaveUserOpaqueIdentifier(ctx, opaqueID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
package commands
|
package commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
@ -24,16 +26,51 @@ func recoverErr(i any) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func configFilterExisting(configs []string) (finalConfigs []string) {
|
func flagsGetUserIdentifiersGenerateOptions(flags *pflag.FlagSet) (users, services, sectors []string, err error) {
|
||||||
var err error
|
if users, err = flags.GetStringSlice(cmdFlagNameUsers); err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
for _, c := range configs {
|
|
||||||
if _, err = os.Stat(c); err == nil || !os.IsNotExist(err) {
|
|
||||||
finalConfigs = append(finalConfigs, c)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return finalConfigs
|
if services, err = flags.GetStringSlice(cmdFlagNameServices); err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if sectors, err = flags.GetStringSlice(cmdFlagNameSectors); err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return users, services, sectors, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func flagsGetTOTPExportOptions(flags *pflag.FlagSet) (format, dir string, err error) {
|
||||||
|
if format, err = flags.GetString(cmdFlagNameFormat); err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if dir, err = flags.GetString("dir"); err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch format {
|
||||||
|
case storageTOTPExportFormatCSV, storageTOTPExportFormatURI:
|
||||||
|
break
|
||||||
|
case storageTOTPExportFormatPNG:
|
||||||
|
if dir == "" {
|
||||||
|
dir = utils.RandomString(8, utils.CharSetAlphaNumeric, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = os.Stat(dir); !os.IsNotExist(err) {
|
||||||
|
return "", "", errors.New("output directory must not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = os.MkdirAll(dir, 0700); err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return "", "", errors.New("format must be csv, uri, or png")
|
||||||
|
}
|
||||||
|
|
||||||
|
return format, dir, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:gocyclo
|
//nolint:gocyclo
|
||||||
|
@ -102,37 +139,92 @@ func flagsGetRandomCharacters(flags *pflag.FlagSet, flagNameLength, flagNameChar
|
||||||
return utils.RandomString(n, charset, true), nil
|
return utils.RandomString(n, charset, true), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func termReadPasswordStrWithPrompt(prompt, flag string) (data string, err error) {
|
func termReadConfirmation(flags *pflag.FlagSet, name, prompt, confirmation string) (confirmed bool, err error) {
|
||||||
var d []byte
|
if confirmed, _ = flags.GetBool(name); confirmed {
|
||||||
|
return confirmed, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
terminal, fd, state, err := getTerminal(prompt)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func(fd int, oldState *term.State) {
|
||||||
|
_ = term.Restore(fd, oldState)
|
||||||
|
}(fd, state)
|
||||||
|
|
||||||
|
var input string
|
||||||
|
|
||||||
|
if input, err = terminal.ReadLine(); err != nil {
|
||||||
|
return false, fmt.Errorf("failed to read from the terminal: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if input != confirmation {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTerminal(prompt string) (terminal *term.Terminal, fd int, state *term.State, err error) {
|
||||||
|
fd = int(syscall.Stdin) //nolint:unconvert,nolintlint
|
||||||
|
|
||||||
|
if !term.IsTerminal(fd) {
|
||||||
|
return nil, -1, nil, ErrStdinIsNotTerminal
|
||||||
|
}
|
||||||
|
|
||||||
|
var width, height int
|
||||||
|
|
||||||
|
if width, height, err = term.GetSize(int(syscall.Stdout)); err != nil { //nolint:unconvert,nolintlint
|
||||||
|
return nil, -1, nil, fmt.Errorf("failed to get terminal size: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
state, err = term.MakeRaw(fd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, -1, nil, fmt.Errorf("failed to get terminal state: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c := struct {
|
||||||
|
io.Reader
|
||||||
|
io.Writer
|
||||||
|
}{
|
||||||
|
os.Stdin,
|
||||||
|
os.Stdout,
|
||||||
|
}
|
||||||
|
|
||||||
|
terminal = term.NewTerminal(c, prompt)
|
||||||
|
|
||||||
|
if err = terminal.SetSize(width, height); err != nil {
|
||||||
|
return nil, -1, nil, fmt.Errorf("failed to set terminal size: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return terminal, fd, state, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func termReadPasswordWithPrompt(prompt, flag string) (password string, err error) {
|
||||||
|
terminal, fd, state, err := getTerminal("")
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, ErrStdinIsNotTerminal) {
|
||||||
|
switch len(flag) {
|
||||||
|
case 0:
|
||||||
|
return "", err
|
||||||
|
case 1:
|
||||||
|
return "", fmt.Errorf("you must either use an interactive terminal or use the -%s flag", flag)
|
||||||
|
default:
|
||||||
|
return "", fmt.Errorf("you must either use an interactive terminal or use the --%s flag", flag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if d, err = termReadPasswordWithPrompt(prompt, flag); err != nil {
|
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return string(d), nil
|
defer func(fd int, oldState *term.State) {
|
||||||
}
|
_ = term.Restore(fd, oldState)
|
||||||
|
}(fd, state)
|
||||||
|
|
||||||
func termReadPasswordWithPrompt(prompt, flag string) (data []byte, err error) {
|
if password, err = terminal.ReadPassword(prompt); err != nil {
|
||||||
fd := int(syscall.Stdin) //nolint:unconvert,nolintlint
|
return "", fmt.Errorf("failed to read the input from the terminal: %w", err)
|
||||||
|
|
||||||
if isTerm := term.IsTerminal(fd); !isTerm {
|
|
||||||
switch len(flag) {
|
|
||||||
case 0:
|
|
||||||
return nil, ErrStdinIsNotTerminal
|
|
||||||
case 1:
|
|
||||||
return nil, fmt.Errorf("you must either use an interactive terminal or use the -%s flag", flag)
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("you must either use an interactive terminal or use the --%s flag", flag)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Print(prompt)
|
return password, nil
|
||||||
|
|
||||||
if data, err = term.ReadPassword(fd); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to read the input from the terminal: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("")
|
|
||||||
|
|
||||||
return data, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,64 +4,51 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/authelia/authelia/v4/internal/configuration"
|
|
||||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func newValidateConfigCmd() (cmd *cobra.Command) {
|
func newValidateConfigCmd(ctx *CmdCtx) (cmd *cobra.Command) {
|
||||||
cmd = &cobra.Command{
|
cmd = &cobra.Command{
|
||||||
Use: "validate-config",
|
Use: "validate-config",
|
||||||
Short: cmdAutheliaValidateConfigShort,
|
Short: cmdAutheliaValidateConfigShort,
|
||||||
Long: cmdAutheliaValidateConfigLong,
|
Long: cmdAutheliaValidateConfigLong,
|
||||||
Example: cmdAutheliaValidateConfigExample,
|
Example: cmdAutheliaValidateConfigExample,
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
RunE: cmdValidateConfigRunE,
|
PreRunE: ctx.ChainRunE(
|
||||||
|
ctx.ConfigLoadRunE,
|
||||||
|
ctx.ConfigValidateKeysRunE,
|
||||||
|
ctx.ConfigValidateRunE,
|
||||||
|
),
|
||||||
|
RunE: ctx.ValidateConfigRunE,
|
||||||
|
|
||||||
DisableAutoGenTag: true,
|
DisableAutoGenTag: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdWithConfigFlags(cmd, false, []string{"configuration.yml"})
|
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdValidateConfigRunE(cmd *cobra.Command, _ []string) (err error) {
|
// ValidateConfigRunE is the RunE for the authelia validate-config command.
|
||||||
var (
|
func (ctx *CmdCtx) ValidateConfigRunE(_ *cobra.Command, _ []string) (err error) {
|
||||||
configs []string
|
|
||||||
val *schema.StructValidator
|
|
||||||
)
|
|
||||||
|
|
||||||
if configs, err = cmd.Flags().GetStringSlice(cmdFlagNameConfig); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
config, val, err = loadConfig(configs, true, true, configuration.NewFileFiltersDefault()...)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error occurred loading configuration: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case val.HasErrors():
|
case ctx.cconfig.validator.HasErrors():
|
||||||
fmt.Println("Configuration parsed and loaded with errors:")
|
fmt.Println("Configuration parsed and loaded with errors:")
|
||||||
fmt.Println("")
|
fmt.Println("")
|
||||||
|
|
||||||
for _, err = range val.Errors() {
|
for _, err = range ctx.cconfig.validator.Errors() {
|
||||||
fmt.Printf("\t - %v\n", err)
|
fmt.Printf("\t - %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("")
|
fmt.Println("")
|
||||||
|
|
||||||
if !val.HasWarnings() {
|
if !ctx.cconfig.validator.HasWarnings() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
fallthrough
|
fallthrough
|
||||||
case val.HasWarnings():
|
case ctx.cconfig.validator.HasWarnings():
|
||||||
fmt.Println("Configuration parsed and loaded with warnings:")
|
fmt.Println("Configuration parsed and loaded with warnings:")
|
||||||
fmt.Println("")
|
fmt.Println("")
|
||||||
|
|
||||||
for _, err = range val.Warnings() {
|
for _, err = range ctx.cconfig.validator.Warnings() {
|
||||||
fmt.Printf("\t - %v\n", err)
|
fmt.Printf("\t - %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,15 +86,13 @@ func loadSources(ko *koanf.Koanf, val *schema.StructValidator, sources ...Source
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, source := range sources {
|
for _, source := range sources {
|
||||||
err := source.Load(val)
|
if err = source.Load(val); err != nil {
|
||||||
if err != nil {
|
|
||||||
val.Push(fmt.Errorf("failed to load configuration from %s source: %+v", source.Name(), err))
|
val.Push(fmt.Errorf("failed to load configuration from %s source: %+v", source.Name(), err))
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err = source.Merge(ko, val)
|
if err = source.Merge(ko, val); err != nil {
|
||||||
if err != nil {
|
|
||||||
val.Push(fmt.Errorf("failed to merge configuration from %s source: %+v", source.Name(), err))
|
val.Push(fmt.Errorf("failed to merge configuration from %s source: %+v", source.Name(), err))
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -224,7 +224,9 @@ func NewDefaultSourcesFiltered(files []string, filters []FileFilter, prefix, del
|
||||||
|
|
||||||
// NewDefaultSourcesWithDefaults returns a slice of Source configured to load from specified YAML files with additional sources.
|
// NewDefaultSourcesWithDefaults returns a slice of Source configured to load from specified YAML files with additional sources.
|
||||||
func NewDefaultSourcesWithDefaults(files []string, filters []FileFilter, prefix, delimiter string, defaults Source, additionalSources ...Source) (sources []Source) {
|
func NewDefaultSourcesWithDefaults(files []string, filters []FileFilter, prefix, delimiter string, defaults Source, additionalSources ...Source) (sources []Source) {
|
||||||
sources = []Source{defaults}
|
if defaults != nil {
|
||||||
|
sources = []Source{defaults}
|
||||||
|
}
|
||||||
|
|
||||||
if len(filters) == 0 {
|
if len(filters) == 0 {
|
||||||
sources = append(sources, NewDefaultSources(files, prefix, delimiter, additionalSources...)...)
|
sources = append(sources, NewDefaultSources(files, prefix, delimiter, additionalSources...)...)
|
||||||
|
|
|
@ -21,28 +21,28 @@ type YAMLFileSource struct {
|
||||||
filters []FileFilter
|
filters []FileFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnvironmentSource is a configuration Source which loads values from the environment.
|
// EnvironmentSource is a configuration configuration.Source which loads values from the environment.
|
||||||
type EnvironmentSource struct {
|
type EnvironmentSource struct {
|
||||||
koanf *koanf.Koanf
|
koanf *koanf.Koanf
|
||||||
prefix string
|
prefix string
|
||||||
delimiter string
|
delimiter string
|
||||||
}
|
}
|
||||||
|
|
||||||
// SecretsSource loads environment variables that have a value pointing to a file.
|
// SecretsSource is a configuration.Source which loads environment variables that have a value pointing to a file.
|
||||||
type SecretsSource struct {
|
type SecretsSource struct {
|
||||||
koanf *koanf.Koanf
|
koanf *koanf.Koanf
|
||||||
prefix string
|
prefix string
|
||||||
delimiter string
|
delimiter string
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommandLineSource loads configuration from the command line flags.
|
// CommandLineSource is a configuration.Source which loads configuration from the command line flags.
|
||||||
type CommandLineSource struct {
|
type CommandLineSource struct {
|
||||||
koanf *koanf.Koanf
|
koanf *koanf.Koanf
|
||||||
flags *pflag.FlagSet
|
flags *pflag.FlagSet
|
||||||
callback func(flag *pflag.Flag) (string, any)
|
callback func(flag *pflag.Flag) (string, any)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MapSource loads configuration from the command line flags.
|
// MapSource is a configuration.Source which loads configuration from the command line flags.
|
||||||
type MapSource struct {
|
type MapSource struct {
|
||||||
m map[string]any
|
m map[string]any
|
||||||
koanf *koanf.Koanf
|
koanf *koanf.Koanf
|
||||||
|
|
|
@ -84,18 +84,6 @@ func (s *CLISuite) TestShouldFailValidateConfig() {
|
||||||
s.Assert().Contains(output, "failed to load configuration from yaml file(/config/invalid.yml) source: open /config/invalid.yml: no such file or directory")
|
s.Assert().Contains(output, "failed to load configuration from yaml file(/config/invalid.yml) source: open /config/invalid.yml: no such file or directory")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CLISuite) TestShouldHashPasswordArgon2idLegacy() {
|
|
||||||
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "hash-password", "test", "-m", "32"})
|
|
||||||
s.Assert().NoError(err)
|
|
||||||
s.Assert().Contains(output, "Digest: $argon2id$v=19$m=32768,t=3,p=4$")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *CLISuite) TestShouldHashPasswordSHA512Legacy() {
|
|
||||||
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "hash-password", "test", "-z"})
|
|
||||||
s.Assert().NoError(err)
|
|
||||||
s.Assert().Contains(output, "Digest: $6$rounds=50000")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *CLISuite) TestShouldHashPasswordArgon2() {
|
func (s *CLISuite) TestShouldHashPasswordArgon2() {
|
||||||
var (
|
var (
|
||||||
output string
|
output string
|
||||||
|
@ -782,18 +770,6 @@ func (s *CLISuite) TestShouldNotGenerateRSAWithBadCAFileContent() {
|
||||||
s.Assert().Contains(output, "Error: could not parse certificate from file '/tmp/ca.public.bad.crt': failed to parse PEM block containing the key\n")
|
s.Assert().Contains(output, "Error: could not parse certificate from file '/tmp/ca.public.bad.crt': failed to parse PEM block containing the key\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CLISuite) TestStorageShouldShowErrWithoutConfig() {
|
|
||||||
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "storage", "schema-info"})
|
|
||||||
s.Assert().EqualError(err, "exit status 1")
|
|
||||||
|
|
||||||
s.Assert().Contains(output, "Error: storage: configuration for a 'local', 'mysql' or 'postgres' database must be provided, storage: option 'encryption_key' is required\n")
|
|
||||||
|
|
||||||
output, err = s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "storage", "migrate", "history"})
|
|
||||||
s.Assert().EqualError(err, "exit status 1")
|
|
||||||
|
|
||||||
s.Assert().Contains(output, "Error: storage: configuration for a 'local', 'mysql' or 'postgres' database must be provided, storage: option 'encryption_key' is required\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *CLISuite) TestStorage00ShouldShowCorrectPreInitInformation() {
|
func (s *CLISuite) TestStorage00ShouldShowCorrectPreInitInformation() {
|
||||||
_ = os.Remove("/tmp/db.sqlite3")
|
_ = os.Remove("/tmp/db.sqlite3")
|
||||||
|
|
||||||
|
@ -804,8 +780,7 @@ func (s *CLISuite) TestStorage00ShouldShowCorrectPreInitInformation() {
|
||||||
|
|
||||||
s.Assert().Regexp(pattern, output)
|
s.Assert().Regexp(pattern, output)
|
||||||
|
|
||||||
patternOutdated := regexp.MustCompile(`Error: schema is version \d+ which is outdated please migrate to version \d+ in order to use this command or use an older binary`)
|
patternOutdated := regexp.MustCompile(`Error: command requires the use of a up to date schema version: storage schema outdated: version \d+ is outdated please migrate to version \d+ in order to use this command or use an older binary`)
|
||||||
|
|
||||||
output, err = s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "storage", "user", "totp", "export", "--config=/config/configuration.storage.yml"})
|
output, err = s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "storage", "user", "totp", "export", "--config=/config/configuration.storage.yml"})
|
||||||
s.Assert().EqualError(err, "exit status 1")
|
s.Assert().EqualError(err, "exit status 1")
|
||||||
s.Assert().Regexp(patternOutdated, output)
|
s.Assert().Regexp(patternOutdated, output)
|
||||||
|
@ -815,8 +790,8 @@ func (s *CLISuite) TestStorage00ShouldShowCorrectPreInitInformation() {
|
||||||
s.Assert().Regexp(patternOutdated, output)
|
s.Assert().Regexp(patternOutdated, output)
|
||||||
|
|
||||||
output, err = s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "storage", "encryption", "check", "--config=/config/configuration.storage.yml"})
|
output, err = s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "storage", "encryption", "check", "--config=/config/configuration.storage.yml"})
|
||||||
s.Assert().NoError(err)
|
s.Assert().EqualError(err, "exit status 1")
|
||||||
s.Assert().Contains(output, "Storage Encryption Key Validation: FAILURE\n\n\tCause: The schema version doesn't support encryption.\n")
|
s.Assert().Contains(output, "Error: command requires the use of a up to date schema version: storage schema outdated: version 0 is outdated please migrate to version 7 in order to use this command or use an older binary\n")
|
||||||
|
|
||||||
output, err = s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "storage", "migrate", "down", "--target=0", "--destroy-data", "--config=/config/configuration.storage.yml"})
|
output, err = s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "storage", "migrate", "down", "--target=0", "--destroy-data", "--config=/config/configuration.storage.yml"})
|
||||||
s.Assert().EqualError(err, "exit status 1")
|
s.Assert().EqualError(err, "exit status 1")
|
||||||
|
|
Loading…
Reference in New Issue