Merge remote-tracking branch 'origin/master' into feat-settings-ui

# Conflicts:
#	internal/model/webauthn.go
pull/4372/head
James Elliott 2022-11-13 09:19:22 +11:00
commit 9b66bb4fe2
No known key found for this signature in database
GPG Key ID: 0F1C4A096E857E49
439 changed files with 23755 additions and 7875 deletions

View File

@ -795,6 +795,34 @@
"contributions": [
"doc"
]
},
{
"login": "LongerHV",
"name": "Michał Mieszczak",
"avatar_url": "https://avatars.githubusercontent.com/u/46924944?v=4",
"profile": "https://github.com/LongerHV",
"contributions": [
"ideas",
"code"
]
},
{
"login": "paul-ohl",
"name": "Paul Ohl",
"avatar_url": "https://avatars.githubusercontent.com/u/37795294?v=4",
"profile": "https://github.com/paul-ohl",
"contributions": [
"doc"
]
},
{
"login": "smkent",
"name": "Stephen Kent",
"avatar_url": "https://avatars.githubusercontent.com/u/2831985?v=4",
"profile": "https://github.com/smkent",
"contributions": [
"ideas"
]
}
],
"contributorsPerLine": 7

View File

@ -16,10 +16,12 @@ coverage:
default: false
backend:
base: auto
threshold: 0.15%
flags:
- backend
frontend:
base: auto
threshold: 0.15%
flags:
- frontend

View File

@ -0,0 +1,144 @@
---
name: Bug Report
description: Report a bug
labels:
- type/bug/unconfirmed
- status/needs-triage
- priority/4/normal
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report. If you are unsure if this is actually a bug we generally recommend creating a [Question and Answer Discussion](https://github.com/authelia/authelia/discussions/new?category=q-a) first.
Please review the following requirements before submitting this issue type:
1. Please ensure you do not report security vulnerabilities via this method. See our [Security Policy](https://www.authelia.com/security-policy).
2. Please try to give as much information as possible for us to be able to reproduce the issue and provide a quick fix.
3. Please ensure an issue does not already exist for this potential bug.
4. Please only provide specific versions. Latest is not a version.
5. Please read the [Troubleshooting Sanitization](https://www.authelia.com/r/sanitize) reference guide if you plan on removing or adjusting any values for the logs or configuration files.
6. Please consider including a [HTTP Archive File](https://www.authelia.com/r/har) if you're having redirection issues.
- type: dropdown
id: version
attributes:
label: Version
description: What version(s) of Authelia can you reproduce this bug on?
multiple: true
options:
- v4.37.2
- v4.37.1
- v4.37.0
- v4.36.9
- v4.36.8
- v4.36.7
- v4.36.6
- v4.36.5
- v4.36.4
- v4.36.3
- v4.36.2
- v4.36.1
- v4.36.0
- v4.35.6
- v4.35.5
- v4.35.4
- v4.35.3
- v4.35.2
- v4.35.1
- v4.35.0
- v4.34.6
- v4.34.5
- v4.34.4
- v4.34.3
- v4.34.2
- v4.34.1
- v4.34.0
- v4.33.2
- v4.33.1
- v4.33.0
- v4.32.2
- v4.32.1
- v4.32.0
validations:
required: true
- type: dropdown
id: deployment
attributes:
label: Deployment Method
description: How are you deploying Authelia?
options:
- Docker
- Kubernetes
- Bare-metal
- Other
validations:
required: true
- type: dropdown
id: proxy
attributes:
label: Reverse Proxy
description: What reverse proxy are you using?
options:
- Caddy
- Traefik
- Envoy
- Istio
- NGINX
- SWAG
- NGINX Proxy Manager
- HAProxy
validations:
required: true
- type: input
id: proxy-version
attributes:
label: Reverse Proxy Version
description: What is the version of your reverse proxy?
placeholder: x.x.x
validations:
required: false
- type: textarea
id: description
attributes:
label: Description
description: Describe the bug
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: Reproduction
description: Describe how we can reproduce this issue
validations:
required: true
- type: textarea
id: expectations
attributes:
label: Expectations
description: Describe the desired or expected results
validations:
required: false
- type: textarea
id: logs
attributes:
label: Logs
description: Provide the logs (the template will automatically put this content in a code block)
render: shell
validations:
required: false
- type: textarea
id: configuration
attributes:
label: Configuration
description: Provide the Authelia configuration file (the template will automatically put this content in a code block)
render: yaml
validations:
required: false
- type: textarea
id: documentation
attributes:
label: Documentation
description: Provide any relevant specification or other documentation if applicable
validations:
required: false
...

View File

@ -1,41 +0,0 @@
---
name: Bug Report
about: Use this template to report bugs other than security vulnerabilities
labels: Possible Bug
---
## Bug Report
<!--
1. IMPORTANT: Do not report security vulnerabilities via GitHub issues. Please click 'choose a different type' and see
the dedicated report a security vulnerability link.
2. Remember to customize the title above.
3. Replace the below sections (not this section) starting with <!- - and ending with - -> with relevant information,
making sure to remove the <!- - and - ->.
4. Sections that start with _N/A_ are optional, but if you populate them with values please remove the _N/A_.
-->
### Description
<!--
Describe the bug here.
-->
### Expected Behaviour
_N/A_
<!--
Describe the behaviour your expect here.
-->
### Reproduction Steps
_N/A_
<!--
1. Replace this step with your first step. Add additional steps below this.
-->
### Additional Information
_N/A_
<!--
This section is for relevant additional information like; logs, configurations, environment information, etc.
-->

View File

@ -1,6 +1,15 @@
---
blank_issues_enabled: false
contact_links:
- name: Idea
url: https://github.com/authelia/authelia/discussions/new?category=ideas
about: Submit an Idea for Voting
- name: Question
url: https://github.com/authelia/authelia/discussions/new?category=q-a
about: Ask a Question
- name: Discussion
url: https://github.com/authelia/authelia/discussions/new
about: Start a Discussion related to Ideas, Polls, Show and Tell, or General Topics
- name: Documentation
url: https://www.authelia.com/
about: Read the Documentation

View File

@ -0,0 +1,47 @@
---
name: Feature Request
description: Submit a Feature Request
labels:
- type/feature
- status/needs-design
- priority/4/normal
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this feature request. A feature request is created as issue for the purpose of tracking the design and implementation of a feature.
Please review the following requirements before submitting this issue type:
1. Ensure there are no other similar feature requests.
2. Make sure you've checked the [Documentation](https://www.authelia.com) doesn't clearly document the features existence already.
3. Consider creating an [Idea Discussion](https://github.com/authelia/authelia/discussions/new?category=ideas) which can be voted on instead if one doesn't exist.
- type: textarea
id: description
attributes:
label: Description
description: Describe the feature
validations:
required: true
- type: textarea
id: use-case
attributes:
label: Use Case
description: Provide a use case
validations:
required: true
- type: textarea
id: details
attributes:
label: Details
description: Describe the feature in detail
validations:
required: false
- type: textarea
id: documentation
attributes:
label: Documentation
description: Provide any relevant specification or other documentation if applicable
validations:
required: false
...

View File

@ -1,26 +0,0 @@
---
name: Feature Request
about: Use this template to request features
labels: Feature Request
---
## Feature Request
<!--
1. IMPORTANT: Do not report security vulnerabilities via GitHub issues. Please click 'choose a different type' and see the dedicated report a security vulnerability link.
2. Remember to customize the title above.
3. Replace the below sections (not this section) starting with <!- - and ending with - -> with relevant information,
making sure to remove the <!- - and - ->.
4. Sections that start with _N/A_ are optional, but if you populate them with values please remove the _N/A_.
-->
### Description
<!--
Describe the feature here.
-->
### Use Case
_N/A_
<!--
Describe the specific use case if it isn't clear or may not be clear from your feature description here.
-->

View File

@ -1,7 +0,0 @@
---
name: Miscellaneous
about: Use this template for everything other than feature requests, security vulnerabilities, or bug reports such as questions
---
<!--
IMPORTANT: Do not report security vulnerabilities via GitHub issues. Please click 'choose a different type' and see the dedicated report a security vulnerability link.
-->

5
.github/pre-commit vendored
View File

@ -1,7 +1,6 @@
#!/bin/sh
if [[ ! -z "$NO_HOOK" ]]
then
if [ -n "$NO_HOOK" ]; then
exit 0
fi
@ -9,4 +8,4 @@ fi
. "$(dirname "$0")/required-apps"
golangci-lint run -v --fix && \
cd web && ${PMGR} lint
cd web && "${PMGR}" lint

16
.github/required-apps vendored
View File

@ -1,19 +1,19 @@
#!/bin/sh
PMGR=pnpm
export PMGR=pnpm
if [[ ! -x "$(command -v golangci-lint)" ]]; then
if [ ! -x "$(command -v golangci-lint)" ]; then
echo "You must install golangci-lint."
exit 1
fi
if [[ ! -x "$(command -v pnpm)" ]]; then
PMGR=yarn
if [[ ! -x "$(command -v yarn)" ]]; then
PMGR=npm
if [[ ! -x "$(command -v npm)" ]]; then
if [ ! -x "$(command -v pnpm)" ]; then
export PMGR=yarn
if [ ! -x "$(command -v yarn)" ]; then
export PMGR=npm
if [ ! -x "$(command -v npm)" ]; then
echo "You must install a node package manager."
exit 1
fi
fi
fi
fi

View File

@ -2,16 +2,16 @@
"extends": [
"config:base",
":semanticCommitTypeAll(build)",
":separatePatchReleases"
":separatePatchReleases",
"workarounds:doNotUpgradeFromAlpineStableToEdge"
],
"ignorePaths": [
"docs/**"
],
"ignorePresets": [
":combinePatchMinorReleases",
"helpers:disableTypesNodeMajor",
":prHourlyLimit2",
":semanticPrefixFixDepsChoreOthers"
":semanticPrefixFixDepsChoreOthers",
"workarounds:all"
],
"enabledManagers": [
"bundler",
@ -24,6 +24,13 @@
"dependencies"
],
"packageRules": [
{
"matchUpdateTypes": ["digest", "minor", "patch"],
"matchCurrentVersion": "!/^0/",
"automerge": true,
"automergeType": "pr",
"platformAutomerge": true
},
{
"datasources": [
"docker"
@ -47,14 +54,6 @@
"addLabels": [
"javascript"
]
},
{
"datasources": [
"rubygems"
],
"addLabels": [
"ruby"
]
}
],
"postUpdateOptions": [

View File

@ -6,7 +6,8 @@ ignore: |
internal/configuration/test_resources/config_bad_quoting.yml
web/pnpm-lock.yaml
web/node_modules/
.github/ISSUE_TEMPLATE/feature-request.yml
.github/ISSUE_TEMPLATE/bug-report.yml
rules:
document-end:
level: warning

View File

@ -1,7 +1,7 @@
# ========================================
# ===== Build image for the frontend =====
# ========================================
FROM node:18-alpine AS builder-frontend
FROM node:19-alpine AS builder-frontend
WORKDIR /node/src/app
@ -15,7 +15,7 @@ RUN yarn global add pnpm && \
# =======================================
# ===== Build image for the backend =====
# =======================================
FROM golang:1.19.1-alpine AS builder-backend
FROM golang:1.19.3-alpine AS builder-backend
WORKDIR /go/src/app

View File

@ -1,7 +1,7 @@
# ========================================
# ===== Build image for the frontend =====
# ========================================
FROM node:18-alpine AS builder-frontend
FROM node:19-alpine AS builder-frontend
WORKDIR /node/src/app
@ -13,7 +13,7 @@ RUN yarn install --frozen-lockfile && yarn build
# =======================================
# ===== Build image for the backend =====
# =======================================
FROM golang:1.19.1-alpine AS builder-backend
FROM golang:1.19.3-alpine AS builder-backend
WORKDIR /go/src/app

268
README.md
View File

@ -16,9 +16,8 @@
[![Matrix](https://img.shields.io/matrix/authelia-support:matrix.org?label=matrix&logo=matrix&style=flat-square&color=blue)](https://matrix.to/#/#support:authelia.com)
**Authelia** is an open-source authentication and authorization server providing two-factor authentication and single
sign-on (SSO) for your applications via a web portal. It acts as a companion for reverse proxies like [nginx],
[Traefik], [caddy] or [HAProxy] to let them know whether requests should either be allowed or redirected to Authelia's
portal for authentication.
sign-on (SSO) for your applications via a web portal. It acts as a companion for [reverse proxies](#proxy-support) by
allowing, denying, or redirecting requests.
Documentation is available at [https://www.authelia.com/](https://www.authelia.com/).
@ -31,9 +30,12 @@ The following is a simple diagram of the architecture:
**Authelia** can be installed as a standalone service from the [AUR](https://aur.archlinux.org/packages/authelia/),
[APT](https://apt.authelia.com/stable/debian/packages/authelia/),
[FreeBSD Ports](https://svnweb.freebsd.org/ports/head/www/authelia/), or using a
[Static binary](https://github.com/authelia/authelia/releases/latest),
[.deb package]((https://github.com/authelia/authelia/releases/latest)), [Docker] or [Kubernetes] either manually or via
the Helm [Chart](https://charts.authelia.com) (beta) leveraging ingress controllers and ingress configurations.
[static binary](https://github.com/authelia/authelia/releases/latest),
[.deb package]((https://github.com/authelia/authelia/releases/latest)), as a container on [Docker] or [Kubernetes].
Deployment can be orchestrated via the Helm [Chart](https://charts.authelia.com) (beta) leveraging ingress controllers
and ingress configurations.
<p align="center">
<img src="./docs/static/images/logos/kubernetes.png" height="100"/>
@ -70,13 +72,14 @@ This is a list of the key features of Authelia:
* Curated configuration from [LinuxServer](https://www.linuxserver.io/) via their
[Swag](https://docs.linuxserver.io/general/swag) container as well as a
[guide](https://blog.linuxserver.io/2020/08/26/setting-up-authelia/).
* Compatible with [caddy] using the [forward_auth](https://caddyserver.com/docs/caddyfile/directives/forward_auth)
* Compatible with [Caddy] using the [forward_auth](https://caddyserver.com/docs/caddyfile/directives/forward_auth)
directive.
* Kubernetes Support:
* Compatible with the [ingress-nginx](https://github.com/kubernetes/ingress-nginx), the
[Traefik Kubernetes CRD](https://doc.traefik.io/traefik/providers/kubernetes-crd/), and the
[Traefik Kubernetes Ingress](https://doc.traefik.io/traefik/providers/kubernetes-crd/) Kubernetes ingress
controllers out of the box.
* Compatible with several Kubernetes ingress controllers:
* [ingress-nginx](https://www.authelia.com/integration/kubernetes/nginx-ingress/)
* [Traefik Kubernetes CRD](https://www.authelia.com/integration/kubernetes/traefik-ingress/#ingressroute)
* [Traefik Kubernetes Ingress](https://www.authelia.com/integration/kubernetes/traefik-ingress/#ingress)
* [Istio](https://www.authelia.com/integration/kubernetes/istio/)
* Beta support for installing via Helm using our [Charts](https://charts.authelia.com).
* Beta support for [OpenID Connect](https://www.authelia.com/roadmap/active/openid-connect/).
@ -86,22 +89,14 @@ If you want to know more about the roadmap, follow [Roadmap](https://www.autheli
## Proxy support
Authelia works in combination with [nginx], [Traefik], [caddy] or [HAProxy]. It can be deployed on bare metal with
Docker or on top of [Kubernetes].
Authelia works in combination with [nginx], [Traefik], [Caddy], [Skipper], [Envoy], or [HAProxy].
<p align="center">
<img src="./docs/static/images/logos/nginx.png" height="50"/>
<img src="./docs/static/images/logos/traefik.png" height="50"/>
<img src="./docs/static/images/logos/caddy.png" height="50"/>
<img src="./docs/static/images/logos/haproxy.png" height="50"/>
<img src="./docs/static/images/logos/kubernetes.png" height="50"/>
</p>
***Help Wanted:*** Assistance would be appreciated in getting Authelia working with
[Envoy](https://www.envoyproxy.io/).
<p align="center">
<img src="./docs/static/images/logos/envoy.png" height="50"/>
<img src="./docs/static/images/logos/haproxy.png" height="50"/>
</p>
## Getting Started
@ -200,113 +195,120 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center"><a href="https://github.com/clems4ever"><img src="https://avatars.githubusercontent.com/u/3193257?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Clément Michaud</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=clems4ever" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=clems4ever" title="Documentation">📖</a> <a href="#ideas-clems4ever" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-clems4ever" title="Maintenance">🚧</a> <a href="#question-clems4ever" title="Answering Questions">💬</a> <a href="https://github.com/authelia/authelia/pulls?q=is%3Apr+reviewed-by%3Aclems4ever" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/authelia/authelia/commits?author=clems4ever" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/nightah"><img src="https://avatars.githubusercontent.com/u/3339418?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Amir Zarrinkafsh</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=nightah" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=nightah" title="Documentation">📖</a> <a href="#ideas-nightah" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-nightah" title="Maintenance">🚧</a> <a href="#question-nightah" title="Answering Questions">💬</a> <a href="https://github.com/authelia/authelia/pulls?q=is%3Apr+reviewed-by%3Anightah" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/authelia/authelia/commits?author=nightah" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/james-d-elliott"><img src="https://avatars.githubusercontent.com/u/3903683?v=4?s=100" width="100px;" alt=""/><br /><sub><b>James Elliott</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=james-d-elliott" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=james-d-elliott" title="Documentation">📖</a> <a href="#ideas-james-d-elliott" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-james-d-elliott" title="Maintenance">🚧</a> <a href="#question-james-d-elliott" title="Answering Questions">💬</a> <a href="https://github.com/authelia/authelia/pulls?q=is%3Apr+reviewed-by%3Ajames-d-elliott" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/authelia/authelia/commits?author=james-d-elliott" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/n4kre"><img src="https://avatars.githubusercontent.com/u/14371127?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Antoine Favre</b></sub></a><br /><a href="https://github.com/authelia/authelia/issues?q=author%3An4kre" title="Bug reports">🐛</a> <a href="#ideas-n4kre" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://github.com/BankaiNoJutsu"><img src="https://avatars.githubusercontent.com/u/2241519?v=4?s=100" width="100px;" alt=""/><br /><sub><b>BankaiNoJutsu</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=BankaiNoJutsu" title="Code">💻</a> <a href="#design-BankaiNoJutsu" title="Design">🎨</a></td>
<td align="center"><a href="https://github.com/p-rintz"><img src="https://avatars.githubusercontent.com/u/13933258?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Philipp Rintz</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=p-rintz" title="Documentation">📖</a></td>
<td align="center"><a href="http://callanbryant.co.uk/"><img src="https://avatars.githubusercontent.com/u/208440?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Callan Bryant</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=naggie" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=naggie" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/ViViDboarder"><img src="https://avatars.githubusercontent.com/u/137025?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ian</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=ViViDboarder" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/FrozenDragoon"><img src="https://avatars.githubusercontent.com/u/5301673?v=4?s=100" width="100px;" alt=""/><br /><sub><b>FrozenDragoon</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=FrozenDragoon" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/vdot0x23"><img src="https://avatars.githubusercontent.com/u/40716069?v=4?s=100" width="100px;" alt=""/><br /><sub><b>vdot0x23</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=vdot0x23" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/alexw1982"><img src="https://avatars.githubusercontent.com/u/11628284?v=4?s=100" width="100px;" alt=""/><br /><sub><b>alexw1982</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=alexw1982" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/Sohalt"><img src="https://avatars.githubusercontent.com/u/2157287?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sohalt</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=Sohalt" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=Sohalt" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/Tedyst"><img src="https://avatars.githubusercontent.com/u/13637623?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Stoica Tedy</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=Tedyst" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Chemsmith"><img src="https://avatars.githubusercontent.com/u/9061024?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dylan Smith</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=Chemsmith" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/LukasK13"><img src="https://avatars.githubusercontent.com/u/24586740?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lukas Klass</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=LukasK13" title="Documentation">📖</a></td>
<td align="center"><a href="https://staiger.it/"><img src="https://avatars.githubusercontent.com/u/9325003?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Philipp Staiger</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=lippl" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=lippl" title="Documentation">📖</a> <a href="https://github.com/authelia/authelia/commits?author=lippl" title="Tests">⚠️</a></td>
<td align="center"><a href="https://yaleman.org/"><img src="https://avatars.githubusercontent.com/u/168188?v=4?s=100" width="100px;" alt=""/><br /><sub><b>James Hodgkinson</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=yaleman" title="Documentation">📖</a></td>
<td align="center"><a href="https://chris.smith.xyz/"><img src="https://avatars.githubusercontent.com/u/1979423?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Chris Smith</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=chris13524" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/mqmq0"><img src="https://avatars.githubusercontent.com/u/13240971?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mihály</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=mqmq0" title="Documentation">📖</a></td>
<td align="center"><a href="https://iret.xyz/"><img src="https://avatars.githubusercontent.com/u/6560655?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Silver Bullet</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=SilverBut" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/skenmy"><img src="https://avatars.githubusercontent.com/u/1454505?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Paul Williams</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=skenmy" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=skenmy" title="Tests">⚠️</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/ntimo"><img src="https://avatars.githubusercontent.com/u/6145026?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Timo</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=ntimo" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/andrewkliskey"><img src="https://avatars.githubusercontent.com/u/44645768?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Andrew Kliskey</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=andrewkliskey" title="Documentation">📖</a></td>
<td align="center"><a href="http://kristofmattei.be/"><img src="https://avatars.githubusercontent.com/u/864376?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kristof Mattei</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=Kristof-Mattei" title="Documentation">📖</a></td>
<td align="center"><a href="https://www.zmiguel.me/"><img src="https://avatars.githubusercontent.com/u/4400540?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ZMiguel Valdiviesso</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=zmiguel" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/akusei"><img src="https://avatars.githubusercontent.com/u/12972900?v=4?s=100" width="100px;" alt=""/><br /><sub><b>akusei</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=akusei" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=akusei" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/Peaches491"><img src="https://avatars.githubusercontent.com/u/494334?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Daniel Miller</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=Peaches491" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/dustins"><img src="https://avatars.githubusercontent.com/u/14645?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dustin Sweigart</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=dustins" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=dustins" title="Documentation">📖</a> <a href="https://github.com/authelia/authelia/commits?author=dustins" title="Tests">⚠️</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/rogue780"><img src="https://avatars.githubusercontent.com/u/247716?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Shawn Haggard</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=rogue780" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=rogue780" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/kevynb"><img src="https://avatars.githubusercontent.com/u/4941215?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kevyn Bruyere</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=kevynb" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/ducksecops"><img src="https://avatars.githubusercontent.com/u/25612094?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Daniel Sutton</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=ducksecops" title="Code">💻</a></td>
<td align="center"><a href="http://www.xenuser.org/"><img src="https://avatars.githubusercontent.com/u/2216868?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Valentin Höbel</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=xenuser" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/thehedgefrog"><img src="https://avatars.githubusercontent.com/u/38590447?v=4?s=100" width="100px;" alt=""/><br /><sub><b>thehedgefrog</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=thehedgefrog" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/ViRb3"><img src="https://avatars.githubusercontent.com/u/2650170?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Victor</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=ViRb3" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/whiskerch"><img src="https://avatars.githubusercontent.com/u/35109315?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Chris Whisker</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=whiskerch" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/nasatome"><img src="https://avatars.githubusercontent.com/u/18271791?v=4?s=100" width="100px;" alt=""/><br /><sub><b>nasatome</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=nasatome" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/bbros-dev"><img src="https://avatars.githubusercontent.com/u/60454087?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Begley Brothers (Development)</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=bbros-dev" title="Documentation">📖</a></td>
<td align="center"><a href="http://mikekusold.com/"><img src="https://avatars.githubusercontent.com/u/509966?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mike Kusold</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=kusold" title="Code">💻</a></td>
<td align="center"><a href="https://dzervas.gr/"><img src="https://avatars.githubusercontent.com/u/1029195?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dimitris Zervas</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=dzervas" title="Documentation">📖</a></td>
<td align="center"><a href="http://paypal.me/DHoung"><img src="https://avatars.githubusercontent.com/u/52870424?v=4?s=100" width="100px;" alt=""/><br /><sub><b>TheCatLady</b></sub></a><br /><a href="#ideas-TheCatLady" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://lauri.vosandi.com/"><img src="https://avatars.githubusercontent.com/u/194685?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lauri Võsandi</b></sub></a><br /><a href="#ideas-laurivosandi" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://github.com/knnnrd"><img src="https://avatars.githubusercontent.com/u/5852381?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kennard Vermeiren</b></sub></a><br /><a href="#ideas-knnnrd" title="Ideas, Planning, & Feedback">🤔</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/ThinkChaos"><img src="https://avatars.githubusercontent.com/u/4761135?v=4?s=100" width="100px;" alt=""/><br /><sub><b>ThinkChaos</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=ThinkChaos" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=ThinkChaos" title="Documentation">📖</a> <a href="https://github.com/authelia/authelia/commits?author=ThinkChaos" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/except"><img src="https://avatars.githubusercontent.com/u/26675576?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hasan</b></sub></a><br /><a href="#security-except" title="Security">🛡️</a></td>
<td align="center"><a href="http://blog.dchidell.com"><img src="https://avatars.githubusercontent.com/u/26146619?v=4?s=100" width="100px;" alt=""/><br /><sub><b>David Chidell</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=dchidell" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/mardom1"><img src="https://avatars.githubusercontent.com/u/32371724?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Marcel Marquardt</b></sub></a><br /><a href="https://github.com/authelia/authelia/issues?q=author%3Amardom1" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://cdine.org"><img src="https://avatars.githubusercontent.com/u/127512?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ian Gallagher</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=craSH" title="Documentation">📖</a></td>
<td align="center"><a href="https://wuhanstudio.cc"><img src="https://avatars.githubusercontent.com/u/15157070?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Wu Han</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=wuhanstudio" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/lavih"><img src="https://avatars.githubusercontent.com/u/47455309?v=4?s=100" width="100px;" alt=""/><br /><sub><b>lavih</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=lavih" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="http://jonbayl"><img src="https://avatars.githubusercontent.com/u/30201351?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jon B. </b></sub></a><br /><a href="#security-jonbayl" title="Security">🛡️</a></td>
<td align="center"><a href="https://github.com/AlexGustafsson"><img src="https://avatars.githubusercontent.com/u/14974112?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alex Gustafsson</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=AlexGustafsson" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=AlexGustafsson" title="Documentation">📖</a></td>
<td align="center"><a href="https://www.aarsen.me/"><img src="https://avatars.githubusercontent.com/u/7805050?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Arsenović Arsen</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=ArsenArsen" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=ArsenArsen" title="Tests">⚠️</a> <a href="#security-ArsenArsen" title="Security">🛡️</a></td>
<td align="center"><a href="https://github.com/dakriy"><img src="https://avatars.githubusercontent.com/u/13756065?v=4?s=100" width="100px;" alt=""/><br /><sub><b>dakriy</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=dakriy" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/davama"><img src="https://avatars.githubusercontent.com/u/5359152?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dave</b></sub></a><br /><a href="#userTesting-davama" title="User Testing">📓</a></td>
<td align="center"><a href="https://github.com/nreymundo"><img src="https://avatars.githubusercontent.com/u/5833447?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Nicolas Reymundo</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=nreymundo" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/polandy"><img src="https://avatars.githubusercontent.com/u/3670670?v=4?s=100" width="100px;" alt=""/><br /><sub><b>polandy</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=polandy" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/you1996"><img src="https://avatars.githubusercontent.com/u/45292366?v=4?s=100" width="100px;" alt=""/><br /><sub><b>yossbg</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=you1996" title="Code">💻</a> <a href="#design-you1996" title="Design">🎨</a></td>
<td align="center"><a href="https://github.com/mpdcampbell"><img src="https://avatars.githubusercontent.com/u/47434940?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Michael Campbell</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=mpdcampbell" title="Documentation">📖</a></td>
<td align="center"><a href="https://sievenpiper.co"><img src="https://avatars.githubusercontent.com/u/1131882?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Justin Sievenpiper</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=jsievenpiper" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/kaysond"><img src="https://avatars.githubusercontent.com/u/1147328?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aram Akhavan</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=kaysond" title="Documentation">📖</a></td>
<td align="center"><a href="https://skhuf.net"><img src="https://avatars.githubusercontent.com/u/286341?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Shadow</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=shadow7412" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/tarioch"><img src="https://avatars.githubusercontent.com/u/2998148?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Patrick Ruckstuhl</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=tarioch" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/FineWolf"><img src="https://avatars.githubusercontent.com/u/203591?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Andrew Moore</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=FineWolf" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=FineWolf" title="Documentation">📖</a> <a href="https://github.com/authelia/authelia/commits?author=FineWolf" title="Tests">⚠️</a></td>
</tr>
<tr>
<td align="center"><a href="http://www.dennisgaida.de"><img src="https://avatars.githubusercontent.com/u/2392217?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dennis Gaida</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=DennisGaida" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/Alestrix"><img src="https://avatars.githubusercontent.com/u/7452860?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alestrix</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=Alestrix" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/bgh-github"><img src="https://avatars.githubusercontent.com/u/99472455?v=4?s=100" width="100px;" alt=""/><br /><sub><b>bgh-github</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=bgh-github" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/mind-ar"><img src="https://avatars.githubusercontent.com/u/10672208?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Manuel Nuñez</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=mind-ar" title="Code">💻</a> <a href="#translation-mind-ar" title="Translation">🌍</a></td>
<td align="center"><a href="https://github.com/protvis74"><img src="https://avatars.githubusercontent.com/u/50554836?v=4?s=100" width="100px;" alt=""/><br /><sub><b>protvis74</b></sub></a><br /><a href="#translation-protvis74" title="Translation">🌍</a></td>
<td align="center"><a href="http://itjamie.com"><img src="https://avatars.githubusercontent.com/u/1613241?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jamie (Bear) Murphy </b></sub></a><br /><a href="https://github.com/authelia/authelia/pulls?q=is%3Apr+reviewed-by%3AITJamie" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="https://github.com/Beanow"><img src="https://avatars.githubusercontent.com/u/497556?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Robin van Boven</b></sub></a><br /><a href="#security-Beanow" title="Security">🛡️</a></td>
</tr>
<tr>
<td align="center"><a href="http://www.cybertrol.com"><img src="https://avatars.githubusercontent.com/u/1178293?v=4?s=100" width="100px;" alt=""/><br /><sub><b>alphabet5</b></sub></a><br /><a href="#ideas-alphabet5" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://github.com/rjmidau"><img src="https://avatars.githubusercontent.com/u/8134995?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Robert Meredith</b></sub></a><br /><a href="#ideas-rjmidau" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://github.com/adriang-90"><img src="https://avatars.githubusercontent.com/u/60886162?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Adrian Gąsior</b></sub></a><br /><a href="#security-adriang-90" title="Security">🛡️</a></td>
<td align="center"><a href="http://jamesw.link/me"><img src="https://avatars.githubusercontent.com/u/8067792?v=4?s=100" width="100px;" alt=""/><br /><sub><b>James White</b></sub></a><br /><a href="#question-jamesmacwhite" title="Answering Questions">💬</a></td>
<td align="center"><a href="https://www.zxlim.xyz"><img src="https://avatars.githubusercontent.com/u/19372079?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zhao Xiang Lim</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=zxlim" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/Auzborn123"><img src="https://avatars.githubusercontent.com/u/42992103?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Auzborn123</b></sub></a><br /><a href="#translation-Auzborn123" title="Translation">🌍</a></td>
<td align="center"><a href="https://github.com/SvanGlan"><img src="https://avatars.githubusercontent.com/u/106152205?v=4?s=100" width="100px;" alt=""/><br /><sub><b>SvanGlan</b></sub></a><br /><a href="#translation-SvanGlan" title="Translation">🌍</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/HannesJo0139"><img src="https://avatars.githubusercontent.com/u/42114183?v=4?s=100" width="100px;" alt=""/><br /><sub><b>HannesJo0139</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=HannesJo0139" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/andreas-berg"><img src="https://avatars.githubusercontent.com/u/39428693?v=4?s=100" width="100px;" alt=""/><br /><sub><b>andreas-berg</b></sub></a><br /><a href="https://github.com/authelia/authelia/issues?q=author%3Aandreas-berg" title="Bug reports">🐛</a></td>
<td align="center"><a href="http://radenac.me"><img src="https://avatars.githubusercontent.com/u/47008408?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Clément Radenac</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=clem3109" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/boomam"><img src="https://avatars.githubusercontent.com/u/37086258?v=4?s=100" width="100px;" alt=""/><br /><sub><b>boomam</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=boomam" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/Northguy"><img src="https://avatars.githubusercontent.com/u/1189058?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Northguy</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=Northguy" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/polarathene"><img src="https://avatars.githubusercontent.com/u/5098581?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Brennan Kinney</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=polarathene" title="Documentation">📖</a></td>
</tr>
<tbody>
<tr>
<td align="center"><a href="https://github.com/clems4ever"><img src="https://avatars.githubusercontent.com/u/3193257?v=4?s=100" width="100px;" alt="Clément Michaud"/><br /><sub><b>Clément Michaud</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=clems4ever" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=clems4ever" title="Documentation">📖</a> <a href="#ideas-clems4ever" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-clems4ever" title="Maintenance">🚧</a> <a href="#question-clems4ever" title="Answering Questions">💬</a> <a href="https://github.com/authelia/authelia/pulls?q=is%3Apr+reviewed-by%3Aclems4ever" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/authelia/authelia/commits?author=clems4ever" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/nightah"><img src="https://avatars.githubusercontent.com/u/3339418?v=4?s=100" width="100px;" alt="Amir Zarrinkafsh"/><br /><sub><b>Amir Zarrinkafsh</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=nightah" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=nightah" title="Documentation">📖</a> <a href="#ideas-nightah" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-nightah" title="Maintenance">🚧</a> <a href="#question-nightah" title="Answering Questions">💬</a> <a href="https://github.com/authelia/authelia/pulls?q=is%3Apr+reviewed-by%3Anightah" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/authelia/authelia/commits?author=nightah" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/james-d-elliott"><img src="https://avatars.githubusercontent.com/u/3903683?v=4?s=100" width="100px;" alt="James Elliott"/><br /><sub><b>James Elliott</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=james-d-elliott" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=james-d-elliott" title="Documentation">📖</a> <a href="#ideas-james-d-elliott" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-james-d-elliott" title="Maintenance">🚧</a> <a href="#question-james-d-elliott" title="Answering Questions">💬</a> <a href="https://github.com/authelia/authelia/pulls?q=is%3Apr+reviewed-by%3Ajames-d-elliott" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/authelia/authelia/commits?author=james-d-elliott" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/n4kre"><img src="https://avatars.githubusercontent.com/u/14371127?v=4?s=100" width="100px;" alt="Antoine Favre"/><br /><sub><b>Antoine Favre</b></sub></a><br /><a href="https://github.com/authelia/authelia/issues?q=author%3An4kre" title="Bug reports">🐛</a> <a href="#ideas-n4kre" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://github.com/BankaiNoJutsu"><img src="https://avatars.githubusercontent.com/u/2241519?v=4?s=100" width="100px;" alt="BankaiNoJutsu"/><br /><sub><b>BankaiNoJutsu</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=BankaiNoJutsu" title="Code">💻</a> <a href="#design-BankaiNoJutsu" title="Design">🎨</a></td>
<td align="center"><a href="https://github.com/p-rintz"><img src="https://avatars.githubusercontent.com/u/13933258?v=4?s=100" width="100px;" alt="Philipp Rintz"/><br /><sub><b>Philipp Rintz</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=p-rintz" title="Documentation">📖</a></td>
<td align="center"><a href="http://callanbryant.co.uk/"><img src="https://avatars.githubusercontent.com/u/208440?v=4?s=100" width="100px;" alt="Callan Bryant"/><br /><sub><b>Callan Bryant</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=naggie" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=naggie" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/ViViDboarder"><img src="https://avatars.githubusercontent.com/u/137025?v=4?s=100" width="100px;" alt="Ian"/><br /><sub><b>Ian</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=ViViDboarder" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/FrozenDragoon"><img src="https://avatars.githubusercontent.com/u/5301673?v=4?s=100" width="100px;" alt="FrozenDragoon"/><br /><sub><b>FrozenDragoon</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=FrozenDragoon" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/vdot0x23"><img src="https://avatars.githubusercontent.com/u/40716069?v=4?s=100" width="100px;" alt="vdot0x23"/><br /><sub><b>vdot0x23</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=vdot0x23" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/alexw1982"><img src="https://avatars.githubusercontent.com/u/11628284?v=4?s=100" width="100px;" alt="alexw1982"/><br /><sub><b>alexw1982</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=alexw1982" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/Sohalt"><img src="https://avatars.githubusercontent.com/u/2157287?v=4?s=100" width="100px;" alt="Sohalt"/><br /><sub><b>Sohalt</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=Sohalt" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=Sohalt" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/Tedyst"><img src="https://avatars.githubusercontent.com/u/13637623?v=4?s=100" width="100px;" alt="Stoica Tedy"/><br /><sub><b>Stoica Tedy</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=Tedyst" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Chemsmith"><img src="https://avatars.githubusercontent.com/u/9061024?v=4?s=100" width="100px;" alt="Dylan Smith"/><br /><sub><b>Dylan Smith</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=Chemsmith" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/LukasK13"><img src="https://avatars.githubusercontent.com/u/24586740?v=4?s=100" width="100px;" alt="Lukas Klass"/><br /><sub><b>Lukas Klass</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=LukasK13" title="Documentation">📖</a></td>
<td align="center"><a href="https://staiger.it/"><img src="https://avatars.githubusercontent.com/u/9325003?v=4?s=100" width="100px;" alt="Philipp Staiger"/><br /><sub><b>Philipp Staiger</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=lippl" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=lippl" title="Documentation">📖</a> <a href="https://github.com/authelia/authelia/commits?author=lippl" title="Tests">⚠️</a></td>
<td align="center"><a href="https://yaleman.org/"><img src="https://avatars.githubusercontent.com/u/168188?v=4?s=100" width="100px;" alt="James Hodgkinson"/><br /><sub><b>James Hodgkinson</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=yaleman" title="Documentation">📖</a></td>
<td align="center"><a href="https://chris.smith.xyz/"><img src="https://avatars.githubusercontent.com/u/1979423?v=4?s=100" width="100px;" alt="Chris Smith"/><br /><sub><b>Chris Smith</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=chris13524" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/mqmq0"><img src="https://avatars.githubusercontent.com/u/13240971?v=4?s=100" width="100px;" alt="Mihály"/><br /><sub><b>Mihály</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=mqmq0" title="Documentation">📖</a></td>
<td align="center"><a href="https://iret.xyz/"><img src="https://avatars.githubusercontent.com/u/6560655?v=4?s=100" width="100px;" alt="Silver Bullet"/><br /><sub><b>Silver Bullet</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=SilverBut" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/skenmy"><img src="https://avatars.githubusercontent.com/u/1454505?v=4?s=100" width="100px;" alt="Paul Williams"/><br /><sub><b>Paul Williams</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=skenmy" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=skenmy" title="Tests">⚠️</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/ntimo"><img src="https://avatars.githubusercontent.com/u/6145026?v=4?s=100" width="100px;" alt="Timo"/><br /><sub><b>Timo</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=ntimo" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/andrewkliskey"><img src="https://avatars.githubusercontent.com/u/44645768?v=4?s=100" width="100px;" alt="Andrew Kliskey"/><br /><sub><b>Andrew Kliskey</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=andrewkliskey" title="Documentation">📖</a></td>
<td align="center"><a href="http://kristofmattei.be/"><img src="https://avatars.githubusercontent.com/u/864376?v=4?s=100" width="100px;" alt="Kristof Mattei"/><br /><sub><b>Kristof Mattei</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=Kristof-Mattei" title="Documentation">📖</a></td>
<td align="center"><a href="https://www.zmiguel.me/"><img src="https://avatars.githubusercontent.com/u/4400540?v=4?s=100" width="100px;" alt="ZMiguel Valdiviesso"/><br /><sub><b>ZMiguel Valdiviesso</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=zmiguel" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/akusei"><img src="https://avatars.githubusercontent.com/u/12972900?v=4?s=100" width="100px;" alt="akusei"/><br /><sub><b>akusei</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=akusei" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=akusei" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/Peaches491"><img src="https://avatars.githubusercontent.com/u/494334?v=4?s=100" width="100px;" alt="Daniel Miller"/><br /><sub><b>Daniel Miller</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=Peaches491" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/dustins"><img src="https://avatars.githubusercontent.com/u/14645?v=4?s=100" width="100px;" alt="Dustin Sweigart"/><br /><sub><b>Dustin Sweigart</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=dustins" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=dustins" title="Documentation">📖</a> <a href="https://github.com/authelia/authelia/commits?author=dustins" title="Tests">⚠️</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/rogue780"><img src="https://avatars.githubusercontent.com/u/247716?v=4?s=100" width="100px;" alt="Shawn Haggard"/><br /><sub><b>Shawn Haggard</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=rogue780" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=rogue780" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/kevynb"><img src="https://avatars.githubusercontent.com/u/4941215?v=4?s=100" width="100px;" alt="Kevyn Bruyere"/><br /><sub><b>Kevyn Bruyere</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=kevynb" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/ducksecops"><img src="https://avatars.githubusercontent.com/u/25612094?v=4?s=100" width="100px;" alt="Daniel Sutton"/><br /><sub><b>Daniel Sutton</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=ducksecops" title="Code">💻</a></td>
<td align="center"><a href="http://www.xenuser.org/"><img src="https://avatars.githubusercontent.com/u/2216868?v=4?s=100" width="100px;" alt="Valentin Höbel"/><br /><sub><b>Valentin Höbel</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=xenuser" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/thehedgefrog"><img src="https://avatars.githubusercontent.com/u/38590447?v=4?s=100" width="100px;" alt="thehedgefrog"/><br /><sub><b>thehedgefrog</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=thehedgefrog" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/ViRb3"><img src="https://avatars.githubusercontent.com/u/2650170?v=4?s=100" width="100px;" alt="Victor"/><br /><sub><b>Victor</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=ViRb3" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/whiskerch"><img src="https://avatars.githubusercontent.com/u/35109315?v=4?s=100" width="100px;" alt="Chris Whisker"/><br /><sub><b>Chris Whisker</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=whiskerch" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/nasatome"><img src="https://avatars.githubusercontent.com/u/18271791?v=4?s=100" width="100px;" alt="nasatome"/><br /><sub><b>nasatome</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=nasatome" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/bbros-dev"><img src="https://avatars.githubusercontent.com/u/60454087?v=4?s=100" width="100px;" alt="Begley Brothers (Development)"/><br /><sub><b>Begley Brothers (Development)</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=bbros-dev" title="Documentation">📖</a></td>
<td align="center"><a href="http://mikekusold.com/"><img src="https://avatars.githubusercontent.com/u/509966?v=4?s=100" width="100px;" alt="Mike Kusold"/><br /><sub><b>Mike Kusold</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=kusold" title="Code">💻</a></td>
<td align="center"><a href="https://dzervas.gr/"><img src="https://avatars.githubusercontent.com/u/1029195?v=4?s=100" width="100px;" alt="Dimitris Zervas"/><br /><sub><b>Dimitris Zervas</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=dzervas" title="Documentation">📖</a></td>
<td align="center"><a href="http://paypal.me/DHoung"><img src="https://avatars.githubusercontent.com/u/52870424?v=4?s=100" width="100px;" alt="TheCatLady"/><br /><sub><b>TheCatLady</b></sub></a><br /><a href="#ideas-TheCatLady" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://lauri.vosandi.com/"><img src="https://avatars.githubusercontent.com/u/194685?v=4?s=100" width="100px;" alt="Lauri Võsandi"/><br /><sub><b>Lauri Võsandi</b></sub></a><br /><a href="#ideas-laurivosandi" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://github.com/knnnrd"><img src="https://avatars.githubusercontent.com/u/5852381?v=4?s=100" width="100px;" alt="Kennard Vermeiren"/><br /><sub><b>Kennard Vermeiren</b></sub></a><br /><a href="#ideas-knnnrd" title="Ideas, Planning, & Feedback">🤔</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/ThinkChaos"><img src="https://avatars.githubusercontent.com/u/4761135?v=4?s=100" width="100px;" alt="ThinkChaos"/><br /><sub><b>ThinkChaos</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=ThinkChaos" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=ThinkChaos" title="Documentation">📖</a> <a href="https://github.com/authelia/authelia/commits?author=ThinkChaos" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/except"><img src="https://avatars.githubusercontent.com/u/26675576?v=4?s=100" width="100px;" alt="Hasan"/><br /><sub><b>Hasan</b></sub></a><br /><a href="#security-except" title="Security">🛡️</a></td>
<td align="center"><a href="http://blog.dchidell.com"><img src="https://avatars.githubusercontent.com/u/26146619?v=4?s=100" width="100px;" alt="David Chidell"/><br /><sub><b>David Chidell</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=dchidell" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/mardom1"><img src="https://avatars.githubusercontent.com/u/32371724?v=4?s=100" width="100px;" alt="Marcel Marquardt"/><br /><sub><b>Marcel Marquardt</b></sub></a><br /><a href="https://github.com/authelia/authelia/issues?q=author%3Amardom1" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://cdine.org"><img src="https://avatars.githubusercontent.com/u/127512?v=4?s=100" width="100px;" alt="Ian Gallagher"/><br /><sub><b>Ian Gallagher</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=craSH" title="Documentation">📖</a></td>
<td align="center"><a href="https://wuhanstudio.cc"><img src="https://avatars.githubusercontent.com/u/15157070?v=4?s=100" width="100px;" alt="Wu Han"/><br /><sub><b>Wu Han</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=wuhanstudio" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/lavih"><img src="https://avatars.githubusercontent.com/u/47455309?v=4?s=100" width="100px;" alt="lavih"/><br /><sub><b>lavih</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=lavih" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="http://jonbayl"><img src="https://avatars.githubusercontent.com/u/30201351?v=4?s=100" width="100px;" alt="Jon B. "/><br /><sub><b>Jon B. </b></sub></a><br /><a href="#security-jonbayl" title="Security">🛡️</a></td>
<td align="center"><a href="https://github.com/AlexGustafsson"><img src="https://avatars.githubusercontent.com/u/14974112?v=4?s=100" width="100px;" alt="Alex Gustafsson"/><br /><sub><b>Alex Gustafsson</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=AlexGustafsson" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=AlexGustafsson" title="Documentation">📖</a></td>
<td align="center"><a href="https://www.aarsen.me/"><img src="https://avatars.githubusercontent.com/u/7805050?v=4?s=100" width="100px;" alt="Arsenović Arsen"/><br /><sub><b>Arsenović Arsen</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=ArsenArsen" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=ArsenArsen" title="Tests">⚠️</a> <a href="#security-ArsenArsen" title="Security">🛡️</a></td>
<td align="center"><a href="https://github.com/dakriy"><img src="https://avatars.githubusercontent.com/u/13756065?v=4?s=100" width="100px;" alt="dakriy"/><br /><sub><b>dakriy</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=dakriy" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/davama"><img src="https://avatars.githubusercontent.com/u/5359152?v=4?s=100" width="100px;" alt="Dave"/><br /><sub><b>Dave</b></sub></a><br /><a href="#userTesting-davama" title="User Testing">📓</a></td>
<td align="center"><a href="https://github.com/nreymundo"><img src="https://avatars.githubusercontent.com/u/5833447?v=4?s=100" width="100px;" alt="Nicolas Reymundo"/><br /><sub><b>Nicolas Reymundo</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=nreymundo" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/polandy"><img src="https://avatars.githubusercontent.com/u/3670670?v=4?s=100" width="100px;" alt="polandy"/><br /><sub><b>polandy</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=polandy" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/you1996"><img src="https://avatars.githubusercontent.com/u/45292366?v=4?s=100" width="100px;" alt="yossbg"/><br /><sub><b>yossbg</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=you1996" title="Code">💻</a> <a href="#design-you1996" title="Design">🎨</a></td>
<td align="center"><a href="https://github.com/mpdcampbell"><img src="https://avatars.githubusercontent.com/u/47434940?v=4?s=100" width="100px;" alt="Michael Campbell"/><br /><sub><b>Michael Campbell</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=mpdcampbell" title="Documentation">📖</a></td>
<td align="center"><a href="https://sievenpiper.co"><img src="https://avatars.githubusercontent.com/u/1131882?v=4?s=100" width="100px;" alt="Justin Sievenpiper"/><br /><sub><b>Justin Sievenpiper</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=jsievenpiper" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/kaysond"><img src="https://avatars.githubusercontent.com/u/1147328?v=4?s=100" width="100px;" alt="Aram Akhavan"/><br /><sub><b>Aram Akhavan</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=kaysond" title="Documentation">📖</a></td>
<td align="center"><a href="https://skhuf.net"><img src="https://avatars.githubusercontent.com/u/286341?v=4?s=100" width="100px;" alt="Shadow"/><br /><sub><b>Shadow</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=shadow7412" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/tarioch"><img src="https://avatars.githubusercontent.com/u/2998148?v=4?s=100" width="100px;" alt="Patrick Ruckstuhl"/><br /><sub><b>Patrick Ruckstuhl</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=tarioch" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/FineWolf"><img src="https://avatars.githubusercontent.com/u/203591?v=4?s=100" width="100px;" alt="Andrew Moore"/><br /><sub><b>Andrew Moore</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=FineWolf" title="Code">💻</a> <a href="https://github.com/authelia/authelia/commits?author=FineWolf" title="Documentation">📖</a> <a href="https://github.com/authelia/authelia/commits?author=FineWolf" title="Tests">⚠️</a></td>
</tr>
<tr>
<td align="center"><a href="http://www.dennisgaida.de"><img src="https://avatars.githubusercontent.com/u/2392217?v=4?s=100" width="100px;" alt="Dennis Gaida"/><br /><sub><b>Dennis Gaida</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=DennisGaida" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/Alestrix"><img src="https://avatars.githubusercontent.com/u/7452860?v=4?s=100" width="100px;" alt="Alestrix"/><br /><sub><b>Alestrix</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=Alestrix" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/bgh-github"><img src="https://avatars.githubusercontent.com/u/99472455?v=4?s=100" width="100px;" alt="bgh-github"/><br /><sub><b>bgh-github</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=bgh-github" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/mind-ar"><img src="https://avatars.githubusercontent.com/u/10672208?v=4?s=100" width="100px;" alt="Manuel Nuñez"/><br /><sub><b>Manuel Nuñez</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=mind-ar" title="Code">💻</a> <a href="#translation-mind-ar" title="Translation">🌍</a></td>
<td align="center"><a href="https://github.com/protvis74"><img src="https://avatars.githubusercontent.com/u/50554836?v=4?s=100" width="100px;" alt="protvis74"/><br /><sub><b>protvis74</b></sub></a><br /><a href="#translation-protvis74" title="Translation">🌍</a></td>
<td align="center"><a href="http://itjamie.com"><img src="https://avatars.githubusercontent.com/u/1613241?v=4?s=100" width="100px;" alt="Jamie (Bear) Murphy "/><br /><sub><b>Jamie (Bear) Murphy </b></sub></a><br /><a href="https://github.com/authelia/authelia/pulls?q=is%3Apr+reviewed-by%3AITJamie" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="https://github.com/Beanow"><img src="https://avatars.githubusercontent.com/u/497556?v=4?s=100" width="100px;" alt="Robin van Boven"/><br /><sub><b>Robin van Boven</b></sub></a><br /><a href="#security-Beanow" title="Security">🛡️</a></td>
</tr>
<tr>
<td align="center"><a href="http://www.cybertrol.com"><img src="https://avatars.githubusercontent.com/u/1178293?v=4?s=100" width="100px;" alt="alphabet5"/><br /><sub><b>alphabet5</b></sub></a><br /><a href="#ideas-alphabet5" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://github.com/rjmidau"><img src="https://avatars.githubusercontent.com/u/8134995?v=4?s=100" width="100px;" alt="Robert Meredith"/><br /><sub><b>Robert Meredith</b></sub></a><br /><a href="#ideas-rjmidau" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center"><a href="https://github.com/adriang-90"><img src="https://avatars.githubusercontent.com/u/60886162?v=4?s=100" width="100px;" alt="Adrian Gąsior"/><br /><sub><b>Adrian Gąsior</b></sub></a><br /><a href="#security-adriang-90" title="Security">🛡️</a></td>
<td align="center"><a href="http://jamesw.link/me"><img src="https://avatars.githubusercontent.com/u/8067792?v=4?s=100" width="100px;" alt="James White"/><br /><sub><b>James White</b></sub></a><br /><a href="#question-jamesmacwhite" title="Answering Questions">💬</a></td>
<td align="center"><a href="https://www.zxlim.xyz"><img src="https://avatars.githubusercontent.com/u/19372079?v=4?s=100" width="100px;" alt="Zhao Xiang Lim"/><br /><sub><b>Zhao Xiang Lim</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=zxlim" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/Auzborn123"><img src="https://avatars.githubusercontent.com/u/42992103?v=4?s=100" width="100px;" alt="Auzborn123"/><br /><sub><b>Auzborn123</b></sub></a><br /><a href="#translation-Auzborn123" title="Translation">🌍</a></td>
<td align="center"><a href="https://github.com/SvanGlan"><img src="https://avatars.githubusercontent.com/u/106152205?v=4?s=100" width="100px;" alt="SvanGlan"/><br /><sub><b>SvanGlan</b></sub></a><br /><a href="#translation-SvanGlan" title="Translation">🌍</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/HannesJo0139"><img src="https://avatars.githubusercontent.com/u/42114183?v=4?s=100" width="100px;" alt="HannesJo0139"/><br /><sub><b>HannesJo0139</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=HannesJo0139" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/andreas-berg"><img src="https://avatars.githubusercontent.com/u/39428693?v=4?s=100" width="100px;" alt="andreas-berg"/><br /><sub><b>andreas-berg</b></sub></a><br /><a href="https://github.com/authelia/authelia/issues?q=author%3Aandreas-berg" title="Bug reports">🐛</a></td>
<td align="center"><a href="http://radenac.me"><img src="https://avatars.githubusercontent.com/u/47008408?v=4?s=100" width="100px;" alt="Clément Radenac"/><br /><sub><b>Clément Radenac</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=clem3109" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/boomam"><img src="https://avatars.githubusercontent.com/u/37086258?v=4?s=100" width="100px;" alt="boomam"/><br /><sub><b>boomam</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=boomam" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/Northguy"><img src="https://avatars.githubusercontent.com/u/1189058?v=4?s=100" width="100px;" alt="Northguy"/><br /><sub><b>Northguy</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=Northguy" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/polarathene"><img src="https://avatars.githubusercontent.com/u/5098581?v=4?s=100" width="100px;" alt="Brennan Kinney"/><br /><sub><b>Brennan Kinney</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=polarathene" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/LongerHV"><img src="https://avatars.githubusercontent.com/u/46924944?v=4?s=100" width="100px;" alt="Michał Mieszczak"/><br /><sub><b>Michał Mieszczak</b></sub></a><br /><a href="#ideas-LongerHV" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/authelia/authelia/commits?author=LongerHV" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/paul-ohl"><img src="https://avatars.githubusercontent.com/u/37795294?v=4?s=100" width="100px;" alt="Paul Ohl"/><br /><sub><b>Paul Ohl</b></sub></a><br /><a href="https://github.com/authelia/authelia/commits?author=paul-ohl" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/smkent"><img src="https://avatars.githubusercontent.com/u/2831985?v=4?s=100" width="100px;" alt="Stephen Kent"/><br /><sub><b>Stephen Kent</b></sub></a><br /><a href="#ideas-smkent" title="Ideas, Planning, & Feedback">🤔</a></td>
</tr>
</tbody>
</table>
<!-- markdownlint-restore -->
@ -389,10 +391,12 @@ Companies contributing to Authelia via Open Collective will have a special menti
[Webauthn]: https://www.yubico.com/authentication-standards/webauthn/
[auth_request]: https://nginx.org/en/docs/http/ngx_http_auth_request_module.html
[config.template.yml]: ./config.template.yml
[nginx]: https://www.nginx.com/
[Traefik]: https://traefik.io/
[caddy]: https://caddyserver.com/
[HAProxy]: https://www.haproxy.org/
[nginx]: https://www.authelia.com/integration/proxies/nginx/
[Traefik]: https://www.authelia.com/integration/proxies/traefik/
[Caddy]: https://www.authelia.com/integration/proxies/caddy/
[Skipper]: https://www.authelia.com/integration/proxies/skipper/
[Envoy]: https://www.authelia.com/integration/proxies/envoy/
[HAProxy]: https://www.authelia.com/integration/proxies/haproxy/
[Docker]: https://docker.com/
[Kubernetes]: https://kubernetes.io/
[security]: https://github.com/authelia/authelia/security/policy

View File

@ -176,7 +176,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/handlers.firstFactorRequestBody'
$ref: '#/components/schemas/handlers.bodyFirstFactorRequest'
responses:
"200":
description: Successful Operation
@ -446,7 +446,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/handlers.signTOTPRequestBody'
$ref: '#/components/schemas/handlers.bodySignTOTPRequest'
responses:
"200":
description: Successful Operation
@ -579,7 +579,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/handlers.signDuoRequestBody'
$ref: '#/components/schemas/handlers.bodySignDuoRequest'
responses:
"200":
description: Successful Operation
@ -785,7 +785,7 @@ components:
items:
type: string
example: push
handlers.firstFactorRequestBody:
handlers.bodyFirstFactorRequest:
required:
- username
- password
@ -800,6 +800,12 @@ components:
targetURL:
type: string
example: https://home.example.com
workflow:
type: string
example: openid_connect
workflowID:
type: string
example: 3ebcfbc5-b0fd-4ee0-9d3c-080ae1e7298c
requestMethod:
type: string
example: GET
@ -852,13 +858,21 @@ components:
password:
type: string
example: password
handlers.signDuoRequestBody:
handlers.bodySignDuoRequest:
type: object
properties:
targetURL:
type: string
example: https://secure.example.com
handlers.signTOTPRequestBody:
passcode:
type: string
workflow:
type: string
example: openid_connect
workflowID:
type: string
example: 3ebcfbc5-b0fd-4ee0-9d3c-080ae1e7298c
handlers.bodySignTOTPRequest:
type: object
properties:
token:
@ -867,6 +881,12 @@ components:
targetURL:
type: string
example: https://secure.example.com
workflow:
type: string
example: openid_connect
workflowID:
type: string
example: 3ebcfbc5-b0fd-4ee0-9d3c-080ae1e7298c
handlers.StateResponse:
type: object
properties:
@ -1047,6 +1067,12 @@ components:
userHandle:
type: string
format: byte
workflow:
type: string
example: openid_connect
workflowID:
type: string
example: 3ebcfbc5-b0fd-4ee0-9d3c-080ae1e7298c
webauthn.PublicKeyCredentialCreationOptions:
type: object
properties:

View File

@ -1,36 +0,0 @@
package main
import (
"github.com/spf13/cobra"
)
func newAllCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "all",
Short: "Run all generators with default options",
RunE: allRunE,
DisableAutoGenTag: true,
}
return cmd
}
func allRunE(cmd *cobra.Command, args []string) (err error) {
for _, subCmd := range cmd.Parent().Commands() {
if subCmd == cmd || subCmd.Use == "completion" || subCmd.Use == "help [command]" {
continue
}
switch {
case subCmd.RunE != nil:
if err = subCmd.RunE(subCmd, args); err != nil {
return err
}
case subCmd.Run != nil:
subCmd.Run(subCmd, args)
}
}
return nil
}

View File

@ -1,34 +1,330 @@
package main
import (
"crypto/ecdsa"
"crypto/rsa"
"encoding/json"
"fmt"
"io"
"net/http"
"net/mail"
"net/url"
"os"
"path/filepath"
"reflect"
"regexp"
"strings"
"time"
"github.com/spf13/cobra"
"github.com/authelia/authelia/v4/internal/configuration/schema"
)
func newCodeCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "code",
Use: cmdUseCode,
Short: "Generate code",
RunE: codeRunE,
RunE: rootSubCommandsRunE,
DisableAutoGenTag: true,
}
cmd.AddCommand(newCodeKeysCmd())
cmd.AddCommand(newCodeKeysCmd(), newCodeServerCmd(), newCodeScriptsCmd())
return cmd
}
func codeRunE(cmd *cobra.Command, args []string) (err error) {
for _, subCmd := range cmd.Commands() {
switch {
case subCmd.RunE != nil:
if err = subCmd.RunE(subCmd, args); err != nil {
return err
}
case subCmd.Run != nil:
subCmd.Run(subCmd, args)
}
func newCodeServerCmd() *cobra.Command {
cmd := &cobra.Command{
Use: cmdUseServer,
Short: "Generate the Authelia server files",
RunE: codeServerRunE,
DisableAutoGenTag: true,
}
return cmd
}
func newCodeScriptsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: cmdUseCodeScripts,
Short: "Generate the generated portion of the authelia-scripts command",
RunE: codeScriptsRunE,
DisableAutoGenTag: true,
}
return cmd
}
func newCodeKeysCmd() *cobra.Command {
cmd := &cobra.Command{
Use: cmdUseKeys,
Short: "Generate the list of valid configuration keys",
RunE: codeKeysRunE,
DisableAutoGenTag: true,
}
return cmd
}
func codeServerRunE(cmd *cobra.Command, args []string) (err error) {
data := TemplateCSP{
PlaceholderNONCE: codeCSPNonce,
TemplateDefault: buildCSP(codeCSPProductionDefaultSrc, codeCSPValuesCommon, codeCSPValuesProduction),
TemplateDevelopment: buildCSP(codeCSPDevelopmentDefaultSrc, codeCSPValuesCommon, codeCSPValuesDevelopment),
}
var outputPath string
if outputPath, err = getPFlagPath(cmd.Flags(), cmdFlagRoot, cmdFlagFileServerGenerated); err != nil {
return err
}
var f *os.File
if f, err = os.Create(outputPath); err != nil {
return fmt.Errorf("failed to create file '%s': %w", outputPath, err)
}
if err = tmplServer.Execute(f, data); err != nil {
_ = f.Close()
return fmt.Errorf("failed to write output file '%s': %w", outputPath, err)
}
if err = f.Close(); err != nil {
return fmt.Errorf("failed to close output file '%s': %w", outputPath, err)
}
return nil
}
func codeScriptsRunE(cmd *cobra.Command, args []string) (err error) {
var (
root, pathScriptsGen string
resp *http.Response
)
data := &tmplScriptsGEnData{}
if root, err = cmd.Flags().GetString(cmdFlagRoot); err != nil {
return err
}
if pathScriptsGen, err = cmd.Flags().GetString(cmdFlagFileScriptsGen); err != nil {
return err
}
if data.Package, err = cmd.Flags().GetString(cmdFlagPackageScriptsGen); err != nil {
return err
}
if resp, err = http.Get("https://api.github.com/repos/swagger-api/swagger-ui/tags"); err != nil {
return fmt.Errorf("failed to get latest version of the Swagger UI: %w", err)
}
defer resp.Body.Close()
var (
respJSON []GitHubTagsJSON
respRaw []byte
)
if respRaw, err = io.ReadAll(resp.Body); err != nil {
return fmt.Errorf("failed to get latest version of the Swagger UI: %w", err)
}
if err = json.Unmarshal(respRaw, &respJSON); err != nil {
return fmt.Errorf("failed to get latest version of the Swagger UI: %w", err)
}
if len(respJSON) < 1 {
return fmt.Errorf("failed to get latest version of the Swagger UI: the api returned zero results")
}
if strings.HasPrefix(respJSON[0].Name, "v") {
data.VersionSwaggerUI = respJSON[0].Name[1:]
} else {
data.VersionSwaggerUI = respJSON[0].Name
}
fullPathScriptsGen := filepath.Join(root, pathScriptsGen)
var f *os.File
if f, err = os.Create(fullPathScriptsGen); err != nil {
return fmt.Errorf("failed to create file '%s': %w", fullPathScriptsGen, err)
}
if err = tmplScriptsGen.Execute(f, data); err != nil {
_ = f.Close()
return fmt.Errorf("failed to write output file '%s': %w", fullPathScriptsGen, err)
}
if err = f.Close(); err != nil {
return fmt.Errorf("failed to close output file '%s': %w", fullPathScriptsGen, err)
}
return nil
}
func codeKeysRunE(cmd *cobra.Command, args []string) (err error) {
var (
pathCodeConfigKeys, root string
f *os.File
)
data := tmplConfigurationKeysData{
Timestamp: time.Now(),
Keys: readTags("", reflect.TypeOf(schema.Configuration{})),
}
if root, err = cmd.Flags().GetString(cmdFlagRoot); err != nil {
return err
}
if pathCodeConfigKeys, err = cmd.Flags().GetString(cmdFlagFileConfigKeys); err != nil {
return err
}
if data.Package, err = cmd.Flags().GetString(cmdFlagPackageConfigKeys); err != nil {
return err
}
fullPathCodeConfigKeys := filepath.Join(root, pathCodeConfigKeys)
if f, err = os.Create(fullPathCodeConfigKeys); err != nil {
return fmt.Errorf("failed to create file '%s': %w", fullPathCodeConfigKeys, err)
}
if err = tmplCodeConfigurationSchemaKeys.Execute(f, data); err != nil {
_ = f.Close()
return fmt.Errorf("failed to write output file '%s': %w", fullPathCodeConfigKeys, err)
}
if err = f.Close(); err != nil {
return fmt.Errorf("failed to close output file '%s': %w", fullPathCodeConfigKeys, err)
}
return nil
}
var decodedTypes = []reflect.Type{
reflect.TypeOf(mail.Address{}),
reflect.TypeOf(regexp.Regexp{}),
reflect.TypeOf(url.URL{}),
reflect.TypeOf(time.Duration(0)),
reflect.TypeOf(schema.Address{}),
reflect.TypeOf(rsa.PrivateKey{}),
reflect.TypeOf(ecdsa.PrivateKey{}),
}
func containsType(needle reflect.Type, haystack []reflect.Type) (contains bool) {
for _, t := range haystack {
if needle.Kind() == reflect.Ptr {
if needle.Elem() == t {
return true
}
} else if needle == t {
return true
}
}
return false
}
//nolint:gocyclo
func readTags(prefix string, t reflect.Type) (tags []string) {
tags = make([]string, 0)
if t.Kind() != reflect.Struct {
if t.Kind() == reflect.Slice {
tags = append(tags, readTags(getKeyNameFromTagAndPrefix(prefix, "", true), t.Elem())...)
}
return
}
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
tag := field.Tag.Get("koanf")
if tag == "" {
tags = append(tags, prefix)
continue
}
switch field.Type.Kind() {
case reflect.Struct:
if !containsType(field.Type, decodedTypes) {
tags = append(tags, readTags(getKeyNameFromTagAndPrefix(prefix, tag, false), field.Type)...)
continue
}
case reflect.Slice:
switch field.Type.Elem().Kind() {
case reflect.Struct:
if !containsType(field.Type.Elem(), decodedTypes) {
tags = append(tags, getKeyNameFromTagAndPrefix(prefix, tag, false))
tags = append(tags, readTags(getKeyNameFromTagAndPrefix(prefix, tag, true), field.Type.Elem())...)
continue
}
case reflect.Slice:
tags = append(tags, readTags(getKeyNameFromTagAndPrefix(prefix, tag, true), field.Type.Elem())...)
}
case reflect.Ptr:
switch field.Type.Elem().Kind() {
case reflect.Struct:
if !containsType(field.Type.Elem(), decodedTypes) {
tags = append(tags, readTags(getKeyNameFromTagAndPrefix(prefix, tag, false), field.Type.Elem())...)
continue
}
case reflect.Slice:
if field.Type.Elem().Elem().Kind() == reflect.Struct {
if !containsType(field.Type.Elem(), decodedTypes) {
tags = append(tags, readTags(getKeyNameFromTagAndPrefix(prefix, tag, true), field.Type.Elem())...)
continue
}
}
}
}
tags = append(tags, getKeyNameFromTagAndPrefix(prefix, tag, false))
}
return tags
}
func getKeyNameFromTagAndPrefix(prefix, name string, slice bool) string {
nameParts := strings.SplitN(name, ",", 2)
if prefix == "" {
return nameParts[0]
}
if len(nameParts) == 2 && nameParts[1] == "squash" {
return prefix
}
if slice {
if name == "" {
return fmt.Sprintf("%s[]", prefix)
}
return fmt.Sprintf("%s.%s[]", prefix, nameParts[0])
}
return fmt.Sprintf("%s.%s", prefix, nameParts[0])
}

View File

@ -1,173 +0,0 @@
package main
import (
"fmt"
"net/mail"
"net/url"
"os"
"reflect"
"regexp"
"strings"
"text/template"
"time"
"github.com/spf13/cobra"
"github.com/authelia/authelia/v4/internal/configuration/schema"
)
func newCodeKeysCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "keys",
Short: "Generate the list of valid configuration keys",
RunE: codeKeysRunE,
DisableAutoGenTag: true,
}
cmd.Flags().StringP("file", "f", "./internal/configuration/schema/keys.go", "Sets the path of the keys file")
cmd.Flags().String("package", "schema", "Sets the package name of the keys file")
return cmd
}
func codeKeysRunE(cmd *cobra.Command, args []string) (err error) {
var (
file string
f *os.File
)
data := keysTemplateStruct{
Timestamp: time.Now(),
Keys: readTags("", reflect.TypeOf(schema.Configuration{})),
}
if file, err = cmd.Flags().GetString("file"); err != nil {
return err
}
if data.Package, err = cmd.Flags().GetString("package"); err != nil {
return err
}
if f, err = os.Create(file); err != nil {
return fmt.Errorf("failed to create file '%s': %w", file, err)
}
var (
content []byte
tmpl *template.Template
)
if content, err = templatesFS.ReadFile("templates/config_keys.go.tmpl"); err != nil {
return err
}
if tmpl, err = template.New("keys").Parse(string(content)); err != nil {
return err
}
return tmpl.Execute(f, data)
}
type keysTemplateStruct struct {
Timestamp time.Time
Keys []string
Package string
}
var decodedTypes = []reflect.Type{
reflect.TypeOf(mail.Address{}),
reflect.TypeOf(regexp.Regexp{}),
reflect.TypeOf(url.URL{}),
reflect.TypeOf(time.Duration(0)),
reflect.TypeOf(schema.Address{}),
}
func containsType(needle reflect.Type, haystack []reflect.Type) (contains bool) {
for _, t := range haystack {
if needle.Kind() == reflect.Ptr {
if needle.Elem() == t {
return true
}
} else if needle == t {
return true
}
}
return false
}
func readTags(prefix string, t reflect.Type) (tags []string) {
tags = make([]string, 0)
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
tag := field.Tag.Get("koanf")
if tag == "" {
tags = append(tags, prefix)
continue
}
switch field.Type.Kind() {
case reflect.Struct:
if !containsType(field.Type, decodedTypes) {
tags = append(tags, readTags(getKeyNameFromTagAndPrefix(prefix, tag, false), field.Type)...)
continue
}
case reflect.Slice:
if field.Type.Elem().Kind() == reflect.Struct {
if !containsType(field.Type.Elem(), decodedTypes) {
tags = append(tags, getKeyNameFromTagAndPrefix(prefix, tag, false))
tags = append(tags, readTags(getKeyNameFromTagAndPrefix(prefix, tag, true), field.Type.Elem())...)
continue
}
}
case reflect.Ptr:
switch field.Type.Elem().Kind() {
case reflect.Struct:
if !containsType(field.Type.Elem(), decodedTypes) {
tags = append(tags, readTags(getKeyNameFromTagAndPrefix(prefix, tag, false), field.Type.Elem())...)
continue
}
case reflect.Slice:
if field.Type.Elem().Elem().Kind() == reflect.Struct {
if !containsType(field.Type.Elem(), decodedTypes) {
tags = append(tags, readTags(getKeyNameFromTagAndPrefix(prefix, tag, true), field.Type.Elem())...)
continue
}
}
}
}
tags = append(tags, getKeyNameFromTagAndPrefix(prefix, tag, false))
}
return tags
}
func getKeyNameFromTagAndPrefix(prefix, name string, slice bool) string {
nameParts := strings.SplitN(name, ",", 2)
if prefix == "" {
return nameParts[0]
}
if len(nameParts) == 2 && nameParts[1] == "squash" {
return prefix
}
if slice {
return fmt.Sprintf("%s.%s[]", prefix, nameParts[0])
}
return fmt.Sprintf("%s.%s", prefix, nameParts[0])
}

View File

@ -0,0 +1,220 @@
package main
import (
"fmt"
"os"
"path/filepath"
"sort"
"strings"
"github.com/spf13/cobra"
)
// CommitMessageTmpl is a template data structure which is used to generate files with commit message information.
type CommitMessageTmpl struct {
Scopes ScopesTmpl
Types TypesTmpl
}
// TypesTmpl is a template data structure which is used to generate files with commit message types.
type TypesTmpl struct {
List []string
Details []NameDescriptionTmpl
}
// ScopesTmpl is a template data structure which is used to generate files with commit message scopes.
type ScopesTmpl struct {
All []string
Packages []string
Extra []NameDescriptionTmpl
}
// NameDescriptionTmpl is a template item which includes a name, description and list of scopes.
type NameDescriptionTmpl struct {
Name string
Description string
Scopes []string
}
func newCommitLintCmd() *cobra.Command {
cmd := &cobra.Command{
Use: cmdUseCommitLint,
Short: "Generate commit lint files",
RunE: commitLintRunE,
DisableAutoGenTag: true,
}
return cmd
}
var commitScopesExtra = []NameDescriptionTmpl{
{"api", "used for changes that change the openapi specification", nil},
{"cmd", "used for changes to the `%s` top level binaries", nil},
{"web", "used for changes to the React based frontend", nil},
}
var commitTypes = []NameDescriptionTmpl{
{"build", "Changes that affect the build system or external dependencies", []string{"bundler", "deps", "docker", "go", "npm"}},
{"ci", "Changes to our CI configuration files and scripts", []string{"autheliabot", "buildkite", "codecov", "golangci-lint", "renovate", "reviewdog"}},
{"docs", "Documentation only changes", nil},
{"feat", "A new feature", nil},
{"fix", "A bug fix", nil},
{"i18n", "Updating translations or internationalization settings", nil},
{"perf", "A code change that improves performance", nil},
{"refactor", "A code change that neither fixes a bug nor adds a feature", nil},
{"release", "Releasing a new version of Authelia", nil},
{"test", "Adding missing tests or correcting existing tests", nil},
}
var commitTypesExtra = []string{"revert"}
func getGoPackages(dir string) (pkgs []string, err error) {
var (
entries []os.DirEntry
entriesSub []os.DirEntry
)
if entries, err = os.ReadDir(dir); err != nil {
return nil, fmt.Errorf("failed to detect go packages in directory '%s': %w", dir, err)
}
for _, entry := range entries {
if !entry.IsDir() {
continue
}
if entriesSub, err = os.ReadDir(filepath.Join(dir, entry.Name())); err != nil {
continue
}
for _, entrySub := range entriesSub {
if entrySub.IsDir() {
continue
}
if strings.HasSuffix(entrySub.Name(), ".go") {
pkgs = append(pkgs, entry.Name())
break
}
}
}
return pkgs, nil
}
func commitLintRunE(cmd *cobra.Command, args []string) (err error) {
var root, pathCommitLintConfig, pathDocsCommitMessageGuidelines string
if root, err = cmd.Flags().GetString(cmdFlagRoot); err != nil {
return err
}
if pathCommitLintConfig, err = cmd.Flags().GetString(cmdFlagFileConfigCommitLint); err != nil {
return err
}
if pathDocsCommitMessageGuidelines, err = cmd.Flags().GetString(cmdFlagFileDocsCommitMsgGuidelines); err != nil {
return err
}
data := &CommitMessageTmpl{
Scopes: ScopesTmpl{
All: []string{},
Packages: []string{},
Extra: []NameDescriptionTmpl{},
},
Types: TypesTmpl{
List: []string{},
Details: []NameDescriptionTmpl{},
},
}
var (
cmds []string
pkgs []string
)
if cmds, err = getGoPackages(filepath.Join(root, subPathCmd)); err != nil {
return err
}
if pkgs, err = getGoPackages(filepath.Join(root, subPathInternal)); err != nil {
return err
}
data.Scopes.All = append(data.Scopes.All, pkgs...)
data.Scopes.Packages = append(data.Scopes.Packages, pkgs...)
for _, scope := range commitScopesExtra {
switch scope.Name {
case subPathCmd:
data.Scopes.Extra = append(data.Scopes.Extra, NameDescriptionTmpl{Name: scope.Name, Description: fmt.Sprintf(scope.Description, strings.Join(cmds, "|"))})
default:
data.Scopes.Extra = append(data.Scopes.Extra, scope)
}
data.Scopes.All = append(data.Scopes.All, scope.Name)
}
for _, cType := range commitTypes {
data.Types.List = append(data.Types.List, cType.Name)
data.Types.Details = append(data.Types.Details, cType)
data.Scopes.All = append(data.Scopes.All, cType.Scopes...)
}
data.Types.List = append(data.Types.List, commitTypesExtra...)
sort.Slice(data.Scopes.All, func(i, j int) bool {
return data.Scopes.All[i] < data.Scopes.All[j]
})
sort.Slice(data.Scopes.Packages, func(i, j int) bool {
return data.Scopes.Packages[i] < data.Scopes.Packages[j]
})
sort.Slice(data.Scopes.Extra, func(i, j int) bool {
return data.Scopes.Extra[i].Name < data.Scopes.Extra[j].Name
})
sort.Slice(data.Types.List, func(i, j int) bool {
return data.Types.List[i] < data.Types.List[j]
})
sort.Slice(data.Types.Details, func(i, j int) bool {
return data.Types.Details[i].Name < data.Types.Details[j].Name
})
var f *os.File
fullPathCommitLintConfig := filepath.Join(root, pathCommitLintConfig)
if f, err = os.Create(fullPathCommitLintConfig); err != nil {
return fmt.Errorf("failed to create output file '%s': %w", fullPathCommitLintConfig, err)
}
if err = tmplDotCommitLintRC.Execute(f, data); err != nil {
return fmt.Errorf("failed to write output file '%s': %w", fullPathCommitLintConfig, err)
}
if err = f.Close(); err != nil {
return fmt.Errorf("failed to close output file '%s': %w", fullPathCommitLintConfig, err)
}
fullPathDocsCommitMessageGuidelines := filepath.Join(root, pathDocsCommitMessageGuidelines)
if f, err = os.Create(fullPathDocsCommitMessageGuidelines); err != nil {
return fmt.Errorf("failed to create output file '%s': %w", fullPathDocsCommitMessageGuidelines, err)
}
if err = tmplDocsCommitMessageGuidelines.Execute(f, data); err != nil {
return fmt.Errorf("failed to write output file '%s': %w", fullPathDocsCommitMessageGuidelines, err)
}
if err = f.Close(); err != nil {
return fmt.Errorf("failed to close output file '%s': %w", fullPathDocsCommitMessageGuidelines, err)
}
return nil
}

View File

@ -6,30 +6,14 @@ import (
func newDocsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "docs",
Use: cmdUseDocs,
Short: "Generate docs",
RunE: docsRunE,
RunE: rootSubCommandsRunE,
DisableAutoGenTag: true,
}
cmd.PersistentFlags().StringP("cwd", "C", "", "Sets the CWD for git commands")
cmd.AddCommand(newDocsCLICmd(), newDocsDateCmd())
cmd.AddCommand(newDocsCLICmd(), newDocsDataCmd(), newDocsDateCmd())
return cmd
}
func docsRunE(cmd *cobra.Command, args []string) (err error) {
for _, subCmd := range cmd.Commands() {
switch {
case subCmd.RunE != nil:
if err = subCmd.RunE(subCmd, args); err != nil {
return err
}
case subCmd.Run != nil:
subCmd.Run(subCmd, args)
}
}
return nil
}

View File

@ -16,52 +16,50 @@ import (
func newDocsCLICmd() *cobra.Command {
cmd := &cobra.Command{
Use: "cli",
Use: cmdUseDocsCLI,
Short: "Generate CLI docs",
RunE: docsCLIRunE,
DisableAutoGenTag: true,
}
cmd.Flags().StringP("directory", "d", "./docs/content/en/reference/cli", "The directory to store the markdown in")
return cmd
}
func docsCLIRunE(cmd *cobra.Command, args []string) (err error) {
var root string
var outputPath string
if root, err = cmd.Flags().GetString("directory"); err != nil {
if outputPath, err = getPFlagPath(cmd.Flags(), cmdFlagRoot, cmdFlagDocs, cmdFlagDocsContent, cmdFlagDocsCLIReference); err != nil {
return err
}
if err = os.MkdirAll(root, 0775); err != nil {
if err = os.MkdirAll(outputPath, 0775); err != nil {
if !os.IsExist(err) {
return err
}
}
if err = genCLIDoc(commands.NewRootCmd(), filepath.Join(root, "authelia")); err != nil {
if err = genCLIDoc(commands.NewRootCmd(), filepath.Join(outputPath, "authelia")); err != nil {
return err
}
if err = genCLIDocWriteIndex(root, "authelia"); err != nil {
if err = genCLIDocWriteIndex(outputPath, "authelia"); err != nil {
return err
}
if err = genCLIDoc(cmdscripts.NewRootCmd(), filepath.Join(root, "authelia-scripts")); err != nil {
if err = genCLIDoc(cmdscripts.NewRootCmd(), filepath.Join(outputPath, "authelia-scripts")); err != nil {
return err
}
if err = genCLIDocWriteIndex(root, "authelia-scripts"); err != nil {
if err = genCLIDocWriteIndex(outputPath, "authelia-scripts"); err != nil {
return err
}
if err = genCLIDoc(newRootCmd(), filepath.Join(root, "authelia-gen")); err != nil {
if err = genCLIDoc(newRootCmd(), filepath.Join(outputPath, cmdUseRoot)); err != nil {
return err
}
if err = genCLIDocWriteIndex(root, "authelia-gen"); err != nil {
if err = genCLIDocWriteIndex(outputPath, cmdUseRoot); err != nil {
return err
}
@ -69,6 +67,16 @@ func docsCLIRunE(cmd *cobra.Command, args []string) (err error) {
}
func genCLIDoc(cmd *cobra.Command, path string) (err error) {
if _, err = os.Stat(path); err != nil && !os.IsNotExist(err) {
return err
}
if err == nil || !os.IsNotExist(err) {
if err = os.RemoveAll(path); err != nil {
return fmt.Errorf("failed to remove docs: %w", err)
}
}
if err = os.Mkdir(path, 0755); err != nil {
if !os.IsExist(err) {
return err

View File

@ -0,0 +1,132 @@
package main
import (
"encoding/json"
"fmt"
"os"
"reflect"
"strings"
"github.com/spf13/cobra"
"github.com/authelia/authelia/v4/internal/configuration"
"github.com/authelia/authelia/v4/internal/configuration/schema"
)
func newDocsDataCmd() *cobra.Command {
cmd := &cobra.Command{
Use: cmdUseDocsData,
Short: "Generate docs data files",
RunE: rootSubCommandsRunE,
DisableAutoGenTag: true,
}
cmd.AddCommand(newDocsDataMiscCmd(), newDocsDataKeysCmd())
return cmd
}
func newDocsDataMiscCmd() *cobra.Command {
cmd := &cobra.Command{
Use: cmdUseDocsDataMisc,
Short: "Generate docs data file misc.json",
RunE: docsDataMiscRunE,
DisableAutoGenTag: true,
}
return cmd
}
func docsDataMiscRunE(cmd *cobra.Command, args []string) (err error) {
data := DocsDataMisc{
CSP: TemplateCSP{
PlaceholderNONCE: codeCSPNonce,
TemplateDefault: buildCSP(codeCSPProductionDefaultSrc, codeCSPValuesCommon, codeCSPValuesProduction),
TemplateDevelopment: buildCSP(codeCSPDevelopmentDefaultSrc, codeCSPValuesCommon, codeCSPValuesDevelopment),
},
}
data.CSP.TemplateDefault = strings.ReplaceAll(data.CSP.TemplateDefault, "%s", codeCSPNonce)
data.CSP.TemplateDevelopment = strings.ReplaceAll(data.CSP.TemplateDevelopment, "%s", codeCSPNonce)
var (
outputPath string
dataJSON []byte
)
if outputPath, err = getPFlagPath(cmd.Flags(), cmdFlagRoot, cmdFlagDocs, cmdFlagDocsData, cmdFlagDocsDataMisc); err != nil {
return err
}
if dataJSON, err = json.Marshal(data); err != nil {
return err
}
if err = os.WriteFile(outputPath, dataJSON, 0600); err != nil {
return fmt.Errorf("failed to write file '%s': %w", outputPath, err)
}
return nil
}
func newDocsDataKeysCmd() *cobra.Command {
cmd := &cobra.Command{
Use: cmdUseKeys,
Short: "Generate the docs data file for configuration keys",
RunE: docsKeysRunE,
DisableAutoGenTag: true,
}
return cmd
}
func docsKeysRunE(cmd *cobra.Command, args []string) (err error) {
//nolint:prealloc
var (
data []ConfigurationKey
)
keys := readTags("", reflect.TypeOf(schema.Configuration{}))
for _, key := range keys {
if strings.Contains(key, "[]") {
continue
}
ck := ConfigurationKey{
Path: key,
Secret: configuration.IsSecretKey(key),
}
switch {
case ck.Secret:
ck.Env = configuration.ToEnvironmentSecretKey(key, configuration.DefaultEnvPrefix, configuration.DefaultEnvDelimiter)
default:
ck.Env = configuration.ToEnvironmentKey(key, configuration.DefaultEnvPrefix, configuration.DefaultEnvDelimiter)
}
data = append(data, ck)
}
var (
dataJSON []byte
outputPath string
)
if outputPath, err = getPFlagPath(cmd.Flags(), cmdFlagRoot, cmdFlagDocs, cmdFlagDocsData, cmdFlagDocsDataKeys); err != nil {
return err
}
if dataJSON, err = json.Marshal(data); err != nil {
return err
}
if err = os.WriteFile(outputPath, dataJSON, 0600); err != nil {
return fmt.Errorf("failed to write file '%s': %w", outputPath, err)
}
return nil
}

View File

@ -17,14 +17,13 @@ import (
func newDocsDateCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "date",
Use: cmdUseDocsDate,
Short: "Generate doc dates",
RunE: docsDateRunE,
DisableAutoGenTag: true,
}
cmd.Flags().StringP("directory", "d", "./docs/content", "The directory to modify")
cmd.Flags().String("commit-until", "HEAD", "The commit to check the logs until")
cmd.Flags().String("commit-since", "", "The commit to check the logs since")
@ -33,14 +32,14 @@ func newDocsDateCmd() *cobra.Command {
func docsDateRunE(cmd *cobra.Command, args []string) (err error) {
var (
dir, cwd, commitUtil, commitSince, commitFilter string
pathDocsContent, cwd, commitUtil, commitSince, commitFilter string
)
if dir, err = cmd.Flags().GetString("directory"); err != nil {
if pathDocsContent, err = getPFlagPath(cmd.Flags(), cmdFlagRoot, cmdFlagDocs, cmdFlagDocsContent); err != nil {
return err
}
if cwd, err = cmd.Flags().GetString("cwd"); err != nil {
if cwd, err = cmd.Flags().GetString(cmdFlagCwd); err != nil {
return err
}
@ -56,7 +55,7 @@ func docsDateRunE(cmd *cobra.Command, args []string) (err error) {
commitFilter = fmt.Sprintf("%s...%s", commitUtil, commitSince)
}
return filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error {
return filepath.Walk(pathDocsContent, func(path string, info fs.FileInfo, err error) error {
if err != nil {
return err
}
@ -76,7 +75,7 @@ func docsDateRunE(cmd *cobra.Command, args []string) (err error) {
return nil
}
frontmatter := map[string]interface{}{}
frontmatter := map[string]any{}
if err = yaml.Unmarshal(frontmatterBytes, frontmatter); err != nil {
return err
@ -163,7 +162,7 @@ func replaceDates(path string, date time.Time, dateGit *time.Time) {
for scanner.Scan() {
if found < 2 && frontmatter < 2 {
switch {
case scanner.Text() == frontmatterDelimiterLine:
case scanner.Text() == delimiterLineFrontMatter:
buf.Write(scanner.Bytes())
frontmatter++
case frontmatter != 0 && strings.HasPrefix(scanner.Text(), "date: "):
@ -207,13 +206,13 @@ func getFrontmatter(path string) []byte {
for scanner.Scan() {
if start {
if scanner.Text() == frontmatterDelimiterLine {
if scanner.Text() == delimiterLineFrontMatter {
break
}
buf.Write(scanner.Bytes())
buf.Write(newline)
} else if scanner.Text() == frontmatterDelimiterLine {
} else if scanner.Text() == delimiterLineFrontMatter {
start = true
}
}

View File

@ -0,0 +1,236 @@
package main
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"github.com/spf13/cobra"
)
func newGitHubCmd() *cobra.Command {
cmd := &cobra.Command{
Use: cmdUseGitHub,
Short: "Generate GitHub files",
RunE: rootSubCommandsRunE,
DisableAutoGenTag: true,
}
cmd.AddCommand(newGitHubIssueTemplatesCmd())
return cmd
}
func newGitHubIssueTemplatesCmd() *cobra.Command {
cmd := &cobra.Command{
Use: cmdUseGitHubIssueTemplates,
Short: "Generate GitHub issue templates",
RunE: rootSubCommandsRunE,
DisableAutoGenTag: true,
}
cmd.AddCommand(newGitHubIssueTemplatesBugReportCmd(), newGitHubIssueTemplatesFeatureCmd())
return cmd
}
func newGitHubIssueTemplatesFeatureCmd() *cobra.Command {
cmd := &cobra.Command{
Use: cmdUseGitHubIssueTemplatesFR,
Short: "Generate GitHub feature request issue template",
RunE: cmdGitHubIssueTemplatesFeatureRunE,
DisableAutoGenTag: true,
}
return cmd
}
func newGitHubIssueTemplatesBugReportCmd() *cobra.Command {
cmd := &cobra.Command{
Use: cmdUseGitHubIssueTemplatesBR,
Short: "Generate GitHub bug report issue template",
RunE: cmdGitHubIssueTemplatesBugReportRunE,
DisableAutoGenTag: true,
}
return cmd
}
func cmdGitHubIssueTemplatesFeatureRunE(cmd *cobra.Command, args []string) (err error) {
var (
cwd, file, root string
tags, tagsFuture []string
latestMajor, latestMinor, latestPatch, versions int
)
if cwd, err = cmd.Flags().GetString(cmdFlagCwd); err != nil {
return err
}
if root, err = cmd.Flags().GetString(cmdFlagRoot); err != nil {
return err
}
if file, err = cmd.Flags().GetString(cmdFlagFeatureRequest); err != nil {
return err
}
if versions, err = cmd.Flags().GetInt(cmdFlagVersions); err != nil {
return err
}
if tags, err = getGitTags(cwd); err != nil {
return err
}
latest := tags[0]
if _, err = fmt.Sscanf(latest, "v%d.%d.%d", &latestMajor, &latestMinor, &latestPatch); err != nil {
return fmt.Errorf("error occurred parsing version as semver: %w", err)
}
var (
minor int
)
for minor = latestMinor + 1; minor < latestMinor+versions; minor++ {
tagsFuture = append(tagsFuture, fmt.Sprintf("v%d.%d.0", latestMajor, minor))
}
tagsFuture = append(tagsFuture, fmt.Sprintf("v%d.0.0", latestMajor+1))
var (
f *os.File
)
fullPath := filepath.Join(root, file)
if f, err = os.Create(fullPath); err != nil {
return fmt.Errorf("failed to create file '%s': %w", fullPath, err)
}
data := &tmplIssueTemplateData{
Labels: []string{labelTypeFeature.String(), labelStatusNeedsDesign.String(), labelPriorityNormal.String()},
Versions: tagsFuture,
}
if err = tmplIssueTemplateFeature.Execute(f, data); err != nil {
return err
}
return nil
}
func cmdGitHubIssueTemplatesBugReportRunE(cmd *cobra.Command, args []string) (err error) {
var (
cwd, file, dirRoot string
latestMinor, versions int
tags []string
)
if cwd, err = cmd.Flags().GetString(cmdFlagCwd); err != nil {
return err
}
if dirRoot, err = cmd.Flags().GetString(cmdFlagRoot); err != nil {
return err
}
if file, err = cmd.Flags().GetString(cmdFlagBugReport); err != nil {
return err
}
if versions, err = cmd.Flags().GetInt(cmdFlagVersions); err != nil {
return err
}
if tags, err = getGitTags(cwd); err != nil {
return err
}
latest := tags[0]
latestParts := strings.Split(latest, ".")
if len(latestParts) < 2 {
return fmt.Errorf("error extracting latest minor version from tag: %s does not appear to be a semver", latest)
}
if latestMinor, err = strconv.Atoi(latestParts[1]); err != nil {
return fmt.Errorf("error extracting latest minor version from tag: %w", err)
}
//nolint:prealloc
var (
tagsRecent []string
parts []string
minor int
)
for _, tag := range tags {
if parts = strings.Split(tag, "."); len(parts) < 2 {
return fmt.Errorf("error extracting minor version from tag: %s does not appear to be a semver", tag)
}
if minor, err = strconv.Atoi(parts[1]); err != nil {
return fmt.Errorf("error extracting minor version from tag: %w", err)
}
if minor < latestMinor-versions {
break
}
tagsRecent = append(tagsRecent, tag)
}
var (
f *os.File
)
fullPath := filepath.Join(dirRoot, file)
if f, err = os.Create(fullPath); err != nil {
return fmt.Errorf("failed to create file '%s': %w", fullPath, err)
}
data := &tmplIssueTemplateData{
Labels: []string{labelTypeBugUnconfirmed.String(), labelStatusNeedsTriage.String(), labelPriorityNormal.String()},
Versions: tagsRecent,
Proxies: []string{"Caddy", "Traefik", "Envoy", "Istio", "NGINX", "SWAG", "NGINX Proxy Manager", "HAProxy"},
}
if err = tmplGitHubIssueTemplateBug.Execute(f, data); err != nil {
return err
}
return nil
}
func getGitTags(cwd string) (tags []string, err error) {
var (
args []string
tagsOutput []byte
)
if len(cwd) != 0 {
args = append(args, "-C", cwd)
}
args = append(args, "tag", "--sort=-creatordate")
cmd := exec.Command("git", args...)
if tagsOutput, err = cmd.Output(); err != nil {
return nil, err
}
return strings.Split(string(tagsOutput), "\n"), nil
}

View File

@ -0,0 +1,215 @@
package main
import (
"encoding/json"
"fmt"
"io/fs"
"os"
"path/filepath"
"sort"
"strings"
"github.com/spf13/cobra"
"golang.org/x/text/language"
"golang.org/x/text/language/display"
"github.com/authelia/authelia/v4/internal/utils"
)
func newLocalesCmd() *cobra.Command {
cmd := &cobra.Command{
Use: cmdUseLocales,
Short: "Generate locales files",
RunE: localesRunE,
DisableAutoGenTag: true,
}
return cmd
}
func localesRunE(cmd *cobra.Command, args []string) (err error) {
var (
root, pathLocales string
pathWebI18NIndex, pathDocsDataLanguages string
)
if root, err = cmd.Flags().GetString(cmdFlagRoot); err != nil {
return err
}
if pathLocales, err = cmd.Flags().GetString(cmdFlagDirLocales); err != nil {
return err
}
if pathWebI18NIndex, err = cmd.Flags().GetString(cmdFlagFileWebI18N); err != nil {
return err
}
if pathDocsDataLanguages, err = getPFlagPath(cmd.Flags(), cmdFlagRoot, cmdFlagDocs, cmdFlagDocsData, cmdFlagDocsDataLanguages); err != nil {
return err
}
data, err := getLanguages(filepath.Join(root, pathLocales))
if err != nil {
return err
}
fullPathWebI18NIndex := filepath.Join(root, pathWebI18NIndex)
var (
f *os.File
dataJSON []byte
)
if f, err = os.Create(fullPathWebI18NIndex); err != nil {
return fmt.Errorf("failed to create file '%s': %w", fullPathWebI18NIndex, err)
}
if err = tmplWebI18NIndex.Execute(f, data); err != nil {
return err
}
if dataJSON, err = json.Marshal(data); err != nil {
return err
}
fullPathDocsDataLanguages := filepath.Join(root, pathDocsDataLanguages)
if err = os.WriteFile(fullPathDocsDataLanguages, dataJSON, 0600); err != nil {
return fmt.Errorf("failed to write file '%s': %w", fullPathDocsDataLanguages, err)
}
return nil
}
//nolint:gocyclo
func getLanguages(dir string) (languages *Languages, err error) {
//nolint:prealloc
var locales []string
languages = &Languages{
Defaults: DefaultsLanguages{
Namespace: localeNamespaceDefault,
},
}
var defaultTag language.Tag
if defaultTag, err = language.Parse(localeDefault); err != nil {
return nil, fmt.Errorf("failed to parse default language: %w", err)
}
languages.Defaults.Language = Language{
Display: display.English.Tags().Name(defaultTag),
Locale: localeDefault,
}
if err = filepath.Walk(dir, func(path string, info fs.FileInfo, errWalk error) (err error) {
if errWalk != nil {
return errWalk
}
nameLower := strings.ToLower(info.Name())
ext := filepath.Ext(nameLower)
ns := strings.Replace(nameLower, ext, "", 1)
if ext != ".json" {
return nil
}
if !utils.IsStringInSlice(ns, languages.Namespaces) {
languages.Namespaces = append(languages.Namespaces, ns)
}
fdir, _ := filepath.Split(path)
locale := filepath.Base(fdir)
if utils.IsStringInSlice(locale, locales) {
for i, l := range languages.Languages {
if l.Locale == locale {
if utils.IsStringInSlice(ns, languages.Languages[i].Namespaces) {
break
}
languages.Languages[i].Namespaces = append(languages.Languages[i].Namespaces, ns)
break
}
}
return nil
}
var localeReal string
parts := strings.SplitN(locale, "-", 2)
if len(parts) == 2 && strings.EqualFold(parts[0], parts[1]) {
localeReal = parts[0]
} else {
localeReal = locale
}
var tag language.Tag
if tag, err = language.Parse(localeReal); err != nil {
return fmt.Errorf("failed to parse language '%s': %w", localeReal, err)
}
l := Language{
Display: display.English.Tags().Name(tag),
Locale: localeReal,
Namespaces: []string{ns},
Fallbacks: []string{languages.Defaults.Language.Locale},
Tag: tag,
}
languages.Languages = append(languages.Languages, l)
locales = append(locales, l.Locale)
return nil
}); err != nil {
return nil, err
}
var langs []Language //nolint:prealloc
for i, lang := range languages.Languages {
p := lang.Tag.Parent()
if p.String() == "und" || strings.Contains(p.String(), "-") {
continue
}
if utils.IsStringInSlice(p.String(), locales) {
continue
}
if p.String() != lang.Locale {
lang.Fallbacks = append([]string{p.String()}, lang.Fallbacks...)
}
languages.Languages[i] = lang
l := Language{
Display: display.English.Tags().Name(p),
Locale: p.String(),
Namespaces: lang.Namespaces,
Fallbacks: []string{languages.Defaults.Language.Locale},
Tag: p,
}
langs = append(langs, l)
locales = append(locales, l.Locale)
}
languages.Languages = append(languages.Languages, langs...)
sort.Slice(languages.Languages, func(i, j int) bool {
return languages.Languages[i].Locale == localeDefault || languages.Languages[i].Locale < languages.Languages[j].Locale
})
return languages, nil
}

View File

@ -0,0 +1,128 @@
package main
import (
"sort"
"strings"
"github.com/spf13/cobra"
"github.com/authelia/authelia/v4/internal/utils"
)
var rootCmd *cobra.Command
func init() {
rootCmd = newRootCmd()
}
func newRootCmd() *cobra.Command {
cmd := &cobra.Command{
Use: cmdUseRoot,
Short: "Authelia's generator tooling",
RunE: rootSubCommandsRunE,
DisableAutoGenTag: true,
}
cmd.PersistentFlags().StringP(cmdFlagCwd, "C", "", "Sets the CWD for git commands")
cmd.PersistentFlags().StringP(cmdFlagRoot, "d", dirCurrent, "The repository root")
cmd.PersistentFlags().StringSliceP(cmdFlagExclude, "X", nil, "Sets the names of excluded generators")
cmd.PersistentFlags().String(cmdFlagFeatureRequest, fileGitHubIssueTemplateFR, "Sets the path of the feature request issue template file")
cmd.PersistentFlags().String(cmdFlagBugReport, fileGitHubIssueTemplateBR, "Sets the path of the bug report issue template file")
cmd.PersistentFlags().Int(cmdFlagVersions, 5, "the maximum number of minor versions to list in output templates")
cmd.PersistentFlags().String(cmdFlagDirLocales, dirLocales, "The locales directory in relation to the root")
cmd.PersistentFlags().String(cmdFlagFileWebI18N, fileWebI18NIndex, "The i18n typescript configuration file in relation to the root")
cmd.PersistentFlags().String(cmdFlagDocsDataLanguages, fileDocsDataLanguages, "The languages docs data file in relation to the docs data folder")
cmd.PersistentFlags().String(cmdFlagDocsDataMisc, fileDocsDataMisc, "The misc docs data file in relation to the docs data folder")
cmd.PersistentFlags().String(cmdFlagDocsCLIReference, dirDocsCLIReference, "The directory to store the markdown in")
cmd.PersistentFlags().String(cmdFlagDocs, dirDocs, "The directory with the docs")
cmd.PersistentFlags().String(cmdFlagDocsContent, dirDocsContent, "The directory with the docs content")
cmd.PersistentFlags().String(cmdFlagDocsData, dirDocsData, "The directory with the docs data")
cmd.PersistentFlags().String(cmdFlagFileConfigKeys, fileCodeConfigKeys, "Sets the path of the keys file")
cmd.PersistentFlags().String(cmdFlagDocsDataKeys, fileDocsDataConfigKeys, "Sets the path of the docs keys file")
cmd.PersistentFlags().String(cmdFlagPackageConfigKeys, pkgConfigSchema, "Sets the package name of the keys file")
cmd.PersistentFlags().String(cmdFlagFileScriptsGen, fileScriptsGen, "Sets the path of the authelia-scripts gen file")
cmd.PersistentFlags().String(cmdFlagFileServerGenerated, fileServerGenerated, "Sets the path of the server generated file")
cmd.PersistentFlags().String(cmdFlagPackageScriptsGen, pkgScriptsGen, "Sets the package name of the authelia-scripts gen file")
cmd.PersistentFlags().String(cmdFlagFileConfigCommitLint, fileCICommitLintConfig, "The commit lint javascript configuration file in relation to the root")
cmd.PersistentFlags().String(cmdFlagFileDocsCommitMsgGuidelines, fileDocsCommitMessageGuidelines, "The commit message guidelines documentation file in relation to the root")
cmd.AddCommand(newCodeCmd(), newDocsCmd(), newGitHubCmd(), newLocalesCmd(), newCommitLintCmd())
return cmd
}
func rootSubCommandsRunE(cmd *cobra.Command, args []string) (err error) {
var exclude []string
if exclude, err = cmd.Flags().GetStringSlice(cmdFlagExclude); err != nil {
return err
}
subCmds := cmd.Commands()
switch cmd.Use {
case cmdUseRoot:
sort.Slice(subCmds, func(i, j int) bool {
switch subCmds[j].Use {
case cmdUseDocs:
// Ensure `docs` subCmd is last.
return true
default:
return subCmds[i].Use < subCmds[j].Use
}
})
case cmdUseDocs:
sort.Slice(subCmds, func(i, j int) bool {
switch subCmds[j].Use {
case cmdUseDocsDate:
// Ensure `date` subCmd is last.
return true
default:
return subCmds[i].Use < subCmds[j].Use
}
})
default:
sort.Slice(subCmds, func(i, j int) bool {
return subCmds[i].Use < subCmds[j].Use
})
}
for _, subCmd := range subCmds {
if subCmd.Use == cmdUseCompletion || strings.HasPrefix(subCmd.Use, "help ") || utils.IsStringSliceContainsAny([]string{resolveCmdName(subCmd), subCmd.Use}, exclude) {
continue
}
rootCmd.SetArgs(rootCmdGetArgs(subCmd, args))
if err = rootCmd.Execute(); err != nil {
return err
}
}
return nil
}
func resolveCmdName(cmd *cobra.Command) string {
parent := cmd.Parent()
if parent != nil && parent.Use != cmd.Use && parent.Use != cmdUseRoot {
return resolveCmdName(parent) + "." + cmd.Use
}
return cmd.Use
}
func rootCmdGetArgs(cmd *cobra.Command, args []string) []string {
for {
if cmd == rootCmd {
break
}
args = append([]string{cmd.Use}, args...)
cmd = cmd.Parent()
}
return args
}

View File

@ -1,7 +1,113 @@
package main
const (
dateFmtRFC2822 = "Mon, _2 Jan 2006 15:04:05 -0700"
dateFmtYAML = "2006-01-02T15:04:05-07:00"
frontmatterDelimiterLine = "---"
dirCurrent = "./"
dirLocales = "internal/server/locales"
subPathCmd = "cmd"
subPathInternal = "internal"
fileCICommitLintConfig = "web/.commitlintrc.js"
fileWebI18NIndex = "web/src/i18n/index.ts"
fileDocsCommitMessageGuidelines = "docs/content/en/contributing/guidelines/commit-message.md"
fileCodeConfigKeys = "internal/configuration/schema/keys.go"
fileServerGenerated = "internal/server/gen.go"
fileScriptsGen = "cmd/authelia-scripts/cmd/gen.go"
dirDocs = "docs"
dirDocsContent = "content"
dirDocsData = "data"
dirDocsCLIReference = "en/reference/cli"
fileDocsDataLanguages = "languages.json"
fileDocsDataMisc = "misc.json"
fileDocsDataConfigKeys = "configkeys.json"
fileGitHubIssueTemplateFR = ".github/ISSUE_TEMPLATE/feature-request.yml"
fileGitHubIssueTemplateBR = ".github/ISSUE_TEMPLATE/bug-report.yml"
)
const (
dateFmtRFC2822 = "Mon, _2 Jan 2006 15:04:05 -0700"
dateFmtYAML = "2006-01-02T15:04:05-07:00"
)
const (
delimiterLineFrontMatter = "---"
localeDefault = "en"
localeNamespaceDefault = "portal"
)
const (
pkgConfigSchema = "schema"
pkgScriptsGen = "cmd"
)
const (
cmdUseRoot = "authelia-gen"
cmdUseCompletion = "completion"
cmdUseDocs = "docs"
cmdUseDocsDate = "date"
cmdUseDocsCLI = "cli"
cmdUseDocsData = "data"
cmdUseDocsDataMisc = "misc"
cmdUseGitHub = "github"
cmdUseGitHubIssueTemplates = "issue-templates"
cmdUseGitHubIssueTemplatesFR = "feature-request"
cmdUseGitHubIssueTemplatesBR = "bug-report"
cmdUseLocales = "locales"
cmdUseCommitLint = "commit-lint"
cmdUseCode = "code"
cmdUseCodeScripts = "scripts"
cmdUseKeys = "keys"
cmdUseServer = "server"
)
const (
cmdFlagRoot = "dir.root"
cmdFlagExclude = "exclude"
cmdFlagVersions = "versions"
cmdFlagDirLocales = "dir.locales"
cmdFlagDocsCLIReference = "dir.docs.cli-reference"
cmdFlagDocsContent = "dir.docs.content"
cmdFlagDocsData = "dir.docs.data"
cmdFlagDocs = "dir.docs"
cmdFlagDocsDataLanguages = "file.docs.data.languages"
cmdFlagDocsDataMisc = "file.docs.data.misc"
cmdFlagDocsDataKeys = "file.docs.data.keys"
cmdFlagCwd = "cwd"
cmdFlagFileConfigKeys = "file.configuration-keys"
cmdFlagFileScriptsGen = "file.scripts.gen"
cmdFlagFileServerGenerated = "file.server.generated"
cmdFlagFileConfigCommitLint = "file.commit-lint-config"
cmdFlagFileDocsCommitMsgGuidelines = "file.docs-commit-msg-guidelines"
cmdFlagFileWebI18N = "file.web-i18n"
cmdFlagFeatureRequest = "file.feature-request"
cmdFlagBugReport = "file.bug-report"
cmdFlagPackageConfigKeys = "package.configuration.keys"
cmdFlagPackageScriptsGen = "package.scripts.gen"
)
const (
codeCSPProductionDefaultSrc = "'self'"
codeCSPDevelopmentDefaultSrc = "'self' 'unsafe-eval'"
codeCSPNonce = "${NONCE}"
)
var (
codeCSPValuesCommon = []CSPValue{
{Name: "default-src", Value: ""},
{Name: "frame-src", Value: "'none'"},
{Name: "object-src", Value: "'none'"},
{Name: "style-src", Value: "'self' 'nonce-%s'"},
{Name: "frame-ancestors", Value: "'none'"},
{Name: "base-uri", Value: "'self'"},
}
codeCSPValuesProduction = []CSPValue{}
codeCSPValuesDevelopment = []CSPValue{}
)

View File

@ -0,0 +1,48 @@
package main
import (
"fmt"
"path/filepath"
"strings"
"github.com/spf13/pflag"
)
func getPFlagPath(flags *pflag.FlagSet, flagNames ...string) (fullPath string, err error) {
if len(flagNames) == 0 {
return "", fmt.Errorf("no flag names")
}
var p string
for i, flagName := range flagNames {
if p, err = flags.GetString(flagName); err != nil {
return "", fmt.Errorf("failed to lookup flag '%s': %w", flagName, err)
}
if i == 0 {
fullPath = p
} else {
fullPath = filepath.Join(fullPath, p)
}
}
return fullPath, nil
}
func buildCSP(defaultSrc string, ruleSets ...[]CSPValue) string {
var rules []string
for _, ruleSet := range ruleSets {
for _, rule := range ruleSet {
switch rule.Name {
case "default-src":
rules = append(rules, fmt.Sprintf("%s %s", rule.Name, defaultSrc))
default:
rules = append(rules, fmt.Sprintf("%s %s", rule.Name, rule.Value))
}
}
}
return strings.Join(rules, "; ")
}

View File

@ -1,29 +1,7 @@
package main
import (
"embed"
"github.com/spf13/cobra"
)
//go:embed templates/*
var templatesFS embed.FS
func main() {
if err := newRootCmd().Execute(); err != nil {
if err := rootCmd.Execute(); err != nil {
panic(err)
}
}
func newRootCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "authelia-gen",
Short: "Authelia's generator tooling",
DisableAutoGenTag: true,
}
cmd.AddCommand(newAllCmd(), newCodeCmd(), newDocsCmd())
return cmd
}

View File

@ -0,0 +1,70 @@
package main
import (
"embed"
"fmt"
"strings"
"text/template"
)
//go:embed templates/*
var templatesFS embed.FS
var (
funcMap = template.FuncMap{
"stringsContains": strings.Contains,
"join": strings.Join,
"joinX": fmJoinX,
}
tmplCodeConfigurationSchemaKeys = template.Must(newTMPL("internal_configuration_schema_keys.go"))
tmplGitHubIssueTemplateBug = template.Must(newTMPL("github_issue_template_bug_report.yml"))
tmplIssueTemplateFeature = template.Must(newTMPL("github_issue_template_feature.yml"))
tmplWebI18NIndex = template.Must(newTMPL("web_i18n_index.ts"))
tmplDotCommitLintRC = template.Must(newTMPL("dot_commitlintrc.js"))
tmplDocsCommitMessageGuidelines = template.Must(newTMPL("docs-contributing-development-commitmsg.md"))
tmplScriptsGen = template.Must(newTMPL("cmd-authelia-scripts-gen.go"))
tmplServer = template.Must(newTMPL("server_gen.go"))
)
func fmJoinX(elems []string, sep string, n int, p string) string {
buf := strings.Builder{}
c := 0
e := len(elems) - 1
for i := 0; i <= e; i++ {
if c+len(elems[i])+1 > n {
c = 0
buf.WriteString(p)
}
c += len(elems[i]) + 1
buf.WriteString(elems[i])
if i < e {
buf.WriteString(sep)
}
}
return buf.String()
}
func newTMPL(name string) (tmpl *template.Template, err error) {
return template.New(name).Funcs(funcMap).Parse(mustLoadTmplFS(name))
}
func mustLoadTmplFS(tmpl string) string {
var (
content []byte
err error
)
if content, err = templatesFS.ReadFile(fmt.Sprintf("templates/%s.tmpl", tmpl)); err != nil {
panic(err)
}
return string(content)
}

View File

@ -0,0 +1,11 @@
// Code generated by go generate. DO NOT EDIT.
//
// Run the following command to generate this file:
// go run ./cmd/authelia-gen code scripts
//
package {{ .Package }}
const (
versionSwaggerUI = "{{ .VersionSwaggerUI }}"
)

View File

@ -0,0 +1,139 @@
---
title: "Commit Message"
description: "Authelia Development Commit Message Guidelines"
lead: "This section covers the git commit message guidelines we use for development."
date: 2021-01-30T19:29:07+11:00
draft: false
images: []
menu:
contributing:
parent: "guidelines"
weight: 320
toc: true
aliases:
- /docs/contributing/commitmsg-guidelines.html
- /contributing/development/guidelines-commit-message/
---
The reasons for these conventions are as follows:
* simple navigation though git history
* easier to read git history
## Commit Message Format
Each commit message consists of a __header__, a __body__, and a __footer__.
```bash
<header>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```
The `header` is mandatory and must conform to the [Commit Message Header](#commit-message-header) format. The header
cannot be longer than 72 characters.
The `body` is mandatory for all commits except for those of type "docs". When the body is present it must be at least 20
characters long and must conform to the [Commit Message Body](#commit-message-body) format.
The `footer` is optional. The [Commit Message Footer](#commit-message-footer) format describes what the footer is used
for, and the structure it must have.
### Commit Message Header
```text
<type>(<scope>): <summary>
│ │ │
│ │ └─⫸ Summary in present tense. Not capitalized. No period at the end.
│ │
│ └─⫸ Commit Scope: {{ joinX .Scopes.All "|" 70 "\n │ " }}
└─⫸ Commit Type: {{ join .Types.List "|" }}
```
The `<type>` and `<summary>` fields are mandatory, the `(<scope>)` field is optional.
#### Allowed type values:
{{ range .Types.Details }}
* __{{ .Name }}__ {{ .Description }}
{{- if .Scopes }}
(example scopes: {{ join .Scopes ", " }})
{{- end }}
{{- end }}
#### Allowed scope values:
The scope should be the name of the package affected (as perceived by the person reading the changelog generated from
commit messages).
{{ range .Scopes.Packages }}
* {{ . }}
{{- end }}
There are currently a few exceptions to the "use package name" rule:
{{ range .Scopes.Extra }}
* `{{ .Name }}`: {{ .Description }}
{{- end }}
* none/empty string: useful for `test`, `refactor` and changes that are done across multiple packages
(e.g. `test: add missing unit tests`) and for docs changes that are not related to a specific package
(e.g. `docs: fix typo in tutorial`).
#### Summary
Use the summary field to provide a succinct description of the change:
* use the imperative, present tense: "change" not "changed" nor "changes"
* don't capitalize the first letter
* no dot (.) at the end
### Commit Message Body
Just as in the summary, use the imperative, present tense: "fix" not "fixed" nor "fixes".
Explain the motivation for the change in the commit message body. This commit message should explain *why* you are
making the change. You can include a comparison of the previous behavior with the new behavior in order to illustrate
the impact of the change.
### Commit Message Footer
The footer can contain information about breaking changes and is also the place to reference GitHub issues and other PRs
that this commit closes or is related to.
```text
BREAKING CHANGE: <breaking change summary>
<BLANK LINE>
<breaking change description + migration instructions>
<BLANK LINE>
<BLANK LINE>
Fixes #<issue number>
```
Breaking Change section should start with the phrase "BREAKING CHANGE: " followed by a summary of the breaking change, a
blank line, and a detailed description of the breaking change that also includes migration instructions.
### Revert Commits
If the commit reverts a previous commit, it should begin with `revert:`, followed by the header of the reverted commit.
The content of the commit message body should contain:
* information about the SHA of the commit being reverted in the following format: `This reverts commit <SHA>`,
* a clear description of the reason for reverting the commit message.
## Commit Message Examples
```bash
fix(logging): disabled colored logging outputs when file is specified
In some scenarios if a user has a log_file_path specified and a TTY seems to be detected this causes terminal coloring outputs to be written to the file.
This in turn will cause issues when attempting to utilise the log with the provided fail2ban regexes.
We now override any TTY detection/logging treatments and disable coloring/removal of the timestamp when a user is utilising the text based logger to a file.
Fixes #1480.
```
This document is based on [AngularJS Git Commit Message Format].
[AngularJS Git Commit Message Format]: https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit

View File

@ -0,0 +1,25 @@
module.exports = {
extends: ["@commitlint/config-conventional"],
rules: {
"body-max-line-length": [2, "always", "Infinity"],
"body-min-length": [2, "always", 20],
"header-case": [2, "always", "lower-case"],
"header-max-length": [2, "always", 72],
"type-enum": [
2,
"always",
["{{ join .Types.List "\", \"" }}"],
],
"scope-enum": [
2,
"always",
[
{{- range .Scopes.All }}
"{{ . }}",
{{- end }}
],
],
},
defaultIgnores: true,
helpUrl: "https://www.authelia.com/contributing/guidelines/commit-message/",
};

View File

@ -0,0 +1,109 @@
---
name: Bug Report
description: Report a bug
labels:
{{- range .Labels }}
- {{ . }}
{{- end }}
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report. If you are unsure if this is actually a bug we generally recommend creating a [Question and Answer Discussion](https://github.com/authelia/authelia/discussions/new?category=q-a) first.
Please review the following requirements before submitting this issue type:
1. Please ensure you do not report security vulnerabilities via this method. See our [Security Policy](https://www.authelia.com/security-policy).
2. Please try to give as much information as possible for us to be able to reproduce the issue and provide a quick fix.
3. Please ensure an issue does not already exist for this potential bug.
4. Please only provide specific versions. Latest is not a version.
5. Please read the [Troubleshooting Sanitization](https://www.authelia.com/r/sanitize) reference guide if you plan on removing or adjusting any values for the logs or configuration files.
6. Please consider including a [HTTP Archive File](https://www.authelia.com/r/har) if you're having redirection issues.
- type: dropdown
id: version
attributes:
label: Version
description: What version(s) of Authelia can you reproduce this bug on?
multiple: true
options:
{{- range .Versions }}
- {{ . }}
{{- end }}
validations:
required: true
- type: dropdown
id: deployment
attributes:
label: Deployment Method
description: How are you deploying Authelia?
options:
- Docker
- Kubernetes
- Bare-metal
- Other
validations:
required: true
- type: dropdown
id: proxy
attributes:
label: Reverse Proxy
description: What reverse proxy are you using?
options:
{{- range .Proxies }}
- {{ . }}
{{- end }}
validations:
required: true
- type: input
id: proxy-version
attributes:
label: Reverse Proxy Version
description: What is the version of your reverse proxy?
placeholder: x.x.x
validations:
required: false
- type: textarea
id: description
attributes:
label: Description
description: Describe the bug
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: Reproduction
description: Describe how we can reproduce this issue
validations:
required: true
- type: textarea
id: expectations
attributes:
label: Expectations
description: Describe the desired or expected results
validations:
required: false
- type: textarea
id: logs
attributes:
label: Logs
description: Provide the logs (the template will automatically put this content in a code block)
render: shell
validations:
required: false
- type: textarea
id: configuration
attributes:
label: Configuration
description: Provide the Authelia configuration file (the template will automatically put this content in a code block)
render: yaml
validations:
required: false
- type: textarea
id: documentation
attributes:
label: Documentation
description: Provide any relevant specification or other documentation if applicable
validations:
required: false
...

View File

@ -0,0 +1,47 @@
---
name: Feature Request
description: Submit a Feature Request
labels:
{{- range .Labels }}
- {{ . }}
{{- end }}
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this feature request. A feature request is created as issue for the purpose of tracking the design and implementation of a feature.
Please review the following requirements before submitting this issue type:
1. Ensure there are no other similar feature requests.
2. Make sure you've checked the [Documentation](https://www.authelia.com) doesn't clearly document the features existence already.
3. Consider creating an [Idea Discussion](https://github.com/authelia/authelia/discussions/new?category=ideas) which can be voted on instead if one doesn't exist.
- type: textarea
id: description
attributes:
label: Description
description: Describe the feature
validations:
required: true
- type: textarea
id: use-case
attributes:
label: Use Case
description: Provide a use case
validations:
required: true
- type: textarea
id: details
attributes:
label: Details
description: Describe the feature in detail
validations:
required: false
- type: textarea
id: documentation
attributes:
label: Documentation
description: Provide any relevant specification or other documentation if applicable
validations:
required: false
...

View File

@ -0,0 +1,13 @@
// Code generated by go generate. DO NOT EDIT.
//
// Run the following command to generate this file:
// go run ./cmd/authelia-gen code server
//
package server
const (
placeholderCSPNonce = "{{ .PlaceholderNONCE }}"
tmplCSPDefault = "{{ .TemplateDefault }}"
tmplCSPDevelopment = "{{ .TemplateDevelopment }}"
)

View File

@ -0,0 +1,57 @@
// Code generated by go generate. DO NOT EDIT.
//
// Run the following command to generate this file:
// go run ./cmd/authelia-gen locales
//
import i18n from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import Backend from "i18next-http-backend";
import { initReactI18next } from "react-i18next";
import LocalStorageCustomDetector from "@i18n/detectors/localStorageCustom";
import { getBasePath } from "@utils/BasePath";
const basePath = getBasePath();
const CustomLanguageDetector = new LanguageDetector();
CustomLanguageDetector.addDetector(LocalStorageCustomDetector);
i18n.use(Backend)
.use(CustomLanguageDetector)
.use(initReactI18next)
.init({
detection: {
order: ["querystring", "localStorageCustom", "navigator"],
lookupQuerystring: "lng",
lookupLocalStorage: "lng",
},
backend: {
loadPath: basePath + "/locales/{{"{{lng}}"}}/{{"{{ns}}"}}.json",
},
load: "all",
ns: [{{ range $i, $value := .Namespaces }}{{ if eq $i 0 }}"{{ $value }}"{{ else }}, "{{ $value }}"{{ end }}{{ end }}],
defaultNS: "{{ .Defaults.Namespace }}",
fallbackLng: {
default: ["{{ .Defaults.Language.Locale }}"],
{{- range .Languages }}
{{- if and (not (eq .Locale "en")) (not (eq (len .Fallbacks) 0)) }}
{{ if stringsContains .Locale "-" }}"{{ .Locale }}"{{ else }}{{ .Locale }}{{ end }}: [{{ range $i, $value := .Fallbacks }}{{ if eq $i 0 }}"{{ $value }}"{{ else }}, "{{ $value }}"{{ end }}{{ end }}],
{{- end }}
{{- end }}
},
supportedLngs: [
{{- range $i, $value := .Languages }}
"{{ $value.Locale }}",
{{- end }}
],
lowerCaseLng: false,
nonExplicitSupportedLngs: true,
interpolation: {
escapeValue: false,
},
debug: false,
});
export default i18n;

View File

@ -0,0 +1,145 @@
package main
import (
"fmt"
"strings"
"time"
"golang.org/x/text/language"
)
type tmplIssueTemplateData struct {
Labels []string
Versions []string
Proxies []string
}
type tmplConfigurationKeysData struct {
Timestamp time.Time
Keys []string
Package string
}
type tmplScriptsGEnData struct {
Package string
VersionSwaggerUI string
}
// GitHubTagsJSON represents the JSON struct for the GitHub Tags API.
type GitHubTagsJSON struct {
Name string `json:"name"`
}
// DocsDataMisc represents the docs misc data schema.
type DocsDataMisc struct {
CSP TemplateCSP `json:"csp"`
}
// TemplateCSP represents the CSP template vars.
type TemplateCSP struct {
TemplateDefault string `json:"default"`
TemplateDevelopment string `json:"development"`
PlaceholderNONCE string `json:"nonce"`
}
// ConfigurationKey is the docs json model for the Authelia configuration keys.
type ConfigurationKey struct {
Path string `json:"path"`
Secret bool `json:"secret"`
Env string `json:"env"`
}
// Languages is the docs json model for the Authelia languages configuration.
type Languages struct {
Defaults DefaultsLanguages `json:"defaults"`
Namespaces []string `json:"namespaces"`
Languages []Language `json:"languages"`
}
type DefaultsLanguages struct {
Language Language `json:"language"`
Namespace string `json:"namespace"`
}
// Language is the docs json model for a language.
type Language struct {
Display string `json:"display"`
Locale string `json:"locale"`
Namespaces []string `json:"namespaces,omitempty"`
Fallbacks []string `json:"fallbacks,omitempty"`
Tag language.Tag `json:"-"`
}
const (
labelAreaPrefixPriority = "priority"
labelAreaPrefixType = "type"
labelAreaPrefixStatus = "status"
)
type labelPriority int
//nolint:deadcode // Kept for future use.
const (
labelPriorityCritical labelPriority = iota
labelPriorityHigh
labelPriorityMedium
labelPriorityNormal
labelPriorityLow
)
var labelPriorityDescriptions = [...]string{
"Critical",
"High",
"Medium",
"Normal",
"Low",
}
func (p labelPriority) String() string {
return fmt.Sprintf("%s/%d/%s", labelAreaPrefixPriority, p+1, strings.ToLower(labelPriorityDescriptions[p]))
}
func (p labelPriority) Description() string {
return labelPriorityDescriptions[p]
}
type labelStatus int
const (
labelStatusNeedsDesign labelStatus = iota
labelStatusNeedsTriage
)
var labelStatusDescriptions = [...]string{
"needs-design",
"needs-triage",
}
func (s labelStatus) String() string {
return fmt.Sprintf("%s/%s", labelAreaPrefixStatus, labelStatusDescriptions[s])
}
type labelType int
//nolint:deadcode // Kept for future use.
const (
labelTypeFeature labelType = iota
labelTypeBugUnconfirmed
labelTypeBug
)
var labelTypeDescriptions = [...]string{
"feature",
"bug/unconfirmed",
"bug",
}
func (t labelType) String() string {
return fmt.Sprintf("%s/%s", labelAreaPrefixType, labelTypeDescriptions[t])
}
type CSPValue struct {
Name string
Value string
}

View File

@ -168,8 +168,8 @@ func pnpmInstall() {
shell(fmt.Sprintf("cd %s/web && pnpm install", cwd))
}
func bootstrapPrintln(args ...interface{}) {
a := make([]interface{}, 0)
func bootstrapPrintln(args ...any) {
a := make([]any, 0)
a = append(a, "[BOOTSTRAP]")
a = append(a, args...)
fmt.Println(a...)

View File

@ -40,7 +40,7 @@ func cmdBuildRun(cobraCmd *cobra.Command, args []string) {
cmdCleanRun(cobraCmd, args)
xflags, err := getXFlags(branch, os.Getenv("BUILDKITE_BUILD_NUMBER"), "")
buildMetaData, err := getBuild(branch, os.Getenv("BUILDKITE_BUILD_NUMBER"), "")
if err != nil {
log.Fatal(err)
}
@ -62,11 +62,11 @@ func cmdBuildRun(cobraCmd *cobra.Command, args []string) {
if buildkite {
log.Info("Building Authelia Go binaries with gox...")
buildAutheliaBinaryGOX(xflags)
buildAutheliaBinaryGOX(buildMetaData.XFlags())
} else {
log.Info("Building Authelia Go binary...")
buildAutheliaBinaryGO(xflags)
buildAutheliaBinaryGO(buildMetaData.XFlags())
}
cleanAssets()
@ -146,8 +146,7 @@ func buildFrontend(branch string) {
}
func buildSwagger() {
swaggerVer := "4.13.0"
cmd := utils.CommandWithStdout("bash", "-c", "wget -q https://github.com/swagger-api/swagger-ui/archive/v"+swaggerVer+".tar.gz -O ./v"+swaggerVer+".tar.gz")
cmd := utils.CommandWithStdout("bash", "-c", "wget -q https://github.com/swagger-api/swagger-ui/archive/v"+versionSwaggerUI+".tar.gz -O ./v"+versionSwaggerUI+".tar.gz")
err := cmd.Run()
if err != nil {
@ -161,14 +160,14 @@ func buildSwagger() {
log.Fatal(err)
}
cmd = utils.CommandWithStdout("tar", "-C", "internal/server/public_html/api", "--exclude=index.html", "--strip-components=2", "-xf", "v"+swaggerVer+".tar.gz", "swagger-ui-"+swaggerVer+"/dist")
cmd = utils.CommandWithStdout("tar", "-C", "internal/server/public_html/api", "--exclude=index.html", "--strip-components=2", "-xf", "v"+versionSwaggerUI+".tar.gz", "swagger-ui-"+versionSwaggerUI+"/dist")
err = cmd.Run()
if err != nil {
log.Fatal(err)
}
cmd = utils.CommandWithStdout("rm", "./v"+swaggerVer+".tar.gz")
cmd = utils.CommandWithStdout("rm", "./v"+versionSwaggerUI+".tar.gz")
err = cmd.Run()
if err != nil {

View File

@ -13,15 +13,17 @@ import (
var container string
var containers = []string{"dev", "coverage"}
var defaultContainer = "dev"
var ciBranch = os.Getenv("BUILDKITE_BRANCH")
var ciPullRequest = os.Getenv("BUILDKITE_PULL_REQUEST")
var ciTag = os.Getenv("BUILDKITE_TAG")
var dockerTags = regexp.MustCompile(`v(?P<Patch>(?P<Minor>(?P<Major>\d+)\.\d+)\.\d+.*)`)
var ignoredSuffixes = regexp.MustCompile("alpha|beta")
var publicRepo = regexp.MustCompile(`.*:.*`)
var tags = dockerTags.FindStringSubmatch(ciTag)
var (
containers = []string{"dev", "coverage"}
defaultContainer = "dev"
ciBranch = os.Getenv("BUILDKITE_BRANCH")
ciPullRequest = os.Getenv("BUILDKITE_PULL_REQUEST")
ciTag = os.Getenv("BUILDKITE_TAG")
dockerTags = regexp.MustCompile(`v(?P<Patch>(?P<Minor>(?P<Major>\d+)\.\d+)\.\d+.*)`)
ignoredSuffixes = regexp.MustCompile("alpha|beta")
publicRepo = regexp.MustCompile(`.*:.*`)
tags = dockerTags.FindStringSubmatch(ciTag)
)
func newDockerCmd() (cmd *cobra.Command) {
cmd = &cobra.Command{
@ -98,15 +100,14 @@ func cmdDockerPushManifestRun(_ *cobra.Command, _ []string) {
log.Infof("Detected tags: '%s' | '%s' | '%s'", tags[1], tags[2], tags[3])
login(docker, dockerhub)
login(docker, ghcr)
deployManifest(docker, tags[1])
publishDockerReadme(docker)
if !ignoredSuffixes.MatchString(ciTag) {
deployManifest(docker, tags[2])
deployManifest(docker, tags[3])
deployManifest(docker, "latest")
publishDockerReadme(docker)
if ignoredSuffixes.MatchString(ciTag) {
deployManifest(docker, tags[1])
} else {
deployManifest(docker, tags[1], tags[2], tags[3], "latest")
}
publishDockerReadme(docker)
} else {
log.Fatal("Docker manifest will not be published, the specified tag does not conform to the standard")
}
@ -143,13 +144,12 @@ func dockerBuildOfficialImage(arch string) error {
filename := "Dockerfile"
dockerfile := fmt.Sprintf("%s.%s", filename, arch)
flags, err := getXFlags(ciBranch, os.Getenv("BUILDKITE_BUILD_NUMBER"), "")
buildMetaData, err := getBuild(ciBranch, os.Getenv("BUILDKITE_BUILD_NUMBER"), "")
if err != nil {
log.Fatal(err)
}
return docker.Build(IntermediateDockerImageName, dockerfile, ".",
strings.Join(flags, " "))
return docker.Build(IntermediateDockerImageName, dockerfile, ".", buildMetaData)
}
func login(docker *Docker, registry string) {
@ -181,13 +181,17 @@ func login(docker *Docker, registry string) {
}
}
func deployManifest(docker *Docker, tag string) {
log.Infof("Docker manifest %s:%s will be deployed on %s and %s", DockerImageName, tag, dockerhub, ghcr)
func deployManifest(docker *Docker, tag ...string) {
tags = make([]string, 0)
dockerhub := dockerhub + "/" + DockerImageName + ":" + tag
ghcr := ghcr + "/" + DockerImageName + ":" + tag
log.Infof("The following Docker manifest(s) will be deployed on %s and %s", dockerhub, ghcr)
if err := docker.Manifest(dockerhub, ghcr); err != nil {
for _, t := range tag {
log.Infof("- %s:%s", DockerImageName, t)
tags = append(tags, dockerhub+"/"+DockerImageName+":"+t, ghcr+"/"+DockerImageName+":"+t)
}
if err := docker.Manifest(tags); err != nil {
log.Fatal(err)
}
}

View File

@ -0,0 +1,11 @@
// Code generated by go generate. DO NOT EDIT.
//
// Run the following command to generate this file:
// go run ./cmd/authelia-gen code scripts
//
package cmd
const (
versionSwaggerUI = "4.15.2"
)

View File

@ -2,66 +2,63 @@ package cmd
import (
"fmt"
"strings"
"strconv"
"time"
"github.com/authelia/authelia/v4/internal/utils"
)
func getXFlags(branch, build, extra string) (flags []string, err error) {
if branch == "" {
out, _, err := utils.RunCommandAndReturnOutput("git rev-parse --abbrev-ref HEAD")
if err != nil {
return flags, fmt.Errorf("error getting branch with git rev-parse: %w", err)
func getBuild(branch, buildNumber, extra string) (b *Build, err error) {
var out string
b = &Build{
Branch: branch,
Extra: extra,
}
if buildNumber != "" {
if b.Number, err = strconv.Atoi(buildNumber); err != nil {
return nil, fmt.Errorf("error parsing provided build number: %w", err)
}
}
if b.Branch == "" {
if out, _, err = utils.RunCommandAndReturnOutput("git rev-parse --abbrev-ref HEAD"); err != nil {
return nil, fmt.Errorf("error getting branch with git rev-parse: %w", err)
}
if out == "" {
branch = "master"
b.Branch = "master"
} else {
branch = out
b.Branch = out
}
}
gitTagCommit, _, err := utils.RunCommandAndReturnOutput("git rev-list --tags --max-count=1")
if err != nil {
return flags, fmt.Errorf("error getting tag commit with git rev-list: %w", err)
var (
gitTagCommit string
)
if gitTagCommit, _, err = utils.RunCommandAndReturnOutput("git rev-list --tags --max-count=1"); err != nil {
return nil, fmt.Errorf("error getting tag commit with git rev-list: %w", err)
}
tag, _, err := utils.RunCommandAndReturnOutput(fmt.Sprintf("git describe --tags --abbrev=0 %s", gitTagCommit))
if err != nil {
return flags, fmt.Errorf("error getting tag with git describe: %w", err)
if b.Tag, _, err = utils.RunCommandAndReturnOutput(fmt.Sprintf("git describe --tags --abbrev=0 %s", gitTagCommit)); err != nil {
return nil, fmt.Errorf("error getting tag with git describe: %w", err)
}
commit, _, err := utils.RunCommandAndReturnOutput("git rev-parse HEAD")
if err != nil {
return flags, fmt.Errorf("error getting commit with git rev-parse: %w", err)
if b.Commit, _, err = utils.RunCommandAndReturnOutput("git rev-parse HEAD"); err != nil {
return nil, fmt.Errorf("error getting commit with git rev-parse: %w", err)
}
var states []string
if gitTagCommit == commit {
states = append(states, "tagged")
} else {
states = append(states, "untagged")
if gitTagCommit == b.Commit {
b.Tagged = true
}
if _, exitCode, _ := utils.RunCommandAndReturnOutput("git diff --quiet"); exitCode != 0 {
states = append(states, "dirty")
} else {
states = append(states, "clean")
if _, exitCode, _ := utils.RunCommandAndReturnOutput("git diff --quiet"); exitCode == 0 {
b.Clean = true
}
if build == "" {
build = "manual"
}
b.Date = time.Now()
return []string{
fmt.Sprintf(fmtLDFLAGSX, "BuildBranch", branch),
fmt.Sprintf(fmtLDFLAGSX, "BuildTag", tag),
fmt.Sprintf(fmtLDFLAGSX, "BuildCommit", commit),
fmt.Sprintf(fmtLDFLAGSX, "BuildDate", time.Now().Format("Mon, 02 Jan 2006 15:04:05 -0700")),
fmt.Sprintf(fmtLDFLAGSX, "BuildState", strings.Join(states, " ")),
fmt.Sprintf(fmtLDFLAGSX, "BuildExtra", extra),
fmt.Sprintf(fmtLDFLAGSX, "BuildNumber", build),
}, nil
return b, nil
}

View File

@ -1,6 +1,13 @@
package cmd
import (
"bufio"
"encoding/json"
"fmt"
"net/http"
"os"
"strings"
"github.com/authelia/authelia/v4/internal/utils"
)
@ -8,11 +15,20 @@ import (
type Docker struct{}
// Build build a docker image.
func (d *Docker) Build(tag, dockerfile, target, ldflags string) error {
return utils.CommandWithStdout(
"docker", "build", "-t", tag, "-f", dockerfile,
"--progress=plain", "--build-arg", "LDFLAGS_EXTRA="+ldflags,
target).Run()
func (d *Docker) Build(tag, dockerfile, target string, buildMetaData *Build) error {
args := []string{"build", "-t", tag, "-f", dockerfile, "--progress=plain"}
for label, value := range buildMetaData.ContainerLabels() {
if value == "" {
continue
}
args = append(args, "--label", fmt.Sprintf("%s=%s", label, value))
}
args = append(args, "--build-arg", "LDFLAGS_EXTRA="+strings.Join(buildMetaData.XFlags(), " "), target)
return utils.CommandWithStdout("docker", args...).Run()
}
// Tag tag a docker image.
@ -26,11 +42,107 @@ func (d *Docker) Login(username, password, registry string) error {
}
// Manifest push a docker manifest to dockerhub.
func (d *Docker) Manifest(tag1, tag2 string) error {
return utils.CommandWithStdout("docker", "build", "-t", tag1, "-t", tag2, "--platform", "linux/amd64,linux/arm/v7,linux/arm64", "--builder", "buildx", "--push", ".").Run()
func (d *Docker) Manifest(tags []string) error {
args := []string{"build"}
for _, tag := range tags {
args = append(args, "-t", tag)
}
annotations := ""
buildMetaData, err := getBuild(ciBranch, os.Getenv("BUILDKITE_BUILD_NUMBER"), "")
if err != nil {
return err
}
for label, value := range buildMetaData.ContainerLabels() {
if value == "" {
continue
}
annotations += fmt.Sprintf("annotation.%s=%s,", label, value)
args = append(args, "--label", fmt.Sprintf("%s=%s", label, value))
}
var baseImageTag string
from, err := getDockerfileDirective("Dockerfile", "FROM")
if err == nil {
baseImageTag = from[strings.IndexRune(from, ':')+1:]
args = append(args, "--label", "org.opencontainers.image.base.name=docker.io/library/alpine:"+baseImageTag)
}
resp, err := http.Get("https://hub.docker.com/v2/repositories/library/alpine/tags/" + baseImageTag + "/images")
if err != nil {
return err
}
defer resp.Body.Close()
images := DockerImages{}
if err = json.NewDecoder(resp.Body).Decode(&images); err != nil {
return err
}
var (
digestAMD64, digestARM, digestARM64 string
)
for _, platform := range []string{"linux/amd64", "linux/arm/v7", "linux/arm64"} {
for _, image := range images {
if !image.Match(platform) {
continue
}
switch platform {
case "linux/amd64":
digestAMD64 = image.Digest
case "linux/arm/v7":
digestARM = image.Digest
case "linux/arm64":
digestARM64 = image.Digest
}
}
}
finalArgs := make([]string, len(args))
copy(finalArgs, args)
finalArgs = append(finalArgs, "--output", "type=image,\"name="+dockerhub+"/"+DockerImageName+","+ghcr+"/"+DockerImageName+"\","+annotations+"annotation.org.opencontainers.image.base.name=docker.io/library/alpine:"+baseImageTag+",annotation[linux/amd64].org.opencontainers.image.base.digest="+digestAMD64+",annotation[linux/arm/v7].org.opencontainers.image.base.digest="+digestARM+",annotation[linux/arm64].org.opencontainers.image.base.digest="+digestARM64, "--platform", "linux/amd64,linux/arm/v7,linux/arm64", "--builder", "buildx", "--push", ".")
if err = utils.CommandWithStdout("docker", finalArgs...).Run(); err != nil {
return err
}
return nil
}
// PublishReadme push README.md to dockerhub.
func (d *Docker) PublishReadme() error {
return utils.CommandWithStdout("bash", "-c", `token=$(curl -fs --retry 3 -H "Content-Type: application/json" -X "POST" -d '{"username": "'$DOCKER_USERNAME'", "password": "'$DOCKER_PASSWORD'"}' https://hub.docker.com/v2/users/login/ | jq -r .token) && jq -n --arg msg "$(cat README.md | sed -r 's/(\<img\ src\=\")(\.\/)/\1https:\/\/github.com\/authelia\/authelia\/raw\/master\//' | sed 's/\.\//https:\/\/github.com\/authelia\/authelia\/blob\/master\//g' | sed '/start \[contributing\]/ a <a href="https://github.com/authelia/authelia/graphs/contributors"><img src="https://opencollective.com/authelia-sponsors/contributors.svg?width=890" /></a>' | sed '/Thanks goes to/,/### Backers/{/### Backers/!d}')" '{"registry":"registry-1.docker.io","full_description": $msg }' | curl -fs --retry 3 -o /dev/null -L -X "PATCH" -H "Content-Type: application/json" -H "Authorization: JWT $token" -d @- https://hub.docker.com/v2/repositories/authelia/authelia/`).Run()
}
func getDockerfileDirective(filePath, directive string) (from string, err error) {
var f *os.File
if f, err = os.Open(filePath); err != nil {
return "", err
}
defer f.Close()
s := bufio.NewScanner(f)
for s.Scan() {
data := s.Text()
if strings.HasPrefix(data, directive+" ") {
return data[5:], nil
}
}
return "", nil
}

View File

@ -1,7 +1,130 @@
package cmd
import (
"fmt"
"strconv"
"strings"
"time"
"github.com/authelia/authelia/v4/internal/utils"
)
// HostEntry represents an entry in /etc/hosts.
type HostEntry struct {
Domain string
IP string
}
// DockerImages represents some of the data from the docker images API.
type DockerImages []DockerImage
// DockerImage represents some of the data from the docker images API.
type DockerImage struct {
Architecture string `json:"architecture"`
Variant any `json:"variant"`
Digest string `json:"digest"`
OS string `json:"os"`
}
// Match returns true if this image matches the platform.
func (d DockerImage) Match(platform string) bool {
parts := []string{d.OS, d.Architecture}
if strings.Join(parts, "/") == platform {
return true
}
if d.Variant == nil {
return false
}
parts = append(parts, d.Variant.(string))
return strings.Join(parts, "/") == platform
}
// Build represents a builds metadata.
type Build struct {
Branch string
Tag string
Commit string
Tagged bool
Clean bool
Extra string
Number int
Date time.Time
}
// States returns the state tags for this Build.
func (b Build) States() []string {
var states []string
if b.Tagged {
states = append(states, "tagged")
} else {
states = append(states, "untagged")
}
if b.Clean {
states = append(states, "clean")
} else {
states = append(states, "dirty")
}
return states
}
// State returns the state tags string for this Build.
func (b Build) State() string {
return strings.Join(b.States(), " ")
}
// XFlags returns the XFlags for this Build.
func (b Build) XFlags() []string {
return []string{
fmt.Sprintf(fmtLDFLAGSX, "BuildBranch", b.Branch),
fmt.Sprintf(fmtLDFLAGSX, "BuildTag", b.Tag),
fmt.Sprintf(fmtLDFLAGSX, "BuildCommit", b.Commit),
fmt.Sprintf(fmtLDFLAGSX, "BuildDate", b.Date.Format("Mon, 02 Jan 2006 15:04:05 -0700")),
fmt.Sprintf(fmtLDFLAGSX, "BuildState", b.State()),
fmt.Sprintf(fmtLDFLAGSX, "BuildExtra", b.Extra),
fmt.Sprintf(fmtLDFLAGSX, "BuildNumber", strconv.Itoa(b.Number)),
}
}
// ContainerLabels returns the container labels for this Build.
func (b Build) ContainerLabels() (labels map[string]string) {
var version string
switch {
case b.Clean && b.Tagged:
version = utils.VersionAdv(b.Tag, b.State(), b.Commit, b.Branch, b.Extra)
case b.Clean:
version = fmt.Sprintf("%s-pre+%s.%s", b.Tag, b.Branch, b.Commit)
case b.Tagged:
version = fmt.Sprintf("%s-dirty", b.Tag)
default:
version = fmt.Sprintf("%s-dirty+%s.%s", b.Tag, b.Branch, b.Commit)
}
if strings.HasPrefix(version, "v") && len(version) > 1 {
version = version[1:]
}
labels = map[string]string{
"org.opencontainers.image.created": b.Date.Format(time.RFC3339),
"org.opencontainers.image.authors": "",
"org.opencontainers.image.url": "https://github.com/authelia/authelia/pkgs/container/authelia",
"org.opencontainers.image.documentation": "https://www.authelia.com",
"org.opencontainers.image.source": fmt.Sprintf("https://github.com/authelia/authelia/tree/%s", b.Commit),
"org.opencontainers.image.version": version,
"org.opencontainers.image.revision": b.Commit,
"org.opencontainers.image.vendor": "Authelia",
"org.opencontainers.image.licenses": "Apache-2.0",
"org.opencontainers.image.ref.name": "",
"org.opencontainers.image.title": "authelia",
"org.opencontainers.image.description": "Authelia is an open-source authentication and authorization server providing two-factor authentication and single sign-on (SSO) for your applications via a web portal.",
}
return labels
}

View File

@ -37,10 +37,10 @@ func cmdXFlagsRun(cobraCmd *cobra.Command, _ []string) {
log.Fatal(err)
}
flags, err := getXFlags("", build, extra)
buildMetaData, err := getBuild("", build, extra)
if err != nil {
log.Fatal(err)
}
fmt.Println(strings.Join(flags, " "))
fmt.Println(strings.Join(buildMetaData.XFlags(), " "))
}

File diff suppressed because it is too large Load Diff

View File

@ -6,14 +6,4 @@ files:
- source: /internal/server/locales/en/*
translation: /internal/server/locales/%locale%/%original_file_name%
skip_untranslated_files: true
languages_mapping:
locale:
"de-DE": de
"en-EN": en
"es-ES": es
"fr-FR": fr
"nl-NL": nl
"pt-PT": pt
"ru-RU": ru
"zh-CH": zh
...

View File

@ -48,18 +48,18 @@
weight = 10
[[footer]]
name = "Privacy"
url = "/information/privacy-policy"
name = "Privacy Policy"
url = "/policies/privacy"
weight = 10
[[footer]]
name = "Code of Conduct"
url = "/information/code-of-conduct"
name = "Security Policy"
url = "/policies/security"
weight = 20
[[footer]]
name = "Security"
url = "/information/security"
name = "Code of Conduct"
url = "/code-of-conduct"
weight = 30
[[footer]]

View File

@ -0,0 +1,133 @@
---
title: "4.37: Pre-Release Notes"
description: "Authelia 4.37 is just around the corner. This version has several additional features and improvements to existing features. In this blog post we'll discuss the new features and roughly what it means for users."
lead: "Pre-Release Notes for 4.37"
excerpt: "Authelia 4.37 is just around the corner. This version has several additional features and improvements to existing features. In this blog post we'll discuss the new features and roughly what it means for users."
date: 2022-09-26T06:55:09+10:00
draft: false
images: []
categories: ["News", "Release Notes"]
tags: ["releases", "pre-release-notes"]
contributors: ["James Elliott"]
pinned: false
homepage: false
---
Authelia [4.37](https://github.com/authelia/authelia/milestone/16) is just around the corner. This version has several
additional features and improvements to existing features. In this blog post we'll discuss the new features and roughly
what it means for users.
_**Note:** These features are still subject to change however it represents the most likely features._
This blog entry (and technically the blog itself) is part of a new effort I'm making for which I'm not entirely sure how
useful it'll be but I'd love to hear your feedback regardless. We don't use any analytics or interactive components to
gauge the consumption or reception of the website so it is invaluable to get this feedback.
## Envoy Support
We'll be supporting [Envoy] and [Istio] in this release. Support for this proxy mostly completes our proxy support status
with all major proxies supported excluding Microsoft IIS.
[Envoy]: https://www.envoyproxy.io/
[Istio]: https://istio.io/
## OpenID Connect Improvements
Several items from the [OpenID Connect Roadmap](../../roadmap/active/openid-connect.md) are being checked off in this
release.
### Hashed Client Secrets
We'll be supporting hashed OpenID Connect client secrets in this release. People will still be able to use plaintext
secrets if they wish however we'll be recommending people utilize PBKDF2, BCrypt or SHA512 SHA2CRYPT (see
[Password Algorithms](#password-algorithms) for a full compatibility list). This doesn't change anything for OpenID
Connect Relying Parties, it only requires a change in the Authelia configuration.
### Consent Modes
Currently we support an explicit consent mode, and a pre-configured consent mode if the pre-configured duration is set.
In this release we're planning to support an implicit consent mode which will never ask users for any consent. In
addition it will make the consent mode configuration slightly more explicit.
### JWKS Certificate Chain
Currently we do not support JWKS certificates, we only support private keys. We will support advertising the Certificate
Chain via the JWKS endpoint in this release. This means when provided with a Certificate Chain will be able to
theoretically validate the level of trust associated with the JWKS.
Some applications theoretically require this, most probably don't support it at all. However the beauty of this change
is that if it's not supported by the other party they can just ignore it. We've yet to have users request this but it's
likely inevitable that someone will ask or some third party will require it at some point, so we're preemptively
implementing it.
## Container Annotations / Labels
In this release we're going to start adding the [OCI Image Format Specification]'s set of [Annotations] to all of our
images.
For the time being we will also add the [Annotations] as container labels. This is because [Annotations] are a
relatively unsupported specification at this stage. A majority of use cases for the [Annotations] either actually use
labels or fallback to labels.
[OCI Image Format Specification]: https://github.com/opencontainers/image-spec
[Annotations]: https://github.com/opencontainers/image-spec/blob/main/annotations.md
## Password Algorithms
Several new password hashing algorithms will be supported in this release. The list of supported algorithms will become:
* Argon2:
* Argon2id (previously supported)
* Argon2i
* Argon2d
* PBKDF2:
* SHA1
* SHA224
* SHA256
* SHA384
* SHA512
* SCrypt
* BCrypt
* SHA2 CRYPT:
* SHA256
* SHA512 (previously supported)
## Users YAML File Authentication Backend
In addition to the [Password Algorithms](#password-algorithms) changes we'll also be adding a few major features to the
Users YAML File Authentication Backend.
### Automatic Reload
Administrators will be able to allow automatic reload the YAML file with the users database for deployments of the YAML
File backend. This change will not extend to the main configuration file at this time.
### Email Lookup
Administrators will be able to allow users to use their email or their username to login similar to how this can be done
with an LDAP filter already, bringing feature parity to the YAML File backend.
## Mutual TLS Support
This release will add support for Mutual TLS for Redis, LDAP, and SMTP. This improves compatibility with these systems
when password authentication is not desired.
## Query Parameter Authorization Criteria
We'll be adding a very specific query parameter matcher to the access control rules in this release. It will allow
individually targeting specific query arguments and testing if they exist/don't exist, equal/don't equal a value, or if
they match/don't match a specific Regular Expression.
This rule type takes a performance hit when compared to the resources rule type, so the resources rule type is generally
encouraged. However for complex matching of query parameters a Regular Expression is hard to get exactly right. This
feature alleviates this issue.
## Compatibility Features
Compatibility Features are toggle on features which allows operation with a third party. Usually they're implemented to
allow ignoring a specific specification the third party has not implemented correctly.
We'll be adding the following compatibility features in this release:
* LDAP Servers which do not support querying the RootDSE for supported controls or extensions.
* SMTP Servers which advertise support for STARTTLS but do not actually support it.

View File

@ -47,4 +47,4 @@ future.
[Hugo]: https://gohugo.io/
[Doks]: https://getdoks.org/
[Documentation Contributing]: ../../contributing/prologue/documentation.md
[Documentation Contributing]: ../../contributing/prologue/documentation-contributions.md

View File

@ -20,13 +20,36 @@ aliases:
authentication_backend:
file:
path: /config/users.yml
watch: false
search:
email: false
case_insensitive: false
password:
algorithm: argon2id
iterations: 3
key_length: 32
salt_length: 16
parallelism: 4
memory: 64
algorithm: argon2
argon2:
variant: argon2id
iterations: 3
memory: 65536
parallelism: 4
key_length: 32
salt_length: 16
scrypt:
iterations: 16
block_size: 8
parallelism: 1
key_length: 32
salt_length: 16
pbkdf2:
variant: sha512
iterations: 310000
salt_length: 16
sha2crypt:
variant: sha512
iterations: 50000
salt_length: 16
bcrypt:
variant: standard
cost: 12
```
## Options
@ -39,70 +62,37 @@ The path to the file with the user details list. Supported file types are:
* [YAML File](../../reference/guides/passwords.md#yaml-format)
### password
### watch
#### algorithm
{{< confkey type="boolean" default="false" required="no" >}}
{{< confkey type="string" default="argon2id" required="no" >}}
Enables reloading the database by watching it for changes.
Controls the hashing algorithm used for hashing new passwords. Value must be one of:
### search
* `argon2id` for the [Argon2] `id` variant
* `sha512` for the [SHA Crypt] `SHA512` variant
Username searching functionality options.
#### iterations
*__Important Note:__ This functionality is experimental.*
{{< confkey type="integer" required="no" >}}
#### email
Controls the number of hashing iterations done by the other hashing settings ([Argon2] parameter `t`, [SHA Crypt]
parameter `rounds`). This affects the effective cost of hashing.
{{< confkey type="boolean" default="false" required="no" >}}
| Algorithm | Minimum | Default | Recommended |
|:---------:|:-------:|:-------:|:------------------------------------------------------------------------------------------:|
| argon2id | 1 | 3 | [See Recommendations](../../reference/guides/passwords.md#recommended-parameters-argon2id) |
| sha512 | 1000 | 50000 | [See Recommendations](../../reference/guides/passwords.md#recommended-parameters-sha512) |
Allows users to login using their email address. If enabled two users must not have the same emails and their usernames
must not be an email.
#### key_length
*__Note:__ Emails are always checked using case-insensitive lookup.*
{{< confkey type="integer" default="32" required="no" >}}
#### case_insensitive
*__Important:__ This setting is specific to the `argon2id` algorithm and unused with the `sha512` algorithm.*
{{< confkey type="boolean" default="false" required="no" >}}
Sets the key length of the [Argon2] hash output. The minimum value is `16` with the recommended value of `32` being set
as the default.
Enabling this search option allows users to login with their username regardless of case. If enabled users must only
have lowercase usernames.
#### salt_length
*__Note:__ Emails are always checked using case-insensitive lookup.*
{{< confkey type="integer" default="16" required="no" >}}
Controls the length of the random salt added to each password before hashing. There is not a compelling reason to have
this set to anything other than `16`, however the minimum is `8` with the recommended value of `16` being set as the
default.
#### parallelism
{{< confkey type="integer" default="4" required="no" >}}
*__Important:__ This setting is specific to the `argon2id` algorithm and unused with the `sha512` algorithm.*
Sets the number of threads used by [Argon2] when hashing passwords ([Argon2] parameter `p`). The minimum value is `1`
with the recommended value of `4` being set as the default. This affects the effective cost of hashing.
#### memory
{{< confkey type="integer" default="64" required="no" >}}
*__Important:__ This setting is specific to the `argon2id` algorithm and unused with the `sha512` algorithm.*
Sets the amount of memory in megabytes allocated to a single password hashing calculation ([Argon2] parameter `m`). This
affects the effective cost of hashing.
This memory is released by go after the hashing process completes, however the operating system may not reclaim the
memory until a later time such as when the system is experiencing memory pressure which may cause the appearance of more
memory being in use than Authelia is actually actively using. Authelia will typically reuse this memory if it has not be
reclaimed as long as another hashing calculation is not still utilizing it.
## Reference
## Password Options
A [reference guide](../../reference/guides/passwords.md) exists specifically for choosing password hashing values. This
section contains far more information than is practical to include in this configuration document. See the
@ -110,5 +100,164 @@ section contains far more information than is practical to include in this confi
This guide contains examples such as the [User / Password File](../../reference/guides/passwords.md#user--password-file).
### algorithm
{{< confkey type="string" default="argon2" required="no" >}}
Controls the hashing algorithm used for hashing new passwords. Value must be one of:
* `argon2` for the [Argon2](#argon2) algorithm
* `scrypt` for the [Scrypt](#scrypt) algorithm
* `pbkdf2` for the [PBKDF2](#pbkdf2) algorithm
* `sha2crypt` for the [SHA2Crypt](#sha2crypt) algorithm
* `bcrypt` for the [Bcrypt](#bcrypt) algorithm
### argon2
The [Argon2] algorithm implementation. This is one of the only algorithms that was designed purely with password hashing
in mind and is subsequently one of the best algorithms to date for security.
#### variant
{{< confkey type="string" default="argon2id" required="no" >}}
Controls the variant when hashing passwords using [Argon2]. Recommended `argon2id`.
Permitted values `argon2id`, `argon2i`, `argon2d`.
#### iterations
{{< confkey type="integer" default="3" required="no" >}}
Controls the number of iterations when hashing passwords using [Argon2].
#### memory
{{< confkey type="integer" default="65536" required="no" >}}
Controls the amount of memory in kibibytes when hashing passwords using [Argon2].
#### parallelism
{{< confkey type="integer" default="4" required="no" >}}
Controls the parallelism factor when hashing passwords using [Argon2].
#### key_length
{{< confkey type="integer" default="32" required="no" >}}
Controls the output key length when hashing passwords using [Argon2].
#### salt_length
{{< confkey type="integer" default="16" required="no" >}}
Controls the output salt length when hashing passwords using [Argon2].
### scrypt
The [Scrypt] algorithm implementation.
#### iterations
{{< confkey type="integer" default="16" required="no" >}}
Controls the number of iterations when hashing passwords using [Scrypt].
#### block_size
{{< confkey type="integer" default="8" required="no" >}}
Controls the block size when hashing passwords using [Scrypt].
#### parallelism
{{< confkey type="integer" default="1" required="no" >}}
Controls the parallelism factor when hashing passwords using [Scrypt].
#### key_length
{{< confkey type="integer" default="32" required="no" >}}
Controls the output key length when hashing passwords using [Scrypt].
#### salt_length
{{< confkey type="integer" default="16" required="no" >}}
Controls the output salt length when hashing passwords using [Scrypt].
### pbkdf2
The [PBKDF2] algorithm implementation.
#### variant
{{< confkey type="string" default="sha512" required="no" >}}
Controls the variant when hashing passwords using [PBKDF2]. Recommended `sha512`.
Permitted values `sha1`, `sha224`, `sha256`, `sha384`, `sha512`.
#### iterations
{{< confkey type="integer" default="310000" required="no" >}}
Controls the number of iterations when hashing passwords using [PBKDF2].
#### salt_length
{{< confkey type="integer" default="16" required="no" >}}
Controls the output salt length when hashing passwords using [PBKDF2].
### sha2crypt
The [SHA2 Crypt] algorithm implementation.
#### variant
{{< confkey type="string" default="sha512" required="no" >}}
Controls the variant when hashing passwords using [SHA2 Crypt]. Recommended `sha512`.
Permitted values `sha256`, `sha512`.
#### iterations
{{< confkey type="integer" default="50000" required="no" >}}
Controls the number of iterations when hashing passwords using [SHA2 Crypt].
#### salt_length
{{< confkey type="integer" default="16" required="no" >}}
Controls the output salt length when hashing passwords using [SHA2 Crypt].
### bcrypt
The [Bcrypt] algorithm implementation.
#### variant
{{< confkey type="string" default="standard" required="no" >}}
Controls the variant when hashing passwords using [Bcrypt]. Recommended `standard`.
Permitted values `standard`, `sha256`.
*__Important Note:__ The `sha256` variant is a special variant designed by
[Passlib](https://passlib.readthedocs.io/en/stable/lib/passlib.hash.bcrypt_sha256.html). This variant passes the
password through a SHA256 HMAC before passing it to the [Bcrypt] algorithm, effectively bypassing the 72 byte password
truncation that [Bcrypt] does. It is not supported by many other systems.*
#### cost
{{< confkey type="integer" default="12" required="no" >}}
Controls the hashing cost when hashing passwords using [Bcrypt].
[Argon2]: https://www.rfc-editor.org/rfc/rfc9106.html
[SHA Crypt]: https://www.akkadia.org/drepper/SHA-crypt.txt
[Scrypt]: https://en.wikipedia.org/wiki/Scrypt
[PBKDF2]: https://www.ietf.org/rfc/rfc2898.html
[SHA2 Crypt]: https://www.akkadia.org/drepper/SHA-crypt.txt
[Bcrypt]: https://en.wikipedia.org/wiki/Bcrypt

View File

@ -28,13 +28,81 @@ authentication_backend:
server_name: ldap.example.com
skip_verify: false
minimum_version: TLS1.2
maximum_version: TLS1.3
certificate_chain: |
-----BEGIN CERTIFICATE-----
MIIC5jCCAc6gAwIBAgIRAK4Sj7FiN6PXo/urPfO4E7owDQYJKoZIhvcNAQELBQAw
EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAPKv3pSyP4ozGEiVLJ14dIWFCEGEgq7WUMI0SZZqQA2ID0L59U/Q
/Usyy7uC9gfMUzODTpANtkOjFQcQAsxlR1FOjVBrX5QgjSvXwbQn3DtwMA7XWSl6
LuYx2rBYSlMSN5UZQm/RxMtXfLK2b51WgEEYDFi+nECSqKzR4R54eOPkBEWRfvuY
91AMjlhpivg8e4JWkq4LVQUKbmiFYwIdK8XQiN4blY9WwXwJFYs5sQ/UYMwBFi0H
kWOh7GEjfxgoUOPauIueZSMSlQp7zqAH39N0ZSYb6cS0Npj57QoWZSY3ak87ebcR
Nf4rCvZLby7LoN7qYCKxmCaDD3x2+NYpWH8CAwEAAaM1MDMwDgYDVR0PAQH/BAQD
AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcN
AQELBQADggEBAHSITqIQSNzonFl3DzxHPEzr2hp6peo45buAAtu8FZHoA+U7Icfh
/ZXjPg7Xz+hgFwM/DTNGXkMWacQA/PaNWvZspgRJf2AXvNbMSs2UQODr7Tbv+Fb4
lyblmMUNYFMCFVAMU0eIxXAFq2qcwv8UMcQFT0Z/35s6PVOakYnAGGQjTfp5Ljuq
wsdc/xWmM0cHWube6sdRRUD7SY20KU/kWzl8iFO0VbSSrDf1AlEhnLEkp1SPaxXg
OdBnl98MeoramNiJ7NT6Jnyb3zZ578fjaWfThiBpagItI8GZmG4s4Ovh2JbheN8i
ZsjNr9jqHTjhyLVbDRlmJzcqoj4JhbKs6/I^invalid DO NOT USE=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDBDCCAeygAwIBAgIRALJsPg21kA0zY4F1wUCIuoMwDQYJKoZIhvcNAQELBQAw
EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAMXHBvVxUzYk0u34/DINMSF+uiOekKOAjOrC6Mi9Ww8ytPVO7t2S
zfTvM+XnEJqkFQFgimERfG/eGhjF9XIEY6LtnXe8ATvOK4nTwdufzBaoeQu3Gd50
5VXr6OHRo//ErrGvFXwP3g8xLePABsi/fkH3oDN+ztewOBMDzpd+KgTrk8ysv2ou
kNRMKFZZqASvCgv0LD5KWvUCnL6wgf1oTXG7aztduA4oSkUP321GpOmBC5+5ElU7
ysoRzvD12o9QJ/IfEaulIX06w9yVMo60C/h6A3U6GdkT1SiyTIqR7v7KU/IWd/Qi
Lfftcj91VhCmJ73Meff2e2S2PrpjdXbG5FMCAwEAAaNTMFEwDgYDVR0PAQH/BAQD
AgKkMA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
Z7AtA3mzFc0InSBA5fiMfeLXA3owDQYJKoZIhvcNAQELBQADggEBAEE5hm1mtlk/
kviCoHH4evbpw7rxPxDftIQlqYTtvMM4eWY/6icFoSZ4fUHEWYyps8SsPu/8f2tf
71LGgZn0FdHi1QU2H8m0HHK7TFw+5Q6RLrLdSyk0PItJ71s9en7r8pX820nAFEHZ
HkOSfJZ7B5hFgUDkMtVM6bardXAhoqcMk4YCU96e9d4PB4eI+xGc+mNuYvov3RbB
D0s8ICyojeyPVLerz4wHjZu68Z5frAzhZ68YbzNs8j2fIBKKHkHyLG1iQyF+LJVj
2PjCP+auJsj6fQQpMGoyGtpLcSDh+ptcTngUD8JsWipzTCjmaNqdPHAOYmcgtf4b
qocikt3WAdU^invalid DO NOT USE=
-----END CERTIFICATE-----
private_key: |
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA8q/elLI/ijMYSJUsnXh0hYUIQYSCrtZQwjRJlmpADYgPQvn1
T9D9SzLLu4L2B8xTM4NOkA22Q6MVBxACzGVHUU6NUGtflCCNK9fBtCfcO3AwDtdZ
KXou5jHasFhKUxI3lRlCb9HEy1d8srZvnVaAQRgMWL6cQJKorNHhHnh44+QERZF+
+5j3UAyOWGmK+Dx7glaSrgtVBQpuaIVjAh0rxdCI3huVj1bBfAkVizmxD9RgzAEW
LQeRY6HsYSN/GChQ49q4i55lIxKVCnvOoAff03RlJhvpxLQ2mPntChZlJjdqTzt5
txE1/isK9ktvLsug3upgIrGYJoMPfHb41ilYfwIDAQABAoIBAQDTOdFf2JjHH1um
aPgRAvNf9v7Nj5jytaRKs5nM6iNf46ls4QPreXnMhqSeSwj6lpNgBYxOgzC9Q+cc
Y4ob/paJJPaIJTxmP8K/gyWcOQlNToL1l+eJ20eQoZm23NGr5fIsunSBwLEpTrdB
ENqqtcwhW937K8Pxy/Q1nuLyU2bc6Tn/ivLozc8n27dpQWWKh8537VY7ancIaACr
LJJLYxKqhQpjtBWAyCDvZQirnAOm9KnvIHaGXIswCZ4Xbsu0Y9NL+woARPyRVQvG
jfxy4EmO9s1s6y7OObSukwKDSNihAKHx/VIbvVWx8g2Lv5fGOa+J2Y7o9Qurs8t5
BQwMTt0BAoGBAPUw5Z32EszNepAeV3E2mPFUc5CLiqAxagZJuNDO2pKtyN29ETTR
Ma4O1cWtGb6RqcNNN/Iukfkdk27Q5nC9VJSUUPYelOLc1WYOoUf6oKRzE72dkMQV
R4bf6TkjD+OVR17fAfkswkGahZ5XA7j48KIQ+YC4jbnYKSxZTYyKPjH/AoGBAP1i
tqXt36OVlP+y84wWqZSjMelBIVa9phDVGJmmhz3i1cMni8eLpJzWecA3pfnG6Tm9
ze5M4whASleEt+M00gEvNaU9ND+z0wBfi+/DwJYIbv8PQdGrBiZFrPhTPjGQUldR
lXccV2meeLZv7TagVxSi3DO6dSJfSEHyemd5j9mBAoGAX8Hv+0gOQZQCSOTAq8Nx
6dZcp9gHlNaXnMsP9eTDckOSzh636JPGvj6m+GPJSSbkURUIQ3oyokMNwFqvlNos
fTaLhAOfjBZI9WnDTTQxpugWjphJ4HqbC67JC/qIiw5S6FdaEvGLEEoD4zoChywZ
9oGAn+fz2d/0/JAH/FpFPgsCgYEAp/ipZgPzziiZ9ov1wbdAQcWRj7RaWnssPFpX
jXwEiXT3CgEMO4MJ4+KWIWOChrti3qFBg6i6lDyyS6Qyls7sLFbUdC7HlTcrOEMe
rBoTcCI1GqZNlqWOVQ65ZIEiaI7o1vPBZo2GMQEZuq8mDKFsOMThvvTrM5cAep84
n6HJR4ECgYABWcbsSnr0MKvVth/inxjbKapbZnp2HUCuw87Ie5zK2Of/tbC20wwk
yKw3vrGoE3O1t1g2m2tn8UGGASeZ842jZWjIODdSi5+icysQGuULKt86h/woz2SQ
27GoE2i5mh6Yez6VAYbUuns3FcwIsMyWLq043Tu2DNkx9ijOOAuQzw^invalid..
DO NOT USE==
-----END RSA PRIVATE KEY-----
base_dn: DC=example,DC=com
additional_users_dn: ou=users
additional_users_dn: OU=users
users_filter: (&({username_attribute}={input})(objectClass=person))
username_attribute: uid
mail_attribute: mail
display_name_attribute: displayName
additional_groups_dn: ou=groups
additional_groups_dn: OU=groups
groups_filter: (&(member={dn})(objectClass=groupOfNames))
group_name_attribute: cn
permit_referrals: false
@ -198,6 +266,13 @@ server and utilizing a service account.*
Permits binding to the server without a password. For this option to be enabled both the [password](#password)
configuration option must be blank and the [password_reset disable](introduction.md#disable) option must be `true`.
### permit_feature_detection_failure
{{< confkey type="boolean" default="false" required="no" >}}
Authelia searches for the RootDSE to discover supported controls and extensions. This option is a compatability option
which *__should not__* be enabled unless the LDAP server returns an error when searching for the RootDSE.
### user
{{< confkey type="string" required="yes" >}}
@ -214,7 +289,7 @@ especially for containerized deployments.*
The password paired with the [user](#user) used to bind to the LDAP server for lookup and password change operations.
It's __strongly recommended__ this is a
[Random Alphanumeric String](../miscellaneous/guides.md#generating-a-random-alphanumeric-string) with 64 or more
[Random Alphanumeric String](../../reference/guides/generating-secure-values.md#generating-a-random-alphanumeric-string) with 64 or more
characters and the user password is changed to this value.
## Refresh Interval

View File

@ -33,33 +33,72 @@ The following snippet provides a sample-configuration for the OIDC identity prov
identity_providers:
oidc:
hmac_secret: this_is_a_secret_abc123abc123abc
issuer_certificate_chain: |
-----BEGIN CERTIFICATE-----
MIIC5jCCAc6gAwIBAgIRAK4Sj7FiN6PXo/urPfO4E7owDQYJKoZIhvcNAQELBQAw
EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAPKv3pSyP4ozGEiVLJ14dIWFCEGEgq7WUMI0SZZqQA2ID0L59U/Q
/Usyy7uC9gfMUzODTpANtkOjFQcQAsxlR1FOjVBrX5QgjSvXwbQn3DtwMA7XWSl6
LuYx2rBYSlMSN5UZQm/RxMtXfLK2b51WgEEYDFi+nECSqKzR4R54eOPkBEWRfvuY
91AMjlhpivg8e4JWkq4LVQUKbmiFYwIdK8XQiN4blY9WwXwJFYs5sQ/UYMwBFi0H
kWOh7GEjfxgoUOPauIueZSMSlQp7zqAH39N0ZSYb6cS0Npj57QoWZSY3ak87ebcR
Nf4rCvZLby7LoN7qYCKxmCaDD3x2+NYpWH8CAwEAAaM1MDMwDgYDVR0PAQH/BAQD
AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcN
AQELBQADggEBAHSITqIQSNzonFl3DzxHPEzr2hp6peo45buAAtu8FZHoA+U7Icfh
/ZXjPg7Xz+hgFwM/DTNGXkMWacQA/PaNWvZspgRJf2AXvNbMSs2UQODr7Tbv+Fb4
lyblmMUNYFMCFVAMU0eIxXAFq2qcwv8UMcQFT0Z/35s6PVOakYnAGGQjTfp5Ljuq
wsdc/xWmM0cHWube6sdRRUD7SY20KU/kWzl8iFO0VbSSrDf1AlEhnLEkp1SPaxXg
OdBnl98MeoramNiJ7NT6Jnyb3zZ578fjaWfThiBpagItI8GZmG4s4Ovh2JbheN8i
ZsjNr9jqHTjhyLVbDRlmJzcqoj4JhbKs6/I^invalid DO NOT USE=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDBDCCAeygAwIBAgIRALJsPg21kA0zY4F1wUCIuoMwDQYJKoZIhvcNAQELBQAw
EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAMXHBvVxUzYk0u34/DINMSF+uiOekKOAjOrC6Mi9Ww8ytPVO7t2S
zfTvM+XnEJqkFQFgimERfG/eGhjF9XIEY6LtnXe8ATvOK4nTwdufzBaoeQu3Gd50
5VXr6OHRo//ErrGvFXwP3g8xLePABsi/fkH3oDN+ztewOBMDzpd+KgTrk8ysv2ou
kNRMKFZZqASvCgv0LD5KWvUCnL6wgf1oTXG7aztduA4oSkUP321GpOmBC5+5ElU7
ysoRzvD12o9QJ/IfEaulIX06w9yVMo60C/h6A3U6GdkT1SiyTIqR7v7KU/IWd/Qi
Lfftcj91VhCmJ73Meff2e2S2PrpjdXbG5FMCAwEAAaNTMFEwDgYDVR0PAQH/BAQD
AgKkMA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
Z7AtA3mzFc0InSBA5fiMfeLXA3owDQYJKoZIhvcNAQELBQADggEBAEE5hm1mtlk/
kviCoHH4evbpw7rxPxDftIQlqYTtvMM4eWY/6icFoSZ4fUHEWYyps8SsPu/8f2tf
71LGgZn0FdHi1QU2H8m0HHK7TFw+5Q6RLrLdSyk0PItJ71s9en7r8pX820nAFEHZ
HkOSfJZ7B5hFgUDkMtVM6bardXAhoqcMk4YCU96e9d4PB4eI+xGc+mNuYvov3RbB
D0s8ICyojeyPVLerz4wHjZu68Z5frAzhZ68YbzNs8j2fIBKKHkHyLG1iQyF+LJVj
2PjCP+auJsj6fQQpMGoyGtpLcSDh+ptcTngUD8JsWipzTCjmaNqdPHAOYmcgtf4b
qocikt3WAdU^invalid DO NOT USE=
-----END CERTIFICATE-----
issuer_private_key: |
-----BEGIN RSA PRIVATE KEY-----
MXIEogIB$AKCAQEAxZVJP3WF//PG2fLQoEC9DtdiFG/+00vqlbVzz47nyxKONIPI
lmL3UdmqpGTKMe/5Brqse4ZAKlQHiDbwzK9ypnfigtHuvh/JO0S7ChP70RC67ed1
HV1nyfz5eW3llbtGJPrlYLqITNgctHp6zmRUFtSzPj9qFvozI93LJi492yL1+vu8
Un3Dm8+Qq6XM2tPdEcldB/dtBwOWoF+8eOOVsu0TDuB5bwlhBVGJuSAuzBPRS2bF
Ga4uk0JDdkDOMCEQxC5uWDFxgfERSMFyfLVWD47woDbuWEBq10c0z+dpWPMp7Ain
YnnkqicwCN88Z0zid6MmMQ65F4+9Hc+qC/p6xwIDAQABAoIBAGlhaAHKor+Su3o/
AXqXTL5/rbYMzbLQiLt0XeJT69jpeqMTroZXHmWvXE3128mqnf0yzw/K2Ko6yxGh
i+j/onya8FqpsVYCCgfsbn2/js1AyRJeIp6Y1ORsYnqbXJnxmkXa80AV/OBPW2/+
60TtSdQrebY3iFPc+i2k+9bPTvpyyDLKlz8UwdZG+k5uyYNIyQTccz+PjwsIvDij
7tKYamhhLN3QXt3/aZTFpjTgezP4WyriZxjWrddHowc47q2rwNS95ND39JcysJAc
0Pcbu8A5lVa7Fx33uOtzDfKWIW7xVEN+OtPgN+FbTjXcXk5IZedl+pW5lU5P++G/
ZPvz+WECgYEA9g6HwdODW3e68bOqsFoKg35+vfUFMzlyMF8HFylNVfnLpTEDr637
owzMFvcUxVd71b+gV5nnnbI+riUFIgyR8vhCjhy4moopDPahC4/KwN4NG6uz+i1h
AB6D5+zn2BjnO/5xMMFGlApWtRNmJVGYlNDj3bXKh2VXzzy03VNeD8kCgYEAzZFL
OlzoRB1HKpTWIECcuvxofMxLOLb3zs0k2t/FYNYIpovmGWCCAULz13y53e5+/+5m
7I9VUZJFaIhaZ36qVBApCKdru69pZMkWCcQO9jELFcx51Ez7OgJWzu7GS1QJCPKC
fEDxI0rZK21j93/Sl/nUnEir7CYpQ+wvCaGuHg8CgYAXgbncfY1+DokwkB6NbHy2
pT4Mfbz6cNGE538w6kQ2I4AeDvmwLentYMqaow478CinegAiflSPTzkHwAemghbr
ZGZPV1UXhn13fJRUG2+eT1hnPVcbXnx223N0k8Bud6qXo65CnyRT/kzcTbcjd5Eh
Hne2daicmMTzynPo9Q72aQKBgBmobO9X8VWvIdbaxO85oVZlctVA2pK1o7CYQmVf
UM+JZ4MCKzI3rYJizPS0iK5+ujNPmmEkcs2/qBIoEsCgOrpLWhPOcc/3UPxXbPzD
D+sCrBOIdhxdj23qJNOnUfDNCGOpgUfpAzAYg4q8GKInvi1h7XukRnEvQi9MJ4LY
P1dZAoGASGcGnTMkmeSXP8ux+dvQJAiJskn/sJIgBZ5uq5GRCeLBUosRSVxM75UK
vAh/c/RBj+pYXVKuPuHGZCQJxsdcRXzXNGouUtgbaYML5Me/Hagt20QzDRBfuGBg
qeZBJaXhjElvw6PUWtg4x+LYRCBpq/bS3LK3ozZrSTukVkKDegw=
MIIEpAIBAAKCAQEA8q/elLI/ijMYSJUsnXh0hYUIQYSCrtZQwjRJlmpADYgPQvn1
T9D9SzLLu4L2B8xTM4NOkA22Q6MVBxACzGVHUU6NUGtflCCNK9fBtCfcO3AwDtdZ
KXou5jHasFhKUxI3lRlCb9HEy1d8srZvnVaAQRgMWL6cQJKorNHhHnh44+QERZF+
+5j3UAyOWGmK+Dx7glaSrgtVBQpuaIVjAh0rxdCI3huVj1bBfAkVizmxD9RgzAEW
LQeRY6HsYSN/GChQ49q4i55lIxKVCnvOoAff03RlJhvpxLQ2mPntChZlJjdqTzt5
txE1/isK9ktvLsug3upgIrGYJoMPfHb41ilYfwIDAQABAoIBAQDTOdFf2JjHH1um
aPgRAvNf9v7Nj5jytaRKs5nM6iNf46ls4QPreXnMhqSeSwj6lpNgBYxOgzC9Q+cc
Y4ob/paJJPaIJTxmP8K/gyWcOQlNToL1l+eJ20eQoZm23NGr5fIsunSBwLEpTrdB
ENqqtcwhW937K8Pxy/Q1nuLyU2bc6Tn/ivLozc8n27dpQWWKh8537VY7ancIaACr
LJJLYxKqhQpjtBWAyCDvZQirnAOm9KnvIHaGXIswCZ4Xbsu0Y9NL+woARPyRVQvG
jfxy4EmO9s1s6y7OObSukwKDSNihAKHx/VIbvVWx8g2Lv5fGOa+J2Y7o9Qurs8t5
BQwMTt0BAoGBAPUw5Z32EszNepAeV3E2mPFUc5CLiqAxagZJuNDO2pKtyN29ETTR
Ma4O1cWtGb6RqcNNN/Iukfkdk27Q5nC9VJSUUPYelOLc1WYOoUf6oKRzE72dkMQV
R4bf6TkjD+OVR17fAfkswkGahZ5XA7j48KIQ+YC4jbnYKSxZTYyKPjH/AoGBAP1i
tqXt36OVlP+y84wWqZSjMelBIVa9phDVGJmmhz3i1cMni8eLpJzWecA3pfnG6Tm9
ze5M4whASleEt+M00gEvNaU9ND+z0wBfi+/DwJYIbv8PQdGrBiZFrPhTPjGQUldR
lXccV2meeLZv7TagVxSi3DO6dSJfSEHyemd5j9mBAoGAX8Hv+0gOQZQCSOTAq8Nx
6dZcp9gHlNaXnMsP9eTDckOSzh636JPGvj6m+GPJSSbkURUIQ3oyokMNwFqvlNos
fTaLhAOfjBZI9WnDTTQxpugWjphJ4HqbC67JC/qIiw5S6FdaEvGLEEoD4zoChywZ
9oGAn+fz2d/0/JAH/FpFPgsCgYEAp/ipZgPzziiZ9ov1wbdAQcWRj7RaWnssPFpX
jXwEiXT3CgEMO4MJ4+KWIWOChrti3qFBg6i6lDyyS6Qyls7sLFbUdC7HlTcrOEMe
rBoTcCI1GqZNlqWOVQ65ZIEiaI7o1vPBZo2GMQEZuq8mDKFsOMThvvTrM5cAep84
n6HJR4ECgYABWcbsSnr0MKvVth/inxjbKapbZnp2HUCuw87Ie5zK2Of/tbC20wwk
yKw3vrGoE3O1t1g2m2tn8UGGASeZ842jZWjIODdSi5+icysQGuULKt86h/woz2SQ
27GoE2i5mh6Yez6VAYbUuns3FcwIsMyWLq043Tu2DNkx9ijOOAuQzw^invalid..
DO NOT USE==
-----END RSA PRIVATE KEY-----
access_token_lifespan: 1h
authorize_code_lifespan: 1m
@ -79,11 +118,12 @@ identity_providers:
clients:
- id: myapp
description: My Application
secret: this_is_a_secret
secret: '$plaintext$this_is_a_secret'
sector_identifier: ''
public: false
authorization_policy: two_factor
pre_configured_consent_duration: ''
consent_mode: explicit
pre_configured_consent_duration: 1w
audience: []
scopes:
- openid
@ -117,9 +157,26 @@ The HMAC secret used to sign the [JWT]'s. The provided string is hashed to a SHA
purpose of meeting the required format.
It's __strongly recommended__ this is a
[Random Alphanumeric String](../miscellaneous/guides.md#generating-a-random-alphanumeric-string) with 64 or more
[Random Alphanumeric String](../../reference/guides/generating-secure-values.md#generating-a-random-alphanumeric-string) with 64 or more
characters.
### issuer_certificate_chain
{{< confkey type="string" required="no" >}}
The certificate chain/bundle to be used with the [issuer_private_key](#issuer_private_key) DER base64 ([RFC4648])
encoded PEM format used to sign/encrypt the [OpenID Connect] [JWT]'s. When configured it enables the [x5c] and [x5t]
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
The first certificate in the chain must have the public key for the [issuer_private_key](#issuer_private_key), each
certificate in the chain must be valid for the current date, and each certificate in the chain should be signed by the
certificate immediately following it if present.
### issuer_private_key
{{< confkey type="string" required="yes" >}}
@ -127,9 +184,16 @@ characters.
*__Important Note:__ This can also be defined using a [secret](../methods/secrets.md) which is __strongly recommended__
especially for containerized deployments.*
The private key in DER base64 ([RFC4648]) encoded PEM format used to encrypt the [OpenID Connect] [JWT]'s. The key must
be generated by the administrator and can be done by following the
[Generating an RSA Keypair](../miscellaneous/guides.md#generating-an-rsa-keypair) guide.
The private key used to sign/encrypt the [OpenID Connect] issued [JWT]'s. The key must be generated by the administrator
and can be done by following the [Generating an RSA Keypair](../../reference/guides/generating-secure-values.md#generating-an-rsa-keypair) guide.
The private key *__MUST__*:
* Be a PEM block encoded in the DER base64 format ([RFC4648]).
* Be an RSA Key.
* Have a key size of at least 2048 bits.
If the [issuer_certificate_chain](#issuer_certificate_chain) is provided the private key must include matching public
key data for the first certificate in the chain.
### access_token_lifespan
@ -288,10 +352,10 @@ A friendly description for this client shown in the UI. This defaults to the sam
{{< confkey type="string" required="situational" >}}
The shared secret between Authelia and the application consuming this client. This secret must match the secret
configured in the application. Currently this is stored in plain text.
configured in the application.
This secret must be generated by the administrator and can be done by following the
[Generating a Random Alphanumeric String](../miscellaneous/guides.md#generating-a-random-alphanumeric-string) guide.
[Generating Client Secrets](../../integration/openid-connect/specific-information.md#generating-client-secrets) guide.
This must be provided when the client is a confidential client type, and must be blank when using the public client
type. To set the client type to public see the [public](#public) configuration option.
@ -345,19 +409,38 @@ URI.
The authorization policy for this client: either `one_factor` or `two_factor`.
#### consent_mode
{{< confkey type="string" default="auto" required="no" >}}
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. |
| pre-configured | Allows the end-user to remember their consent for the [pre_configured_consent_duration]. |
[pre_configured_consent_duration]: #pre_configured_consent_duration
#### pre_configured_consent_duration
{{< confkey type="duration" required="no" >}}
{{< confkey type="duration" default="1w" required="no" >}}
*__Note:__ This setting uses the [duration notation format](../prologue/common.md#duration-notation-format). Please see
the [common options](../prologue/common.md#duration-notation-format) documentation for information on this format.*
Configuring this enables users of this client to remember their consent as a pre-configured consent. The period of time
dictates how long a users choice to remember the pre-configured consent lasts.
Specifying this in the configuration without a consent [consent_mode] enables the `pre-configured` mode. If this is
specified as well as the [consent_mode] then it only has an effect if the [consent_mode] is `pre-configured` or `auto`.
The period of time dictates how long a users choice to remember the pre-configured consent lasts.
Pre-configured consents are only valid if the subject, client id are exactly the same and the requested scopes/audience
match exactly with the granted scopes/audience.
[consent_mode]: #consent_mode
#### audience
{{< confkey type="list(string)" required="no" >}}

View File

@ -50,3 +50,7 @@ Can be replaced by this environment variable configuration:
AUTHELIA_LOG_LEVEL=info
AUTHELIA_SERVER_BUFFERS_READ=4096
```
## Environment Variables
{{% table-config-keys secrets="false" %}}

View File

@ -52,33 +52,32 @@ Here is the list of the environment variables which are considered secrets and c
secrets can be loaded into the configuration if they end with one of the suffixes above, you can set the value of any
other configuration using the environment but instead of loading a file the value of the environment variable is used.
| Configuration Key | Environment Variable |
|:---------------------------------------------------:|:--------------------------------------------------------:|
| [server.tls.key] | AUTHELIA_SERVER_TLS_KEY_FILE |
| [jwt_secret] | AUTHELIA_JWT_SECRET_FILE |
| [duo_api.secret_key] | AUTHELIA_DUO_API_SECRET_KEY_FILE |
| [session.secret] | AUTHELIA_SESSION_SECRET_FILE |
| [session.redis.password] | AUTHELIA_SESSION_REDIS_PASSWORD_FILE |
| [session.redis.high_availability.sentinel_password] | AUTHELIA_REDIS_HIGH_AVAILABILITY_SENTINEL_PASSWORD_FILE |
| [storage.encryption_key] | AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE |
| [storage.mysql.password] | AUTHELIA_STORAGE_MYSQL_PASSWORD_FILE |
| [storage.postgres.password] | AUTHELIA_STORAGE_POSTGRES_PASSWORD_FILE |
| [notifier.smtp.password] | AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE |
| [authentication_backend.ldap.password] | AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE |
| [identity_providers.oidc.issuer_private_key] | AUTHELIA_IDENTITY_PROVIDERS_OIDC_ISSUER_PRIVATE_KEY_FILE |
| [identity_providers.oidc.hmac_secret] | AUTHELIA_IDENTITY_PROVIDERS_OIDC_HMAC_SECRET_FILE |
{{% table-config-keys secrets="true" %}}
[server.tls.key]: ../miscellaneous/server.md#key
[jwt_secret]: ../miscellaneous/introduction.md#jwt_secret
[duo_api.integration_key]: ../second-factor/duo.md#integration_key
[duo_api.secret_key]: ../second-factor/duo.md#secret_key
[session.secret]: ../session/introduction.md#secret
[session.redis.password]: ../session/redis.md#password
[session.redis.tls.certificate_chain]: ../session/redis.md#tls
[session.redis.tls.private_key]: ../session/redis.md#tls
[session.redis.high_availability.sentinel_password]: ../session/redis.md#sentinel_password
[storage.encryption_key]: ../storage/introduction.md#encryption_key
[storage.mysql.password]: ../storage/mysql.md#password
[storage.mysql.tls.certificate_chain]: ../storage/mysql.md#tls
[storage.mysql.tls.private_key]: ../storage/mysql.md#tls
[storage.postgres.password]: ../storage/postgres.md#password
[storage.postgres.tls.certificate_chain]: ../storage/postgres.md#tls
[storage.postgres.tls.private_key]: ../storage/postgres.md#tls
[storage.postgres.ssl.key]: ../storage/postgres.md
[notifier.smtp.password]: ../notifications/smtp.md#password
[notifier.smtp.tls.certificate_chain]: ../notifications/smtp.md#tls
[notifier.smtp.tls.private_key]: ../notifications/smtp.md#tls
[authentication_backend.ldap.password]: ../first-factor/ldap.md#password
[authentication_backend.ldap.tls.certificate_chain]: ../first-factor/ldap.md#tls
[authentication_backend.ldap.tls.private_key]: ../first-factor/ldap.md#tls
[identity_providers.oidc.issuer_certificate_chain]: ../identity-providers/open-id-connect.md#issuer_certificate_chain
[identity_providers.oidc.issuer_private_key]: ../identity-providers/open-id-connect.md#issuer_private_key
[identity_providers.oidc.hmac_secret]: ../identity-providers/open-id-connect.md#hmac_secret

View File

@ -1,77 +0,0 @@
---
title: "Guides"
description: "Miscellaneous Guides for Configuration."
lead: "This section contains miscellaneous guides used in the configuration."
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
configuration:
parent: "miscellaneous"
weight: 199500
toc: true
---
## Generating a Random Alphanumeric String
Some sections of the configuration recommend generating a random string. There are many ways to accomplish this, one
possible way on Linux is utilizing the following command which prints a string with a length in characters of
`${LENGTH}` to `stdout`. The string will only contain alphanumeric characters.
```bash
LENGTH=64
tr -cd '[:alnum:]' < /dev/urandom | fold -w "${LENGTH}" | head -n 1 | tr -d '\n' ; echo
```
## Generating an RSA Keypair
Some sections of the configuration need an RSA keypair. There are many ways to achieve this, this section explains two
such ways.
### openssl
The `openssl` command on Linux can be used to generate a RSA 4096 bit keypair:
```bash
openssl genrsa -out private.pem 4096
openssl rsa -in private.pem -outform PEM -pubout -out public.pem
```
### authelia
The __Authelia__ docker container or CLI binary can be used to generate a RSA 4096 bit keypair:
```bash
docker run -u "$(id -u):$(id -g)" -v "$(pwd)":/keys authelia/authelia:latest authelia crypto pair rsa generate --bits 4096 --directory /keys
```
```bash
authelia crypto pair rsa generate --directory /path/to/keys
```
## Generating an RSA Self-Signed Certificate
Some sections of the configuration need a certificate and it may be possible to use a self-signed certificate. There are
many ways to achieve this, this section explains two such ways.
### openssl
The `openssl` command on Linux can be used to generate a RSA 4096 bit self-signed certificate for the domain
`example.com`:
```bash
openssl req -x509 -nodes -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365 -subj '/CN=example.com'
```
### authelia
The __Authelia__ docker container or binary can be used to generate a RSA 4096 bit self-signed certificate for the
domain `example.com`:
```bash
docker run -u "$(id -u):$(id -g)" -v "$(pwd)":/keys authelia/authelia authelia crypto certificate rsa generate --common-name example.com --directory /keys
```
```bash
authelia crypto certificate rsa generate --common-name example.com --directory /path/to/keys
```

View File

@ -73,7 +73,7 @@ default_2fa_method: totp
especially for containerized deployments.*
Defines the secret used to craft JWT tokens leveraged by the identity verification process. This can a random string.
It's strongly recommended this is a [Random Alphanumeric String](guides.md#generating-a-random-alphanumeric-string) with
It's strongly recommended this is a [Random Alphanumeric String](../../reference/guides/generating-secure-values.md/#generating-a-random-alphanumeric-string) with
64 or more characters.
### theme

View File

@ -35,9 +35,9 @@ server:
read: 4096
write: 4096
timeouts:
read: 10s
write: 10s
idle: 10s
read: 6s
write: 6s
idle: 30s
```
## Options
@ -130,7 +130,7 @@ security on lower areas of the OSI model. However it required, if you specify bo
[tls certificate](#certificate) options, Authelia will listen for TLS connections.
The key must be generated by the administrator and can be done by following the
[Generating an RSA Self Signed Certificate](../miscellaneous/guides.md#generating-an-rsa-self-signed-certificate)
[Generating an RSA Self Signed Certificate](../../reference/guides/generating-secure-values.md#generating-an-rsa-self-signed-certificate)
guide provided a self-signed certificate is fit for purpose. If a self-signed certificate is fit for purpose is beyond
the scope of the documentation and if it is not fit for purpose we instead recommend generating a certificate signing
request or obtaining a certificate signed by one of the many ACME certificate providers. Methods to achieve this are
@ -161,11 +161,11 @@ or intermediate certificates. If no item is provided mutual TLS is disabled.
{{< confkey type="string" required="no" >}}
This customizes the value of the Content-Security-Policy header. It will replace all instances of `${NONCE}` with the
nonce value of the Authelia react bundle. This is an advanced option to customize and you should do sufficient research
about how browsers utilize and understand this header before attempting to customize it.
This customizes the value of the Content-Security-Policy header. It will replace all instances of the below placeholder
with the nonce value of the Authelia react bundle. This is an advanced option to customize and you should do sufficient
research about how browsers utilize and understand this header before attempting to customize it.
For example, the default CSP template is `default-src 'self'; frame-src 'none'; object-src 'none'; style-src 'self' 'nonce-${NONCE}'; frame-ancestors 'none'; base-uri 'self'`.
{{< csp >}}
### buffers

View File

@ -31,11 +31,80 @@ notifier:
subject: "[Authelia] {title}"
startup_check_address: test@authelia.com
disable_require_tls: false
disable_starttls: false
disable_html_emails: false
tls:
server_name: smtp.example.com
skip_verify: false
minimum_version: TLS1.2
maximum_version: TLS1.3
certificate_chain: |
-----BEGIN CERTIFICATE-----
MIIC5jCCAc6gAwIBAgIRAK4Sj7FiN6PXo/urPfO4E7owDQYJKoZIhvcNAQELBQAw
EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAPKv3pSyP4ozGEiVLJ14dIWFCEGEgq7WUMI0SZZqQA2ID0L59U/Q
/Usyy7uC9gfMUzODTpANtkOjFQcQAsxlR1FOjVBrX5QgjSvXwbQn3DtwMA7XWSl6
LuYx2rBYSlMSN5UZQm/RxMtXfLK2b51WgEEYDFi+nECSqKzR4R54eOPkBEWRfvuY
91AMjlhpivg8e4JWkq4LVQUKbmiFYwIdK8XQiN4blY9WwXwJFYs5sQ/UYMwBFi0H
kWOh7GEjfxgoUOPauIueZSMSlQp7zqAH39N0ZSYb6cS0Npj57QoWZSY3ak87ebcR
Nf4rCvZLby7LoN7qYCKxmCaDD3x2+NYpWH8CAwEAAaM1MDMwDgYDVR0PAQH/BAQD
AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcN
AQELBQADggEBAHSITqIQSNzonFl3DzxHPEzr2hp6peo45buAAtu8FZHoA+U7Icfh
/ZXjPg7Xz+hgFwM/DTNGXkMWacQA/PaNWvZspgRJf2AXvNbMSs2UQODr7Tbv+Fb4
lyblmMUNYFMCFVAMU0eIxXAFq2qcwv8UMcQFT0Z/35s6PVOakYnAGGQjTfp5Ljuq
wsdc/xWmM0cHWube6sdRRUD7SY20KU/kWzl8iFO0VbSSrDf1AlEhnLEkp1SPaxXg
OdBnl98MeoramNiJ7NT6Jnyb3zZ578fjaWfThiBpagItI8GZmG4s4Ovh2JbheN8i
ZsjNr9jqHTjhyLVbDRlmJzcqoj4JhbKs6/I^invalid DO NOT USE=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDBDCCAeygAwIBAgIRALJsPg21kA0zY4F1wUCIuoMwDQYJKoZIhvcNAQELBQAw
EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAMXHBvVxUzYk0u34/DINMSF+uiOekKOAjOrC6Mi9Ww8ytPVO7t2S
zfTvM+XnEJqkFQFgimERfG/eGhjF9XIEY6LtnXe8ATvOK4nTwdufzBaoeQu3Gd50
5VXr6OHRo//ErrGvFXwP3g8xLePABsi/fkH3oDN+ztewOBMDzpd+KgTrk8ysv2ou
kNRMKFZZqASvCgv0LD5KWvUCnL6wgf1oTXG7aztduA4oSkUP321GpOmBC5+5ElU7
ysoRzvD12o9QJ/IfEaulIX06w9yVMo60C/h6A3U6GdkT1SiyTIqR7v7KU/IWd/Qi
Lfftcj91VhCmJ73Meff2e2S2PrpjdXbG5FMCAwEAAaNTMFEwDgYDVR0PAQH/BAQD
AgKkMA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
Z7AtA3mzFc0InSBA5fiMfeLXA3owDQYJKoZIhvcNAQELBQADggEBAEE5hm1mtlk/
kviCoHH4evbpw7rxPxDftIQlqYTtvMM4eWY/6icFoSZ4fUHEWYyps8SsPu/8f2tf
71LGgZn0FdHi1QU2H8m0HHK7TFw+5Q6RLrLdSyk0PItJ71s9en7r8pX820nAFEHZ
HkOSfJZ7B5hFgUDkMtVM6bardXAhoqcMk4YCU96e9d4PB4eI+xGc+mNuYvov3RbB
D0s8ICyojeyPVLerz4wHjZu68Z5frAzhZ68YbzNs8j2fIBKKHkHyLG1iQyF+LJVj
2PjCP+auJsj6fQQpMGoyGtpLcSDh+ptcTngUD8JsWipzTCjmaNqdPHAOYmcgtf4b
qocikt3WAdU^invalid DO NOT USE=
-----END CERTIFICATE-----
private_key: |
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA8q/elLI/ijMYSJUsnXh0hYUIQYSCrtZQwjRJlmpADYgPQvn1
T9D9SzLLu4L2B8xTM4NOkA22Q6MVBxACzGVHUU6NUGtflCCNK9fBtCfcO3AwDtdZ
KXou5jHasFhKUxI3lRlCb9HEy1d8srZvnVaAQRgMWL6cQJKorNHhHnh44+QERZF+
+5j3UAyOWGmK+Dx7glaSrgtVBQpuaIVjAh0rxdCI3huVj1bBfAkVizmxD9RgzAEW
LQeRY6HsYSN/GChQ49q4i55lIxKVCnvOoAff03RlJhvpxLQ2mPntChZlJjdqTzt5
txE1/isK9ktvLsug3upgIrGYJoMPfHb41ilYfwIDAQABAoIBAQDTOdFf2JjHH1um
aPgRAvNf9v7Nj5jytaRKs5nM6iNf46ls4QPreXnMhqSeSwj6lpNgBYxOgzC9Q+cc
Y4ob/paJJPaIJTxmP8K/gyWcOQlNToL1l+eJ20eQoZm23NGr5fIsunSBwLEpTrdB
ENqqtcwhW937K8Pxy/Q1nuLyU2bc6Tn/ivLozc8n27dpQWWKh8537VY7ancIaACr
LJJLYxKqhQpjtBWAyCDvZQirnAOm9KnvIHaGXIswCZ4Xbsu0Y9NL+woARPyRVQvG
jfxy4EmO9s1s6y7OObSukwKDSNihAKHx/VIbvVWx8g2Lv5fGOa+J2Y7o9Qurs8t5
BQwMTt0BAoGBAPUw5Z32EszNepAeV3E2mPFUc5CLiqAxagZJuNDO2pKtyN29ETTR
Ma4O1cWtGb6RqcNNN/Iukfkdk27Q5nC9VJSUUPYelOLc1WYOoUf6oKRzE72dkMQV
R4bf6TkjD+OVR17fAfkswkGahZ5XA7j48KIQ+YC4jbnYKSxZTYyKPjH/AoGBAP1i
tqXt36OVlP+y84wWqZSjMelBIVa9phDVGJmmhz3i1cMni8eLpJzWecA3pfnG6Tm9
ze5M4whASleEt+M00gEvNaU9ND+z0wBfi+/DwJYIbv8PQdGrBiZFrPhTPjGQUldR
lXccV2meeLZv7TagVxSi3DO6dSJfSEHyemd5j9mBAoGAX8Hv+0gOQZQCSOTAq8Nx
6dZcp9gHlNaXnMsP9eTDckOSzh636JPGvj6m+GPJSSbkURUIQ3oyokMNwFqvlNos
fTaLhAOfjBZI9WnDTTQxpugWjphJ4HqbC67JC/qIiw5S6FdaEvGLEEoD4zoChywZ
9oGAn+fz2d/0/JAH/FpFPgsCgYEAp/ipZgPzziiZ9ov1wbdAQcWRj7RaWnssPFpX
jXwEiXT3CgEMO4MJ4+KWIWOChrti3qFBg6i6lDyyS6Qyls7sLFbUdC7HlTcrOEMe
rBoTcCI1GqZNlqWOVQ65ZIEiaI7o1vPBZo2GMQEZuq8mDKFsOMThvvTrM5cAep84
n6HJR4ECgYABWcbsSnr0MKvVth/inxjbKapbZnp2HUCuw87Ie5zK2Of/tbC20wwk
yKw3vrGoE3O1t1g2m2tn8UGGASeZ842jZWjIODdSi5+icysQGuULKt86h/woz2SQ
27GoE2i5mh6Yez6VAYbUuns3FcwIsMyWLq043Tu2DNkx9ijOOAuQzw^invalid..
DO NOT USE==
-----END RSA PRIVATE KEY-----
```
## Options
@ -60,7 +129,7 @@ The port the SMTP service is listening on.
A connection is securely established with TLS after a succesful STARTTLS negotiation.
[Port 465 is an exception][docs-security-smtp-port] when supported by the mail server as a `submissions` service port.
[Port 465 is an exception][docs-security-smtp-port] when supported by the mail server as a `submissions` service port.
STARTTLS negotiation is not required for this port, the connection is implicitly established with TLS.
[docs-security-smtp-port]: ../../overview/security/measures.md#smtp-ports
@ -87,7 +156,7 @@ especially for containerized deployments.*
The password paired with the [username](#username) sent for authentication with the SMTP server.
It's __strongly recommended__ this is a
[Random Alphanumeric String](../miscellaneous/guides.md#generating-a-random-alphanumeric-string) with 64 or more
[Random Alphanumeric String](../../reference/guides/generating-secure-values.md#generating-a-random-alphanumeric-string) with 64 or more
characters and the user password is changed to this value.
### sender
@ -132,6 +201,18 @@ to leave this as is, but you can customize it if you have issues or you desire t
For security reasons the default settings for Authelia require the SMTP connection is encrypted by TLS. See [security]
for more information. This option disables this measure (not recommended).
### disable_starttls
{{< confkey type="boolean" default="false" required="no" >}}
Some SMTP servers ignore SMTP specifications and claim to support STARTTLS when they in fact do not.
For security reasons Authelia refuses to send messages to these servers.
This option disables this measure and is enabled *__AT YOUR OWN RISK__*. It's *__strongly recommended__*
that instead of enabling this option you either fix the issue with the SMTP server's configuration or
have the administrators of the server fix it. If the issue can't be fixed by configuration we recommend
lodging an issue with the authors of the SMTP server.
See [security] for more information.
### disable_html_emails
{{< confkey type="boolean" default="false" required="no" >}}

View File

@ -129,10 +129,39 @@ instead you should tweak the `server_name` option, and the global option
{{< confkey type="string" default="TLS1.2" required="no" >}}
The key `minimum_version` controls the minimum TLS version Authelia will use when opening TLS connections.
The possible values are `TLS1.3`, `TLS1.2`, `TLS1.1`, `TLS1.0`. Anything other than `TLS1.3` or `TLS1.2`
Controls the minimum TLS version Authelia will use when performing TLS handshakes.
The possible values are `TLS1.3`, `TLS1.2`, `TLS1.1`, `TLS1.0`, `SSL3.0`. Anything other than `TLS1.3` or `TLS1.2`
are very old and deprecated. You should avoid using these and upgrade your backend service instead of decreasing
this value.
this value. At the time of this writing `SSL3.0` will always produce errors.
### maximum_version
{{< confkey type="string" default="TLS1.3" required="no" >}}
Controls the maximum TLS version Authelia will use when performing TLS handshakes.
The possible values are `TLS1.3`, `TLS1.2`, `TLS1.1`, `TLS1.0`, `SSL3.0`. Anything other than `TLS1.3` or `TLS1.2`
are very old and deprecated. You should avoid using these and upgrade your backend service instead of decreasing
this value. At the time of this writing `SSL3.0` will always produce errors.
### certificate_chain
{{< confkey type="string" required="no" >}}
The certificate chain/bundle to be used with the [private_key](#private_key) to perform mutual TLS authentication with
the server.
The value must be one or more certificates encoded in the DER base64 ([RFC4648]) encoded PEM format.
### private_key
{{< confkey type="string" required="yes" >}}
*__Important Note:__ This can also be defined using a [secret](../methods/secrets.md) which is __strongly recommended__
especially for containerized deployments.*
The private key to be used with the [certificate_chain](#certificate_chain) for mutual TLS authentication.
The value must be one private key encoded in the DER base64 ([RFC4648]) encoded PEM format.
## Server Buffers
@ -152,7 +181,7 @@ Configures the maximum response size. The default of 4096 is generally sufficien
### read
{{< confkey type="duration" default="2s" required="no" >}}
{{< confkey type="duration" default="6s" required="no" >}}
*__Note:__ This setting uses the [duration notation format](#duration-notation-format). Please see the
[common options](#duration-notation-format) documentation for information on this format.*
@ -161,7 +190,7 @@ Configures the server read timeout.
### write
{{< confkey type="duration" default="2s" required="no" >}}
{{< confkey type="duration" default="6s" required="no" >}}
*__Note:__ This setting uses the [duration notation format](#duration-notation-format). Please see the
[common options](#duration-notation-format) documentation for information on this format.*

View File

@ -42,6 +42,17 @@ access_control:
- HEAD
resources:
- '^/api.*'
query:
- - operator: 'present'
key: 'secure'
- operator: 'absent'
key: 'insecure'
- - operator: 'pattern'
key: 'token'
value: '^(abc123|zyx789)$'
- operator: 'not pattern'
key: 'random'
value: '^(1|2)$'
```
## Options
@ -51,11 +62,11 @@ access_control:
{{< confkey type="string" default="deny" required="no" >}}
The default [policy](#policies) defines the policy applied if no [rules](#rules) section apply to the information known
about the request. It is recommended that this is configured to [deny](#deny) for security reasons. Sites which you do
about the request. It is recommended that this is configured to [deny] for security reasons. Sites which you do
not wish to secure at all with Authelia should not be configured in your reverse proxy to perform authentication with
Authelia at all for performance reasons.
See [Policies](#policies) for more information.
See the [policies] section for more information.
### networks (global)
@ -66,8 +77,8 @@ The main/global networks section contains a list of networks with a name label t
complicated network related configuration a lot cleaner and easier to read.
This section has two options, `name` and `networks`. Where the `networks` section is a list of IP addresses in CIDR
notation and where `name` is a friendly name to label the collection of networks for reuse in the [networks](#networks)
section of the [rules](#rules) section below.
notation and where `name` is a friendly name to label the collection of networks for reuse in the [networks] section of
the [rules] section below.
This configuration option *does nothing* by itself, it's only useful if you use these aliases in the [rules](#networks)
section below.
@ -77,7 +88,7 @@ section below.
{{< confkey type="list" required="no" >}}
The rules have many configuration options. A rule matches when all criteria of the rule match the request excluding the
`policy` which is the [policy](#policies) applied to the request.
[policy] which is the [policy](#policies) applied to the request.
A rule defines two primary things:
@ -86,29 +97,29 @@ A rule defines two primary things:
The criteria is broken into several parts:
* [domain](#domain): domain or list of domains targeted by the request.
* [domain_regex](#domain_regex): regex form of [domain](#domain).
* [resources](#resources): pattern or list of patterns that the path should match.
* [subject](#subject): the user or group of users to define the policy for.
* [networks](#networks): the network addresses, ranges (CIDR notation) or groups from where the request originates.
* [methods](#methods): the http methods used in the request.
* [domain]: domain or list of domains targeted by the request.
* [domain_regex]: regex form of [domain].
* [resources]: pattern or list of patterns that the path should match.
* [subject]: the user or group of users to define the policy for.
* [networks]: the network addresses, ranges (CIDR notation) or groups from where the request originates.
* [methods]: the http methods used in the request.
A rule is matched when all criteria of the rule match. Rules are evaluated in sequential order, and the first rule that
is a match for a given request is the rule applied; subsequent rules have *no effect*. This is particularly
__important__ for bypass rules. Bypass rules should generally appear near the top of the rules list. However you need to
carefully evaluate your rule list __in order__ to see which rule matches a particular scenario. A comprehensive
understanding of how rules apply is also recommended.
A rule is matched when all criteria of the rule match. Rules are evaluated in sequential order as per
[Rule Matching Concept 1]. It's *__strongly recommended__* that individuals read the [Rule Matching](#rule-matching)
section.
[rules]: #rules
#### domain
{{< confkey type="list(string)" required="yes" >}}
*__Required:__ This criteria and/or the [domain_regex](#domain_regex) criteria are required.*
*__Required:__ This criteria and/or the [domain_regex] criteria are required.*
This criteria matches the domain name and has two methods of configuration, either as a single string or as a list of
strings. When it's a list of strings the rule matches when __any__ of the domains in the list match the request domain.
When used in conjunction with [domain_regex](#domain_regex) the rule will match when either the [domain](#domain) or the
[domain_regex](#domain_regex) criteria matches.
When used in conjunction with [domain_regex] the rule will match when either the [domain] or the [domain_regex] criteria
matches.
Rules may start with a few different wildcards:
@ -117,9 +128,8 @@ Rules may start with a few different wildcards:
string __must__ be quoted like `"*.example.com"`.
* The user wildcard is `{user}.`, which when in front of a domain dynamically matches the username of the user. For
example `{user}.example.com` would match `fred.example.com` if the user logged in was named `fred`. *__Warning:__ this is
officially deprecated as the [domain_regex](#domain_regex) criteria completely replaces the functionality in a much
more useful way. It is strongly recommended you do not use this as it will be removed in a future version, most likely
v5.0.0.*
officially deprecated as the [domain_regex] criteria completely replaces the functionality in a much more useful
way. It is strongly recommended you do not use this as it will be removed in a future version, most likely v5.0.0.*
* The group wildcard is `{group}.`, which when in front of a domain dynamically matches if the logged in user has the
group in that location. For example `{group}.example.com` would match `admins.example.com` if the user logged in was
in the following groups `admins,users,people` because `admins` is in the list.
@ -129,6 +139,8 @@ or subdomains of that domain. This is because a website can only write cookies f
theoretically possible for us to do this with multiple domains however we would have to be security conscious in our
implementation, and it is not currently a priority.
[domain]: #domain
##### Examples
*Single domain of `*.example.com` matched. All rules in this list are effectively the same rule just expressed in
@ -158,7 +170,7 @@ access_control:
policy: bypass
```
*Multiple domains matched either via a static domain or via a [domain_regex](#domain_regex). This rule will match
*Multiple domains matched either via a static domain or via a [domain_regex]. This rule will match
either `apple.example.com`, `pub-data.example.com`, or `img-data.example.com`.*
```yaml
@ -173,20 +185,20 @@ access_control:
{{< confkey type="list(string)" required="yes" >}}
*__Required:__ This criteria and/or the [domain](#domain) criteria are required.*
*__Required:__ This criteria and/or the [domain] criteria are required.*
*__Important Note:__ If you intend to use this criteria with a bypass rule please read
[bypass and subjects](#bypass-and-user-identity) before doing so.*
*__Important Note:__ If you intend to use this criteria with a bypass rule please read [Rule Matching Concept 2].*
*__Important Note:__ to utilize regex you must escape it properly. See
[regular expressions](../prologue/common.md#regular-expressions) for more information.*
This criteria matches the domain name and has two methods of configuration, either as a single string or as a list of
strings. When it's a list of strings the rule matches when __any__ of the domains in the list match the request domain.
When used in conjunction with [domain](#domain) the rule will match when either the [domain](#domain) or the
[domain_regex](#domain_regex) criteria matches.
When used in conjunction with [domain] the rule will match when either the [domain] or the [domain_regex] criteria matches.
In addition to standard regex patterns this criteria can match some [Named Regex Groups](#named-regex-groups).
In addition to standard regex patterns this criteria can match some [Named Regex Groups].
[domain_regex]: #domain_regex
##### Examples
@ -222,15 +234,14 @@ access_control:
The specific [policy](#policies) to apply to the selected rule. This is not criteria for a match, this is the action to
take when a match is made.
[policy]: #policy
#### subject
{{< confkey type="list(list(string))" required="no" >}}
*__Note:__ this rule criteria __may not__ be used for the `bypass` policy the minimum required authentication level to
identify the subject is `one_factor`. We have taken an opinionated stance on preventing this configuration as it could
result in problematic security scenarios with badly thought out configurations and cannot see a likely configuration
scenario that would require users to do this. If you have a scenario in mind please open an
[issue](https://github.com/authelia/authelia/issues/new) on GitHub.*
*__Note:__ this rule criteria __may not__ be used for the [bypass] policy the minimum required authentication level to
identify the subject is [one_factor]. See [Rule Matching Concept 2] for more information.*
This criteria matches identifying characteristics about the subject. Currently this is either user or groups the user
belongs to. This allows you to effectively control exactly what each user is authorized to access or to specifically
@ -241,6 +252,8 @@ The format of this rule is unique in as much as it is a list of lists. The logic
`OR` and `AND` logic. The first level of the list defines the `OR` logic, and the second level defines the `AND` logic.
Additionally each level of these lists does not have to be explicitly defined.
[subject]: #subject
##### Examples
*Matches when the user has the username `john`, __or__ the user is in the groups `admin` __and__ `app-name`, __or__ the
@ -306,6 +319,8 @@ relevant methods are listed in this table:
| [RFC5789] | PATCH | [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods) |
| [RFC4918] | PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK | |
[methods]: #methods
##### Examples
*Bypass `OPTIONS` requests to the `example.com` domain.*
@ -341,6 +356,8 @@ privileges when a user is on the local networks.
There are a large number of scenarios regarding networks and the order of the rules. This provides a lot of flexibility
for administrators to tune the security to their specific needs if desired.
[networks]: #networks
##### Examples
*Require [two_factor](#two_factor) for all clients other than internal clients and `112.134.145.167`. The first two
@ -394,6 +411,8 @@ It's important when configuring resource rules that you enclose them in quotes o
with escaping the expressions. Failure to do so may prevent Authelia from starting. It's technically optional but will
likely save you a lot of time if you do it for all resource rules.
[resources]: #resources
##### Examples
*Applies the [bypass](#bypass) policy when the domain is `app.example.com` and the url is `/api`, or starts with either
@ -408,59 +427,176 @@ access_control:
- '^/api([/?].*)?$'
```
#### query
{{< confkey type="list(list(object))" required="no" >}}
The query criteria is an advanced criteria which can allow configuration of rules that match specific query argument
keys against various rules. It's recommended to use [resources](#resources) rules instead for basic needs.
The format of this rule is unique in as much as it is a list of lists. The logic behind this format is to allow for both
`OR` and `AND` logic. The first level of the list defines the `OR` logic, and the second level defines the `AND` logic.
Additionally each level of these lists does not have to be explicitly defined.
##### key
{{< confkey type="string" required="yes" >}}
The query argument key to check.
##### value
{{< confkey type="string" required="situational" >}}
The value to match against. This is required unless the operator is `absent` or `present`. It's recommended this value
is always quoted as per the examples.
##### operator
{{< confkey type="string" required="situational" >}}
The rule operator for this rule. Valid operators can be found in the
[Rule Operators](../../reference/guides/rule-operators.md#operators) reference guide.
If [key](#key) and [value](#value) are specified this defaults to `equal`, otherwise if [key](#key) is specified it
defaults to `present`.
##### Examples
```yaml
access_control:
rules:
- domain: app.example.com
policy: bypass
query:
- - operator: 'present'
key: 'secure'
- operator: 'absent'
key: 'insecure'
- - operator: 'pattern'
key: 'token'
value: '^(abc123|zyx789)$'
- operator: 'not pattern'
key: 'random'
value: '^(1|2)$'
```
## Policies
The policy of the first matching rule in the configured list decides the policy applied to the request, if no rule
matches the request the [default_policy](#default_policy) is applied.
[policies]: #policies
### deny
This is the policy applied by default, and is what we recommend as the default policy for all installs. Its effect
is literally to deny the user access to the resource. Additionally you can use this policy to conditionally deny
access in desired situations. Examples include denying access to an API that has no authentication mechanism built in.
[deny]: #deny
### bypass
This policy skips all authentication and allows anyone to use the resource. This policy is not available with a rule
that includes a [subject](#subject) restriction because the minimum authentication level required to obtain information
about the subject is [one_factor](#one_factor).
that includes a [subject] restriction because the minimum authentication level required to obtain information
about the subject is [one_factor]. See [Rule Matching Concept 2] for more information.
#### bypass and user identity
The [bypass](#bypass) policy cannot be used when the rule uses a criteria that requires we know the users identity. This
means:
* If the rule defines [subjects](#subject) criteria
* If the rule defines [domain regex](#domain_regex) criteria which contains either the user or group named match groups
This is because these criteria types require knowing who the user is in order to determine if their identity matches the
request. This information can only be known after 1FA, which means the minimum policy that can be used logically is
[one_factor](#one_factor).
[bypass]: #bypass
### one_factor
This policy requires the user at minimum complete 1FA successfully (username and password). This means if they have
performed 2FA then they will be allowed to access the resource.
[one_factor]: #one_factor
### two_factor
This policy requires the user to complete 2FA successfully. This is currently the highest level of authentication
policy available.
[two_factor]: #two_factor
## Rule Matching
There are two important concepts to understand when it comes to rule matching. This section covers these concepts.
You can easily evaluate if your access control rules section matches a given request, and why it doesn't match using the
[authelia access-control check-policy](../../reference/cli/authelia/authelia_access-control_check-policy.md) command.
### Rule Matching Concept 1: Sequential Order
Rules are matched in sequential order. The first entry in the list where all criteria match is the rule which is applied.
Some rule criteria additionally allow for a list of criteria, when one of these criteria in the list match a request that
criteria is considered a match for that specific rule.
This is particularly __important__ for bypass rules. Bypass rules should generally appear near the top of the rules
list. However you need to carefully evaluate your rule list __in order__ to see which rule matches a particular
scenario. A comprehensive understanding of how rules apply is also recommended.
For example the following rule will consider requests for either `example.com` or any subdomain of `example.com` a match
if they have a path of exactly `/api` or if they start with `/api/`. This means that the second rule for
`app.example.com` will not be considered if the request is to `https://app.example.com/api` because the first rule is
a match for that request.
```yaml
- domains:
- 'example.com'
- '*.example.com'
policy: bypass
resources:
- '^/api$'
- '^/api/'
- domains:
- 'app.example.com'
policy: two_factor
```
[Rule Matching Concept 1]: #rule-matching-concept-1-sequential-order
### Rule Matching Concept 2: Subject Criteria Requires Authentication
Rules that have subject reliant elements require authentication to determine if they match. Due to this these rules
must not be used with the [bypass] policy. The criteria which have subject reliant elements are:
* The [subject] criteria itself
* The [domain_regex] criteria when it contains the [Named Regex Groups].
In addition if the rule has a subject criteria but all other criteria match then the user will be immediately forwarded
for authentication if no prior rules match the request per [Rule Matching Concept 1]. This means if you have two
identical rules, and one of them has a subject based reliant criteria, and the other one is a [bypass] rule then the
[bypass] rule should generally come first.
[Rule Matching Concept 2]: #rule-matching-concept-2-subject-criteria-requires-authentication
## Named Regex Groups
Some criteria allow matching named regex groups. These are the groups we accept:
| Group Name | Match Value |
|:----------:|:-----------------:|
| User | username |
| Group | groups (contains) |
| Group Name | Match Value | Match Type |
|:----------:|:-----------:|:-----------:|
| User | username | Equals |
| Group | groups | Has (Equal) |
For the group name `Group` the regex pattern matches if the user has the specific group name matching the pattern. Both
regex groups are case-insensitive due to the fact that the regex groups are used in domain criteria and domain names
Named regex groups are represented with the syntax `(?P<User>\w+)` where `User` is the group name from the table above,
and `\w+` is the pattern for the area of the pattern that should be compared to the match value.
The match type `Equals` matches if the value extracted from the pattern is equal to the match value. The match type
`Has (Equal)` matches if the value extracted from the pattern is equal to one of the values in the match value (the
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).
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
alphanumeric (including spaces).
[Named Regex Groups]: #named-regex-groups
## Detailed example
Here is a detailed example of an example access control section:

View File

@ -88,7 +88,7 @@ especially for containerized deployments.*
The secret key used to encrypt session data in Redis.
It's __strongly recommended__ this is a
[Random Alphanumeric String](../miscellaneous/guides.md#generating-a-random-alphanumeric-string) with 64 or more
[Random Alphanumeric String](../../reference/guides/generating-secure-values.md#generating-a-random-alphanumeric-string) with 64 or more
characters.
### expiration

View File

@ -34,6 +34,74 @@ session:
server_name: myredis.example.com
skip_verify: false
minimum_version: TLS1.2
maximum_version: TLS1.3
certificate_chain: |
-----BEGIN CERTIFICATE-----
MIIC5jCCAc6gAwIBAgIRAK4Sj7FiN6PXo/urPfO4E7owDQYJKoZIhvcNAQELBQAw
EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAPKv3pSyP4ozGEiVLJ14dIWFCEGEgq7WUMI0SZZqQA2ID0L59U/Q
/Usyy7uC9gfMUzODTpANtkOjFQcQAsxlR1FOjVBrX5QgjSvXwbQn3DtwMA7XWSl6
LuYx2rBYSlMSN5UZQm/RxMtXfLK2b51WgEEYDFi+nECSqKzR4R54eOPkBEWRfvuY
91AMjlhpivg8e4JWkq4LVQUKbmiFYwIdK8XQiN4blY9WwXwJFYs5sQ/UYMwBFi0H
kWOh7GEjfxgoUOPauIueZSMSlQp7zqAH39N0ZSYb6cS0Npj57QoWZSY3ak87ebcR
Nf4rCvZLby7LoN7qYCKxmCaDD3x2+NYpWH8CAwEAAaM1MDMwDgYDVR0PAQH/BAQD
AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcN
AQELBQADggEBAHSITqIQSNzonFl3DzxHPEzr2hp6peo45buAAtu8FZHoA+U7Icfh
/ZXjPg7Xz+hgFwM/DTNGXkMWacQA/PaNWvZspgRJf2AXvNbMSs2UQODr7Tbv+Fb4
lyblmMUNYFMCFVAMU0eIxXAFq2qcwv8UMcQFT0Z/35s6PVOakYnAGGQjTfp5Ljuq
wsdc/xWmM0cHWube6sdRRUD7SY20KU/kWzl8iFO0VbSSrDf1AlEhnLEkp1SPaxXg
OdBnl98MeoramNiJ7NT6Jnyb3zZ578fjaWfThiBpagItI8GZmG4s4Ovh2JbheN8i
ZsjNr9jqHTjhyLVbDRlmJzcqoj4JhbKs6/I^invalid DO NOT USE=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDBDCCAeygAwIBAgIRALJsPg21kA0zY4F1wUCIuoMwDQYJKoZIhvcNAQELBQAw
EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAMXHBvVxUzYk0u34/DINMSF+uiOekKOAjOrC6Mi9Ww8ytPVO7t2S
zfTvM+XnEJqkFQFgimERfG/eGhjF9XIEY6LtnXe8ATvOK4nTwdufzBaoeQu3Gd50
5VXr6OHRo//ErrGvFXwP3g8xLePABsi/fkH3oDN+ztewOBMDzpd+KgTrk8ysv2ou
kNRMKFZZqASvCgv0LD5KWvUCnL6wgf1oTXG7aztduA4oSkUP321GpOmBC5+5ElU7
ysoRzvD12o9QJ/IfEaulIX06w9yVMo60C/h6A3U6GdkT1SiyTIqR7v7KU/IWd/Qi
Lfftcj91VhCmJ73Meff2e2S2PrpjdXbG5FMCAwEAAaNTMFEwDgYDVR0PAQH/BAQD
AgKkMA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
Z7AtA3mzFc0InSBA5fiMfeLXA3owDQYJKoZIhvcNAQELBQADggEBAEE5hm1mtlk/
kviCoHH4evbpw7rxPxDftIQlqYTtvMM4eWY/6icFoSZ4fUHEWYyps8SsPu/8f2tf
71LGgZn0FdHi1QU2H8m0HHK7TFw+5Q6RLrLdSyk0PItJ71s9en7r8pX820nAFEHZ
HkOSfJZ7B5hFgUDkMtVM6bardXAhoqcMk4YCU96e9d4PB4eI+xGc+mNuYvov3RbB
D0s8ICyojeyPVLerz4wHjZu68Z5frAzhZ68YbzNs8j2fIBKKHkHyLG1iQyF+LJVj
2PjCP+auJsj6fQQpMGoyGtpLcSDh+ptcTngUD8JsWipzTCjmaNqdPHAOYmcgtf4b
qocikt3WAdU^invalid DO NOT USE=
-----END CERTIFICATE-----
private_key: |
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA8q/elLI/ijMYSJUsnXh0hYUIQYSCrtZQwjRJlmpADYgPQvn1
T9D9SzLLu4L2B8xTM4NOkA22Q6MVBxACzGVHUU6NUGtflCCNK9fBtCfcO3AwDtdZ
KXou5jHasFhKUxI3lRlCb9HEy1d8srZvnVaAQRgMWL6cQJKorNHhHnh44+QERZF+
+5j3UAyOWGmK+Dx7glaSrgtVBQpuaIVjAh0rxdCI3huVj1bBfAkVizmxD9RgzAEW
LQeRY6HsYSN/GChQ49q4i55lIxKVCnvOoAff03RlJhvpxLQ2mPntChZlJjdqTzt5
txE1/isK9ktvLsug3upgIrGYJoMPfHb41ilYfwIDAQABAoIBAQDTOdFf2JjHH1um
aPgRAvNf9v7Nj5jytaRKs5nM6iNf46ls4QPreXnMhqSeSwj6lpNgBYxOgzC9Q+cc
Y4ob/paJJPaIJTxmP8K/gyWcOQlNToL1l+eJ20eQoZm23NGr5fIsunSBwLEpTrdB
ENqqtcwhW937K8Pxy/Q1nuLyU2bc6Tn/ivLozc8n27dpQWWKh8537VY7ancIaACr
LJJLYxKqhQpjtBWAyCDvZQirnAOm9KnvIHaGXIswCZ4Xbsu0Y9NL+woARPyRVQvG
jfxy4EmO9s1s6y7OObSukwKDSNihAKHx/VIbvVWx8g2Lv5fGOa+J2Y7o9Qurs8t5
BQwMTt0BAoGBAPUw5Z32EszNepAeV3E2mPFUc5CLiqAxagZJuNDO2pKtyN29ETTR
Ma4O1cWtGb6RqcNNN/Iukfkdk27Q5nC9VJSUUPYelOLc1WYOoUf6oKRzE72dkMQV
R4bf6TkjD+OVR17fAfkswkGahZ5XA7j48KIQ+YC4jbnYKSxZTYyKPjH/AoGBAP1i
tqXt36OVlP+y84wWqZSjMelBIVa9phDVGJmmhz3i1cMni8eLpJzWecA3pfnG6Tm9
ze5M4whASleEt+M00gEvNaU9ND+z0wBfi+/DwJYIbv8PQdGrBiZFrPhTPjGQUldR
lXccV2meeLZv7TagVxSi3DO6dSJfSEHyemd5j9mBAoGAX8Hv+0gOQZQCSOTAq8Nx
6dZcp9gHlNaXnMsP9eTDckOSzh636JPGvj6m+GPJSSbkURUIQ3oyokMNwFqvlNos
fTaLhAOfjBZI9WnDTTQxpugWjphJ4HqbC67JC/qIiw5S6FdaEvGLEEoD4zoChywZ
9oGAn+fz2d/0/JAH/FpFPgsCgYEAp/ipZgPzziiZ9ov1wbdAQcWRj7RaWnssPFpX
jXwEiXT3CgEMO4MJ4+KWIWOChrti3qFBg6i6lDyyS6Qyls7sLFbUdC7HlTcrOEMe
rBoTcCI1GqZNlqWOVQ65ZIEiaI7o1vPBZo2GMQEZuq8mDKFsOMThvvTrM5cAep84
n6HJR4ECgYABWcbsSnr0MKvVth/inxjbKapbZnp2HUCuw87Ie5zK2Of/tbC20wwk
yKw3vrGoE3O1t1g2m2tn8UGGASeZ842jZWjIODdSi5+icysQGuULKt86h/woz2SQ
27GoE2i5mh6Yez6VAYbUuns3FcwIsMyWLq043Tu2DNkx9ijOOAuQzw^invalid..
DO NOT USE==
-----END RSA PRIVATE KEY-----
high_availability:
sentinel_name: mysentinel
# If `sentinel_username` is supplied, Authelia will connect using ACL-based
@ -86,7 +154,7 @@ especially for containerized deployments.*
The password for [redis authentication](https://redis.io/commands/auth).
It's __strongly recommended__ this is a
[Random Alphanumeric String](../miscellaneous/guides.md#generating-a-random-alphanumeric-string) with 64 or more
[Random Alphanumeric String](../../reference/guides/generating-secure-values.md#generating-a-random-alphanumeric-string) with 64 or more
characters and the user password is changed to this value.
### database_index
@ -145,7 +213,7 @@ authenticate to the Redis Sentinel with ACL-based authentication. Otherwise, thi
authentication.
It's __strongly recommended__ this is a
[Random Alphanumeric String](../miscellaneous/guides.md#generating-a-random-alphanumeric-string) with 64 or more
[Random Alphanumeric String](../../reference/guides/generating-secure-values.md#generating-a-random-alphanumeric-string) with 64 or more
characters and the user password is changed to this value.
#### nodes

View File

@ -44,10 +44,10 @@ value, and use that to encrypt the data with the AES-GCM 256bit algorithm.
The minimum length of this key is 20 characters.
It's __strongly recommended__ this is a
[Random Alphanumeric String](../miscellaneous/guides.md#generating-a-random-alphanumeric-string) with 64 or more
[Random Alphanumeric String](../../reference/guides/generating-secure-values.md#generating-a-random-alphanumeric-string) with 64 or more
characters.
See [securty measures](../../overview/security/measures.md#storage-security-measures) for more information.
See [security measures](../../overview/security/measures.md#storage-security-measures) for more information.
### postgres

View File

@ -34,3 +34,4 @@ this instance if you wanted to downgrade to pre1 you would need to use an Authel
| 3 | 4.34.2 | WebAuthn - fix V2 migration kid column length and provide migration path for anyone on V2 |
| 4 | 4.35.0 | Added OpenID Connect storage tables and opaque user identifier tables |
| 5 | 4.35.1 | Fixed the oauth2_consent_session table to accept NULL subjects for users who are not yet signed in |
| 6 | 4.37.0 | Adjusted the OpenID Connect tables to allow pre-configured consent improvements |

View File

@ -17,12 +17,12 @@ aliases:
## Version support
When using MySQL or MariaDB we recommend using the latest version that is officially supported by the MySQL or MariaDB
developers. We also suggest checking out [PostgreSQL](postgres.md) as an alternative.
When using [MySQL] or [MariaDB] we recommend using the latest version that is officially supported by the [MySQL] or
[MariaDB] developers. We also suggest checking out [PostgreSQL](postgres.md) as an alternative.
The oldest versions that have been tested are MySQL 5.7 and MariaDB 10.6.
The oldest versions that have been tested are [MySQL] 5.7 and [MariaDB] 10.6.
If using MySQL 5.7 or MariaDB 10.6 you may be required to adjust the `explicit_defaults_for_timestamp` setting. This
If using [MySQL] 5.7 or [MariaDB] 10.6 you may be required to adjust the `explicit_defaults_for_timestamp` setting. This
will be evident when the container starts with an error similar to `Error 1067: Invalid default value for 'exp'`. You
can adjust this setting in the mysql.cnf file like so:
@ -43,6 +43,78 @@ storage:
username: authelia
password: mypassword
timeout: 5s
tls:
server_name: mysql.example.com
skip_verify: false
minimum_version: TLS1.2
maximum_version: TLS1.3
certificate_chain: |
-----BEGIN CERTIFICATE-----
MIIC5jCCAc6gAwIBAgIRAK4Sj7FiN6PXo/urPfO4E7owDQYJKoZIhvcNAQELBQAw
EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAPKv3pSyP4ozGEiVLJ14dIWFCEGEgq7WUMI0SZZqQA2ID0L59U/Q
/Usyy7uC9gfMUzODTpANtkOjFQcQAsxlR1FOjVBrX5QgjSvXwbQn3DtwMA7XWSl6
LuYx2rBYSlMSN5UZQm/RxMtXfLK2b51WgEEYDFi+nECSqKzR4R54eOPkBEWRfvuY
91AMjlhpivg8e4JWkq4LVQUKbmiFYwIdK8XQiN4blY9WwXwJFYs5sQ/UYMwBFi0H
kWOh7GEjfxgoUOPauIueZSMSlQp7zqAH39N0ZSYb6cS0Npj57QoWZSY3ak87ebcR
Nf4rCvZLby7LoN7qYCKxmCaDD3x2+NYpWH8CAwEAAaM1MDMwDgYDVR0PAQH/BAQD
AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcN
AQELBQADggEBAHSITqIQSNzonFl3DzxHPEzr2hp6peo45buAAtu8FZHoA+U7Icfh
/ZXjPg7Xz+hgFwM/DTNGXkMWacQA/PaNWvZspgRJf2AXvNbMSs2UQODr7Tbv+Fb4
lyblmMUNYFMCFVAMU0eIxXAFq2qcwv8UMcQFT0Z/35s6PVOakYnAGGQjTfp5Ljuq
wsdc/xWmM0cHWube6sdRRUD7SY20KU/kWzl8iFO0VbSSrDf1AlEhnLEkp1SPaxXg
OdBnl98MeoramNiJ7NT6Jnyb3zZ578fjaWfThiBpagItI8GZmG4s4Ovh2JbheN8i
ZsjNr9jqHTjhyLVbDRlmJzcqoj4JhbKs6/I^invalid DO NOT USE=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDBDCCAeygAwIBAgIRALJsPg21kA0zY4F1wUCIuoMwDQYJKoZIhvcNAQELBQAw
EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAMXHBvVxUzYk0u34/DINMSF+uiOekKOAjOrC6Mi9Ww8ytPVO7t2S
zfTvM+XnEJqkFQFgimERfG/eGhjF9XIEY6LtnXe8ATvOK4nTwdufzBaoeQu3Gd50
5VXr6OHRo//ErrGvFXwP3g8xLePABsi/fkH3oDN+ztewOBMDzpd+KgTrk8ysv2ou
kNRMKFZZqASvCgv0LD5KWvUCnL6wgf1oTXG7aztduA4oSkUP321GpOmBC5+5ElU7
ysoRzvD12o9QJ/IfEaulIX06w9yVMo60C/h6A3U6GdkT1SiyTIqR7v7KU/IWd/Qi
Lfftcj91VhCmJ73Meff2e2S2PrpjdXbG5FMCAwEAAaNTMFEwDgYDVR0PAQH/BAQD
AgKkMA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
Z7AtA3mzFc0InSBA5fiMfeLXA3owDQYJKoZIhvcNAQELBQADggEBAEE5hm1mtlk/
kviCoHH4evbpw7rxPxDftIQlqYTtvMM4eWY/6icFoSZ4fUHEWYyps8SsPu/8f2tf
71LGgZn0FdHi1QU2H8m0HHK7TFw+5Q6RLrLdSyk0PItJ71s9en7r8pX820nAFEHZ
HkOSfJZ7B5hFgUDkMtVM6bardXAhoqcMk4YCU96e9d4PB4eI+xGc+mNuYvov3RbB
D0s8ICyojeyPVLerz4wHjZu68Z5frAzhZ68YbzNs8j2fIBKKHkHyLG1iQyF+LJVj
2PjCP+auJsj6fQQpMGoyGtpLcSDh+ptcTngUD8JsWipzTCjmaNqdPHAOYmcgtf4b
qocikt3WAdU^invalid DO NOT USE=
-----END CERTIFICATE-----
private_key: |
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA8q/elLI/ijMYSJUsnXh0hYUIQYSCrtZQwjRJlmpADYgPQvn1
T9D9SzLLu4L2B8xTM4NOkA22Q6MVBxACzGVHUU6NUGtflCCNK9fBtCfcO3AwDtdZ
KXou5jHasFhKUxI3lRlCb9HEy1d8srZvnVaAQRgMWL6cQJKorNHhHnh44+QERZF+
+5j3UAyOWGmK+Dx7glaSrgtVBQpuaIVjAh0rxdCI3huVj1bBfAkVizmxD9RgzAEW
LQeRY6HsYSN/GChQ49q4i55lIxKVCnvOoAff03RlJhvpxLQ2mPntChZlJjdqTzt5
txE1/isK9ktvLsug3upgIrGYJoMPfHb41ilYfwIDAQABAoIBAQDTOdFf2JjHH1um
aPgRAvNf9v7Nj5jytaRKs5nM6iNf46ls4QPreXnMhqSeSwj6lpNgBYxOgzC9Q+cc
Y4ob/paJJPaIJTxmP8K/gyWcOQlNToL1l+eJ20eQoZm23NGr5fIsunSBwLEpTrdB
ENqqtcwhW937K8Pxy/Q1nuLyU2bc6Tn/ivLozc8n27dpQWWKh8537VY7ancIaACr
LJJLYxKqhQpjtBWAyCDvZQirnAOm9KnvIHaGXIswCZ4Xbsu0Y9NL+woARPyRVQvG
jfxy4EmO9s1s6y7OObSukwKDSNihAKHx/VIbvVWx8g2Lv5fGOa+J2Y7o9Qurs8t5
BQwMTt0BAoGBAPUw5Z32EszNepAeV3E2mPFUc5CLiqAxagZJuNDO2pKtyN29ETTR
Ma4O1cWtGb6RqcNNN/Iukfkdk27Q5nC9VJSUUPYelOLc1WYOoUf6oKRzE72dkMQV
R4bf6TkjD+OVR17fAfkswkGahZ5XA7j48KIQ+YC4jbnYKSxZTYyKPjH/AoGBAP1i
tqXt36OVlP+y84wWqZSjMelBIVa9phDVGJmmhz3i1cMni8eLpJzWecA3pfnG6Tm9
ze5M4whASleEt+M00gEvNaU9ND+z0wBfi+/DwJYIbv8PQdGrBiZFrPhTPjGQUldR
lXccV2meeLZv7TagVxSi3DO6dSJfSEHyemd5j9mBAoGAX8Hv+0gOQZQCSOTAq8Nx
6dZcp9gHlNaXnMsP9eTDckOSzh636JPGvj6m+GPJSSbkURUIQ3oyokMNwFqvlNos
fTaLhAOfjBZI9WnDTTQxpugWjphJ4HqbC67JC/qIiw5S6FdaEvGLEEoD4zoChywZ
9oGAn+fz2d/0/JAH/FpFPgsCgYEAp/ipZgPzziiZ9ov1wbdAQcWRj7RaWnssPFpX
jXwEiXT3CgEMO4MJ4+KWIWOChrti3qFBg6i6lDyyS6Qyls7sLFbUdC7HlTcrOEMe
rBoTcCI1GqZNlqWOVQ65ZIEiaI7o1vPBZo2GMQEZuq8mDKFsOMThvvTrM5cAep84
n6HJR4ECgYABWcbsSnr0MKvVth/inxjbKapbZnp2HUCuw87Ie5zK2Of/tbC20wwk
yKw3vrGoE3O1t1g2m2tn8UGGASeZ842jZWjIODdSi5+icysQGuULKt86h/woz2SQ
27GoE2i5mh6Yez6VAYbUuns3FcwIsMyWLq043Tu2DNkx9ijOOAuQzw^invalid..
DO NOT USE==
-----END RSA PRIVATE KEY-----
```
## Options
@ -55,12 +127,22 @@ See the [encryption_key docs](introduction.md#encryption_key).
{{< confkey type="string" default="localhost" required="no" >}}
The database server host.
The database server host. This can also be a unix socket.
If utilising an IPv6 literal address it must be enclosed by square brackets and quoted:
```yaml
host: "[fd00:1111:2222:3333::1]"
storage:
mysql:
host: "[fd00:1111:2222:3333::1]"
```
If utilizing a unix socket it must have the `/` prefix:
```yaml
storage:
mysql:
host: /var/run/mysqld.sock
```
### port
@ -92,7 +174,7 @@ especially for containerized deployments.*
The password paired with the [username](#username) used to connect to the database.
It's __strongly recommended__ this is a
[Random Alphanumeric String](../miscellaneous/guides.md#generating-a-random-alphanumeric-string) with 64 or more
[Random Alphanumeric String](../../reference/guides/generating-secure-values.md#generating-a-random-alphanumeric-string) with 64 or more
characters and the user password is changed to this value.
### timeout
@ -100,3 +182,11 @@ characters and the user password is changed to this value.
{{< confkey type="duration" default="5s" required="no" >}}
The SQL connection timeout.
### tls
If defined enables connecting to [MySQL] or [MariaDB] over a TLS socket, and additionally controls the TLS connection
validation process. You can see how to configure the tls section [here](../prologue/common.md#tls-configuration).
[MySQL]: https://www.mysql.com/
[MariaDB]: https://mariadb.org/

View File

@ -16,10 +16,10 @@ aliases:
## Version support
See [PostgreSQL support](https://www.postgresql.org/support/versioning/) for the versions supported by PostgreSQL. We
recommend the *current minor* version of one of the versions supported by PostgreSQL.
See [PostgreSQL support](https://www.postgresql.org/support/versioning/) for the versions supported by [PostgreSQL]. We
recommend the *current minor* version of one of the versions supported by [PostgreSQL].
The versions of PostgreSQL that should be supported by Authelia are:
The versions of [PostgreSQL] that should be supported by Authelia are:
* 14
* 13
@ -40,11 +40,78 @@ storage:
schema: public
username: authelia
password: mypassword
ssl:
mode: disable
root_certificate: /path/to/root_cert.pem
certificate: /path/to/cert.pem
key: /path/to/key.pem
tls:
server_name: psotgres.example.com
skip_verify: false
minimum_version: TLS1.2
maximum_version: TLS1.3
certificate_chain: |
-----BEGIN CERTIFICATE-----
MIIC5jCCAc6gAwIBAgIRAK4Sj7FiN6PXo/urPfO4E7owDQYJKoZIhvcNAQELBQAw
EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAPKv3pSyP4ozGEiVLJ14dIWFCEGEgq7WUMI0SZZqQA2ID0L59U/Q
/Usyy7uC9gfMUzODTpANtkOjFQcQAsxlR1FOjVBrX5QgjSvXwbQn3DtwMA7XWSl6
LuYx2rBYSlMSN5UZQm/RxMtXfLK2b51WgEEYDFi+nECSqKzR4R54eOPkBEWRfvuY
91AMjlhpivg8e4JWkq4LVQUKbmiFYwIdK8XQiN4blY9WwXwJFYs5sQ/UYMwBFi0H
kWOh7GEjfxgoUOPauIueZSMSlQp7zqAH39N0ZSYb6cS0Npj57QoWZSY3ak87ebcR
Nf4rCvZLby7LoN7qYCKxmCaDD3x2+NYpWH8CAwEAAaM1MDMwDgYDVR0PAQH/BAQD
AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcN
AQELBQADggEBAHSITqIQSNzonFl3DzxHPEzr2hp6peo45buAAtu8FZHoA+U7Icfh
/ZXjPg7Xz+hgFwM/DTNGXkMWacQA/PaNWvZspgRJf2AXvNbMSs2UQODr7Tbv+Fb4
lyblmMUNYFMCFVAMU0eIxXAFq2qcwv8UMcQFT0Z/35s6PVOakYnAGGQjTfp5Ljuq
wsdc/xWmM0cHWube6sdRRUD7SY20KU/kWzl8iFO0VbSSrDf1AlEhnLEkp1SPaxXg
OdBnl98MeoramNiJ7NT6Jnyb3zZ578fjaWfThiBpagItI8GZmG4s4Ovh2JbheN8i
ZsjNr9jqHTjhyLVbDRlmJzcqoj4JhbKs6/I^invalid DO NOT USE=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDBDCCAeygAwIBAgIRALJsPg21kA0zY4F1wUCIuoMwDQYJKoZIhvcNAQELBQAw
EzERMA8GA1UEChMIQXV0aGVsaWEwHhcNNzAwMTAxMDAwMDAwWhcNNzEwMTAxMDAw
MDAwWjATMREwDwYDVQQKEwhBdXRoZWxpYTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAMXHBvVxUzYk0u34/DINMSF+uiOekKOAjOrC6Mi9Ww8ytPVO7t2S
zfTvM+XnEJqkFQFgimERfG/eGhjF9XIEY6LtnXe8ATvOK4nTwdufzBaoeQu3Gd50
5VXr6OHRo//ErrGvFXwP3g8xLePABsi/fkH3oDN+ztewOBMDzpd+KgTrk8ysv2ou
kNRMKFZZqASvCgv0LD5KWvUCnL6wgf1oTXG7aztduA4oSkUP321GpOmBC5+5ElU7
ysoRzvD12o9QJ/IfEaulIX06w9yVMo60C/h6A3U6GdkT1SiyTIqR7v7KU/IWd/Qi
Lfftcj91VhCmJ73Meff2e2S2PrpjdXbG5FMCAwEAAaNTMFEwDgYDVR0PAQH/BAQD
AgKkMA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
Z7AtA3mzFc0InSBA5fiMfeLXA3owDQYJKoZIhvcNAQELBQADggEBAEE5hm1mtlk/
kviCoHH4evbpw7rxPxDftIQlqYTtvMM4eWY/6icFoSZ4fUHEWYyps8SsPu/8f2tf
71LGgZn0FdHi1QU2H8m0HHK7TFw+5Q6RLrLdSyk0PItJ71s9en7r8pX820nAFEHZ
HkOSfJZ7B5hFgUDkMtVM6bardXAhoqcMk4YCU96e9d4PB4eI+xGc+mNuYvov3RbB
D0s8ICyojeyPVLerz4wHjZu68Z5frAzhZ68YbzNs8j2fIBKKHkHyLG1iQyF+LJVj
2PjCP+auJsj6fQQpMGoyGtpLcSDh+ptcTngUD8JsWipzTCjmaNqdPHAOYmcgtf4b
qocikt3WAdU^invalid DO NOT USE=
-----END CERTIFICATE-----
private_key: |
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA8q/elLI/ijMYSJUsnXh0hYUIQYSCrtZQwjRJlmpADYgPQvn1
T9D9SzLLu4L2B8xTM4NOkA22Q6MVBxACzGVHUU6NUGtflCCNK9fBtCfcO3AwDtdZ
KXou5jHasFhKUxI3lRlCb9HEy1d8srZvnVaAQRgMWL6cQJKorNHhHnh44+QERZF+
+5j3UAyOWGmK+Dx7glaSrgtVBQpuaIVjAh0rxdCI3huVj1bBfAkVizmxD9RgzAEW
LQeRY6HsYSN/GChQ49q4i55lIxKVCnvOoAff03RlJhvpxLQ2mPntChZlJjdqTzt5
txE1/isK9ktvLsug3upgIrGYJoMPfHb41ilYfwIDAQABAoIBAQDTOdFf2JjHH1um
aPgRAvNf9v7Nj5jytaRKs5nM6iNf46ls4QPreXnMhqSeSwj6lpNgBYxOgzC9Q+cc
Y4ob/paJJPaIJTxmP8K/gyWcOQlNToL1l+eJ20eQoZm23NGr5fIsunSBwLEpTrdB
ENqqtcwhW937K8Pxy/Q1nuLyU2bc6Tn/ivLozc8n27dpQWWKh8537VY7ancIaACr
LJJLYxKqhQpjtBWAyCDvZQirnAOm9KnvIHaGXIswCZ4Xbsu0Y9NL+woARPyRVQvG
jfxy4EmO9s1s6y7OObSukwKDSNihAKHx/VIbvVWx8g2Lv5fGOa+J2Y7o9Qurs8t5
BQwMTt0BAoGBAPUw5Z32EszNepAeV3E2mPFUc5CLiqAxagZJuNDO2pKtyN29ETTR
Ma4O1cWtGb6RqcNNN/Iukfkdk27Q5nC9VJSUUPYelOLc1WYOoUf6oKRzE72dkMQV
R4bf6TkjD+OVR17fAfkswkGahZ5XA7j48KIQ+YC4jbnYKSxZTYyKPjH/AoGBAP1i
tqXt36OVlP+y84wWqZSjMelBIVa9phDVGJmmhz3i1cMni8eLpJzWecA3pfnG6Tm9
ze5M4whASleEt+M00gEvNaU9ND+z0wBfi+/DwJYIbv8PQdGrBiZFrPhTPjGQUldR
lXccV2meeLZv7TagVxSi3DO6dSJfSEHyemd5j9mBAoGAX8Hv+0gOQZQCSOTAq8Nx
6dZcp9gHlNaXnMsP9eTDckOSzh636JPGvj6m+GPJSSbkURUIQ3oyokMNwFqvlNos
fTaLhAOfjBZI9WnDTTQxpugWjphJ4HqbC67JC/qIiw5S6FdaEvGLEEoD4zoChywZ
9oGAn+fz2d/0/JAH/FpFPgsCgYEAp/ipZgPzziiZ9ov1wbdAQcWRj7RaWnssPFpX
jXwEiXT3CgEMO4MJ4+KWIWOChrti3qFBg6i6lDyyS6Qyls7sLFbUdC7HlTcrOEMe
rBoTcCI1GqZNlqWOVQ65ZIEiaI7o1vPBZo2GMQEZuq8mDKFsOMThvvTrM5cAep84
n6HJR4ECgYABWcbsSnr0MKvVth/inxjbKapbZnp2HUCuw87Ie5zK2Of/tbC20wwk
yKw3vrGoE3O1t1g2m2tn8UGGASeZ842jZWjIODdSi5+icysQGuULKt86h/woz2SQ
27GoE2i5mh6Yez6VAYbUuns3FcwIsMyWLq043Tu2DNkx9ijOOAuQzw^invalid..
DO NOT USE==
-----END RSA PRIVATE KEY-----
```
## Options
@ -57,12 +124,22 @@ See the [encryption_key docs](introduction.md#encryption_key).
{{< confkey type="string" required="yes" >}}
The database server host.
The database server host. This can also be a unix socket.
If utilising an IPv6 literal address it must be enclosed by square brackets and quoted:
```yaml
host: "[fd00:1111:2222:3333::1]"
storage:
postgres:
host: "[fd00:1111:2222:3333::1]"
```
If utilizing a unix socket it must have the `/` prefix:
```yaml
storage:
postgres:
host: /var/run/postgres.sock
```
### port
@ -101,7 +178,7 @@ especially for containerized deployments.*
The password paired with the [username](#username) used to connect to the database.
It's __strongly recommended__ this is a
[Random Alphanumeric String](../miscellaneous/guides.md#generating-a-random-alphanumeric-string) with 64 or more
[Random Alphanumeric String](../../reference/guides/generating-secure-values.md#generating-a-random-alphanumeric-string) with 64 or more
characters and the user password is changed to this value.
### timeout
@ -110,32 +187,9 @@ characters and the user password is changed to this value.
The SQL connection timeout.
### ssl
### tls
#### mode
If defined enables connecting to [PostgreSQL] over a TLS socket, and additionally controls the TLS connection
validation process. You can see how to configure the tls section [here](../prologue/common.md#tls-configuration).
{{< confkey type="string" default="disable" required="no" >}}
SSL mode configures how to handle SSL connections with Postgres.
Valid options are 'disable', 'require', 'verify-ca', or 'verify-full'.
See the [PostgreSQL Documentation](https://www.postgresql.org/docs/12/libpq-ssl.html)
or [pgx - PostgreSQL Driver and Toolkit Documentation](https://pkg.go.dev/github.com/jackc/pgx?tab=doc)
for more information.
#### root_certificate
{{< confkey type="string" required="no" >}}
The optional location of the root certificate file encoded in the PEM format for validation purposes.
#### certificate
{{< confkey type="string" required="no" >}}
The optional location of the certificate file encoded in the PEM format for validation purposes.
#### key
{{< confkey type="string" required="no" >}}
The optional location of the key file encoded in the PEM format for authentication purposes.
[PostgreSQL]: https://www.postgresql.org/

View File

@ -25,8 +25,8 @@ telemetry:
read: 4096
write: 4096
timeouts:
read: 2s
write: 2s
read: 6s
write: 6s
idle: 30s
```

View File

@ -0,0 +1,9 @@
---
title: "Guidelines"
description: "Contributing Guidelines"
lead: ""
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
weight: 300
---

View File

@ -1,5 +1,5 @@
---
title: "Commit Message Guidelines"
title: "Commit Message"
description: "Authelia Development Commit Message Guidelines"
lead: "This section covers the git commit message guidelines we use for development."
date: 2021-01-30T19:29:07+11:00
@ -7,11 +7,12 @@ draft: false
images: []
menu:
contributing:
parent: "development"
weight: 231
parent: "guidelines"
weight: 320
toc: true
aliases:
- /docs/contributing/commitmsg-guidelines.html
- /contributing/development/guidelines-commit-message/
---
The reasons for these conventions are as follows:
@ -47,11 +48,13 @@ for, and the structure it must have.
│ │ │
│ │ └─⫸ Summary in present tense. Not capitalized. No period at the end.
│ │
│ └─⫸ Commit Scope: api|authentication|authorization|cmd|commands|configuration|duo|
│ handlers|logging|middlewares|mocks|model|notification|ntp|oidc|
│ regulation|server|session|storage|suites|templates|utils|web
│ └─⫸ Commit Scope: api|autheliabot|authentication|authorization|buildkite|bundler|cmd|
│ codecov|commands|configuration|deps|docker|duo|go|golangci-lint|
│ handlers|logging|metrics|middlewares|mocks|model|notification|npm|ntp|
│ oidc|regulation|renovate|reviewdog|server|session|storage|suites|
│ templates|totp|utils|web
└─⫸ Commit Type: build|ci|docs|feat|fix|perf|refactor|release|test
└─⫸ Commit Type: build|ci|docs|feat|fix|i18n|perf|refactor|release|revert|test
```
The `<type>` and `<summary>` fields are mandatory, the `(<scope>)` field is optional.
@ -65,6 +68,7 @@ The `<type>` and `<summary>` fields are mandatory, the `(<scope>)` field is opti
* __docs__ Documentation only changes
* __feat__ A new feature
* __fix__ A bug fix
* __i18n__ Updating translations or internationalization settings
* __perf__ A code change that improves performance
* __refactor__ A code change that neither fixes a bug nor adds a feature
* __release__ Releasing a new version of Authelia
@ -101,7 +105,7 @@ commit messages).
There are currently a few exceptions to the "use package name" rule:
* `api`: used for changes that change the openapi specification
* `cmd`: used for changes to the `authelia|authelia-scripts|authelia-suites` top level binaries
* `cmd`: used for changes to the `authelia|authelia-gen|authelia-scripts|authelia-suites` top level binaries
* `web`: used for changes to the React based frontend
* none/empty string: useful for `test`, `refactor` and changes that are done across multiple packages
(e.g. `test: add missing unit tests`) and for docs changes that are not related to a specific package

View File

@ -0,0 +1,32 @@
---
title: "Documentation"
description: "Authelia Development Documentation Guidelines"
lead: "This section covers the guidelines we use when writing documentation."
date: 2022-10-02T14:32:16+11:00
draft: false
images: []
menu:
contributing:
parent: "guidelines"
weight: 320
toc: true
---
## Domains
Always use the generic domain (or subdomain of) `example.com` in documentation.
If it's necessary to utilize more than one domain please ask for specific feedback in any PR.
## Certificates
When including certificates in documentation always ensure they are valid for 1 year starting at `Jan 1 00:00:00 1970`.
This ensures the certificate is not valid for multiple reasons.
In addition the guidance for [Private Keys](#private-keys) should be followed.
## Private Keys
Always append invalid data to the END of the PEM block before the base64 padding `=` (if present). The suggested
text is `^invalid DO NOT USE`. This both has an invalid base64 character `^` and has information to communicate that
users should not use the PEM block.

View File

@ -0,0 +1,21 @@
---
title: "Guidelines"
description: "An introduction into guidelines for contributing to the Authelia project."
lead: "An introduction into guidelines for contributing to the Authelia project."
date: 2022-10-02T14:32:16+11:00
draft: false
images: []
menu:
contributing:
parent: "guidelines"
weight: 310
toc: true
---
The guidelines section contains various guidelines for contributing to Authelia. We implement various guidelines via
automatic processes that will provide feedback in the PR, but this does not cover every situation. You will find both
those which are automated and those which are not in this section.
While it's expected that people aim to follow all of these guidelines we understand that there are logical exceptions to
all guidelines and if it makes sense we're likely to agree with you. So if you find a situation where it doesn't make
sense to follow one just let us know your reasoning when you make a PR if it's not obvious.

View File

@ -1,5 +1,5 @@
---
title: "Pull Request Guidelines"
title: "Pull Request"
description: "Authelia Development Pull Request Guidelines"
lead: "This section covers the pull request guidelines."
date: 2022-06-15T17:51:47+10:00
@ -7,9 +7,11 @@ draft: false
images: []
menu:
contributing:
parent: "development"
weight: 232
parent: "guidelines"
weight: 320
toc: true
aliases:
- /contributing/development/guidelines-pull-request/
---
[Pull Request] guidelines are in place in order to maintain consistency and clearly communicate our process for

View File

@ -1,5 +1,5 @@
---
title: "Style Guidelines"
title: "Style"
description: "Authelia Development Style Guidelines"
lead: "This section covers the style guidelines we use for development."
date: 2021-04-11T21:25:03+10:00
@ -7,17 +7,18 @@ draft: false
images: []
menu:
contributing:
parent: "development"
weight: 230
parent: "guidelines"
weight: 320
toc: true
aliases:
- /docs/contributing/style-guide.html
- /contributing/development/guidelines-style/
---
This is a general guide to the code style we aim to abide by. This is by no means an exhaustive list and we're
constantly changing and improving it. This is also a work in progress document.
For our commit messages please see our [Commit Message Guidelines](guidelines-commit-message.md).
For our commit messages please see our [Commit Message Guidelines](../guidelines/commit-message.md).
## Tools

View File

@ -1,5 +1,5 @@
---
title: "Documentation"
title: "Documentation Contributions"
description: "Information on contributing documentation to the Authelia project."
lead: "Authelia has great documentation however there are always things that can be added. This section describes the contribution process for the documentation even though it's incredibly easy."
date: 2022-06-15T17:51:47+10:00
@ -10,6 +10,8 @@ menu:
parent: "prologue"
weight: 130
toc: true
alias:
- /contributing/prologue/documentation
---
## Introduction
@ -38,14 +40,12 @@ It's relatively easy to run the __Authelia__ website locally to test out the cha
The following steps will allow you to run the website on the localhost and view it live in your browser:
1. Run the following commands:
```bash
git clone https://github.com/authelia/authelia.git
cd authelia/docs
npm run install
npm run start
```
```bash
git clone https://github.com/authelia/authelia.git
cd authelia/docs
npm run install
npm run start
```
2. Visit [http://localhost:1313/](http://localhost:1313/) in your browser.
3. Modify pages to see the effects live in your browser.

View File

@ -18,7 +18,7 @@ Contributions to __Authelia__ have four main forms:
* Utilizing GitHub [Issues] or [Discussions] to make commentary about bugs, ideas, etc.
* [Development](../development/introduction.md)
* [Documentation](../documentation/#introduction)
* [Documentation](documentation-contributions.md)
* [Financial](financial.md)
We encourage our community to be part of __Authelia__ by contributing in these ways. We encourage anyone who wishes to

View File

@ -0,0 +1,93 @@
---
title: "Istio"
description: "A guide to integrating Authelia with the Istio Kubernetes Ingress."
lead: "A guide to integrating Authelia with the Istio Kubernetes Ingress."
date: 2022-10-02T13:59:09+11:00
draft: false
images: []
menu:
integration:
parent: "kubernetes"
weight: 551
toc: true
---
Istio uses [Envoy](../proxies/envoy.md) as an Ingress. This means it has a relatively comprehensive integration option.
Istio is supported with Authelia v4.37.0 and higher via [Envoy]'s [external authorization] filter.
[external authorization]: https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/ext_authz/v3/ext_authz.proto.html#extensions-filters-http-ext-authz-v3-extauthz
## Example
This example assumes that you have deployed an Authelia pod and you have configured it to be served on the URL
`https://auth.example.com` and there is a Kubernetes Service with the name `authelia` in the `default` namespace with
TCP port `80` configured to route to the Authelia pod's HTTP port and that your cluster is configured with the default
DNS domain name of `cluster.local`.
### Operator
This is an example IstioOperator manifest adjusted to authenticate with Authelia. This example only shows the necessary
portions of the resource that you add as well as context. You will need to adapt it to your needs.
```yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
meshConfig:
extensionProviders:
- name: 'authelia'
envoyExtAuthzHttp:
service: 'authelia.default.svc.cluster.local'
port: 80
pathPrefix: '/api/verify/'
includeRequestHeadersInCheck:
- accept
- cookie
- proxy-authorization
headersToUpstreamOnAllow:
- 'authorization'
- 'proxy-authorization'
- 'remote-*'
- 'authelia-*'
includeAdditionalHeadersInCheck:
X-Authelia-URL: 'https://auth.example.com/'
X-Forwarded-Method: '%REQ(:METHOD)%'
X-Forwarded-Proto: '%REQ(:SCHEME)%'
X-Forwarded-Host: '%REQ(:AUTHORITY)%'
X-Forwarded-URI: '%REQ(:PATH)%'
X-Forwarded-For: '%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%'
headersToDownstreamOnDeny:
- set-cookie
headersToDownstreamOnAllow:
- set-cookie
```
### Authorization Policy
The following [Authorization Policy] applies the above filter extension provider to the `nextcloud.example.com` domain:
```yaml
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: nextcloud
namespace: apps
spec:
action: CUSTOM
provider:
name: 'authelia'
rules:
- to:
- operation:
hosts:
- 'nextcloud.example.com'
```
## See Also
- Istio [External Authentication](https://istio.io/latest/docs/tasks/security/authorization/authz-custom/) Documentation
- Istio [Authorization Policy] Documentation
- Istio [IstioOperator Options](https://istio.io/latest/docs/reference/config/istio.operator.v1alpha1/) Documentation
- Istio [MeshConfig Extension Provider EnvoyExtAuthz HTTP Provider](https://istio.io/latest/docs/reference/config/istio.mesh.v1alpha1/#MeshConfig-ExtensionProvider-EnvoyExternalAuthorizationHttpProvider) Documentation
[Authorization Policy]: https://istio.io/latest/docs/reference/config/security/authorization-policy/

View File

@ -8,7 +8,7 @@ images: []
menu:
integration:
parent: "kubernetes"
weight: 551
weight: 552
toc: true
---

View File

@ -14,4 +14,151 @@ toc: true
## UNDER CONSTRUCTION
This section of the documentation is under construction.
This section is still a work in progress.
## Configuration
### OpenLDAP
**Tested:**
* Version: [v2.5.13](https://www.openldap.org/software/release/announce_lts.html)
* Container `bitnami/openldap:2.5.13-debian-11-r7`
Create within OpenLDAP, either via CLI or with a GUI management application like
[phpLDAPadmin](http://phpldapadmin.sourceforge.net/wiki/index.php/Main_Page) or [LDAP Admin](http://www.ldapadmin.org/)
a basic user with a complex password.
*Make note of its CN.* You can also create a group to use within Authelia if you would like granular control of who can
login, and reference it within the filters below.
### Authelia
In your Authelia configuration you will need to enter and update the following variables -
* url `ldap://OpenLDAP:1389` - servers dns name & port.
*tip: if you have Authelia on a container network that is routable, you can just use the container name*
* server_name `ldap01.example.com` - servers name
* base_dn `DC=example,DC=com` - common name of domain root.
* groups_filter `DC=example,DC=com` - replace relevant section with your own domain in common name format, same as base_dn.
* user `authelia` - username for Authelia service account
* password `SUPER_COMPLEX_PASSWORD` - password for Authelia service account
```yaml
ldap:
implementation: custom
url: ldap://OpenLDAP:1389
timeout: 5s
start_tls: false
tls:
server_name: ldap01.example.com
skip_verify: true
minimum_version: TLS1.2
base_dn: DC=example,DC=com
additional_users_dn: OU=users
users_filter: (&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person))
username_attribute: uid
mail_attribute: mail
display_name_attribute: displayName
additional_groups_dn: OU=groups
groups_filter: (&(member=UID={input},OU=users,DC=example,DC=com)(objectClass=groupOfNames))
group_name_attribute: cn
user: UID=authelia,OU=service accounts,DC=example,DC=com
password: "SUPER_COMPLEX_PASSWORD"
```
Following this, restart Authelia, and you should be able to begin using LDAP integration for your user logins, with
Authelia taking the email attribute for users straight from the 'mail' attribute within the LDAP object.
### FreeIPA
**Tested:**
* Version: [v4.9.9](https://www.freeipa.org/page/Releases/4.9.9)
* Container: `freeipa/freeipa-server:fedora-36-4.9.9`
Create within FreeIPA, either via CLI or within its GUI management application `https://server_ip` a basic user with a
complex password.
*Make note of its CN.* You can also create a group to use within Authelia if you would like granular control of who can
login, and reference it within the filters below.
### Authelia
In your Authelia configuration you will need to enter and update the following variables -
* url `ldap://ldap` - servers dns name. Port will assume 389 as standard. Specify custom port with `:port` if needed.
* server_name `ldap01.example.com` - servers name
* base_dn `DC=example,DC=com` - common name of domain root.
* groups_filter `DC=example,DC=com` - replace relevant section with your own domain in common name format, same as base_dn.
* user `authelia` - username for Authelia service account
* password `SUPER_COMPLEX_PASSWORD` - password for Authelia service account
```yaml
ldap:
implementation: custom
url: ldaps://ldap.example.com
timeout: 5s
start_tls: false
tls:
server_name: ldap.example.com
skip_verify: true
minimum_version: TLS1.2
base_dn: dc=example,DC=com
username_attribute: uid
additional_users_dn: CN=users,CN=accounts
users_filter: (&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person))
additional_groups_dn: OU=groups
groups_filter: (&(member=UID={input},CN=users,CN=accounts,DC=example,DC=com)(objectClass=groupOfNames))
group_name_attribute: cn
mail_attribute: mail
display_name_attribute: displayName
user: UID=authelia,CN=users,CN=accounts,DC=example,DC=com
password: "SUPER_COMPLEX_PASSWORD"
```
Following this, restart Authelia, and you should be able to begin using LDAP integration for your user logins, with
Authelia taking the email attribute for users straight from the 'mail' attribute within the LDAP object.
### lldap
**Tested:**
* Version: [v0.4.0](https://github.com/nitnelave/lldap/releases/tag/v0.4.07)
Create within lldap, a basic user with a complex password, and add to the group "lldap_password_manager"
You can also create a group to use within Authelia if you would like granular control of who can login, and reference it
within the filters below.
### Authelia
In your Authelia configuration you will need to enter and update the following variables -
* url `ldap://OpenLDAP:1389` - servers dns name & port.
*tip: if you have Authelia on a container network that is routable, you can just use the container name*
* base_dn `DC=example,DC=com` - common name of domain root.
* user `authelia` - username for Authelia service account.
* password `SUPER_COMPLEX_PASSWORD` - password for Authelia service account,
```yaml
ldap:
implementation: custom
url: ldap://lldap:3890
timeout: 5s
start_tls: false
base_dn: dc=example,DC=com
username_attribute: uid
additional_users_dn: OU=people
# To allow sign in both with username and email, one can use a filter like
# (&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person))
users_filter: (&({username_attribute}={input})(objectClass=person))
additional_groups_dn: OU=groups
groups_filter: (member={dn})
group_name_attribute: cn
mail_attribute: mail
display_name_attribute: displayName
# The username and password of the admin or service user.
user: UID=authelia,OU=people,DC=example,DC=com
password: "SUPER_COMPLEX_PASSWORD"
```
Following this, restart Authelia, and you should be able to begin using lldap integration for your user logins, with
Authelia taking the email attribute for users straight from the 'mail' attribute within the LDAP object.
## See Also
[Authelia]: https://www.authelia.com
[Bitnami OpenLDAP]: https://hub.docker.com/r/bitnami/openldap/
[FreeIPA]: https://www.freeipa.org/page/Main_Page
[lldap]: https://github.com/nitnelave/lldap

View File

@ -22,9 +22,16 @@ community: true
## Before You Begin
You are required to utilize a unique client id and a unique and random client secret for all [OpenID Connect] relying
parties. You should not use the client secret in this example, you should randomly generate one yourself. You may also
choose to utilize a different client id, it's completely up to you.
### 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
### Assumptions
This example makes the following assumptions:
@ -59,7 +66,7 @@ The following YAML configuration is an example __Authelia__
```yaml
- id: guacamole
description: Apache Guacamole
secret: guacamole_client_secret
secret: '$plaintext$guacamole_client_secret'
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -22,9 +22,16 @@ community: true
## Before You Begin
You are required to utilize a unique client id and a unique and random client secret for all [OpenID Connect] relying
parties. You should not use the client secret in this example, you should randomly generate one yourself. You may also
choose to utilize a different client id, it's completely up to you.
### 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
### Assumptions
This example makes the following assumptions:
@ -62,7 +69,7 @@ which will operate with the above example:
```yaml
- id: argocd
description: Argo CD
secret: argocd_client_secret
secret: '$plaintext$argocd_client_secret'
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -22,9 +22,16 @@ community: true
## Before You Begin
You are required to utilize a unique client id and a unique and random client secret for all [OpenID Connect] relying
parties. You should not use the client secret in this example, you should randomly generate one yourself. You may also
choose to utilize a different client id, it's completely up to you.
### 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
### Assumptions
This example makes the following assumptions:
@ -33,6 +40,12 @@ This example makes the following assumptions:
* __Client ID:__ `bookstack`
* __Client Secret:__ `bookstack_client_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
## Configuration
### Application
@ -58,7 +71,7 @@ which will operate with the above example:
```yaml
- id: bookstack
description: BookStack
secret: bookstack_client_secret
secret: '$plaintext$bookstack_client_secret'
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -20,9 +20,16 @@ community: true
## Before You Begin
You are required to utilize a unique client id and a unique and random client secret for all [OpenID Connect] relying
parties. You should not use the client secret in this example, you should randomly generate one yourself. You may also
choose to utilize a different client id, it's completely up to you.
### 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
### Assumptions
This example makes the following assumptions:
@ -31,8 +38,11 @@ This example makes the following assumptions:
* __Client ID:__ `cloudflare`
* __Client Secret:__ `cloudflare_client_secret`
*__Important Note:__ Cloudflare does not properly URL encode the secret. This means you'll either have to use
only alphanumeric characters for the secret or URL encode it yourself.*
*__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
## Configuration
@ -69,7 +79,7 @@ which will operate with the above example:
```yaml
- id: cloudflare
description: Cloudflare ZeroTrust
secret: cloudflare_client_secret
secret: '$plaintext$cloudflare_client_secret'
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -22,9 +22,16 @@ community: true
## Before You Begin
You are required to utilize a unique client id and a unique and random client secret for all [OpenID Connect] relying
parties. You should not use the client secret in this example, you should randomly generate one yourself. You may also
choose to utilize a different client id, it's completely up to you.
### 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
### Assumptions
This example makes the following assumptions:
@ -79,7 +86,7 @@ will operate with the above example:
```yaml
- id: gitea
description: Gitea
secret: gitea_client_secret
secret: '$plaintext$gitea_client_secret'
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -22,9 +22,16 @@ community: true
## Before You Begin
You are required to utilize a unique client id and a unique and random client secret for all [OpenID Connect] relying
parties. You should not use the client secret in this example, you should randomly generate one yourself. You may also
choose to utilize a different client id, it's completely up to you.
### 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
### Assumptions
This example makes the following assumptions:
@ -75,7 +82,7 @@ which will operate with the above example:
```yaml
- id: gitlab
description: GitLab
secret: gitlab_client_secret
secret: '$plaintext$gitlab_client_secret'
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -22,9 +22,16 @@ community: true
## Before You Begin
You are required to utilize a unique client id and a unique and random client secret for all [OpenID Connect] relying
parties. You should not use the client secret in this example, you should randomly generate one yourself. You may also
choose to utilize a different client id, it's completely up to you.
### 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
### Assumptions
This example makes the following assumptions:
@ -93,7 +100,7 @@ which will operate with the above example:
```yaml
- id: grafana
description: Grafana
secret: grafana_client_secret
secret: '$plaintext$grafana_client_secret'
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -22,9 +22,16 @@ community: true
## Before You Begin
You are required to utilize a unique client id and a unique and random client secret for all [OpenID Connect] relying
parties. You should not use the client secret in this example, you should randomly generate one yourself. You may also
choose to utilize a different client id, it's completely up to you.
### 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
### Assumptions
This example makes the following assumptions:
@ -66,7 +73,7 @@ which will operate with the above example:
```yaml
- id: harbor
description: Harbor
secret: harbor_client_secret
secret: '$plaintext$harbor_client_secret'
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -22,9 +22,16 @@ community: true
## Before You Begin
You are required to utilize a unique client id and a unique and random client secret for all [OpenID Connect] relying
parties. You should not use the client secret in this example, you should randomly generate one yourself. You may also
choose to utilize a different client id, it's completely up to you.
### 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
### Assumptions
This example makes the following assumptions:
@ -49,7 +56,7 @@ which will operate with the above example:
```yaml
- id: vault
description: HashiCorp Vault
secret: vault_client_secret
secret: '$plaintext$vault_client_secret'
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -22,9 +22,16 @@ community: true
## Before You Begin
You are required to utilize a unique client id and a unique and random client secret for all [OpenID Connect] relying
parties. You should not use the client secret in this example, you should randomly generate one yourself. You may also
choose to utilize a different client id, it's completely up to you.
### 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
### Assumptions
This example makes the following assumptions:
@ -71,14 +78,14 @@ which will operate with the above example:
```yaml
- id: komga
description: Komga
secret: komga_client_secret
secret: '$plaintext$komga_client_secret'
public: false
authorization_policy: two_factor
redirect_uris:
- https://komga.example.com/login/oauth2/code/authelia
scopes:
- openid
- preferred_username
- profile
- email
grant_types:
- authorization_code

View File

@ -22,9 +22,16 @@ community: true
## Before You Begin
You are required to utilize a unique client id and a unique and random client secret for all [OpenID Connect] relying
parties. You should not use the client secret in this example, you should randomly generate one yourself. You may also
choose to utilize a different client id, it's completely up to you.
### 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
### Assumptions
This example makes the following assumptions:
@ -87,7 +94,7 @@ which will operate with the above example:
```yaml
- id: nextcloud
description: NextCloud
secret: nextcloud_client_secret
secret: '$plaintext$nextcloud_client_secret'
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -22,9 +22,16 @@ community: true
## Before You Begin
You are required to utilize a unique client id and a unique and random client secret for all [OpenID Connect] relying
parties. You should not use the client secret in this example, you should randomly generate one yourself. You may also
choose to utilize a different client id, it's completely up to you.
### 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
### Assumptions
This example makes the following assumptions:
@ -66,7 +73,7 @@ which will operate with the above example:
```yaml
- id: outline
description: Outline
secret: outline_client_secret
secret: '$plaintext$outline_client_secret'
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -24,9 +24,16 @@ aliases:
## Before You Begin
You are required to utilize a unique client id and a unique and random client secret for all [OpenID Connect] relying
parties. You should not use the client secret in this example, you should randomly generate one yourself. You may also
choose to utilize a different client id, it's completely up to you.
### 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
### Assumptions
This example makes the following assumptions:
@ -67,7 +74,7 @@ which will operate with the above example:
```yaml
- id: portainer
description: Portainer
secret: portainer_client_secret
secret: '$plaintext$portainer_client_secret'
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -22,11 +22,21 @@ aliases:
* [Proxmox]
* 7.1-10
## Before You Begin
### Common Notes
You are required to utilize a unique client id and a unique and random client secret for all [OpenID Connect] relying
parties. You should not use the client secret in this example, you should randomly generate one yourself. You may also
choose to utilize a different client id, it's completely up to you.
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
### Specific Notes
*__Important Note:__ [Proxmox] requires you create the Realm prior to adding the provider. This is not covered in this
guide.*
### Assumptions
This example makes the following assumptions:
@ -34,6 +44,7 @@ This example makes the following assumptions:
* __Authelia Root URL:__ `https://auth.example.com`
* __Client ID:__ `proxmox`
* __Client Secret:__ `proxmox_client_secret`
* __Realm__ `authelia`
## Configuration
@ -47,14 +58,14 @@ To configure [Proxmox] to utilize Authelia as an [OpenID Connect] Provider:
4. Add an OpenID Connect Server
5. Set the following values:
1. Issuer URL: `https://auth.example.com`
2. Realm: anything you wish
2. Realm: `authelia`
3. Client ID: `proxmox`
4. Client Key: `proxmox_client_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].
{{< figure src="proxmox.gif" alt="Proxmox" width="736" style="padding-right: 10px" >}}
{{< figure src="proxmox.png" alt="Proxmox" width="736" style="padding-right: 10px" >}}
### Authelia
@ -65,7 +76,7 @@ which will operate with the above example:
```yaml
- id: proxmox
description: Proxmox
secret: proxmox_client_secret
secret: '$plaintext$proxmox_client_secret'
public: false
authorization_policy: two_factor
redirect_uris:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -16,15 +16,22 @@ community: true
## Tested Versions
* [Authelia]
* [v4.35.5](https://github.com/authelia/authelia/releases/tag/v4.35.5)
* [v4.36.9](https://github.com/authelia/authelia/releases/tag/v4.36.9)
* [Seafile] Server
* 9.0.4
* [9.0.9](https://manual.seafile.com/changelog/server-changelog/#909-2022-09-22)
## Before You Begin
You are required to utilize a unique client id and a unique and random client secret for all [OpenID Connect] relying
parties. You should not use the client secret in this example, you should randomly generate one yourself. You may also
choose to utilize a different client id, it's completely up to you.
### 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
### Assumptions
This example makes the following assumptions:
@ -39,7 +46,10 @@ This example makes the following assumptions:
To configure [Seafile] to utilize Authelia as an [OpenID Connect] Provider:
1. Edit your [Seafile] `seahub_settings.py` configuration file and add configure the following:
1. [Seafile] may require some dependencies such as `requests_oauthlib` to be manually installed.
See the [Seafile] documentation in the [see also](#see-also) section for more information.
2. Edit your [Seafile] `seahub_settings.py` configuration file and add configure the following:
```python
ENABLE_OAUTH = True
@ -52,15 +62,14 @@ OAUTH_AUTHORIZATION_URL = 'https://auth.example.com/api/oidc/authorization'
OAUTH_TOKEN_URL = 'https://auth.example.com/api/oidc/token'
OAUTH_USER_INFO_URL = 'https://auth.example.com/api/oidc/userinfo'
OAUTH_SCOPE = [
"openid",
"profile",
"email",
"groups",
"openid",
"profile",
"email",
]
OAUTH_ATTRIBUTE_MAP = {
"id": (True, "preferred_username"),
"email": (True, "email"),
"name": (False, "name"),
"email": (False, "email"),
"id": (False, "not used"),
}
```
@ -73,7 +82,7 @@ which will operate with the above example:
```yaml
- id: seafile
description: Seafile
secret: seafile_client_secret
secret: '$plaintext$seafile_client_secret'
public: false
authorization_policy: two_factor
redirect_uris:

View File

@ -0,0 +1,39 @@
---
title: "Specific Information"
description: "Specific information regarding integrating the Authelia OpenID Connect Provider with an OpenID Connect relying party"
lead: "Specific information regarding integrating the Authelia OpenID Connect Provider with an OpenID Connect relying party."
date: 2022-10-20T15:27:09+11:00
draft: false
images: []
menu:
integration:
parent: "openid-connect"
weight: 615
toc: true
---
## Generating Client Secrets
We strongly recommend the following guidelines for generating client secrets:
1. Each client should have a unique secret.
2. Each secret should be randomly generated.
3. Each secret should have a length above 40 characters.
4. The secrets should be stored in the configuration in a supported hash format. *__Note:__ This does not mean you
configure the relying party / client application with the hashed version, just the secret value in the Authelia
configuration.*
5. Secrets should only have alphanumeric characters as some implementations do not appropriately encode the secret
when using it to access the token endpoint.
Authelia provides an easy way to perform such actions via the [Generating a Random Password Hash] guide. Users can
perform a command such as `authelia crypto hash generate pbkdf2 --variant sha512 --random --random.length 72` command to
both generate a client secret with 72 characters which is printed and is to be used with the relying party and hash it
using PBKDF2 which can be stored in the Authelia configuration.
[Generating a Random Password Hash]: ../../reference/guides/generating-secure-values.md#generating-a-random-password-hash
### 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.

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