@@ -108,6 +108,8 @@ components:
|
|||||||
$ref: '#/components/schemas/AuthInternalUser'
|
$ref: '#/components/schemas/AuthInternalUser'
|
||||||
authHTTPAddress:
|
authHTTPAddress:
|
||||||
type: string
|
type: string
|
||||||
|
authHTTPFingerprint:
|
||||||
|
type: string
|
||||||
authHTTPExclude:
|
authHTTPExclude:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
|
|||||||
@@ -121,6 +121,21 @@ authHTTPExclude:
|
|||||||
- action: pprof
|
- action: pprof
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If the authentication server uses HTTPS and has a self-signed or invalid TLS certificate, you can provide the fingerprint of the certificate to validate it anyway:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
authMethod: http
|
||||||
|
authHTTPAddress: https://myauthserver/auth
|
||||||
|
authHTTPFingerprint: 33949e05fffb5ff3e8aa16f8213a6251b4d9363804ba53233c4da9a46d6f2739
|
||||||
|
```
|
||||||
|
|
||||||
|
The fingerprint can be obtained with:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
openssl s_client -connect myauthserver:443 </dev/null 2>/dev/null | sed -n '/BEGIN/,/END/p' > server.crt
|
||||||
|
openssl x509 -in server.crt -noout -fingerprint -sha256 | cut -d "=" -f2 | tr -d ':'
|
||||||
|
```
|
||||||
|
|
||||||
### External JWT provider
|
### External JWT provider
|
||||||
|
|
||||||
Authentication can be delegated to an external identity server, that is capable of generating JWTs and provides a JWKS endpoint. With respect to the HTTP-based method, this has the advantage that the external server is contacted once, and not for every request, greatly improving performance. In order to use the JWT-based authentication method, set `authMethod` and `authJWTJWKS`:
|
Authentication can be delegated to an external identity server, that is capable of generating JWTs and provides a JWKS endpoint. With respect to the HTTP-based method, this has the advantage that the external server is contacted once, and not for every request, greatly improving performance. In order to use the JWT-based authentication method, set `authMethod` and `authJWTJWKS`:
|
||||||
@@ -146,6 +161,22 @@ The JWT is expected to contain a claim, with a list of permissions in the same f
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If the JWKS server uses TLS and has a self-signed or invalid TLS certificate, you can provide the fingerprint of the certificate to validate it anyway:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
authMethod: jwt
|
||||||
|
authJWTJWKS: https://my_identity_server/jwks_endpoint
|
||||||
|
authJWTJWKSFingerprint: 33949e05fffb5ff3e8aa16f8213a6251b4d9363804ba53233c4da9a46d6f2739
|
||||||
|
authJWTClaimKey: mediamtx_permissions
|
||||||
|
```
|
||||||
|
|
||||||
|
The fingerprint can be obtained with:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
openssl s_client -connect my_identity_server:443 </dev/null 2>/dev/null | sed -n '/BEGIN/,/END/p' > server.crt
|
||||||
|
openssl x509 -in server.crt -noout -fingerprint -sha256 | cut -d "=" -f2 | tr -d ':'
|
||||||
|
```
|
||||||
|
|
||||||
#### Keycloak setup
|
#### Keycloak setup
|
||||||
|
|
||||||
Here's a tutorial on how to setup the [Keycloak identity server](https://www.keycloak.org/) in order to provide JWTs.
|
Here's a tutorial on how to setup the [Keycloak identity server](https://www.keycloak.org/) in order to provide JWTs.
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ type Manager struct {
|
|||||||
Method conf.AuthMethod
|
Method conf.AuthMethod
|
||||||
InternalUsers []conf.AuthInternalUser
|
InternalUsers []conf.AuthInternalUser
|
||||||
HTTPAddress string
|
HTTPAddress string
|
||||||
|
HTTPFingerprint string
|
||||||
HTTPExclude []conf.AuthInternalUserPermission
|
HTTPExclude []conf.AuthInternalUserPermission
|
||||||
JWTJWKS string
|
JWTJWKS string
|
||||||
JWTJWKSFingerprint string
|
JWTJWKSFingerprint string
|
||||||
@@ -172,7 +173,22 @@ func (m *Manager) authenticateHTTP(req *Request) error {
|
|||||||
Query: req.Query,
|
Query: req.Query,
|
||||||
})
|
})
|
||||||
|
|
||||||
res, err := http.Post(m.HTTPAddress, "application/json", bytes.NewReader(enc))
|
u, err := url.Parse(m.HTTPAddress)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tr := &http.Transport{
|
||||||
|
TLSClientConfig: tls.MakeConfig(u.Hostname(), m.HTTPFingerprint),
|
||||||
|
}
|
||||||
|
defer tr.CloseIdleConnections()
|
||||||
|
|
||||||
|
httpClient := &http.Client{
|
||||||
|
Timeout: m.ReadTimeout,
|
||||||
|
Transport: tr,
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := httpClient.Post(m.HTTPAddress, "application/json", bytes.NewReader(enc))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("HTTP request failed: %w", err)
|
return fmt.Errorf("HTTP request failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
|
"crypto/tls"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -16,6 +17,58 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var testTLSCertPub = []byte(`-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDazCCAlOgAwIBAgIUXw1hEC3LFpTsllv7D3ARJyEq7sIwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
|
||||||
|
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDEyMTMxNzQ0NThaFw0zMDEy
|
||||||
|
MTExNzQ0NThaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
|
||||||
|
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
|
||||||
|
AQUAA4IBDwAwggEKAoIBAQDG8DyyS51810GsGwgWr5rjJK7OE1kTTLSNEEKax8Bj
|
||||||
|
zOyiaz8rA2JGl2VUEpi2UjDr9Cm7nd+YIEVs91IIBOb7LGqObBh1kGF3u5aZxLkv
|
||||||
|
NJE+HrLVvUhaDobK2NU+Wibqc/EI3DfUkt1rSINvv9flwTFu1qHeuLWhoySzDKEp
|
||||||
|
OzYxpFhwjVSokZIjT4Red3OtFz7gl2E6OAWe2qoh5CwLYVdMWtKR0Xuw3BkDPk9I
|
||||||
|
qkQKx3fqv97LPEzhyZYjDT5WvGrgZ1WDAN3booxXF3oA1H3GHQc4m/vcLatOtb8e
|
||||||
|
nI59gMQLEbnp08cl873bAuNuM95EZieXTHNbwUnq5iybAgMBAAGjUzBRMB0GA1Ud
|
||||||
|
DgQWBBQBKhJh8eWu0a4au9X/2fKhkFX2vjAfBgNVHSMEGDAWgBQBKhJh8eWu0a4a
|
||||||
|
u9X/2fKhkFX2vjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBj
|
||||||
|
3aCW0YPKukYgVK9cwN0IbVy/D0C1UPT4nupJcy/E0iC7MXPZ9D/SZxYQoAkdptdO
|
||||||
|
xfI+RXkpQZLdODNx9uvV+cHyZHZyjtE5ENu/i5Rer2cWI/mSLZm5lUQyx+0KZ2Yu
|
||||||
|
tEI1bsebDK30msa8QSTn0WidW9XhFnl3gRi4wRdimcQapOWYVs7ih+nAlSvng7NI
|
||||||
|
XpAyRs8PIEbpDDBMWnldrX4TP6EWYUi49gCp8OUDRREKX3l6Ls1vZ02F34yHIt/7
|
||||||
|
7IV/XSKG096bhW+icKBWV0IpcEsgTzPK1J1hMxgjhzIMxGboAeUU+kidthOob6Sd
|
||||||
|
XQxaORfgM//NzX9LhUPk
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
`)
|
||||||
|
|
||||||
|
var testTLSCertKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEogIBAAKCAQEAxvA8skudfNdBrBsIFq+a4ySuzhNZE0y0jRBCmsfAY8zsoms/
|
||||||
|
KwNiRpdlVBKYtlIw6/Qpu53fmCBFbPdSCATm+yxqjmwYdZBhd7uWmcS5LzSRPh6y
|
||||||
|
1b1IWg6GytjVPlom6nPxCNw31JLda0iDb7/X5cExbtah3ri1oaMkswyhKTs2MaRY
|
||||||
|
cI1UqJGSI0+EXndzrRc+4JdhOjgFntqqIeQsC2FXTFrSkdF7sNwZAz5PSKpECsd3
|
||||||
|
6r/eyzxM4cmWIw0+Vrxq4GdVgwDd26KMVxd6ANR9xh0HOJv73C2rTrW/HpyOfYDE
|
||||||
|
CxG56dPHJfO92wLjbjPeRGYnl0xzW8FJ6uYsmwIDAQABAoIBACi0BKcyQ3HElSJC
|
||||||
|
kaAao+Uvnzh4yvPg8Nwf5JDIp/uDdTMyIEWLtrLczRWrjGVZYbsVROinP5VfnPTT
|
||||||
|
kYwkfKINj2u+gC6lsNuPnRuvHXikF8eO/mYvCTur1zZvsQnF5kp4GGwIqr+qoPUP
|
||||||
|
bB0UMndG1PdpoMryHe+JcrvTrLHDmCeH10TqOwMsQMLHYLkowvxwJWsmTY7/Qr5S
|
||||||
|
Wm3PPpOcW2i0uyPVuyuv4yD1368fqnqJ8QFsQp1K6QtYsNnJ71Hut1/IoxK/e6hj
|
||||||
|
5Z+byKtHVtmcLnABuoOT7BhleJNFBksX9sh83jid4tMBgci+zXNeGmgqo2EmaWAb
|
||||||
|
agQslkECgYEA8B1rzjOHVQx/vwSzDa4XOrpoHQRfyElrGNz9JVBvnoC7AorezBXQ
|
||||||
|
M9WTHQIFTGMjzD8pb+YJGi3gj93VN51r0SmJRxBaBRh1ZZI9kFiFzngYev8POgD3
|
||||||
|
ygmlS3kTHCNxCK/CJkB+/jMBgtPj5ygDpCWVcTSuWlQFphePkW7jaaECgYEA1Blz
|
||||||
|
ulqgAyJHZaqgcbcCsI2q6m527hVr9pjzNjIVmkwu38yS9RTCgdlbEVVDnS0hoifl
|
||||||
|
+jVMEGXjF3xjyMvL50BKbQUH+KAa+V4n1WGlnZOxX9TMny8MBjEuSX2+362vQ3BX
|
||||||
|
4vOlX00gvoc+sY+lrzvfx/OdPCHQGVYzoKCxhLsCgYA07HcviuIAV/HsO2/vyvhp
|
||||||
|
xF5gTu+BqNUHNOZDDDid+ge+Jre2yfQLCL8VPLXIQW3Jff53IH/PGl+NtjphuLvj
|
||||||
|
7UDJvgvpZZuymIojP6+2c3gJ3CASC9aR3JBnUzdoE1O9s2eaoMqc4scpe+SWtZYf
|
||||||
|
3vzSZ+cqF6zrD/Rf/M35IQKBgHTU4E6ShPm09CcoaeC5sp2WK8OevZw/6IyZi78a
|
||||||
|
r5Oiy18zzO97U/k6xVMy6F+38ILl/2Rn31JZDVJujniY6eSkIVsUHmPxrWoXV1HO
|
||||||
|
y++U32uuSFiXDcSLarfIsE992MEJLSAynbF1Rsgsr3gXbGiuToJRyxbIeVy7gwzD
|
||||||
|
94TpAoGAY4/PejWQj9psZfAhyk5dRGra++gYRQ/gK1IIc1g+Dd2/BxbT/RHr05GK
|
||||||
|
6vwrfjsoRyMWteC1SsNs/CurjfQ/jqCfHNP5XPvxgd5Ec8sRJIiV7V5RTuWJsPu1
|
||||||
|
+3K6cnKEyg+0ekYmLertRFIY6SwWmY1fyKgTvxudMcsBY7dC4xs=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
|
`)
|
||||||
|
|
||||||
func mustParseCIDR(v string) conf.IPNetwork {
|
func mustParseCIDR(v string) conf.IPNetwork {
|
||||||
_, ne, err := net.ParseCIDR(v)
|
_, ne, err := net.ParseCIDR(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -309,6 +362,62 @@ func TestAuthHTTP(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAuthHTTPFingerprint(t *testing.T) {
|
||||||
|
httpServ := &http.Server{
|
||||||
|
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
require.Equal(t, http.MethodPost, r.Method)
|
||||||
|
require.Equal(t, "/auth", r.URL.Path)
|
||||||
|
|
||||||
|
var in struct {
|
||||||
|
IP string `json:"ip"`
|
||||||
|
User string `json:"user"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
Protocol string `json:"protocol"`
|
||||||
|
ID string `json:"id"`
|
||||||
|
Action string `json:"action"`
|
||||||
|
Query string `json:"query"`
|
||||||
|
}
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&in)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
if in.User != "testuser" || in.Password != "testpass" {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
ln, err := net.Listen("tcp", "localhost:9121")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
cert, err := tls.X509KeyPair(testTLSCertPub, testTLSCertKey)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
httpServ.TLSConfig = &tls.Config{Certificates: []tls.Certificate{cert}}
|
||||||
|
|
||||||
|
go httpServ.ServeTLS(ln, "", "")
|
||||||
|
defer httpServ.Shutdown(context.Background())
|
||||||
|
|
||||||
|
m := Manager{
|
||||||
|
Method: conf.AuthMethodHTTP,
|
||||||
|
HTTPAddress: "https://localhost:9121/auth",
|
||||||
|
HTTPFingerprint: "33949e05fffb5ff3e8aa16f8213a6251b4d9363804ba53233c4da9a46d6f2739",
|
||||||
|
}
|
||||||
|
|
||||||
|
err2 := m.Authenticate(&Request{
|
||||||
|
Action: conf.AuthActionPublish,
|
||||||
|
Path: "teststream",
|
||||||
|
Protocol: ProtocolRTSP,
|
||||||
|
Credentials: &Credentials{
|
||||||
|
User: "testuser",
|
||||||
|
Pass: "testpass",
|
||||||
|
},
|
||||||
|
IP: net.ParseIP("127.0.0.1"),
|
||||||
|
})
|
||||||
|
require.Nil(t, err2)
|
||||||
|
}
|
||||||
|
|
||||||
func TestAuthHTTPExclude(t *testing.T) {
|
func TestAuthHTTPExclude(t *testing.T) {
|
||||||
m := Manager{
|
m := Manager{
|
||||||
Method: conf.AuthMethodHTTP,
|
Method: conf.AuthMethodHTTP,
|
||||||
@@ -584,3 +693,86 @@ func TestAuthJWTRefresh(t *testing.T) {
|
|||||||
m.RefreshJWTJWKS()
|
m.RefreshJWTJWKS()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAuthJWTFingerprint(t *testing.T) {
|
||||||
|
key, err := rsa.GenerateKey(rand.Reader, 1024)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
httpServ := &http.Server{
|
||||||
|
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
jwk, err2 := jwkset.NewJWKFromKey(key, jwkset.JWKOptions{
|
||||||
|
Metadata: jwkset.JWKMetadataOptions{
|
||||||
|
KID: "test-key-id",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
require.NoError(t, err2)
|
||||||
|
|
||||||
|
jwkSet := jwkset.NewMemoryStorage()
|
||||||
|
err2 = jwkSet.KeyWrite(context.Background(), jwk)
|
||||||
|
require.NoError(t, err2)
|
||||||
|
|
||||||
|
response, err2 := jwkSet.JSONPublic(r.Context())
|
||||||
|
if err2 != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
_, _ = w.Write(response)
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
ln, err := net.Listen("tcp", "localhost:4568")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
cert, err := tls.X509KeyPair(testTLSCertPub, testTLSCertKey)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
httpServ.TLSConfig = &tls.Config{Certificates: []tls.Certificate{cert}}
|
||||||
|
|
||||||
|
go httpServ.ServeTLS(ln, "", "")
|
||||||
|
defer httpServ.Shutdown(context.Background())
|
||||||
|
|
||||||
|
type customClaims struct {
|
||||||
|
jwt.RegisteredClaims
|
||||||
|
MediaMTXPermissions []conf.AuthInternalUserPermission `json:"my_permission_key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
claims := customClaims{
|
||||||
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
|
||||||
|
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||||
|
NotBefore: jwt.NewNumericDate(time.Now()),
|
||||||
|
Issuer: "test",
|
||||||
|
Subject: "somebody",
|
||||||
|
ID: "1",
|
||||||
|
},
|
||||||
|
MediaMTXPermissions: []conf.AuthInternalUserPermission{{
|
||||||
|
Action: conf.AuthActionPublish,
|
||||||
|
Path: "mypath",
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
|
||||||
|
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
|
||||||
|
token.Header[jwkset.HeaderKID] = "test-key-id"
|
||||||
|
ss, err := token.SignedString(key)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
m := Manager{
|
||||||
|
Method: conf.AuthMethodJWT,
|
||||||
|
JWTJWKS: "https://localhost:4568/jwks",
|
||||||
|
JWTJWKSFingerprint: "33949e05fffb5ff3e8aa16f8213a6251b4d9363804ba53233c4da9a46d6f2739",
|
||||||
|
JWTClaimKey: "my_permission_key",
|
||||||
|
}
|
||||||
|
|
||||||
|
err2 := m.Authenticate(&Request{
|
||||||
|
Action: conf.AuthActionPublish,
|
||||||
|
Path: "mypath",
|
||||||
|
Protocol: ProtocolRTSP,
|
||||||
|
Credentials: &Credentials{
|
||||||
|
Token: ss,
|
||||||
|
},
|
||||||
|
IP: net.ParseIP("127.0.0.1"),
|
||||||
|
})
|
||||||
|
require.Nil(t, err2)
|
||||||
|
}
|
||||||
|
|||||||
@@ -262,6 +262,7 @@ type Conf struct {
|
|||||||
AuthInternalUsers []AuthInternalUser `json:"authInternalUsers"`
|
AuthInternalUsers []AuthInternalUser `json:"authInternalUsers"`
|
||||||
AuthHTTPAddress string `json:"authHTTPAddress"`
|
AuthHTTPAddress string `json:"authHTTPAddress"`
|
||||||
ExternalAuthenticationURL *string `json:"externalAuthenticationURL,omitempty"` // deprecated
|
ExternalAuthenticationURL *string `json:"externalAuthenticationURL,omitempty"` // deprecated
|
||||||
|
AuthHTTPFingerprint string `json:"authHTTPFingerprint"`
|
||||||
AuthHTTPExclude []AuthInternalUserPermission `json:"authHTTPExclude"`
|
AuthHTTPExclude []AuthInternalUserPermission `json:"authHTTPExclude"`
|
||||||
AuthJWTJWKS string `json:"authJWTJWKS"`
|
AuthJWTJWKS string `json:"authJWTJWKS"`
|
||||||
AuthJWTJWKSFingerprint string `json:"authJWTJWKSFingerprint"`
|
AuthJWTJWKSFingerprint string `json:"authJWTJWKSFingerprint"`
|
||||||
|
|||||||
@@ -337,6 +337,7 @@ func (p *Core) createResources(initial bool) error {
|
|||||||
Method: p.conf.AuthMethod,
|
Method: p.conf.AuthMethod,
|
||||||
InternalUsers: p.conf.AuthInternalUsers,
|
InternalUsers: p.conf.AuthInternalUsers,
|
||||||
HTTPAddress: p.conf.AuthHTTPAddress,
|
HTTPAddress: p.conf.AuthHTTPAddress,
|
||||||
|
HTTPFingerprint: p.conf.AuthHTTPFingerprint,
|
||||||
HTTPExclude: p.conf.AuthHTTPExclude,
|
HTTPExclude: p.conf.AuthHTTPExclude,
|
||||||
JWTJWKS: p.conf.AuthJWTJWKS,
|
JWTJWKS: p.conf.AuthJWTJWKS,
|
||||||
JWTJWKSFingerprint: p.conf.AuthJWTJWKSFingerprint,
|
JWTJWKSFingerprint: p.conf.AuthJWTJWKSFingerprint,
|
||||||
@@ -719,6 +720,7 @@ func (p *Core) closeResources(newConf *conf.Conf, calledByAPI bool) {
|
|||||||
closeAuthManager := newConf == nil ||
|
closeAuthManager := newConf == nil ||
|
||||||
newConf.AuthMethod != p.conf.AuthMethod ||
|
newConf.AuthMethod != p.conf.AuthMethod ||
|
||||||
newConf.AuthHTTPAddress != p.conf.AuthHTTPAddress ||
|
newConf.AuthHTTPAddress != p.conf.AuthHTTPAddress ||
|
||||||
|
newConf.AuthHTTPFingerprint != p.conf.AuthHTTPFingerprint ||
|
||||||
!reflect.DeepEqual(newConf.AuthHTTPExclude, p.conf.AuthHTTPExclude) ||
|
!reflect.DeepEqual(newConf.AuthHTTPExclude, p.conf.AuthHTTPExclude) ||
|
||||||
newConf.AuthJWTJWKS != p.conf.AuthJWTJWKS ||
|
newConf.AuthJWTJWKS != p.conf.AuthJWTJWKS ||
|
||||||
newConf.AuthJWTJWKSFingerprint != p.conf.AuthJWTJWKSFingerprint ||
|
newConf.AuthJWTJWKSFingerprint != p.conf.AuthJWTJWKSFingerprint ||
|
||||||
|
|||||||
@@ -107,6 +107,12 @@ authInternalUsers:
|
|||||||
# If the response code is 20x, authentication is accepted, otherwise
|
# If the response code is 20x, authentication is accepted, otherwise
|
||||||
# it is discarded.
|
# it is discarded.
|
||||||
authHTTPAddress:
|
authHTTPAddress:
|
||||||
|
# If the HTTP authentication URL has a self-signed or invalid certificate,
|
||||||
|
# you can provide the fingerprint of the certificate in order to
|
||||||
|
# validate it anyway. It can be obtained by running:
|
||||||
|
# openssl s_client -connect auth_http_domain:443 </dev/null 2>/dev/null | sed -n '/BEGIN/,/END/p' > server.crt
|
||||||
|
# openssl x509 -in server.crt -noout -fingerprint -sha256 | cut -d "=" -f2 | tr -d ':'
|
||||||
|
authHTTPFingerprint:
|
||||||
# Actions to exclude from HTTP-based authentication.
|
# Actions to exclude from HTTP-based authentication.
|
||||||
# Format is the same as the one of user permissions.
|
# Format is the same as the one of user permissions.
|
||||||
authHTTPExclude:
|
authHTTPExclude:
|
||||||
|
|||||||
Reference in New Issue
Block a user