Merge branch 'master' into patch-1

pull/4861/head
James Elliott 2023-02-11 15:38:41 +11:00 committed by GitHub
commit 7a2c830b2e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
180 changed files with 2749 additions and 1837 deletions

2
.gitignore vendored
View File

@ -25,3 +25,5 @@ authelia-image-dev.tar
/authelia
__debug_bin
internal/suites/common/pki/ca/ca.private.pem

View File

@ -15,7 +15,7 @@ RUN yarn global add pnpm && \
# =======================================
# ===== Build image for the backend =====
# =======================================
FROM golang:1.19.5-alpine AS builder-backend
FROM golang:1.20.0-alpine AS builder-backend
WORKDIR /go/src/app

View File

@ -13,7 +13,7 @@ RUN yarn install --frozen-lockfile && yarn build
# =======================================
# ===== Build image for the backend =====
# =======================================
FROM golang:1.19.5-alpine AS builder-backend
FROM golang:1.20.0-alpine AS builder-backend
WORKDIR /go/src/app

View File

@ -816,7 +816,7 @@ paths:
summary: OAuth 2.0 Authorization Server Metadata
description: >
This endpoint retrieves the OAuth 2.0 Authorization Server Metadata document (RFC8414) used by clients to
perform discovery for an OAuth 2.0 Authorization Server. See https://www.rfc-editor.org/rfc/rfc8414.
perform discovery for an OAuth 2.0 Authorization Server. See https://datatracker.ietf.org/doc/html/rfc8414.
responses:
"200":
description: OK
@ -2822,8 +2822,8 @@ components:
description: >
JSON array containing a list of the JWS [JWS] signing algorithms (alg values) [JWA] supported by the
UserInfo Endpoint to encode the Claims in a JWT [JWT]. The value none MAY be included. See Also:
JWS: https://datatracker.ietf.org/doc/html/rfc7515 JWA: https://datatracker.ietf.org/doc/html/rfc7518 JWT:
https://datatracker.ietf.org/doc/html/rfc7519
JWS: https://datatracker.ietf.org/doc/html/rfc7515 JWA: https://datatracker.ietf.org/doc/html/rfc7518
JWT: https://datatracker.ietf.org/doc/html/rfc7519
type: array
example: ["none", "RS256"]
items:

View File

@ -108,8 +108,9 @@ func genCLIDocWriteIndex(path, name string) (err error) {
func prepend(input string) string {
now := time.Now()
pathz := strings.Split(strings.Replace(input, ".md", "", 1), "\\")
parts := strings.Split(pathz[len(pathz)-1], "_")
_, filename := filepath.Split(strings.Replace(input, ".md", "", 1))
parts := strings.Split(filename, "_")
cmd := parts[0]

View File

@ -64,7 +64,7 @@ func cmdBootstrapRun(_ *cobra.Command, _ []string) {
fmt.Println()
bootstrapPrintln("Run 'authelia-scripts suites setup Standalone' to start Authelia and visit https://home.example.com:8080.")
bootstrapPrintln("More details at https://github.com/authelia/authelia/blob/master/docs/getting-started.md")
bootstrapPrintln("More details at https://www.authelia.com/contributing/development/build-and-test/")
}
var hostEntries = []HostEntry{

View File

@ -426,7 +426,7 @@ authentication_backend:
## changed once attributed to a user otherwise it would break the configuration for that user. Technically,
## non-unique attributes like 'mail' can also be used but we don't recommend using them, we instead advise to use
## a filter to perform alternative lookups and the attributes mentioned above (sAMAccountName and uid) to
## follow https://www.ietf.org/rfc/rfc2307.txt.
## follow https://datatracker.ietf.org/doc/html/rfc2307.
# username_attribute: uid
## The additional_users_dn is prefixed to base_dn and delimited by a comma when searching for users.

View File

@ -1 +1 @@
canonifyURLs = false
baseurl = "https://authelia-staging.netlify.app/"

View File

@ -1 +0,0 @@
canonifyURLs = false

View File

@ -1,2 +1 @@
canonifyURLs = false
baseurl = "https://authelia-staging.netlify.app/"

View File

@ -256,8 +256,8 @@ truncation that [Bcrypt] does. It is not supported by many other systems.*
Controls the hashing cost when hashing passwords using [Bcrypt].
[Argon2]: https://www.rfc-editor.org/rfc/rfc9106.html
[Argon2]: https://datatracker.ietf.org/doc/html/rfc9106
[Scrypt]: https://en.wikipedia.org/wiki/Scrypt
[PBKDF2]: https://www.ietf.org/rfc/rfc2898.html
[PBKDF2]: https://datatracker.ietf.org/doc/html/rfc2898
[SHA2 Crypt]: https://www.akkadia.org/drepper/SHA-crypt.txt
[Bcrypt]: https://en.wikipedia.org/wiki/Bcrypt

View File

@ -316,4 +316,4 @@ for your users.
[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
[RFC2307]: https://datatracker.ietf.org/doc/html/rfc2307

View File

@ -119,7 +119,7 @@ identity_providers:
clients:
- id: myapp
description: My Application
secret: '$plaintext$this_is_a_secret'
secret: '$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng' # The digest of 'insecure_secret'.
sector_identifier: ''
public: false
authorization_policy: two_factor
@ -170,9 +170,9 @@ encoded PEM format used to sign/encrypt the [OpenID Connect 1.0] [JWT]'s. When c
JSON key's in the JWKs [Discoverable Endpoint](../../integration/openid-connect/introduction.md#discoverable-endpoints)
as per [RFC7517].
[RFC7517]: https://www.rfc-editor.org/rfc/rfc7517
[x5c]: https://www.rfc-editor.org/rfc/rfc7517#section-4.7
[x5t]: https://www.rfc-editor.org/rfc/rfc7517#section-4.8
[RFC7517]: https://datatracker.ietf.org/doc/html/rfc7517
[x5c]: https://datatracker.ietf.org/doc/html/rfc7517#section-4.7
[x5t]: https://datatracker.ietf.org/doc/html/rfc7517#section-4.8
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
@ -251,7 +251,7 @@ this value.
{{< confkey type="string" default="public_clients_only" required="no" >}}
[Proof Key for Code Exchange](https://www.rfc-editor.org/rfc/rfc7636.html) enforcement policy: if specified, must be
[Proof Key for Code Exchange](https://datatracker.ietf.org/doc/html/rfc7636) enforcement policy: if specified, must be
either `never`, `public_clients_only` or `always`.
If set to `public_clients_only` (default), [PKCE] will be required for public clients using the
@ -402,9 +402,6 @@ This enables the public client type for this client. This is for clients that ar
confidentiality of credentials, you can read more about client types in [RFC6749 Section 2.1]. This is particularly
useful for SPA's and CLI tools. This option requires setting the [client secret](#secret) to a blank string.
In addition to the standard rules for redirect URIs, public clients can use the `urn:ietf:wg:oauth:2.0:oob` redirect
URI.
#### redirect_uris
{{< confkey type="list(string)" required="yes" >}}
@ -420,7 +417,6 @@ their redirect URIs are as follows:
attempt to authorize will fail and an error will be generated.
2. The redirect URIs are case-sensitive.
3. The URI must include a scheme and that scheme must be one of `http` or `https`.
4. The client can ignore rule 3 and use `urn:ietf:wg:oauth:2.0:oob` if it is a [public](#public) client type.
#### audience
@ -434,30 +430,41 @@ A list of audiences this client is allowed to request.
A list of scopes to allow this client to consume. See
[scope definitions](../../integration/openid-connect/introduction.md#scope-definitions) for more information. The
documentation for the application you want to use with Authelia will most-likely provide you with the scopes to allow.
documentation for the application you are trying to configure [OpenID Connect 1.0] for will likely have a list of scopes
or claims required which can be matched with the above guide.
#### grant_types
{{< confkey type="list(string)" default="refresh_token, authorization_code" required="no" >}}
A list of grant types this client can return. *It is recommended that this isn't configured at this time unless you
know what you're doing*. Valid options are: `implicit`, `refresh_token`, `authorization_code`, `password`,
`client_credentials`.
*__Important Note:__ It is recommended that this isn't configured at this time unless you know what you're doing.*
The list of grant types this client is permitted to use in order to obtain access to the relevant tokens.
See the [Grant Types](../../integration/openid-connect/introduction.md#grant-types) section of the
[OpenID Connect 1.0 Integration Guide](../../integration/openid-connect/introduction.md#grant-types) for more information.
#### response_types
{{< confkey type="list(string)" default="code" required="no" >}}
A list of response types this client can return. *It is recommended that this isn't configured at this time unless you
know what you're doing*. Valid options are: `code`, `code id_token`, `id_token`, `token id_token`, `token`,
`token id_token code`.
*__Important Note:__ It is recommended that this isn't configured at this time unless you know what you're doing.*
A list of response types this client supports.
See the [Response Types](../../integration/openid-connect/introduction.md#response-types) section of the
[OpenID Connect 1.0 Integration Guide](../../integration/openid-connect/introduction.md#response-types) for more information.
#### response_modes
{{< confkey type="list(string)" default="form_post, query, fragment" required="no" >}}
A list of response modes this client can return. It is recommended that this isn't configured at this time unless you
know what you're doing. Potential values are `form_post`, `query`, and `fragment`.
*__Important Note:__ It is recommended that this isn't configured at this time unless you know what you're doing.*
A list of response modes this client supports.
See the [Response Modes](../../integration/openid-connect/introduction.md#response-modes) section of the
[OpenID Connect 1.0 Integration Guide](../../integration/openid-connect/introduction.md#response-modes) for more information.
#### authorization_policy
@ -495,13 +502,17 @@ more information.
{{< confkey type="string" default="auto" required="no" >}}
*__Important Note:__ the `implicit` consent mode is not technically part of the specification. It theoretically could be
misused in certain conditions specifically with public clients or when the client credentials (i.e. client secret) has
been exposed to an attacker. For these reasons this mode is discouraged.*
Configures the consent mode. The following table describes the different modes:
| Value | Description |
|:--------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|
|:--------------:|:----------------------------------------------------------------------------------------------------------------------------------------------:|
| auto | Automatically determined (default). Uses `explicit` unless [pre_configured_consent_duration] is specified in which case uses `pre-configured`. |
| explicit | Requires the user provide unique explicit consent for every authorization. |
| 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. |
| implicit | Automatically assumes consent for every authorization, never asking the user if they wish to give consent. |
| pre-configured | Allows the end-user to remember their consent for the [pre_configured_consent_duration]. |
[pre_configured_consent_duration]: #preconfiguredconsentduration
@ -530,12 +541,12 @@ To integrate Authelia's [OpenID Connect 1.0] implementation with a relying party
[token lifespan]: https://docs.apigee.com/api-platform/antipatterns/oauth-long-expiration
[OpenID Connect 1.0]: https://openid.net/connect/
[JWT]: https://www.rfc-editor.org/rfc/rfc7519.html
[RFC6234]: https://www.rfc-editor.org/rfc/rfc6234.html
[RFC4648]: https://www.rfc-editor.org/rfc/rfc4648.html
[RFC7468]: https://www.rfc-editor.org/rfc/rfc7468.html
[RFC6749 Section 2.1]: https://www.rfc-editor.org/rfc/rfc6749.html#section-2.1
[PKCE]: https://www.rfc-editor.org/rfc/rfc7636.html
[JWT]: https://datatracker.ietf.org/doc/html/rfc7519
[RFC6234]: https://datatracker.ietf.org/doc/html/rfc6234
[RFC4648]: https://datatracker.ietf.org/doc/html/rfc4648
[RFC7468]: https://datatracker.ietf.org/doc/html/rfc7468
[RFC6749 Section 2.1]: https://datatracker.ietf.org/doc/html/rfc6749#section-2.1
[PKCE]: https://datatracker.ietf.org/doc/html/rfc7636
[Authorization Code Flow]: https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth
[Subject Identifier Type]: https://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes
[Pairwise Identifier Algorithm]: https://openid.net/specs/openid-connect-core-1_0.html#PairwiseAlg

View File

@ -164,7 +164,7 @@ characters and the user password is changed to this value.
{{< confkey type="string" required="yes" >}}
The sender is used to construct both the SMTP command `MAIL FROM` and to add the `FROM` header. This address must be
in [RFC5322](https://www.rfc-editor.org/rfc/rfc5322.html#section-3.4) format. This means it must one of two formats:
in [RFC5322](https://datatracker.ietf.org/doc/html/rfc5322#section-3.4) format. This means it must one of two formats:
* jsmith@domain.com
* John Smith <jsmith@domain.com>

View File

@ -35,10 +35,18 @@ The way this format works is you can either configure an integer or a string in
supply an integer, it is considered a representation of seconds. If you supply a string, it parses the string in blocks
of quantities and units (number followed by a unit letter). For example `5h` indicates a quantity of 5 units of `h`.
The following is ignored:
- all spaces
- leading zeros
While you can use multiple of these blocks in combination, we suggest keeping it simple and use a single value.
### Unit Legend
#### Short Units
These values have been available for a long time.
| Unit | Associated Letter |
|:-------:|:-----------------:|
| Years | y |
@ -49,6 +57,21 @@ While you can use multiple of these blocks in combination, we suggest keeping it
| Minutes | m |
| Seconds | s |
#### Long Units
These values are more human readable but have only been available since v4.38.0.
| Unit | Human Readable Long Unit |
|:------------:|:-----------------------------:|
| Years | `year`, `years` |
| Months | `month`, `months` |
| Weeks | `week`, `weeks` |
| Days | `day`, `days` |
| Hours | `hour`, `hours` |
| Minutes | `minute`, `minutes` |
| Seconds | `second`, `seconds` |
| Milliseconds | `millisecond`, `milliseconds` |
### Examples
| Desired Value | Configuration Examples |
@ -154,7 +177,7 @@ The value must be one or more certificates encoded in the DER base64 ([RFC4648])
### private_key
{{< confkey type="string" required="yes" >}}
{{< confkey type="string" required="no" >}}
*__Important Note:__ This can also be defined using a [secret](../methods/secrets.md) which is __strongly recommended__
especially for containerized deployments.*
@ -163,6 +186,8 @@ The private key to be used with the [certificate_chain](#certificatechain) for m
The value must be one private key encoded in the DER base64 ([RFC4648]) encoded PEM format.
[RFC4648]: https://datatracker.ietf.org/doc/html/rfc4648
## Server Buffers
### read

View File

@ -172,5 +172,5 @@ at least a minimal configuration that has the storage backend connection details
See the [CLI Documentation](../../reference/cli/authelia/authelia_storage_user_totp_export.md) for methods to perform
exports.
[RFC4226]: https://www.rfc-editor.org/rfc/rfc4226.html
[RFC6238]: https://www.rfc-editor.org/rfc/rfc6238.html
[RFC4226]: https://datatracker.ietf.org/doc/html/rfc4226
[RFC6238]: https://datatracker.ietf.org/doc/html/rfc6238

View File

@ -588,8 +588,8 @@ The match type `Equals` matches if the value extracted from the pattern is equal
match value is a list/slice).
The regex groups are case-insensitive due to the fact that the regex groups are used in domain criteria and domain names
should not be compared in a case-sensitive way as per the [RFC4343](https://www.rfc-editor.org/rfc/rfc4343.html)
abstract and [RFC3986 Section 3.2.2](https://www.rfc-editor.org/rfc/rfc3986#section-3.2.2).
should not be compared in a case-sensitive way as per the [RFC4343](https://datatracker.ietf.org/doc/html/rfc4343)
abstract and [RFC3986 Section 3.2.2](https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2).
We do not currently apply any other normalization to usernames or groups when matching these groups. As such it's
generally *__not recommended__* to use these patterns with usernames or groups which contain characters that are not
@ -664,6 +664,6 @@ access_control:
policy: bypass
```
[RFC7231]: https://www.rfc-editor.org/rfc/rfc7231.html
[RFC5789]: https://www.rfc-editor.org/rfc/rfc5789.html
[RFC4918]: https://www.rfc-editor.org/rfc/rfc4918.html
[RFC7231]: https://datatracker.ietf.org/doc/html/rfc7231
[RFC5789]: https://datatracker.ietf.org/doc/html/rfc5789
[RFC4918]: https://datatracker.ietf.org/doc/html/rfc4918

View File

@ -137,11 +137,12 @@ cookies for this domain.
For example if Authelia is accessible via the URL `https://auth.example.com` the domain should be either
`auth.example.com` or `example.com`.
Please note most good DynamicDNS solutions fall into a specially protected group of domains and browsers do not allow
you to write cookies for the root domain. i.e. if you have been assigned `john.duckdns.org` you can't use `duckdns.org`
for the domain value as browsers will not allow `john.duckdns.org` to read or write cookies for `duckdns.org`.
The value must not match a domain on the [Public Suffix List](https://publicsuffix.org/list/) as browsers do not allow
websites to write cookies for these domains. This includes most Dynamic DNS services such as `duckdns.org`. You should
use your domain instead of `duckdns.org` for this value, for example `example.duckdns.org`.
Consequently, if you have `john.duckdns.org` and `mary.duckdns.org` you cannot share cookies between these domains.
Consequently, if you have `example.duckdns.org` and `example-auth.duckdns.org` you cannot share cookies between these
domains.
#### authelia_url

View File

@ -21,7 +21,7 @@ In order to build and contribute to __Authelia__, you need to make sure the foll
* General:
* [git]
* Backend Development:
* [go] *(v1.19 or greater)*
* [go] *(v1.20 or greater)*
* [gcc]
* Frontend Development
* [Node.js] *(v18 or greater)*

View File

@ -22,14 +22,7 @@ community: true
## Before You Begin
### Common Notes
1. You are *__required__* to utilize a unique client id for every client.
2. The client id on this page is merely an example and you can theoretically use any alphanumeric string.
3. You *__should not__* use the client secret in this example, We *__strongly recommend__* reading the
[Generating Client Secrets] guide instead.
[Generating Client Secrets]: ../specific-information.md#generating-client-secrets
{{% oidc-common %}}
### Assumptions
@ -38,7 +31,7 @@ This example makes the following assumptions:
* __Application Root URL:__ `https://guacamole.example.com`
* __Authelia Root URL:__ `https://auth.example.com`
* __Client ID:__ `guacamole`
* __Client Secret:__ `guacamole_client_secret`
* __Client Secret:__ `insecure_secret`
## Configuration
@ -66,7 +59,7 @@ The following YAML configuration is an example __Authelia__
```yaml
- id: guacamole
description: Apache Guacamole
secret: '$plaintext$guacamole_client_secret'
secret: '$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng' # The digest of 'insecure_secret'.
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -22,14 +22,7 @@ community: true
## Before You Begin
### Common Notes
1. You are *__required__* to utilize a unique client id for every client.
2. The client id on this page is merely an example and you can theoretically use any alphanumeric string.
3. You *__should not__* use the client secret in this example, We *__strongly recommend__* reading the
[Generating Client Secrets] guide instead.
[Generating Client Secrets]: ../specific-information.md#generating-client-secrets
{{% oidc-common %}}
### Assumptions
@ -38,7 +31,7 @@ This example makes the following assumptions:
* __Application Root URL:__ `https://argocd.example.com`
* __Authelia Root URL:__ `https://auth.example.com`
* __Client ID:__ `argocd`
* __Client Secret:__ `argocd_client_secret`
* __Client Secret:__ `insecure_secret`
* __CLI Client ID:__ `argocd-cli`
## Configuration
@ -51,7 +44,7 @@ To configure [Argo CD] to utilize Authelia as an [OpenID Connect 1.0] Provider u
name: Authelia
issuer: https://auth.example.com
clientID: argocd
clientSecret: argocd_client_secret
clientSecret: insecure_secret
cliClientID: argocd-cli
requestedScopes:
- openid
@ -69,7 +62,7 @@ which will operate with the above example:
```yaml
- id: argocd
description: Argo CD
secret: '$plaintext$argocd_client_secret'
secret: '$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng' # The digest of 'insecure_secret'.
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -22,14 +22,7 @@ community: true
## Before You Begin
### Common Notes
1. You are *__required__* to utilize a unique client id for every client.
2. The client id on this page is merely an example and you can theoretically use any alphanumeric string.
3. You *__should not__* use the client secret in this example, We *__strongly recommend__* reading the
[Generating Client Secrets] guide instead.
[Generating Client Secrets]: ../specific-information.md#generating-client-secrets
{{% oidc-common %}}
### Assumptions
@ -38,13 +31,13 @@ This example makes the following assumptions:
* __Application Root URL:__ `https://bookstack.example.com`
* __Authelia Root URL:__ `https://auth.example.com`
* __Client ID:__ `bookstack`
* __Client Secret:__ `bookstack_client_secret`
* __Client Secret:__ `insecure_secret`
*__Important Note:__ [BookStack] does not properly URL encode the secret per [RFC6749 Appendix B] at the time this
article was last modified (noted at the bottom). This means you'll either have to use only alphanumeric characters for
the secret or URL encode the secret yourself.*
[RFC6749 Appendix B]: https://www.rfc-editor.org/rfc/rfc6749#appendix-B
[RFC6749 Appendix B]: https://datatracker.ietf.org/doc/html/rfc6749#appendix-B
## Configuration
@ -58,7 +51,7 @@ To configure [BookStack] to utilize Authelia as an [OpenID Connect 1.0] Provider
2. OIDC_NAME: `Authelia`
3. OIDC_DISPLAY_NAME_CLAIMS: `name`
4. OIDC_CLIENT_ID: `bookstack`
5. OIDC_CLIENT_SECRET: `bookstack_client_secret`
5. OIDC_CLIENT_SECRET: `insecure_secret`
6. OIDC_ISSUER: `https://auth.example.com`
7. OIDC_ISSUER_DISCOVER: `true`
@ -71,7 +64,7 @@ which will operate with the above example:
```yaml
- id: bookstack
description: BookStack
secret: '$plaintext$bookstack_client_secret'
secret: '$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng' # The digest of 'insecure_secret'.
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -20,14 +20,7 @@ community: true
## Before You Begin
### Common Notes
1. You are *__required__* to utilize a unique client id for every client.
2. The client id on this page is merely an example and you can theoretically use any alphanumeric string.
3. You *__should not__* use the client secret in this example, We *__strongly recommend__* reading the
[Generating Client Secrets] guide instead.
[Generating Client Secrets]: ../specific-information.md#generating-client-secrets
{{% oidc-common %}}
### Assumptions
@ -36,13 +29,13 @@ This example makes the following assumptions:
* __Cloudflare Team Name:__ `example-team`
* __Authelia Root URL:__ `https://auth.example.com`
* __Client ID:__ `cloudflare`
* __Client Secret:__ `cloudflare_client_secret`
* __Client Secret:__ `insecure_secret`
*__Important Note:__ [Cloudflare Zero Trust] does not properly URL encode the secret per [RFC6749 Appendix B] at the
time this article was last modified (noted at the bottom). This means you'll either have to use only alphanumeric
characters for the secret or URL encode the secret yourself.*
[RFC6749 Appendix B]: https://www.rfc-editor.org/rfc/rfc6749#appendix-B
[RFC6749 Appendix B]: https://datatracker.ietf.org/doc/html/rfc6749#appendix-B
## Configuration
@ -62,7 +55,7 @@ To configure [Cloudflare Zero Trust] to utilize Authelia as an [OpenID Connect 1
6. Set the following values:
1. Name: `Authelia`
2. App ID: `cloudflare`
3. Client Secret: `cloudflare_client_secret`
3. Client Secret: `insecure_secret`
4. Auth URL: `https://auth.example.com/api/oidc/authorization`
5. Token URL: `https://auth.example.com/api/oidc/token`
6. Certificate URL: `https://auth.example.com/jwks.json`
@ -79,7 +72,7 @@ which will operate with the above example:
```yaml
- id: cloudflare
description: Cloudflare ZeroTrust
secret: '$plaintext$cloudflare_client_secret'
secret: '$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng' # The digest of 'insecure_secret'.
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -22,14 +22,7 @@ community: true
## Before You Begin
### Common Notes
1. You are *__required__* to utilize a unique client id for every client.
2. The client id on this page is merely an example and you can theoretically use any alphanumeric string.
3. You *__should not__* use the client secret in this example, We *__strongly recommend__* reading the
[Generating Client Secrets] guide instead.
[Generating Client Secrets]: ../specific-information.md#generating-client-secrets
{{% oidc-common %}}
### Assumptions
@ -38,7 +31,7 @@ This example makes the following assumptions:
* __Application Root URL:__ `https://gitea.example.com`
* __Authelia Root URL:__ `https://auth.example.com`
* __Client ID:__ `gitea`
* __Client Secret:__ `gitea_client_secret`
* __Client Secret:__ `insecure_secret`
## Configuration
@ -54,7 +47,7 @@ To configure [Gitea] to utilize Authelia as an [OpenID Connect 1.0] Provider:
1. Authentication Name: `authelia`
2. OAuth2 Provider: `OpenID Connect`
3. Client ID (Key): `gitea`
4. Client Secret: `gitea_client_secret`
4. Client Secret: `insecure_secret`
5. OpenID Connect Auto Discovery URL: `https://auth.example.com/.well-known/openid-configuration`
{{< figure src="gitea.png" alt="Gitea" width="300" >}}
@ -86,7 +79,7 @@ will operate with the above example:
```yaml
- id: gitea
description: Gitea
secret: '$plaintext$gitea_client_secret'
secret: '$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng' # The digest of 'insecure_secret'.
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -22,14 +22,7 @@ community: true
## Before You Begin
### Common Notes
1. You are *__required__* to utilize a unique client id for every client.
2. The client id on this page is merely an example and you can theoretically use any alphanumeric string.
3. You *__should not__* use the client secret in this example, We *__strongly recommend__* reading the
[Generating Client Secrets] guide instead.
[Generating Client Secrets]: ../specific-information.md#generating-client-secrets
{{% oidc-common %}}
### Assumptions
@ -38,7 +31,7 @@ This example makes the following assumptions:
* __Application Root URL:__ `https://gitlab.example.com`
* __Authelia Root URL:__ `https://auth.example.com`
* __Client ID:__ `gitlab`
* __Client Secret:__ `gitlab_client_secret`
* __Client Secret:__ `insecure_secret`
## Configuration
@ -65,7 +58,7 @@ gitlab_rails['omniauth_providers'] = [
send_scope_to_token_endpoint: "false",
client_options: {
identifier: "gitlab",
secret: "gitlab_client_secret",
secret: "insecure_secret",
redirect_uri: "https://gitlab.example.com/users/auth/openid_connect/callback"
}
}
@ -82,7 +75,7 @@ which will operate with the above example:
```yaml
- id: gitlab
description: GitLab
secret: '$plaintext$gitlab_client_secret'
secret: '$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng' # The digest of 'insecure_secret'.
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -22,14 +22,7 @@ community: true
## Before You Begin
### Common Notes
1. You are *__required__* to utilize a unique client id for every client.
2. The client id on this page is merely an example and you can theoretically use any alphanumeric string.
3. You *__should not__* use the client secret in this example, We *__strongly recommend__* reading the
[Generating Client Secrets] guide instead.
[Generating Client Secrets]: ../specific-information.md#generating-client-secrets
{{% oidc-common %}}
### Assumptions
@ -38,7 +31,7 @@ This example makes the following assumptions:
* __Application Root URL:__ `https://grafana.example.com`
* __Authelia Root URL:__ `https://auth.example.com`
* __Client ID:__ `grafana`
* __Client Secret:__ `grafana_client_secret`
* __Client Secret:__ `insecure_secret`
## Configuration
@ -58,7 +51,7 @@ enabled = true
name = Authelia
icon = signin
client_id = grafana
client_secret = grafana_client_secret
client_secret = insecure_secret
scopes = openid profile email groups
empty_scopes = false
auth_url = https://auth.example.com/api/oidc/authorization
@ -80,7 +73,7 @@ Configure the following environment variables:
| GF_AUTH_GENERIC_OAUTH_ENABLED | true |
| GF_AUTH_GENERIC_OAUTH_NAME | Authelia |
| GF_AUTH_GENERIC_OAUTH_CLIENT_ID | grafana |
| GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET | grafana_client_secret |
| GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET | insecure_secret |
| GF_AUTH_GENERIC_OAUTH_SCOPES | openid profile email groups |
| GF_AUTH_GENERIC_OAUTH_EMPTY_SCOPES | false |
| GF_AUTH_GENERIC_OAUTH_AUTH_URL | https://auth.example.com/api/oidc/authorization |
@ -100,7 +93,7 @@ which will operate with the above example:
```yaml
- id: grafana
description: Grafana
secret: '$plaintext$grafana_client_secret'
secret: '$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng' # The digest of 'insecure_secret'.
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -22,14 +22,7 @@ community: true
## Before You Begin
### Common Notes
1. You are *__required__* to utilize a unique client id for every client.
2. The client id on this page is merely an example and you can theoretically use any alphanumeric string.
3. You *__should not__* use the client secret in this example, We *__strongly recommend__* reading the
[Generating Client Secrets] guide instead.
[Generating Client Secrets]: ../specific-information.md#generating-client-secrets
{{% oidc-common %}}
### Assumptions
@ -38,7 +31,7 @@ This example makes the following assumptions:
* __Application Root URL:__ `https://harbor.example.com`
* __Authelia Root URL:__ `https://auth.example.com`
* __Client ID:__ `harbor`
* __Client Secret:__ `harbor_client_secret`
* __Client Secret:__ `insecure_secret`
## Configuration
@ -54,7 +47,7 @@ To configure [Harbor] to utilize Authelia as an [OpenID Connect 1.0] Provider:
1. OIDC Provider Name: `Authelia`
2. OIDC Provider Endpoint: `https://auth.example.com`
3. OIDC Client ID: `harbor`
4. OIDC Client Secret: `harbor_client_secret`
4. OIDC Client Secret: `insecure_secret`
5. Group Claim Name: `groups`
6. OIDC Scope: `openid,profile,email,groups`
7. For OIDC Admin Group you can specify a group name that matches your authentication backend.
@ -73,7 +66,7 @@ which will operate with the above example:
```yaml
- id: harbor
description: Harbor
secret: '$plaintext$harbor_client_secret'
secret: '$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng' # The digest of 'insecure_secret'.
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -22,14 +22,7 @@ community: true
## Before You Begin
### Common Notes
1. You are *__required__* to utilize a unique client id for every client.
2. The client id on this page is merely an example and you can theoretically use any alphanumeric string.
3. You *__should not__* use the client secret in this example, We *__strongly recommend__* reading the
[Generating Client Secrets] guide instead.
[Generating Client Secrets]: ../specific-information.md#generating-client-secrets
{{% oidc-common %}}
### Assumptions
@ -38,7 +31,7 @@ This example makes the following assumptions:
* __Application Root URL:__ `https://vault.example.com`
* __Authelia Root URL:__ `https://auth.example.com`
* __Client ID:__ `vault`
* __Client Secret:__ `vault_client_secret`
* __Client Secret:__ `insecure_secret`
## Configuration
@ -56,7 +49,7 @@ which will operate with the above example:
```yaml
- id: vault
description: HashiCorp Vault
secret: '$plaintext$vault_client_secret'
secret: '$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng' # The digest of 'insecure_secret'.
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -87,6 +87,68 @@ This scope includes the profile information the authentication backend reports a
| preferred_username | string | username | The username the user used to login with |
| name | string | display_name | The users display name |
## Parameters
The following section describes advanced parameters which can be used in various endpoints as well as their related
configuration options.
### Grant Types
The following describes the various [OAuth 2.0] and [OpenID Connect 1.0] grant types and their support level. The value
field is both the required value for the `grant_type` parameter in the authorization request and the `grant_types`
configuration option.
| Grant Type | Supported | Value | Notes |
|:-----------------------------------------------:|:---------:|:----------------------------------------------:|:-------------------------------------------------------------------:|
| [OAuth 2.0 Authorization Code] | Yes | `authorization_code` | |
| [OAuth 2.0 Resource Owner Password Credentials] | No | `password` | This Grant Type has been deprecated and should not normally be used |
| [OAuth 2.0 Client Credentials] | Yes | `client_credentials` | |
| [OAuth 2.0 Implicit] | Yes | `implicit` | This Grant Type has been deprecated and should not normally be used |
| [OAuth 2.0 Refresh Token] | Yes | `refresh_token` | |
| [OAuth 2.0 Device Code] | No | `urn:ietf:params:oauth:grant-type:device_code` | |
|
[OAuth 2.0 Authorization Code]: https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.1
[OAuth 2.0 Implicit]: https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.2
[OAuth 2.0 Resource Owner Password Credentials]: https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.3
[OAuth 2.0 Client Credentials]: https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.4
[OAuth 2.0 Refresh Token]: https://datatracker.ietf.org/doc/html/rfc6749#section-1.5
[OAuth 2.0 Device Code]: https://datatracker.ietf.org/doc/html/rfc8628#section-3.4
### Response Types
The following describes the supported response types. See the [OAuth 2.0 Multiple Response Type Encoding Practices] for
more technical information.
| Flow Type | Values |
|:-------------------------:|:---------------------:|
| [Authorization Code Flow] | `code` |
| [Implicit Flow] | `token id_token` |
| [Implicit Flow] | `id_token` |
| [Implicit Flow] | `token` |
| [Hybrid Flow] | `code token` |
| [Hybrid Flow] | `code id_token` |
| [Hybrid Flow] | `code token id_token` |
[Authorization Code Flow]: https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth
[Implicit Flow]: https://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth
[Hybrid Flow]: https://openid.net/specs/openid-connect-core-1_0.html#HybridFlowAuth
[OAuth 2.0 Multiple Response Type Encoding Practices]: https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html
### Response Modes
The following describes the supported response modes. See the [OAuth 2.0 Multiple Response Type Encoding Practices] for
more technical information.
| Name | Value |
|:---------------------:|:-----------:|
| Query String | `query` |
| Fragment | `fragment` |
| [OAuth 2.0 Form Post] | `form_post` |
[OAuth 2.0 Form Post]: https://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html
## Authentication Method References
Authelia currently supports adding the `amr` [Claim] to the [ID Token] utilizing the [RFC8176] Authentication Method
@ -166,16 +228,16 @@ These endpoints implement OpenID Connect elements.
[OpenID Connect 1.0]: https://openid.net/connect/
[OpenID Connect Discovery]: https://openid.net/specs/openid-connect-discovery-1_0.html
[OAuth 2.0 Authorization Server Metadata]: https://www.rfc-editor.org/rfc/rfc8414.html
[OAuth 2.0 Authorization Server Metadata]: https://datatracker.ietf.org/doc/html/rfc8414
[JSON Web Key Sets]: https://www.rfc-editor.org/rfc/rfc7517.html#section-5
[JSON Web Key Sets]: https://datatracker.ietf.org/doc/html/rfc7517#section-5
[Authorization]: https://openid.net/specs/openid-connect-core-1_0.html#AuthorizationEndpoint
[Token]: https://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint
[UserInfo]: https://openid.net/specs/openid-connect-core-1_0.html#UserInfo
[Introspection]: https://www.rfc-editor.org/rfc/rfc7662.html
[Revocation]: https://www.rfc-editor.org/rfc/rfc7009.html
[Introspection]: https://datatracker.ietf.org/doc/html/rfc7662
[Revocation]: https://datatracker.ietf.org/doc/html/rfc7009
[RFC8176]: https://www.rfc-editor.org/rfc/rfc8176.html
[RFC4122]: https://www.rfc-editor.org/rfc/rfc4122.html
[RFC8176]: https://datatracker.ietf.org/doc/html/rfc8176
[RFC4122]: https://datatracker.ietf.org/doc/html/rfc4122
[Subject Identifier Types]: https://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes

View File

@ -22,14 +22,7 @@ community: true
## Before You Begin
### Common Notes
1. You are *__required__* to utilize a unique client id for every client.
2. The client id on this page is merely an example and you can theoretically use any alphanumeric string.
3. You *__should not__* use the client secret in this example, We *__strongly recommend__* reading the
[Generating Client Secrets] guide instead.
[Generating Client Secrets]: ../specific-information.md#generating-client-secrets
{{% oidc-common %}}
### Assumptions
@ -38,7 +31,7 @@ This example makes the following assumptions:
* __Application Root URL:__ `https://komga.example.com`
* __Authelia Root URL:__ `https://auth.example.com`
* __Client ID:__ `komga`
* __Client Secret:__ `komga_client_secret`
* __Client Secret:__ `insecure_secret`
## Configuration
@ -58,7 +51,7 @@ spring:
registration:
authelia:
client-id: `komga`
client-secret: `komga_client_secret`
client-secret: `insecure_secret`
client-name: Authelia
scope: openid,profile,email
authorization-grant-type: authorization_code
@ -78,7 +71,7 @@ which will operate with the above example:
```yaml
- id: komga
description: Komga
secret: '$plaintext$komga_client_secret'
secret: '$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng' # The digest of 'insecure_secret'.
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -22,14 +22,7 @@ community: true
## Before You Begin
### Common Notes
1. You are *__required__* to utilize a unique client id for every client.
2. The client id on this page is merely an example and you can theoretically use any alphanumeric string.
3. You *__should not__* use the client secret in this example, We *__strongly recommend__* reading the
[Generating Client Secrets] guide instead.
[Generating Client Secrets]: ../specific-information.md#generating-client-secrets
{{% oidc-common %}}
### Assumptions
@ -38,7 +31,7 @@ This example makes the following assumptions:
* __Application Root URL:__ `https://nextcloud.example.com`
* __Authelia Root URL:__ `https://auth.example.com`
* __Client ID:__ `nextcloud`
* __Client Secret:__ `nextcloud_client_secret`
* __Client Secret:__ `insecure_secret`
## Configuration
@ -55,7 +48,7 @@ $CONFIG = array (
'lost_password_link' => 'disabled',
'oidc_login_provider_url' => 'https://auth.example.com',
'oidc_login_client_id' => 'nextcloud',
'oidc_login_client_secret' => 'nextcloud_client_secret',
'oidc_login_client_secret' => 'insecure_secret',
'oidc_login_auto_redirect' => false,
'oidc_login_end_session_redirect' => false,
'oidc_login_button_text' => 'Log in with Authelia',
@ -94,7 +87,7 @@ which will operate with the above example:
```yaml
- id: nextcloud
description: NextCloud
secret: '$plaintext$nextcloud_client_secret'
secret: '$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng' # The digest of 'insecure_secret'.
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -22,14 +22,7 @@ community: true
## Before You Begin
### Common Notes
1. You are *__required__* to utilize a unique client id for every client.
2. The client id on this page is merely an example and you can theoretically use any alphanumeric string.
3. You *__should not__* use the client secret in this example, We *__strongly recommend__* reading the
[Generating Client Secrets] guide instead.
[Generating Client Secrets]: ../specific-information.md#generating-client-secrets
{{% oidc-common %}}
### Assumptions
@ -38,7 +31,7 @@ This example makes the following assumptions:
* __Application Root URL:__ `https://outline.example.com`
* __Authelia Root URL:__ `https://auth.example.com`
* __Client ID:__ `outline`
* __Client Secret:__ `outline_client_secret`
* __Client Secret:__ `insecure_secret`
*__Important Note:__ At the time of this writing [Outline] requires the `offline_access` scope by default. Failure to include this scope will result
in an error as [Outline] will attempt to use a refresh token that is never issued.*
@ -55,7 +48,7 @@ URL=https://outline.example.com
FORCE_HTTPS=true
OIDC_CLIENT_ID=outline
OIDC_CLIENT_SECRET=outline_client_secret
OIDC_CLIENT_SECRET=insecure_secret
OIDC_AUTH_URI=https://auth.example.com/api/oidc/authorization
OIDC_TOKEN_URI=https://auth.example.com/api/oidc/token
OIDC_USERINFO_URI=https://auth.example.com/api/oidc/userinfo
@ -73,7 +66,7 @@ which will operate with the above example:
```yaml
- id: outline
description: Outline
secret: '$plaintext$outline_client_secret'
secret: '$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng' # The digest of 'insecure_secret'.
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -24,14 +24,7 @@ aliases:
## Before You Begin
### Common Notes
1. You are *__required__* to utilize a unique client id for every client.
2. The client id on this page is merely an example and you can theoretically use any alphanumeric string.
3. You *__should not__* use the client secret in this example, We *__strongly recommend__* reading the
[Generating Client Secrets] guide instead.
[Generating Client Secrets]: ../specific-information.md#generating-client-secrets
{{% oidc-common %}}
### Assumptions
@ -40,7 +33,7 @@ This example makes the following assumptions:
* __Application Root URL:__ `https://portainer.example.com`
* __Authelia Root URL:__ `https://auth.example.com`
* __Client ID:__ `portainer`
* __Client Secret:__ `portainer_client_secret`
* __Client Secret:__ `insecure_secret`
## Configuration
@ -55,7 +48,7 @@ To configure [Portainer] to utilize Authelia as an [OpenID Connect 1.0] Provider
2. Provider: Custom
3. Enable *Automatic User Provision* if you want users to automatically be created in [Portainer].
4. Client ID: `portainer`
5. Client Secret: `portainer_client_secret`
5. Client Secret: `insecure_secret`
6. Authorization URL: `https://auth.example.com/api/oidc/authorization`
7. Access Token URL: `https://auth.example.com/api/oidc/token`
8. Resource URL: `https://auth.example.com/api/oidc/userinfo`
@ -75,7 +68,7 @@ which will operate with the above example:
```yaml
- id: portainer
description: Portainer
secret: '$plaintext$portainer_client_secret'
secret: '$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng' # The digest of 'insecure_secret'.
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -43,7 +43,7 @@ This example makes the following assumptions:
* __Application Root URL:__ `https://proxmox.example.com`
* __Authelia Root URL:__ `https://auth.example.com`
* __Client ID:__ `proxmox`
* __Client Secret:__ `proxmox_client_secret`
* __Client Secret:__ `insecure_secret`
* __Realm__ `authelia`
## Configuration
@ -60,7 +60,7 @@ To configure [Proxmox] to utilize Authelia as an [OpenID Connect 1.0] Provider:
1. Issuer URL: `https://auth.example.com`
2. Realm: `authelia`
3. Client ID: `proxmox`
4. Client Key: `proxmox_client_secret`
4. Client Key: `insecure_secret`
5. Username Claim `preferred_username`
6. Scopes: `openid profile email`
7. Enable *Autocreate Users* if you want users to automatically be created in [Proxmox].
@ -76,7 +76,7 @@ which will operate with the above example:
```yaml
- id: proxmox
description: Proxmox
secret: '$plaintext$proxmox_client_secret'
secret: '$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng' # The digest of 'insecure_secret'.
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -22,14 +22,7 @@ community: true
## Before You Begin
### Common Notes
1. You are *__required__* to utilize a unique client id for every client.
2. The client id on this page is merely an example and you can theoretically use any alphanumeric string.
3. You *__should not__* use the client secret in this example, We *__strongly recommend__* reading the
[Generating Client Secrets] guide instead.
[Generating Client Secrets]: ../specific-information.md#generating-client-secrets
{{% oidc-common %}}
### Assumptions
@ -38,7 +31,7 @@ This example makes the following assumptions:
* __Application Root URL:__ `https://seafile.example.com`
* __Authelia Root URL:__ `https://auth.example.com`
* __Client ID:__ `seafile`
* __Client Secret:__ `seafile_client_secret`
* __Client Secret:__ `insecure_secret`
## Configuration
@ -55,7 +48,7 @@ To configure [Seafile] to utilize Authelia as an [OpenID Connect 1.0] Provider:
ENABLE_OAUTH = True
OAUTH_ENABLE_INSECURE_TRANSPORT = False
OAUTH_CLIENT_ID = "seafile"
OAUTH_CLIENT_SECRET = "seafile_client_secret"
OAUTH_CLIENT_SECRET = "insecure_secret"
OAUTH_REDIRECT_URL = 'https://seafile.example.com/oauth/callback/'
OAUTH_PROVIDER_DOMAIN = 'auth.example.com'
OAUTH_AUTHORIZATION_URL = 'https://auth.example.com/api/oidc/authorization'
@ -82,7 +75,7 @@ which will operate with the above example:
```yaml
- id: seafile
description: Seafile
secret: '$plaintext$seafile_client_secret'
secret: '$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng' # The digest of 'insecure_secret'.
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -34,6 +34,22 @@ using PBKDF2 which can be stored in the Authelia configuration.
### Plaintext
Authelia supports storing the plaintext secret in the configuration. This may be discontinued in the future. Plaintext
is either denoted by the `$plaintext$` prefix where everything after the prefix is the secret. In addition if the secret
does not start with the `$` character it's considered as a plaintext secret for the time being but is deprecated.
Authelia *technically* supports storing the plaintext secret in the configuration. This will likely be completely
unavailable in the future as it was a mistake to implement it like this in the first place. While some other OpenID
Connect 1.0 providers operate in this way, it's more often than not that they operating in this way in error. The
current *technical support* for this is only to prevent massive upheaval to users and give them time to migrate.
As per [RFC6819 Section 5.1.4.1.3](https://datatracker.ietf.org/doc/html/rfc6819#section-5.1.4.1.3) the secret should
only be stored by the authorization server as hashes / digests unless there is a very specific specification or protocol
that is implemented by the authorization server which requires access to the secret in the clear to operate properly in
which case the secret should be encrypted and not be stored in plaintext. The most likely long term outcome is that the
client configurations will be stored in the database with the secret both salted and peppered.
Authelia currently does not implement any of the specifications or protocols which require secrets being accessible in
the clear and currently has no plans to implement any of these. As such it's *__strongly discouraged and heavily
deprecated__* and we instead recommended that users remove this from their configuration entirely and use the
[Generating Client Secrets](#generating-client-secrets) guide.
Plaintext is either denoted by the `$plaintext$` prefix where everything after the prefix is the secret. In addition if
the secret does not start with the `$` character it's considered as a plaintext secret for the time being but is
deprecated as is the `$plaintext$` prefix.

View File

@ -22,14 +22,7 @@ community: true
## Before You Begin
### Common Notes
1. You are *__required__* to utilize a unique client id for every client.
2. The client id on this page is merely an example and you can theoretically use any alphanumeric string.
3. You *__should not__* use the client secret in this example, We *__strongly recommend__* reading the
[Generating Client Secrets] guide instead.
[Generating Client Secrets]: ../specific-information.md#generating-client-secrets
{{% oidc-common %}}
### Assumptions
@ -38,7 +31,7 @@ This example makes the following assumptions:
* __Application Root URL:__ `https://matrix.example.com/`
* __Authelia Root URL:__ `https://auth.example.com`
* __Client ID:__ `synapse`
* __Client Secret:__ `synapse_client_secret`
* __Client Secret:__ `insecure_secret`
## Configuration
@ -56,7 +49,7 @@ oidc_providers:
discover: true
issuer: "https://auth.example.com"
client_id: "synapse"
client_secret: "synapse_client_secret"
client_secret: "insecure_secret"
scopes: ["openid", "profile", "email"]
allow_existing_users: true
user_mapping_provider:
@ -76,7 +69,7 @@ which will operate with the above example:
```yaml
- id: synapse
description: Synapse
secret: '$plaintext$synapse_client_secret'
secret: '$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng' # The digest of 'insecure_secret'.
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -22,14 +22,7 @@ community: true
## Before You Begin
### Common Notes
1. You are *__required__* to utilize a unique client id for every client.
2. The client id on this page is merely an example and you can theoretically use any alphanumeric string.
3. You *__should not__* use the client secret in this example, We *__strongly recommend__* reading the
[Generating Client Secrets] guide instead.
[Generating Client Secrets]: ../specific-information.md#generating-client-secrets
{{% oidc-common %}}
### Specific Notes
@ -43,7 +36,7 @@ This example makes the following assumptions:
* __Application Root URL:__ `https://dsm.example.com/`
* __Authelia Root URL:__ `https://auth.example.com`
* __Client ID:__ `synology-dsm`
* __Client Secret:__ `synology-dsm_client_secret`
* __Client Secret:__ `insecure_secret`
## Configuration
@ -61,7 +54,7 @@ To configure [Synology DSM] to utilize Authelia as an [OpenID Connect 1.0] Provi
* Name: `Authelia`
* Well Known URL: `https://auth.example.com/.well-known/openid-configuration`
* Application ID: `synology-dsm`
* Application Key: `synology-dsm_client_secret`
* Application Key: `insecure_secret`
* Redirect URL: `https://dsm.example.com`
* Authorisation Scope: `openid profile groups email`
* Username Claim: `preferred_username`
@ -78,7 +71,7 @@ which will operate with the above example:
```yaml
- id: synology-dsm
description: Synology DSM
secret: '$plaintext$synology-dsm_client_secret'
secret: '$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng' # The digest of 'insecure_secret'.
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -102,7 +102,7 @@ nextcloud.example.com {
## The following commented line is for configuring the Authelia URL in the proxy. We strongly suggest
## this is configured in the Session Cookies section of the Authelia configuration.
# uri /api/authz/forward-auth?authelia_url=https://auth.example.com/
copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
copy_headers Authorization Proxy-Authorization Remote-User Remote-Groups Remote-Email Remote-Name
## This import needs to be included if you're relying on a trusted proxies configuration.
import trusted_proxy_list
@ -141,7 +141,7 @@ example.com {
handle @nextcloud {
forward_auth authelia:9091 {
uri /api/authz/forward-auth?authelia_url=https://example.com/authelia/
copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
copy_headers Authorization Proxy-Authorization Remote-User Remote-Groups Remote-Email Remote-Name
## This import needs to be included if you're relying on a trusted proxies configuration.
import trusted_proxy_list
@ -198,10 +198,12 @@ nextcloud.example.com {
## 2. Copy the relevant headers from the auth request and provide them to the backend.
@good status 2xx
handle_response @good {
request_header Authorization {http.reverse_proxy.header.Authorization}
request_header Proxy-Authorization {http.reverse_proxy.header.Proxy-Authorization}
request_header Remote-User {http.reverse_proxy.header.Remote-User}
request_header Remote-Groups {http.reverse_proxy.header.Remote-Groups}
request_header Remote-Name {http.reverse_proxy.header.Remote-Name}
request_header Remote-Email {http.reverse_proxy.header.Remote-Email}
request_header Remote-Name {http.reverse_proxy.header.Remote-Name}
}
}

View File

@ -168,6 +168,13 @@ static_resources:
- name: envoy.filters.http.ext_authz
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
transport_api_version: v3
allowed_headers:
patterns:
- exact: authorization
- exact: proxy-authorization
- exact: accept
- exact: cookie
http_service:
path_prefix: /api/authz/ext-authz/
server_uri:
@ -177,9 +184,10 @@ static_resources:
authorization_request:
allowed_headers:
patterns:
- exact: authorization
- exact: proxy-authorization
- exact: accept
- exact: cookie
- exact: proxy-authorization
headers_to_add:
- key: X-Forwarded-Proto
value: '%REQ(:SCHEME)%'
@ -207,9 +215,9 @@ static_resources:
clusters:
- name: nextcloud
connect_timeout: 0.25s
type: LOGICAL_DNS
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
type: logical_dns
dns_lookup_family: v4_only
lb_policy: round_robin
load_assignment:
cluster_name: nextcloud
endpoints:
@ -221,9 +229,9 @@ static_resources:
port_value: 80
- name: authelia
connect_timeout: 0.25s
type: LOGICAL_DNS
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
type: logical_dns
dns_lookup_family: v4_only
lb_policy: round_robin
load_assignment:
cluster_name: authelia
endpoints:
@ -233,6 +241,17 @@ static_resources:
socket_address:
address: authelia
port_value: 9091
layered_runtime:
layers:
- name: static_layer_0
static_layer:
envoy:
resource_limits:
listener:
example_listener_name:
connection_limit: 10000
overload:
global_downstream_max_connections: 50000
```
{{< /details >}}

View File

@ -218,29 +218,53 @@ backend be_authelia
server authelia authelia:9091
backend be_nextcloud
# Pass Remote-User, Remote-Name, Remote-Email and Remote-Groups headers
## Pass the special authorization response headers to the protected application.
acl authorization_exist var(req.auth_response_header.authorization) -m found
acl proxy_authorization_exist var(req.auth_response_header.proxy_authorization) -m found
http-request set-header Authorization %[var(req.auth_response_header.authorization)] if authorization_exist
http-request set-header Proxy-Authorization %[var(req.auth_response_header.proxy_authorization)] if proxy_authorization_exist
## Pass the special metadata response headers to the protected application.
acl remote_user_exist var(req.auth_response_header.remote_user) -m found
acl remote_groups_exist var(req.auth_response_header.remote_groups) -m found
acl remote_name_exist var(req.auth_response_header.remote_name) -m found
acl remote_email_exist var(req.auth_response_header.remote_email) -m found
http-request set-header Remote-User %[var(req.auth_response_header.remote_user)] if remote_user_exist
http-request set-header Remote-Groups %[var(req.auth_response_header.remote_groups)] if remote_groups_exist
http-request set-header Remote-Name %[var(req.auth_response_header.remote_name)] if remote_name_exist
http-request set-header Remote-Email %[var(req.auth_response_header.remote_email)] if remote_email_exist
## Pass the Set-Cookie response headers to the user.
acl set_cookie_exist var(req.auth_response_header.set_cookie) -m found
http-response set-header Set-Cookie %[var(req.auth_response_header.set_cookie)] if set_cookie_exist
server nextcloud nextcloud:443 ssl verify none
backend be_heimdall
# Pass Remote-User, Remote-Name, Remote-Email and Remote-Groups headers
## Pass the special authorization response headers to the protected application.
acl authorization_exist var(req.auth_response_header.authorization) -m found
acl proxy_authorization_exist var(req.auth_response_header.proxy_authorization) -m found
http-request set-header Authorization %[var(req.auth_response_header.authorization)] if authorization_exist
http-request set-header Proxy-Authorization %[var(req.auth_response_header.proxy_authorization)] if proxy_authorization_exist
## Pass the special metadata response headers to the protected application.
acl remote_user_exist var(req.auth_response_header.remote_user) -m found
acl remote_groups_exist var(req.auth_response_header.remote_groups) -m found
acl remote_name_exist var(req.auth_response_header.remote_name) -m found
acl remote_email_exist var(req.auth_response_header.remote_email) -m found
http-request set-header Remote-User %[var(req.auth_response_header.remote_user)] if remote_user_exist
http-request set-header Remote-Groups %[var(req.auth_response_header.remote_groups)] if remote_groups_exist
http-request set-header Remote-Name %[var(req.auth_response_header.remote_name)] if remote_name_exist
http-request set-header Remote-Email %[var(req.auth_response_header.remote_email)] if remote_email_exist
## Pass the Set-Cookie response headers to the user.
acl set_cookie_exist var(req.auth_response_header.set_cookie) -m found
http-response set-header Set-Cookie %[var(req.auth_response_header.set_cookie)] if set_cookie_exist
server heimdall heimdall:443 ssl verify none
```
@ -325,29 +349,53 @@ listen authelia_proxy
server authelia authelia:9091 ssl verify none
backend be_nextcloud
# Pass Remote-User, Remote-Name, Remote-Email and Remote-Groups headers
## Pass the special authorization response headers to the protected application.
acl authorization_exist var(req.auth_response_header.authorization) -m found
acl proxy_authorization_exist var(req.auth_response_header.proxy_authorization) -m found
http-request set-header Authorization %[var(req.auth_response_header.authorization)] if authorization_exist
http-request set-header Proxy-Authorization %[var(req.auth_response_header.proxy_authorization)] if proxy_authorization_exist
## Pass the special metadata response headers to the protected application.
acl remote_user_exist var(req.auth_response_header.remote_user) -m found
acl remote_groups_exist var(req.auth_response_header.remote_groups) -m found
acl remote_name_exist var(req.auth_response_header.remote_name) -m found
acl remote_email_exist var(req.auth_response_header.remote_email) -m found
http-request set-header Remote-User %[var(req.auth_response_header.remote_user)] if remote_user_exist
http-request set-header Remote-Groups %[var(req.auth_response_header.remote_groups)] if remote_groups_exist
http-request set-header Remote-Name %[var(req.auth_response_header.remote_name)] if remote_name_exist
http-request set-header Remote-Email %[var(req.auth_response_header.remote_email)] if remote_email_exist
## Pass the Set-Cookie response headers to the user.
acl set_cookie_exist var(req.auth_response_header.set_cookie) -m found
http-response set-header Set-Cookie %[var(req.auth_response_header.set_cookie)] if set_cookie_exist
server nextcloud nextcloud:443 ssl verify none
backend be_heimdall
# Pass Remote-User, Remote-Name, Remote-Email and Remote-Groups headers
## Pass the special authorization response headers to the protected application.
acl authorization_exist var(req.auth_response_header.authorization) -m found
acl proxy_authorization_exist var(req.auth_response_header.proxy_authorization) -m found
http-request set-header Authorization %[var(req.auth_response_header.authorization)] if authorization_exist
http-request set-header Proxy-Authorization %[var(req.auth_response_header.proxy_authorization)] if proxy_authorization_exist
## Pass the special metadata response headers to the protected application.
acl remote_user_exist var(req.auth_response_header.remote_user) -m found
acl remote_groups_exist var(req.auth_response_header.remote_groups) -m found
acl remote_name_exist var(req.auth_response_header.remote_name) -m found
acl remote_email_exist var(req.auth_response_header.remote_email) -m found
http-request set-header Remote-User %[var(req.auth_response_header.remote_user)] if remote_user_exist
http-request set-header Remote-Groups %[var(req.auth_response_header.remote_groups)] if remote_groups_exist
http-request set-header Remote-Name %[var(req.auth_response_header.remote_name)] if remote_name_exist
http-request set-header Remote-Email %[var(req.auth_response_header.remote_email)] if remote_email_exist
## Pass the Set-Cookie response headers to the user.
acl set_cookie_exist var(req.auth_response_header.set_cookie) -m found
http-response set-header Set-Cookie %[var(req.auth_response_header.set_cookie)] if set_cookie_exist
server heimdall heimdall:443 ssl verify none
```

View File

@ -433,17 +433,29 @@ set_escape_uri $target_url $scheme://$http_host$request_uri;
## Uncomment this line if you're using NGINX without the http_set_misc module.
# set $target_url $scheme://$http_host$request_uri;
## Save the upstream response headers from Authelia to variables.
## Save the upstream authorization response headers from Authelia to variables.
auth_request_set $authorization $upstream_http_authorization;
auth_request_set $proxy_authorization $upstream_http_proxy_authorization;
## Inject the authorization response headers from the variables into the request made to the backend.
proxy_set_header Authorization $authorization;
proxy_set_header Proxy-Authorization $proxy_authorization;
## Save the upstream metadata response headers from Authelia to variables.
auth_request_set $user $upstream_http_remote_user;
auth_request_set $groups $upstream_http_remote_groups;
auth_request_set $name $upstream_http_remote_name;
auth_request_set $email $upstream_http_remote_email;
## Inject the response headers from the variables into the request made to the backend.
## Inject the metadata response headers from the variables into the request made to the backend.
proxy_set_header Remote-User $user;
proxy_set_header Remote-Groups $groups;
proxy_set_header Remote-Name $name;
proxy_set_header Remote-Email $email;
proxy_set_header Remote-Name $name;
## Include the Set-Cookie header if present.
auth_request_set $cookie $upstream_http_set_cookie;
add_header Set-Cookie $cookie;
## If the subreqest returns 200 pass to the backend, if the subrequest returns 401 redirect to the portal.
error_page 401 =302 https://auth.example.com/?rd=$target_url;

View File

@ -157,7 +157,7 @@ services:
## configured in the Session Cookies section of the Authelia configuration.
# - 'traefik.http.middlewares.authelia.forwardAuth.address=http://authelia:9091/api/authz/forward-auth?authelia_url=https%3A%2F%2Fauth.example.com%2F'
- 'traefik.http.middlewares.authelia.forwardAuth.trustForwardHeader=true'
- 'traefik.http.middlewares.authelia.forwardAuth.authResponseHeaders=Authorization,Proxy-Authorization,Remote-User,Remote-Groups,Remote-Name,Remote-Email'
- 'traefik.http.middlewares.authelia.forwardAuth.authResponseHeaders=Authorization,Proxy-Authorization,Remote-User,Remote-Groups,Remote-Email,Remote-Name'
nextcloud:
container_name: nextcloud
image: linuxserver/nextcloud
@ -503,7 +503,7 @@ This can be avoided a couple different ways:
## configured in the Session Cookies section of the Authelia configuration.
# - 'traefik.http.middlewares.authelia.forwardAuth.address=http://authelia:9091/api/authz/forward-auth?authelia_url=https%3A%2F%2Fauth.example.com%2F'
- 'traefik.http.middlewares.authelia.forwardAuth.trustForwardHeader=true'
- 'traefik.http.middlewares.authelia.forwardAuth.authResponseHeaders=Authorization,Proxy-Authorization,Remote-User,Remote-Groups,Remote-Name,Remote-Email'
- 'traefik.http.middlewares.authelia.forwardAuth.authResponseHeaders=Authorization,Proxy-Authorization,Remote-User,Remote-Groups,Remote-Email,Remote-Name'
```
## See Also

View File

@ -137,7 +137,7 @@ services:
## configured in the Session Cookies section of the Authelia configuration.
# - 'traefik.frontend.auth.forward.address=http://authelia:9091/api/authz/forward-auth?authelia_url=https%3A%2F%2Fauth.example.com%2F'
- 'traefik.frontend.auth.forward.trustForwardHeader=true'
- 'traefik.frontend.auth.forward.authResponseHeaders=Authorization,Proxy-Authorization,Remote-User,Remote-Groups,Remote-Name,Remote-Email'
- 'traefik.frontend.auth.forward.authResponseHeaders=Authorization,Proxy-Authorization,Remote-User,Remote-Groups,Remote-Email,Remote-Name'
expose:
- 443
restart: unless-stopped
@ -156,7 +156,7 @@ services:
- 'traefik.frontend.rule=Host:heimdall.example.com'
- 'traefik.frontend.auth.forward.address=http://authelia:9091/api/authz/forward-auth/basic'
- 'traefik.frontend.auth.forward.trustForwardHeader=true'
- 'traefik.frontend.auth.forward.authResponseHeaders=Authorization,Proxy-Authorization,Remote-User,Remote-Groups,Remote-Name,Remote-Email'
- 'traefik.frontend.auth.forward.authResponseHeaders=Authorization,Proxy-Authorization,Remote-User,Remote-Groups,Remote-Email,Remote-Name'
expose:
- 443
restart: unless-stopped

View File

@ -216,9 +216,9 @@ to port 587 (_the `submission` port, a common alternative that uses STARTTLS ins
[docs-config-smtp-port]: ../../configuration/notifications/smtp.md#port
[cleartext]: https://cwe.mitre.org/data/definitions/312.html
[service-submissions]: https://www.rfc-editor.org/rfc/rfc8314#section-7.3
[port-465]: https://www.rfc-editor.org/rfc/rfc8314#section-3.3
[smtp-auth]: https://www.rfc-editor.org/rfc/rfc6409#section-4.3
[service-submissions]: https://datatracker.ietf.org/doc/html/rfc8314#section-7.3
[port-465]: https://datatracker.ietf.org/doc/html/rfc8314#section-3.3
[smtp-auth]: https://datatracker.ietf.org/doc/html/rfc6409#section-4.3
## Protection against open redirects

View File

@ -35,20 +35,23 @@ authelia crypto certificate ecdsa generate --help
### Options
```
--bundle enables generating the certificate bundle if the --path.ca flag is set
--ca create the certificate as a certificate authority certificate
-n, --common-name string certificate common name
--country strings certificate country
-b, --curve string Sets the elliptic curve which can be P224, P256, P384, or P521 (default "P256")
-d, --directory string directory where the generated keys, certificates, etc will be stored
--duration duration duration of time the certificate is valid for (default 8760h0m0s)
--duration string duration of time the certificate is valid for (default "1y")
--extended-usage strings specify the extended usage types of the certificate
--file.ca-certificate string certificate authority certificate to use when signing this certificate (default "ca.public.crt")
--file.ca-private-key string certificate authority private key to use to signing this certificate (default "ca.private.pem")
--file.certificate string name of the file to export the certificate data to (default "public.crt")
--file.certificate-bundle string name of the file to export the certificate bundle data to when the --bundle flag is set (default "public.bundle.crt")
--file.private-key string name of the file to export the private key data to (default "private.pem")
-h, --help help for generate
-l, --locality strings certificate locality
--not-before string earliest date and time the certificate is considered valid formatted as Jan 2 15:04:05 2006 (default is now)
--not-after string latest date and time the certificate is considered valid in various formats
--not-before string earliest date and time the certificate is considered valid in various formats (default is now)
-o, --organization strings certificate organization (default [Authelia])
--organizational-unit strings certificate organizational unit
--path.ca string source directory of the certificate authority files, if not provided the certificate will be self-signed

View File

@ -39,12 +39,13 @@ authelia crypto certificate ecdsa request --help
--country strings certificate country
-b, --curve string Sets the elliptic curve which can be P224, P256, P384, or P521 (default "P256")
-d, --directory string directory where the generated keys, certificates, etc will be stored
--duration duration duration of time the certificate is valid for (default 8760h0m0s)
--duration string duration of time the certificate is valid for (default "1y")
--file.csr string name of the file to export the certificate request data to (default "request.csr")
--file.private-key string name of the file to export the private key data to (default "private.pem")
-h, --help help for request
-l, --locality strings certificate locality
--not-before string earliest date and time the certificate is considered valid formatted as Jan 2 15:04:05 2006 (default is now)
--not-after string latest date and time the certificate is considered valid in various formats
--not-before string earliest date and time the certificate is considered valid in various formats (default is now)
-o, --organization strings certificate organization (default [Authelia])
--organizational-unit strings certificate organizational unit
-p, --postcode strings certificate postcode

View File

@ -35,19 +35,22 @@ authelia crypto certificate ed25519 request --help
### Options
```
--bundle enables generating the certificate bundle if the --path.ca flag is set
--ca create the certificate as a certificate authority certificate
-n, --common-name string certificate common name
--country strings certificate country
-d, --directory string directory where the generated keys, certificates, etc will be stored
--duration duration duration of time the certificate is valid for (default 8760h0m0s)
--duration string duration of time the certificate is valid for (default "1y")
--extended-usage strings specify the extended usage types of the certificate
--file.ca-certificate string certificate authority certificate to use when signing this certificate (default "ca.public.crt")
--file.ca-private-key string certificate authority private key to use to signing this certificate (default "ca.private.pem")
--file.certificate string name of the file to export the certificate data to (default "public.crt")
--file.certificate-bundle string name of the file to export the certificate bundle data to when the --bundle flag is set (default "public.bundle.crt")
--file.private-key string name of the file to export the private key data to (default "private.pem")
-h, --help help for generate
-l, --locality strings certificate locality
--not-before string earliest date and time the certificate is considered valid formatted as Jan 2 15:04:05 2006 (default is now)
--not-after string latest date and time the certificate is considered valid in various formats
--not-before string earliest date and time the certificate is considered valid in various formats (default is now)
-o, --organization strings certificate organization (default [Authelia])
--organizational-unit strings certificate organizational unit
--path.ca string source directory of the certificate authority files, if not provided the certificate will be self-signed

View File

@ -38,12 +38,13 @@ authelia crypto certificate ed25519 request --help
-n, --common-name string certificate common name
--country strings certificate country
-d, --directory string directory where the generated keys, certificates, etc will be stored
--duration duration duration of time the certificate is valid for (default 8760h0m0s)
--duration string duration of time the certificate is valid for (default "1y")
--file.csr string name of the file to export the certificate request data to (default "request.csr")
--file.private-key string name of the file to export the private key data to (default "private.pem")
-h, --help help for request
-l, --locality strings certificate locality
--not-before string earliest date and time the certificate is considered valid formatted as Jan 2 15:04:05 2006 (default is now)
--not-after string latest date and time the certificate is considered valid in various formats
--not-before string earliest date and time the certificate is considered valid in various formats (default is now)
-o, --organization strings certificate organization (default [Authelia])
--organizational-unit strings certificate organizational unit
-p, --postcode strings certificate postcode

View File

@ -36,19 +36,22 @@ authelia crypto certificate rsa generate --help
```
-b, --bits int number of RSA bits for the certificate (default 2048)
--bundle enables generating the certificate bundle if the --path.ca flag is set
--ca create the certificate as a certificate authority certificate
-n, --common-name string certificate common name
--country strings certificate country
-d, --directory string directory where the generated keys, certificates, etc will be stored
--duration duration duration of time the certificate is valid for (default 8760h0m0s)
--duration string duration of time the certificate is valid for (default "1y")
--extended-usage strings specify the extended usage types of the certificate
--file.ca-certificate string certificate authority certificate to use when signing this certificate (default "ca.public.crt")
--file.ca-private-key string certificate authority private key to use to signing this certificate (default "ca.private.pem")
--file.certificate string name of the file to export the certificate data to (default "public.crt")
--file.certificate-bundle string name of the file to export the certificate bundle data to when the --bundle flag is set (default "public.bundle.crt")
--file.private-key string name of the file to export the private key data to (default "private.pem")
-h, --help help for generate
-l, --locality strings certificate locality
--not-before string earliest date and time the certificate is considered valid formatted as Jan 2 15:04:05 2006 (default is now)
--not-after string latest date and time the certificate is considered valid in various formats
--not-before string earliest date and time the certificate is considered valid in various formats (default is now)
-o, --organization strings certificate organization (default [Authelia])
--organizational-unit strings certificate organizational unit
--path.ca string source directory of the certificate authority files, if not provided the certificate will be self-signed

View File

@ -39,12 +39,13 @@ authelia crypto certificate rsa request --help
-n, --common-name string certificate common name
--country strings certificate country
-d, --directory string directory where the generated keys, certificates, etc will be stored
--duration duration duration of time the certificate is valid for (default 8760h0m0s)
--duration string duration of time the certificate is valid for (default "1y")
--file.csr string name of the file to export the certificate request data to (default "request.csr")
--file.private-key string name of the file to export the private key data to (default "private.pem")
-h, --help help for request
-l, --locality strings certificate locality
--not-before string earliest date and time the certificate is considered valid formatted as Jan 2 15:04:05 2006 (default is now)
--not-after string latest date and time the certificate is considered valid in various formats
--not-before string earliest date and time the certificate is considered valid in various formats (default is now)
-o, --organization strings certificate organization (default [Authelia])
--organizational-unit strings certificate organizational unit
-p, --postcode strings certificate postcode

View File

@ -56,6 +56,9 @@ The following implementations exist:
- Specific configuration defaults for [Active Directory]
- Special implementation details:
- Includes a special encoding format required for changing passwords with [Active Directory]
- `rfc2307bis`:
- Specific configuration defaults for [RFC2307bis]
- No special implementation details
- `freeipa`:
- Specific configuration defaults for [FreeIPA]
- No special implementation details
@ -70,11 +73,17 @@ The following implementations exist:
[FreeIPA]: https://www.freeipa.org/
[lldap]: https://github.com/nitnelave/lldap
[GLAuth]: https://glauth.github.io/
[RFC2307bis]: https://datatracker.ietf.org/doc/html/draft-howard-rfc2307bis-02
### Filter replacements
Various replacements occur in the user and groups filter. The replacements either occur at startup or upon an LDAP
search.
search which is indicated by the phase column.
The phases exist to optimize performance. The replacements in the startup phase are replaced once before the connection
is ever established. In addition to this, during the startup phase we purposefully check the filters for which search
phase replacements exist so we only have to check if the replacement is necessary once, and we don't needlessly perform
every possible replacement on every search regardless of if it's needed or not.
#### Users filter replacements
@ -117,6 +126,7 @@ Username column.
|:---------------:|:--------------:|:------------:|:----:|:----------:|
| custom | N/A | displayName | mail | cn |
| activedirectory | sAMAccountName | displayName | mail | cn |
| rfc2307bis | uid | displayName | mail | cn |
| freeipa | uid | displayName | mail | cn |
| lldap | uid | cn | mail | cn |
| glauth | cn | description | mail | cn |
@ -130,17 +140,29 @@ the following conditions:
- The [Active Directory] implementation achieves this via the `(!(userAccountControl:1.2.840.113556.1.4.803:=2))` filter.
- The [FreeIPA] implementation achieves this via the `(!(nsAccountLock=TRUE))` filter.
- The [GLAuth] implementation achieves this via the `(!(accountStatus=inactive))` filter.
- The following implementations have no suitable attribute for this as far as we're aware:
- [RFC2307bis]
- [lldap]
- Their password is expired:
- The [Active Directory] implementation achieves this via the `(!(pwdLastSet=0))` filter.
- The [FreeIPA] implementation achieves this via the `(krbPasswordExpiration>={date-time:generalized})` filter.
- The following implementations have no suitable attribute for this as far as we're aware:
- [RFC2307bis]
- [GLAuth]
- [lldap]
- Their account is expired:
- The [Active Directory] implementation achieves this via the `(|(!(accountExpires=*))(accountExpires=0)(accountExpires>={date-time:microsoft-nt}))` filter.
- The [FreeIPA] implementation achieves this via the `(|(!(krbPrincipalExpiration=*))(krbPrincipalExpiration>={date-time:generalized}))` filter.
- The following implementations have no suitable attribute for this as far as we're aware:
- [RFC2307bis]
- [GLAuth]
- [lldap]
| Implementation | Users Filter | Groups Filter |
|:---------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------:|
|:---------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------------------------------:|
| custom | N/A | N/A |
| activedirectory | (&(&#124;({username_attribute}={input})({mail_attribute}={input}))(sAMAccountType=805306368)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(!(pwdLastSet=0))(&#124;(!(accountExpires=*))(accountExpires=0)(accountExpires>={date-time:microsoft-nt}))) | (&(member={dn})(&#124;(sAMAccountType=268435456)(sAMAccountType=536870912))) |
| rfc2307bis | (&(&#124;({username_attribute}={input})({mail_attribute}={input}))(&#124;(objectClass=inetOrgPerson)(objectClass=organizationalPerson))) | (&(&#124;(member={dn})(uniqueMember={dn}))(&#124;(objectClass=groupOfNames)(objectClass=groupOfUniqueNames)(objectClass=groupOfMembers))) |
| freeipa | (&(&#124;({username_attribute}={input})({mail_attribute}={input}))(objectClass=person)(!(nsAccountLock=TRUE))(krbPasswordExpiration>={date-time:generalized})(&#124;(!(krbPrincipalExpiration=*))(krbPrincipalExpiration>={date-time:generalized}))) | (&(member={dn})(objectClass=groupOfNames)) |
| lldap | (&(&#124;({username_attribute}={input})({mail_attribute}={input}))(objectClass=person)) | (&(member={dn})(objectClass=groupOfNames)) |
| glauth | (&(&#124;({username_attribute}={input})({mail_attribute}={input}))(objectClass=posixAccount)(!(accountStatus=inactive))) | (&(uniqueMember={dn})(objectClass=posixGroup)) |

View File

@ -193,14 +193,14 @@ This table suggests the parameters for the [SHA2 Crypt] algorithm:
| Standard CPU | sha512 | 50000 | 16 |
| High End CPU | sha512 | 150000 | 16 |
[Argon2]: https://www.rfc-editor.org/rfc/rfc9106.html
[Argon2]: https://datatracker.ietf.org/doc/html/rfc9106
[Scrypt]: https://en.wikipedia.org/wiki/Scrypt
[PBKDF2]: https://www.ietf.org/rfc/rfc2898.html
[PBKDF2]: https://datatracker.ietf.org/doc/html/rfc2898
[SHA2 Crypt]: https://www.akkadia.org/drepper/SHA-crypt.txt
[Bcrypt]: https://en.wikipedia.org/wiki/Bcrypt
[FIPS-140 compliance]: https://csrc.nist.gov/publications/detail/fips/140/2/final
[RFC9106 Parameter Choice]: https://www.rfc-editor.org/rfc/rfc9106.html#section-4
[RFC9106 Parameter Choice]: https://datatracker.ietf.org/doc/html/rfc9106#section-4
[YAML]: https://yaml.org/
[crypt hash generate]: ../cli/authelia/authelia_crypto_hash_generate.md
[Password Hashing Competition]: https://en.wikipedia.org/wiki/Password_Hashing_Competition

View File

@ -46,7 +46,7 @@ utilize these overrides should either check for changes to the files in the
The locales directory holds folders of internationalization locales. This directory can be utilized to override these
locales. They are the names of locales that are returned by the `navigator.langauge` ECMAScript command. These are
generally those in the [RFC5646 / BCP47 Format](https://www.rfc-editor.org/rfc/rfc5646.html) specifically the language
generally those in the [RFC5646 / BCP47 Format](https://datatracker.ietf.org/doc/html/rfc5646) specifically the language
codes from [Crowdin](https://support.crowdin.com/api/language-codes/).
Each directory has JSON files which you can explore the format of in the

View File

@ -78,6 +78,9 @@ The following functions which mimic the behaviour of helm exist in most templati
- kindIs
- default
- empty
- indent
- nindent
- uuidv4
See the [Helm Documentation](https://helm.sh/docs/chart_template_guide/function_list/) for more information. Please
note that only the functions listed above are supported and the functions don't necessarily behave exactly the same.
@ -92,3 +95,7 @@ The following is a list of special functions and their syntax.
#### iterate
Input is a single uint. Returns a slice of uints from 0 to the provided uint.
#### fileContent
Input is a path. Returns the content of a file.

View File

@ -39,11 +39,11 @@ Feature List:
* [User Consent](https://openid.net/specs/openid-connect-core-1_0.html#Consent)
* [Authorization Code Flow](https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowSteps)
* [OpenID Connect Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html)
* [RS256 Signature Strategy](https://www.rfc-editor.org/rfc/rfc7518.html#section-3.1)
* [RS256 Signature Strategy](https://datatracker.ietf.org/doc/html/rfc7518#section-3.1)
* Per Client Scope/Grant Type/Response Type Restriction
* Per Client Authorization Policy (1FA/2FA)
* Per Client List of Valid Redirection URI's
* [Confidential Client Type](https://www.rfc-editor.org/rfc/rfc6749.html#section-2.1)
* [Confidential Client Type](https://datatracker.ietf.org/doc/html/rfc6749#section-2.1)
### Beta 2
@ -56,7 +56,7 @@ Feature List:
* Token/Code Lifespan
* Client Debug Messages
* Client Audience
* [Public Client Type](https://www.rfc-editor.org/rfc/rfc6749.html#section-2.1)
* [Public Client Type](https://datatracker.ietf.org/doc/html/rfc6749#section-2.1)
### Beta 3
@ -97,7 +97,7 @@ Feature List:
Feature List:
* [JWK's backed by X509 Certificate Chains](https://www.rfc-editor.org/rfc/rfc7517#section-4.7)
* [JWK's backed by X509 Certificate Chains](https://datatracker.ietf.org/doc/html/rfc7517#section-4.7)
* Hashed Client Secrets
* Per-Client [Consent](https://openid.net/specs/openid-connect-core-1_0.html#Consent) Mode:
* Explicit:
@ -115,7 +115,7 @@ Feature List:
{{< roadmap-status stage="in-progress" version="v4.38.0" >}}
* [OAuth 2.0 Pushed Authorization Requests](https://www.rfc-editor.org/rfc/rfc9126.html)
* [OAuth 2.0 Pushed Authorization Requests](https://datatracker.ietf.org/doc/html/rfc9126)
* Per-Client [Proof Key Code Exchange (PKCE)] Policy
### Beta 7
@ -177,7 +177,7 @@ Should be implemented alongside [Dynamic Client Registration](#openid-connect-dy
{{< roadmap-status stage="complete" version="v4.34.0" >}}
See the [IETF Specification RFC8414](https://www.rfc-editor.org/rfc/rfc8414.html) for more information.
See the [IETF Specification RFC8414](https://datatracker.ietf.org/doc/html/rfc8414) for more information.
#### OpenID Connect Session Management
@ -205,9 +205,9 @@ The `preferred_username` claim was missing and was fixed.
[Cross Origin Resource Sharing]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
[RFC8176]: https://www.rfc-editor.org/rfc/rfc8176.html
[RFC8693 Section 4.3]: https://www.rfc-editor.org/rfc/rfc8693.html/#section-4.3
[RFC4122]: https://www.rfc-editor.org/rfc/rfc4122.html
[RFC8176]: https://datatracker.ietf.org/doc/html/rfc8176
[RFC8693 Section 4.3]: https://datatracker.ietf.org/doc/html/rfc8693/#section-4.3
[RFC4122]: https://datatracker.ietf.org/doc/html/rfc4122
[OpenID Connect]: https://openid.net/connect/
[OpenID Connect Front-Channel Logout]: https://openid.net/specs/openid-connect-frontchannel-1_0.html
@ -219,4 +219,4 @@ The `preferred_username` claim was missing and was fixed.
[OpenID Connect Core (Subject Identifier Types)]: https://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes
[OpenID Connect Core (Pairwise Identifier Algorithm)]: https://openid.net/specs/openid-connect-core-1_0.html#PairwiseAlg
[OpenID Connect Core (Mandatory to Implement Features for All OpenID Providers)]: https://openid.net/specs/openid-connect-core-1_0.html#ServerMTI
[Proof Key Code Exchange (PKCE)]: https://www.rfc-editor.org/rfc/rfc7636.html
[Proof Key Code Exchange (PKCE)]: https://datatracker.ietf.org/doc/html/rfc7636

View File

@ -0,0 +1,18 @@
{{ $specificinfo := "../specific-information/" }}{{ $config := "../../../configuration/identity-providers/open-id-connect.md" }}
{{- with .Get "specificinfo" }}{{ $specificinfo = . }}{{ end }}
{{- with .Get "config" }}{{ $config = . }}{{ end }}
### Common Notes
1. The [OpenID Connect 1.0](https://openid.net/specs/openid-connect-core-1_0.html) `client_id` parameter:
1. This *__must__* be a unique value for every client.
2. The value used in this guide is merely for demonstration purposes and you can theoretically use nearly any
alphanumeric string.
2. The [OpenID Connect 1.0](https://openid.net/specs/openid-connect-core-1_0.html) `secret` parameter:
1. The value used in this guide is merely for demonstration purposes and you *__should absolutely not__* use this in
production and should instead utilize the
[Generating Client Secrets]({{ $specificinfo }}#generating-client-secrets) guide.
2. This string may be stored as plaintext in the Authelia configuration but this behaviour is deprecated and is not
guaranteed to be supported in the future. See the [Plaintext]({{ $specificinfo }}#plaintext) guide for more
information.
3. The Configuration example for Authelia is only a portion of the required configuration and it should be used as a
guide in conjunction with the standard [OpenID Connect 1.0 Configuration]({{ $config }}) guide.

View File

@ -5,7 +5,7 @@
[build.environment]
NODE_VERSION = "16.18.1"
NPM_VERSION = "8.19.2"
GO_VERSION = "1.19.4"
GO_VERSION = "1.19.5"
[context.production]
command = "pnpm run build"

20
go.mod
View File

@ -1,19 +1,19 @@
module github.com/authelia/authelia/v4
go 1.19
go 1.20
require (
github.com/Gurpartap/logrus-stack v0.0.0-20170710170904-89c00d8a28f4
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
github.com/deckarep/golang-set/v2 v2.1.0
github.com/duosecurity/duo_api_golang v0.0.0-20221117185402-091daa09e19d
github.com/duosecurity/duo_api_golang v0.0.0-20230203160531-b221c950c2b0
github.com/fasthttp/router v1.4.16
github.com/fasthttp/session/v2 v2.4.16
github.com/fsnotify/fsnotify v1.6.0
github.com/go-asn1-ber/asn1-ber v1.5.4
github.com/go-crypt/crypt v0.2.3
github.com/go-crypt/crypt v0.2.5
github.com/go-ldap/ldap/v3 v3.4.4
github.com/go-rod/rod v0.112.4
github.com/go-rod/rod v0.112.5
github.com/go-sql-driver/mysql v1.7.0
github.com/go-webauthn/webauthn v0.7.0
github.com/golang-jwt/jwt/v4 v4.4.3
@ -28,7 +28,7 @@ require (
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
github.com/ory/fosite v0.44.0
github.com/ory/herodot v0.9.13
github.com/ory/x v0.0.534
github.com/ory/x v0.0.535
github.com/otiai10/copy v1.9.0
github.com/pkg/errors v0.9.1
github.com/pquerna/otp v1.4.0
@ -40,9 +40,10 @@ require (
github.com/trustelem/zxcvbn v1.0.1
github.com/valyala/fasthttp v1.44.0
github.com/wneessen/go-mail v0.3.8
golang.org/x/net v0.6.0
golang.org/x/sync v0.1.0
golang.org/x/term v0.4.0
golang.org/x/text v0.6.0
golang.org/x/term v0.5.0
golang.org/x/text v0.7.0
gopkg.in/square/go-jose.v2 v2.6.0
gopkg.in/yaml.v3 v3.0.1
)
@ -64,7 +65,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.10 // indirect
github.com/go-crypt/x v0.1.12 // 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
@ -109,9 +110,8 @@ require (
github.com/ysmood/leakless v0.8.0 // indirect
golang.org/x/crypto v0.5.0 // indirect
golang.org/x/mod v0.7.0 // indirect
golang.org/x/net v0.5.0 // indirect
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect
golang.org/x/sys v0.4.0 // indirect
golang.org/x/sys v0.5.0 // indirect
golang.org/x/tools v0.4.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71 // indirect

36
go.sum
View File

@ -127,8 +127,8 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cu
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/duosecurity/duo_api_golang v0.0.0-20221117185402-091daa09e19d h1:DdF2JKufY7l8IBJuGeanPFR5gVpWJfEh1LWJFM/zDas=
github.com/duosecurity/duo_api_golang v0.0.0-20221117185402-091daa09e19d/go.mod h1:jI+QUTOK3wqIOrUl0Cwnwlgc/P6vs6pZOuQY3aKggwg=
github.com/duosecurity/duo_api_golang v0.0.0-20230203160531-b221c950c2b0 h1:+0VqbFomxHYZLIsuLJ7FjAdjhJTQ4P3/o6paTMx5kAY=
github.com/duosecurity/duo_api_golang v0.0.0-20230203160531-b221c950c2b0/go.mod h1:jI+QUTOK3wqIOrUl0Cwnwlgc/P6vs6pZOuQY3aKggwg=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/ecordell/optgen v0.0.6 h1:aSknPe6ZUBrjwHGp2+6XfmfCGYGD6W0ZDfCmmsrS7s4=
@ -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.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-crypt/crypt v0.2.5 h1:QYGV/OkamPz69fME+JbD0wVmPnAL3C1Ooypqb1FHnHk=
github.com/go-crypt/crypt v0.2.5/go.mod h1:VtajXhpCQlYwf4ekvp1I/6bSFi1YKobq0QInA1AFCQQ=
github.com/go-crypt/x v0.1.12 h1:UQvK75MBYGdeY7PdP/YbkUqiGxNzJq3BlO/lTVT6yuU=
github.com/go-crypt/x v0.1.12/go.mod h1:037K8Cyl2IJUzO297LjhDIeYZYxg7K8yzbCco6ZNtV0=
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=
@ -182,8 +182,8 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-rod/rod v0.112.4 h1:Ck002nM6rCORdVFtD778WxiadS5oJsmqytjXTG5bqiQ=
github.com/go-rod/rod v0.112.4/go.mod h1:ElViL9ABbcshNQw93+11FrYRH92RRhMKleuILo6+5V0=
github.com/go-rod/rod v0.112.5 h1:2mH97UK8We4D2MfX388WqPjG1lDbxx8lLi5MzfvnEo0=
github.com/go-rod/rod v0.112.5/go.mod h1:ElViL9ABbcshNQw93+11FrYRH92RRhMKleuILo6+5V0=
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=
@ -459,8 +459,8 @@ github.com/ory/go-convenience v0.1.0/go.mod h1:uEY/a60PL5c12nYz4V5cHY03IBmwIAEm8
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/go.mod h1:ypOuyJmEUb3oENywQZRgeAMwqgOyDqwboO1tj3DjTaM=
github.com/ory/x v0.0.534 h1:hc49pmcOuHdJ6rbHVGtJJ4/LU88dzDCtEQKfgeo/ecU=
github.com/ory/x v0.0.534/go.mod h1:CQopDsCC9t0tQsddE9UlyRFVEFd2xjKBVcw4nLMMMS0=
github.com/ory/x v0.0.535 h1:muhBRYkAz52J00yEGw6LtwJDF5HhyxM2w0E0V4w5z+o=
github.com/ory/x v0.0.535/go.mod h1:CQopDsCC9t0tQsddE9UlyRFVEFd2xjKBVcw4nLMMMS0=
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=
@ -749,8 +749,8 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -854,13 +854,13 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc
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.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.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.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/term v0.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg=
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
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=
@ -872,8 +872,8 @@ 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.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.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=

View File

@ -533,18 +533,16 @@ const (
storageMigrateDirectionDown = "down"
)
const (
timeLayoutCertificateNotBefore = "Jan 2 15:04:05 2006"
)
const (
cmdFlagNameDirectory = "directory"
cmdFlagNamePathCA = "path.ca"
cmdFlagNameBundle = "bundle"
cmdFlagNameFilePrivateKey = "file.private-key"
cmdFlagNameFilePublicKey = "file.public-key"
cmdFlagNameFileCertificate = "file.certificate"
cmdFlagNameFileCertificateBundle = "file.certificate-bundle"
cmdFlagNameFileCAPrivateKey = "file.ca-private-key"
cmdFlagNameFileCACertificate = "file.ca-certificate"
cmdFlagNameFileCSR = "file.csr"
@ -564,6 +562,7 @@ const (
cmdFlagNamePostcode = "postcode"
cmdFlagNameNotBefore = "not-before"
cmdFlagNameNotAfter = "not-after"
cmdFlagNameDuration = "duration"
cmdFlagNamePKCS8 = "pkcs8"
@ -749,4 +748,27 @@ Secrets:
way: 'key', 'secret', 'password', 'token'.
The available options and the specific secret mapping can be found here: https://www.authelia.com/configuration/methods/secrets/`
helpTopicTimeLayouts = `Several commands take date time inputs which are parsed. These inputs are parsed with
specific layouts in mind and these layouts are handled in order.
Format:
The layouts use a format where specific sequence of characters are representative of a portion of each timestamp.
See the go documentation for more information on how these layouts work, however the layouts are fairly self
explanatory and you can just use standard unix timestamps if desired.
Layouts:
Unix (µs): 1675899060000000
Unix (ms): 1675899060000
Unix (s): 1675899060
Simple: Jan 2 15:04:05 2006
Date Time: 2006-01-02 15:04:05
RFC3339: 2006-01-02T15:04:05Z07:00
RFC1123 with numeric timezone: Mon, 02 Jan 2006 15:04:05 -0700
Ruby Date: Mon Jan 02 15:04:05 -0700 2006
ANSIC: Mon Jan _2 15:04:05 2006
Date: 2006-01-02`
)

View File

@ -313,7 +313,7 @@ func (ctx *CmdCtx) CryptoCertificateRequestRunE(cmd *cobra.Command, _ []string)
b.WriteString(fmt.Sprintf("\n\tSubject Alternative Names: %s\n\n", strings.Join(cryptoSANsToString(template.DNSNames, template.IPAddresses), ", ")))
if privateKeyPath, csrPath, err = cryptoGetWritePathsFromCmd(cmd); err != nil {
if _, privateKeyPath, csrPath, err = cryptoGetWritePathsFromCmd(cmd); err != nil {
return err
}
@ -329,15 +329,11 @@ func (ctx *CmdCtx) CryptoCertificateRequestRunE(cmd *cobra.Command, _ []string)
return fmt.Errorf("failed to create certificate request: %w", err)
}
if privateKeyPath, csrPath, err = cryptoGetWritePathsFromCmd(cmd); err != nil {
return err
}
if err = utils.WriteKeyToPEM(privateKey, privateKeyPath, false); err != nil {
return err
}
if err = utils.WriteCertificateBytesToPEM(csr, csrPath, true); err != nil {
if err = utils.WriteCertificateBytesToPEM(csrPath, true, csr); err != nil {
return err
}
@ -406,21 +402,23 @@ func (ctx *CmdCtx) CryptoCertificateGenerateRunE(cmd *cobra.Command, _ []string,
b.WriteString(fmt.Sprintf("\n\tSubject Alternative Names: %s\n\n", strings.Join(cryptoSANsToString(template.DNSNames, template.IPAddresses), ", ")))
var (
privateKeyPath, certificatePath string
dir, privateKeyPath, certificatePath, certificateBundlePath string
bundle bool
certificate []byte
)
if privateKeyPath, certificatePath, err = cryptoGetWritePathsFromCmd(cmd); err != nil {
if dir, privateKeyPath, certificatePath, err = cryptoGetWritePathsFromCmd(cmd); err != nil {
return err
}
if bundle, certificateBundlePath, err = cryptoGetCertificateBundleFromCmd(cmd, dir, caCertificate); err != nil {
return err
}
b.WriteString("Output Paths:\n")
b.WriteString(fmt.Sprintf("\tPrivate Key: %s\n", privateKeyPath))
b.WriteString(fmt.Sprintf("\tCertificate: %s\n\n", certificatePath))
fmt.Print(b.String())
b.Reset()
b.WriteString(fmt.Sprintf("\tCertificate: %s\n", certificatePath))
if certificate, err = x509.CreateCertificate(ctx.providers.Random, template, parent, publicKey, signatureKey); err != nil {
return fmt.Errorf("failed to create certificate: %w", err)
@ -430,10 +428,24 @@ func (ctx *CmdCtx) CryptoCertificateGenerateRunE(cmd *cobra.Command, _ []string,
return err
}
if err = utils.WriteCertificateBytesToPEM(certificate, certificatePath, false); err != nil {
if err = utils.WriteCertificateBytesToPEM(certificatePath, false, certificate); err != nil {
return err
}
if bundle {
b.WriteString(fmt.Sprintf("\tCertificate (bundle): %s\n", certificateBundlePath))
if err = utils.WriteCertificateBytesToPEM(certificateBundlePath, false, certificate, caCertificate.Raw); err != nil {
return err
}
}
b.WriteString("\n")
fmt.Print(b.String())
b.Reset()
return nil
}
@ -448,7 +460,7 @@ func (ctx *CmdCtx) CryptoPairGenerateRunE(cmd *cobra.Command, _ []string, privat
return err
}
if privateKeyPath, publicKeyPath, err = cryptoGetWritePathsFromCmd(cmd); err != nil {
if _, privateKeyPath, publicKeyPath, err = cryptoGetWritePathsFromCmd(cmd); err != nil {
return err
}

View File

@ -32,8 +32,9 @@ func cmdFlagsCryptoCertificateCommon(cmd *cobra.Command) {
cmd.Flags().StringSliceP(cmdFlagNameStreetAddress, "s", nil, "certificate street address")
cmd.Flags().StringSliceP(cmdFlagNamePostcode, "p", nil, "certificate postcode")
cmd.Flags().String(cmdFlagNameNotBefore, "", fmt.Sprintf("earliest date and time the certificate is considered valid formatted as %s (default is now)", timeLayoutCertificateNotBefore))
cmd.Flags().Duration(cmdFlagNameDuration, 365*24*time.Hour, "duration of time the certificate is valid for")
cmd.Flags().String(cmdFlagNameNotBefore, "", "earliest date and time the certificate is considered valid in various formats (default is now)")
cmd.Flags().String(cmdFlagNameNotAfter, "", "latest date and time the certificate is considered valid in various formats")
cmd.Flags().String(cmdFlagNameDuration, "1y", "duration of time the certificate is valid for")
cmd.Flags().StringSlice(cmdFlagNameSANs, nil, "subject alternative names")
}
@ -42,6 +43,8 @@ func cmdFlagsCryptoCertificateGenerate(cmd *cobra.Command) {
cmd.Flags().String(cmdFlagNameFileCAPrivateKey, "ca.private.pem", "certificate authority private key to use to signing this certificate")
cmd.Flags().String(cmdFlagNameFileCACertificate, "ca.public.crt", "certificate authority certificate to use when signing this certificate")
cmd.Flags().String(cmdFlagNameFileCertificate, "public.crt", "name of the file to export the certificate data to")
cmd.Flags().String(cmdFlagNameFileCertificateBundle, "public.bundle.crt", fmt.Sprintf("name of the file to export the certificate bundle data to when the --%s flag is set", cmdFlagNameBundle))
cmd.Flags().Bool(cmdFlagNameBundle, false, fmt.Sprintf("enables generating the certificate bundle if the --%s flag is set", cmdFlagNamePathCA))
cmd.Flags().StringSlice(cmdFlagNameExtendedUsage, nil, "specify the extended usage types of the certificate")
@ -91,17 +94,15 @@ func cryptoSANsToString(dnsSANs []string, ipSANs []net.IP) (sans []string) {
return sans
}
func cryptoGetWritePathsFromCmd(cmd *cobra.Command) (privateKey, publicKey string, err error) {
var dir string
func cryptoGetWritePathsFromCmd(cmd *cobra.Command) (dir, privateKey, publicKey string, err error) {
if dir, err = cmd.Flags().GetString(cmdFlagNameDirectory); err != nil {
return "", "", err
return "", "", "", err
}
ca, _ := cmd.Flags().GetBool(cmdFlagNameCA)
csr := cmd.Use == cmdUseRequest
var private, public string
var pathPrivate, pathPublic string
var flagPrivate, flagPublic string
@ -118,15 +119,15 @@ func cryptoGetWritePathsFromCmd(cmd *cobra.Command) (privateKey, publicKey strin
flagPrivate, flagPublic = cmdFlagNameFilePrivateKey, cmdFlagNameFileCertificate
}
if private, err = cmd.Flags().GetString(flagPrivate); err != nil {
return "", "", err
if pathPrivate, err = cmd.Flags().GetString(flagPrivate); err != nil {
return "", "", "", err
}
if public, err = cmd.Flags().GetString(flagPublic); err != nil {
return "", "", err
if pathPublic, err = cmd.Flags().GetString(flagPublic); err != nil {
return "", "", "", err
}
return filepath.Join(dir, private), filepath.Join(dir, public), nil
return dir, filepath.Join(dir, pathPrivate), filepath.Join(dir, pathPublic), nil
}
func (ctx *CmdCtx) cryptoGenPrivateKeyFromCmd(cmd *cobra.Command) (privateKey any, err error) {
@ -169,6 +170,28 @@ func (ctx *CmdCtx) cryptoGenPrivateKeyFromCmd(cmd *cobra.Command) (privateKey an
return privateKey, nil
}
func cryptoGetCertificateBundleFromCmd(cmd *cobra.Command, dir string, caCertificate *x509.Certificate) (bundle bool, bundlePath string, err error) {
if bundle, err = cmd.Flags().GetBool(cmdFlagNameBundle); err != nil {
return false, "", err
}
if !bundle {
return bundle, bundlePath, err
}
if caCertificate == nil {
return false, "", fmt.Errorf("the --%s flag can't be used with self-signed certificates, you can specify the authority path using the --%s flag", cmdFlagNameBundle, cmdFlagNamePathCA)
}
if bundlePath, err = cmd.Flags().GetString(cmdFlagNameFileCertificateBundle); err != nil {
return false, "", err
}
bundlePath = filepath.Join(dir, bundlePath)
return bundle, bundlePath, err
}
func cryptoGetCAFromCmd(cmd *cobra.Command) (privateKey any, cert *x509.Certificate, err error) {
if !cmd.Flags().Changed(cmdFlagNamePathCA) {
return nil, nil, nil
@ -339,8 +362,8 @@ func (ctx *CmdCtx) cryptoGetCertificateFromCmd(cmd *cobra.Command) (certificate
var (
ca bool
subject *pkix.Name
notBeforeStr string
duration time.Duration
notBefore, notAfter time.Time
)
if ca, err = cmd.Flags().GetBool(cmdFlagNameCA); err != nil {
@ -351,30 +374,16 @@ func (ctx *CmdCtx) cryptoGetCertificateFromCmd(cmd *cobra.Command) (certificate
return nil, err
}
if notBeforeStr, err = cmd.Flags().GetString(cmdFlagNameNotBefore); err != nil {
return nil, err
}
if duration, err = cmd.Flags().GetDuration(cmdFlagNameDuration); err != nil {
if notBefore, notAfter, err = cryptoCertificateValidityFromCmd(cmd); err != nil {
return nil, err
}
var (
notBefore time.Time
serialNumber *big.Int
dnsSANs, extKeyUsages []string
ipSANs []net.IP
)
switch len(notBeforeStr) {
case 0:
notBefore = time.Now()
default:
if notBefore, err = time.Parse(timeLayoutCertificateNotBefore, notBeforeStr); err != nil {
return nil, fmt.Errorf("failed to parse not before: %w", err)
}
}
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
if serialNumber, err = ctx.providers.Random.IntErr(serialNumberLimit); err != nil {
@ -396,7 +405,7 @@ func (ctx *CmdCtx) cryptoGetCertificateFromCmd(cmd *cobra.Command) (certificate
Subject: *subject,
NotBefore: notBefore,
NotAfter: notBefore.Add(duration),
NotAfter: notAfter,
IsCA: ca,
@ -415,6 +424,57 @@ func (ctx *CmdCtx) cryptoGetCertificateFromCmd(cmd *cobra.Command) (certificate
return certificate, nil
}
func cryptoCertificateValidityFromCmd(cmd *cobra.Command) (notBefore, notAfter time.Time, err error) {
never := time.UnixMicro(0)
switch cmd.Flags().Changed(cmdFlagNameNotBefore) {
case true:
var notBeforeStr string
if notBeforeStr, err = cmd.Flags().GetString(cmdFlagNameNotBefore); err != nil {
return never, never, err
}
if notBefore, err = utils.ParseTimeString(notBeforeStr); err != nil {
return never, never, fmt.Errorf("failed to parse not before: %w", err)
}
default:
notBefore = time.Now()
}
switch useNotAfter := cmd.Flags().Changed(cmdFlagNameNotAfter); {
case useNotAfter && cmd.Flags().Changed(cmdFlagNameDuration):
return never, never, fmt.Errorf("failed to determine not after ")
case useNotAfter:
var notAfterStr string
if notAfterStr, err = cmd.Flags().GetString(cmdFlagNameNotAfter); err != nil {
return never, never, err
}
if notAfter, err = utils.ParseTimeString(notAfterStr); err != nil {
return never, never, fmt.Errorf("failed to parse not after: %w", err)
}
default:
var (
durationStr string
duration time.Duration
)
if durationStr, err = cmd.Flags().GetString(cmdFlagNameDuration); err != nil {
return never, never, err
}
if duration, err = utils.ParseDurationString(durationStr); err != nil {
return never, never, fmt.Errorf("failed to parse duration string: %w", err)
}
notAfter = notBefore.Add(duration)
}
return notBefore, notAfter, nil
}
func fmtCryptoHashUse(use string) string {
switch use {
case cmdUseHashArgon2:

View File

@ -58,6 +58,7 @@ func NewRootCmd() (cmd *cobra.Command) {
newHelpTopic("config", "Help for the config file/directory paths", helpTopicConfig),
newHelpTopic("filters", "help topic for the config filters", helpTopicConfigFilters),
newHelpTopic("time-layouts", "help topic for the various time layouts", helpTopicTimeLayouts),
)
return cmd

View File

@ -426,7 +426,7 @@ authentication_backend:
## changed once attributed to a user otherwise it would break the configuration for that user. Technically,
## non-unique attributes like 'mail' can also be used but we don't recommend using them, we instead advise to use
## a filter to perform alternative lookups and the attributes mentioned above (sAMAccountName and uid) to
## follow https://www.ietf.org/rfc/rfc2307.txt.
## follow https://datatracker.ietf.org/doc/html/rfc2307.
# username_attribute: uid
## The additional_users_dn is prefixed to base_dn and delimited by a comma when searching for users.

View File

@ -105,6 +105,9 @@ func TestShouldValidateConfigurationWithFilters(t *testing.T) {
testSetEnv(t, "JWT_SECRET", "abc")
testSetEnv(t, "AUTHENTICATION_BACKEND_LDAP_PASSWORD", "abc")
t.Setenv("ABC_CLIENT_SECRET", "$plaintext$example-abc")
t.Setenv("XYZ_CLIENT_SECRET", "$plaintext$example-xyz")
t.Setenv("ANOTHER_CLIENT_SECRET", "$plaintext$example-123")
t.Setenv("SERVICES_SERVER", "10.10.10.10")
t.Setenv("ROOT_DOMAIN", "example.org")
@ -118,6 +121,11 @@ func TestShouldValidateConfigurationWithFilters(t *testing.T) {
assert.Equal(t, "api-123456789.example.org", config.DuoAPI.Hostname)
assert.Equal(t, "10.10.10.10", config.Notifier.SMTP.Host)
assert.Equal(t, "10.10.10.10", config.Session.Redis.Host)
require.Len(t, config.IdentityProviders.OIDC.Clients, 3)
assert.Equal(t, "$plaintext$example-abc", config.IdentityProviders.OIDC.Clients[0].Secret.String())
assert.Equal(t, "$plaintext$example-xyz", config.IdentityProviders.OIDC.Clients[1].Secret.String())
assert.Equal(t, "$plaintext$example-123", config.IdentityProviders.OIDC.Clients[2].Secret.String())
}
func TestShouldNotIgnoreInvalidEnvs(t *testing.T) {

View File

@ -199,6 +199,20 @@ var DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory =
},
}
// DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis represents the default LDAP config for the LDAPImplementationRFC2307bis Implementation.
var DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis = LDAPAuthenticationBackend{
UsersFilter: "(&(|({username_attribute}={input})({mail_attribute}={input}))(|(objectClass=inetOrgPerson)(objectClass=organizationalPerson)))",
UsernameAttribute: ldapAttrUserID,
MailAttribute: ldapAttrMail,
DisplayNameAttribute: ldapAttrDisplayName,
GroupsFilter: "(&(|(member={dn})(uniqueMember={dn}))(|(objectClass=groupOfNames)(objectClass=groupOfUniqueNames)(objectClass=groupOfMembers)))",
GroupNameAttribute: ldapAttrCommonName,
Timeout: time.Second * 5,
TLS: &TLSConfig{
MinimumVersion: TLSVersion{tls.VersionTLS12},
},
}
// DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA represents the default LDAP config for the LDAPImplementationFreeIPA Implementation.
var DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA = LDAPAuthenticationBackend{
UsersFilter: "(&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person)(!(nsAccountLock=TRUE))(krbPasswordExpiration>={date-time:generalized})(|(!(krbPrincipalExpiration=*))(krbPrincipalExpiration>={date-time:generalized})))",

View File

@ -65,6 +65,9 @@ const (
// LDAPImplementationActiveDirectory is the string for the Active Directory LDAP implementation.
LDAPImplementationActiveDirectory = "activedirectory"
// LDAPImplementationRFC2307bis is the string for the RFC2307bis LDAP implementation.
LDAPImplementationRFC2307bis = "rfc2307bis"
// LDAPImplementationFreeIPA is the string for the FreeIPA LDAP implementation.
LDAPImplementationFreeIPA = "freeipa"

View File

@ -174,4 +174,21 @@ notifier:
port: 1025
sender: 'admin@{{ env "ROOT_DOMAIN" }}'
disable_require_tls: true
identity_providers:
oidc:
cors:
allowed_origins:
- https://google.com
- https://example.com
clients:
- id: abc
secret: '${ABC_CLIENT_SECRET}'
consent_mode: explicit
- id: xyz
secret: '$XYZ_CLIENT_SECRET'
consent_mode: explicit
- id: '123'
secret: $ANOTHER_CLIENT_SECRET
consent_mode: explicit
...

View File

@ -321,49 +321,19 @@ func validateLDAPAuthenticationBackend(config *schema.AuthenticationBackend, val
config.LDAP.Implementation = schema.LDAPImplementationCustom
}
var implementation *schema.LDAPAuthenticationBackend
switch config.LDAP.Implementation {
case schema.LDAPImplementationCustom:
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationCustom
case schema.LDAPImplementationActiveDirectory:
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory
case schema.LDAPImplementationFreeIPA:
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA
case schema.LDAPImplementationLLDAP:
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP
case schema.LDAPImplementationGLAuth:
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth
default:
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendImplementation, config.LDAP.Implementation, strings.Join(validLDAPImplementations, "', '")))
}
configDefaultTLS := &schema.TLSConfig{}
if implementation != nil {
if config.LDAP.Timeout == 0 {
config.LDAP.Timeout = implementation.Timeout
}
configDefaultTLS = &schema.TLSConfig{
MinimumVersion: implementation.TLS.MinimumVersion,
MaximumVersion: implementation.TLS.MaximumVersion,
}
setDefaultImplementationLDAPAuthenticationBackendProfileAttributes(config.LDAP, implementation)
}
defaultTLS := validateLDAPAuthenticationBackendImplementation(config, validator)
if config.LDAP.URL == "" {
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendMissingOption, "url"))
} else {
configDefaultTLS.ServerName = validateLDAPAuthenticationBackendURL(config.LDAP, validator)
defaultTLS.ServerName = validateLDAPAuthenticationBackendURL(config.LDAP, validator)
}
if config.LDAP.TLS == nil {
config.LDAP.TLS = &schema.TLSConfig{}
}
if err := ValidateTLSConfig(config.LDAP.TLS, configDefaultTLS); err != nil {
if err := ValidateTLSConfig(config.LDAP.TLS, defaultTLS); err != nil {
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendTLSConfigInvalid, err))
}
@ -382,6 +352,44 @@ func validateLDAPAuthenticationBackend(config *schema.AuthenticationBackend, val
validateLDAPRequiredParameters(config, validator)
}
func validateLDAPAuthenticationBackendImplementation(config *schema.AuthenticationBackend, validator *schema.StructValidator) *schema.TLSConfig {
var implementation *schema.LDAPAuthenticationBackend
switch config.LDAP.Implementation {
case schema.LDAPImplementationCustom:
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationCustom
case schema.LDAPImplementationActiveDirectory:
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory
case schema.LDAPImplementationRFC2307bis:
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis
case schema.LDAPImplementationFreeIPA:
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA
case schema.LDAPImplementationLLDAP:
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP
case schema.LDAPImplementationGLAuth:
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth
default:
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendImplementation, config.LDAP.Implementation, strings.Join(validLDAPImplementations, "', '")))
}
tlsconfig := &schema.TLSConfig{}
if implementation != nil {
if config.LDAP.Timeout == 0 {
config.LDAP.Timeout = implementation.Timeout
}
tlsconfig = &schema.TLSConfig{
MinimumVersion: implementation.TLS.MinimumVersion,
MaximumVersion: implementation.TLS.MaximumVersion,
}
setDefaultImplementationLDAPAuthenticationBackendProfileAttributes(config.LDAP, implementation)
}
return tlsconfig
}
func ldapImplementationShouldSetStr(config, implementation string) bool {
return config == "" && implementation != ""
}

View File

@ -609,7 +609,7 @@ func (suite *LDAPAuthenticationBackendSuite) TestShouldRaiseErrorWhenImplementat
suite.Assert().Len(suite.validator.Warnings(), 0)
suite.Require().Len(suite.validator.Errors(), 1)
suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: ldap: option 'implementation' is configured as 'masd' but must be one of the following values: 'custom', 'activedirectory', 'freeipa', 'lldap'")
suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: ldap: option 'implementation' is configured as 'masd' but must be one of the following values: 'custom', 'activedirectory', 'rfc2307bis', 'freeipa', 'lldap', 'glauth'")
}
func (suite *LDAPAuthenticationBackendSuite) TestShouldRaiseErrorWhenURLNotProvided() {
@ -1002,6 +1002,108 @@ func TestActiveDirectoryAuthenticationBackend(t *testing.T) {
suite.Run(t, new(ActiveDirectoryAuthenticationBackendSuite))
}
type RFC2307bisAuthenticationBackendSuite struct {
suite.Suite
config schema.AuthenticationBackend
validator *schema.StructValidator
}
func (suite *RFC2307bisAuthenticationBackendSuite) SetupTest() {
suite.validator = schema.NewStructValidator()
suite.config = schema.AuthenticationBackend{}
suite.config.LDAP = &schema.LDAPAuthenticationBackend{}
suite.config.LDAP.Implementation = schema.LDAPImplementationRFC2307bis
suite.config.LDAP.URL = testLDAPURL
suite.config.LDAP.User = testLDAPUser
suite.config.LDAP.Password = testLDAPPassword
suite.config.LDAP.BaseDN = testLDAPBaseDN
suite.config.LDAP.TLS = schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.TLS
}
func (suite *RFC2307bisAuthenticationBackendSuite) TestShouldSetDefaults() {
ValidateAuthenticationBackend(&suite.config, suite.validator)
suite.Assert().Len(suite.validator.Warnings(), 0)
suite.Assert().Len(suite.validator.Errors(), 0)
suite.Assert().Equal(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.Timeout,
suite.config.LDAP.Timeout)
suite.Assert().Equal(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.AdditionalUsersDN,
suite.config.LDAP.AdditionalUsersDN)
suite.Assert().Equal(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.AdditionalGroupsDN,
suite.config.LDAP.AdditionalGroupsDN)
suite.Assert().Equal(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.UsersFilter,
suite.config.LDAP.UsersFilter)
suite.Assert().Equal(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.UsernameAttribute,
suite.config.LDAP.UsernameAttribute)
suite.Assert().Equal(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.DisplayNameAttribute,
suite.config.LDAP.DisplayNameAttribute)
suite.Assert().Equal(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.MailAttribute,
suite.config.LDAP.MailAttribute)
suite.Assert().Equal(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.GroupsFilter,
suite.config.LDAP.GroupsFilter)
suite.Assert().Equal(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.GroupNameAttribute,
suite.config.LDAP.GroupNameAttribute)
}
func (suite *RFC2307bisAuthenticationBackendSuite) TestShouldOnlySetDefaultsIfNotManuallyConfigured() {
suite.config.LDAP.Timeout = time.Second * 2
suite.config.LDAP.UsersFilter = "(&({username_attribute}={input})(objectClass=Person))"
suite.config.LDAP.UsernameAttribute = "o"
suite.config.LDAP.MailAttribute = "Email"
suite.config.LDAP.DisplayNameAttribute = "Given"
suite.config.LDAP.GroupsFilter = "(&(member={dn})(objectClass=posixGroup)(objectClass=top))"
suite.config.LDAP.GroupNameAttribute = "gid"
suite.config.LDAP.AdditionalUsersDN = "OU=users,OU=OpenLDAP"
suite.config.LDAP.AdditionalGroupsDN = "OU=groups,OU=OpenLDAP"
ValidateAuthenticationBackend(&suite.config, suite.validator)
suite.Assert().NotEqual(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.Timeout,
suite.config.LDAP.Timeout)
suite.Assert().NotEqual(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.AdditionalUsersDN,
suite.config.LDAP.AdditionalUsersDN)
suite.Assert().NotEqual(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.AdditionalGroupsDN,
suite.config.LDAP.AdditionalGroupsDN)
suite.Assert().NotEqual(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.Timeout,
suite.config.LDAP.Timeout)
suite.Assert().NotEqual(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.UsersFilter,
suite.config.LDAP.UsersFilter)
suite.Assert().NotEqual(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.UsernameAttribute,
suite.config.LDAP.UsernameAttribute)
suite.Assert().NotEqual(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.DisplayNameAttribute,
suite.config.LDAP.DisplayNameAttribute)
suite.Assert().NotEqual(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.MailAttribute,
suite.config.LDAP.MailAttribute)
suite.Assert().NotEqual(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.GroupsFilter,
suite.config.LDAP.GroupsFilter)
suite.Assert().NotEqual(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.GroupNameAttribute,
suite.config.LDAP.GroupNameAttribute)
}
func TestRFC2307bisAuthenticationBackend(t *testing.T) {
suite.Run(t, new(RFC2307bisAuthenticationBackendSuite))
}
type FreeIPAAuthenticationBackendSuite struct {
suite.Suite
config schema.AuthenticationBackend

View File

@ -160,7 +160,7 @@ func TestShouldRaiseErrorOnInvalidCertificatesDirectory(t *testing.T) {
func TestShouldNotRaiseErrorOnValidCertificatesDirectory(t *testing.T) {
validator := schema.NewStructValidator()
config := newDefaultConfig()
config.CertificatesDirectory = "../../suites/common/ssl"
config.CertificatesDirectory = "../../suites/common/pki"
ValidateConfiguration(&config, validator)

View File

@ -267,7 +267,9 @@ const (
errFmtSessionDomainDuplicateCookieScope = "session: domain config %s: option 'domain' shares the same cookie domain scope as another configured session domain"
errFmtSessionDomainPortalURLInsecure = "session: domain config %s: option 'authelia_url' does not have a secure scheme with a value of '%s'"
errFmtSessionDomainPortalURLNotInCookieScope = "session: domain config %s: option 'authelia_url' does not share a cookie scope with domain '%s' with a value of '%s'"
errFmtSessionDomainInvalidDomain = "session: domain config %s: option 'domain' is not a valid domain"
errFmtSessionDomainInvalidDomain = "session: domain config %s: option 'domain' is not a valid cookie domain"
errFmtSessionDomainInvalidDomainNoDots = "session: domain config %s: option 'domain' is not a valid cookie domain: must have at least a single period"
errFmtSessionDomainInvalidDomainPublic = "session: domain config %s: option 'domain' is not a valid cookie domain: the domain is part of the special public suffix list"
)
// Regulation Error Consts.
@ -337,7 +339,14 @@ const (
)
var (
validLDAPImplementations = []string{schema.LDAPImplementationCustom, schema.LDAPImplementationActiveDirectory, schema.LDAPImplementationFreeIPA, schema.LDAPImplementationLLDAP}
validLDAPImplementations = []string{
schema.LDAPImplementationCustom,
schema.LDAPImplementationActiveDirectory,
schema.LDAPImplementationRFC2307bis,
schema.LDAPImplementationFreeIPA,
schema.LDAPImplementationLLDAP,
schema.LDAPImplementationGLAuth,
}
)
const (

View File

@ -104,12 +104,22 @@ func validateSessionDomainName(i int, config *schema.SessionConfiguration, valid
switch {
case d.Domain == "":
validator.Push(fmt.Errorf(errFmtSessionDomainRequired, sessionDomainDescriptor(i, d)))
return
case strings.HasPrefix(d.Domain, "*."):
validator.Push(fmt.Errorf(errFmtSessionDomainMustBeRoot, sessionDomainDescriptor(i, d), d.Domain))
return
case strings.HasPrefix(d.Domain, "."):
validator.PushWarning(fmt.Errorf(errFmtSessionDomainHasPeriodPrefix, sessionDomainDescriptor(i, d)))
case !strings.Contains(d.Domain, "."):
validator.Push(fmt.Errorf(errFmtSessionDomainInvalidDomainNoDots, sessionDomainDescriptor(i, d)))
return
case !reDomainCharacters.MatchString(d.Domain):
validator.Push(fmt.Errorf(errFmtSessionDomainInvalidDomain, sessionDomainDescriptor(i, d)))
return
}
if isCookieDomainAPublicSuffix(d.Domain) {
validator.Push(fmt.Errorf(errFmtSessionDomainInvalidDomainPublic, sessionDomainDescriptor(i, d)))
}
}

View File

@ -586,45 +586,6 @@ func TestShouldRaiseErrorOnBadRedisTLSOptionsMinVerGreaterThanMax(t *testing.T)
assert.EqualError(t, validator.Errors()[0], "session: redis: tls: option combination of 'minimum_version' and 'maximum_version' is invalid: minimum version TLS1.3 is greater than the maximum version TLS1.0")
}
func TestShouldRaiseErrorWhenDomainNotSet(t *testing.T) {
validator := schema.NewStructValidator()
config := newDefaultSessionConfig()
config.Domain = ""
config.Cookies = []schema.SessionCookieConfiguration{}
ValidateSession(&config, validator)
assert.False(t, validator.HasWarnings())
assert.Len(t, validator.Errors(), 1)
assert.EqualError(t, validator.Errors()[0], "session: option 'domain' is required")
}
func TestShouldRaiseErrorWhenDomainIsWildcard(t *testing.T) {
validator := schema.NewStructValidator()
config := newDefaultSessionConfig()
config.Domain = "*.example.com"
ValidateSession(&config, validator)
assert.Len(t, validator.Warnings(), 0)
require.Len(t, validator.Errors(), 1)
assert.EqualError(t, validator.Errors()[0], "session: domain config #1 (domain '*.example.com'): option 'domain' must be the domain you wish to protect not a wildcard domain but it is configured as '*.example.com'")
}
func TestShouldRaiseErrorWhenDomainNameIsInvalid(t *testing.T) {
validator := schema.NewStructValidator()
config := newDefaultSessionConfig()
config.Domain = "example!.com"
ValidateSession(&config, validator)
assert.Len(t, validator.Warnings(), 0)
require.Len(t, validator.Errors(), 1)
assert.EqualError(t, validator.Errors()[0], "session: domain config #1 (domain 'example!.com'): option 'domain' is not a valid domain")
}
func TestShouldRaiseErrorWhenHaveDuplicatedDomainName(t *testing.T) {
validator := schema.NewStructValidator()
config := newDefaultSessionConfig()
@ -675,10 +636,18 @@ func TestShouldRaiseErrorWhenDomainIsInvalid(t *testing.T) {
testCases := []struct {
name string
have string
warnings []string
expected []string
}{
{"ShouldRaiseErrorOnMissingDomain", "", []string{"session: domain config #1 (domain ''): option 'domain' is required"}},
{"ShouldNotRaiseErrorOnValidDomain", exampleDotCom, nil},
{"ShouldNotRaiseErrorOnValidDomain", exampleDotCom, nil, nil},
{"ShouldRaiseErrorOnMissingDomain", "", nil, []string{"session: domain config #1 (domain ''): option 'domain' is required"}},
{"ShouldRaiseErrorOnDomainWithInvalidChars", "example!.com", nil, []string{"session: domain config #1 (domain 'example!.com'): option 'domain' is not a valid cookie domain"}},
{"ShouldRaiseErrorOnDomainWithoutDots", "localhost", nil, []string{"session: domain config #1 (domain 'localhost'): option 'domain' is not a valid cookie domain: must have at least a single period"}},
{"ShouldRaiseErrorOnPublicDomainDuckDNS", "duckdns.org", nil, []string{"session: domain config #1 (domain 'duckdns.org'): option 'domain' is not a valid cookie domain: the domain is part of the special public suffix list"}},
{"ShouldNotRaiseErrorOnSuffixOfPublicDomainDuckDNS", "example.duckdns.org", nil, nil},
{"ShouldRaiseWarningOnDomainWithLeadingDot", ".example.com", []string{"session: domain config #1 (domain '.example.com'): option 'domain' has a prefix of '.' which is not supported or intended behaviour: you can use this at your own risk but we recommend removing it"}, nil},
{"ShouldRaiseErrorOnDomainWithLeadingStarDot", "*.example.com", nil, []string{"session: domain config #1 (domain '*.example.com'): option 'domain' must be the domain you wish to protect not a wildcard domain but it is configured as '*.example.com'"}},
{"ShouldRaiseErrorOnDomainNotSet", "", nil, []string{"session: domain config #1 (domain ''): option 'domain' is required"}},
}
for _, tc := range testCases {
@ -692,14 +661,18 @@ func TestShouldRaiseErrorWhenDomainIsInvalid(t *testing.T) {
SessionCookieCommonConfiguration: schema.SessionCookieCommonConfiguration{
Domain: tc.have,
},
AutheliaURL: MustParseURL("https://auth.example.com")},
},
}
ValidateSession(&config, validator)
assert.Len(t, validator.Warnings(), 0)
require.Len(t, validator.Warnings(), len(tc.warnings))
require.Len(t, validator.Errors(), len(tc.expected))
for i, expected := range tc.warnings {
assert.EqualError(t, validator.Warnings()[i], expected)
}
for i, expected := range tc.expected {
assert.EqualError(t, validator.Errors()[i], expected)
}

View File

@ -0,0 +1,15 @@
package validator
import (
"strings"
"golang.org/x/net/publicsuffix"
)
func isCookieDomainAPublicSuffix(domain string) (valid bool) {
var suffix string
suffix, _ = publicsuffix.PublicSuffix(domain)
return len(strings.TrimLeft(domain, ".")) == len(suffix)
}

View File

@ -0,0 +1,40 @@
package validator
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestIsCookieDomainValid(t *testing.T) {
testCases := []struct {
domain string
expected bool
}{
{"example.com", false},
{".example.com", false},
{"*.example.com", false},
{"authelia.com", false},
{"duckdns.org", true},
{".duckdns.org", true},
{"example.duckdns.org", false},
{"192.168.2.1", false},
{"localhost", true},
{"com", true},
{"randomnada", true},
}
for _, tc := range testCases {
name := "ShouldFail"
if tc.expected {
name = "ShouldPass"
}
t.Run(tc.domain, func(t *testing.T) {
t.Run(name, func(t *testing.T) {
assert.Equal(t, tc.expected, isCookieDomainAPublicSuffix(tc.domain))
})
})
}
}

View File

@ -234,11 +234,11 @@ func (p *CORSPolicy) handleOPTIONS(ctx *fasthttp.RequestCtx) {
/* The OPTIONS method should not return a 204 as per the following specifications when read together:
RFC7231 (https://www.rfc-editor.org/rfc/rfc7231#section-4.3.7):
RFC7231 (https://datatracker.ietf.org/doc/html/rfc7231#section-4.3.7):
A server MUST generate a Content-Length field with a value of "0" if no payload body is to be sent in
the response.
RFC7230 (https://www.rfc-editor.org/rfc/rfc7230#section-3.3.2):
RFC7230 (https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2):
A server MUST NOT send a Content-Length header field in any response with a status code of 1xx (Informational)
or 204 (No Content).
*/

View File

@ -121,33 +121,48 @@ func (mr *MockRandomMockRecorder) IntErr(arg0 interface{}) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IntErr", reflect.TypeOf((*MockRandom)(nil).IntErr), arg0)
}
// Integer mocks base method.
func (m *MockRandom) Integer(arg0 int) int {
// Intn mocks base method.
func (m *MockRandom) Intn(arg0 int) int {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Integer", arg0)
ret := m.ctrl.Call(m, "Intn", arg0)
ret0, _ := ret[0].(int)
return ret0
}
// Integer indicates an expected call of Integer.
func (mr *MockRandomMockRecorder) Integer(arg0 interface{}) *gomock.Call {
// Intn indicates an expected call of Intn.
func (mr *MockRandomMockRecorder) Intn(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Integer", reflect.TypeOf((*MockRandom)(nil).Integer), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Intn", reflect.TypeOf((*MockRandom)(nil).Intn), arg0)
}
// IntegerErr mocks base method.
func (m *MockRandom) IntegerErr(arg0 int) (int, error) {
// IntnErr mocks base method.
func (m *MockRandom) IntnErr(arg0 int) (int, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "IntegerErr", arg0)
ret := m.ctrl.Call(m, "IntnErr", arg0)
ret0, _ := ret[0].(int)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// IntegerErr indicates an expected call of IntegerErr.
func (mr *MockRandomMockRecorder) IntegerErr(arg0 interface{}) *gomock.Call {
// IntnErr indicates an expected call of IntnErr.
func (mr *MockRandomMockRecorder) IntnErr(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IntegerErr", reflect.TypeOf((*MockRandom)(nil).IntegerErr), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IntnErr", reflect.TypeOf((*MockRandom)(nil).IntnErr), arg0)
}
// Prime mocks base method.
func (m *MockRandom) Prime(arg0 int) (*big.Int, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Prime", arg0)
ret0, _ := ret[0].(*big.Int)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Prime indicates an expected call of Prime.
func (mr *MockRandomMockRecorder) Prime(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Prime", reflect.TypeOf((*MockRandom)(nil).Prime), arg0)
}
// Read mocks base method.

View File

@ -163,8 +163,8 @@ func (n *SMTPNotifier) Send(ctx context.Context, recipient mail.Address, subject
}
func (n *SMTPNotifier) setMessageID(msg *gomail.Msg, domain string) {
rn := n.random.Integer(100000000)
rm := n.random.Integer(10000)
rn := n.random.Intn(100000000)
rm := n.random.Intn(10000)
rs := n.random.StringCustom(17, random.CharSetAlphaNumeric)
pid := os.Getpid() + rm

View File

@ -180,7 +180,7 @@ func (s *Store) DeleteAccessTokenSession(ctx context.Context, signature string)
return s.revokeSessionBySignature(ctx, storage.OAuth2SessionTypeAccessToken, signature)
}
// RevokeAccessToken revokes an access token as specified in: https://tools.ietf.org/html/rfc7009#section-2.1
// RevokeAccessToken revokes an access token as specified in: https://datatracker.ietf.org/doc/html/rfc7009#section-2.1
// If the token passed to the request is an access token, the server MAY revoke the respective refresh token as well.
// This implements a portion of oauth2.TokenRevocationStorage.
func (s *Store) RevokeAccessToken(ctx context.Context, requestID string) (err error) {
@ -205,7 +205,7 @@ func (s *Store) DeleteRefreshTokenSession(ctx context.Context, signature string)
return s.revokeSessionBySignature(ctx, storage.OAuth2SessionTypeRefreshToken, signature)
}
// RevokeRefreshToken revokes a refresh token as specified in: https://tools.ietf.org/html/rfc7009#section-2.1
// RevokeRefreshToken revokes a refresh token as specified in: https://datatracker.ietf.org/doc/html/rfc7009#section-2.1
// If the particular token is a refresh token and the authorization server supports the revocation of access tokens,
// then the authorization server SHOULD also invalidate all access tokens based on the same authorization grant (see Implementation Note).
// This implements a portion of oauth2.TokenRevocationStorage.
@ -213,7 +213,7 @@ func (s *Store) RevokeRefreshToken(ctx context.Context, requestID string) (err e
return s.provider.DeactivateOAuth2SessionByRequestID(ctx, storage.OAuth2SessionTypeRefreshToken, requestID)
}
// RevokeRefreshTokenMaybeGracePeriod revokes an access token as specified in: https://tools.ietf.org/html/rfc7009#section-2.1
// RevokeRefreshTokenMaybeGracePeriod revokes an access token as specified in: https://datatracker.ietf.org/doc/html/rfc7009#section-2.1
// If the token passed to the request is an access token, the server MAY revoke the respective refresh token as well.
// This implements a portion of oauth2.TokenRevocationStorage.
func (s *Store) RevokeRefreshTokenMaybeGracePeriod(ctx context.Context, requestID string, signature string) (err error) {

View File

@ -25,7 +25,7 @@ const (
CharSetSymbolic = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
// CharSetSymbolicRFC3986Unreserved are RFC3986 unreserved symbol characters.
// See https://www.rfc-editor.org/rfc/rfc3986#section-2.3.
// See https://datatracker.ietf.org/doc/html/rfc3986#section-2.3.
CharSetSymbolicRFC3986Unreserved = "-._~"
// CharSetAlphaNumeric are literally just valid alphanumeric printable ASCII chars.
@ -35,7 +35,7 @@ const (
CharSetASCII = CharSetAlphabetic + CharSetNumeric + CharSetSymbolic
// CharSetRFC3986Unreserved are RFC3986 unreserved characters.
// See https://www.rfc-editor.org/rfc/rfc3986#section-2.3.
// See https://datatracker.ietf.org/doc/html/rfc3986#section-2.3.
CharSetRFC3986Unreserved = CharSetAlphabetic + CharSetNumeric + CharSetSymbolicRFC3986Unreserved
// CharSetUnambiguousUpper are a set of unambiguous uppercase characters.

View File

@ -18,11 +18,7 @@ func (r *Cryptographical) Read(p []byte) (n int, err error) {
// BytesErr returns random data as bytes with the standard random.DefaultN length and can contain any byte values
// (including unreadable byte values). If an error is returned from the random read this function returns it.
func (r *Cryptographical) BytesErr() (data []byte, err error) {
data = make([]byte, DefaultN)
_, err = rand.Read(data)
return data, err
return r.BytesCustomErr(0, nil)
}
// Bytes returns random data as bytes with the standard random.DefaultN length and can contain any byte values
@ -49,9 +45,11 @@ func (r *Cryptographical) BytesCustomErr(n int, charset []byte) (data []byte, er
t := len(charset)
if t > 0 {
for i := 0; i < n; i++ {
data[i] = charset[data[i]%byte(t)]
}
}
return data, nil
}
@ -81,6 +79,36 @@ func (r *Cryptographical) StringCustom(n int, characters string) (data string) {
return string(r.BytesCustom(n, []byte(characters)))
}
// IntnErr returns a random int error combination with a maximum of n.
func (r *Cryptographical) IntnErr(n int) (value int, err error) {
if n <= 0 {
return 0, fmt.Errorf("n must be more than 0")
}
max := big.NewInt(int64(n))
var result *big.Int
if result, err = r.IntErr(max); err != nil {
return 0, err
}
value = int(result.Int64())
if value < 0 {
return 0, fmt.Errorf("generated number is too big for int")
}
return value, nil
}
// Intn returns a random int with a maximum of n.
func (r *Cryptographical) Intn(n int) (value int) {
value, _ = r.IntnErr(n)
return value
}
// IntErr returns a random *big.Int error combination with a maximum of max.
func (r *Cryptographical) IntErr(max *big.Int) (value *big.Int, err error) {
if max == nil {
@ -105,32 +133,8 @@ func (r *Cryptographical) Int(max *big.Int) (value *big.Int) {
return value
}
// IntegerErr returns a random int error combination with a maximum of n.
func (r *Cryptographical) IntegerErr(n int) (value int, err error) {
if n <= 0 {
return 0, fmt.Errorf("n must be more than 0")
}
max := big.NewInt(int64(n))
var result *big.Int
if result, err = r.IntErr(max); err != nil {
return 0, err
}
value = int(result.Int64())
if value < 0 {
return 0, fmt.Errorf("generated number is too big for int")
}
return value, nil
}
// Integer returns a random int with a maximum of n.
func (r *Cryptographical) Integer(n int) (value int) {
value, _ = r.IntegerErr(n)
return value
// Prime returns a number of the given bit length that is prime with high probability. Prime will return error for any
// error returned by rand.Read or if bits < 2.
func (r *Cryptographical) Prime(bits int) (prime *big.Int, err error) {
return rand.Prime(rand.Reader, bits)
}

View File

@ -1,26 +1,36 @@
package random
import (
crand "crypto/rand"
"fmt"
"math/big"
"math/rand"
"sync"
"time"
)
// NewMathematical runs rand.Seed with the current time and returns a random.Provider, specifically *random.Mathematical.
func NewMathematical() *Mathematical {
rand.Seed(time.Now().UnixNano())
return &Mathematical{}
return &Mathematical{
rand: rand.New(rand.NewSource(time.Now().UnixNano())), //nolint:gosec
lock: &sync.Mutex{},
}
}
// Mathematical is the random.Provider which uses math/rand and is COMPLETELY UNSAFE FOR PRODUCTION IN MOST SITUATIONS.
// Use random.Cryptographical instead.
type Mathematical struct{}
type Mathematical struct {
rand *rand.Rand
lock *sync.Mutex
}
// Read implements the io.Reader interface.
func (r *Mathematical) Read(p []byte) (n int, err error) {
return rand.Read(p) //nolint:gosec
r.lock.Lock()
defer r.lock.Unlock()
return r.rand.Read(p)
}
// BytesErr returns random data as bytes with the standard random.DefaultN length and can contain any byte values
@ -28,7 +38,7 @@ func (r *Mathematical) Read(p []byte) (n int, err error) {
func (r *Mathematical) BytesErr() (data []byte, err error) {
data = make([]byte, DefaultN)
if _, err = rand.Read(data); err != nil { //nolint:gosec
if _, err = r.Read(data); err != nil {
return nil, err
}
@ -53,7 +63,7 @@ func (r *Mathematical) BytesCustomErr(n int, charset []byte) (data []byte, err e
data = make([]byte, n)
if _, err = rand.Read(data); err != nil { //nolint:gosec
if _, err = r.Read(data); err != nil {
return nil, err
}
@ -91,17 +101,18 @@ func (r *Mathematical) StringCustom(n int, characters string) (data string) {
return string(r.BytesCustom(n, []byte(characters)))
}
// IntErr returns a random *big.Int error combination with a maximum of max.
func (r *Mathematical) IntErr(max *big.Int) (value *big.Int, err error) {
if max == nil {
return nil, fmt.Errorf("max is required")
}
// Intn returns a random int with a maximum of n.
func (r *Mathematical) Intn(n int) int {
r.lock.Lock()
if max.Sign() <= 0 {
return nil, fmt.Errorf("max must be 1 or more")
}
defer r.lock.Unlock()
return big.NewInt(int64(rand.Intn(max.Sign()))), nil //nolint:gosec
return r.rand.Intn(n)
}
// IntnErr returns a random int error combination with a maximum of n.
func (r *Mathematical) IntnErr(n int) (output int, err error) {
return r.Intn(n), nil
}
// Int returns a random *big.Int with a maximum of max.
@ -115,12 +126,25 @@ func (r *Mathematical) Int(max *big.Int) (value *big.Int) {
return value
}
// IntegerErr returns a random int error combination with a maximum of n.
func (r *Mathematical) IntegerErr(n int) (output int, err error) {
return r.Integer(n), nil
// IntErr returns a random *big.Int error combination with a maximum of max.
func (r *Mathematical) IntErr(max *big.Int) (value *big.Int, err error) {
if max == nil {
return nil, fmt.Errorf("max is required")
}
if max.Sign() <= 0 {
return nil, fmt.Errorf("max must be 1 or more")
}
r.lock.Lock()
defer r.lock.Unlock()
return big.NewInt(int64(r.Intn(max.Sign()))), nil
}
// Integer returns a random int with a maximum of n.
func (r *Mathematical) Integer(n int) int {
return rand.Intn(n) //nolint:gosec
// Prime returns a number of the given bit length that is prime with high probability. Prime will return error for any
// error returned by rand.Read or if bits < 2.
func (r *Mathematical) Prime(bits int) (prime *big.Int, err error) {
return crand.Prime(r, bits)
}

View File

@ -32,15 +32,19 @@ type Provider interface {
// StringCustom is an overload of GenerateCustom which takes a characters string and returns a string.
StringCustom(n int, characters string) (data string)
// Intn returns a random integer with a maximum of n.
Intn(n int) (value int)
// IntnErr returns a random int error combination with a maximum of n.
IntnErr(n int) (value int, err error)
// IntErr returns a random *big.Int error combination with a maximum of max.
IntErr(max *big.Int) (value *big.Int, err error)
// Int returns a random *big.Int with a maximum of max.
Int(max *big.Int) (value *big.Int)
// IntegerErr returns a random int error combination with a maximum of n.
IntegerErr(n int) (value int, err error)
// Integer returns a random integer with a maximum of n.
Integer(n int) (value int)
// Prime returns a number of the given bit length that is prime with high probability. Prime will return error for any
// error returned by rand.Read or if bits < 2.
Prime(bits int) (prime *big.Int, err error)
}

View File

@ -10,8 +10,8 @@ default_redirection_url: https://home.example.com:8080/
server:
port: 9091
tls:
certificate: /config/ssl/cert.pem
key: /config/ssl/key.pem
certificate: /pki/public.backend.crt
key: /pki/private.backend.pem
log:
level: debug

View File

@ -4,5 +4,5 @@ services:
authelia-backend:
volumes:
- './ActiveDirectory/configuration.yml:/config/configuration.yml:ro'
- './common/ssl:/config/ssl:ro'
- './common/pki:/pki:ro'
...

View File

@ -6,8 +6,8 @@
server:
port: 9091
tls:
certificate: /config/ssl/cert.pem
key: /config/ssl/key.pem
certificate: /pki/public.backend.crt
key: /pki/private.backend.pem
log:
level: debug

View File

@ -5,5 +5,5 @@ services:
volumes:
- './BypassAll/configuration.yml:/config/configuration.yml:ro'
- './BypassAll/users.yml:/config/users.yml'
- './common/ssl:/config/ssl:ro'
- './common/pki:/pki:ro'
...

View File

@ -6,8 +6,8 @@
server:
port: 9091
tls:
certificate: /config/ssl/cert.pem
key: /config/ssl/key.pem
certificate: /pki/public.backend.crt
key: /pki/private.backend.pem
log:
level: debug

View File

@ -6,7 +6,7 @@ services:
- './CLI/configuration.yml:/config/configuration.yml:ro'
- './CLI/storage.yml:/config/configuration.storage.yml:ro'
- './CLI/users.yml:/config/users.yml'
- './common/ssl:/config/ssl:ro'
- './common/pki:/pki:ro'
- '/tmp:/tmp'
user: ${USER_ID}:${GROUP_ID}
...

View File

@ -9,8 +9,8 @@ server:
port: 9091
asset_path: /config/assets/
tls:
certificate: /config/ssl/cert.pem
key: /config/ssl/key.pem
certificate: /pki/public.backend.crt
key: /pki/private.backend.pem
endpoints:
authz:
caddy:

View File

@ -5,5 +5,5 @@ services:
volumes:
- './Caddy/configuration.yml:/config/configuration.yml:ro'
- './Caddy/users.yml:/config/users.yml'
- './common/ssl:/config/ssl:ro'
- './common/pki:/pki:ro'
...

View File

@ -9,8 +9,8 @@ default_redirection_url: https://home.example.com:8080/
server:
port: 9091
tls:
certificate: /config/ssl/cert.pem
key: /config/ssl/key.pem
certificate: /pki/public.backend.crt
key: /pki/private.backend.pem
log:
level: debug

View File

@ -5,5 +5,5 @@ services:
volumes:
- './Docker/configuration.yml:/config/configuration.yml:ro'
- './Docker/users.yml:/config/users.yml'
- './common/ssl:/config/ssl:ro'
- './common/pki:/pki:ro'
...

View File

@ -9,8 +9,8 @@ default_redirection_url: https://home.example.com:8080/
server:
port: 9091
tls:
certificate: /config/ssl/cert.pem
key: /config/ssl/key.pem
certificate: /pki/public.backend.crt
key: /pki/private.backend.pem
log:
level: trace

View File

@ -5,7 +5,7 @@ services:
volumes:
- './DuoPush/configuration.yml:/config/configuration.yml:ro'
- './DuoPush/users.yml:/config/users.yml'
- './common/ssl:/config/ssl:ro'
- './common/pki:/pki:ro'
- '/tmp:/tmp'
user: ${USER_ID}:${GROUP_ID}
...

View File

@ -9,8 +9,8 @@ server:
port: 9091
asset_path: /config/assets/
tls:
certificate: /config/ssl/cert.pem
key: /config/ssl/key.pem
certificate: /pki/public.backend.crt
key: /pki/private.backend.pem
endpoints:
authz:
ext-authz:

View File

@ -5,5 +5,5 @@ services:
volumes:
- './Envoy/configuration.yml:/config/configuration.yml:ro'
- './Envoy/users.yml:/config/users.yml'
- './common/ssl:/config/ssl:ro'
- './common/pki:/pki:ro'
...

View File

@ -8,8 +8,8 @@ jwt_secret: unsecure_secret
server:
port: 9091
tls:
certificate: /config/ssl/cert.pem
key: /config/ssl/key.pem
certificate: /pki/public.backend.crt
key: /pki/private.backend.pem
log:
level: debug

Some files were not shown because too many files have changed in this diff Show More