feat(configuration): mtls clients (#4221)
This implements mTLS support for LDAP, Redis, and SMTP. Specified via the tls.certificate_chain and tls.private_key options. Closes #4044pull/4222/head
parent
6e835bd8f8
commit
9532823a99
|
@ -315,6 +315,82 @@ authentication_backend:
|
||||||
## Minimum TLS version for either Secure LDAP or LDAP StartTLS.
|
## Minimum TLS version for either Secure LDAP or LDAP StartTLS.
|
||||||
minimum_version: TLS1.2
|
minimum_version: TLS1.2
|
||||||
|
|
||||||
|
## Maximum TLS version for either Secure LDAP or LDAP StartTLS.
|
||||||
|
maximum_version: TLS1.3
|
||||||
|
|
||||||
|
## The certificate chain used with the private_key if the server requests TLS Client Authentication
|
||||||
|
## i.e. Mutual TLS.
|
||||||
|
# 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-----
|
||||||
|
|
||||||
|
## The private key used with the certificate_chain if the server requests TLS Client Authentication
|
||||||
|
## i.e. Mutual TLS.
|
||||||
|
# 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-----
|
||||||
|
|
||||||
## The distinguished name of the container searched for objects in the directory information tree.
|
## The distinguished name of the container searched for objects in the directory information tree.
|
||||||
## See also: additional_users_dn, additional_groups_dn.
|
## See also: additional_users_dn, additional_groups_dn.
|
||||||
base_dn: dc=example,dc=com
|
base_dn: dc=example,dc=com
|
||||||
|
|
|
@ -28,6 +28,74 @@ authentication_backend:
|
||||||
server_name: ldap.example.com
|
server_name: ldap.example.com
|
||||||
skip_verify: false
|
skip_verify: false
|
||||||
minimum_version: TLS1.2
|
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
|
base_dn: DC=example,DC=com
|
||||||
additional_users_dn: ou=users
|
additional_users_dn: ou=users
|
||||||
users_filter: (&({username_attribute}={input})(objectClass=person))
|
users_filter: (&({username_attribute}={input})(objectClass=person))
|
||||||
|
|
|
@ -37,6 +37,74 @@ notifier:
|
||||||
server_name: smtp.example.com
|
server_name: smtp.example.com
|
||||||
skip_verify: false
|
skip_verify: false
|
||||||
minimum_version: TLS1.2
|
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
|
## Options
|
||||||
|
@ -139,9 +207,9 @@ for more information. This option disables this measure (not recommended).
|
||||||
|
|
||||||
Some SMTP servers ignore SMTP specifications and claim to support STARTTLS when they in fact do not.
|
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.
|
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__*
|
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
|
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
|
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.
|
lodging an issue with the authors of the SMTP server.
|
||||||
See [security] for more information.
|
See [security] for more information.
|
||||||
|
|
||||||
|
|
|
@ -129,10 +129,39 @@ instead you should tweak the `server_name` option, and the global option
|
||||||
|
|
||||||
{{< confkey type="string" default="TLS1.2" required="no" >}}
|
{{< confkey type="string" default="TLS1.2" required="no" >}}
|
||||||
|
|
||||||
The key `minimum_version` controls the minimum TLS version Authelia will use when opening TLS connections.
|
Controls the minimum TLS version Authelia will use when performing TLS handshakes.
|
||||||
The possible values are `TLS1.3`, `TLS1.2`, `TLS1.1`, `TLS1.0`. Anything other than `TLS1.3` or `TLS1.2`
|
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
|
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
|
## Server Buffers
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,74 @@ session:
|
||||||
server_name: myredis.example.com
|
server_name: myredis.example.com
|
||||||
skip_verify: false
|
skip_verify: false
|
||||||
minimum_version: TLS1.2
|
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:
|
high_availability:
|
||||||
sentinel_name: mysentinel
|
sentinel_name: mysentinel
|
||||||
# If `sentinel_username` is supplied, Authelia will connect using ACL-based
|
# If `sentinel_username` is supplied, Authelia will connect using ACL-based
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -53,7 +53,7 @@ func newLDAPUserProvider(config schema.LDAPAuthenticationBackend, disableResetPa
|
||||||
config.TLS = schema.DefaultLDAPAuthenticationBackendConfigurationImplementationCustom.TLS
|
config.TLS = schema.DefaultLDAPAuthenticationBackendConfigurationImplementationCustom.TLS
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsConfig := utils.NewTLSConfig(config.TLS, tls.VersionTLS12, certPool)
|
tlsConfig := utils.NewTLSConfig(config.TLS, certPool)
|
||||||
|
|
||||||
var dialOpts = []ldap.DialOpt{
|
var dialOpts = []ldap.DialOpt{
|
||||||
ldap.DialWithDialer(&net.Dialer{Timeout: config.Timeout}),
|
ldap.DialWithDialer(&net.Dialer{Timeout: config.Timeout}),
|
||||||
|
|
|
@ -315,6 +315,82 @@ authentication_backend:
|
||||||
## Minimum TLS version for either Secure LDAP or LDAP StartTLS.
|
## Minimum TLS version for either Secure LDAP or LDAP StartTLS.
|
||||||
minimum_version: TLS1.2
|
minimum_version: TLS1.2
|
||||||
|
|
||||||
|
## Maximum TLS version for either Secure LDAP or LDAP StartTLS.
|
||||||
|
maximum_version: TLS1.3
|
||||||
|
|
||||||
|
## The certificate chain used with the private_key if the server requests TLS Client Authentication
|
||||||
|
## i.e. Mutual TLS.
|
||||||
|
# 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-----
|
||||||
|
|
||||||
|
## The private key used with the certificate_chain if the server requests TLS Client Authentication
|
||||||
|
## i.e. Mutual TLS.
|
||||||
|
# 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-----
|
||||||
|
|
||||||
## The distinguished name of the container searched for objects in the directory information tree.
|
## The distinguished name of the container searched for objects in the directory information tree.
|
||||||
## See also: additional_users_dn, additional_groups_dn.
|
## See also: additional_users_dn, additional_groups_dn.
|
||||||
base_dn: dc=example,dc=com
|
base_dn: dc=example,dc=com
|
||||||
|
|
|
@ -346,6 +346,76 @@ func StringToX509CertificateChainHookFunc() mapstructure.DecodeHookFuncType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StringToTLSVersionHookFunc decodes strings to schema.TLSVersion's.
|
||||||
|
func StringToTLSVersionHookFunc() mapstructure.DecodeHookFuncType {
|
||||||
|
return func(f reflect.Type, t reflect.Type, data interface{}) (value interface{}, err error) {
|
||||||
|
var ptr bool
|
||||||
|
|
||||||
|
if f.Kind() != reflect.String {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
prefixType := ""
|
||||||
|
|
||||||
|
if t.Kind() == reflect.Ptr {
|
||||||
|
ptr = true
|
||||||
|
prefixType = "*"
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedType := reflect.TypeOf(schema.TLSVersion{})
|
||||||
|
|
||||||
|
if ptr && t.Elem() != expectedType {
|
||||||
|
return data, nil
|
||||||
|
} else if !ptr && t != expectedType {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dataStr := data.(string)
|
||||||
|
|
||||||
|
var result *schema.TLSVersion
|
||||||
|
|
||||||
|
if result, err = schema.NewTLSVersion(dataStr); err != nil {
|
||||||
|
return nil, fmt.Errorf(errFmtDecodeHookCouldNotParse, dataStr, prefixType, expectedType, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ptr {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return *result, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringToCryptoPrivateKeyHookFunc decodes strings to schema.CryptographicPrivateKey's.
|
||||||
|
func StringToCryptoPrivateKeyHookFunc() mapstructure.DecodeHookFuncType {
|
||||||
|
return func(f reflect.Type, t reflect.Type, data interface{}) (value interface{}, err error) {
|
||||||
|
if f.Kind() != reflect.String {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
field, _ := reflect.TypeOf(schema.TLSConfig{}).FieldByName("PrivateKey")
|
||||||
|
expectedType := field.Type
|
||||||
|
|
||||||
|
if t != expectedType {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dataStr := data.(string)
|
||||||
|
|
||||||
|
var i any
|
||||||
|
|
||||||
|
if i, err = utils.ParseX509FromPEM([]byte(dataStr)); err != nil {
|
||||||
|
return nil, fmt.Errorf(errFmtDecodeHookCouldNotParseBasic, "", expectedType, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result, ok := i.(schema.CryptographicPrivateKey); !ok {
|
||||||
|
return nil, fmt.Errorf(errFmtDecodeHookCouldNotParseBasic, "", expectedType, fmt.Errorf("the data is for a %T not a %s", i, expectedType))
|
||||||
|
} else {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// StringToPrivateKeyHookFunc decodes strings to rsa.PrivateKey's.
|
// StringToPrivateKeyHookFunc decodes strings to rsa.PrivateKey's.
|
||||||
func StringToPrivateKeyHookFunc() mapstructure.DecodeHookFuncType {
|
func StringToPrivateKeyHookFunc() mapstructure.DecodeHookFuncType {
|
||||||
return func(f reflect.Type, t reflect.Type, data interface{}) (value interface{}, err error) {
|
return func(f reflect.Type, t reflect.Type, data interface{}) (value interface{}, err error) {
|
||||||
|
|
|
@ -64,6 +64,8 @@ func unmarshal(ko *koanf.Koanf, val *schema.StructValidator, path string, o any)
|
||||||
StringToX509CertificateHookFunc(),
|
StringToX509CertificateHookFunc(),
|
||||||
StringToX509CertificateChainHookFunc(),
|
StringToX509CertificateChainHookFunc(),
|
||||||
StringToPrivateKeyHookFunc(),
|
StringToPrivateKeyHookFunc(),
|
||||||
|
StringToCryptoPrivateKeyHookFunc(),
|
||||||
|
StringToTLSVersionHookFunc(),
|
||||||
StringToPasswordDigestHookFunc(true),
|
StringToPasswordDigestHookFunc(true),
|
||||||
ToTimeDurationHookFunc(),
|
ToTimeDurationHookFunc(),
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package schema
|
package schema
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -180,7 +181,7 @@ var DefaultLDAPAuthenticationBackendConfigurationImplementationCustom = LDAPAuth
|
||||||
GroupNameAttribute: "cn",
|
GroupNameAttribute: "cn",
|
||||||
Timeout: time.Second * 5,
|
Timeout: time.Second * 5,
|
||||||
TLS: &TLSConfig{
|
TLS: &TLSConfig{
|
||||||
MinimumVersion: "TLS1.2",
|
MinimumVersion: TLSVersion{tls.VersionTLS12},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,6 +195,6 @@ var DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory =
|
||||||
GroupNameAttribute: "cn",
|
GroupNameAttribute: "cn",
|
||||||
Timeout: time.Second * 5,
|
Timeout: time.Second * 5,
|
||||||
TLS: &TLSConfig{
|
TLS: &TLSConfig{
|
||||||
MinimumVersion: "TLS1.2",
|
MinimumVersion: TLSVersion{tls.VersionTLS12},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package schema
|
package schema
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"regexp"
|
"regexp"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -9,20 +10,51 @@ const (
|
||||||
argon2 = "argon2"
|
argon2 = "argon2"
|
||||||
argon2id = "argon2id"
|
argon2id = "argon2id"
|
||||||
sha512 = "sha512"
|
sha512 = "sha512"
|
||||||
sha256 = "sha256"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProfileRefreshDisabled represents a value for refresh_interval that disables the check entirely.
|
const (
|
||||||
|
// TLSVersion13 is the textual representation of TLS 1.3.
|
||||||
|
TLSVersion13 = "TLS1.3"
|
||||||
|
|
||||||
|
// TLSVersion12 is the textual representation of TLS 1.2.
|
||||||
|
TLSVersion12 = "TLS1.2"
|
||||||
|
|
||||||
|
// TLSVersion11 is the textual representation of TLS 1.1.
|
||||||
|
TLSVersion11 = "TLS1.1"
|
||||||
|
|
||||||
|
// TLSVersion10 is the textual representation of TLS 1.0.
|
||||||
|
TLSVersion10 = "TLS1.0"
|
||||||
|
|
||||||
|
// SSLVersion30 is the textual representation of SSL 3.0.
|
||||||
|
SSLVersion30 = "SSL3.0"
|
||||||
|
|
||||||
|
// Version13 is the textual representation of version 1.3.
|
||||||
|
Version13 = "1.3"
|
||||||
|
|
||||||
|
// Version12 is the textual representation of version 1.2.
|
||||||
|
Version12 = "1.2"
|
||||||
|
|
||||||
|
// Version11 is the textual representation of version 1.1.
|
||||||
|
Version11 = "1.1"
|
||||||
|
|
||||||
|
// Version10 is the textual representation of version 1.0.
|
||||||
|
Version10 = "1.0"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrTLSVersionNotSupported returned when an unknown TLS version supplied.
|
||||||
|
var ErrTLSVersionNotSupported = errors.New("supplied tls version isn't supported")
|
||||||
|
|
||||||
|
// ProfileRefreshDisabled represents a Value for refresh_interval that disables the check entirely.
|
||||||
const ProfileRefreshDisabled = "disable"
|
const ProfileRefreshDisabled = "disable"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// ProfileRefreshAlways represents a value for refresh_interval that's the same as 0ms.
|
// ProfileRefreshAlways represents a Value for refresh_interval that's the same as 0ms.
|
||||||
ProfileRefreshAlways = "always"
|
ProfileRefreshAlways = "always"
|
||||||
|
|
||||||
// RefreshIntervalDefault represents the default value of refresh_interval.
|
// RefreshIntervalDefault represents the default Value of refresh_interval.
|
||||||
RefreshIntervalDefault = "5m"
|
RefreshIntervalDefault = "5m"
|
||||||
|
|
||||||
// RefreshIntervalAlways represents the duration value refresh interval should have if set to always.
|
// RefreshIntervalAlways represents the duration Value refresh interval should have if set to always.
|
||||||
RefreshIntervalAlways = 0 * time.Millisecond
|
RefreshIntervalAlways = 0 * time.Millisecond
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -84,8 +84,11 @@ var Keys = []string{
|
||||||
"authentication_backend.ldap.timeout",
|
"authentication_backend.ldap.timeout",
|
||||||
"authentication_backend.ldap.start_tls",
|
"authentication_backend.ldap.start_tls",
|
||||||
"authentication_backend.ldap.tls.minimum_version",
|
"authentication_backend.ldap.tls.minimum_version",
|
||||||
|
"authentication_backend.ldap.tls.maximum_version",
|
||||||
"authentication_backend.ldap.tls.skip_verify",
|
"authentication_backend.ldap.tls.skip_verify",
|
||||||
"authentication_backend.ldap.tls.server_name",
|
"authentication_backend.ldap.tls.server_name",
|
||||||
|
"authentication_backend.ldap.tls.private_key",
|
||||||
|
"authentication_backend.ldap.tls.certificate_chain",
|
||||||
"authentication_backend.ldap.base_dn",
|
"authentication_backend.ldap.base_dn",
|
||||||
"authentication_backend.ldap.additional_users_dn",
|
"authentication_backend.ldap.additional_users_dn",
|
||||||
"authentication_backend.ldap.users_filter",
|
"authentication_backend.ldap.users_filter",
|
||||||
|
@ -115,8 +118,11 @@ var Keys = []string{
|
||||||
"session.redis.maximum_active_connections",
|
"session.redis.maximum_active_connections",
|
||||||
"session.redis.minimum_idle_connections",
|
"session.redis.minimum_idle_connections",
|
||||||
"session.redis.tls.minimum_version",
|
"session.redis.tls.minimum_version",
|
||||||
|
"session.redis.tls.maximum_version",
|
||||||
"session.redis.tls.skip_verify",
|
"session.redis.tls.skip_verify",
|
||||||
"session.redis.tls.server_name",
|
"session.redis.tls.server_name",
|
||||||
|
"session.redis.tls.private_key",
|
||||||
|
"session.redis.tls.certificate_chain",
|
||||||
"session.redis.high_availability.sentinel_name",
|
"session.redis.high_availability.sentinel_name",
|
||||||
"session.redis.high_availability.sentinel_username",
|
"session.redis.high_availability.sentinel_username",
|
||||||
"session.redis.high_availability.sentinel_password",
|
"session.redis.high_availability.sentinel_password",
|
||||||
|
@ -195,8 +201,11 @@ var Keys = []string{
|
||||||
"notifier.smtp.disable_html_emails",
|
"notifier.smtp.disable_html_emails",
|
||||||
"notifier.smtp.disable_starttls",
|
"notifier.smtp.disable_starttls",
|
||||||
"notifier.smtp.tls.minimum_version",
|
"notifier.smtp.tls.minimum_version",
|
||||||
|
"notifier.smtp.tls.maximum_version",
|
||||||
"notifier.smtp.tls.skip_verify",
|
"notifier.smtp.tls.skip_verify",
|
||||||
"notifier.smtp.tls.server_name",
|
"notifier.smtp.tls.server_name",
|
||||||
|
"notifier.smtp.tls.private_key",
|
||||||
|
"notifier.smtp.tls.certificate_chain",
|
||||||
"notifier.template_path",
|
"notifier.template_path",
|
||||||
"server.host",
|
"server.host",
|
||||||
"server.port",
|
"server.port",
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package schema
|
package schema
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -42,6 +43,6 @@ var DefaultSMTPNotifierConfiguration = SMTPNotifierConfiguration{
|
||||||
Identifier: "localhost",
|
Identifier: "localhost",
|
||||||
StartupCheckAddress: mail.Address{Name: "Authelia Test", Address: "test@authelia.com"},
|
StartupCheckAddress: mail.Address{Name: "Authelia Test", Address: "test@authelia.com"},
|
||||||
TLS: &TLSConfig{
|
TLS: &TLSConfig{
|
||||||
MinimumVersion: "TLS1.2",
|
MinimumVersion: TLSVersion{tls.VersionTLS12},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package schema
|
package schema
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -54,3 +55,10 @@ var DefaultSessionConfiguration = SessionConfiguration{
|
||||||
RememberMeDuration: time.Hour * 24 * 30,
|
RememberMeDuration: time.Hour * 24 * 30,
|
||||||
SameSite: "lax",
|
SameSite: "lax",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DefaultRedisConfiguration is the default redis configuration.
|
||||||
|
var DefaultRedisConfiguration = RedisSessionConfiguration{
|
||||||
|
TLS: &TLSConfig{
|
||||||
|
MinimumVersion: TLSVersion{Value: tls.VersionTLS12},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
|
@ -6,9 +6,20 @@ import (
|
||||||
|
|
||||||
// TLSConfig is a representation of the TLS configuration.
|
// TLSConfig is a representation of the TLS configuration.
|
||||||
type TLSConfig struct {
|
type TLSConfig struct {
|
||||||
MinimumVersion string `koanf:"minimum_version"`
|
MinimumVersion TLSVersion `koanf:"minimum_version"`
|
||||||
SkipVerify bool `koanf:"skip_verify"`
|
MaximumVersion TLSVersion `koanf:"maximum_version"`
|
||||||
ServerName string `koanf:"server_name"`
|
|
||||||
|
SkipVerify bool `koanf:"skip_verify"`
|
||||||
|
ServerName string `koanf:"server_name"`
|
||||||
|
|
||||||
|
PrivateKey CryptographicPrivateKey `koanf:"private_key"`
|
||||||
|
CertificateChain X509CertificateChain `koanf:"certificate_chain"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TLSCertificateConfig is a representation of the TLS Certificate configuration.
|
||||||
|
type TLSCertificateConfig struct {
|
||||||
|
Key CryptographicPrivateKey `koanf:"key"`
|
||||||
|
CertificateChain X509CertificateChain `koanf:"certificate_chain"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerTimeouts represents server timeout configurations.
|
// ServerTimeouts represents server timeout configurations.
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -174,6 +175,71 @@ func NewX509CertificateChain(in string) (chain *X509CertificateChain, err error)
|
||||||
return chain, nil
|
return chain, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewTLSVersion returns a new TLSVersion given a string.
|
||||||
|
func NewTLSVersion(input string) (version *TLSVersion, err error) {
|
||||||
|
switch strings.ReplaceAll(strings.ToUpper(input), " ", "") {
|
||||||
|
case TLSVersion13, Version13:
|
||||||
|
return &TLSVersion{tls.VersionTLS13}, nil
|
||||||
|
case TLSVersion12, Version12:
|
||||||
|
return &TLSVersion{tls.VersionTLS12}, nil
|
||||||
|
case TLSVersion11, Version11:
|
||||||
|
return &TLSVersion{tls.VersionTLS11}, nil
|
||||||
|
case TLSVersion10, Version10:
|
||||||
|
return &TLSVersion{tls.VersionTLS10}, nil
|
||||||
|
case SSLVersion30:
|
||||||
|
return &TLSVersion{tls.VersionSSL30}, nil //nolint:staticcheck
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, ErrTLSVersionNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
|
// TLSVersion is a struct which handles tls.Config versions.
|
||||||
|
type TLSVersion struct {
|
||||||
|
Value uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
// MaxVersion returns the value of this as a MaxVersion value.
|
||||||
|
func (v *TLSVersion) MaxVersion() uint16 {
|
||||||
|
if v.Value == 0 {
|
||||||
|
return tls.VersionTLS13
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// MinVersion returns the value of this as a MinVersion value.
|
||||||
|
func (v *TLSVersion) MinVersion() uint16 {
|
||||||
|
if v.Value == 0 {
|
||||||
|
return tls.VersionTLS12
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// String provides the Stringer.
|
||||||
|
func (v *TLSVersion) String() string {
|
||||||
|
switch v.Value {
|
||||||
|
case tls.VersionTLS10:
|
||||||
|
return TLSVersion10
|
||||||
|
case tls.VersionTLS11:
|
||||||
|
return TLSVersion11
|
||||||
|
case tls.VersionTLS12:
|
||||||
|
return TLSVersion12
|
||||||
|
case tls.VersionTLS13:
|
||||||
|
return TLSVersion13
|
||||||
|
case tls.VersionSSL30: //nolint:staticcheck
|
||||||
|
return SSLVersion30
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CryptographicPrivateKey represents the actual crypto.PrivateKey interface.
|
||||||
|
type CryptographicPrivateKey interface {
|
||||||
|
Public() crypto.PublicKey
|
||||||
|
Equal(x crypto.PrivateKey) bool
|
||||||
|
}
|
||||||
|
|
||||||
// X509CertificateChain is a helper struct that holds a list of *x509.Certificate's.
|
// X509CertificateChain is a helper struct that holds a list of *x509.Certificate's.
|
||||||
type X509CertificateChain struct {
|
type X509CertificateChain struct {
|
||||||
certs []*x509.Certificate
|
certs []*x509.Certificate
|
||||||
|
@ -259,10 +325,32 @@ func (c *X509CertificateChain) EqualKey(other any) (equal bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Certificates for this X509CertificateChain.
|
// Certificates for this X509CertificateChain.
|
||||||
func (c *X509CertificateChain) Certificates() []*x509.Certificate {
|
func (c *X509CertificateChain) Certificates() (certificates []*x509.Certificate) {
|
||||||
return c.certs
|
return c.certs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CertificatesRaw for this X509CertificateChain.
|
||||||
|
func (c *X509CertificateChain) CertificatesRaw() (certificates [][]byte) {
|
||||||
|
if !c.HasCertificates() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cert := range c.certs {
|
||||||
|
certificates = append(certificates, cert.Raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
return certificates
|
||||||
|
}
|
||||||
|
|
||||||
|
// Leaf returns the first certificate if available for use with tls.Certificate.
|
||||||
|
func (c *X509CertificateChain) Leaf() (leaf *x509.Certificate) {
|
||||||
|
if !c.HasCertificates() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.certs[0]
|
||||||
|
}
|
||||||
|
|
||||||
// Validate the X509CertificateChain ensuring the certificates were provided in the correct order
|
// Validate the X509CertificateChain ensuring the certificates were provided in the correct order
|
||||||
// (with nth being signed by the nth+1), and that all of the certificates are valid based on the current time.
|
// (with nth being signed by the nth+1), and that all of the certificates are valid based on the current time.
|
||||||
func (c *X509CertificateChain) Validate() (err error) {
|
func (c *X509CertificateChain) Validate() (err error) {
|
||||||
|
|
|
@ -18,6 +18,35 @@ duo_api:
|
||||||
authentication_backend:
|
authentication_backend:
|
||||||
ldap:
|
ldap:
|
||||||
url: ldap://127.0.0.1
|
url: ldap://127.0.0.1
|
||||||
|
tls:
|
||||||
|
private_key: |
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEpAIBAAKCAQEA6z1LOg1ZCqb0lytXWZ+MRBpMHEXOoTOLYgfZXt1IYyE3Z758
|
||||||
|
cyalk0NYQhY5cZDsXPYWPvAHiPMUxutWkoxFwby56S+AbIMa3/Is+ILrHRJs8Exn
|
||||||
|
ZkpyrYFxPX12app2kErdmAkHSx0Z5/kuXiz96PHs8S8/ZbyZolLHzdfLtSzjvRm5
|
||||||
|
Zue5iFzsf19NJz5CIBfv8g5lRwtE8wNJoRSpn1xq7fqfuA0weDNFPzjlNWRLy6aa
|
||||||
|
rK7qJexRkmkCs4sLgyl+9NODYJpvmN8E1yhyC27E0joI6rBFVW7Ihv+cSPCdDzGp
|
||||||
|
EWe81x3AeqAa3mjVqkiq4u4Z2i8JDgBaPboqJwIDAQABAoIBAAFdLZ58jVOefDSU
|
||||||
|
L8F5R1rtvBs93GDa56f926jNJ6pLewLC+/2+757W+SAI+PRLntM7Kg3bXm/Q2QH+
|
||||||
|
Q1Y+MflZmspbWCdI61L5GIGoYKyeers59i+FpvySj5GHtLQRiTZ0+Kv1AXHSDWBm
|
||||||
|
9XneUOqU3IbZe0ifu1RRno72/VtjkGXbW8Mkkw+ohyGbIeTx/0/JQ6sSNZTT3Vk7
|
||||||
|
8i4IXptq3HSF0/vqZuah8rShoeNq72pD1YLM9YPdL5by1QkDLnqATDiCpLBTCaNV
|
||||||
|
I8sqYEun+HYbQzBj8ZACG2JVZpEEidONWQHw5BPWO95DSZYrVnEkuCqeH+u5vYt7
|
||||||
|
CHuJ3AECgYEA+W3v5z+j91w1VPHS0VB3SCDMouycAMIUnJPAbt+0LPP0scUFsBGE
|
||||||
|
hPAKddC54pmMZRQ2KIwBKiyWfCrJ8Xz8Yogn7fJgmwTHidJBr2WQpIEkNGlK3Dzi
|
||||||
|
jXL2sh0yC7sHvn0DqiQ79l/e7yRbSnv2wrTJEczOOH2haD7/tBRyCYECgYEA8W+q
|
||||||
|
E9YyGvEltnPFaOxofNZ8LHVcZSsQI5b6fc0iE7fjxFqeXPXEwGSOTwqQLQRiHn9b
|
||||||
|
CfPmIG4Vhyq0otVmlPvUnfBZ2OK+tl5X2/mQFO3ROMdvpi0KYa994uqfJdSTaqLn
|
||||||
|
jjoKFB906UFHnDQDLZUNiV1WwnkTglgLc+xrd6cCgYEAqqthyv6NyBTM3Tm2gcio
|
||||||
|
Ra9Dtntl51LlXZnvwy3IkDXBCd6BHM9vuLKyxZiziGx+Vy90O1xI872cnot8sINQ
|
||||||
|
Am+dur/tAEVN72zxyv0Y8qb2yfH96iKy9gxi5s75TnOEQgAygLnYWaWR2lorKRUX
|
||||||
|
bHTdXBOiS58S0UzCFEslGIECgYBqkO4SKWYeTDhoKvuEj2yjRYyzlu28XeCWxOo1
|
||||||
|
otiauX0YSyNBRt2cSgYiTzhKFng0m+QUJYp63/wymB/5C5Zmxi0XtWIDADpLhqLj
|
||||||
|
HmmBQ2Mo26alQ5YkffBju0mZyhVzaQop1eZi8WuKFV1FThPlB7hc3E0SM5zv2Grd
|
||||||
|
tQnOWwKBgQC40yZY0PcjuILhy+sIc0Wvh7LUA7taSdTye149kRvbvsCDN7Jh75lM
|
||||||
|
USjhLXY0Nld2zBm9r8wMb81mXH29uvD+tDqqsICvyuKlA/tyzXR+QTr7dCVKVwu0
|
||||||
|
1YjCJ36UpTsLre2f8nOSLtNmRfDPtbOE2mkOoO9dD9UU0XZwnvn9xw==
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
base_dn: dc=example,dc=com
|
base_dn: dc=example,dc=com
|
||||||
username_attribute: uid
|
username_attribute: uid
|
||||||
additional_users_dn: ou=users
|
additional_users_dn: ou=users
|
||||||
|
|
|
@ -201,6 +201,22 @@ func (suite *AccessControl) TestShouldRaiseErrorInvalidSubject() {
|
||||||
suite.Assert().EqualError(suite.validator.Errors()[1], fmt.Sprintf(errAccessControlRuleBypassPolicyInvalidWithSubjects, ruleDescriptor(1, suite.config.AccessControl.Rules[0])))
|
suite.Assert().EqualError(suite.validator.Errors()[1], fmt.Sprintf(errAccessControlRuleBypassPolicyInvalidWithSubjects, ruleDescriptor(1, suite.config.AccessControl.Rules[0])))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *AccessControl) TestShouldRaiseErrorBypassWithSubjectDomainRegexGroup() {
|
||||||
|
suite.config.AccessControl.Rules = []schema.ACLRule{
|
||||||
|
{
|
||||||
|
DomainsRegex: MustCompileRegexps([]string{`^(?P<User>\w+)\.example\.com$`}),
|
||||||
|
Policy: "bypass",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidateRules(suite.config, suite.validator)
|
||||||
|
|
||||||
|
suite.Require().Len(suite.validator.Warnings(), 0)
|
||||||
|
suite.Require().Len(suite.validator.Errors(), 1)
|
||||||
|
|
||||||
|
suite.Assert().EqualError(suite.validator.Errors()[0], "access control: rule #1: 'policy' option 'bypass' is not supported when 'domain_regex' option contains the user or group named matches. For more information see: https://www.authelia.com/c/acl-match-concept-2")
|
||||||
|
}
|
||||||
|
|
||||||
func (suite *AccessControl) TestShouldSetQueryDefaults() {
|
func (suite *AccessControl) TestShouldSetQueryDefaults() {
|
||||||
domains := []string{"public.example.com"}
|
domains := []string{"public.example.com"}
|
||||||
suite.config.AccessControl.Rules = []schema.ACLRule{
|
suite.config.AccessControl.Rules = []schema.ACLRule{
|
||||||
|
@ -359,3 +375,13 @@ func TestShouldReturnCorrectResultsForValidNetworkGroups(t *testing.T) {
|
||||||
assert.True(t, validNetwork)
|
assert.True(t, validNetwork)
|
||||||
assert.False(t, invalidNetwork)
|
assert.False(t, invalidNetwork)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MustCompileRegexps(exps []string) (regexps []regexp.Regexp) {
|
||||||
|
regexps = make([]regexp.Regexp, len(exps))
|
||||||
|
|
||||||
|
for i, exp := range exps {
|
||||||
|
regexps[i] = *regexp.MustCompile(exp)
|
||||||
|
}
|
||||||
|
|
||||||
|
return regexps
|
||||||
|
}
|
||||||
|
|
|
@ -321,19 +321,35 @@ func validateLDAPAuthenticationBackend(config *schema.AuthenticationBackend, val
|
||||||
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendImplementation, config.LDAP.Implementation, strings.Join([]string{schema.LDAPImplementationCustom, schema.LDAPImplementationActiveDirectory}, "', '")))
|
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendImplementation, config.LDAP.Implementation, strings.Join([]string{schema.LDAPImplementationCustom, schema.LDAPImplementationActiveDirectory}, "', '")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
configDefaultTLS := &schema.TLSConfig{}
|
||||||
|
|
||||||
if implementation != nil {
|
if implementation != nil {
|
||||||
setDefaultImplementationLDAPAuthenticationBackendProfileMisc(config.LDAP, implementation)
|
if config.LDAP.Timeout == 0 {
|
||||||
|
config.LDAP.Timeout = implementation.Timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
configDefaultTLS = &schema.TLSConfig{
|
||||||
|
MinimumVersion: implementation.TLS.MinimumVersion,
|
||||||
|
MaximumVersion: implementation.TLS.MaximumVersion,
|
||||||
|
}
|
||||||
|
|
||||||
setDefaultImplementationLDAPAuthenticationBackendProfileAttributes(config.LDAP, implementation)
|
setDefaultImplementationLDAPAuthenticationBackendProfileAttributes(config.LDAP, implementation)
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.LDAP.TLS != nil {
|
if config.LDAP.URL == "" {
|
||||||
if _, err := utils.TLSStringToTLSConfigVersion(config.LDAP.TLS.MinimumVersion); err != nil {
|
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendMissingOption, "url"))
|
||||||
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendTLSMinVersion, config.LDAP.TLS.MinimumVersion, err))
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
configDefaultTLS.ServerName = validateLDAPAuthenticationBackendURL(config.LDAP, validator)
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.LDAP.TLS == nil {
|
||||||
config.LDAP.TLS = &schema.TLSConfig{}
|
config.LDAP.TLS = &schema.TLSConfig{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := ValidateTLSConfig(config.LDAP.TLS, configDefaultTLS); err != nil {
|
||||||
|
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendTLSConfigInvalid, err))
|
||||||
|
}
|
||||||
|
|
||||||
if strings.Contains(config.LDAP.UsersFilter, "{0}") {
|
if strings.Contains(config.LDAP.UsersFilter, "{0}") {
|
||||||
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendFilterReplacedPlaceholders, "users_filter", "{0}", "{input}"))
|
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendFilterReplacedPlaceholders, "users_filter", "{0}", "{input}"))
|
||||||
}
|
}
|
||||||
|
@ -346,31 +362,9 @@ func validateLDAPAuthenticationBackend(config *schema.AuthenticationBackend, val
|
||||||
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendFilterReplacedPlaceholders, "groups_filter", "{1}", "{username}"))
|
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendFilterReplacedPlaceholders, "groups_filter", "{1}", "{username}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.LDAP.URL == "" {
|
|
||||||
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendMissingOption, "url"))
|
|
||||||
} else {
|
|
||||||
validateLDAPAuthenticationBackendURL(config.LDAP, validator)
|
|
||||||
}
|
|
||||||
|
|
||||||
validateLDAPRequiredParameters(config, validator)
|
validateLDAPRequiredParameters(config, validator)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setDefaultImplementationLDAPAuthenticationBackendProfileMisc(config *schema.LDAPAuthenticationBackend, implementation *schema.LDAPAuthenticationBackend) {
|
|
||||||
if config.Timeout == 0 {
|
|
||||||
config.Timeout = implementation.Timeout
|
|
||||||
}
|
|
||||||
|
|
||||||
if implementation.TLS == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.TLS == nil {
|
|
||||||
config.TLS = implementation.TLS
|
|
||||||
} else if config.TLS.MinimumVersion == "" {
|
|
||||||
config.TLS.MinimumVersion = implementation.TLS.MinimumVersion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ldapImplementationShouldSetStr(config, implementation string) bool {
|
func ldapImplementationShouldSetStr(config, implementation string) bool {
|
||||||
return config == "" && implementation != ""
|
return config == "" && implementation != ""
|
||||||
}
|
}
|
||||||
|
@ -401,7 +395,7 @@ func setDefaultImplementationLDAPAuthenticationBackendProfileAttributes(config *
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateLDAPAuthenticationBackendURL(config *schema.LDAPAuthenticationBackend, validator *schema.StructValidator) {
|
func validateLDAPAuthenticationBackendURL(config *schema.LDAPAuthenticationBackend, validator *schema.StructValidator) (hostname string) {
|
||||||
var (
|
var (
|
||||||
parsedURL *url.URL
|
parsedURL *url.URL
|
||||||
err error
|
err error
|
||||||
|
@ -420,9 +414,8 @@ func validateLDAPAuthenticationBackendURL(config *schema.LDAPAuthenticationBacke
|
||||||
}
|
}
|
||||||
|
|
||||||
config.URL = parsedURL.String()
|
config.URL = parsedURL.String()
|
||||||
if config.TLS.ServerName == "" {
|
|
||||||
config.TLS.ServerName = parsedURL.Hostname()
|
return parsedURL.Hostname()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateLDAPRequiredParameters(config *schema.AuthenticationBackend, validator *schema.StructValidator) {
|
func validateLDAPRequiredParameters(config *schema.AuthenticationBackend, validator *schema.StructValidator) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package validator
|
package validator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -625,6 +626,42 @@ func (suite *LDAPAuthenticationBackendSuite) TestShouldRaiseErrorWhenPasswordNot
|
||||||
suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: ldap: option 'password' is required")
|
suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: ldap: option 'password' is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *LDAPAuthenticationBackendSuite) TestShouldNotRaiseErrorWhenPasswordNotProvidedWithPermitUnauthenticatedBind() {
|
||||||
|
suite.config.LDAP.Password = ""
|
||||||
|
suite.config.LDAP.PermitUnauthenticatedBind = true
|
||||||
|
|
||||||
|
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
||||||
|
|
||||||
|
suite.Assert().Len(suite.validator.Warnings(), 0)
|
||||||
|
suite.Require().Len(suite.validator.Errors(), 1)
|
||||||
|
|
||||||
|
suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: ldap: option 'permit_unauthenticated_bind' can't be enabled when password reset is enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *LDAPAuthenticationBackendSuite) TestShouldRaiseErrorWhenPasswordProvidedWithPermitUnauthenticatedBind() {
|
||||||
|
suite.config.LDAP.Password = "test"
|
||||||
|
suite.config.LDAP.PermitUnauthenticatedBind = true
|
||||||
|
suite.config.PasswordReset.Disable = true
|
||||||
|
|
||||||
|
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
||||||
|
|
||||||
|
suite.Assert().Len(suite.validator.Warnings(), 0)
|
||||||
|
suite.Require().Len(suite.validator.Errors(), 1)
|
||||||
|
|
||||||
|
suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: ldap: option 'permit_unauthenticated_bind' can't be enabled when a password is specified")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *LDAPAuthenticationBackendSuite) TestShouldNotRaiseErrorWhenPermitUnauthenticatedBindConfiguredCorrectly() {
|
||||||
|
suite.config.LDAP.Password = ""
|
||||||
|
suite.config.LDAP.PermitUnauthenticatedBind = true
|
||||||
|
suite.config.PasswordReset.Disable = true
|
||||||
|
|
||||||
|
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
||||||
|
|
||||||
|
suite.Assert().Len(suite.validator.Warnings(), 0)
|
||||||
|
suite.Require().Len(suite.validator.Errors(), 0)
|
||||||
|
}
|
||||||
|
|
||||||
func (suite *LDAPAuthenticationBackendSuite) TestShouldRaiseErrorWhenBaseDNNotProvided() {
|
func (suite *LDAPAuthenticationBackendSuite) TestShouldRaiseErrorWhenBaseDNNotProvided() {
|
||||||
suite.config.LDAP.BaseDN = ""
|
suite.config.LDAP.BaseDN = ""
|
||||||
|
|
||||||
|
@ -783,19 +820,19 @@ func (suite *LDAPAuthenticationBackendSuite) TestShouldHelpDetectNoInputPlacehol
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *LDAPAuthenticationBackendSuite) TestShouldSetDefaultTLSMinimumVersion() {
|
func (suite *LDAPAuthenticationBackendSuite) TestShouldSetDefaultTLSMinimumVersion() {
|
||||||
suite.config.LDAP.TLS = &schema.TLSConfig{MinimumVersion: ""}
|
suite.config.LDAP.TLS = &schema.TLSConfig{MinimumVersion: schema.TLSVersion{}}
|
||||||
|
|
||||||
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
||||||
|
|
||||||
suite.Assert().Len(suite.validator.Warnings(), 0)
|
suite.Assert().Len(suite.validator.Warnings(), 0)
|
||||||
suite.Assert().Len(suite.validator.Errors(), 0)
|
suite.Assert().Len(suite.validator.Errors(), 0)
|
||||||
|
|
||||||
suite.Assert().Equal(schema.DefaultLDAPAuthenticationBackendConfigurationImplementationCustom.TLS.MinimumVersion, suite.config.LDAP.TLS.MinimumVersion)
|
suite.Assert().Equal(schema.DefaultLDAPAuthenticationBackendConfigurationImplementationCustom.TLS.MinimumVersion.Value, suite.config.LDAP.TLS.MinimumVersion.MinVersion())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *LDAPAuthenticationBackendSuite) TestShouldNotAllowInvalidTLSValue() {
|
func (suite *LDAPAuthenticationBackendSuite) TestShouldNotAllowSSL30() {
|
||||||
suite.config.LDAP.TLS = &schema.TLSConfig{
|
suite.config.LDAP.TLS = &schema.TLSConfig{
|
||||||
MinimumVersion: "SSL2.0",
|
MinimumVersion: schema.TLSVersion{Value: tls.VersionSSL30}, //nolint:staticcheck
|
||||||
}
|
}
|
||||||
|
|
||||||
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
||||||
|
@ -803,7 +840,21 @@ func (suite *LDAPAuthenticationBackendSuite) TestShouldNotAllowInvalidTLSValue()
|
||||||
suite.Assert().Len(suite.validator.Warnings(), 0)
|
suite.Assert().Len(suite.validator.Warnings(), 0)
|
||||||
suite.Require().Len(suite.validator.Errors(), 1)
|
suite.Require().Len(suite.validator.Errors(), 1)
|
||||||
|
|
||||||
suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: ldap: tls: option 'minimum_tls_version' is invalid: SSL2.0: supplied tls version isn't supported")
|
suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: ldap: tls: option 'minimum_version' is invalid: minimum version is TLS1.0 but SSL3.0 was configured")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *LDAPAuthenticationBackendSuite) TestShouldNotAllowTLSVerMinGreaterThanVerMax() {
|
||||||
|
suite.config.LDAP.TLS = &schema.TLSConfig{
|
||||||
|
MinimumVersion: schema.TLSVersion{Value: tls.VersionTLS13},
|
||||||
|
MaximumVersion: schema.TLSVersion{Value: tls.VersionTLS12},
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
||||||
|
|
||||||
|
suite.Assert().Len(suite.validator.Warnings(), 0)
|
||||||
|
suite.Require().Len(suite.validator.Errors(), 1)
|
||||||
|
|
||||||
|
suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: ldap: tls: option combination of 'minimum_version' and 'maximum_version' is invalid: minimum version TLS1.3 is greater than the maximum version TLS1.2")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLdapAuthenticationBackend(t *testing.T) {
|
func TestLdapAuthenticationBackend(t *testing.T) {
|
||||||
|
|
|
@ -25,7 +25,7 @@ func newDefaultConfig() schema.Configuration {
|
||||||
DefaultPolicy: "two_factor",
|
DefaultPolicy: "two_factor",
|
||||||
}
|
}
|
||||||
config.Session = schema.SessionConfiguration{
|
config.Session = schema.SessionConfiguration{
|
||||||
Domain: "example.com",
|
Domain: examplecom,
|
||||||
Name: "authelia_session",
|
Name: "authelia_session",
|
||||||
Secret: "secret",
|
Secret: "secret",
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,11 @@ const (
|
||||||
errFmtNotifierTemplatePathUnknownError = "notifier: option 'template_path' refers to location '%s' which couldn't be opened: %w"
|
errFmtNotifierTemplatePathUnknownError = "notifier: option 'template_path' refers to location '%s' which couldn't be opened: %w"
|
||||||
errFmtNotifierFileSystemFileNameNotConfigured = "notifier: filesystem: option 'filename' is required"
|
errFmtNotifierFileSystemFileNameNotConfigured = "notifier: filesystem: option 'filename' is required"
|
||||||
errFmtNotifierSMTPNotConfigured = "notifier: smtp: option '%s' is required"
|
errFmtNotifierSMTPNotConfigured = "notifier: smtp: option '%s' is required"
|
||||||
errFmtNotifierStartTlsDisabled = "Notifier SMTP connection has opportunistic STARTTLS explicitly disabled which means all emails will be sent insecurely over plain text and this setting is only necessary for non-compliant SMTP servers which advertise they support STARTTLS when they actually don't support STARTTLS"
|
errFmtNotifierSMTPTLSConfigInvalid = "notifier: smtp: tls: %w"
|
||||||
|
errFmtNotifierStartTlsDisabled = "notifier: smtp: option 'disable_starttls' is enabled: " +
|
||||||
|
"opportunistic STARTTLS is explicitly disabled which means all emails will be sent insecurely over plaintext " +
|
||||||
|
"and this setting is only necessary for non-compliant SMTP servers which advertise they support STARTTLS " +
|
||||||
|
"when they actually don't support STARTTLS"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -91,10 +95,9 @@ const (
|
||||||
errFmtLDAPAuthBackendUnauthenticatedBindWithPassword = "authentication_backend: ldap: option 'permit_unauthenticated_bind' can't be enabled when a password is specified"
|
errFmtLDAPAuthBackendUnauthenticatedBindWithPassword = "authentication_backend: ldap: option 'permit_unauthenticated_bind' can't be enabled when a password is specified"
|
||||||
errFmtLDAPAuthBackendUnauthenticatedBindWithResetEnabled = "authentication_backend: ldap: option 'permit_unauthenticated_bind' can't be enabled when password reset is enabled"
|
errFmtLDAPAuthBackendUnauthenticatedBindWithResetEnabled = "authentication_backend: ldap: option 'permit_unauthenticated_bind' can't be enabled when password reset is enabled"
|
||||||
|
|
||||||
errFmtLDAPAuthBackendMissingOption = "authentication_backend: ldap: option '%s' is required"
|
errFmtLDAPAuthBackendMissingOption = "authentication_backend: ldap: option '%s' is required"
|
||||||
errFmtLDAPAuthBackendTLSMinVersion = "authentication_backend: ldap: tls: option " +
|
errFmtLDAPAuthBackendTLSConfigInvalid = "authentication_backend: ldap: tls: %w"
|
||||||
"'minimum_tls_version' is invalid: %s: %w"
|
errFmtLDAPAuthBackendImplementation = "authentication_backend: ldap: option 'implementation' " +
|
||||||
errFmtLDAPAuthBackendImplementation = "authentication_backend: ldap: option 'implementation' " +
|
|
||||||
errSuffixMustBeOneOf
|
errSuffixMustBeOneOf
|
||||||
errFmtLDAPAuthBackendFilterReplacedPlaceholders = "authentication_backend: ldap: option " +
|
errFmtLDAPAuthBackendFilterReplacedPlaceholders = "authentication_backend: ldap: option " +
|
||||||
"'%s' has an invalid placeholder: '%s' has been removed, please use '%s' instead"
|
"'%s' has an invalid placeholder: '%s' has been removed, please use '%s' instead"
|
||||||
|
@ -247,6 +250,7 @@ const (
|
||||||
errFmtSessionRedisPortRange = "session: redis: option 'port' must be between 1 and 65535 but is configured as '%d'"
|
errFmtSessionRedisPortRange = "session: redis: option 'port' must be between 1 and 65535 but is configured as '%d'"
|
||||||
errFmtSessionRedisHostRequired = "session: redis: option 'host' is required"
|
errFmtSessionRedisHostRequired = "session: redis: option 'host' is required"
|
||||||
errFmtSessionRedisHostOrNodesRequired = "session: redis: option 'host' or the 'high_availability' option 'nodes' is required"
|
errFmtSessionRedisHostOrNodesRequired = "session: redis: option 'host' or the 'high_availability' option 'nodes' is required"
|
||||||
|
errFmtSessionRedisTLSConfigInvalid = "session: redis: tls: %w"
|
||||||
|
|
||||||
errFmtSessionRedisSentinelMissingName = "session: redis: high_availability: option 'sentinel_name' is required"
|
errFmtSessionRedisSentinelMissingName = "session: redis: high_availability: option 'sentinel_name' is required"
|
||||||
errFmtSessionRedisSentinelNodeHostMissing = "session: redis: high_availability: option 'nodes': option 'host' is required for each node but one or more nodes are missing this"
|
errFmtSessionRedisSentinelNodeHostMissing = "session: redis: high_availability: option 'nodes': option 'host' is required for each node but one or more nodes are missing this"
|
||||||
|
|
|
@ -10,3 +10,7 @@ const (
|
||||||
testLDAPUser = "user"
|
testLDAPUser = "user"
|
||||||
testEncryptionKey = "a_not_so_secure_encryption_key"
|
testEncryptionKey = "a_not_so_secure_encryption_key"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
examplecom = "example.com"
|
||||||
|
)
|
||||||
|
|
|
@ -257,7 +257,7 @@ func TestShouldRaiseErrorWhenOIDCServerClientBadValues(t *testing.T) {
|
||||||
RedirectURIs: []string{
|
RedirectURIs: []string{
|
||||||
"https://google.com",
|
"https://google.com",
|
||||||
},
|
},
|
||||||
SectorIdentifier: mustParseURL("example.com"),
|
SectorIdentifier: mustParseURL(examplecom),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -289,12 +289,12 @@ func TestShouldRaiseErrorWhenOIDCServerClientBadValues(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Errors: []string{
|
Errors: []string{
|
||||||
fmt.Sprintf(errFmtOIDCClientInvalidSectorIdentifier, "client-invalid-sector", "https://user:pass@example.com/path?query=abc#fragment", "example.com", "scheme", "https"),
|
fmt.Sprintf(errFmtOIDCClientInvalidSectorIdentifier, "client-invalid-sector", "https://user:pass@example.com/path?query=abc#fragment", examplecom, "scheme", "https"),
|
||||||
fmt.Sprintf(errFmtOIDCClientInvalidSectorIdentifier, "client-invalid-sector", "https://user:pass@example.com/path?query=abc#fragment", "example.com", "path", "/path"),
|
fmt.Sprintf(errFmtOIDCClientInvalidSectorIdentifier, "client-invalid-sector", "https://user:pass@example.com/path?query=abc#fragment", examplecom, "path", "/path"),
|
||||||
fmt.Sprintf(errFmtOIDCClientInvalidSectorIdentifier, "client-invalid-sector", "https://user:pass@example.com/path?query=abc#fragment", "example.com", "query", "query=abc"),
|
fmt.Sprintf(errFmtOIDCClientInvalidSectorIdentifier, "client-invalid-sector", "https://user:pass@example.com/path?query=abc#fragment", examplecom, "query", "query=abc"),
|
||||||
fmt.Sprintf(errFmtOIDCClientInvalidSectorIdentifier, "client-invalid-sector", "https://user:pass@example.com/path?query=abc#fragment", "example.com", "fragment", "fragment"),
|
fmt.Sprintf(errFmtOIDCClientInvalidSectorIdentifier, "client-invalid-sector", "https://user:pass@example.com/path?query=abc#fragment", examplecom, "fragment", "fragment"),
|
||||||
fmt.Sprintf(errFmtOIDCClientInvalidSectorIdentifier, "client-invalid-sector", "https://user:pass@example.com/path?query=abc#fragment", "example.com", "username", "user"),
|
fmt.Sprintf(errFmtOIDCClientInvalidSectorIdentifier, "client-invalid-sector", "https://user:pass@example.com/path?query=abc#fragment", examplecom, "username", "user"),
|
||||||
fmt.Sprintf(errFmtOIDCClientInvalidSectorIdentifierWithoutValue, "client-invalid-sector", "https://user:pass@example.com/path?query=abc#fragment", "example.com", "password"),
|
fmt.Sprintf(errFmtOIDCClientInvalidSectorIdentifierWithoutValue, "client-invalid-sector", "https://user:pass@example.com/path?query=abc#fragment", examplecom, "password"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -83,11 +83,17 @@ func validateSMTPNotifier(config *schema.SMTPNotifierConfiguration, validator *s
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.TLS == nil {
|
if config.TLS == nil {
|
||||||
config.TLS = schema.DefaultSMTPNotifierConfiguration.TLS
|
config.TLS = &schema.TLSConfig{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.TLS.ServerName == "" {
|
configDefaultTLS := &schema.TLSConfig{
|
||||||
config.TLS.ServerName = config.Host
|
ServerName: config.Host,
|
||||||
|
MinimumVersion: schema.DefaultSMTPNotifierConfiguration.TLS.MinimumVersion,
|
||||||
|
MaximumVersion: schema.DefaultSMTPNotifierConfiguration.TLS.MaximumVersion,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ValidateTLSConfig(config.TLS, configDefaultTLS); err != nil {
|
||||||
|
validator.Push(fmt.Errorf(errFmtNotifierSMTPTLSConfigInvalid, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.DisableStartTLS {
|
if config.DisableStartTLS {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package validator
|
package validator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -22,7 +23,7 @@ func (suite *NotifierSuite) SetupTest() {
|
||||||
Username: "john",
|
Username: "john",
|
||||||
Password: "password",
|
Password: "password",
|
||||||
Sender: mail.Address{Name: "Authelia", Address: "authelia@example.com"},
|
Sender: mail.Address{Name: "Authelia", Address: "authelia@example.com"},
|
||||||
Host: "example.com",
|
Host: examplecom,
|
||||||
Port: 25,
|
Port: 25,
|
||||||
}
|
}
|
||||||
suite.config.FileSystem = nil
|
suite.config.FileSystem = nil
|
||||||
|
@ -77,8 +78,8 @@ func (suite *NotifierSuite) TestSMTPShouldSetTLSDefaults() {
|
||||||
suite.Assert().Len(suite.validator.Warnings(), 0)
|
suite.Assert().Len(suite.validator.Warnings(), 0)
|
||||||
suite.Assert().Len(suite.validator.Errors(), 0)
|
suite.Assert().Len(suite.validator.Errors(), 0)
|
||||||
|
|
||||||
suite.Assert().Equal("example.com", suite.config.SMTP.TLS.ServerName)
|
suite.Assert().Equal(examplecom, suite.config.SMTP.TLS.ServerName)
|
||||||
suite.Assert().Equal("TLS1.2", suite.config.SMTP.TLS.MinimumVersion)
|
suite.Assert().Equal(uint16(tls.VersionTLS12), suite.config.SMTP.TLS.MinimumVersion.Value)
|
||||||
suite.Assert().False(suite.config.SMTP.TLS.SkipVerify)
|
suite.Assert().False(suite.config.SMTP.TLS.SkipVerify)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +97,7 @@ func (suite *NotifierSuite) TestSMTPShouldDefaultStartupCheckAddress() {
|
||||||
func (suite *NotifierSuite) TestSMTPShouldDefaultTLSServerNameToHost() {
|
func (suite *NotifierSuite) TestSMTPShouldDefaultTLSServerNameToHost() {
|
||||||
suite.config.SMTP.Host = "google.com"
|
suite.config.SMTP.Host = "google.com"
|
||||||
suite.config.SMTP.TLS = &schema.TLSConfig{
|
suite.config.SMTP.TLS = &schema.TLSConfig{
|
||||||
MinimumVersion: "TLS1.1",
|
MinimumVersion: schema.TLSVersion{Value: tls.VersionTLS11},
|
||||||
}
|
}
|
||||||
|
|
||||||
ValidateNotifier(&suite.config, suite.validator)
|
ValidateNotifier(&suite.config, suite.validator)
|
||||||
|
@ -105,10 +106,51 @@ func (suite *NotifierSuite) TestSMTPShouldDefaultTLSServerNameToHost() {
|
||||||
suite.Assert().Len(suite.validator.Errors(), 0)
|
suite.Assert().Len(suite.validator.Errors(), 0)
|
||||||
|
|
||||||
suite.Assert().Equal("google.com", suite.config.SMTP.TLS.ServerName)
|
suite.Assert().Equal("google.com", suite.config.SMTP.TLS.ServerName)
|
||||||
suite.Assert().Equal("TLS1.1", suite.config.SMTP.TLS.MinimumVersion)
|
suite.Assert().Equal(uint16(tls.VersionTLS11), suite.config.SMTP.TLS.MinimumVersion.MinVersion())
|
||||||
suite.Assert().False(suite.config.SMTP.TLS.SkipVerify)
|
suite.Assert().False(suite.config.SMTP.TLS.SkipVerify)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *NotifierSuite) TestSMTPShouldErrorOnSSL30() {
|
||||||
|
suite.config.SMTP.Host = examplecom
|
||||||
|
suite.config.SMTP.TLS = &schema.TLSConfig{
|
||||||
|
MinimumVersion: schema.TLSVersion{Value: tls.VersionSSL30}, //nolint:staticcheck
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidateNotifier(&suite.config, suite.validator)
|
||||||
|
|
||||||
|
suite.Assert().Len(suite.validator.Warnings(), 0)
|
||||||
|
suite.Require().Len(suite.validator.Errors(), 1)
|
||||||
|
|
||||||
|
suite.Assert().EqualError(suite.validator.Errors()[0], "notifier: smtp: tls: option 'minimum_version' is invalid: minimum version is TLS1.0 but SSL3.0 was configured")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *NotifierSuite) TestSMTPShouldErrorOnTLSMinVerGreaterThanMaxVer() {
|
||||||
|
suite.config.SMTP.Host = examplecom
|
||||||
|
suite.config.SMTP.TLS = &schema.TLSConfig{
|
||||||
|
MinimumVersion: schema.TLSVersion{Value: tls.VersionTLS13},
|
||||||
|
MaximumVersion: schema.TLSVersion{Value: tls.VersionTLS10},
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidateNotifier(&suite.config, suite.validator)
|
||||||
|
|
||||||
|
suite.Assert().Len(suite.validator.Warnings(), 0)
|
||||||
|
suite.Require().Len(suite.validator.Errors(), 1)
|
||||||
|
|
||||||
|
suite.Assert().EqualError(suite.validator.Errors()[0], "notifier: smtp: tls: option combination of 'minimum_version' and 'maximum_version' is invalid: minimum version TLS1.3 is greater than the maximum version TLS1.0")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *NotifierSuite) TestSMTPShouldWarnOnDisabledSTARTTLS() {
|
||||||
|
suite.config.SMTP.Host = examplecom
|
||||||
|
suite.config.SMTP.DisableStartTLS = true
|
||||||
|
|
||||||
|
ValidateNotifier(&suite.config, suite.validator)
|
||||||
|
|
||||||
|
suite.Require().Len(suite.validator.Warnings(), 1)
|
||||||
|
suite.Assert().Len(suite.validator.Errors(), 0)
|
||||||
|
|
||||||
|
suite.Assert().EqualError(suite.validator.Warnings()[0], "notifier: smtp: option 'disable_starttls' is enabled: opportunistic STARTTLS is explicitly disabled which means all emails will be sent insecurely over plaintext and this setting is only necessary for non-compliant SMTP servers which advertise they support STARTTLS when they actually don't support STARTTLS")
|
||||||
|
}
|
||||||
|
|
||||||
func (suite *NotifierSuite) TestSMTPShouldEnsureHostAndPortAreProvided() {
|
func (suite *NotifierSuite) TestSMTPShouldEnsureHostAndPortAreProvided() {
|
||||||
suite.config.FileSystem = nil
|
suite.config.FileSystem = nil
|
||||||
ValidateNotifier(&suite.config, suite.validator)
|
ValidateNotifier(&suite.config, suite.validator)
|
||||||
|
|
|
@ -58,6 +58,18 @@ func validateRedisCommon(config *schema.SessionConfiguration, validator *schema.
|
||||||
if config.Secret == "" {
|
if config.Secret == "" {
|
||||||
validator.Push(fmt.Errorf(errFmtSessionSecretRequired, "redis"))
|
validator.Push(fmt.Errorf(errFmtSessionSecretRequired, "redis"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.Redis.TLS != nil {
|
||||||
|
configDefaultTLS := &schema.TLSConfig{
|
||||||
|
ServerName: config.Redis.Host,
|
||||||
|
MinimumVersion: schema.DefaultRedisConfiguration.TLS.MinimumVersion,
|
||||||
|
MaximumVersion: schema.DefaultRedisConfiguration.TLS.MaximumVersion,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ValidateTLSConfig(config.Redis.TLS, configDefaultTLS); err != nil {
|
||||||
|
validator.Push(fmt.Errorf(errFmtSessionRedisTLSConfigInvalid, err))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateRedis(config *schema.SessionConfiguration, validator *schema.StructValidator) {
|
func validateRedis(config *schema.SessionConfiguration, validator *schema.StructValidator) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package validator
|
package validator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -13,7 +14,7 @@ import (
|
||||||
func newDefaultSessionConfig() schema.SessionConfiguration {
|
func newDefaultSessionConfig() schema.SessionConfiguration {
|
||||||
config := schema.SessionConfiguration{}
|
config := schema.SessionConfiguration{}
|
||||||
config.Secret = testJWTSecret
|
config.Secret = testJWTSecret
|
||||||
config.Domain = "example.com"
|
config.Domain = examplecom
|
||||||
|
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
@ -354,6 +355,67 @@ func TestShouldRaiseErrorsWhenRedisHostNotSet(t *testing.T) {
|
||||||
assert.EqualError(t, errors[0], errFmtSessionRedisHostRequired)
|
assert.EqualError(t, errors[0], errFmtSessionRedisHostRequired)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestShouldSetDefaultRedisTLSOptions(t *testing.T) {
|
||||||
|
validator := schema.NewStructValidator()
|
||||||
|
config := newDefaultSessionConfig()
|
||||||
|
|
||||||
|
config.Redis = &schema.RedisSessionConfiguration{
|
||||||
|
Host: "redis.local",
|
||||||
|
Port: 6379,
|
||||||
|
TLS: &schema.TLSConfig{},
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidateSession(&config, validator)
|
||||||
|
|
||||||
|
assert.Len(t, validator.Warnings(), 0)
|
||||||
|
assert.Len(t, validator.Errors(), 0)
|
||||||
|
|
||||||
|
assert.Equal(t, uint16(tls.VersionTLS12), config.Redis.TLS.MinimumVersion.Value)
|
||||||
|
assert.Equal(t, uint16(0), config.Redis.TLS.MaximumVersion.Value)
|
||||||
|
assert.Equal(t, "redis.local", config.Redis.TLS.ServerName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShouldRaiseErrorOnBadRedisTLSOptionsSSL30(t *testing.T) {
|
||||||
|
validator := schema.NewStructValidator()
|
||||||
|
config := newDefaultSessionConfig()
|
||||||
|
|
||||||
|
config.Redis = &schema.RedisSessionConfiguration{
|
||||||
|
Host: "redis.local",
|
||||||
|
Port: 6379,
|
||||||
|
TLS: &schema.TLSConfig{
|
||||||
|
MinimumVersion: schema.TLSVersion{Value: tls.VersionSSL30}, //nolint:staticcheck
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidateSession(&config, validator)
|
||||||
|
|
||||||
|
assert.Len(t, validator.Warnings(), 0)
|
||||||
|
require.Len(t, validator.Errors(), 1)
|
||||||
|
|
||||||
|
assert.EqualError(t, validator.Errors()[0], "session: redis: tls: option 'minimum_version' is invalid: minimum version is TLS1.0 but SSL3.0 was configured")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShouldRaiseErrorOnBadRedisTLSOptionsMinVerGreaterThanMax(t *testing.T) {
|
||||||
|
validator := schema.NewStructValidator()
|
||||||
|
config := newDefaultSessionConfig()
|
||||||
|
|
||||||
|
config.Redis = &schema.RedisSessionConfiguration{
|
||||||
|
Host: "redis.local",
|
||||||
|
Port: 6379,
|
||||||
|
TLS: &schema.TLSConfig{
|
||||||
|
MinimumVersion: schema.TLSVersion{Value: tls.VersionTLS13},
|
||||||
|
MaximumVersion: schema.TLSVersion{Value: tls.VersionTLS10},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidateSession(&config, validator)
|
||||||
|
|
||||||
|
assert.Len(t, validator.Warnings(), 0)
|
||||||
|
require.Len(t, validator.Errors(), 1)
|
||||||
|
|
||||||
|
assert.EqualError(t, validator.Errors()[0], "session: redis: tls: option combination of 'minimum_version' and 'maximum_version' is invalid: minimum version TLS1.3 is greater than the maximum version TLS1.0")
|
||||||
|
}
|
||||||
|
|
||||||
func TestShouldRaiseErrorWhenDomainNotSet(t *testing.T) {
|
func TestShouldRaiseErrorWhenDomainNotSet(t *testing.T) {
|
||||||
validator := schema.NewStructValidator()
|
validator := schema.NewStructValidator()
|
||||||
config := newDefaultSessionConfig()
|
config := newDefaultSessionConfig()
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
package validator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ValidateTLSConfig sets the default values and validates a schema.TLSConfig.
|
||||||
|
func ValidateTLSConfig(config *schema.TLSConfig, configDefault *schema.TLSConfig) (err error) {
|
||||||
|
if config == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.ServerName == "" {
|
||||||
|
config.ServerName = configDefault.ServerName
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.MinimumVersion.Value == 0 {
|
||||||
|
config.MinimumVersion.Value = configDefault.MinimumVersion.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.MaximumVersion.Value == 0 {
|
||||||
|
config.MaximumVersion.Value = configDefault.MaximumVersion.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.MinimumVersion.MinVersion() < tls.VersionTLS10 {
|
||||||
|
return errors.New("option 'minimum_version' is invalid: minimum version is TLS1.0 but SSL3.0 was configured")
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.MinimumVersion.MinVersion() > config.MaximumVersion.MaxVersion() {
|
||||||
|
return fmt.Errorf("option combination of 'minimum_version' and 'maximum_version' is invalid: minimum version %s is greater than the maximum version %s", config.MinimumVersion.String(), config.MaximumVersion.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.CertificateChain.HasCertificates() || config.PrivateKey != nil) && !config.CertificateChain.EqualKey(config.PrivateKey) {
|
||||||
|
return errors.New("option 'certificates' is invalid: provided certificate is not the public key for the private key provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -27,7 +27,7 @@ import (
|
||||||
func NewSMTPNotifier(config *schema.SMTPNotifierConfiguration, certPool *x509.CertPool, templateProvider *templates.Provider) *SMTPNotifier {
|
func NewSMTPNotifier(config *schema.SMTPNotifierConfiguration, certPool *x509.CertPool, templateProvider *templates.Provider) *SMTPNotifier {
|
||||||
notifier := &SMTPNotifier{
|
notifier := &SMTPNotifier{
|
||||||
config: config,
|
config: config,
|
||||||
tlsConfig: utils.NewTLSConfig(config.TLS, tls.VersionTLS12, certPool),
|
tlsConfig: utils.NewTLSConfig(config.TLS, certPool),
|
||||||
log: logging.Logger(),
|
log: logging.Logger(),
|
||||||
templates: templateProvider,
|
templates: templateProvider,
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ func TestShouldConfigureSMTPNotifierWithTLS11(t *testing.T) {
|
||||||
Port: 25,
|
Port: 25,
|
||||||
TLS: &schema.TLSConfig{
|
TLS: &schema.TLSConfig{
|
||||||
ServerName: "smtp.example.com",
|
ServerName: "smtp.example.com",
|
||||||
MinimumVersion: "TLS1.1",
|
MinimumVersion: schema.TLSVersion{Value: tls.VersionTLS11},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ func NewProviderConfig(config schema.SessionConfiguration, certPool *x509.CertPo
|
||||||
var tlsConfig *tls.Config
|
var tlsConfig *tls.Config
|
||||||
|
|
||||||
if config.Redis.TLS != nil {
|
if config.Redis.TLS != nil {
|
||||||
tlsConfig = utils.NewTLSConfig(config.Redis.TLS, tls.VersionTLS12, certPool)
|
tlsConfig = utils.NewTLSConfig(config.Redis.TLS, certPool)
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Redis.HighAvailability != nil && config.Redis.HighAvailability.SentinelName != "" {
|
if config.Redis.HighAvailability != nil && config.Redis.HighAvailability.SentinelName != "" {
|
||||||
|
|
|
@ -42,7 +42,7 @@ func TestShouldCreateRedisSessionProviderTLS(t *testing.T) {
|
||||||
Password: "pass",
|
Password: "pass",
|
||||||
TLS: &schema.TLSConfig{
|
TLS: &schema.TLSConfig{
|
||||||
ServerName: "redis.fqdn.example.com",
|
ServerName: "redis.fqdn.example.com",
|
||||||
MinimumVersion: "TLS1.3",
|
MinimumVersion: schema.TLSVersion{Value: tls.VersionTLS13},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
providerConfig := NewProviderConfig(configuration, nil)
|
providerConfig := NewProviderConfig(configuration, nil)
|
||||||
|
|
|
@ -235,17 +235,26 @@ func IsX509PrivateKey(i any) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTLSConfig generates a tls.Config from a schema.TLSConfig and a x509.CertPool.
|
// NewTLSConfig generates a tls.Config from a schema.TLSConfig and a x509.CertPool.
|
||||||
func NewTLSConfig(config *schema.TLSConfig, defaultMinVersion uint16, certPool *x509.CertPool) (tlsConfig *tls.Config) {
|
func NewTLSConfig(config *schema.TLSConfig, certPool *x509.CertPool) (tlsConfig *tls.Config) {
|
||||||
minVersion, err := TLSStringToTLSConfigVersion(config.MinimumVersion)
|
var certificates []tls.Certificate
|
||||||
if err != nil {
|
|
||||||
minVersion = defaultMinVersion
|
if config.CertificateChain.HasCertificates() && config.PrivateKey != nil {
|
||||||
|
certificates = []tls.Certificate{
|
||||||
|
{
|
||||||
|
Certificate: config.CertificateChain.CertificatesRaw(),
|
||||||
|
Leaf: config.CertificateChain.Leaf(),
|
||||||
|
PrivateKey: config.PrivateKey,
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &tls.Config{
|
return &tls.Config{
|
||||||
ServerName: config.ServerName,
|
ServerName: config.ServerName,
|
||||||
InsecureSkipVerify: config.SkipVerify, //nolint:gosec // Informed choice by user. Off by default.
|
InsecureSkipVerify: config.SkipVerify, //nolint:gosec // Informed choice by user. Off by default.
|
||||||
MinVersion: minVersion,
|
MinVersion: config.MinimumVersion.MinVersion(),
|
||||||
|
MaxVersion: config.MinimumVersion.MaxVersion(),
|
||||||
RootCAs: certPool,
|
RootCAs: certPool,
|
||||||
|
Certificates: certificates,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,22 +299,6 @@ func NewX509CertPool(directory string) (certPool *x509.CertPool, warnings []erro
|
||||||
return certPool, warnings, errors
|
return certPool, warnings, errors
|
||||||
}
|
}
|
||||||
|
|
||||||
// TLSStringToTLSConfigVersion returns a go crypto/tls version for a tls.Config based on string input.
|
|
||||||
func TLSStringToTLSConfigVersion(input string) (version uint16, err error) {
|
|
||||||
switch strings.ToUpper(input) {
|
|
||||||
case "TLS1.3", TLS13:
|
|
||||||
return tls.VersionTLS13, nil
|
|
||||||
case "TLS1.2", TLS12:
|
|
||||||
return tls.VersionTLS12, nil
|
|
||||||
case "TLS1.1", TLS11:
|
|
||||||
return tls.VersionTLS11, nil
|
|
||||||
case "TLS1.0", TLS10:
|
|
||||||
return tls.VersionTLS10, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0, ErrTLSVersionNotSupported
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteCertificateBytesToPEM writes a certificate/csr to a file in the PEM format.
|
// WriteCertificateBytesToPEM writes a certificate/csr to a file in the PEM format.
|
||||||
func WriteCertificateBytesToPEM(cert []byte, path string, csr bool) (err error) {
|
func WriteCertificateBytesToPEM(cert []byte, path string, csr bool) (err error) {
|
||||||
out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"crypto/tls"
|
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -14,75 +13,8 @@ import (
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestShouldSetupDefaultTLSMinVersionOnErr(t *testing.T) {
|
|
||||||
schemaTLSConfig := &schema.TLSConfig{
|
|
||||||
MinimumVersion: "NotAVersion",
|
|
||||||
ServerName: "golang.org",
|
|
||||||
SkipVerify: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
tlsConfig := NewTLSConfig(schemaTLSConfig, tls.VersionTLS12, nil)
|
|
||||||
|
|
||||||
assert.Equal(t, uint16(tls.VersionTLS12), tlsConfig.MinVersion)
|
|
||||||
assert.Equal(t, "golang.org", tlsConfig.ServerName)
|
|
||||||
assert.True(t, tlsConfig.InsecureSkipVerify)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestShouldReturnCorrectTLSVersions(t *testing.T) {
|
|
||||||
tls13 := uint16(tls.VersionTLS13)
|
|
||||||
tls12 := uint16(tls.VersionTLS12)
|
|
||||||
tls11 := uint16(tls.VersionTLS11)
|
|
||||||
tls10 := uint16(tls.VersionTLS10)
|
|
||||||
|
|
||||||
version, err := TLSStringToTLSConfigVersion(TLS13)
|
|
||||||
assert.Equal(t, tls13, version)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
version, err = TLSStringToTLSConfigVersion("TLS" + TLS13)
|
|
||||||
assert.Equal(t, tls13, version)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
version, err = TLSStringToTLSConfigVersion(TLS12)
|
|
||||||
assert.Equal(t, tls12, version)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
version, err = TLSStringToTLSConfigVersion("TLS" + TLS12)
|
|
||||||
assert.Equal(t, tls12, version)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
version, err = TLSStringToTLSConfigVersion(TLS11)
|
|
||||||
assert.Equal(t, tls11, version)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
version, err = TLSStringToTLSConfigVersion("TLS" + TLS11)
|
|
||||||
assert.Equal(t, tls11, version)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
version, err = TLSStringToTLSConfigVersion(TLS10)
|
|
||||||
assert.Equal(t, tls10, version)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
version, err = TLSStringToTLSConfigVersion("TLS" + TLS10)
|
|
||||||
assert.Equal(t, tls10, version)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestShouldReturnZeroAndErrorOnInvalidTLSVersions(t *testing.T) {
|
|
||||||
version, err := TLSStringToTLSConfigVersion("TLS1.4")
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Equal(t, uint16(0), version)
|
|
||||||
assert.EqualError(t, err, "supplied tls version isn't supported")
|
|
||||||
|
|
||||||
version, err = TLSStringToTLSConfigVersion("SSL3.0")
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Equal(t, uint16(0), version)
|
|
||||||
assert.EqualError(t, err, "supplied tls version isn't supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestShouldReturnErrWhenX509DirectoryNotExist(t *testing.T) {
|
func TestShouldReturnErrWhenX509DirectoryNotExist(t *testing.T) {
|
||||||
pool, warnings, errors := NewX509CertPool("/tmp/asdfzyxabc123/not/a/real/dir")
|
pool, warnings, errors := NewX509CertPool("/tmp/asdfzyxabc123/not/a/real/dir")
|
||||||
assert.NotNil(t, pool)
|
assert.NotNil(t, pool)
|
||||||
|
|
Loading…
Reference in New Issue