mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2025-04-09 19:03:35 +03:00
home: tls manager web api
This commit is contained in:
parent
85a4de7931
commit
e35f742e42
3 changed files with 71 additions and 31 deletions
internal/home
|
@ -677,6 +677,8 @@ func run(opts options, clientBuildFS fs.FS, done chan struct{}, sigHdlr *signalH
|
||||||
globalContext.web, err = initWeb(ctx, opts, clientBuildFS, upd, slogLogger, tlsMgr, customURL)
|
globalContext.web, err = initWeb(ctx, opts, clientBuildFS, upd, slogLogger, tlsMgr, customURL)
|
||||||
fatalOnError(err)
|
fatalOnError(err)
|
||||||
|
|
||||||
|
tlsMgr.setWebAPI(globalContext.web)
|
||||||
|
|
||||||
statsDir, querylogDir, err := checkStatsAndQuerylogDirs(&globalContext, config)
|
statsDir, querylogDir, err := checkStatsAndQuerylogDirs(&globalContext, config)
|
||||||
fatalOnError(err)
|
fatalOnError(err)
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,12 @@ type tlsManager struct {
|
||||||
// tlsRoots is a pool of root CAs for TLSv1.2.
|
// tlsRoots is a pool of root CAs for TLSv1.2.
|
||||||
tlsRoots *x509.CertPool
|
tlsRoots *x509.CertPool
|
||||||
|
|
||||||
|
// webAPI is the web UI and API server.
|
||||||
|
//
|
||||||
|
// TODO(s.chzhen): Temporary cyclic dependency due to ongoing refactoring.
|
||||||
|
// Resolve it.
|
||||||
|
webAPI *webAPI
|
||||||
|
|
||||||
// configModified is called when the TLS configuration is changed via an
|
// configModified is called when the TLS configuration is changed via an
|
||||||
// HTTP request.
|
// HTTP request.
|
||||||
configModified func()
|
configModified func()
|
||||||
|
@ -116,6 +122,14 @@ func newTLSManager(ctx context.Context, conf *tlsManagerConfig) (m *tlsManager,
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setWebAPI stores the provided web API. It must be called before
|
||||||
|
// [tlsManager.start], [tlsManager.reload], or [tlsManager.handleTLSConfigure].
|
||||||
|
//
|
||||||
|
// TODO(s.chzhen): Remove it once cyclic dependency is resolved.
|
||||||
|
func (m *tlsManager) setWebAPI(webAPI *webAPI) {
|
||||||
|
m.webAPI = webAPI
|
||||||
|
}
|
||||||
|
|
||||||
// load reloads the TLS configuration from files or data from the config file.
|
// load reloads the TLS configuration from files or data from the config file.
|
||||||
func (m *tlsManager) load(ctx context.Context) (err error) {
|
func (m *tlsManager) load(ctx context.Context) (err error) {
|
||||||
err = m.loadTLSConf(ctx, &m.conf, m.status)
|
err = m.loadTLSConf(ctx, &m.conf, m.status)
|
||||||
|
@ -163,7 +177,7 @@ func (m *tlsManager) start(_ context.Context) {
|
||||||
// The background context is used because the TLSConfigChanged wraps context
|
// The background context is used because the TLSConfigChanged wraps context
|
||||||
// with timeout on its own and shuts down the server, which handles current
|
// with timeout on its own and shuts down the server, which handles current
|
||||||
// request.
|
// request.
|
||||||
globalContext.web.tlsConfigChanged(context.Background(), tlsConf)
|
m.webAPI.tlsConfigChanged(context.Background(), tlsConf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// reload updates the configuration and restarts the TLS manager.
|
// reload updates the configuration and restarts the TLS manager.
|
||||||
|
@ -215,7 +229,7 @@ func (m *tlsManager) reload(ctx context.Context) {
|
||||||
// The background context is used because the TLSConfigChanged wraps context
|
// The background context is used because the TLSConfigChanged wraps context
|
||||||
// with timeout on its own and shuts down the server, which handles current
|
// with timeout on its own and shuts down the server, which handles current
|
||||||
// request.
|
// request.
|
||||||
globalContext.web.tlsConfigChanged(context.Background(), tlsConf)
|
m.webAPI.tlsConfigChanged(context.Background(), tlsConf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// reconfigureDNSServer updates the DNS server configuration using the stored
|
// reconfigureDNSServer updates the DNS server configuration using the stored
|
||||||
|
@ -554,7 +568,7 @@ func (m *tlsManager) handleTLSConfigure(w http.ResponseWriter, r *http.Request)
|
||||||
// same reason.
|
// same reason.
|
||||||
if restartHTTPS {
|
if restartHTTPS {
|
||||||
go func() {
|
go func() {
|
||||||
globalContext.web.tlsConfigChanged(context.Background(), req.tlsConfigSettings)
|
m.webAPI.tlsConfigChanged(context.Background(), req.tlsConfigSettings)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -756,27 +770,12 @@ func (m *tlsManager) validateCertificates(
|
||||||
) (err error) {
|
) (err error) {
|
||||||
// Check only the public certificate separately from the key.
|
// Check only the public certificate separately from the key.
|
||||||
if len(certChain) > 0 {
|
if len(certChain) > 0 {
|
||||||
var certs []*x509.Certificate
|
var ok bool
|
||||||
certs, status.ValidCert, err = m.parseCertChain(ctx, certChain)
|
ok, err = m.validateCertificate(ctx, status, certChain, serverName)
|
||||||
if !status.ValidCert {
|
if !ok {
|
||||||
// Don't wrap the error, since it's informative enough as is.
|
// Don't wrap the error, since it's informative enough as is.
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
mainCert := certs[0]
|
|
||||||
status.Subject = mainCert.Subject.String()
|
|
||||||
status.Issuer = mainCert.Issuer.String()
|
|
||||||
status.NotAfter = mainCert.NotAfter
|
|
||||||
status.NotBefore = mainCert.NotBefore
|
|
||||||
status.DNSNames = mainCert.DNSNames
|
|
||||||
|
|
||||||
if chainErr := m.validateCertChain(ctx, certs, serverName); chainErr != nil {
|
|
||||||
// Let self-signed certs through and don't return this error to set
|
|
||||||
// its message into the status.WarningValidation afterwards.
|
|
||||||
err = chainErr
|
|
||||||
} else {
|
|
||||||
status.ValidChain = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the private key by parsing it.
|
// Validate the private key by parsing it.
|
||||||
|
@ -804,6 +803,41 @@ func (m *tlsManager) validateCertificates(
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validateCertificate processes certificate data. status must not be nil, as
|
||||||
|
// it is used to accumulate the validation results. Other parameters are
|
||||||
|
// optional. If ok is true, the returned error, if any, is not critical.
|
||||||
|
func (m *tlsManager) validateCertificate(
|
||||||
|
ctx context.Context,
|
||||||
|
status *tlsConfigStatus,
|
||||||
|
certChain []byte,
|
||||||
|
serverName string,
|
||||||
|
) (ok bool, err error) {
|
||||||
|
var certs []*x509.Certificate
|
||||||
|
certs, status.ValidCert, err = m.parseCertChain(ctx, certChain)
|
||||||
|
if !status.ValidCert {
|
||||||
|
// Don't wrap the error, since it's informative enough as is.
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
mainCert := certs[0]
|
||||||
|
status.Subject = mainCert.Subject.String()
|
||||||
|
status.Issuer = mainCert.Issuer.String()
|
||||||
|
status.NotAfter = mainCert.NotAfter
|
||||||
|
status.NotBefore = mainCert.NotBefore
|
||||||
|
status.DNSNames = mainCert.DNSNames
|
||||||
|
|
||||||
|
err = m.validateCertChain(ctx, certs, serverName)
|
||||||
|
if err != nil {
|
||||||
|
// Let self-signed certs through and don't return this error to set
|
||||||
|
// its message into the status.WarningValidation afterwards.
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
|
||||||
|
status.ValidChain = true
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Key types.
|
// Key types.
|
||||||
const (
|
const (
|
||||||
keyTypeECDSA = "ECDSA"
|
keyTypeECDSA = "ECDSA"
|
||||||
|
@ -866,7 +900,10 @@ func unmarshalTLS(r *http.Request) (tlsConfigSettingsExt, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.PrivateKey != "" {
|
if data.PrivateKey == "" {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
var key []byte
|
var key []byte
|
||||||
key, err = base64.StdEncoding.DecodeString(data.PrivateKey)
|
key, err = base64.StdEncoding.DecodeString(data.PrivateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -877,7 +914,6 @@ func unmarshalTLS(r *http.Request) (tlsConfigSettingsExt, error) {
|
||||||
if data.PrivateKeyPath != "" {
|
if data.PrivateKeyPath != "" {
|
||||||
return data, fmt.Errorf("private key data and file can't be set together")
|
return data, fmt.Errorf("private key data and file can't be set together")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -261,6 +261,7 @@ func TestTLSManager_Reload(t *testing.T) {
|
||||||
certDER, key = newCertAndKey(t, snAfter)
|
certDER, key = newCertAndKey(t, snAfter)
|
||||||
writeCertAndKey(t, certDER, certPath, key, keyPath)
|
writeCertAndKey(t, certDER, certPath, key, keyPath)
|
||||||
|
|
||||||
|
m.setWebAPI(globalContext.web)
|
||||||
m.reload(ctx)
|
m.reload(ctx)
|
||||||
|
|
||||||
m.WriteDiskConfig(conf)
|
m.WriteDiskConfig(conf)
|
||||||
|
@ -511,6 +512,7 @@ func TestTLSManager_HandleTLSConfigure(t *testing.T) {
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
// Reconfigure the TLS manager.
|
// Reconfigure the TLS manager.
|
||||||
|
m.setWebAPI(globalContext.web)
|
||||||
m.handleTLSConfigure(w, r)
|
m.handleTLSConfigure(w, r)
|
||||||
|
|
||||||
// The [tlsManager.handleTLSConfigure] method will start the DNS server and
|
// The [tlsManager.handleTLSConfigure] method will start the DNS server and
|
||||||
|
|
Loading…
Add table
Reference in a new issue