[FEATURE] Add TLS support. (#677)
* [FEATURE] Add TLS support. Fixes #368. * [FEATURE] Introduce OnError hook in suites. This hook allows to perform actions following an erroneous suite like displaying the logs of Authelia. * Display Authelia logs of Standalone suite when tests fail. * Fix Standalone suite. * Apply suggestions from code review * Rename ssl_key and ssl_cert into tls_key and tls_cert.pull/680/head^2
parent
0c43740a4e
commit
faf43de14f
|
@ -151,6 +151,14 @@ func runOnSetupTimeout(suite string) error {
|
||||||
return utils.RunCommandWithTimeout(cmd, 15*time.Second)
|
return utils.RunCommandWithTimeout(cmd, 15*time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func runOnError(suite string) error {
|
||||||
|
cmd := utils.CommandWithStdout("go", "run", "cmd/authelia-suites/main.go", "error", suite)
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Env = os.Environ()
|
||||||
|
return utils.RunCommandWithTimeout(cmd, 15*time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
func setupSuite(suiteName string) error {
|
func setupSuite(suiteName string) error {
|
||||||
log.Infof("Setup environment for suite %s...", suiteName)
|
log.Infof("Setup environment for suite %s...", suiteName)
|
||||||
signalChannel := make(chan os.Signal)
|
signalChannel := make(chan os.Signal)
|
||||||
|
@ -261,11 +269,19 @@ func runSuiteTests(suiteName string, withEnv bool) error {
|
||||||
|
|
||||||
testErr := cmd.Run()
|
testErr := cmd.Run()
|
||||||
|
|
||||||
if withEnv {
|
// If the tests failed, run the error hook.
|
||||||
err := teardownSuite(suiteName)
|
if testErr != nil {
|
||||||
|
if err := runOnError(suiteName); err != nil {
|
||||||
|
// Do not return this error to return the test error instead
|
||||||
|
// and not skip the teardown phase.
|
||||||
|
log.Errorf("Error executing OnError callback: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if withEnv {
|
||||||
log.Error(err)
|
if err := teardownSuite(suiteName); err != nil {
|
||||||
|
// Do not return this error to return the test error instead
|
||||||
|
log.Errorf("Error running teardown: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,12 @@ func main() {
|
||||||
Run: setupTimeoutSuite,
|
Run: setupTimeoutSuite,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errorCmd := &cobra.Command{
|
||||||
|
Use: "error [suite]",
|
||||||
|
Short: "Run the OnError callback when some tests fail",
|
||||||
|
Run: runErrorCallback,
|
||||||
|
}
|
||||||
|
|
||||||
stopCmd := &cobra.Command{
|
stopCmd := &cobra.Command{
|
||||||
Use: "teardown [suite]",
|
Use: "teardown [suite]",
|
||||||
Short: "Teardown the suite environment",
|
Short: "Teardown the suite environment",
|
||||||
|
@ -46,8 +52,11 @@ func main() {
|
||||||
|
|
||||||
rootCmd.AddCommand(startCmd)
|
rootCmd.AddCommand(startCmd)
|
||||||
rootCmd.AddCommand(setupTimeoutCmd)
|
rootCmd.AddCommand(setupTimeoutCmd)
|
||||||
|
rootCmd.AddCommand(errorCmd)
|
||||||
rootCmd.AddCommand(stopCmd)
|
rootCmd.AddCommand(stopCmd)
|
||||||
rootCmd.Execute()
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createRunningSuiteFile(suite string) error {
|
func createRunningSuiteFile(suite string) error {
|
||||||
|
@ -120,6 +129,18 @@ func setupTimeoutSuite(cmd *cobra.Command, args []string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func runErrorCallback(cmd *cobra.Command, args []string) {
|
||||||
|
suiteName := args[0]
|
||||||
|
s := suites.GlobalRegistry.Get(suiteName)
|
||||||
|
|
||||||
|
if s.OnError == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := s.OnError(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func teardownSuite(cmd *cobra.Command, args []string) {
|
func teardownSuite(cmd *cobra.Command, args []string) {
|
||||||
if os.Getenv("SKIP_TEARDOWN") != "" {
|
if os.Getenv("SKIP_TEARDOWN") != "" {
|
||||||
return
|
return
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
# The host and port to listen on
|
# The host and port to listen on
|
||||||
host: 0.0.0.0
|
host: 0.0.0.0
|
||||||
port: 9091
|
port: 9091
|
||||||
|
# tls_key: /var/lib/authelia/ssl/key.pem
|
||||||
|
# tls_cert: /var/lib/authelia/ssl/cert.pem
|
||||||
|
|
||||||
# Level of verbosity for logs: info, debug, trace
|
# Level of verbosity for logs: info, debug, trace
|
||||||
logs_level: debug
|
logs_level: debug
|
||||||
|
|
|
@ -10,6 +10,7 @@ nav_order: 5
|
||||||
Here are the main customizable options in Authelia.
|
Here are the main customizable options in Authelia.
|
||||||
|
|
||||||
## Host & Port
|
## Host & Port
|
||||||
|
|
||||||
`optional: true`
|
`optional: true`
|
||||||
|
|
||||||
Defines the address to listen on.
|
Defines the address to listen on.
|
||||||
|
@ -17,6 +18,17 @@ Defines the address to listen on.
|
||||||
host: 0.0.0.0
|
host: 0.0.0.0
|
||||||
port: 9091
|
port: 9091
|
||||||
|
|
||||||
|
## TLS
|
||||||
|
|
||||||
|
`optional: true`
|
||||||
|
|
||||||
|
Authelia can use TLS. Provide the certificate and the key with the
|
||||||
|
following configuration options:
|
||||||
|
|
||||||
|
tls_key: /var/lib/authelia/ssl/key.pem
|
||||||
|
tls_cert: /var/lib/authelia/ssl/cert.pem
|
||||||
|
|
||||||
|
|
||||||
## Logs level
|
## Logs level
|
||||||
|
|
||||||
`optional: true`
|
`optional: true`
|
||||||
|
@ -50,4 +62,4 @@ can redirect her after the authentication process.
|
||||||
However, when a user visits the sign in portal directly, the portal considers
|
However, when a user visits the sign in portal directly, the portal considers
|
||||||
the targeted website is the portal. In that case and if the default redirection URL
|
the targeted website is the portal. In that case and if the default redirection URL
|
||||||
is configured, the user is redirected to that URL. If not defined, the user is not
|
is configured, the user is redirected to that URL. If not defined, the user is not
|
||||||
redirected after authentication.
|
redirected after authentication.
|
||||||
|
|
|
@ -2,8 +2,11 @@ package schema
|
||||||
|
|
||||||
// Configuration object extracted from YAML configuration file.
|
// Configuration object extracted from YAML configuration file.
|
||||||
type Configuration struct {
|
type Configuration struct {
|
||||||
Host string `mapstructure:"host"`
|
Host string `mapstructure:"host"`
|
||||||
Port int `mapstructure:"port"`
|
Port int `mapstructure:"port"`
|
||||||
|
TLSCert string `mapstructure:"tls_cert"`
|
||||||
|
TLSKey string `mapstructure:"tls_key"`
|
||||||
|
|
||||||
LogsLevel string `mapstructure:"logs_level"`
|
LogsLevel string `mapstructure:"logs_level"`
|
||||||
|
|
||||||
// This secret is used by the identity validation process to forge JWT tokens
|
// This secret is used by the identity validation process to forge JWT tokens
|
||||||
|
|
|
@ -24,6 +24,12 @@ func Validate(configuration *schema.Configuration, validator *schema.StructValid
|
||||||
configuration.LogsLevel = defaultLogsLevel
|
configuration.LogsLevel = defaultLogsLevel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if configuration.TLSKey != "" && configuration.TLSCert == "" {
|
||||||
|
validator.Push(fmt.Errorf("No TLS certificate provided, please check the \"tls_cert\" which has been configured"))
|
||||||
|
} else if configuration.TLSKey == "" && configuration.TLSCert != "" {
|
||||||
|
validator.Push(fmt.Errorf("No TLS key provided, please check the \"tls_key\" which has been configured"))
|
||||||
|
}
|
||||||
|
|
||||||
if configuration.DefaultRedirectionURL != "" {
|
if configuration.DefaultRedirectionURL != "" {
|
||||||
_, err := url.ParseRequestURI(configuration.DefaultRedirectionURL)
|
_, err := url.ParseRequestURI(configuration.DefaultRedirectionURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -99,3 +99,33 @@ func TestShouldAddDefaultAccessControl(t *testing.T) {
|
||||||
assert.NotNil(t, config.AccessControl)
|
assert.NotNil(t, config.AccessControl)
|
||||||
assert.Equal(t, "deny", config.AccessControl.DefaultPolicy)
|
assert.Equal(t, "deny", config.AccessControl.DefaultPolicy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestShouldRaiseErrorWhenTLSCertWithoutKeyIsProvided(t *testing.T) {
|
||||||
|
validator := schema.NewStructValidator()
|
||||||
|
config := newDefaultConfig()
|
||||||
|
config.TLSCert = "/tmp/cert.pem"
|
||||||
|
|
||||||
|
Validate(&config, validator)
|
||||||
|
require.Len(t, validator.Errors(), 1)
|
||||||
|
assert.EqualError(t, validator.Errors()[0], "No TLS key provided, please check the \"tls_key\" which has been configured")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShouldRaiseErrorWhenTLSKeyWithoutCertIsProvided(t *testing.T) {
|
||||||
|
validator := schema.NewStructValidator()
|
||||||
|
config := newDefaultConfig()
|
||||||
|
config.TLSKey = "/tmp/key.pem"
|
||||||
|
|
||||||
|
Validate(&config, validator)
|
||||||
|
require.Len(t, validator.Errors(), 1)
|
||||||
|
assert.EqualError(t, validator.Errors()[0], "No TLS certificate provided, please check the \"tls_cert\" which has been configured")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShouldNotRaiseErrorWhenBothTLSCertificateAndKeyAreProvided(t *testing.T) {
|
||||||
|
validator := schema.NewStructValidator()
|
||||||
|
config := newDefaultConfig()
|
||||||
|
config.TLSCert = "/tmp/cert.pem"
|
||||||
|
config.TLSKey = "/tmp/key.pem"
|
||||||
|
|
||||||
|
Validate(&config, validator)
|
||||||
|
require.Len(t, validator.Errors(), 0)
|
||||||
|
}
|
||||||
|
|
|
@ -101,9 +101,18 @@ func StartServer(configuration schema.Configuration, providers middlewares.Provi
|
||||||
ctx.SendFile(path.Join(publicDir, "index.html"))
|
ctx.SendFile(path.Join(publicDir, "index.html"))
|
||||||
}
|
}
|
||||||
|
|
||||||
portPattern := fmt.Sprintf("%s:%d", configuration.Host, configuration.Port)
|
addrPattern := fmt.Sprintf("%s:%d", configuration.Host, configuration.Port)
|
||||||
logging.Logger().Infof("Authelia is listening on %s", portPattern)
|
|
||||||
|
|
||||||
logging.Logger().Fatal(fasthttp.ListenAndServe(portPattern,
|
if configuration.TLSCert != "" && configuration.TLSKey != "" {
|
||||||
middlewares.LogRequestMiddleware(router.Handler)))
|
logging.Logger().Infof("Authelia is listening on %s and uses TLS", addrPattern)
|
||||||
|
|
||||||
|
logging.Logger().Fatal(fasthttp.ListenAndServeTLS(addrPattern,
|
||||||
|
configuration.TLSCert, configuration.TLSKey,
|
||||||
|
middlewares.LogRequestMiddleware(router.Handler)))
|
||||||
|
} else {
|
||||||
|
logging.Logger().Infof("Authelia is listening on %s and do not use TLS", addrPattern)
|
||||||
|
|
||||||
|
logging.Logger().Fatal(fasthttp.ListenAndServe(addrPattern,
|
||||||
|
middlewares.LogRequestMiddleware(router.Handler)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
###############################################################
|
###############################################################
|
||||||
|
|
||||||
port: 9091
|
port: 9091
|
||||||
|
tls_cert: /var/lib/authelia/ssl/cert.pem
|
||||||
|
tls_key: /var/lib/authelia/ssl/key.pem
|
||||||
|
|
||||||
logs_level: debug
|
logs_level: debug
|
||||||
|
|
||||||
|
|
|
@ -7,5 +7,6 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- './Standalone/configuration.yml:/etc/authelia/configuration.yml:ro'
|
- './Standalone/configuration.yml:/etc/authelia/configuration.yml:ro'
|
||||||
- './Standalone/users.yml:/var/lib/authelia/users.yml'
|
- './Standalone/users.yml:/var/lib/authelia/users.yml'
|
||||||
|
- './Standalone/ssl:/var/lib/authelia/ssl'
|
||||||
- '/tmp:/tmp'
|
- '/tmp:/tmp'
|
||||||
user: ${USER_ID}:${GROUP_ID}
|
user: ${USER_ID}:${GROUP_ID}
|
|
@ -0,0 +1,19 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIC/jCCAeagAwIBAgIRAKF0IRxC55eee6icERVf6fgwDQYJKoZIhvcNAQELBQAw
|
||||||
|
EjEQMA4GA1UEChMHQWNtZSBDbzAgFw0yMDAzMDExMjMzMzlaGA8yMTIwMDIwNjEy
|
||||||
|
MzMzOVowEjEQMA4GA1UEChMHQWNtZSBDbzCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||||
|
ADCCAQoCggEBAMi7/oSazFIxP3rHsSLjw5XPnpMKEaVwU1zLRzW6W80BDa/ER5to
|
||||||
|
I3POGLv8lAhtUwB6WvyilrCZfs/D5lkcCxswafU/2LNppFuODnW+PG9eobgOy6Nv
|
||||||
|
f+KbnZFPRV7PB2yK6DqMyb+tbTQ7F6rEf4i6n28DI0dNyNvUCk0ld3o93LZBvC/D
|
||||||
|
/+Ulf3Vtdfsd2TckXvdA8lH4VGQJ+FIxhboTlbW8VJlk1V7FZef7+m867kOnPSaj
|
||||||
|
zv5yygrIA0XPaMAZC/SZrXHMdhvcs43fgmmTel7JD4Sy/Z/pmFlrZr5Xa8jcWycJ
|
||||||
|
ILLuPnXhgKstgq5wtDkTMZ6rpgMrKcjMKcMCAwEAAaNNMEswDgYDVR0PAQH/BAQD
|
||||||
|
AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwFgYDVR0RBA8w
|
||||||
|
DYILZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQADggEBABdWkbipzPivAvvamMmQ
|
||||||
|
5iPPeStfdr5MBxJGT9nPbeXdtS/13FJnspLBMMYOw/2AZk7VFrNjxkXc4NHZSlGz
|
||||||
|
FcGMlSO40fyirdYaQTDtS230ucLB+LzfZx37y9dKpEKVmQ151kKJjJ4hAZ47LmAQ
|
||||||
|
aFoDLRo7PA2HmnJ60GrI9wVp96uy1sQ6PcToIyMcVEQ/tLEEow+ykSeiZb9+qBKV
|
||||||
|
K9GUcu2LorhBtUMmEWs0TJElaf6eKUoG6JXM2byulDg24w5b9gC26kAlHWc5WDU5
|
||||||
|
pAXOjlN/OYHB0sDbYViWIL390376fYIfu2N5EDKY4QjEYsWEs4Wm9HVS9IgHP/Gi
|
||||||
|
Xbo=
|
||||||
|
-----END CERTIFICATE-----
|
|
@ -0,0 +1,28 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDIu/6EmsxSMT96
|
||||||
|
x7Ei48OVz56TChGlcFNcy0c1ulvNAQ2vxEebaCNzzhi7/JQIbVMAelr8opawmX7P
|
||||||
|
w+ZZHAsbMGn1P9izaaRbjg51vjxvXqG4Dsujb3/im52RT0Vezwdsiug6jMm/rW00
|
||||||
|
OxeqxH+Iup9vAyNHTcjb1ApNJXd6Pdy2Qbwvw//lJX91bXX7Hdk3JF73QPJR+FRk
|
||||||
|
CfhSMYW6E5W1vFSZZNVexWXn+/pvOu5Dpz0mo87+csoKyANFz2jAGQv0ma1xzHYb
|
||||||
|
3LON34Jpk3peyQ+Esv2f6ZhZa2a+V2vI3FsnCSCy7j514YCrLYKucLQ5EzGeq6YD
|
||||||
|
KynIzCnDAgMBAAECggEAC13R0LJvRWwyewJZvm8FQTNreEoGq8aLgeKk2p792cLo
|
||||||
|
gn5ry5n+/+y4q9RmkX+XRpynEE0omUFn09306jDTVCvOpCuEWsxtmR2XJgWqqGfE
|
||||||
|
Yoa78zo6FJvZNUQ22mKAuh23frFAL1FjsKRz96B+1EA1DPUxhzUZXZFJMAsiE9LZ
|
||||||
|
PxqPmnqXbPZsOb1XG33TAdCp6CC3H8KHICC+i4IC8prjKHGH/Q1saoNw8jmgwv0S
|
||||||
|
DelQUbEtqfmE6BmyTGxdeu4uW2Nv/wcENwySAOPKi5gstlbSKTa4IpKGp7CdquWi
|
||||||
|
stUW6pnSiEeDrDAzwC8uWdncOvnkAy2lRJkz/F9YoQKBgQDrCCqYdvGshecBBnfQ
|
||||||
|
fowxak2YBfG2jhAKPMHzrvQn5FIb+11x/jeXPEfOB6FShIzZ97JpFIpH3tcONlj3
|
||||||
|
OVzGCTD6WdRTcltzXVneJtNog7DliNFY4YmIPmQJ+y+EvJW1rSZTZAZI1Nbijg3n
|
||||||
|
fSd0PTzvgOGHSl1//RI1mFx7MwKBgQDapIPPSF0yf1UJ6Hhzam5NHGZ9fSqV5Qs0
|
||||||
|
Gi7uM08iDV5K7xiPglBkbN2EuMlgVnHaa5g8X897uwRSYR6nL4PRvcJiNSvnhWhe
|
||||||
|
+K3x7iHewIPYVfcghoqzuPKsXH2Zm26usdXHxBBa3IBbKtGaHnAd9h65AOUYAmAx
|
||||||
|
C2BzN90XMQKBgE2MjEFyPZunMulrsOziVG+Zm7ClhXOuvCwkj/pPp8/hzhXdgp+y
|
||||||
|
ObV09lxMuDX59l+VExEI7fd414yg8gngq3PMZJS2PxCpkvMlwhlCxk6d5ShXVHv3
|
||||||
|
LuH9dBS3BJ7PerZPQ24QeuJdF+n45S2UZgg8jHaaF9AEAYXRgsicVSdxAoGAJI0U
|
||||||
|
K/bg/awjv0BJwqGsRt/Ukm32TJC5ysAF0HRrajnp5YULChKy9dbtQV7S63QIHIeY
|
||||||
|
L5+kw/6DvnHV+gULeGjMsjZJXK8Ev7u6+JLivqZYZDYa1iknztvAVegwZxmA61t3
|
||||||
|
bantQgNSwerql2U3QQsAH9Vydw0On6RTP2+7WkECgYBWD3u64hBKmAxPkqPotkgI
|
||||||
|
w/jdOlv8FLHO79+oH1PtKvkzspcYaecKGDm/RNLIXLYnt0AmZEK4qQ4/zDFaR/rc
|
||||||
|
AhoxK2cKTRltMrhp1ivtFfLggVGogtYNxEnjnsD4KMvH3SjSNdt06YgtZ92++fOp
|
||||||
|
UsE8Mpf4/G5X7DmcHJHk+w==
|
||||||
|
-----END PRIVATE KEY-----
|
|
@ -39,4 +39,4 @@ var MX2MailBaseURL = fmt.Sprintf("https://mx2.mail.%s", BaseDomain)
|
||||||
var DuoBaseURL = "https://duo.example.com"
|
var DuoBaseURL = "https://duo.example.com"
|
||||||
|
|
||||||
// AutheliaBaseURL the base URL of Authelia service
|
// AutheliaBaseURL the base URL of Authelia service
|
||||||
var AutheliaBaseURL = "http://authelia.example.com:9091"
|
var AutheliaBaseURL = "https://authelia.example.com:9091"
|
||||||
|
|
|
@ -14,4 +14,14 @@ http {
|
||||||
proxy_pass http://authelia-backend:9091;
|
proxy_pass http://authelia-backend:9091;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
# Reach authelia-backend using TLS.
|
||||||
|
listen 3001;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_pass https://authelia-backend:9091;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
nginx-portal:
|
||||||
|
image: nginx:alpine
|
||||||
|
volumes:
|
||||||
|
- ./example/compose/nginx/portal/nginx.https.conf:/etc/nginx/nginx.conf
|
||||||
|
- ./example/compose/nginx/portal/ssl:/etc/ssl
|
||||||
|
networks:
|
||||||
|
authelianet:
|
||||||
|
aliases:
|
||||||
|
- public.example.com
|
||||||
|
- secure.example.com
|
||||||
|
- login.example.com
|
||||||
|
- duo.example.com
|
||||||
|
# Set the IP to be able to query on port 443
|
||||||
|
ipv4_address: 192.168.240.100
|
|
@ -0,0 +1,227 @@
|
||||||
|
#
|
||||||
|
# You can find a documented example of configuration in ./docs/proxies/nginx.md.
|
||||||
|
#
|
||||||
|
worker_processes 1;
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
server {
|
||||||
|
listen 8080 ssl;
|
||||||
|
server_name login.example.com;
|
||||||
|
|
||||||
|
resolver 127.0.0.11 ipv6=off;
|
||||||
|
set $frontend_endpoint http://authelia-frontend:3001;
|
||||||
|
set $backend_endpoint https://authelia-backend:9091;
|
||||||
|
|
||||||
|
ssl_certificate /etc/ssl/server.cert;
|
||||||
|
ssl_certificate_key /etc/ssl/server.key;
|
||||||
|
|
||||||
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN";
|
||||||
|
|
||||||
|
# Serve the backend API for the portal.
|
||||||
|
location /api {
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
|
||||||
|
# Required by Authelia because "trust proxy" option is used.
|
||||||
|
# See https://expressjs.com/en/guide/behind-proxies.html
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
# Required by Authelia to build correct links for identity validation.
|
||||||
|
proxy_set_header X-Forwarded-Host $http_host;
|
||||||
|
|
||||||
|
# Needed for network ACLs to work. It appends the IP of the client to the list of IPs
|
||||||
|
# and allows Authelia to use it to match the network-based ACLs.
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
|
||||||
|
proxy_intercept_errors on;
|
||||||
|
|
||||||
|
proxy_pass $backend_endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Serves the portal application.
|
||||||
|
location / {
|
||||||
|
# Allow websockets for webpack to auto-reload.
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "Upgrade";
|
||||||
|
proxy_set_header Host "127.0.0.1";
|
||||||
|
|
||||||
|
proxy_pass $frontend_endpoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Serves the home page.
|
||||||
|
server {
|
||||||
|
listen 8080 ssl;
|
||||||
|
server_name home.example.com;
|
||||||
|
|
||||||
|
resolver 127.0.0.11 ipv6=off;
|
||||||
|
set $upstream_endpoint http://nginx-backend;
|
||||||
|
|
||||||
|
ssl_certificate /etc/ssl/server.cert;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Example configuration of domains protected by Authelia.
|
||||||
|
server {
|
||||||
|
listen 8080 ssl;
|
||||||
|
server_name public.example.com
|
||||||
|
admin.example.com
|
||||||
|
secure.example.com
|
||||||
|
dev.example.com
|
||||||
|
singlefactor.example.com
|
||||||
|
mx1.mail.example.com mx2.mail.example.com;
|
||||||
|
|
||||||
|
resolver 127.0.0.11 ipv6=off;
|
||||||
|
set $upstream_verify https://authelia-backend:9091/api/verify;
|
||||||
|
set $upstream_endpoint http://nginx-backend;
|
||||||
|
set $upstream_headers http://httpbin:8000/headers;
|
||||||
|
|
||||||
|
ssl_certificate /etc/ssl/server.cert;
|
||||||
|
ssl_certificate_key /etc/ssl/server.key;
|
||||||
|
|
||||||
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN";
|
||||||
|
|
||||||
|
# Reverse proxy to the backend. It is protected by Authelia by forwarding authorization checks
|
||||||
|
# to the virtual endpoint introduced by nginx and declared in the next block.
|
||||||
|
location / {
|
||||||
|
auth_request /auth_verify;
|
||||||
|
|
||||||
|
auth_request_set $user $upstream_http_remote_user;
|
||||||
|
proxy_set_header X-Forwarded-User $user;
|
||||||
|
|
||||||
|
auth_request_set $groups $upstream_http_remote_groups;
|
||||||
|
proxy_set_header Remote-Groups $groups;
|
||||||
|
|
||||||
|
# Route the request to the correct virtual host in the backend.
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
|
||||||
|
# Authelia relies on Proxy-Authorization header to authenticate in basic auth.
|
||||||
|
# but for the sake of simplicity (because Authorization in supported in most
|
||||||
|
# clients) we take Authorization from the frontend and rewrite it to
|
||||||
|
# Proxy-Authorization before sending it to Authelia.
|
||||||
|
proxy_set_header Proxy-Authorization $http_authorization;
|
||||||
|
|
||||||
|
# mitigate HTTPoxy Vulnerability
|
||||||
|
# https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/
|
||||||
|
proxy_set_header Proxy "";
|
||||||
|
|
||||||
|
# Set the `target_url` variable based on the request. It will be used to build the portal
|
||||||
|
# URL with the correct redirection parameter.
|
||||||
|
set $target_url $scheme://$http_host$request_uri;
|
||||||
|
error_page 401 =302 https://login.example.com:8080/?rd=$target_url;
|
||||||
|
|
||||||
|
proxy_pass $upstream_endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Virtual endpoint forwarding requests to Authelia server.
|
||||||
|
location /auth_verify {
|
||||||
|
internal;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
|
||||||
|
# Provide either X-Original-URL and X-Forwarded-Proto or
|
||||||
|
# X-Forwarded-Proto, X-Forwarded-Host and X-Forwarded-URI or both.
|
||||||
|
# Those headers will be used by Authelia to deduce the target url of the user.
|
||||||
|
#
|
||||||
|
# X-Forwarded-Proto is mandatory since Authelia uses the "trust proxy" option.
|
||||||
|
# See https://expressjs.com/en/guide/behind-proxies.html
|
||||||
|
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
|
||||||
|
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header X-Forwarded-Host $http_host;
|
||||||
|
proxy_set_header X-Forwarded-URI $request_uri;
|
||||||
|
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
|
||||||
|
# Authelia can receive Proxy-Authorization to authenticate however most of the clients
|
||||||
|
# support Authorization instead. Therefore we rewrite Authorization into Proxy-Authorization.
|
||||||
|
proxy_set_header Proxy-Authorization $http_authorization;
|
||||||
|
|
||||||
|
proxy_pass_request_body off;
|
||||||
|
proxy_set_header Content-Length "";
|
||||||
|
|
||||||
|
proxy_pass $upstream_verify;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Used by suites to test the forwarded users and groups headers produced by Authelia.
|
||||||
|
location /headers {
|
||||||
|
auth_request /auth_verify;
|
||||||
|
|
||||||
|
auth_request_set $user $upstream_http_remote_user;
|
||||||
|
proxy_set_header Custom-Forwarded-User $user;
|
||||||
|
|
||||||
|
auth_request_set $groups $upstream_http_remote_groups;
|
||||||
|
proxy_set_header Custom-Forwarded-Groups $groups;
|
||||||
|
|
||||||
|
set $target_url $scheme://$http_host$request_uri;
|
||||||
|
error_page 401 =302 https://login.example.com:8080/?rd=$target_url;
|
||||||
|
|
||||||
|
proxy_pass $upstream_headers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Fake Web Mail used to receive emails sent by Authelia.
|
||||||
|
server {
|
||||||
|
listen 8080 ssl;
|
||||||
|
server_name mail.example.com;
|
||||||
|
|
||||||
|
resolver 127.0.0.11 ipv6=off;
|
||||||
|
set $upstream_endpoint http://smtp:1080;
|
||||||
|
|
||||||
|
ssl_certificate /etc/ssl/server.cert;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Fake API emulating Duo behavior
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
server_name duo.example.com;
|
||||||
|
|
||||||
|
resolver 127.0.0.11 ipv6=off;
|
||||||
|
set $upstream_endpoint http://duo-api:3000;
|
||||||
|
|
||||||
|
ssl_certificate /etc/ssl/server.cert;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Matches all domains. It redirects to the home page.
|
||||||
|
server {
|
||||||
|
listen 8080 ssl;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
ssl_certificate /etc/ssl/server.cert;
|
||||||
|
ssl_certificate_key /etc/ssl/server.key;
|
||||||
|
|
||||||
|
return 301 https://home.example.com:8080/;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,10 +9,15 @@ import (
|
||||||
|
|
||||||
// Suite the definition of a suite
|
// Suite the definition of a suite
|
||||||
type Suite struct {
|
type Suite struct {
|
||||||
SetUp func(tmpPath string) error
|
SetUp func(tmpPath string) error
|
||||||
SetUpTimeout time.Duration
|
SetUpTimeout time.Duration
|
||||||
|
|
||||||
|
// Callback called when an error occur during setup phase.
|
||||||
OnSetupTimeout func() error
|
OnSetupTimeout func() error
|
||||||
|
|
||||||
|
// Callback called when at least one test fail
|
||||||
|
OnError func() error
|
||||||
|
|
||||||
TestTimeout time.Duration
|
TestTimeout time.Duration
|
||||||
|
|
||||||
TearDown func(tmpPath string) error
|
TearDown func(tmpPath string) error
|
||||||
|
|
|
@ -9,6 +9,8 @@ import (
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// WARNING: This scenario is intended to be used with TLS enabled in the authelia backend.
|
||||||
|
|
||||||
type BackendProtectionScenario struct {
|
type BackendProtectionScenario struct {
|
||||||
suite.Suite
|
suite.Suite
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ func init() {
|
||||||
"internal/suites/example/compose/authelia/docker-compose.backend.{}.yml",
|
"internal/suites/example/compose/authelia/docker-compose.backend.{}.yml",
|
||||||
"internal/suites/example/compose/authelia/docker-compose.frontend.{}.yml",
|
"internal/suites/example/compose/authelia/docker-compose.frontend.{}.yml",
|
||||||
"internal/suites/example/compose/nginx/backend/docker-compose.yml",
|
"internal/suites/example/compose/nginx/backend/docker-compose.yml",
|
||||||
"internal/suites/example/compose/nginx/portal/docker-compose.yml",
|
"internal/suites/example/compose/nginx/portal/docker-compose.https.yml",
|
||||||
"internal/suites/example/compose/smtp/docker-compose.yml",
|
"internal/suites/example/compose/smtp/docker-compose.yml",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ func init() {
|
||||||
return waitUntilAutheliaBackendIsReady(dockerEnvironment)
|
return waitUntilAutheliaBackendIsReady(dockerEnvironment)
|
||||||
}
|
}
|
||||||
|
|
||||||
onSetupTimeout := func() error {
|
displayAutheliaLogs := func() error {
|
||||||
backendLogs, err := dockerEnvironment.Logs("authelia-backend", nil)
|
backendLogs, err := dockerEnvironment.Logs("authelia-backend", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -51,7 +51,8 @@ func init() {
|
||||||
GlobalRegistry.Register(standaloneSuiteName, Suite{
|
GlobalRegistry.Register(standaloneSuiteName, Suite{
|
||||||
SetUp: setup,
|
SetUp: setup,
|
||||||
SetUpTimeout: 5 * time.Minute,
|
SetUpTimeout: 5 * time.Minute,
|
||||||
OnSetupTimeout: onSetupTimeout,
|
OnError: displayAutheliaLogs,
|
||||||
|
OnSetupTimeout: displayAutheliaLogs,
|
||||||
TearDown: teardown,
|
TearDown: teardown,
|
||||||
TestTimeout: 3 * time.Minute,
|
TestTimeout: 3 * time.Minute,
|
||||||
TearDownTimeout: 2 * time.Minute,
|
TearDownTimeout: 2 * time.Minute,
|
||||||
|
|
Loading…
Reference in New Issue