Merge remote-tracking branch 'origin/master' into feat-settings-ui
# Conflicts: # api/openapi.ymlpull/4806/head
|
@ -3,7 +3,7 @@
|
|||
set +u
|
||||
|
||||
declare -A BUILDS=(["linux"]="amd64 arm arm64 amd64-musl arm-musl arm64-musl" ["freebsd"]="amd64")
|
||||
DOCKER_IMAGE=authelia/authelia
|
||||
DOCKER_IMAGE=authelia:dist
|
||||
|
||||
if [[ "${BUILDKITE_LABEL}" == ":hammer_and_wrench: Unit Test" ]]; then
|
||||
if [[ ! "${BUILDKITE_BRANCH}" =~ ^renovate/ ]]; then
|
||||
|
|
|
@ -17,7 +17,7 @@ if [[ "${BUILDKITE_LABEL}" == ":service_dog: Linting" ]]; then
|
|||
fi
|
||||
|
||||
if [[ "${BUILDKITE_LABEL}" == ":docker: Build Image [coverage]" ]]; then
|
||||
cp -R /buildkite/.pnpm-store .
|
||||
cp -R /buildkite/.local .
|
||||
fi
|
||||
|
||||
if [[ "${BUILDKITE_STEP_KEY}" =~ build-deb-package-(arm64|armhf) && "${BUILDKITE_AGENT_NAME}" =~ sauron* ]]; then
|
||||
|
@ -30,10 +30,13 @@ fi
|
|||
|
||||
if [[ "${BUILDKITE_LABEL}" =~ ":selenium:" ]]; then
|
||||
DEFAULT_ARCH=coverage
|
||||
echo "--- :docker: Extract, load and tag build container"
|
||||
echo "--- :docker: Extract and load build container"
|
||||
buildkite-agent artifact download "authelia-image-${DEFAULT_ARCH}*" .
|
||||
if [[ "${SUITE}" == "Kubernetes" ]]; then
|
||||
zstd -d authelia-image-coverage.tar.zst --stdout > ./internal/suites/example/kube/authelia-image-${DEFAULT_ARCH}.tar
|
||||
else
|
||||
zstdcat "authelia-image-${DEFAULT_ARCH}.tar.zst" | docker load
|
||||
docker tag authelia/authelia authelia:dist
|
||||
fi
|
||||
|
||||
if [[ "${BUILD_DUO}" == "true" ]] && [[ "${SUITE}" == "DuoPush" ]]; then
|
||||
CONTAINER="integration-duo"
|
||||
|
|
|
@ -7,7 +7,11 @@ trim_trailing_whitespace = true
|
|||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
[{.buildkite/hooks/**,*.sh,*.yml,*.yaml}]
|
||||
[*.{sh,yml,yaml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[.buildkite/hooks/**]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ body:
|
|||
description: What version(s) of Authelia can you reproduce this bug on?
|
||||
multiple: true
|
||||
options:
|
||||
- v4.37.3
|
||||
- v4.37.2
|
||||
- v4.37.1
|
||||
- v4.37.0
|
||||
|
|
|
@ -1,50 +1,27 @@
|
|||
# IDE user configuration
|
||||
.idea/
|
||||
.vscode/
|
||||
|
||||
# NodeJs modules
|
||||
# Nodejs modules
|
||||
.pnpm-store/
|
||||
node_modules/
|
||||
|
||||
# npm debug logs
|
||||
npm-debug.log*
|
||||
|
||||
# Coverage reports
|
||||
coverage/
|
||||
.nyc_output/
|
||||
coverage.txt
|
||||
|
||||
.vscode/
|
||||
|
||||
*.swp
|
||||
*~
|
||||
|
||||
# Directory used by example
|
||||
/notifications/
|
||||
|
||||
# VSCode user configuration
|
||||
.vscode/
|
||||
|
||||
# Generated by TypeScript compiler
|
||||
dist/
|
||||
|
||||
.nyc_output/
|
||||
|
||||
*.tgz
|
||||
|
||||
# Specific files
|
||||
/configuration.yml
|
||||
/config.yml
|
||||
/config.test.yml
|
||||
|
||||
internal/suites/example/ldap/private.ldif
|
||||
|
||||
Configuration.schema.json
|
||||
|
||||
.suite
|
||||
.kube
|
||||
.idea
|
||||
authelia-image-dev.tar
|
||||
|
||||
.authelia-interrupt
|
||||
|
||||
qemu-*-static
|
||||
|
||||
public_html.gen.go
|
||||
|
||||
authelia
|
||||
/authelia
|
||||
__debug_bin
|
||||
|
|
14
.renovaterc
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:base",
|
||||
":semanticCommitTypeAll(build)",
|
||||
|
@ -14,12 +15,15 @@
|
|||
"workarounds:all"
|
||||
],
|
||||
"enabledManagers": [
|
||||
"bundler",
|
||||
"docker-compose",
|
||||
"dockerfile",
|
||||
"gomod",
|
||||
"kubernetes",
|
||||
"npm"
|
||||
],
|
||||
"kubernetes": {
|
||||
"fileMatch": ["kube/.+\\.yml$"],
|
||||
},
|
||||
"labels": [
|
||||
"dependencies"
|
||||
],
|
||||
|
@ -47,6 +51,14 @@
|
|||
"go"
|
||||
]
|
||||
},
|
||||
{
|
||||
"datasources": [
|
||||
"kubernetes"
|
||||
],
|
||||
"addLabels": [
|
||||
"kubernetes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"datasources": [
|
||||
"npm"
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
---
|
||||
extends: default
|
||||
|
||||
locale: en_US.UTF-8
|
||||
|
||||
yaml-files:
|
||||
- '*.yaml'
|
||||
- '*.yml'
|
||||
- '.yamllint'
|
||||
|
||||
ignore: |
|
||||
docs/pnpm-lock.yaml
|
||||
internal/configuration/test_resources/config_bad_quoting.yml
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Anybody willing to contribute to the project either with code, documentation, security reviews or whatever, are very
|
||||
welcome to create or review pull requests and take part in discussions in any of our public
|
||||
[chat rooms](./README.md#contact-options).
|
||||
[chat rooms](README.md#contact-options).
|
||||
|
||||
It's also possible to contribute financially in order to support the community.
|
||||
|
||||
|
@ -42,4 +42,4 @@ Read more about this in the [GitHub docs, Re-requesting a review](https://docs.g
|
|||
Sometimes the codebase can be a challenge to navigate, especially for a first-time contributor. We don't want you
|
||||
spending an hour trying to work out something that would take us only a minute to explain.
|
||||
|
||||
If you'd like some help getting started we have several [contact options](./README.md#contact-options) available.
|
||||
If you'd like some help getting started we have several [contact options](README.md#contact-options) available.
|
||||
|
|
|
@ -5,7 +5,7 @@ FROM node:19-alpine AS builder-frontend
|
|||
|
||||
WORKDIR /node/src/app
|
||||
|
||||
COPY .pnpm-store /root/.pnpm-store
|
||||
COPY .local /root/.local
|
||||
COPY web ./
|
||||
|
||||
# Install the dependencies and build
|
||||
|
@ -15,7 +15,7 @@ RUN yarn global add pnpm && \
|
|||
# =======================================
|
||||
# ===== Build image for the backend =====
|
||||
# =======================================
|
||||
FROM golang:1.19.3-alpine AS builder-backend
|
||||
FROM golang:1.19.4-alpine AS builder-backend
|
||||
|
||||
WORKDIR /go/src/app
|
||||
|
||||
|
|
|
@ -20,4 +20,4 @@ bootstrap.sh
|
|||
|
||||
# Overrides
|
||||
!.healthcheck.env
|
||||
!.pnpm-store
|
||||
!.local
|
||||
|
|
|
@ -13,7 +13,7 @@ RUN yarn install --frozen-lockfile && yarn build
|
|||
# =======================================
|
||||
# ===== Build image for the backend =====
|
||||
# =======================================
|
||||
FROM golang:1.19.3-alpine AS builder-backend
|
||||
FROM golang:1.19.4-alpine AS builder-backend
|
||||
|
||||
WORKDIR /go/src/app
|
||||
|
||||
|
|
|
@ -184,7 +184,7 @@ Internet (your reverse proxies are) however, it's still the control plane for yo
|
|||
|
||||
## Contribute
|
||||
|
||||
If you want to contribute to Authelia, please read our [contribution guidelines](./CONTRIBUTING.md).
|
||||
If you want to contribute to Authelia, please read our [contribution guidelines](CONTRIBUTING.md).
|
||||
|
||||
Authelia exists thanks to all the people who contribute so don't be shy, come chat with us on either [Matrix](#matrix)
|
||||
or [Discord](#discord) and start contributing too.
|
||||
|
@ -379,7 +379,7 @@ Companies contributing to Authelia via Open Collective will have a special menti
|
|||
## License
|
||||
|
||||
**Authelia** is **licensed** under the **[Apache 2.0]** license. The terms of the license are detailed in
|
||||
[LICENSE](./LICENSE).
|
||||
[LICENSE](LICENSE).
|
||||
|
||||
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fauthelia%2Fauthelia.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fauthelia%2Fauthelia?ref=badge_large)
|
||||
|
||||
|
|
|
@ -19,14 +19,14 @@ For more information about [security](https://www.authelia.com/information/secur
|
|||
|
||||
## Contact Options
|
||||
|
||||
Several [contact options](./README.md#contact-options) exist, it's important to make sure you contact the maintainers
|
||||
privately which is described in each available contact method. The methods include our [security email](./README.md#security),
|
||||
[Matrix](./README.md#matrix), and [Discord](./README.md#discord).
|
||||
Several [contact options](README.md#contact-options) exist, it's important to make sure you contact the maintainers
|
||||
privately which is described in each available contact method. The methods include our [security email](README.md#security),
|
||||
[Matrix](README.md#matrix), and [Discord](README.md#discord).
|
||||
|
||||
## Credit
|
||||
|
||||
Users who report bugs will optionally be credited for the discovery. Both in the [security advisory] and in our
|
||||
[all contributors](./README.md#contribute) configuration/documentation.
|
||||
[all contributors](README.md#contribute) configuration/documentation.
|
||||
|
||||
## Process
|
||||
|
||||
|
|
2158
api/openapi.yml
|
@ -87,12 +87,19 @@ var hostEntries = []HostEntry{
|
|||
{Domain: "mail.example.com", IP: "192.168.240.100"},
|
||||
{Domain: "duo.example.com", IP: "192.168.240.100"},
|
||||
|
||||
// For Traefik suite.
|
||||
{Domain: "traefik.example.com", IP: "192.168.240.100"},
|
||||
|
||||
// For HAProxy suite.
|
||||
{Domain: "haproxy.example.com", IP: "192.168.240.100"},
|
||||
|
||||
// Kubernetes dashboard.
|
||||
{Domain: "kubernetes.example.com", IP: "192.168.240.100"},
|
||||
|
||||
// OIDC tester app.
|
||||
{Domain: "oidc.example.com", IP: "192.168.240.100"},
|
||||
{Domain: "oidc-public.example.com", IP: "192.168.240.100"},
|
||||
|
||||
// For Traefik suite.
|
||||
{Domain: "traefik.example.com", IP: "192.168.240.100"},
|
||||
|
||||
// For testing network ACLs.
|
||||
{Domain: "proxy-client1.example.com", IP: "192.168.240.201"},
|
||||
{Domain: "proxy-client2.example.com", IP: "192.168.240.202"},
|
||||
|
@ -107,12 +114,6 @@ var hostEntries = []HostEntry{
|
|||
{Domain: "redis-sentinel-0.example.com", IP: "192.168.240.120"},
|
||||
{Domain: "redis-sentinel-1.example.com", IP: "192.168.240.121"},
|
||||
{Domain: "redis-sentinel-2.example.com", IP: "192.168.240.122"},
|
||||
|
||||
// Kubernetes dashboard.
|
||||
{Domain: "kubernetes.example.com", IP: "192.168.240.110"},
|
||||
// OIDC tester app.
|
||||
{Domain: "oidc.example.com", IP: "192.168.240.100"},
|
||||
{Domain: "oidc-public.example.com", IP: "192.168.240.100"},
|
||||
}
|
||||
|
||||
func runCommand(cmd string, args ...string) {
|
||||
|
@ -151,8 +152,8 @@ func createTemporaryDirectory() {
|
|||
func createPNPMDirectory() {
|
||||
home := os.Getenv("HOME")
|
||||
if home != "" {
|
||||
bootstrapPrintln("Creating ", home+"/.pnpm-store")
|
||||
err := os.MkdirAll(home+"/.pnpm-store", 0755)
|
||||
bootstrapPrintln("Creating ", home+"/.local/share/pnpm/store")
|
||||
err := os.MkdirAll(home+"/.local/share/pnpm/store", 0755)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -161,7 +162,7 @@ func createPNPMDirectory() {
|
|||
}
|
||||
|
||||
func pnpmInstall() {
|
||||
bootstrapPrintln("Installing web dependences ")
|
||||
bootstrapPrintln("Installing web dependencies ")
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
|
|
|
@ -167,14 +167,14 @@ section [here](../prologue/common.md#tls-configuration).
|
|||
|
||||
Sets the base distinguished name container for all LDAP queries. If your LDAP domain is example.com this is usually
|
||||
`DC=example,DC=com`, however you can fine tune this to be more specific for example to only include objects inside the
|
||||
authelia OU: `OU=authelia,DC=example,DC=com`. This is prefixed with the [additional_users_dn](#additional_users_dn) for
|
||||
user searches and [additional_groups_dn](#additional_groups_dn) for groups searches.
|
||||
authelia OU: `OU=authelia,DC=example,DC=com`. This is prefixed with the [additional_users_dn](#additionalusersdn) for
|
||||
user searches and [additional_groups_dn](#additionalgroupsdn) for groups searches.
|
||||
|
||||
### additional_users_dn
|
||||
|
||||
{{< confkey type="string" required="no" >}}
|
||||
|
||||
Additional LDAP path to append to the [base_dn](#base_dn) when searching for users. Useful if you want to restrict
|
||||
Additional LDAP path to append to the [base_dn](#basedn) when searching for users. Useful if you want to restrict
|
||||
exactly which OU to get users from for either security or performance reasons. For example setting it to
|
||||
`OU=users,OU=people` with a base_dn set to `DC=example,DC=com` will mean user searches will occur in
|
||||
`OU=users,OU=people,DC=example,DC=com`.
|
||||
|
@ -184,28 +184,31 @@ exactly which OU to get users from for either security or performance reasons. F
|
|||
{{< confkey type="string" required="situational" >}}
|
||||
|
||||
*__Note:__ This option is technically required however the [implementation](#implementation) option can implicitly set a
|
||||
default negating this requirement. Refer to the [filter defaults](#filter-defaults) for more information.*
|
||||
default negating this requirement. Refer to the [filter defaults](../../reference/guides/ldap.md#filter-defaults) for
|
||||
more information.*
|
||||
|
||||
The LDAP filter to narrow down which users are valid. This is important to set correctly as to exclude disabled users.
|
||||
The default value is dependent on the [implementation](#implementation), refer to the
|
||||
[attribute defaults](#attribute-defaults) for more information.
|
||||
[attribute defaults](../../reference/guides/ldap.md#attribute-defaults) for more information.
|
||||
|
||||
### username_attribute
|
||||
|
||||
{{< confkey type="string" required="situational" >}}
|
||||
|
||||
*__Note:__ This option is technically required however the [implementation](#implementation) option can implicitly set a
|
||||
default negating this requirement. Refer to the [attribute defaults](#attribute-defaults) for more information.*
|
||||
default negating this requirement. Refer to the [attribute defaults](../../reference/guides/ldap.md#attribute-defaults)
|
||||
for more information.*
|
||||
|
||||
The LDAP attribute that maps to the username in *Authelia*. This must contain the `{username_attribute}`
|
||||
[placeholder](#users-filter-replacements).
|
||||
[placeholder](../../reference/guides/ldap.md#users-filter-replacements).
|
||||
|
||||
### mail_attribute
|
||||
|
||||
{{< confkey type="string" required="situational" >}}
|
||||
|
||||
*__Note:__ This option is technically required however the [implementation](#implementation) option can implicitly set a
|
||||
default negating this requirement. Refer to the [attribute defaults](#attribute-defaults) for more information.*
|
||||
default negating this requirement. Refer to the [attribute defaults](../../reference/guides/ldap.md#attribute-defaults)
|
||||
for more information.*
|
||||
|
||||
The attribute to retrieve which contains the users email addresses. This is important for the device registration and
|
||||
password reset processes. The user must have an email address in order for Authelia to perform identity verification
|
||||
|
@ -294,7 +297,7 @@ characters and the user password is changed to this value.
|
|||
|
||||
## Refresh Interval
|
||||
|
||||
It's recommended you either use the default [refresh interval](./introduction.md#refresh_interval) or configure this to
|
||||
It's recommended you either use the default [refresh interval](introduction.md#refreshinterval) or configure this to
|
||||
a value low enough to refresh the user groups and status (deleted, disabled, etc) to adequately secure your environment.
|
||||
|
||||
## Important notes
|
||||
|
@ -311,6 +314,6 @@ for your users.
|
|||
|
||||
- [LDAP Reference Guide](../../reference/guides/ldap.md)
|
||||
|
||||
[username attribute]: #username_attribute
|
||||
[username attribute]: #usernameattribute
|
||||
[TechNet wiki]: https://social.technet.microsoft.com/wiki/contents/articles/5392.active-directory-ldap-syntax-filters.aspx
|
||||
[RFC2307]: https://www.rfc-editor.org/rfc/rfc2307.html
|
||||
|
|
|
@ -157,8 +157,8 @@ The HMAC secret used to sign the [JWT]'s. The provided string is hashed to a SHA
|
|||
purpose of meeting the required format.
|
||||
|
||||
It's __strongly recommended__ this is a
|
||||
[Random Alphanumeric String](../../reference/guides/generating-secure-values.md#generating-a-random-alphanumeric-string) with 64 or more
|
||||
characters.
|
||||
[Random Alphanumeric String](../../reference/guides/generating-secure-values.md#generating-a-random-alphanumeric-string)
|
||||
with 64 or more characters.
|
||||
|
||||
### issuer_certificate_chain
|
||||
|
||||
|
@ -173,7 +173,7 @@ as per [RFC7517].
|
|||
[x5c]: https://www.rfc-editor.org/rfc/rfc7517#section-4.7
|
||||
[x5t]: https://www.rfc-editor.org/rfc/rfc7517#section-4.8
|
||||
|
||||
The first certificate in the chain must have the public key for the [issuer_private_key](#issuer_private_key), each
|
||||
The first certificate in the chain must have the public key for the [issuer_private_key](#issuerprivatekey), each
|
||||
certificate in the chain must be valid for the current date, and each certificate in the chain should be signed by the
|
||||
certificate immediately following it if present.
|
||||
|
||||
|
@ -185,14 +185,15 @@ certificate immediately following it if present.
|
|||
especially for containerized deployments.*
|
||||
|
||||
The private key used to sign/encrypt the [OpenID Connect] issued [JWT]'s. The key must be generated by the administrator
|
||||
and can be done by following the [Generating an RSA Keypair](../../reference/guides/generating-secure-values.md#generating-an-rsa-keypair) guide.
|
||||
and can be done by following the
|
||||
[Generating an RSA Keypair](../../reference/guides/generating-secure-values.md#generating-an-rsa-keypair) guide.
|
||||
|
||||
The private key *__MUST__*:
|
||||
* Be a PEM block encoded in the DER base64 format ([RFC4648]).
|
||||
* Be an RSA Key.
|
||||
* Have a key size of at least 2048 bits.
|
||||
|
||||
If the [issuer_certificate_chain](#issuer_certificate_chain) is provided the private key must include matching public
|
||||
If the [issuer_certificate_chain](#issuercertificatechain) is provided the private key must include matching public
|
||||
key data for the first certificate in the chain.
|
||||
|
||||
### access_token_lifespan
|
||||
|
@ -302,7 +303,7 @@ you must configure this option manually if you want http endpoints to be permitt
|
|||
Origins must only have the scheme, hostname and port, they may not have a trailing slash or path.
|
||||
|
||||
In addition to an Origin URI, you may specify the wildcard origin in the allowed_origins. It MUST be specified by itself
|
||||
and the [allowed_origins_from_client_redirect_uris](#allowed_origins_from_client_redirect_uris) MUST NOT be enabled. The
|
||||
and the [allowed_origins_from_client_redirect_uris](#allowedoriginsfromclientredirecturis) MUST NOT be enabled. The
|
||||
wildcard origin is denoted as `*`. Examples:
|
||||
|
||||
```yaml
|
||||
|
@ -422,7 +423,7 @@ Configures the consent mode. The following table describes the different modes:
|
|||
| implicit | Automatically assumes consent for every authorization, never asking the user if they wish to give consent. *__Note:__* this option is not technically part of the specification. |
|
||||
| pre-configured | Allows the end-user to remember their consent for the [pre_configured_consent_duration]. |
|
||||
|
||||
[pre_configured_consent_duration]: #pre_configured_consent_duration
|
||||
[pre_configured_consent_duration]: #preconfiguredconsentduration
|
||||
|
||||
#### pre_configured_consent_duration
|
||||
|
||||
|
@ -439,7 +440,7 @@ The period of time dictates how long a users choice to remember the pre-configur
|
|||
Pre-configured consents are only valid if the subject, client id are exactly the same and the requested scopes/audience
|
||||
match exactly with the granted scopes/audience.
|
||||
|
||||
[consent_mode]: #consent_mode
|
||||
[consent_mode]: #consentmode
|
||||
|
||||
#### audience
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ likely result in an error or even worse misconfiguration.
|
|||
### Kubernetes
|
||||
|
||||
Please see the
|
||||
[Kubernetes Integration: Enable Service Links](../../integration/kubernetes/introduction/index.md#enable-service-links)
|
||||
[Kubernetes Integration: Enable Service Links](../../integration/kubernetes/introduction.md#enable-service-links)
|
||||
documentation for specific requirements for using *Authelia* with Kubernetes.
|
||||
|
||||
## Mapping
|
||||
|
|
|
@ -55,15 +55,15 @@ other configuration using the environment but instead of loading a file the valu
|
|||
{{% table-config-keys secrets="true" %}}
|
||||
|
||||
[server.tls.key]: ../miscellaneous/server.md#key
|
||||
[jwt_secret]: ../miscellaneous/introduction.md#jwt_secret
|
||||
[duo_api.integration_key]: ../second-factor/duo.md#integration_key
|
||||
[duo_api.secret_key]: ../second-factor/duo.md#secret_key
|
||||
[jwt_secret]: ../miscellaneous/introduction.md#jwtsecret
|
||||
[duo_api.integration_key]: ../second-factor/duo.md#integrationkey
|
||||
[duo_api.secret_key]: ../second-factor/duo.md#secretkey
|
||||
[session.secret]: ../session/introduction.md#secret
|
||||
[session.redis.password]: ../session/redis.md#password
|
||||
[session.redis.tls.certificate_chain]: ../session/redis.md#tls
|
||||
[session.redis.tls.private_key]: ../session/redis.md#tls
|
||||
[session.redis.high_availability.sentinel_password]: ../session/redis.md#sentinel_password
|
||||
[storage.encryption_key]: ../storage/introduction.md#encryption_key
|
||||
[session.redis.high_availability.sentinel_password]: ../session/redis.md#sentinelpassword
|
||||
[storage.encryption_key]: ../storage/introduction.md#encryptionkey
|
||||
[storage.mysql.password]: ../storage/mysql.md#password
|
||||
[storage.mysql.tls.certificate_chain]: ../storage/mysql.md#tls
|
||||
[storage.mysql.tls.private_key]: ../storage/mysql.md#tls
|
||||
|
@ -77,9 +77,9 @@ other configuration using the environment but instead of loading a file the valu
|
|||
[authentication_backend.ldap.password]: ../first-factor/ldap.md#password
|
||||
[authentication_backend.ldap.tls.certificate_chain]: ../first-factor/ldap.md#tls
|
||||
[authentication_backend.ldap.tls.private_key]: ../first-factor/ldap.md#tls
|
||||
[identity_providers.oidc.issuer_certificate_chain]: ../identity-providers/open-id-connect.md#issuer_certificate_chain
|
||||
[identity_providers.oidc.issuer_private_key]: ../identity-providers/open-id-connect.md#issuer_private_key
|
||||
[identity_providers.oidc.hmac_secret]: ../identity-providers/open-id-connect.md#hmac_secret
|
||||
[identity_providers.oidc.issuer_certificate_chain]: ../identity-providers/open-id-connect.md#issuercertificatechain
|
||||
[identity_providers.oidc.issuer_private_key]: ../identity-providers/open-id-connect.md#issuerprivatekey
|
||||
[identity_providers.oidc.hmac_secret]: ../identity-providers/open-id-connect.md#hmacsecret
|
||||
|
||||
|
||||
## Secrets in configuration file
|
||||
|
|
|
@ -73,7 +73,7 @@ default_2fa_method: totp
|
|||
especially for containerized deployments.*
|
||||
|
||||
Defines the secret used to craft JWT tokens leveraged by the identity verification process. This can a random string.
|
||||
It's strongly recommended this is a [Random Alphanumeric String](../../reference/guides/generating-secure-values.md/#generating-a-random-alphanumeric-string) with
|
||||
It's strongly recommended this is a [Random Alphanumeric String](../../reference/guides/generating-secure-values.md#generating-a-random-alphanumeric-string) with
|
||||
64 or more characters.
|
||||
|
||||
### theme
|
||||
|
|
|
@ -68,4 +68,4 @@ Setting this to true will disable the startup check entirely.
|
|||
|
||||
Setting this to true will allow Authelia to start and just log an error instead of exiting. The default is that if
|
||||
Authelia can contact the NTP server successfully, and the time reported by the server is greater than what is configured
|
||||
in [max_desync](#max_desync) that Authelia fails to start and logs a fatal error.
|
||||
in [max_desync](#maxdesync) that Authelia fails to start and logs a fatal error.
|
||||
|
|
|
@ -123,7 +123,7 @@ require an IP address for the host of the backend service but want to verify a s
|
|||
|
||||
The key `skip_verify` completely negates validating the certificate of the backend service. This is not recommended,
|
||||
instead you should tweak the `server_name` option, and the global option
|
||||
[certificates directory](../miscellaneous/introduction.md#certificates_directory).
|
||||
[certificates directory](../miscellaneous/introduction.md#certificatesdirectory).
|
||||
|
||||
### minimum_version
|
||||
|
||||
|
@ -147,7 +147,7 @@ this value. At the time of this writing `SSL3.0` will always produce errors.
|
|||
|
||||
{{< confkey type="string" required="no" >}}
|
||||
|
||||
The certificate chain/bundle to be used with the [private_key](#private_key) to perform mutual TLS authentication with
|
||||
The certificate chain/bundle to be used with the [private_key](#privatekey) to perform mutual TLS authentication with
|
||||
the server.
|
||||
|
||||
The value must be one or more certificates encoded in the DER base64 ([RFC4648]) encoded PEM format.
|
||||
|
@ -159,7 +159,7 @@ The value must be one or more certificates encoded in the DER base64 ([RFC4648])
|
|||
*__Important Note:__ This can also be defined using a [secret](../methods/secrets.md) which is __strongly recommended__
|
||||
especially for containerized deployments.*
|
||||
|
||||
The private key to be used with the [certificate_chain](#certificate_chain) for mutual TLS authentication.
|
||||
The private key to be used with the [certificate_chain](#certificatechain) for mutual TLS authentication.
|
||||
|
||||
The value must be one private key encoded in the DER base64 ([RFC4648]) encoded PEM format.
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ environment variable or other environment variables set. This also applies to ot
|
|||
|
||||
*__Please Note:__ if you're using Authelia with Kubernetes and are not using the provided
|
||||
[helm chart](https://charts.authelia.com) you will be required to
|
||||
[configure the enableServiceLinks](../../integration/kubernetes/introduction/index.md#enable-service-links) option.*
|
||||
[configure the enableServiceLinks](../../integration/kubernetes/introduction.md#enable-service-links) option.*
|
||||
|
||||
### 4.25.0
|
||||
|
||||
|
@ -99,7 +99,7 @@ The following changes occurred in 4.7.0:
|
|||
| logs_level | log_level |
|
||||
| logs_file | log_file |
|
||||
|
||||
*__Please Note:__ The new keys also changed in [4.30.0](#4.30.0) so you will need to update them to the new values if you
|
||||
are using [4.30.0](#4.30.0) or newer instead of the new keys listed here.*
|
||||
*__Please Note:__ The new keys also changed in [4.30.0](#4300) so you will need to update them to the new values if you
|
||||
are using [4.30.0](#4300) or newer instead of the new keys listed here.*
|
||||
|
||||
[YAML]: https://yaml.org/
|
||||
|
|
|
@ -61,10 +61,12 @@ by Authelia from others.
|
|||
|
||||
*__Important Note:__ Many TOTP applications do not support this option. It is strongly advised you find out which
|
||||
applications your users use and test them before changing this option. It is insufficient to test that the application
|
||||
can add the key, it must also authenticate with Authelia as some applications silently ignore these options. Bitwarden
|
||||
can add the key, it must also authenticate with Authelia as some applications silently ignore these options. [Bitwarden]
|
||||
is the only one that has been tested at this time. If you'd like to contribute to documenting support for this option
|
||||
please see [Issue 2650](https://github.com/authelia/authelia/issues/2650).*
|
||||
|
||||
[Bitwarden]: https://bitwarden.com/
|
||||
|
||||
The algorithm used for the TOTP key.
|
||||
|
||||
Possible Values (case-insensitive):
|
||||
|
@ -82,7 +84,7 @@ information.
|
|||
|
||||
*__Important Note:__ Some TOTP applications do not support this option. It is strongly advised you find out which
|
||||
applications your users use and test them before changing this option. It is insufficient to test that the application
|
||||
can add the key, it must also authenticate with Authelia as some applications silently ignore these options. Bitwarden
|
||||
can add the key, it must also authenticate with Authelia as some applications silently ignore these options. [Bitwarden]
|
||||
is the only one that has been tested at this time. If you'd like to contribute to documenting support for this option
|
||||
please see [Issue 2650](https://github.com/authelia/authelia/issues/2650).*
|
||||
|
||||
|
@ -137,7 +139,7 @@ validations.
|
|||
This means if the configuration options are changed, users will not need to regenerate their keys. This functionality
|
||||
takes effect from 4.33.0 onwards, previously the effect was the keys would just fail to validate. If you'd like to force
|
||||
users to register a new device, you can delete the old device for a particular user by using the
|
||||
`authelia storage totp delete <username>` command regardless of if you change the settings or not.
|
||||
`authelia storage user totp delete <username>` command regardless of if you change the settings or not.
|
||||
|
||||
## Input Validation
|
||||
|
||||
|
@ -160,7 +162,7 @@ check the clients.
|
|||
|
||||
## Encryption
|
||||
|
||||
The TOTP secret is [encrypted](../storage/introduction.md#encryption_key) in the database in version 4.33.0 and above.
|
||||
The TOTP secret is [encrypted](../storage/introduction.md#encryptionkey) in the database in version 4.33.0 and above.
|
||||
This is so a user having access to only the database cannot easily compromise your two-factor authentication method.
|
||||
|
||||
This may be inconvenient for some users who wish to export TOTP keys from Authelia to other services. As such there is
|
||||
|
@ -170,19 +172,19 @@ at least a minimal configuration that has the storage backend connection details
|
|||
Export in [Key URI Format](https://github.com/google/google-authenticator/wiki/Key-Uri-Format):
|
||||
|
||||
```bash
|
||||
authelia storage totp export --format uri
|
||||
authelia storage user totp export --format uri
|
||||
```
|
||||
|
||||
Export as CSV:
|
||||
|
||||
```bash
|
||||
authelia storage totp export --format csv
|
||||
authelia storage user totp export --format csv
|
||||
```
|
||||
|
||||
Help:
|
||||
|
||||
```bash
|
||||
authelia storage totp export --help
|
||||
authelia storage user totp export --help
|
||||
```
|
||||
|
||||
[RFC4226]: https://www.rfc-editor.org/rfc/rfc4226.html
|
||||
|
|
|
@ -198,7 +198,7 @@ When used in conjunction with [domain] the rule will match when either the [doma
|
|||
|
||||
In addition to standard regex patterns this criteria can match some [Named Regex Groups].
|
||||
|
||||
[domain_regex]: #domain_regex
|
||||
[domain_regex]: #domainregex
|
||||
|
||||
##### Examples
|
||||
|
||||
|
@ -339,7 +339,7 @@ access_control:
|
|||
{{< confkey type="list(string)" required="no" >}}
|
||||
|
||||
This criteria is a list of values which can be an IP Address, network address range in CIDR notation, or an alias from
|
||||
the [global](#networks-global) section. It matches against the first address in the `X-Forwarded-For` header, or if there
|
||||
the [global](#networks--global-) section. It matches against the first address in the `X-Forwarded-For` header, or if there
|
||||
are none it will fall back to the IP address of the packet TCP source IP address. For this reason it's important for you
|
||||
to configure the proxy server correctly in order to accurately match requests with this criteria. *__Note:__ you may
|
||||
combine CIDR networks with the alias rules as you please.*
|
||||
|
@ -360,7 +360,7 @@ for administrators to tune the security to their specific needs if desired.
|
|||
|
||||
##### Examples
|
||||
|
||||
*Require [two_factor](#two_factor) for all clients other than internal clients and `112.134.145.167`. The first two
|
||||
*Require [two_factor](#twofactor) for all clients other than internal clients and `112.134.145.167`. The first two
|
||||
rules in this list are effectively the same rule just expressed in different ways.*
|
||||
|
||||
```yaml
|
||||
|
@ -485,7 +485,7 @@ access_control:
|
|||
## Policies
|
||||
|
||||
The policy of the first matching rule in the configured list decides the policy applied to the request, if no rule
|
||||
matches the request the [default_policy](#default_policy) is applied.
|
||||
matches the request the [default_policy](#defaultpolicy) is applied.
|
||||
|
||||
[policies]: #policies
|
||||
|
||||
|
@ -510,14 +510,14 @@ about the subject is [one_factor]. See [Rule Matching Concept 2] for more inform
|
|||
This policy requires the user at minimum complete 1FA successfully (username and password). This means if they have
|
||||
performed 2FA then they will be allowed to access the resource.
|
||||
|
||||
[one_factor]: #one_factor
|
||||
[one_factor]: #onefactor
|
||||
|
||||
### two_factor
|
||||
|
||||
This policy requires the user to complete 2FA successfully. This is currently the highest level of authentication
|
||||
policy available.
|
||||
|
||||
[two_factor]: #two_factor
|
||||
[two_factor]: #twofactor
|
||||
|
||||
## Rule Matching
|
||||
|
||||
|
@ -554,7 +554,7 @@ a match for that request.
|
|||
policy: two_factor
|
||||
```
|
||||
|
||||
[Rule Matching Concept 1]: #rule-matching-concept-1-sequential-order
|
||||
[Rule Matching Concept 1]: #rule-matching-concept-1--sequential-order
|
||||
|
||||
### Rule Matching Concept 2: Subject Criteria Requires Authentication
|
||||
|
||||
|
@ -569,7 +569,7 @@ for authentication if no prior rules match the request per [Rule Matching Concep
|
|||
identical rules, and one of them has a subject based reliant criteria, and the other one is a [bypass] rule then the
|
||||
[bypass] rule should generally come first.
|
||||
|
||||
[Rule Matching Concept 2]: #rule-matching-concept-2-subject-criteria-requires-authentication
|
||||
[Rule Matching Concept 2]: #rule-matching-concept-2--subject-criteria-requires-authentication
|
||||
|
||||
## Named Regex Groups
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ There are currently two providers for session storage (three if you count Redis
|
|||
|
||||
* Memory (default, stateful, no additional configuration)
|
||||
* [Redis](redis.md) (stateless).
|
||||
* [Redis Sentinel](redis.md#high_availability) (stateless, highly available).
|
||||
* [Redis Sentinel](redis.md#highavailability) (stateless, highly available).
|
||||
|
||||
### Kubernetes or High Availability
|
||||
|
||||
|
@ -99,7 +99,7 @@ characters.
|
|||
the [common options](../prologue/common.md#duration-notation-format) documentation for information on this format.*
|
||||
|
||||
The period of time before the cookie expires and the session is destroyed. This is overriden by
|
||||
[remember_me_duration](#remember_me_duration) when the remember me box is checked.
|
||||
[remember_me_duration](#remembermeduration) when the remember me box is checked.
|
||||
|
||||
### inactivity
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ storage:
|
|||
username: authelia
|
||||
password: mypassword
|
||||
tls:
|
||||
server_name: psotgres.example.com
|
||||
server_name: postgres.example.com
|
||||
skip_verify: false
|
||||
minimum_version: TLS1.2
|
||||
maximum_version: TLS1.3
|
||||
|
|
|
@ -35,7 +35,7 @@ storage:
|
|||
|
||||
### encryption_key
|
||||
|
||||
See the [encryption_key docs](introduction.md#encryption_key).
|
||||
See the [encryption_key docs](introduction.md#encryptionkey).
|
||||
|
||||
### path
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ toc: true
|
|||
---
|
||||
|
||||
*Authelia* allows collecting telemetry for the purpose of monitoring it. At the present time we only allow collecting
|
||||
[metrics](./metrics.md). These [metrics](./metrics.md) are stored in memory and must be scraped manually by the
|
||||
[metrics](metrics.md). These [metrics](metrics.md) are stored in memory and must be scraped manually by the
|
||||
administrator.
|
||||
|
||||
No metrics or telemetry are reported from an *Authelia* binary to any location the administrator doesn't explicitly
|
||||
|
|
|
@ -24,7 +24,7 @@ was not prompted by any bug bounty program as we do not have one, but we hope to
|
|||
|
||||
Potential usage for the money, ranked in order of priority:
|
||||
|
||||
1. Put Authelia through a comprehensive [Security Audit](../../../information/security.md#help-wanted).
|
||||
1. Put Authelia through a comprehensive [Security Audit](../../policies/security.md#help-wanted).
|
||||
1. Audit of Code Security via Analysis.
|
||||
2. Audit via Penetration Testing.
|
||||
2. Bug Bounty Program.
|
||||
|
@ -38,11 +38,11 @@ Please visit [Open Collective] in order to financially contribute to Authelia.
|
|||
Authelia is sponsored by several companies via indirect means. These companies deserve a special mention since their
|
||||
contributions are very important to us but not easily visible.
|
||||
|
||||
If you feel you have a product or service that Authelia could benefit from please feel free to [contact](../../../information/contact.md) us.
|
||||
If you feel you have a product or service that Authelia could benefit from please feel free to [contact](../../information/contact.md) us.
|
||||
|
||||
We are currently directly looking for someone to sponsor:
|
||||
|
||||
* [Security Audit](../../../information/security.md#help-wanted)
|
||||
* [Security Audit](../../policies/security.md#help-wanted)
|
||||
|
||||
### Balto
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ If the language you wish to translate is not on [Crowdin] then you have a few op
|
|||
## Overrides
|
||||
|
||||
Users can override translations easily locally using the
|
||||
[assets](../../configuration/miscellaneous/server.md#asset_path) directory. This is useful if you wish to perform a
|
||||
[assets](../../configuration/miscellaneous/server.md#assetpath) directory. This is useful if you wish to perform a
|
||||
translation and see if it looks correct in the browser.
|
||||
|
||||
[Crowdin]: https://translate.authelia.com
|
||||
|
|
|
@ -11,8 +11,8 @@ aliases:
|
|||
|
||||
## Security
|
||||
|
||||
If you believe you have identified a security related bug with Authelia please visit the [security policy](security.md)
|
||||
documentation.
|
||||
If you believe you have identified a security related bug with Authelia please visit the
|
||||
[security policy](../policies/security.md) documentation.
|
||||
|
||||
## GitHub
|
||||
|
||||
|
|
|
@ -42,10 +42,10 @@ It expects the following:
|
|||
|
||||
* The file `data/authelia/config/configuration.yml` is present and the configuration file.
|
||||
* The directory `data/authelia/secrets/` exists and contain the relevant [secret](../../configuration/methods/secrets.md) files:
|
||||
* A file named `JWT_SECRET` for the [jwt_secret](../../configuration/miscellaneous/introduction.md#jwt_secret)
|
||||
* A file named `JWT_SECRET` for the [jwt_secret](../../configuration/miscellaneous/introduction.md#jwtsecret)
|
||||
* A file named `SESSION_SECRET` for the [session secret](../../configuration/session/introduction.md#secret)
|
||||
* A file named `STORAGE_PASSWORD` for the [PostgreSQL password secret](../../configuration/storage/postgres.md#password)
|
||||
* A file named `STORAGE_ENCRYPTION_KEY` for the [storage encryption_key secret](../../configuration/storage/introduction.md#encryption_key)
|
||||
* A file named `STORAGE_ENCRYPTION_KEY` for the [storage encryption_key secret](../../configuration/storage/introduction.md#encryptionkey)
|
||||
* You're using PostgreSQL.
|
||||
* You have an external network named `net` which is in bridge mode.
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ toc: true
|
|||
There are three main methods to deploy *Authelia*.
|
||||
|
||||
1. [Docker](docker.md)
|
||||
2. [Kubernetes](../kubernetes/introduction/index.md)
|
||||
2. [Kubernetes](../kubernetes/introduction.md)
|
||||
3. [Bare-Metal](bare-metal.md)
|
||||
|
||||
## Get Started
|
||||
|
|
|
@ -15,4 +15,4 @@ search:
|
|||
index: false
|
||||
---
|
||||
|
||||
Please see the dedicated [Kubernetes Documentation](../kubernetes/introduction/index.md).
|
||||
Please see the dedicated [Kubernetes Documentation](../kubernetes/introduction.md).
|
||||
|
|
|
@ -30,7 +30,7 @@ Users are welcome to reach out directly by using any of our various [contact opt
|
|||
## Get Started
|
||||
|
||||
It's __*strongly recommended*__ that users setting up *Authelia* for the first time take a look at our
|
||||
[Get Started](../../prologue/get-started) guide. This takes you through various steps which are essential to
|
||||
[Get Started](../prologue/get-started.md) guide. This takes you through various steps which are essential to
|
||||
bootstrapping *Authelia*.
|
||||
|
||||
## Important Notes
|
||||
|
@ -70,7 +70,7 @@ spec:
|
|||
If using file-based authentication, the argon2id provider will by default use 1GB of RAM for password generation. This
|
||||
means you should allow for at least this amount in your deployment/daemonset spec and have this much available on your
|
||||
node, alternatively you can
|
||||
[tweak the providers settings](../../../configuration/first-factor/file.md#memory). Otherwise,
|
||||
[tweak the providers settings](../../configuration/first-factor/file.md#memory). Otherwise,
|
||||
your Authelia may OOM during login. See [here](https://github.com/authelia/authelia/issues/1234#issuecomment-663910799)
|
||||
for more info.
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ metadata:
|
|||
name: app
|
||||
namespace: default
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.entryPoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.middlewares: default-forwardauth-authelia@kubernetescrd
|
||||
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||
spec:
|
||||
|
|
|
@ -111,7 +111,7 @@ Below is a list of the potential values we place in the [Claim] and their meanin
|
|||
## User Information Signing Algorithm
|
||||
|
||||
The following table describes the response from the [UserInfo] endpoint depending on the
|
||||
[userinfo_signing_algorithm](../../configuration/identity-providers/open-id-connect.md#userinfo_signing_algorithm).
|
||||
[userinfo_signing_algorithm](../../configuration/identity-providers/open-id-connect.md#userinfosigningalgorithm).
|
||||
|
||||
| Signing Algorithm | Encoding | Content Type |
|
||||
|:-----------------:|:------------:|:-----------------------------------:|
|
||||
|
|
|
@ -38,9 +38,9 @@ used as a basis for configuration.
|
|||
|
||||
The important sections to consider in initial configuration are as follows:
|
||||
|
||||
1. [jwt_secret](../../configuration/miscellaneous/introduction.md#jwt_secret) which is used to sign identity
|
||||
1. [jwt_secret](../../configuration/miscellaneous/introduction.md#jwtsecret) which is used to sign identity
|
||||
verification emails
|
||||
2. [default_redirection_url](../../configuration/miscellaneous/introduction.md#default_redirection_url) which is the
|
||||
2. [default_redirection_url](../../configuration/miscellaneous/introduction.md#defaultredirectionurl) which is the
|
||||
default URL users will be redirected to when visiting *Authelia* directly
|
||||
3. [authentication_backend](../../configuration/first-factor/introduction.md) which you must pick between
|
||||
[LDAP](../../configuration/first-factor/ldap.md) and a [YAML File](../../configuration/first-factor/file.md) and is
|
||||
|
@ -76,8 +76,8 @@ There are several methods of deploying *Authelia* and we recommend reading the
|
|||
The default method of utilizing *Authelia* is via the [Proxy Integrations](../proxies/introduction.md). It's
|
||||
recommended that you read the relevant [Proxy Integration Documentation](../proxies/introduction.md).
|
||||
|
||||
*__Important Note:__ When your [Deployment](#deployment) is on [Kubernetes](../kubernetes/introduction/index.md) we
|
||||
recommend viewing the dedicated [Kubernetes Documentation](../kubernetes/introduction/index.md) prior to viewing the
|
||||
*__Important Note:__ When your [Deployment](#deployment) is on [Kubernetes](../kubernetes/introduction.md) we
|
||||
recommend viewing the dedicated [Kubernetes Documentation](../kubernetes/introduction.md) prior to viewing the
|
||||
[Proxy Integration Documentation](../proxies/introduction.md).*
|
||||
|
||||
## Moving to Production
|
||||
|
|
|
@ -24,12 +24,12 @@ throughout this documentation and in the [See Also](#see-also) section.*
|
|||
## Get Started
|
||||
|
||||
It's __*strongly recommended*__ that users setting up *Authelia* for the first time take a look at our
|
||||
[Get Started](../prologue/get-started.md) guide. This takes you through various steps which are essential to
|
||||
[Get Started](../../prologue/get-started.md) guide. This takes you through various steps which are essential to
|
||||
bootstrapping *Authelia*.
|
||||
|
||||
## Requirements
|
||||
|
||||
[NGINX Proxy Manager] supports the required [NGINX](nginx.md#requirements) requirements for __Authelia__ out-of-the-box.
|
||||
[NGINX Proxy Manager] supports the required [NGINX](../nginx.md#requirements) requirements for __Authelia__ out-of-the-box.
|
||||
|
||||
## Trusted Proxies
|
||||
|
||||
|
@ -37,7 +37,7 @@ bootstrapping *Authelia*.
|
|||
Especially if you have never read it before.*
|
||||
|
||||
To configure trusted proxies for [NGINX Proxy Manager] see the [NGINX] section on
|
||||
[Trusted Proxies](nginx.md#trusted-proxies). Adapting this to [NGINX Proxy Manager] is beyond the scope of
|
||||
[Trusted Proxies](../nginx.md#trusted-proxies). Adapting this to [NGINX Proxy Manager] is beyond the scope of
|
||||
this documentation.
|
||||
|
||||
## Docker Compose
|
||||
|
@ -137,9 +137,9 @@ either most likely require an adjustment, or may require an adjustment if you're
|
|||
### Snippets
|
||||
|
||||
The examples assume you've mounted a volume containing the relevant
|
||||
[NGINX Snippets](nginx.md#supporting-configuration-snippets) from the [NGINX Integration Guide](nginx.md). The suggested
|
||||
snippets are the `proxy.conf`, `authelia-location.conf`, and `authelia-authrequest.conf`. It may be fine to substitute
|
||||
the standard variant of the `proxy.conf` for the headers only variant but this is untested.
|
||||
[NGINX Snippets](../nginx.md#supporting-configuration-snippets) from the [NGINX Integration Guide](../nginx.md). The
|
||||
suggested snippets are the `proxy.conf`, `authelia-location.conf`, and `authelia-authrequest.conf`. It may be fine to
|
||||
substitute the standard variant of the `proxy.conf` for the headers only variant but this is untested.
|
||||
|
||||
These snippets make the addition of a protected proxy host substantially easier.
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ required modules including the `http_set_misc` module.
|
|||
It also includes the [nginx-proxy-confs](https://github.com/linuxserver/docker-mods/tree/nginx-proxy-confs) mod where
|
||||
they have several configuration examples in the `/config/nginx/proxy-confs` directory. This can be omitted if desired.
|
||||
|
||||
If you're looking for a more complete solution [linuxserver.io] also have an nginx container called [SWAG](./swag.md)
|
||||
If you're looking for a more complete solution [linuxserver.io] also have an nginx container called [SWAG](swag.md)
|
||||
which includes ACME and various other useful utilities.
|
||||
|
||||
{{< details "docker-compose.yaml" >}}
|
||||
|
|
|
@ -76,7 +76,7 @@ For example the nginx ngx_http_auth_request_module does not seem to support this
|
|||
|
||||
Authelia detects the upstream request method using the X-Forwarded-Method header. Some proxies set this out of the box,
|
||||
some require you to configure this manually. At the present time all proxies that have
|
||||
[Standard Support](#standard-support) do support this.
|
||||
[Standard Support](#standard) do support this.
|
||||
|
||||
## Specific proxy notes
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ required modules including the `http_set_misc` module.
|
|||
It also includes the [nginx-proxy-confs](https://github.com/linuxserver/docker-mods/tree/nginx-proxy-confs) mod where
|
||||
they have several configuration examples in the `/config/nginx/proxy-confs` directory. This can be omitted if desired.
|
||||
|
||||
If you're looking for a more complete solution [linuxserver.io] also have an nginx container called [SWAG](./swag.md)
|
||||
If you're looking for a more complete solution [linuxserver.io] also have an nginx container called [SWAG](swag.md)
|
||||
which includes ACME and various other useful utilities.
|
||||
|
||||
{{< details "docker-compose.yaml" >}}
|
||||
|
|
|
@ -25,8 +25,8 @@ unreliable and simple usernames and passwords are not sufficient for security.
|
|||
|
||||
__Authelia__ enables primarily two-factor authentication. These methods offered come in two forms:
|
||||
|
||||
* 1FA or first-factor authentication which is handled by a username and password. This falls into the *something you know*
|
||||
categorization.
|
||||
* 1FA or first-factor authentication which is handled by a username and password. This falls into the
|
||||
*something you know* categorization.
|
||||
* 2FA or second-factor authentication which is handled by several methods including one-time passwords, authentication
|
||||
keys, etc. This falls into the *something you have* categorization.
|
||||
|
||||
|
|
|
@ -28,14 +28,7 @@ the user must match the name of the user in Authelia, or must have an alias that
|
|||
|
||||
Then, in Duo interface, click on *Applications* and *Protect an Application*. Select the option *Partner Auth API*. This
|
||||
will generate an integration key, a secret key and a hostname. You can set the name of the application to __Authelia__
|
||||
and then you must add the generated information to Authelia [configuration](../../deployment/index.md) as shown below:
|
||||
|
||||
```yaml
|
||||
duo_api:
|
||||
hostname: api-123456789.example.com
|
||||
integration_key: ABCDEF
|
||||
secret_key: 1234567890abcdefghifjkl
|
||||
```
|
||||
and then you must add the generated information to Authelia [configuration](../../../configuration/second-factor/duo.md).
|
||||
|
||||
See the [configuration documentation](../../../configuration/second-factor/duo.md) for more details.
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: "OpenID Connect 1.0"
|
||||
description: "OpenID Connect 1.0 is a authorization identity framework supported by Authelia."
|
||||
date: 2022-06-15T17:51:47+10:00
|
||||
date: 2022-11-27T16:07:08+11:00
|
||||
draft: false
|
||||
images: []
|
||||
menu:
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
title: "Trusted Headers SSO"
|
||||
description: "Trusted Headers SSO is a simple header authorization framework supported by Authelia."
|
||||
lead: "Trusted Headers is a simple header authorization framework supported by Authelia."
|
||||
date: 2022-06-15T17:51:47+10:00
|
||||
date: 2022-11-27T16:07:08+11:00
|
||||
draft: false
|
||||
images: []
|
||||
menu:
|
||||
|
|
|
@ -53,6 +53,6 @@ Authelia only works for websites served over HTTPS because the session cookie ca
|
|||
connections. Please note that it has been decided that we won't support websites served over HTTP in order to avoid any
|
||||
risk due to misconfiguration (see [#590](https://github.com/authelia/authelia/issues/590)).
|
||||
|
||||
If a self-signed certificate is required, the
|
||||
[Generating an RSA Self-Signed Certificate](../../../reference/guides/generating-secure-values.md#generating-an-rsa-self-signed-certificate)
|
||||
guide should be followed.
|
||||
If a self-signed certificate is required, the [Generating an RSA Self-Signed Certificate] guide should be followed.
|
||||
|
||||
[Generating an RSA Self-Signed Certificate]: ../../../reference/guides/generating-secure-values.md#generating-an-rsa-self-signed-certificate
|
||||
|
|
|
@ -73,7 +73,7 @@ attacker obtains the file, each password has to be brute forced individually.
|
|||
|
||||
Lastly Authelia's implementation of Argon2id is highly tunable. You can tune the key length, salt used, iterations
|
||||
(time), parallelism, and memory usage. To read more about this please read how to
|
||||
[configure](../configuration/authentication/file.md) file authentication.
|
||||
[configure](../../configuration/first-factor/file.md) file authentication.
|
||||
|
||||
## User profile and group membership always kept up-to-date (LDAP authentication provider)
|
||||
|
||||
|
@ -163,33 +163,34 @@ preferable:
|
|||
|
||||
### Configuration Option: certificates_directory
|
||||
|
||||
You can [configure a directory](../../configuration/miscellaneous/introduction.md#certificates_directory) of
|
||||
certificates for Authelia
|
||||
to trust. These certificates can either be CA's or individual public certificates that should be trusted. These
|
||||
are added in addition to the environments PKI trusted certificates if available. This is useful for trusting a
|
||||
certificate that is self-signed without drastically reducing security. This is the most recommended workaround to not
|
||||
having a valid PKI trusted certificate as it gives you complete control over which ones are trusted without disabling
|
||||
critically needed validation of the identity of the target service.
|
||||
You can configure a [certificates_directory] option which contains certificates for Authelia to trust. These certificates
|
||||
can either be CA's or individual public certificates that should be trusted. These are added in addition to the
|
||||
environments PKI trusted certificates if available. This is useful for trusting a certificate that is self-signed without
|
||||
drastically reducing security. This is the most recommended workaround to not having a valid PKI trusted certificate as
|
||||
it gives you complete control over which ones are trusted without disabling critically needed validation of the identity
|
||||
of the target service.
|
||||
|
||||
Read more in the [documentation](../../configuration/miscellaneous/introduction.md#certificates_directory) for this
|
||||
option.
|
||||
Read more in the [certificates_directory] documentation for this option.
|
||||
|
||||
[certificates_directory]: ../../configuration/miscellaneous/introduction.md#certificatesdirectory
|
||||
[certificates directory]: #configuration-option--certificatesdirectory
|
||||
|
||||
### Configuration Option: tls.skip_verify
|
||||
|
||||
The [tls.skip_verify](../../configuration/notifications/smtp.md#tls) option allows you to skip verifying the certificate
|
||||
entirely which is why [certificates_directory](#configuration-option-certificates_directory) is preferred over this.
|
||||
This will effectively mean you cannot be sure the certificate is valid which means an attacker via DNS poisoning or MITM
|
||||
attacks could intercept emails from Authelia compromising a user's security without their knowledge.
|
||||
entirely which is why [certificates directory] is preferred over this. This will effectively mean you cannot be sure the
|
||||
certificate is valid which means an attacker via DNS poisoning or MITM attacks could intercept emails from Authelia
|
||||
compromising a user's security without their knowledge.
|
||||
|
||||
### Configuration Option: disable_require_tls
|
||||
|
||||
Authelia by default ensures that the SMTP server connection is secured via TLS prior to sending sensitive information.
|
||||
|
||||
The [disable_require_tls](../../configuration/notifications/smtp.md#disable_require_tls) option disables this
|
||||
The [disable_require_tls](../../configuration/notifications/smtp.md#disablerequiretls) option disables this
|
||||
requirement which means the emails may be sent in cleartext. This is the least secure option as it effectively removes
|
||||
the validation of SMTP certificates and makes using an encrypted connection with TLS optional.
|
||||
|
||||
This means not only can the vulnerabilities of the [skip_verify](#configuration-option-tlsskip_verify) option be
|
||||
This means not only can the vulnerabilities of the [skip_verify](#configuration-option--tlsskipverify) option be
|
||||
exploited, but any router or switch along the route of the email which receives the packets could be used to silently
|
||||
exploit the cleartext nature of the connection to manipulate the email in transit.
|
||||
|
||||
|
@ -237,7 +238,7 @@ would not even be able to create a TCP connection. This measure is recommended i
|
|||
configured some kind of ACLs specifically allowing the communication between proxies and Authelia instances like in a
|
||||
service mesh or some kind of network overlay.
|
||||
|
||||
To configure mutual TLS, please refer to [this document](../../configuration/miscellaneous/server.md#client_certificates)
|
||||
To configure mutual TLS, please refer to [this document](../../configuration/miscellaneous/server.md#clientcertificates)
|
||||
|
||||
## Additional security
|
||||
|
||||
|
@ -255,7 +256,7 @@ database. The value of this option should be long and as random as possible. See
|
|||
[documentation](../../configuration/session/introduction.md#secret) for this option.
|
||||
|
||||
The validity period of session is highly configurable. For example in a highly security conscious domain you could
|
||||
set the session [remember_me_duration](../../configuration/session/introduction.md#remember_me_duration) to 0 to disable this
|
||||
set the session [remember_me_duration](../../configuration/session/introduction.md#remembermeduration) to 0 to disable this
|
||||
feature, and set the [expiration](../../configuration/session/introduction.md#expiration) to 2 hours and the
|
||||
[inactivity](../../configuration/session/introduction.md#inactivity) of 10 minutes. Configuring the session security in this
|
||||
manner would mean if the cookie age was more than 2 hours or if the user was inactive for more than 10 minutes the
|
||||
|
|
|
@ -37,11 +37,11 @@ This is the preferred method of reporting.
|
|||
|
||||
### Chat
|
||||
|
||||
If you wish to chat directly instead of sending an email please use one of the [chat options](../information/contact.md#chat) but it
|
||||
is vital that when you do that you only do so privately with one of the maintainers. In order to start a private
|
||||
discussion you should ask to have a private discussion with a team member without mentioning the reason why you wish to
|
||||
have a private discussion so that provided the bug is confirmed we can coordinate the release of fixes and information
|
||||
responsibly.
|
||||
If you wish to chat directly instead of sending an email please use one of the
|
||||
[chat options](../information/contact.md#chat) but it is vital that when you do that you only do so privately with one
|
||||
of the maintainers. In order to start a private discussion you should ask to have a private discussion with a team
|
||||
member without mentioning the reason why you wish to have a private discussion so that provided the bug is confirmed we
|
||||
can coordinate the release of fixes and information responsibly.
|
||||
|
||||
## Credit
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ The logo is just the Authelia circle logo without any text.
|
|||
|
||||
#### Logo Files
|
||||
|
||||
[PSD](https://www.authelia.com/images/branding/logo.psd) | [SVG](https://www.authelia.com/images/branding/logo.svg) | [PNG](https://www.authelia.com/images/branding/logo.png)
|
||||
[PSD](https://www.authelia.com/images/branding/logo.psd) | [AI](https://www.authelia.com/images/branding/logo.ai) | [SVG](https://www.authelia.com/images/branding/logo.svg) | [PNG](https://www.authelia.com/images/branding/logo.png)
|
||||
|
||||
#### Logo Example
|
||||
|
||||
|
@ -60,7 +60,7 @@ The logo is the same as the standard logo without padding.
|
|||
|
||||
#### Logo (Cropped) Files
|
||||
|
||||
[PSD](https://www.authelia.com/images/branding/logo-cropped.psd) | [SVG](https://www.authelia.com/images/branding/logo-cropped.svg) | [PNG](https://www.authelia.com/images/branding/logo-cropped.png)
|
||||
[PSD](https://www.authelia.com/images/branding/logo-cropped.psd) | [AI](https://www.authelia.com/images/branding/logo-cropped.ai) | [SVG](https://www.authelia.com/images/branding/logo-cropped.svg) | [PNG](https://www.authelia.com/images/branding/logo-cropped.png)
|
||||
|
||||
#### Logo (Cropped) Example
|
||||
|
||||
|
@ -72,7 +72,7 @@ The title is the Authelia circle logo with the `authelia` branded text.
|
|||
|
||||
#### Title Files
|
||||
|
||||
[PSD](https://www.authelia.com/images/branding/title.psd) | [SVG](https://www.authelia.com/images/branding/title.svg) | [PNG](https://www.authelia.com/images/branding/title.png)
|
||||
[PSD](https://www.authelia.com/images/branding/title.psd) | [AI](https://www.authelia.com/images/branding/title.ai) | [SVG](https://www.authelia.com/images/branding/title.svg) | [PNG](https://www.authelia.com/images/branding/title.png)
|
||||
|
||||
#### Title Example
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ The most insecure method is unauthenticated binds. They are generally considered
|
|||
at all ensures anyone with any level of network access can easily obtain objects and their attributes.
|
||||
|
||||
Authelia does support unauthenticated binds but it is not by default, you must configure the
|
||||
[permit_unauthenticated_bind](../../configuration/first-factor/ldap.md#permit_unauthenticated_bind) configuration
|
||||
[permit_unauthenticated_bind](../../configuration/first-factor/ldap.md#permitunauthenticatedbind) configuration
|
||||
option.
|
||||
|
||||
### End-User Binding
|
||||
|
@ -95,15 +95,16 @@ be appreciated). The userAccountControl filter checks that the account is not di
|
|||
value is not 0 which means the password requires changing at the next login.
|
||||
|
||||
| Implementation | Users Filter | Groups Filter |
|
||||
|:---------------:|:---------------------------------------------------------------------------------------------------------------------------------------------------------------:|:------------------------------------------:|
|
||||
|:---------------:|:---------------------------------------------------------------------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------:|
|
||||
| custom | N/A | N/A |
|
||||
| activedirectory | (&(|({username_attribute}={input})({mail_attribute}={input}))(sAMAccountType=805306368)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(!(pwdLastSet=0))) | (&(member={dn})(sAMAccountType=268435456)) |
|
||||
| activedirectory | (&(|({username_attribute}={input})({mail_attribute}={input}))(sAMAccountType=805306368)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(!(pwdLastSet=0))) | (&(member={dn})(|(sAMAccountType=268435456)(sAMAccountType=536870912))) |
|
||||
|
||||
##### Microsoft Active Directory sAMAccountType
|
||||
|
||||
| Account Type Value | Description | Equivalent Filter |
|
||||
|:------------------:|:--------------------------:|:----------------------------------------------:|
|
||||
| 268435456 | Normal Group Objects | N/A |
|
||||
|:------------------:|:---------------------------------------:|:----------------------------------------------:|
|
||||
| 268435456 | Global/Universal Security Group Objects | N/A |
|
||||
| 536870912 | Domain Local Security Group Objects | N/A |
|
||||
| 805306368 | Normal User Accounts | `(&(objectCategory=person)(objectClass=user))` |
|
||||
|
||||
*__References:__*
|
||||
|
|
|
@ -16,7 +16,7 @@ Authelia uses templates to generate the HTML and plaintext emails sent via the n
|
|||
two extensions; `.html` for HTML templates, and `.txt` for plaintext templates.
|
||||
|
||||
This guide effectively documents the usage of the
|
||||
[template_path](../../configuration/notifications/introduction.md#template_path) notification configuration option.
|
||||
[template_path](../../configuration/notifications/introduction.md#templatepath) notification configuration option.
|
||||
|
||||
## Important Notes
|
||||
|
||||
|
@ -37,7 +37,7 @@ This guide effectively documents the usage of the
|
|||
| PasswordReset | Used to render notifications sent when password has successfully been reset |
|
||||
|
||||
For example, to modify the `IdentityVerification` HTML template, if your
|
||||
[template_path](../../configuration/notifications/introduction.md#template_path) was configured as
|
||||
[template_path](../../configuration/notifications/introduction.md#templatepath) was configured as
|
||||
`/config/email_templates`, you would create the `/config/email_templates/IdentityVerification.html` file to override the
|
||||
HTML `IdentityVerification` template.
|
||||
|
||||
|
|
|
@ -156,7 +156,7 @@ See the [Crypt (C) Wiki page](https://en.wikipedia.org/wiki/Crypt_(C)) for more
|
|||
#### Tuning
|
||||
|
||||
The configuration variables are unique to the file authentication provider, thus they all exist in a key under the file
|
||||
authentication configuration key called [password](../../configuration/first-factor/file.md#password). The defaults are
|
||||
authentication configuration key called [password](../../configuration/first-factor/file.md#password-options). The defaults are
|
||||
considered as sane for a reasonable system however we still recommend taking time to figure out the best values to
|
||||
adequately determine the [cost](#cost).
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ This guide effectively documents the usage of the
|
|||
## Assets
|
||||
|
||||
| Asset | File Name | Directory | Notes |
|
||||
|:-------------------:|:-----------:|:---------:|:-------------:|
|
||||
|:-------------------:|:-----------:|:---------:|:-----------------------:|
|
||||
| Favicon | favicon.ico | No | N/A |
|
||||
| Logo | logo.png | No | N/A |
|
||||
| Translation Locales | locales | Yes | see [locales](#locales) |
|
||||
|
|
|
@ -12,7 +12,6 @@ weight: 220
|
|||
toc: true
|
||||
aliases:
|
||||
- /r/sanitize
|
||||
- /reference/guides/domain-sanitizaiton
|
||||
---
|
||||
|
||||
Some users may wish to hide their domain in files provided during troubleshooting. While this is discouraged, if a user
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
---
|
||||
title: "Cache Integrations"
|
||||
description: "A cache integration reference guide"
|
||||
lead: "This section contains a cache integration reference guide for Authelia."
|
||||
date: 2022-11-19T16:47:09+11:00
|
||||
draft: false
|
||||
images: []
|
||||
menu:
|
||||
reference:
|
||||
parent: "integrations"
|
||||
weight: 320
|
||||
toc: true
|
||||
---
|
||||
|
||||
We currently only support [Redis Standalone] and [Redis Sentinel] for cached information like sessions
|
||||
(other than in-memory).
|
||||
|
||||
## Redis
|
||||
|
||||
The following is guidance on versions of [Redis] supported.
|
||||
|
||||
### Standalone
|
||||
|
||||
When it comes to [Redis Standalone] we support the versions supported by [Redis] themselves which can be found in the
|
||||
[Redis release cycle](https://redis.io/docs/about/releases/) documentation. This is typically the latest available
|
||||
version.
|
||||
|
||||
|
||||
### Sentinel
|
||||
|
||||
When it comes to [Redis Sentinel] we support the versions supported by [Redis] themselves which can be found in the
|
||||
[Redis release cycle](https://redis.io/docs/about/releases/) documentation. This is typically the latest available
|
||||
version.
|
||||
|
||||
_**Note:** Currently we only support [Redis Sentinel] version 6.x due to a breaking change to [Redis Sentinel] in
|
||||
version 7.x. This will be resolved in the near future._
|
||||
|
||||
[Redis]: https://redis.io/
|
||||
[Redis Standalone]: https://redis.io/docs/getting-started/
|
||||
[Redis Sentinel]: https://redis.io/docs/management/sentinel/
|
|
@ -15,16 +15,29 @@ toc: true
|
|||
We generally recommend using [PostgreSQL] for a database. If high availability is not a consideration we also support
|
||||
[SQLite3].
|
||||
|
||||
It is also a general recommendation that if you're using [PostgreSQL], [MySQL], or [MariaDB]; that you do not
|
||||
automatically upgrade the major/minor version of these databases, and pin the image tag so at most the patch version
|
||||
is updated. For example for database version `x.y.z` only the `z` should change, `x` and `y` should remain the same.
|
||||
|
||||
It is also generally recommended that you do not rely on automatic update tools to perform this action
|
||||
unless you are sure they shut down the container properly (i.e. with a graceful stop).
|
||||
|
||||
While this guide exists and it contains some guidance on managing the database being used, it is by no means exhaustive
|
||||
or intended as such and users should refer to the database vendors documentation.
|
||||
|
||||
## PostgreSQL
|
||||
|
||||
The only current support criteria for [PostgreSQL] at present is that the version you're using is supported by the
|
||||
[PostgreSQL] developers. See their [Versioning Policy](https://www.postgresql.org/support/versioning/) for more
|
||||
information.
|
||||
[PostgreSQL] developers. See [Vendor Supported Versions](#vendor-supported-versions) more information.
|
||||
|
||||
We generally perform integration testing against the latest supported version of [PostgreSQL] and that is generally the
|
||||
recommended version for new installations.
|
||||
|
||||
### Vendor Supported Versions
|
||||
|
||||
See the [PostgreSQL Versioning Policy](https://www.postgresql.org/support/versioning/) for information on the versions
|
||||
and platforms that are currently supported by this vendor.
|
||||
|
||||
## MySQL
|
||||
|
||||
[MySQL] and [MariaDB] are both supported as part of the [MySQL] implementation. This is generally discouraged as
|
||||
|
@ -40,8 +53,8 @@ party.
|
|||
4. Must support maximum index size of no less than 2048 bytes. The default maximum index size for the InnoDB engine is
|
||||
3072 bytes on:
|
||||
1. [MySQL] [8.0](https://dev.mysql.com/doc/refman/8.0/en/innodb-limits.html) or later.
|
||||
2. [MySQL] [5.7](https://dev.mysql.com/doc/refman/5.7/en/innodb-limits.html) provided
|
||||
[innodb_large_prefix](#innodb-large-prefixes) or later.
|
||||
2. [MySQL] [5.7](https://dev.mysql.com/doc/refman/5.7/en/innodb-limits.html) or later provided:
|
||||
1. The [innodb_large_prefix](#innodb-large-prefixes) option is **_ON_**.
|
||||
3. [MariaDB] [10.3](https://mariadb.com/kb/en/innodb-system-variables/#innodb_large_prefix) or later.
|
||||
5. Must support ANSI standard time behaviours. See [ANSI standard time behaviours](#ansi-standard-time-behaviours).
|
||||
|
||||
|
@ -52,8 +65,8 @@ supported version of [MariaDB] is generally the recommended version for new inst
|
|||
|
||||
#### InnoDB Large Prefixes
|
||||
|
||||
This can be configured in the [MySQL] configuration file by setting the `innodb_large_prefix` value to on.
|
||||
According to the Oracle documentation this is the default behaviour in
|
||||
This can be configured in the [MySQL] configuration file by setting the `innodb_large_prefix` option to on.
|
||||
According to the [Oracle] documentation this is the default behaviour in
|
||||
[MySQL] [5.7](https://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_large_prefix) and it can't be
|
||||
turned off in [MySQL] [8.0](https://dev.mysql.com/doc/refman/8.0/en/innodb-limits.html) or in [MariaDB] 10.3 and later.
|
||||
|
||||
|
@ -65,7 +78,7 @@ innodb_large_prefix = ON
|
|||
#### ANSI standard time behaviours
|
||||
|
||||
This can be configured in the [MySQL] configuration file by setting the `explicit_defaults_for_timestamp` value to on.
|
||||
According to the Oracle documentation this is the default behaviour in
|
||||
According to the [Oracle] documentation this is the default behaviour in
|
||||
[MySQL] [5.7](https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_explicit_defaults_for_timestamp)
|
||||
and [MySQL] [8.0](https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_explicit_defaults_for_timestamp).
|
||||
This is however not the default behaviour in
|
||||
|
@ -76,19 +89,43 @@ This is however not the default behaviour in
|
|||
explicit_defaults_for_timestamp = ON
|
||||
```
|
||||
|
||||
#### Upgrades
|
||||
|
||||
[MySQL] and [MariaDB] have several standard but important system databases named `mysql`, `sys`, and
|
||||
`performance_schema`. These databases are outside the scope and not intended for individual applications to manage as
|
||||
they are system databases used by [MySQL] and [MariaDB] internally.
|
||||
|
||||
These servers/engines may successfully start when these databases are incompatible with your particular [MySQL] or
|
||||
[MariaDB] version, but may raise errors when you attempt to use particular features of the database. This may lead a
|
||||
user to believe the server/engine is functioning correctly when it is in fact running with a potentially badly corrupted
|
||||
schema.
|
||||
|
||||
The risk here is that the database may run for an extended period of time unnoticed and may be getting more and more
|
||||
corrupt with no visible signs until it's no longer recoverable. This makes it critically important users do not neglect
|
||||
this operation or ensure it's happening.
|
||||
|
||||
While some [MySQL] or [MariaDB] containers will do this automatically or give users an option to perform this
|
||||
automatically, it is strongly recommended that this process is manually done and only done **_after_** doing a backup of
|
||||
all databases on the server as is the recommendation from both [MySQL] and [MariaDB].
|
||||
|
||||
It is your responsibility to ensure these tables are upgraded as per the
|
||||
[mysql_upgrade](https://dev.mysql.com/doc/refman/8.0/en/mysql-upgrade.html) and
|
||||
[mariadb_upgrade](https://mariadb.com/kb/en/mysql_upgrade/) documentation.
|
||||
|
||||
### Vendor Supported Versions
|
||||
|
||||
#### MariaDB Vendor Supported Versions
|
||||
|
||||
See the [MariaDB Server Releases](https://mariadb.com/kb/en/mariadb-server-release-dates/) for more information.
|
||||
See the [MariaDB Server Releases](https://mariadb.com/kb/en/mariadb-server-release-dates/) for information on the
|
||||
versions and platforms that are currently supported by this vendor.
|
||||
|
||||
#### MySQL Vendor Supported Versions
|
||||
|
||||
See the [MySQL Supported Platforms](https://www.mysql.com/support/supportedplatforms/database.html) for information on
|
||||
which versions and platforms they support.
|
||||
the versions and platforms that are currently supported by this vendor.
|
||||
|
||||
[PostgreSQL]: https://www.postgresql.org/
|
||||
[MySQL]: https://www.mysql.com/
|
||||
[MariaDB]: https://mariadb.org/
|
||||
[SQLite3]: https://www.sqlite.org/index.html
|
||||
|
||||
[Oracle]: https://www.oracle.com/
|
||||
|
|
|
@ -3,20 +3,21 @@
|
|||
functions = "functions"
|
||||
|
||||
[build.environment]
|
||||
NODE_VERSION = "16.16.0"
|
||||
NPM_VERSION = "8.11.0"
|
||||
NODE_VERSION = "16.18.1"
|
||||
NPM_VERSION = "8.19.2"
|
||||
GO_VERSION = "1.19.4"
|
||||
|
||||
[context.production]
|
||||
command = "npm run build"
|
||||
command = "pnpm run build"
|
||||
|
||||
[context.deploy-preview]
|
||||
command = "npm run build -- -b $DEPLOY_PRIME_URL"
|
||||
command = "pnpm run build --baseURL $DEPLOY_URL"
|
||||
|
||||
[context.branch-deploy]
|
||||
command = "npm run build -- -b $DEPLOY_PRIME_URL"
|
||||
command = "pnpm run build --baseURL $DEPLOY_URL"
|
||||
|
||||
[context.next]
|
||||
command = "npm run build"
|
||||
command = "pnpm run build"
|
||||
|
||||
[context.next.environment]
|
||||
HUGO_ENV = "next"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"description": "Doks theme",
|
||||
"version": "0.5.0",
|
||||
"engines": {
|
||||
"node": ">=16.16.0"
|
||||
"node": ">=16.18.1"
|
||||
},
|
||||
"browserslist": [
|
||||
"defaults"
|
||||
|
@ -39,7 +39,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "7.19.3",
|
||||
"@babel/core": "7.20.2",
|
||||
"@babel/core": "7.20.5",
|
||||
"@babel/preset-env": "7.20.2",
|
||||
"@fullhuman/postcss-purgecss": "5.0.0",
|
||||
"@hyas/images": "0.3.2",
|
||||
|
@ -49,25 +49,25 @@
|
|||
"bootstrap": "5.2.3",
|
||||
"bootstrap-icons": "1.10.2",
|
||||
"clipboard": "2.0.11",
|
||||
"eslint": "8.28.0",
|
||||
"eslint": "8.29.0",
|
||||
"exec-bin": "1.0.0",
|
||||
"flexsearch": "0.7.31",
|
||||
"highlight.js": "11.7.0",
|
||||
"hugo-installer": "4.0.1",
|
||||
"instant.page": "5.1.1",
|
||||
"katex": "0.16.3",
|
||||
"katex": "0.16.4",
|
||||
"lazysizes": "5.3.2",
|
||||
"markdownlint-cli2": "0.5.1",
|
||||
"netlify-plugin-submit-sitemap": "0.4.0",
|
||||
"node-fetch": "3.3.0",
|
||||
"postcss": "8.4.19",
|
||||
"postcss-cli": "10.0.0",
|
||||
"postcss-cli": "10.1.0",
|
||||
"purgecss-whitelister": "2.4.0",
|
||||
"shx": "0.3.4",
|
||||
"stylelint": "14.15.0",
|
||||
"stylelint": "14.16.0",
|
||||
"stylelint-config-standard-scss": "6.1.0"
|
||||
},
|
||||
"otherDependencies": {
|
||||
"hugo": "0.107.0"
|
||||
"hugo": "0.108.0"
|
||||
}
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 13 KiB |
|
@ -45,7 +45,7 @@ services:
|
|||
- TZ=Australia/Melbourne
|
||||
|
||||
traefik:
|
||||
image: traefik:v2.9.5
|
||||
image: traefik:v2.9.6
|
||||
container_name: traefik
|
||||
volumes:
|
||||
- ./traefik:/etc/traefik
|
||||
|
|
|
@ -32,7 +32,7 @@ services:
|
|||
- TZ=Australia/Melbourne
|
||||
|
||||
traefik:
|
||||
image: traefik:v2.9.5
|
||||
image: traefik:v2.9.6
|
||||
container_name: traefik
|
||||
volumes:
|
||||
- ./traefik:/etc/traefik
|
||||
|
|
20
go.mod
|
@ -11,27 +11,27 @@ require (
|
|||
github.com/fasthttp/session/v2 v2.4.13
|
||||
github.com/fsnotify/fsnotify v1.6.0
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.4
|
||||
github.com/go-crypt/crypt v0.1.14
|
||||
github.com/go-crypt/crypt v0.2.3
|
||||
github.com/go-ldap/ldap/v3 v3.4.4
|
||||
github.com/go-rod/rod v0.112.2
|
||||
github.com/go-sql-driver/mysql v1.6.0
|
||||
github.com/go-sql-driver/mysql v1.7.0
|
||||
github.com/go-webauthn/webauthn v0.5.0
|
||||
github.com/golang-jwt/jwt/v4 v4.4.3
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/hashicorp/go-retryablehttp v0.7.1
|
||||
github.com/jackc/pgx/v5 v5.1.1
|
||||
github.com/jackc/pgx/v5 v5.2.0
|
||||
github.com/jmoiron/sqlx v1.3.5
|
||||
github.com/knadh/koanf v1.4.4
|
||||
github.com/mattn/go-sqlite3 v1.14.16
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
||||
github.com/ory/fosite v0.43.0
|
||||
github.com/ory/fosite v0.44.0
|
||||
github.com/ory/herodot v0.9.13
|
||||
github.com/ory/x v0.0.517
|
||||
github.com/ory/x v0.0.520
|
||||
github.com/otiai10/copy v1.9.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pquerna/otp v1.3.0
|
||||
github.com/pquerna/otp v1.4.0
|
||||
github.com/prometheus/client_golang v1.14.0
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/spf13/cobra v1.6.1
|
||||
|
@ -40,8 +40,8 @@ require (
|
|||
github.com/trustelem/zxcvbn v1.0.1
|
||||
github.com/valyala/fasthttp v1.43.0
|
||||
golang.org/x/sync v0.1.0
|
||||
golang.org/x/term v0.2.0
|
||||
golang.org/x/text v0.4.0
|
||||
golang.org/x/term v0.3.0
|
||||
golang.org/x/text v0.5.0
|
||||
gopkg.in/square/go-jose.v2 v2.6.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
@ -63,7 +63,7 @@ require (
|
|||
github.com/ecordell/optgen v0.0.6 // indirect
|
||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.4.0 // indirect
|
||||
github.com/go-crypt/x v0.1.3 // indirect
|
||||
github.com/go-crypt/x v0.1.10 // indirect
|
||||
github.com/go-redis/redis/v8 v8.11.5 // indirect
|
||||
github.com/go-webauthn/revoke v0.1.6 // indirect
|
||||
github.com/golang/glog v1.0.0 // indirect
|
||||
|
@ -110,7 +110,7 @@ require (
|
|||
golang.org/x/mod v0.6.0 // indirect
|
||||
golang.org/x/net v0.1.0 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect
|
||||
golang.org/x/sys v0.2.0 // indirect
|
||||
golang.org/x/sys v0.3.0 // indirect
|
||||
golang.org/x/tools v0.2.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71 // indirect
|
||||
|
|
39
go.sum
|
@ -162,10 +162,10 @@ github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrt
|
|||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||
github.com/go-crypt/crypt v0.1.14 h1:Pd8iBYlbwDXJNi0lz8CS/qYvpvxCfP0XO/f5PYvVQ4o=
|
||||
github.com/go-crypt/crypt v0.1.14/go.mod h1:VNLdWMD0go46arq5WVZB2MV/9Vw02FOWhKDORXl7K2c=
|
||||
github.com/go-crypt/x v0.1.3 h1:3YSlHqOZsw4gcPzfqrcc5kg4GIhTKmkjl/ZVqJ3CbbU=
|
||||
github.com/go-crypt/x v0.1.3/go.mod h1:/6X1DjQki055ajXV/7pCHZM0OmMR1+csiXFkxK73Kc8=
|
||||
github.com/go-crypt/crypt v0.2.3 h1:g9OPe39VmqonsTXP/zo4byEoxrxAAUG+DzBvjzGWvuw=
|
||||
github.com/go-crypt/crypt v0.2.3/go.mod h1:mbhOIjybuVuh0Vxveb//7UbGV8OCugJC7UPzqs1awYw=
|
||||
github.com/go-crypt/x v0.1.10 h1:HN8oQGrWcg5xPtIIGwPDWs9MvdYEUJrP7JeNkC46dvM=
|
||||
github.com/go-crypt/x v0.1.10/go.mod h1:OI04rm/Ojti3mrUFZAJnx66nFbnZ0CVPF7qG49mBZgI=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
|
@ -184,8 +184,9 @@ github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC
|
|||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||
github.com/go-rod/rod v0.112.2 h1:dwauKYC/H2em8/BcGk3gC0LTzZHf5MIDKf2DVM4z9gU=
|
||||
github.com/go-rod/rod v0.112.2/go.mod h1:ElViL9ABbcshNQw93+11FrYRH92RRhMKleuILo6+5V0=
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
|
||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||
|
@ -338,8 +339,8 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
|
|||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
|
||||
github.com/jackc/pgx/v5 v5.1.1 h1:pZD79K1SYv8wc2HmCQA6VdmRQi7/OtCfv9bM3WAXUYA=
|
||||
github.com/jackc/pgx/v5 v5.1.1/go.mod h1:Ptn7zmohNsWEsdxRawMzk3gaKma2obW+NWTnKa0S4nk=
|
||||
github.com/jackc/pgx/v5 v5.2.0 h1:NdPpngX0Y6z6XDFKqmFQaE+bCtkqzvQIOt1wvBlAqs8=
|
||||
github.com/jackc/pgx/v5 v5.2.0/go.mod h1:Ptn7zmohNsWEsdxRawMzk3gaKma2obW+NWTnKa0S4nk=
|
||||
github.com/jandelgado/gcov2lcov v1.0.5 h1:rkBt40h0CVK4oCb8Dps950gvfd1rYvQ8+cWa346lVU0=
|
||||
github.com/jandelgado/gcov2lcov v1.0.5/go.mod h1:NnSxK6TMlg1oGDBfGelGbjgorT5/L3cchlbtgFYZSss=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
|
@ -449,8 +450,8 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y
|
|||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
||||
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||
github.com/ory/fosite v0.43.0 h1:9H1O3I7CFxS2Y6j9FDAx2W3I5uAyEubc9hECS0UTOgI=
|
||||
github.com/ory/fosite v0.43.0/go.mod h1:BTd8+oG1mRtezZbQq0S4D2HBc815bedZHjjs2KRs39Y=
|
||||
github.com/ory/fosite v0.44.0 h1:Z3UjyO11/wlIoa3BotOqcTkfm7kUNA8F7dd8mOMfx0o=
|
||||
github.com/ory/fosite v0.44.0/go.mod h1:o/G4kAeNn65l6MCod2+KmFfU6JQBSojS7eXys6lKGzM=
|
||||
github.com/ory/go-acc v0.2.6/go.mod h1:4Kb/UnPcT8qRAk3IAxta+hvVapdxTLWtrr7bFLlEgpw=
|
||||
github.com/ory/go-acc v0.2.8 h1:rOHHAPQjf0u7eHFGWpiXK+gIu/e0GRSJNr9pDukdNC4=
|
||||
github.com/ory/go-acc v0.2.8/go.mod h1:iCRZUdGb/7nqvSn8xWZkhfVrtXRZ9Wru2E5rabCjFPI=
|
||||
|
@ -460,8 +461,8 @@ github.com/ory/herodot v0.9.13 h1:cN/Z4eOkErl/9W7hDIDLb79IO/bfsH+8yscBjRpB4IU=
|
|||
github.com/ory/herodot v0.9.13/go.mod h1:IWDs9kSvFQqw/cQ8zi5ksyYvITiUU4dI7glUrhZcJYo=
|
||||
github.com/ory/viper v1.7.5 h1:+xVdq7SU3e1vNaCsk/ixsfxE4zylk1TJUiJrY647jUE=
|
||||
github.com/ory/viper v1.7.5/go.mod h1:ypOuyJmEUb3oENywQZRgeAMwqgOyDqwboO1tj3DjTaM=
|
||||
github.com/ory/x v0.0.517 h1:20FrwHie18q78WGaHcaH0+XoPNdE88zqSXCQNPNlYUs=
|
||||
github.com/ory/x v0.0.517/go.mod h1:xUtRpoiRARyJNPVk/fcCNKzyp25Foxt9GPlj8pd7egY=
|
||||
github.com/ory/x v0.0.520 h1:ryfKHQEViUBv/UdlZhePOG52RpPAooZtK/I7+x58lBI=
|
||||
github.com/ory/x v0.0.520/go.mod h1:7f32P5XMBLCy6aVT+fUYq3WPcMVpzsjC0C+FovlMNqY=
|
||||
github.com/otiai10/copy v1.9.0 h1:7KFNiCgZ91Ru4qW4CWPf/7jqtxLagGRmIxWldPP9VY4=
|
||||
github.com/otiai10/copy v1.9.0/go.mod h1:hsfX19wcn0UWIHUQ3/4fHuehhk2UyArQ9dVFAn3FczI=
|
||||
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
|
||||
|
@ -493,8 +494,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
|
||||
github.com/pquerna/otp v1.3.0 h1:oJV/SkzR33anKXwQU3Of42rL4wbrffP4uvUf1SvS5Xs=
|
||||
github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||
github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
|
||||
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
|
@ -846,12 +847,12 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
|
||||
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
@ -862,8 +863,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
|
|
@ -8,7 +8,12 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/go-crypt/crypt"
|
||||
"github.com/go-crypt/crypt/algorithm"
|
||||
"github.com/go-crypt/crypt/algorithm/argon2"
|
||||
"github.com/go-crypt/crypt/algorithm/bcrypt"
|
||||
"github.com/go-crypt/crypt/algorithm/pbkdf2"
|
||||
"github.com/go-crypt/crypt/algorithm/scrypt"
|
||||
"github.com/go-crypt/crypt/algorithm/shacrypt"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||
"github.com/authelia/authelia/v4/internal/logging"
|
||||
|
@ -17,7 +22,7 @@ import (
|
|||
// FileUserProvider is a provider reading details from a file.
|
||||
type FileUserProvider struct {
|
||||
config *schema.FileAuthenticationBackend
|
||||
hash crypt.Hash
|
||||
hash algorithm.Hash
|
||||
database *FileUserDatabase
|
||||
mutex *sync.Mutex
|
||||
timeoutReload time.Time
|
||||
|
@ -145,39 +150,50 @@ func (p *FileUserProvider) setTimeoutReload(now time.Time) {
|
|||
}
|
||||
|
||||
// NewFileCryptoHashFromConfig returns a crypt.Hash given a valid configuration.
|
||||
func NewFileCryptoHashFromConfig(config schema.Password) (hash crypt.Hash, err error) {
|
||||
func NewFileCryptoHashFromConfig(config schema.Password) (hash algorithm.Hash, err error) {
|
||||
switch config.Algorithm {
|
||||
case hashArgon2, "":
|
||||
hash = crypt.NewArgon2Hash().
|
||||
WithVariant(crypt.NewArgon2Variant(config.Argon2.Variant)).
|
||||
WithT(config.Argon2.Iterations).
|
||||
WithM(config.Argon2.Memory).
|
||||
WithP(config.Argon2.Parallelism).
|
||||
WithK(config.Argon2.KeyLength).
|
||||
WithS(config.Argon2.SaltLength)
|
||||
hash, err = argon2.New(
|
||||
argon2.WithVariantName(config.Argon2.Variant),
|
||||
argon2.WithT(config.Argon2.Iterations),
|
||||
argon2.WithM(uint32(config.Argon2.Memory)),
|
||||
argon2.WithP(config.Argon2.Parallelism),
|
||||
argon2.WithK(config.Argon2.KeyLength),
|
||||
argon2.WithS(config.Argon2.SaltLength),
|
||||
)
|
||||
case hashSHA2Crypt:
|
||||
hash = crypt.NewSHA2CryptHash().
|
||||
WithVariant(crypt.NewSHA2CryptVariant(config.SHA2Crypt.Variant)).
|
||||
WithRounds(config.SHA2Crypt.Iterations).
|
||||
WithSaltLength(config.SHA2Crypt.SaltLength)
|
||||
hash, err = shacrypt.New(
|
||||
shacrypt.WithVariantName(config.SHA2Crypt.Variant),
|
||||
shacrypt.WithIterations(config.SHA2Crypt.Iterations),
|
||||
shacrypt.WithSaltLength(config.SHA2Crypt.SaltLength),
|
||||
)
|
||||
case hashPBKDF2:
|
||||
hash = crypt.NewPBKDF2Hash().
|
||||
WithVariant(crypt.NewPBKDF2Variant(config.PBKDF2.Variant)).
|
||||
WithIterations(config.PBKDF2.Iterations).
|
||||
WithSaltLength(config.PBKDF2.SaltLength)
|
||||
hash, err = pbkdf2.New(
|
||||
pbkdf2.WithVariantName(config.PBKDF2.Variant),
|
||||
pbkdf2.WithIterations(config.PBKDF2.Iterations),
|
||||
pbkdf2.WithSaltLength(config.PBKDF2.SaltLength),
|
||||
)
|
||||
case hashSCrypt:
|
||||
hash = crypt.NewScryptHash().
|
||||
WithLN(config.SCrypt.Iterations).
|
||||
WithP(config.SCrypt.Parallelism).
|
||||
WithR(config.SCrypt.BlockSize)
|
||||
hash, err = scrypt.New(
|
||||
scrypt.WithLN(config.SCrypt.Iterations),
|
||||
scrypt.WithP(config.SCrypt.Parallelism),
|
||||
scrypt.WithR(config.SCrypt.BlockSize),
|
||||
scrypt.WithKeyLength(config.SCrypt.KeyLength),
|
||||
scrypt.WithSaltLength(config.SCrypt.SaltLength),
|
||||
)
|
||||
case hashBCrypt:
|
||||
hash = crypt.NewBcryptHash().
|
||||
WithVariant(crypt.NewBcryptVariant(config.BCrypt.Variant)).
|
||||
WithCost(config.BCrypt.Cost)
|
||||
hash, err = bcrypt.New(
|
||||
bcrypt.WithVariantName(config.BCrypt.Variant),
|
||||
bcrypt.WithIterations(config.BCrypt.Cost),
|
||||
)
|
||||
default:
|
||||
return nil, fmt.Errorf("algorithm '%s' is unknown", config.Algorithm)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize hash settings: %w", err)
|
||||
}
|
||||
|
||||
if err = hash.Validate(); err != nil {
|
||||
return nil, fmt.Errorf("failed to validate hash settings: %w", err)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/asaskevich/govalidator"
|
||||
"github.com/go-crypt/crypt"
|
||||
"github.com/go-crypt/crypt/algorithm"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
|
@ -203,7 +204,7 @@ func (m *FileUserDatabase) ToDatabaseModel() (model *DatabaseModel) {
|
|||
// DatabaseUserDetails is the model of user details in the file database.
|
||||
type DatabaseUserDetails struct {
|
||||
Username string
|
||||
Digest crypt.Digest
|
||||
Digest algorithm.Digest
|
||||
Disabled bool
|
||||
DisplayName string
|
||||
Email string
|
||||
|
@ -308,7 +309,7 @@ type UserDetailsModel struct {
|
|||
|
||||
// ToDatabaseUserDetailsModel converts a UserDetailsModel into a *DatabaseUserDetails.
|
||||
func (m UserDetailsModel) ToDatabaseUserDetailsModel(username string) (model *DatabaseUserDetails, err error) {
|
||||
var d crypt.Digest
|
||||
var d algorithm.Digest
|
||||
|
||||
if d, err = crypt.Decode(m.HashedPassword); err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -252,7 +252,7 @@ func TestShouldRaiseWhenLoadingDatabaseWithBadSHA512HashesForTheFirstTime(t *tes
|
|||
|
||||
provider := NewFileUserProvider(&config)
|
||||
|
||||
assert.EqualError(t, provider.StartupCheck(), "error decoding the authentication database: failed to parse hash for user 'john': sha2crypt decode error: provided encoded hash has an invalid option: option 'rounds00000' is invalid")
|
||||
assert.EqualError(t, provider.StartupCheck(), "error decoding the authentication database: failed to parse hash for user 'john': shacrypt decode error: parameter pair 'rounds00000' is not properly encoded: does not contain kv separator '='")
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -263,7 +263,7 @@ func TestShouldRaiseWhenLoadingDatabaseWithBadArgon2idHashSettingsForTheFirstTim
|
|||
|
||||
provider := NewFileUserProvider(&config)
|
||||
|
||||
assert.EqualError(t, provider.StartupCheck(), "error decoding the authentication database: failed to parse hash for user 'john': argon2 decode error: provided encoded hash has an invalid option: option 'm65536' is invalid")
|
||||
assert.EqualError(t, provider.StartupCheck(), "error decoding the authentication database: failed to parse hash for user 'john': argon2 decode error: parameter pair 'm65536' is not properly encoded: does not contain kv separator '='")
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/go-crypt/crypt"
|
||||
"github.com/go-crypt/crypt/algorithm"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
|
@ -272,7 +273,7 @@ func newCryptoHashValidateCmd() (cmd *cobra.Command) {
|
|||
|
||||
func cmdCryptoHashGenerateFinish(cmd *cobra.Command, args []string, flagsMap map[string]string) (err error) {
|
||||
var (
|
||||
algorithm string
|
||||
algName string
|
||||
configs []string
|
||||
|
||||
c schema.Password
|
||||
|
@ -294,25 +295,25 @@ func cmdCryptoHashGenerateFinish(cmd *cobra.Command, args []string, flagsMap map
|
|||
break
|
||||
case legacy:
|
||||
if sha512, _ := cmd.Flags().GetBool(cmdFlagNameSHA512); sha512 {
|
||||
algorithm = cmdUseHashSHA2Crypt
|
||||
algName = cmdUseHashSHA2Crypt
|
||||
} else {
|
||||
algorithm = cmdUseHashArgon2
|
||||
algName = cmdUseHashArgon2
|
||||
}
|
||||
default:
|
||||
algorithm = cmd.Use
|
||||
algName = cmd.Use
|
||||
}
|
||||
|
||||
if c, err = cmdCryptoHashGetConfig(algorithm, configs, cmd.Flags(), flagsMap); err != nil {
|
||||
if c, err = cmdCryptoHashGetConfig(algName, configs, cmd.Flags(), flagsMap); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if legacy && algorithm == cmdUseHashArgon2 && cmd.Flags().Changed(cmdFlagNameMemory) {
|
||||
if legacy && algName == cmdUseHashArgon2 && cmd.Flags().Changed(cmdFlagNameMemory) {
|
||||
c.Argon2.Memory *= 1024
|
||||
}
|
||||
|
||||
var (
|
||||
hash crypt.Hash
|
||||
digest crypt.Digest
|
||||
hash algorithm.Hash
|
||||
digest algorithm.Digest
|
||||
password string
|
||||
random bool
|
||||
)
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-crypt/crypt"
|
||||
"github.com/go-crypt/crypt/algorithm/plaintext"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||
|
@ -486,7 +486,7 @@ func StringToPrivateKeyHookFunc() mapstructure.DecodeHookFuncType {
|
|||
}
|
||||
|
||||
// StringToPasswordDigestHookFunc decodes a string into a crypt.Digest.
|
||||
func StringToPasswordDigestHookFunc(plaintext bool) mapstructure.DecodeHookFuncType {
|
||||
func StringToPasswordDigestHookFunc() mapstructure.DecodeHookFuncType {
|
||||
return func(f reflect.Type, t reflect.Type, data interface{}) (value interface{}, err error) {
|
||||
var ptr bool
|
||||
|
||||
|
@ -514,11 +514,11 @@ func StringToPasswordDigestHookFunc(plaintext bool) mapstructure.DecodeHookFuncT
|
|||
var result *schema.PasswordDigest
|
||||
|
||||
if !strings.HasPrefix(dataStr, "$") {
|
||||
dataStr = fmt.Sprintf(crypt.StorageFormatSimple, crypt.AlgorithmPrefixPlainText, dataStr)
|
||||
dataStr = fmt.Sprintf(plaintext.EncodingFmt, plaintext.AlgIdentifierPlainText, dataStr)
|
||||
}
|
||||
|
||||
if dataStr != "" {
|
||||
if result, err = schema.NewPasswordDigest(dataStr, plaintext); err != nil {
|
||||
if result, err = schema.DecodePasswordDigest(dataStr); err != nil {
|
||||
return nil, fmt.Errorf(errFmtDecodeHookCouldNotParse, dataStr, prefixType, expectedType.String(), err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package configuration
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
@ -58,8 +57,7 @@ func TestKoanfSecretCallbackWithValidSecrets(t *testing.T) {
|
|||
"AUTHELIA__STORAGE_MYSQL_FAKE_PASSWORD": "storage.mysql.fake_password",
|
||||
}
|
||||
|
||||
dir, err := os.MkdirTemp("", "authelia-test-callbacks")
|
||||
assert.NoError(t, err)
|
||||
dir := t.TempDir()
|
||||
|
||||
secretOne := filepath.Join(dir, "secert_one")
|
||||
secretTwo := filepath.Join(dir, "secret_two")
|
||||
|
@ -108,8 +106,7 @@ func TestKoanfSecretCallbackShouldErrorOnFSError(t *testing.T) {
|
|||
"AUTHELIA_THEME": "theme",
|
||||
}
|
||||
|
||||
dir, err := os.MkdirTemp("", "authelia-test-callbacks")
|
||||
assert.NoError(t, err)
|
||||
dir := t.TempDir()
|
||||
|
||||
secret := filepath.Join(dir, "inaccessible")
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ func unmarshal(ko *koanf.Koanf, val *schema.StructValidator, path string, o any)
|
|||
StringToPrivateKeyHookFunc(),
|
||||
StringToCryptoPrivateKeyHookFunc(),
|
||||
StringToTLSVersionHookFunc(),
|
||||
StringToPasswordDigestHookFunc(true),
|
||||
StringToPasswordDigestHookFunc(),
|
||||
ToTimeDurationHookFunc(),
|
||||
),
|
||||
Metadata: nil,
|
||||
|
|
|
@ -19,8 +19,7 @@ import (
|
|||
func TestShouldErrorSecretNotExist(t *testing.T) {
|
||||
testReset()
|
||||
|
||||
dir, err := os.MkdirTemp("", "authelia-test-secret-not-exist")
|
||||
assert.NoError(t, err)
|
||||
dir := t.TempDir()
|
||||
|
||||
testSetEnv(t, "JWT_SECRET_FILE", filepath.Join(dir, "jwt"))
|
||||
testSetEnv(t, "DUO_API_SECRET_KEY_FILE", filepath.Join(dir, "duo"))
|
||||
|
@ -36,7 +35,7 @@ func TestShouldErrorSecretNotExist(t *testing.T) {
|
|||
testSetEnv(t, "IDENTITY_PROVIDERS_OIDC_HMAC_SECRET_FILE", filepath.Join(dir, "oidc-hmac"))
|
||||
|
||||
val := schema.NewStructValidator()
|
||||
_, _, err = Load(val, NewEnvironmentSource(DefaultEnvPrefix, DefaultEnvDelimiter), NewSecretsSource(DefaultEnvPrefix, DefaultEnvDelimiter))
|
||||
_, _, err := Load(val, NewEnvironmentSource(DefaultEnvPrefix, DefaultEnvDelimiter), NewSecretsSource(DefaultEnvPrefix, DefaultEnvDelimiter))
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, val.Warnings(), 0)
|
||||
|
@ -162,15 +161,14 @@ func TestShouldRaiseIOErrOnUnreadableFile(t *testing.T) {
|
|||
|
||||
testReset()
|
||||
|
||||
dir, err := os.MkdirTemp("", "authelia-conf")
|
||||
assert.NoError(t, err)
|
||||
dir := t.TempDir()
|
||||
|
||||
assert.NoError(t, os.WriteFile(filepath.Join(dir, "myconf.yml"), []byte("server:\n port: 9091\n"), 0000))
|
||||
|
||||
cfg := filepath.Join(dir, "myconf.yml")
|
||||
|
||||
val := schema.NewStructValidator()
|
||||
_, _, err = Load(val, NewYAMLFileSource(cfg))
|
||||
_, _, err := Load(val, NewYAMLFileSource(cfg))
|
||||
|
||||
assert.NoError(t, err)
|
||||
require.Len(t, val.Errors(), 1)
|
||||
|
@ -390,14 +388,13 @@ func TestShouldNotReadConfigurationOnFSAccessDenied(t *testing.T) {
|
|||
|
||||
testReset()
|
||||
|
||||
dir, err := os.MkdirTemp("", "authelia-config")
|
||||
assert.NoError(t, err)
|
||||
dir := t.TempDir()
|
||||
|
||||
cfg := filepath.Join(dir, "config.yml")
|
||||
assert.NoError(t, testCreateFile(filepath.Join(dir, "config.yml"), "port: 9091\n", 0000))
|
||||
|
||||
val := schema.NewStructValidator()
|
||||
_, _, err = Load(val, NewYAMLFileSource(cfg))
|
||||
_, _, err := Load(val, NewYAMLFileSource(cfg))
|
||||
|
||||
assert.NoError(t, err)
|
||||
require.Len(t, val.Errors(), 1)
|
||||
|
@ -408,11 +405,10 @@ func TestShouldNotReadConfigurationOnFSAccessDenied(t *testing.T) {
|
|||
func TestShouldNotLoadDirectoryConfiguration(t *testing.T) {
|
||||
testReset()
|
||||
|
||||
dir, err := os.MkdirTemp("", "authelia-config")
|
||||
assert.NoError(t, err)
|
||||
dir := t.TempDir()
|
||||
|
||||
val := schema.NewStructValidator()
|
||||
_, _, err = Load(val, NewYAMLFileSource(dir))
|
||||
_, _, err := Load(val, NewYAMLFileSource(dir))
|
||||
|
||||
assert.NoError(t, err)
|
||||
require.Len(t, val.Errors(), 1)
|
||||
|
|
|
@ -191,7 +191,7 @@ var DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory =
|
|||
UsernameAttribute: "sAMAccountName",
|
||||
MailAttribute: "mail",
|
||||
DisplayNameAttribute: "displayName",
|
||||
GroupsFilter: "(&(member={dn})(sAMAccountType=268435456))",
|
||||
GroupsFilter: "(&(member={dn})(|(sAMAccountType=268435456)(sAMAccountType=536870912)))",
|
||||
GroupNameAttribute: "cn",
|
||||
Timeout: time.Second * 5,
|
||||
TLS: &TLSConfig{
|
||||
|
|
|
@ -16,6 +16,8 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/go-crypt/crypt"
|
||||
"github.com/go-crypt/crypt/algorithm"
|
||||
"github.com/go-crypt/crypt/algorithm/plaintext"
|
||||
)
|
||||
|
||||
// NewAddressFromString returns an *Address and error depending on the ability to parse the string as an Address.
|
||||
|
@ -110,27 +112,32 @@ func (a Address) Listener() (net.Listener, error) {
|
|||
return net.Listen(a.Scheme, a.HostPort())
|
||||
}
|
||||
|
||||
// NewPasswordDigest returns a new PasswordDigest.
|
||||
func NewPasswordDigest(value string, plaintext bool) (digest *PasswordDigest, err error) {
|
||||
var d crypt.Digest
|
||||
var cdecoder algorithm.DecoderRegister
|
||||
|
||||
switch {
|
||||
case plaintext:
|
||||
d, err = crypt.DecodeWithPlainText(value)
|
||||
default:
|
||||
d, err = crypt.Decode(value)
|
||||
// DecodePasswordDigest returns a new PasswordDigest if it can be decoded.
|
||||
func DecodePasswordDigest(encodedDigest string) (digest *PasswordDigest, err error) {
|
||||
if cdecoder == nil {
|
||||
if cdecoder, err = crypt.NewDefaultDecoder(); err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize decoder: %w", err)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if err = plaintext.RegisterDecoderPlainText(cdecoder); err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize decoder: could not register the plaintext decoder: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
var d algorithm.Digest
|
||||
|
||||
if d, err = cdecoder.Decode(encodedDigest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &PasswordDigest{d}, err
|
||||
return &PasswordDigest{Digest: d}, nil
|
||||
}
|
||||
|
||||
// PasswordDigest is a configuration type for the crypt.Digest.
|
||||
type PasswordDigest struct {
|
||||
crypt.Digest
|
||||
algorithm.Digest
|
||||
}
|
||||
|
||||
// NewX509CertificateChain creates a new *X509CertificateChain from a given string, parsing each PEM block one by one.
|
||||
|
|
|
@ -13,8 +13,7 @@ import (
|
|||
)
|
||||
|
||||
func TestShouldGenerateConfiguration(t *testing.T) {
|
||||
dir, err := os.MkdirTemp("", "authelia-config")
|
||||
assert.NoError(t, err)
|
||||
dir := t.TempDir()
|
||||
|
||||
cfg := filepath.Join(dir, "config.yml")
|
||||
|
||||
|
@ -31,8 +30,7 @@ func TestShouldNotGenerateConfigurationOnFSAccessDenied(t *testing.T) {
|
|||
t.Skip("skipping test due to being on windows")
|
||||
}
|
||||
|
||||
dir, err := os.MkdirTemp("", "authelia-config")
|
||||
assert.NoError(t, err)
|
||||
dir := t.TempDir()
|
||||
|
||||
assert.NoError(t, os.Mkdir(filepath.Join(dir, "zero"), 0000))
|
||||
|
||||
|
@ -44,8 +42,7 @@ func TestShouldNotGenerateConfigurationOnFSAccessDenied(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestShouldNotGenerateConfiguration(t *testing.T) {
|
||||
dir, err := os.MkdirTemp("", "authelia-config")
|
||||
assert.NoError(t, err)
|
||||
dir := t.TempDir()
|
||||
|
||||
cfg := filepath.Join(dir, "..", "not-a-dir", "config.yml")
|
||||
|
||||
|
|
|
@ -5,7 +5,11 @@ import (
|
|||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/go-crypt/crypt"
|
||||
"github.com/go-crypt/crypt/algorithm/argon2"
|
||||
"github.com/go-crypt/crypt/algorithm/bcrypt"
|
||||
"github.com/go-crypt/crypt/algorithm/pbkdf2"
|
||||
"github.com/go-crypt/crypt/algorithm/scrypt"
|
||||
"github.com/go-crypt/crypt/algorithm/shacrypt"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||
"github.com/authelia/authelia/v4/internal/utils"
|
||||
|
@ -91,46 +95,48 @@ func validateFileAuthenticationBackendPasswordConfigArgon2(config *schema.Passwo
|
|||
switch {
|
||||
case config.Argon2.Iterations == 0:
|
||||
config.Argon2.Iterations = schema.DefaultPasswordConfig.Argon2.Iterations
|
||||
case config.Argon2.Iterations < crypt.Argon2IterationsMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "iterations", config.Argon2.Iterations, crypt.Argon2IterationsMin))
|
||||
case config.Argon2.Iterations > crypt.Argon2IterationsMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "iterations", config.Argon2.Iterations, crypt.Argon2IterationsMax))
|
||||
case config.Argon2.Iterations < argon2.IterationsMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "iterations", config.Argon2.Iterations, argon2.IterationsMin))
|
||||
case config.Argon2.Iterations > argon2.IterationsMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "iterations", config.Argon2.Iterations, argon2.IterationsMax))
|
||||
}
|
||||
|
||||
switch {
|
||||
case config.Argon2.Parallelism == 0:
|
||||
config.Argon2.Parallelism = schema.DefaultPasswordConfig.Argon2.Parallelism
|
||||
case config.Argon2.Parallelism < crypt.Argon2ParallelismMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "parallelism", config.Argon2.Parallelism, crypt.Argon2ParallelismMin))
|
||||
case config.Argon2.Parallelism > crypt.Argon2ParallelismMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "parallelism", config.Argon2.Parallelism, crypt.Argon2ParallelismMax))
|
||||
case config.Argon2.Parallelism < argon2.ParallelismMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "parallelism", config.Argon2.Parallelism, argon2.ParallelismMin))
|
||||
case config.Argon2.Parallelism > argon2.ParallelismMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "parallelism", config.Argon2.Parallelism, argon2.ParallelismMax))
|
||||
}
|
||||
|
||||
switch {
|
||||
case config.Argon2.Memory == 0:
|
||||
config.Argon2.Memory = schema.DefaultPasswordConfig.Argon2.Memory
|
||||
case config.Argon2.Memory < 0:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "memory", config.Argon2.Parallelism, 1))
|
||||
case config.Argon2.Memory < (crypt.Argon2MemoryMinParallelismMultiplier * config.Argon2.Parallelism):
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordArgon2MemoryTooLow, config.Argon2.Memory, config.Argon2.Parallelism*crypt.Argon2MemoryMinParallelismMultiplier, config.Argon2.Parallelism, crypt.Argon2MemoryMinParallelismMultiplier))
|
||||
case config.Argon2.Memory < argon2.MemoryMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "memory", config.Argon2.Memory, argon2.MemoryMin))
|
||||
case uint64(config.Argon2.Memory) > uint64(argon2.MemoryMax):
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "memory", config.Argon2.Memory, argon2.MemoryMax))
|
||||
case config.Argon2.Memory < (config.Argon2.Parallelism * argon2.MemoryMinParallelismMultiplier):
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordArgon2MemoryTooLow, config.Argon2.Memory, config.Argon2.Parallelism*argon2.MemoryMinParallelismMultiplier, config.Argon2.Parallelism, argon2.MemoryMinParallelismMultiplier))
|
||||
}
|
||||
|
||||
switch {
|
||||
case config.Argon2.KeyLength == 0:
|
||||
config.Argon2.KeyLength = schema.DefaultPasswordConfig.Argon2.KeyLength
|
||||
case config.Argon2.KeyLength < crypt.Argon2KeySizeMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "key_length", config.Argon2.KeyLength, crypt.Argon2KeySizeMin))
|
||||
case config.Argon2.KeyLength > crypt.Argon2KeySizeMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "key_length", config.Argon2.KeyLength, crypt.Argon2KeySizeMax))
|
||||
case config.Argon2.KeyLength < argon2.KeyLengthMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "key_length", config.Argon2.KeyLength, argon2.KeyLengthMin))
|
||||
case config.Argon2.KeyLength > argon2.KeyLengthMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "key_length", config.Argon2.KeyLength, argon2.KeyLengthMax))
|
||||
}
|
||||
|
||||
switch {
|
||||
case config.Argon2.SaltLength == 0:
|
||||
config.Argon2.SaltLength = schema.DefaultPasswordConfig.Argon2.SaltLength
|
||||
case config.Argon2.SaltLength < crypt.Argon2SaltSizeMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "salt_length", config.Argon2.SaltLength, crypt.Argon2SaltSizeMin))
|
||||
case config.Argon2.SaltLength > crypt.Argon2SaltSizeMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "salt_length", config.Argon2.SaltLength, crypt.Argon2SaltSizeMax))
|
||||
case config.Argon2.SaltLength < argon2.SaltLengthMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashArgon2, "salt_length", config.Argon2.SaltLength, argon2.SaltLengthMin))
|
||||
case config.Argon2.SaltLength > argon2.SaltLengthMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashArgon2, "salt_length", config.Argon2.SaltLength, argon2.SaltLengthMax))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,19 +153,19 @@ func validateFileAuthenticationBackendPasswordConfigSHA2Crypt(config *schema.Pas
|
|||
switch {
|
||||
case config.SHA2Crypt.Iterations == 0:
|
||||
config.SHA2Crypt.Iterations = schema.DefaultPasswordConfig.SHA2Crypt.Iterations
|
||||
case config.SHA2Crypt.Iterations < crypt.SHA2CryptIterationsMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSHA2Crypt, "iterations", config.SHA2Crypt.Iterations, crypt.SHA2CryptIterationsMin))
|
||||
case config.SHA2Crypt.Iterations > crypt.SHA2CryptIterationsMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSHA2Crypt, "iterations", config.SHA2Crypt.Iterations, crypt.SHA2CryptIterationsMax))
|
||||
case config.SHA2Crypt.Iterations < shacrypt.IterationsMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSHA2Crypt, "iterations", config.SHA2Crypt.Iterations, shacrypt.IterationsMin))
|
||||
case config.SHA2Crypt.Iterations > shacrypt.IterationsMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSHA2Crypt, "iterations", config.SHA2Crypt.Iterations, shacrypt.IterationsMax))
|
||||
}
|
||||
|
||||
switch {
|
||||
case config.SHA2Crypt.SaltLength == 0:
|
||||
config.SHA2Crypt.SaltLength = schema.DefaultPasswordConfig.SHA2Crypt.SaltLength
|
||||
case config.SHA2Crypt.SaltLength < crypt.SHA2CryptSaltSizeMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSHA2Crypt, "salt_length", config.SHA2Crypt.SaltLength, crypt.SHA2CryptSaltSizeMin))
|
||||
case config.SHA2Crypt.SaltLength > crypt.SHA2CryptSaltSizeMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSHA2Crypt, "salt_length", config.SHA2Crypt.SaltLength, crypt.SHA2CryptSaltSizeMax))
|
||||
case config.SHA2Crypt.SaltLength < shacrypt.SaltLengthMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSHA2Crypt, "salt_length", config.SHA2Crypt.SaltLength, shacrypt.SaltLengthMin))
|
||||
case config.SHA2Crypt.SaltLength > shacrypt.SaltLengthMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSHA2Crypt, "salt_length", config.SHA2Crypt.SaltLength, shacrypt.SaltLengthMax))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,19 +182,19 @@ func validateFileAuthenticationBackendPasswordConfigPBKDF2(config *schema.Passwo
|
|||
switch {
|
||||
case config.PBKDF2.Iterations == 0:
|
||||
config.PBKDF2.Iterations = schema.DefaultPasswordConfig.PBKDF2.Iterations
|
||||
case config.PBKDF2.Iterations < crypt.PBKDF2IterationsMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashPBKDF2, "iterations", config.PBKDF2.Iterations, crypt.PBKDF2IterationsMin))
|
||||
case config.PBKDF2.Iterations > crypt.PBKDF2IterationsMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashPBKDF2, "iterations", config.PBKDF2.Iterations, crypt.PBKDF2IterationsMax))
|
||||
case config.PBKDF2.Iterations < pbkdf2.IterationsMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashPBKDF2, "iterations", config.PBKDF2.Iterations, pbkdf2.IterationsMin))
|
||||
case config.PBKDF2.Iterations > pbkdf2.IterationsMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashPBKDF2, "iterations", config.PBKDF2.Iterations, pbkdf2.IterationsMax))
|
||||
}
|
||||
|
||||
switch {
|
||||
case config.PBKDF2.SaltLength == 0:
|
||||
config.PBKDF2.SaltLength = schema.DefaultPasswordConfig.PBKDF2.SaltLength
|
||||
case config.PBKDF2.SaltLength < crypt.PBKDF2SaltSizeMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashPBKDF2, "salt_length", config.PBKDF2.SaltLength, crypt.PBKDF2SaltSizeMin))
|
||||
case config.PBKDF2.SaltLength > crypt.PBKDF2SaltSizeMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashPBKDF2, "salt_length", config.PBKDF2.SaltLength, crypt.PBKDF2SaltSizeMax))
|
||||
case config.PBKDF2.SaltLength < pbkdf2.SaltLengthMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashPBKDF2, "salt_length", config.PBKDF2.SaltLength, pbkdf2.SaltLengthMin))
|
||||
case config.PBKDF2.SaltLength > pbkdf2.SaltLengthMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashPBKDF2, "salt_length", config.PBKDF2.SaltLength, pbkdf2.SaltLengthMax))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,53 +211,58 @@ func validateFileAuthenticationBackendPasswordConfigBCrypt(config *schema.Passwo
|
|||
switch {
|
||||
case config.BCrypt.Cost == 0:
|
||||
config.BCrypt.Cost = schema.DefaultPasswordConfig.BCrypt.Cost
|
||||
case config.BCrypt.Cost < crypt.BcryptCostMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashBCrypt, "cost", config.BCrypt.Cost, crypt.BcryptCostMin))
|
||||
case config.BCrypt.Cost > crypt.BcryptCostMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashBCrypt, "cost", config.BCrypt.Cost, crypt.BcryptCostMax))
|
||||
case config.BCrypt.Cost < bcrypt.IterationsMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashBCrypt, "cost", config.BCrypt.Cost, bcrypt.IterationsMin))
|
||||
case config.BCrypt.Cost > bcrypt.IterationsMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashBCrypt, "cost", config.BCrypt.Cost, bcrypt.IterationsMax))
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func validateFileAuthenticationBackendPasswordConfigSCrypt(config *schema.Password, validator *schema.StructValidator) {
|
||||
switch {
|
||||
case config.SCrypt.Iterations == 0:
|
||||
config.SCrypt.Iterations = schema.DefaultPasswordConfig.SCrypt.Iterations
|
||||
case config.SCrypt.Iterations < crypt.ScryptIterationsMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "iterations", config.SCrypt.Iterations, crypt.ScryptIterationsMin))
|
||||
case config.SCrypt.Iterations < scrypt.IterationsMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "iterations", config.SCrypt.Iterations, scrypt.IterationsMin))
|
||||
case config.SCrypt.Iterations > scrypt.IterationsMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSCrypt, "iterations", config.SCrypt.Iterations, scrypt.IterationsMax))
|
||||
}
|
||||
|
||||
switch {
|
||||
case config.SCrypt.BlockSize == 0:
|
||||
config.SCrypt.BlockSize = schema.DefaultPasswordConfig.SCrypt.BlockSize
|
||||
case config.SCrypt.BlockSize < crypt.ScryptBlockSizeMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "block_size", config.SCrypt.BlockSize, crypt.ScryptBlockSizeMin))
|
||||
case config.SCrypt.BlockSize > crypt.ScryptBlockSizeMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSCrypt, "block_size", config.SCrypt.BlockSize, crypt.ScryptBlockSizeMax))
|
||||
case config.SCrypt.BlockSize < scrypt.BlockSizeMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "block_size", config.SCrypt.BlockSize, scrypt.BlockSizeMin))
|
||||
case config.SCrypt.BlockSize > scrypt.BlockSizeMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSCrypt, "block_size", config.SCrypt.BlockSize, scrypt.BlockSizeMax))
|
||||
}
|
||||
|
||||
switch {
|
||||
case config.SCrypt.Parallelism == 0:
|
||||
config.SCrypt.Parallelism = schema.DefaultPasswordConfig.SCrypt.Parallelism
|
||||
case config.SCrypt.Parallelism < crypt.ScryptParallelismMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "parallelism", config.SCrypt.Parallelism, crypt.ScryptParallelismMin))
|
||||
case config.SCrypt.Parallelism < scrypt.ParallelismMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "parallelism", config.SCrypt.Parallelism, scrypt.ParallelismMin))
|
||||
case config.SCrypt.Parallelism > scrypt.ParallelismMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSCrypt, "parallelism", config.SCrypt.Parallelism, scrypt.ParallelismMax))
|
||||
}
|
||||
|
||||
switch {
|
||||
case config.SCrypt.KeyLength == 0:
|
||||
config.SCrypt.KeyLength = schema.DefaultPasswordConfig.SCrypt.KeyLength
|
||||
case config.SCrypt.KeyLength < crypt.ScryptKeySizeMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "key_length", config.SCrypt.KeyLength, crypt.ScryptKeySizeMin))
|
||||
case config.SCrypt.KeyLength > crypt.ScryptKeySizeMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSCrypt, "key_length", config.SCrypt.KeyLength, crypt.ScryptKeySizeMax))
|
||||
case config.SCrypt.KeyLength < scrypt.KeyLengthMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "key_length", config.SCrypt.KeyLength, scrypt.KeyLengthMin))
|
||||
case config.SCrypt.KeyLength > scrypt.KeyLengthMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSCrypt, "key_length", config.SCrypt.KeyLength, scrypt.KeyLengthMax))
|
||||
}
|
||||
|
||||
switch {
|
||||
case config.SCrypt.SaltLength == 0:
|
||||
config.SCrypt.SaltLength = schema.DefaultPasswordConfig.SCrypt.SaltLength
|
||||
case config.SCrypt.SaltLength < crypt.ScryptSaltSizeMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "salt_length", config.SCrypt.SaltLength, crypt.ScryptSaltSizeMin))
|
||||
case config.SCrypt.SaltLength > crypt.ScryptSaltSizeMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSCrypt, "salt_length", config.SCrypt.SaltLength, crypt.ScryptSaltSizeMax))
|
||||
case config.SCrypt.SaltLength < scrypt.SaltLengthMin:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooSmall, hashSCrypt, "salt_length", config.SCrypt.SaltLength, scrypt.SaltLengthMin))
|
||||
case config.SCrypt.SaltLength > scrypt.SaltLengthMax:
|
||||
validator.Push(fmt.Errorf(errFmtFileAuthBackendPasswordOptionTooLarge, hashSCrypt, "salt_length", config.SCrypt.SaltLength, scrypt.SaltLengthMax))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -409,18 +409,22 @@ func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenSCryptOptio
|
|||
}
|
||||
|
||||
func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenSCryptOptionsTooHigh() {
|
||||
suite.config.File.Password.SCrypt.Iterations = 59
|
||||
suite.config.File.Password.SCrypt.BlockSize = 360287970189639672
|
||||
suite.config.File.Password.SCrypt.Parallelism = 1073741825
|
||||
suite.config.File.Password.SCrypt.KeyLength = 1374389534409
|
||||
suite.config.File.Password.SCrypt.SaltLength = 2147483647
|
||||
|
||||
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
||||
|
||||
suite.Assert().Len(suite.validator.Warnings(), 0)
|
||||
suite.Require().Len(suite.validator.Errors(), 3)
|
||||
suite.Require().Len(suite.validator.Errors(), 5)
|
||||
|
||||
suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: file: password: scrypt: option 'block_size' is configured as '360287970189639672' but must be less than or equal to '36028797018963967'")
|
||||
suite.Assert().EqualError(suite.validator.Errors()[1], "authentication_backend: file: password: scrypt: option 'key_length' is configured as '1374389534409' but must be less than or equal to '137438953440'")
|
||||
suite.Assert().EqualError(suite.validator.Errors()[2], "authentication_backend: file: password: scrypt: option 'salt_length' is configured as '2147483647' but must be less than or equal to '1024'")
|
||||
suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: file: password: scrypt: option 'iterations' is configured as '59' but must be less than or equal to '58'")
|
||||
suite.Assert().EqualError(suite.validator.Errors()[1], "authentication_backend: file: password: scrypt: option 'block_size' is configured as '360287970189639672' but must be less than or equal to '36028797018963967'")
|
||||
suite.Assert().EqualError(suite.validator.Errors()[2], "authentication_backend: file: password: scrypt: option 'parallelism' is configured as '1073741825' but must be less than or equal to '1073741823'")
|
||||
suite.Assert().EqualError(suite.validator.Errors()[3], "authentication_backend: file: password: scrypt: option 'key_length' is configured as '1374389534409' but must be less than or equal to '137438953440'")
|
||||
suite.Assert().EqualError(suite.validator.Errors()[4], "authentication_backend: file: password: scrypt: option 'salt_length' is configured as '2147483647' but must be less than or equal to '1024'")
|
||||
}
|
||||
|
||||
func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenArgon2OptionsTooLow() {
|
||||
|
@ -437,13 +441,14 @@ func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenArgon2Optio
|
|||
|
||||
suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: file: password: argon2: option 'iterations' is configured as '-1' but must be greater than or equal to '1'")
|
||||
suite.Assert().EqualError(suite.validator.Errors()[1], "authentication_backend: file: password: argon2: option 'parallelism' is configured as '-1' but must be greater than or equal to '1'")
|
||||
suite.Assert().EqualError(suite.validator.Errors()[2], "authentication_backend: file: password: argon2: option 'memory' is configured as '-1' but must be greater than or equal to '1'")
|
||||
suite.Assert().EqualError(suite.validator.Errors()[2], "authentication_backend: file: password: argon2: option 'memory' is configured as '-1' but must be greater than or equal to '8'")
|
||||
suite.Assert().EqualError(suite.validator.Errors()[3], "authentication_backend: file: password: argon2: option 'key_length' is configured as '1' but must be greater than or equal to '4'")
|
||||
suite.Assert().EqualError(suite.validator.Errors()[4], "authentication_backend: file: password: argon2: option 'salt_length' is configured as '-1' but must be greater than or equal to '1'")
|
||||
}
|
||||
|
||||
func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenArgon2OptionsTooHigh() {
|
||||
suite.config.File.Password.Argon2.Iterations = 9999999999
|
||||
suite.config.File.Password.Argon2.Memory = 4294967296
|
||||
suite.config.File.Password.Argon2.Parallelism = 16777216
|
||||
suite.config.File.Password.Argon2.KeyLength = 9999999998
|
||||
suite.config.File.Password.Argon2.SaltLength = 9999999997
|
||||
|
@ -455,6 +460,7 @@ func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenArgon2Optio
|
|||
|
||||
suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: file: password: argon2: option 'iterations' is configured as '9999999999' but must be less than or equal to '2147483647'")
|
||||
suite.Assert().EqualError(suite.validator.Errors()[1], "authentication_backend: file: password: argon2: option 'parallelism' is configured as '16777216' but must be less than or equal to '16777215'")
|
||||
suite.Assert().EqualError(suite.validator.Errors()[2], "authentication_backend: file: password: argon2: option 'memory' is configured as '4294967296' but must be less than or equal to '4294967295'")
|
||||
suite.Assert().EqualError(suite.validator.Errors()[3], "authentication_backend: file: password: argon2: option 'key_length' is configured as '9999999998' but must be less than or equal to '2147483647'")
|
||||
suite.Assert().EqualError(suite.validator.Errors()[4], "authentication_backend: file: password: argon2: option 'salt_length' is configured as '9999999997' but must be less than or equal to '2147483647'")
|
||||
}
|
||||
|
@ -468,7 +474,19 @@ func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenArgon2Memor
|
|||
suite.Assert().Len(suite.validator.Warnings(), 0)
|
||||
suite.Require().Len(suite.validator.Errors(), 1)
|
||||
|
||||
suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: file: password: argon2: option 'memory' is configured as '4' but must be greater than or equal to '32' or '4' (the value of 'parallelism) multiplied by '8'")
|
||||
suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: file: password: argon2: option 'memory' is configured as '4' but must be greater than or equal to '8'")
|
||||
}
|
||||
|
||||
func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenArgon2MemoryTooLowMultiplier() {
|
||||
suite.config.File.Password.Argon2.Memory = 8
|
||||
suite.config.File.Password.Argon2.Parallelism = 4
|
||||
|
||||
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
||||
|
||||
suite.Assert().Len(suite.validator.Warnings(), 0)
|
||||
suite.Require().Len(suite.validator.Errors(), 1)
|
||||
|
||||
suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: file: password: argon2: option 'memory' is configured as '8' but must be greater than or equal to '32' or '4' (the value of 'parallelism) multiplied by '8'")
|
||||
}
|
||||
|
||||
func (suite *FileBasedAuthenticationBackend) TestShouldRaiseErrorWhenBadAlgorithmDefined() {
|
||||
|
|
|
@ -838,7 +838,7 @@ func TestValidateOIDCClientRedirectURIsSupportingPrivateUseURISchemes(t *testing
|
|||
}
|
||||
|
||||
func MustDecodeSecret(value string) *schema.PasswordDigest {
|
||||
if secret, err := schema.NewPasswordDigest(value, true); err != nil {
|
||||
if secret, err := schema.DecodePasswordDigest(value); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
return secret
|
||||
|
|
|
@ -52,13 +52,7 @@ func OpenIDConnectAuthorization(ctx *middlewares.AutheliaCtx, rw http.ResponseWr
|
|||
return
|
||||
}
|
||||
|
||||
if issuer, err = ctx.IssuerURL(); err != nil {
|
||||
ctx.Logger.Errorf("Authorization Request with id '%s' on client with id '%s' could not be processed: error occurred determining issuer: %+v", requester.GetID(), clientID, err)
|
||||
|
||||
ctx.Providers.OpenIDConnect.WriteAuthorizeError(ctx, rw, requester, oidc.ErrIssuerCouldNotDerive)
|
||||
|
||||
return
|
||||
}
|
||||
issuer = ctx.RootURL()
|
||||
|
||||
userSession := ctx.GetSession()
|
||||
|
||||
|
|
|
@ -130,12 +130,7 @@ func OpenIDConnectConsentPOST(ctx *middlewares.AutheliaCtx) {
|
|||
query url.Values
|
||||
)
|
||||
|
||||
if redirectURI, err = ctx.IssuerURL(); err != nil {
|
||||
ctx.Logger.Errorf("Failed to parse the consent redirect URL: %+v", err)
|
||||
ctx.SetJSONError(messageOperationFailed)
|
||||
|
||||
return
|
||||
}
|
||||
redirectURI = ctx.RootURL()
|
||||
|
||||
if query, err = url.ParseQuery(consent.Form); err != nil {
|
||||
ctx.Logger.Errorf("Failed to parse the consent form values: %+v", err)
|
||||
|
|
|
@ -20,13 +20,7 @@ func OpenIDConnectConfigurationWellKnownGET(ctx *middlewares.AutheliaCtx) {
|
|||
err error
|
||||
)
|
||||
|
||||
if issuer, err = ctx.IssuerURL(); err != nil {
|
||||
ctx.Logger.Errorf("Error occurred determining OpenID Connect issuer details: %+v", err)
|
||||
|
||||
ctx.ReplyStatusCode(fasthttp.StatusBadRequest)
|
||||
|
||||
return
|
||||
}
|
||||
issuer = ctx.RootURL()
|
||||
|
||||
wellKnown := ctx.Providers.OpenIDConnect.GetOpenIDConnectWellKnownConfiguration(issuer.String())
|
||||
|
||||
|
@ -52,13 +46,7 @@ func OAuthAuthorizationServerWellKnownGET(ctx *middlewares.AutheliaCtx) {
|
|||
err error
|
||||
)
|
||||
|
||||
if issuer, err = ctx.IssuerURL(); err != nil {
|
||||
ctx.Logger.Errorf("Error occurred determining OpenID Connect issuer details: %+v", err)
|
||||
|
||||
ctx.ReplyStatusCode(fasthttp.StatusBadRequest)
|
||||
|
||||
return
|
||||
}
|
||||
issuer = ctx.RootURL()
|
||||
|
||||
wellKnown := ctx.Providers.OpenIDConnect.GetOAuth2WellKnownConfiguration(issuer.String())
|
||||
|
||||
|
|
|
@ -144,11 +144,7 @@ func handleOIDCWorkflowResponseWithTargetURL(ctx *middlewares.AutheliaCtx, targe
|
|||
return
|
||||
}
|
||||
|
||||
if issuerURL, err = ctx.IssuerURL(); err != nil {
|
||||
ctx.Error(fmt.Errorf("unable to get issuer for redirection: %w", err), messageAuthenticationFailed)
|
||||
|
||||
return
|
||||
}
|
||||
issuerURL = ctx.RootURL()
|
||||
|
||||
if targetURL.Host != issuerURL.Host {
|
||||
ctx.Error(fmt.Errorf("unable to redirect to '%s': target host '%s' does not match expected issuer host '%s'", targetURL, targetURL.Host, issuerURL.Host), messageAuthenticationFailed)
|
||||
|
@ -221,11 +217,7 @@ func handleOIDCWorkflowResponseWithID(ctx *middlewares.AutheliaCtx, id string) {
|
|||
form url.Values
|
||||
)
|
||||
|
||||
if targetURL, err = ctx.IssuerURL(); err != nil {
|
||||
ctx.Error(fmt.Errorf("unable to get issuer for redirection: %w", err), messageAuthenticationFailed)
|
||||
|
||||
return
|
||||
}
|
||||
targetURL = ctx.RootURL()
|
||||
|
||||
if form, err = consent.GetForm(); err != nil {
|
||||
ctx.Error(fmt.Errorf("unable to get authorization form values from consent session with challenge id '%s': %w", consent.ChallengeID, err), messageAuthenticationFailed)
|
||||
|
|
|
@ -3,7 +3,6 @@ package logging
|
|||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
@ -16,15 +15,10 @@ import (
|
|||
)
|
||||
|
||||
func TestShouldWriteLogsToFile(t *testing.T) {
|
||||
dir, err := os.MkdirTemp("/tmp", "logs-dir")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
defer os.RemoveAll(dir)
|
||||
dir := t.TempDir()
|
||||
|
||||
path := fmt.Sprintf("%s/authelia.log", dir)
|
||||
err = InitializeLogger(schema.LogConfiguration{Format: "text", FilePath: path, KeepStdout: false}, false)
|
||||
err := InitializeLogger(schema.LogConfiguration{Format: "text", FilePath: path, KeepStdout: false}, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
Logger().Info("This is a test")
|
||||
|
@ -39,15 +33,10 @@ func TestShouldWriteLogsToFile(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestShouldWriteLogsToFileAndStdout(t *testing.T) {
|
||||
dir, err := os.MkdirTemp("/tmp", "logs-dir")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
defer os.RemoveAll(dir)
|
||||
dir := t.TempDir()
|
||||
|
||||
path := fmt.Sprintf("%s/authelia.log", dir)
|
||||
err = InitializeLogger(schema.LogConfiguration{Format: "text", FilePath: path, KeepStdout: true}, false)
|
||||
err := InitializeLogger(schema.LogConfiguration{Format: "text", FilePath: path, KeepStdout: true}, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
Logger().Info("This is a test")
|
||||
|
@ -62,15 +51,10 @@ func TestShouldWriteLogsToFileAndStdout(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestShouldFormatLogsAsJSON(t *testing.T) {
|
||||
dir, err := os.MkdirTemp("/tmp", "logs-dir")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
defer os.RemoveAll(dir)
|
||||
dir := t.TempDir()
|
||||
|
||||
path := fmt.Sprintf("%s/authelia.log", dir)
|
||||
err = InitializeLogger(schema.LogConfiguration{Format: "json", FilePath: path, KeepStdout: false}, false)
|
||||
err := InitializeLogger(schema.LogConfiguration{Format: "json", FilePath: path, KeepStdout: false}, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
Logger().Info("This is a test")
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/asaskevich/govalidator"
|
||||
|
@ -81,7 +80,7 @@ func (ctx *AutheliaCtx) ReplyError(err error, message string) {
|
|||
ctx.Logger.Error(marshalErr)
|
||||
}
|
||||
|
||||
ctx.SetContentTypeBytes(contentTypeApplicationJSON)
|
||||
ctx.SetContentTypeApplicationJSON()
|
||||
ctx.SetBody(b)
|
||||
ctx.Logger.Debug(err)
|
||||
}
|
||||
|
@ -90,7 +89,7 @@ func (ctx *AutheliaCtx) ReplyError(err error, message string) {
|
|||
func (ctx *AutheliaCtx) ReplyStatusCode(statusCode int) {
|
||||
ctx.Response.Reset()
|
||||
ctx.SetStatusCode(statusCode)
|
||||
ctx.SetContentTypeBytes(contentTypeTextPlain)
|
||||
ctx.SetContentTypeTextPlain()
|
||||
ctx.SetBodyString(fmt.Sprintf("%d %s", statusCode, fasthttp.StatusMessage(statusCode)))
|
||||
}
|
||||
|
||||
|
@ -108,7 +107,7 @@ func (ctx *AutheliaCtx) ReplyJSON(data any, statusCode int) (err error) {
|
|||
ctx.SetStatusCode(statusCode)
|
||||
}
|
||||
|
||||
ctx.SetContentTypeBytes(contentTypeApplicationJSON)
|
||||
ctx.SetContentTypeApplicationJSON()
|
||||
ctx.SetBody(body)
|
||||
|
||||
return nil
|
||||
|
@ -145,7 +144,7 @@ func (ctx *AutheliaCtx) XForwardedProto() (proto []byte) {
|
|||
}
|
||||
|
||||
// XForwardedMethod return the content of the X-Forwarded-Method header.
|
||||
func (ctx *AutheliaCtx) XForwardedMethod() (method []byte) {
|
||||
func (ctx *AutheliaCtx) XForwardedMethod() []byte {
|
||||
return ctx.RequestCtx.Request.Header.PeekBytes(headerXForwardedMethod)
|
||||
}
|
||||
|
||||
|
@ -171,79 +170,61 @@ func (ctx *AutheliaCtx) XForwardedURI() (uri []byte) {
|
|||
return uri
|
||||
}
|
||||
|
||||
// XAutheliaURL return the content of the X-Authelia-URL header.
|
||||
func (ctx *AutheliaCtx) XAutheliaURL() (autheliaURL []byte) {
|
||||
// XOriginalURL returns the content of the X-Original-URL header.
|
||||
func (ctx *AutheliaCtx) XOriginalURL() []byte {
|
||||
return ctx.RequestCtx.Request.Header.PeekBytes(headerXOriginalURL)
|
||||
}
|
||||
|
||||
// XOriginalMethod return the content of the X-Original-Method header.
|
||||
func (ctx *AutheliaCtx) XOriginalMethod() []byte {
|
||||
return ctx.RequestCtx.Request.Header.PeekBytes(headerXOriginalMethod)
|
||||
}
|
||||
|
||||
// XAutheliaURL return the content of the X-Authelia-URL header which is used to communicate the location of the
|
||||
// portal when using proxies like Envoy.
|
||||
func (ctx *AutheliaCtx) XAutheliaURL() []byte {
|
||||
return ctx.RequestCtx.Request.Header.PeekBytes(headerXAutheliaURL)
|
||||
}
|
||||
|
||||
// QueryArgRedirect return the content of the rd query argument.
|
||||
func (ctx *AutheliaCtx) QueryArgRedirect() (val []byte) {
|
||||
return ctx.RequestCtx.QueryArgs().PeekBytes(queryArgRedirect)
|
||||
func (ctx *AutheliaCtx) QueryArgRedirect() []byte {
|
||||
return ctx.RequestCtx.QueryArgs().PeekBytes(qryArgRedirect)
|
||||
}
|
||||
|
||||
// BasePath returns the base_url as per the path visited by the client.
|
||||
func (ctx *AutheliaCtx) BasePath() (base string) {
|
||||
func (ctx *AutheliaCtx) BasePath() string {
|
||||
if baseURL := ctx.UserValueBytes(UserValueKeyBaseURL); baseURL != nil {
|
||||
return baseURL.(string)
|
||||
}
|
||||
|
||||
return base
|
||||
return ""
|
||||
}
|
||||
|
||||
// ExternalRootURL gets the X-Forwarded-Proto, X-Forwarded-Host headers and the BasePath and forms them into a URL.
|
||||
func (ctx *AutheliaCtx) ExternalRootURL() (string, error) {
|
||||
protocol := ctx.XForwardedProto()
|
||||
if protocol == nil {
|
||||
return "", errMissingXForwardedProto
|
||||
// BasePathSlash is the same as BasePath but returns a final slash as well.
|
||||
func (ctx *AutheliaCtx) BasePathSlash() string {
|
||||
if baseURL := ctx.UserValueBytes(UserValueKeyBaseURL); baseURL != nil {
|
||||
return baseURL.(string) + strSlash
|
||||
}
|
||||
|
||||
host := ctx.XForwardedHost()
|
||||
if host == nil {
|
||||
return "", errMissingXForwardedHost
|
||||
}
|
||||
|
||||
externalRootURL := fmt.Sprintf("%s://%s", protocol, host)
|
||||
|
||||
if base := ctx.BasePath(); base != "" {
|
||||
externalBaseURL, err := url.ParseRequestURI(externalRootURL)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
externalBaseURL.Path = path.Join(externalBaseURL.Path, base)
|
||||
|
||||
return externalBaseURL.String(), nil
|
||||
}
|
||||
|
||||
return externalRootURL, nil
|
||||
return strSlash
|
||||
}
|
||||
|
||||
// IssuerURL returns the expected Issuer.
|
||||
func (ctx *AutheliaCtx) IssuerURL() (issuerURL *url.URL, err error) {
|
||||
issuerURL = &url.URL{
|
||||
Scheme: "https",
|
||||
// RootURL returns the Root URL.
|
||||
func (ctx *AutheliaCtx) RootURL() (issuerURL *url.URL) {
|
||||
return &url.URL{
|
||||
Scheme: string(ctx.XForwardedProto()),
|
||||
Host: string(ctx.XForwardedHost()),
|
||||
Path: ctx.BasePath(),
|
||||
}
|
||||
|
||||
if scheme := ctx.XForwardedProto(); scheme != nil {
|
||||
issuerURL.Scheme = string(scheme)
|
||||
}
|
||||
|
||||
if host := ctx.XForwardedHost(); len(host) != 0 {
|
||||
issuerURL.Host = string(host)
|
||||
} else {
|
||||
return nil, errMissingXForwardedHost
|
||||
}
|
||||
|
||||
if base := ctx.BasePath(); base != "" {
|
||||
issuerURL.Path = path.Join(issuerURL.Path, base)
|
||||
}
|
||||
|
||||
return issuerURL, nil
|
||||
}
|
||||
|
||||
// XOriginalURL return the content of the X-Original-URL header.
|
||||
func (ctx *AutheliaCtx) XOriginalURL() []byte {
|
||||
return ctx.RequestCtx.Request.Header.PeekBytes(headerXOriginalURL)
|
||||
// RootURLSlash is the same as RootURL but includes a final slash as well.
|
||||
func (ctx *AutheliaCtx) RootURLSlash() (issuerURL *url.URL) {
|
||||
return &url.URL{
|
||||
Scheme: string(ctx.XForwardedProto()),
|
||||
Host: string(ctx.XForwardedHost()),
|
||||
Path: ctx.BasePathSlash(),
|
||||
}
|
||||
}
|
||||
|
||||
// GetSession return the user session. Any update will be saved in cache.
|
||||
|
@ -264,7 +245,7 @@ func (ctx *AutheliaCtx) SaveSession(userSession session.UserSession) error {
|
|||
|
||||
// ReplyOK is a helper method to reply ok.
|
||||
func (ctx *AutheliaCtx) ReplyOK() {
|
||||
ctx.SetContentTypeBytes(contentTypeApplicationJSON)
|
||||
ctx.SetContentTypeApplicationJSON()
|
||||
ctx.SetBody(okMessageBytes)
|
||||
}
|
||||
|
||||
|
@ -377,7 +358,7 @@ func (ctx *AutheliaCtx) SpecialRedirect(uri string, statusCode int) {
|
|||
statusCode = fasthttp.StatusFound
|
||||
}
|
||||
|
||||
ctx.SetContentTypeBytes(contentTypeTextHTML)
|
||||
ctx.SetContentTypeTextHTML()
|
||||
ctx.SetStatusCode(statusCode)
|
||||
|
||||
u := fasthttp.AcquireURI()
|
||||
|
@ -400,3 +381,18 @@ func (ctx *AutheliaCtx) RecordAuthentication(success, regulated bool, method str
|
|||
|
||||
ctx.Providers.Metrics.RecordAuthentication(success, regulated, method)
|
||||
}
|
||||
|
||||
// SetContentTypeTextPlain efficiently sets the Content-Type header to 'text/plain; charset=utf-8'.
|
||||
func (ctx *AutheliaCtx) SetContentTypeTextPlain() {
|
||||
ctx.SetContentTypeBytes(contentTypeTextPlain)
|
||||
}
|
||||
|
||||
// SetContentTypeTextHTML efficiently sets the Content-Type header to 'text/html; charset=utf-8'.
|
||||
func (ctx *AutheliaCtx) SetContentTypeTextHTML() {
|
||||
ctx.SetContentTypeBytes(contentTypeTextHTML)
|
||||
}
|
||||
|
||||
// SetContentTypeApplicationJSON efficiently sets the Content-Type header to 'application/json; charset=utf-8'.
|
||||
func (ctx *AutheliaCtx) SetContentTypeApplicationJSON() {
|
||||
ctx.SetContentTypeBytes(contentTypeApplicationJSON)
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ func TestIssuerURL(t *testing.T) {
|
|||
name string
|
||||
proto, host, base string
|
||||
expected string
|
||||
err string
|
||||
}{
|
||||
{
|
||||
name: "Standard",
|
||||
|
@ -36,7 +35,7 @@ func TestIssuerURL(t *testing.T) {
|
|||
{
|
||||
name: "NoHost",
|
||||
proto: "https", host: "", base: "",
|
||||
err: "Missing header X-Forwarded-Host",
|
||||
expected: "https:",
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -52,21 +51,14 @@ func TestIssuerURL(t *testing.T) {
|
|||
mock.Ctx.SetUserValue("base_url", tc.base)
|
||||
}
|
||||
|
||||
actual, err := mock.Ctx.IssuerURL()
|
||||
actual := mock.Ctx.RootURL()
|
||||
|
||||
switch tc.err {
|
||||
case "":
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, actual)
|
||||
|
||||
assert.Equal(t, tc.expected, actual.String())
|
||||
assert.Equal(t, tc.proto, actual.Scheme)
|
||||
assert.Equal(t, tc.host, actual.Host)
|
||||
assert.Equal(t, tc.base, actual.Path)
|
||||
default:
|
||||
assert.EqualError(t, err, tc.err)
|
||||
assert.Nil(t, actual)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ var (
|
|||
|
||||
headerXForwardedURI = []byte("X-Forwarded-URI")
|
||||
headerXOriginalURL = []byte("X-Original-URL")
|
||||
headerXOriginalMethod = []byte("X-Original-Method")
|
||||
headerXForwardedMethod = []byte("X-Forwarded-Method")
|
||||
|
||||
headerVary = []byte(fasthttp.HeaderVary)
|
||||
|
@ -67,13 +68,17 @@ var (
|
|||
const (
|
||||
strProtoHTTPS = "https"
|
||||
strProtoHTTP = "http"
|
||||
strSlash = "/"
|
||||
|
||||
queryArgRedirect = "rd"
|
||||
queryArgToken = "token"
|
||||
)
|
||||
|
||||
var (
|
||||
protoHTTPS = []byte(strProtoHTTPS)
|
||||
protoHTTP = []byte(strProtoHTTP)
|
||||
|
||||
queryArgRedirect = []byte("rd")
|
||||
qryArgRedirect = []byte(queryArgRedirect)
|
||||
|
||||
// UserValueKeyBaseURL is the User Value key where we store the Base URL.
|
||||
UserValueKeyBaseURL = []byte("base_url")
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"net/mail"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
|
@ -62,7 +63,7 @@ func IdentityVerificationStart(args IdentityVerificationStartArgs, delayFunc Tim
|
|||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
|
||||
ss, err := token.SignedString([]byte(ctx.Configuration.JWTSecret))
|
||||
signedToken, err := token.SignedString([]byte(ctx.Configuration.JWTSecret))
|
||||
if err != nil {
|
||||
ctx.Error(err, messageOperationFailed)
|
||||
return
|
||||
|
@ -73,23 +74,23 @@ func IdentityVerificationStart(args IdentityVerificationStartArgs, delayFunc Tim
|
|||
return
|
||||
}
|
||||
|
||||
var (
|
||||
uri string
|
||||
)
|
||||
|
||||
if uri, err = ctx.ExternalRootURL(); err != nil {
|
||||
ctx.Error(err, messageOperationFailed)
|
||||
return
|
||||
}
|
||||
|
||||
disableHTML := false
|
||||
if ctx.Configuration.Notifier.SMTP != nil {
|
||||
disableHTML = ctx.Configuration.Notifier.SMTP.DisableHTMLEmails
|
||||
}
|
||||
|
||||
linkURL := ctx.RootURL()
|
||||
|
||||
query := linkURL.Query()
|
||||
|
||||
query.Set(queryArgToken, signedToken)
|
||||
|
||||
linkURL.Path = path.Join(linkURL.Path, args.TargetEndpoint)
|
||||
linkURL.RawQuery = query.Encode()
|
||||
|
||||
values := templates.EmailIdentityVerificationValues{
|
||||
Title: args.MailTitle,
|
||||
LinkURL: fmt.Sprintf("%s%s?token=%s", uri, args.TargetEndpoint, ss),
|
||||
LinkURL: linkURL.String(),
|
||||
LinkText: args.MailButtonContent,
|
||||
DisplayName: identity.DisplayName,
|
||||
RemoteIP: ctx.RemoteIP().String(),
|
||||
|
|