mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
Merge pull request #204 from clems4ever/verify-redirect
Support 'redirect' parameter in /api/verify endpoint to support Traefik
This commit is contained in:
commit
8a1f38f2f1
|
@ -23,6 +23,7 @@ addons:
|
||||||
- mx1.mail.example.com
|
- mx1.mail.example.com
|
||||||
- mx2.mail.example.com
|
- mx2.mail.example.com
|
||||||
- public.example.com
|
- public.example.com
|
||||||
|
- authelia.example.com
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- npm install -g npm@'>=2.13.5'
|
- npm install -g npm@'>=2.13.5'
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
[](https://gitter.im/authelia/general?utm_source=share-link&utm_medium=link&utm_campaign=share-link)
|
[](https://gitter.im/authelia/general?utm_source=share-link&utm_medium=link&utm_campaign=share-link)
|
||||||
|
|
||||||
**Authelia** is a complete HTTP 2-factor authentication server for proxies like
|
**Authelia** is a complete HTTP 2-factor authentication server for proxies like
|
||||||
nginx. It has been made to work with nginx [auth_request] module and is currently
|
Nginx or Traefik. It has been designed to be proxy agnostic so that you can
|
||||||
used in production to secure internal services in a small docker swarm cluster.
|
use whichever proxy supporting authentication forwarding.
|
||||||
|
|
||||||
# Table of Contents
|
# Table of Contents
|
||||||
1. [Features summary](#features-summary)
|
1. [Features summary](#features-summary)
|
||||||
|
|
|
@ -20,7 +20,7 @@ define({ "api": [
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "<p>Serves the login page and create a create a cookie for the client.</p>",
|
"description": "<p>Serves the login page and create a create a cookie for the client.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "Authentication"
|
"groupTitle": "Authentication"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -56,7 +56,7 @@ define({ "api": [
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "<p>Log out the user and redirect to the URL.</p>",
|
"description": "<p>Log out the user and redirect to the URL.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "Authentication"
|
"groupTitle": "Authentication"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -80,7 +80,7 @@ define({ "api": [
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "<p>Serves the second factor page</p>",
|
"description": "<p>Serves the second factor page</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "Authentication"
|
"groupTitle": "Authentication"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -145,7 +145,7 @@ define({ "api": [
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "<p>Verify credentials against the LDAP.</p>",
|
"description": "<p>Verify credentials against the LDAP.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "Authentication",
|
"groupTitle": "Authentication",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -169,7 +169,7 @@ define({ "api": [
|
||||||
"group": "PasswordReset",
|
"group": "PasswordReset",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "<p>Start password reset request.</p>",
|
"description": "<p>Start password reset request.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "PasswordReset",
|
"groupTitle": "PasswordReset",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -240,7 +240,7 @@ define({ "api": [
|
||||||
"group": "PasswordReset",
|
"group": "PasswordReset",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "<p>Serve a page that requires the username.</p>",
|
"description": "<p>Serve a page that requires the username.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "PasswordReset",
|
"groupTitle": "PasswordReset",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -277,7 +277,7 @@ define({ "api": [
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "<p>Set a new password for the user.</p>",
|
"description": "<p>Set a new password for the user.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "PasswordReset",
|
"groupTitle": "PasswordReset",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -301,7 +301,7 @@ define({ "api": [
|
||||||
"group": "PasswordReset",
|
"group": "PasswordReset",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "<p>Start password reset request.</p>",
|
"description": "<p>Start password reset request.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "PasswordReset",
|
"groupTitle": "PasswordReset",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -366,7 +366,7 @@ define({ "api": [
|
||||||
"group": "TOTP",
|
"group": "TOTP",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "<p>Serves the TOTP registration page that displays the secret. The secret is a QRCode and a base32 secret.</p>",
|
"description": "<p>Serves the TOTP registration page that displays the secret. The secret is a QRCode and a base32 secret.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "TOTP",
|
"groupTitle": "TOTP",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -437,7 +437,7 @@ define({ "api": [
|
||||||
"group": "TOTP",
|
"group": "TOTP",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "<p>Initiates the identity validation</p>",
|
"description": "<p>Initiates the identity validation</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "TOTP",
|
"groupTitle": "TOTP",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -521,7 +521,7 @@ define({ "api": [
|
||||||
"group": "Success 302",
|
"group": "Success 302",
|
||||||
"optional": false,
|
"optional": false,
|
||||||
"field": "Redirect",
|
"field": "Redirect",
|
||||||
"description": "<p>to the URL that has been stored during last call to /verify.</p>"
|
"description": "<p>to the URL that has been stored during last call to /api/verify.</p>"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -549,7 +549,7 @@ define({ "api": [
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "<p>Verify TOTP token. The user is authenticated upon success.</p>",
|
"description": "<p>Verify TOTP token. The user is authenticated upon success.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "TOTP",
|
"groupTitle": "TOTP",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -579,7 +579,7 @@ define({ "api": [
|
||||||
"group": "Success 302",
|
"group": "Success 302",
|
||||||
"optional": false,
|
"optional": false,
|
||||||
"field": "Redirect",
|
"field": "Redirect",
|
||||||
"description": "<p>to the URL that has been stored during last call to /verify.</p>"
|
"description": "<p>to the URL that has been stored during last call to /api/verify.</p>"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -607,7 +607,7 @@ define({ "api": [
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "<p>Complete authentication request of the U2F device.</p>",
|
"description": "<p>Complete authentication request of the U2F device.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "U2F",
|
"groupTitle": "U2F",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -637,13 +637,13 @@ define({ "api": [
|
||||||
"group": "Success 302",
|
"group": "Success 302",
|
||||||
"optional": false,
|
"optional": false,
|
||||||
"field": "Redirect",
|
"field": "Redirect",
|
||||||
"description": "<p>to the URL that has been stored during last call to /verify.</p>"
|
"description": "<p>to the URL that has been stored during last call to /api/verify.</p>"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "<p>Complete U2F registration request.</p>",
|
"description": "<p>Complete U2F registration request.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "U2F",
|
"groupTitle": "U2F",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -679,7 +679,7 @@ define({ "api": [
|
||||||
"name": "RequestU2FRegistration",
|
"name": "RequestU2FRegistration",
|
||||||
"group": "U2F",
|
"group": "U2F",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "U2F",
|
"groupTitle": "U2F",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -745,7 +745,7 @@ define({ "api": [
|
||||||
"group": "U2F",
|
"group": "U2F",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "<p>Serves the U2F registration page that asks the user to touch the token of the U2F device.</p>",
|
"description": "<p>Serves the U2F registration page that asks the user to touch the token of the U2F device.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "U2F",
|
"groupTitle": "U2F",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -850,7 +850,7 @@ define({ "api": [
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "<p>Initiate an authentication request using a U2F device.</p>",
|
"description": "<p>Initiate an authentication request using a U2F device.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "U2F",
|
"groupTitle": "U2F",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -908,7 +908,7 @@ define({ "api": [
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "<p>Initiate a U2F device registration request.</p>",
|
"description": "<p>Initiate a U2F device registration request.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "U2F",
|
"groupTitle": "U2F",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -926,11 +926,24 @@ define({ "api": [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "get",
|
"type": "get",
|
||||||
"url": "/verify",
|
"url": "/api/verify",
|
||||||
"title": "Verify user authentication",
|
"title": "Verify user authentication",
|
||||||
"name": "VerifyAuthentication",
|
"name": "VerifyAuthentication",
|
||||||
"group": "Verification",
|
"group": "Verification",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
"parameter": {
|
||||||
|
"fields": {
|
||||||
|
"Parameter": [
|
||||||
|
{
|
||||||
|
"group": "Parameter",
|
||||||
|
"type": "String",
|
||||||
|
"optional": false,
|
||||||
|
"field": "redirect",
|
||||||
|
"description": "<p>Optional parameter set to the url where the user is redirected if access is refused. It is mainly used by Traefik that does not control the redirection itself.</p>"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"success": {
|
"success": {
|
||||||
"fields": {
|
"fields": {
|
||||||
"Success 204": [
|
"Success 204": [
|
||||||
|
@ -945,18 +958,26 @@ define({ "api": [
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
"Error 302": [
|
||||||
|
{
|
||||||
|
"group": "Error 302",
|
||||||
|
"optional": false,
|
||||||
|
"field": "redirect",
|
||||||
|
"description": "<p>The user is redirected if redirect parameter is provided.</p>"
|
||||||
|
}
|
||||||
|
],
|
||||||
"Error 401": [
|
"Error 401": [
|
||||||
{
|
{
|
||||||
"group": "Error 401",
|
"group": "Error 401",
|
||||||
"optional": false,
|
"optional": false,
|
||||||
"field": "status",
|
"field": "status",
|
||||||
"description": "<p>The user is not authenticated.</p>"
|
"description": "<p>The user get an error if access failed</p>"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "<p>Verify that the user is authenticated, i.e., the two factors have been validated</p>",
|
"description": "<p>Verify that the user is authenticated, i.e., the two factors have been validated. If the user is authenticated the response headers Remote-User and Remote-Groups are set. Remote-User contains the user id of the currently logged in user and Remote-Groups a comma separated list of assigned groups.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "Verification",
|
"groupTitle": "Verification",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "<p>Serves the login page and create a create a cookie for the client.</p>",
|
"description": "<p>Serves the login page and create a create a cookie for the client.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "Authentication"
|
"groupTitle": "Authentication"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -56,7 +56,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "<p>Log out the user and redirect to the URL.</p>",
|
"description": "<p>Log out the user and redirect to the URL.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "Authentication"
|
"groupTitle": "Authentication"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -80,7 +80,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "<p>Serves the second factor page</p>",
|
"description": "<p>Serves the second factor page</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "Authentication"
|
"groupTitle": "Authentication"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -145,7 +145,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "<p>Verify credentials against the LDAP.</p>",
|
"description": "<p>Verify credentials against the LDAP.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "Authentication",
|
"groupTitle": "Authentication",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -169,7 +169,7 @@
|
||||||
"group": "PasswordReset",
|
"group": "PasswordReset",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "<p>Start password reset request.</p>",
|
"description": "<p>Start password reset request.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "PasswordReset",
|
"groupTitle": "PasswordReset",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -240,7 +240,7 @@
|
||||||
"group": "PasswordReset",
|
"group": "PasswordReset",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "<p>Serve a page that requires the username.</p>",
|
"description": "<p>Serve a page that requires the username.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "PasswordReset",
|
"groupTitle": "PasswordReset",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -277,7 +277,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "<p>Set a new password for the user.</p>",
|
"description": "<p>Set a new password for the user.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "PasswordReset",
|
"groupTitle": "PasswordReset",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -301,7 +301,7 @@
|
||||||
"group": "PasswordReset",
|
"group": "PasswordReset",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "<p>Start password reset request.</p>",
|
"description": "<p>Start password reset request.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "PasswordReset",
|
"groupTitle": "PasswordReset",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -366,7 +366,7 @@
|
||||||
"group": "TOTP",
|
"group": "TOTP",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "<p>Serves the TOTP registration page that displays the secret. The secret is a QRCode and a base32 secret.</p>",
|
"description": "<p>Serves the TOTP registration page that displays the secret. The secret is a QRCode and a base32 secret.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "TOTP",
|
"groupTitle": "TOTP",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -437,7 +437,7 @@
|
||||||
"group": "TOTP",
|
"group": "TOTP",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "<p>Initiates the identity validation</p>",
|
"description": "<p>Initiates the identity validation</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "TOTP",
|
"groupTitle": "TOTP",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -521,7 +521,7 @@
|
||||||
"group": "Success 302",
|
"group": "Success 302",
|
||||||
"optional": false,
|
"optional": false,
|
||||||
"field": "Redirect",
|
"field": "Redirect",
|
||||||
"description": "<p>to the URL that has been stored during last call to /verify.</p>"
|
"description": "<p>to the URL that has been stored during last call to /api/verify.</p>"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -549,7 +549,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "<p>Verify TOTP token. The user is authenticated upon success.</p>",
|
"description": "<p>Verify TOTP token. The user is authenticated upon success.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "TOTP",
|
"groupTitle": "TOTP",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -579,7 +579,7 @@
|
||||||
"group": "Success 302",
|
"group": "Success 302",
|
||||||
"optional": false,
|
"optional": false,
|
||||||
"field": "Redirect",
|
"field": "Redirect",
|
||||||
"description": "<p>to the URL that has been stored during last call to /verify.</p>"
|
"description": "<p>to the URL that has been stored during last call to /api/verify.</p>"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -607,7 +607,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "<p>Complete authentication request of the U2F device.</p>",
|
"description": "<p>Complete authentication request of the U2F device.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "U2F",
|
"groupTitle": "U2F",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -637,13 +637,13 @@
|
||||||
"group": "Success 302",
|
"group": "Success 302",
|
||||||
"optional": false,
|
"optional": false,
|
||||||
"field": "Redirect",
|
"field": "Redirect",
|
||||||
"description": "<p>to the URL that has been stored during last call to /verify.</p>"
|
"description": "<p>to the URL that has been stored during last call to /api/verify.</p>"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "<p>Complete U2F registration request.</p>",
|
"description": "<p>Complete U2F registration request.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "U2F",
|
"groupTitle": "U2F",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -679,7 +679,7 @@
|
||||||
"name": "RequestU2FRegistration",
|
"name": "RequestU2FRegistration",
|
||||||
"group": "U2F",
|
"group": "U2F",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "U2F",
|
"groupTitle": "U2F",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -745,7 +745,7 @@
|
||||||
"group": "U2F",
|
"group": "U2F",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "<p>Serves the U2F registration page that asks the user to touch the token of the U2F device.</p>",
|
"description": "<p>Serves the U2F registration page that asks the user to touch the token of the U2F device.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "U2F",
|
"groupTitle": "U2F",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -850,7 +850,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "<p>Initiate an authentication request using a U2F device.</p>",
|
"description": "<p>Initiate an authentication request using a U2F device.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "U2F",
|
"groupTitle": "U2F",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -908,7 +908,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "<p>Initiate a U2F device registration request.</p>",
|
"description": "<p>Initiate a U2F device registration request.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "U2F",
|
"groupTitle": "U2F",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
@ -926,11 +926,24 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "get",
|
"type": "get",
|
||||||
"url": "/verify",
|
"url": "/api/verify",
|
||||||
"title": "Verify user authentication",
|
"title": "Verify user authentication",
|
||||||
"name": "VerifyAuthentication",
|
"name": "VerifyAuthentication",
|
||||||
"group": "Verification",
|
"group": "Verification",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
"parameter": {
|
||||||
|
"fields": {
|
||||||
|
"Parameter": [
|
||||||
|
{
|
||||||
|
"group": "Parameter",
|
||||||
|
"type": "String",
|
||||||
|
"optional": false,
|
||||||
|
"field": "redirect",
|
||||||
|
"description": "<p>Optional parameter set to the url where the user is redirected if access is refused. It is mainly used by Traefik that does not control the redirection itself.</p>"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"success": {
|
"success": {
|
||||||
"fields": {
|
"fields": {
|
||||||
"Success 204": [
|
"Success 204": [
|
||||||
|
@ -945,18 +958,26 @@
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
"Error 302": [
|
||||||
|
{
|
||||||
|
"group": "Error 302",
|
||||||
|
"optional": false,
|
||||||
|
"field": "redirect",
|
||||||
|
"description": "<p>The user is redirected if redirect parameter is provided.</p>"
|
||||||
|
}
|
||||||
|
],
|
||||||
"Error 401": [
|
"Error 401": [
|
||||||
{
|
{
|
||||||
"group": "Error 401",
|
"group": "Error 401",
|
||||||
"optional": false,
|
"optional": false,
|
||||||
"field": "status",
|
"field": "status",
|
||||||
"description": "<p>The user is not authenticated.</p>"
|
"description": "<p>The user get an error if access failed</p>"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "<p>Verify that the user is authenticated, i.e., the two factors have been validated</p>",
|
"description": "<p>Verify that the user is authenticated, i.e., the two factors have been validated. If the user is authenticated the response headers Remote-User and Remote-Groups are set. Remote-User contains the user id of the currently logged in user and Remote-Groups a comma separated list of assigned groups.</p>",
|
||||||
"filename": "src/server/endpoints.ts",
|
"filename": "shared/api.ts",
|
||||||
"groupTitle": "Verification",
|
"groupTitle": "Verification",
|
||||||
"header": {
|
"header": {
|
||||||
"fields": {
|
"fields": {
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
define({
|
define({
|
||||||
"title": "Authelia API documentation",
|
"title": "Authelia API documentation",
|
||||||
"name": "authelia",
|
"name": "authelia",
|
||||||
"version": "2.1.3",
|
"version": "3.7.0",
|
||||||
"description": "2FA Single Sign-On server for nginx using LDAP, TOTP and U2F",
|
"description": "2FA Single Sign-On server for nginx using LDAP, TOTP and U2F",
|
||||||
"sampleUrl": false,
|
"sampleUrl": false,
|
||||||
"defaultVersion": "0.0.0",
|
"defaultVersion": "0.0.0",
|
||||||
"apidoc": "0.3.0",
|
"apidoc": "0.3.0",
|
||||||
"generator": {
|
"generator": {
|
||||||
"name": "apidoc",
|
"name": "apidoc",
|
||||||
"time": "2017-06-11T20:41:36.025Z",
|
"time": "2017-12-04T21:38:44.927Z",
|
||||||
"url": "http://apidocjs.com",
|
"url": "http://apidocjs.com",
|
||||||
"version": "0.17.6"
|
"version": "0.17.6"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
{
|
{
|
||||||
"title": "Authelia API documentation",
|
"title": "Authelia API documentation",
|
||||||
"name": "authelia",
|
"name": "authelia",
|
||||||
"version": "2.1.3",
|
"version": "3.7.0",
|
||||||
"description": "2FA Single Sign-On server for nginx using LDAP, TOTP and U2F",
|
"description": "2FA Single Sign-On server for nginx using LDAP, TOTP and U2F",
|
||||||
"sampleUrl": false,
|
"sampleUrl": false,
|
||||||
"defaultVersion": "0.0.0",
|
"defaultVersion": "0.0.0",
|
||||||
"apidoc": "0.3.0",
|
"apidoc": "0.3.0",
|
||||||
"generator": {
|
"generator": {
|
||||||
"name": "apidoc",
|
"name": "apidoc",
|
||||||
"time": "2017-06-11T20:41:36.025Z",
|
"time": "2017-12-04T21:38:44.927Z",
|
||||||
"url": "http://apidocjs.com",
|
"url": "http://apidocjs.com",
|
||||||
"version": "0.17.6"
|
"version": "0.17.6"
|
||||||
}
|
}
|
||||||
|
|
|
@ -322,5 +322,25 @@ http {
|
||||||
proxy_pass $upstream_headers;
|
proxy_pass $upstream_headers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
server_name authelia.example.com;
|
||||||
|
|
||||||
|
resolver 127.0.0.11 ipv6=off;
|
||||||
|
set $upstream_endpoint http://authelia;
|
||||||
|
|
||||||
|
ssl on;
|
||||||
|
ssl_certificate /etc/ssl/server.crt;
|
||||||
|
ssl_certificate_key /etc/ssl/server.key;
|
||||||
|
|
||||||
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN";
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_pass $upstream_endpoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,15 @@ function replyWithError(req: express.Request, res: express.Response,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function redirectTo(redirectUrl: string, req: express.Request,
|
||||||
|
res: express.Response, logger: IRequestLogger) {
|
||||||
|
return function(err: Error) {
|
||||||
|
logger.error(req, "Error: %s", err.message);
|
||||||
|
logger.debug(req, "Redirecting to %s", redirectUrl);
|
||||||
|
res.redirect(redirectUrl);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function replyWithError400(req: express.Request,
|
export function replyWithError400(req: express.Request,
|
||||||
res: express.Response, logger: IRequestLogger) {
|
res: express.Response, logger: IRequestLogger) {
|
||||||
return replyWithError(req, res, 400, logger);
|
return replyWithError(req, res, 400, logger);
|
||||||
|
|
|
@ -5,6 +5,7 @@ import ErrorReplies = require("../../ErrorReplies");
|
||||||
import { ServerVariables } from "../../ServerVariables";
|
import { ServerVariables } from "../../ServerVariables";
|
||||||
import GetWithSessionCookieMethod from "./get_session_cookie";
|
import GetWithSessionCookieMethod from "./get_session_cookie";
|
||||||
import GetWithBasicAuthMethod from "./get_basic_auth";
|
import GetWithBasicAuthMethod from "./get_basic_auth";
|
||||||
|
import Constants = require("../../../../../shared/constants");
|
||||||
|
|
||||||
import { AuthenticationSessionHandler }
|
import { AuthenticationSessionHandler }
|
||||||
from "../../AuthenticationSessionHandler";
|
from "../../AuthenticationSessionHandler";
|
||||||
|
@ -50,6 +51,12 @@ function replyWith200(res: Express.Response) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRedirectParam(req: Express.Request) {
|
||||||
|
return req.query[Constants.REDIRECT_QUERY_PARAM] != "undefined"
|
||||||
|
? req.query[Constants.REDIRECT_QUERY_PARAM]
|
||||||
|
: undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export default function (vars: ServerVariables) {
|
export default function (vars: ServerVariables) {
|
||||||
return function (req: Express.Request, res: Express.Response)
|
return function (req: Express.Request, res: Express.Response)
|
||||||
: BluebirdPromise<void> {
|
: BluebirdPromise<void> {
|
||||||
|
@ -66,7 +73,15 @@ export default function (vars: ServerVariables) {
|
||||||
.catch(Exceptions.DomainAccessDenied, ErrorReplies
|
.catch(Exceptions.DomainAccessDenied, ErrorReplies
|
||||||
.replyWithError403(req, res, vars.logger))
|
.replyWithError403(req, res, vars.logger))
|
||||||
// The user is not yet authenticated -> 401
|
// The user is not yet authenticated -> 401
|
||||||
.catch(ErrorReplies.replyWithError401(req, res, vars.logger));
|
.catch(function (err) {
|
||||||
|
const redirectUrl = getRedirectParam(req);
|
||||||
|
if (redirectUrl) {
|
||||||
|
ErrorReplies.redirectTo(redirectUrl, req, res, vars.logger)(err);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ErrorReplies.replyWithError401(req, res, vars.logger)(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,11 +24,11 @@ describe("test /api/verify endpoint", function () {
|
||||||
res = ExpressMock.ResponseMock();
|
res = ExpressMock.ResponseMock();
|
||||||
req.originalUrl = "/api/xxxx";
|
req.originalUrl = "/api/xxxx";
|
||||||
req.query = {
|
req.query = {
|
||||||
redirect: "http://redirect.url"
|
redirect: "undefined"
|
||||||
};
|
};
|
||||||
AuthenticationSessionHandler.reset(req as any);
|
AuthenticationSessionHandler.reset(req as any);
|
||||||
req.headers.host = "secret.example.com";
|
req.headers.host = "secret.example.com";
|
||||||
const s = ServerVariablesMockBuilder.build(true);
|
const s = ServerVariablesMockBuilder.build(false);
|
||||||
mocks = s.mocks;
|
mocks = s.mocks;
|
||||||
vars = s.variables;
|
vars = s.variables;
|
||||||
authSession = AuthenticationSessionHandler.get(req as any, vars.logger);
|
authSession = AuthenticationSessionHandler.get(req as any, vars.logger);
|
||||||
|
@ -147,9 +147,6 @@ describe("test /api/verify endpoint", function () {
|
||||||
|
|
||||||
describe("given user tries to access a single factor endpoint", function () {
|
describe("given user tries to access a single factor endpoint", function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
req.query = {
|
|
||||||
redirect: "http://redirect.url"
|
|
||||||
};
|
|
||||||
req.headers["host"] = "redirect.url";
|
req.headers["host"] = "redirect.url";
|
||||||
mocks.config.authentication_methods.per_subdomain_methods = {
|
mocks.config.authentication_methods.per_subdomain_methods = {
|
||||||
"redirect.url": "single_factor"
|
"redirect.url": "single_factor"
|
||||||
|
@ -220,6 +217,36 @@ describe("test /api/verify endpoint", function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("response type 401 | 302", function() {
|
||||||
|
it("should return error code 401", function() {
|
||||||
|
mocks.accessController.isAccessAllowedMock.returns(true);
|
||||||
|
mocks.config.authentication_methods.default_method = "single_factor";
|
||||||
|
mocks.ldapAuthenticator.authenticateStub.rejects(new Error(
|
||||||
|
"Invalid credentials"));
|
||||||
|
req.headers["proxy-authorization"] = "Basic am9objpwYXNzd29yZA==";
|
||||||
|
|
||||||
|
return VerifyGet.default(vars)(req as express.Request, res as any)
|
||||||
|
.then(function () {
|
||||||
|
Assert(res.status.calledWithExactly(401));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should redirect to provided redirection url", function() {
|
||||||
|
const REDIRECT_URL = "http://redirection_url.com";
|
||||||
|
mocks.accessController.isAccessAllowedMock.returns(true);
|
||||||
|
mocks.config.authentication_methods.default_method = "single_factor";
|
||||||
|
mocks.ldapAuthenticator.authenticateStub.rejects(new Error(
|
||||||
|
"Invalid credentials"));
|
||||||
|
req.headers["proxy-authorization"] = "Basic am9objpwYXNzd29yZA==";
|
||||||
|
req.query["redirect"] = REDIRECT_URL;
|
||||||
|
|
||||||
|
return VerifyGet.default(vars)(req as express.Request, res as any)
|
||||||
|
.then(function () {
|
||||||
|
Assert(res.redirect.calledWithExactly(REDIRECT_URL));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("with basic auth", function () {
|
describe("with basic auth", function () {
|
||||||
it("should authenticate correctly", function () {
|
it("should authenticate correctly", function () {
|
||||||
mocks.accessController.isAccessAllowedMock.returns(true);
|
mocks.accessController.isAccessAllowedMock.returns(true);
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
* @apiUse UserSession
|
* @apiUse UserSession
|
||||||
* @apiUse InternalError
|
* @apiUse InternalError
|
||||||
*
|
*
|
||||||
* @apiSuccess (Success 302) Redirect to the URL that has been stored during last call to /verify.
|
* @apiSuccess (Success 302) Redirect to the URL that has been stored during last call to /api/verify.
|
||||||
*
|
*
|
||||||
* @apiDescription Complete U2F registration request.
|
* @apiDescription Complete U2F registration request.
|
||||||
*/
|
*/
|
||||||
|
@ -68,7 +68,7 @@ export const SECOND_FACTOR_U2F_REGISTER_REQUEST_GET = "/api/u2f/register_request
|
||||||
* @apiUse UserSession
|
* @apiUse UserSession
|
||||||
* @apiUse InternalError
|
* @apiUse InternalError
|
||||||
*
|
*
|
||||||
* @apiSuccess (Success 302) Redirect to the URL that has been stored during last call to /verify.
|
* @apiSuccess (Success 302) Redirect to the URL that has been stored during last call to /api/verify.
|
||||||
* @apiError (Error 403) {none} error No authentication request has been provided.
|
* @apiError (Error 403) {none} error No authentication request has been provided.
|
||||||
*
|
*
|
||||||
* @apiDescription Complete authentication request of the U2F device.
|
* @apiDescription Complete authentication request of the U2F device.
|
||||||
|
@ -100,7 +100,7 @@ export const SECOND_FACTOR_U2F_SIGN_REQUEST_GET = "/api/u2f/sign_request";
|
||||||
*
|
*
|
||||||
* @apiParam {String} token TOTP token.
|
* @apiParam {String} token TOTP token.
|
||||||
*
|
*
|
||||||
* @apiSuccess (Success 302) Redirect to the URL that has been stored during last call to /verify.
|
* @apiSuccess (Success 302) Redirect to the URL that has been stored during last call to /api/verify.
|
||||||
* @apiError (Error 401) {none} error TOTP token is invalid.
|
* @apiError (Error 401) {none} error TOTP token is invalid.
|
||||||
*
|
*
|
||||||
* @apiDescription Verify TOTP token. The user is authenticated upon success.
|
* @apiDescription Verify TOTP token. The user is authenticated upon success.
|
||||||
|
@ -270,8 +270,13 @@ export const SECOND_FACTOR_GET = "/secondfactor";
|
||||||
* @apiVersion 1.0.0
|
* @apiVersion 1.0.0
|
||||||
* @apiUse UserSession
|
* @apiUse UserSession
|
||||||
*
|
*
|
||||||
|
* @apiParam {String} redirect Optional parameter set to the url where the user
|
||||||
|
* is redirected if access is refused. It is mainly used by Traefik that does
|
||||||
|
* not control the redirection itself.
|
||||||
|
*
|
||||||
* @apiSuccess (Success 204) status The user is authenticated.
|
* @apiSuccess (Success 204) status The user is authenticated.
|
||||||
* @apiError (Error 401) status The user is not authenticated.
|
* @apiError (Error 302) redirect The user is redirected if redirect parameter is provided.
|
||||||
|
* @apiError (Error 401) status The user get an error if access failed
|
||||||
*
|
*
|
||||||
* @apiDescription Verify that the user is authenticated, i.e., the two
|
* @apiDescription Verify that the user is authenticated, i.e., the two
|
||||||
* factors have been validated.
|
* factors have been validated.
|
||||||
|
|
9
test/features/authelia.feature
Normal file
9
test/features/authelia.feature
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
Feature: Generic tests on Authelia endpoints
|
||||||
|
|
||||||
|
Scenario: /api/verify replies with error when redirect parameter is not provided
|
||||||
|
When I query "https://authelia.example.com:8080/api/verify"
|
||||||
|
Then I get error code 401
|
||||||
|
|
||||||
|
Scenario: /api/verify redirects when redirect parameter is provided
|
||||||
|
When I query "https://authelia.example.com:8080/api/verify?redirect=http://login.example.com:8080"
|
||||||
|
Then I get redirected to "http://login.example.com:8080"
|
51
test/features/step_definitions/authelia.ts
Normal file
51
test/features/step_definitions/authelia.ts
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import Cucumber = require("cucumber");
|
||||||
|
import seleniumWebdriver = require("selenium-webdriver");
|
||||||
|
import Assert = require("assert");
|
||||||
|
import Request = require("request-promise");
|
||||||
|
import Bluebird = require("bluebird");
|
||||||
|
|
||||||
|
Cucumber.defineSupportCode(function ({ Given, When, Then, Before, After }) {
|
||||||
|
Before(function () {
|
||||||
|
this.jar = Request.jar();
|
||||||
|
})
|
||||||
|
|
||||||
|
When("I query {stringInDoubleQuotes}", function (url: string) {
|
||||||
|
const that = this;
|
||||||
|
return Request(url, { followRedirect: false })
|
||||||
|
.then(function(response) {
|
||||||
|
console.log(response);
|
||||||
|
that.response = response;
|
||||||
|
})
|
||||||
|
.catch(function(err: Error) {
|
||||||
|
that.error = err;
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
Then("I get error code 401", function() {
|
||||||
|
const that = this;
|
||||||
|
return new Bluebird(function(resolve, reject) {
|
||||||
|
if(that.error && that.error.statusCode == 401) {
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(that.response)
|
||||||
|
reject(new Error("No error thrown"));
|
||||||
|
else if(that.error.statusCode != 401)
|
||||||
|
reject(new Error("Error code != 401"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Then("I get redirected to {stringInDoubleQuotes}", function(url: string) {
|
||||||
|
const that = this;
|
||||||
|
return new Bluebird(function(resolve, reject) {
|
||||||
|
if(that.error && that.error.statusCode == 302
|
||||||
|
&& that.error.message.indexOf(url) > -1) {
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
reject(new Error("Not redirected"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user