feat: explicitly log if each authentication method is enabled (#3599)

feat: explicitly log if each autentication methods is enabled

When the server starts or when the config is reloaded.
See the discussion in: https://github.com/project-zot/zot/pull/3577#issuecomment-3568505810

Signed-off-by: Andrei Aaron <andreifdaaron@gmail.com>
This commit is contained in:
Andrei Aaron
2025-11-27 11:30:14 +02:00
committed by GitHub
parent e068b8dc9f
commit 69c3a0b99b
3 changed files with 179 additions and 2 deletions
+17 -2
View File
@@ -283,6 +283,15 @@ func (c *Controller) Init() error {
// print the current configuration, but strip secrets
c.Log.Info().Interface("params", c.Config.Sanitize()).Msg("configuration settings")
// log authentication methods status
authConfig := c.Config.CopyAuthConfig()
c.Log.Info().Bool("enabled", authConfig.IsBearerAuthEnabled()).Msg("bearer authentication")
c.Log.Info().Bool("enabled", authConfig.IsHtpasswdAuthEnabled()).Msg("basic authentication (htpasswd)")
c.Log.Info().Bool("enabled", authConfig.IsLdapAuthEnabled()).Msg("basic authentication (LDAP)")
c.Log.Info().Bool("enabled", authConfig.IsAPIKeyEnabled()).Msg("basic authentication (API key)")
c.Log.Info().Bool("enabled", authConfig.IsOpenIDAuthEnabled()).Msg("OpenID authentication")
c.Log.Info().Bool("enabled", c.Config.IsMTLSAuthEnabled()).Msg("mutual TLS authentication")
// print the current runtime environment
DumpRuntimeParams(c.Log)
@@ -310,8 +319,6 @@ func (c *Controller) Init() error {
c.InitCVEInfo()
c.Healthz.Started()
// Get auth config safely
authConfig := c.Config.CopyAuthConfig()
if authConfig.IsHtpasswdAuthEnabled() {
err := c.HTPasswdWatcher.ChangeFile(authConfig.HTPasswd.Path)
if err != nil {
@@ -435,6 +442,14 @@ func (c *Controller) LoadNewConfig(newConfig *config.Config) {
c.Log.Info().Interface("reloaded params", c.Config.Sanitize()).
Msg("loaded new configuration settings")
// log authentication methods status
c.Log.Info().Bool("enabled", authConfig.IsBearerAuthEnabled()).Msg("bearer authentication")
c.Log.Info().Bool("enabled", authConfig.IsHtpasswdAuthEnabled()).Msg("basic authentication (htpasswd)")
c.Log.Info().Bool("enabled", authConfig.IsLdapAuthEnabled()).Msg("basic authentication (LDAP)")
c.Log.Info().Bool("enabled", authConfig.IsAPIKeyEnabled()).Msg("basic authentication (API key)")
c.Log.Info().Bool("enabled", authConfig.IsOpenIDAuthEnabled()).Msg("OpenID authentication")
c.Log.Info().Bool("enabled", c.Config.IsMTLSAuthEnabled()).Msg("mutual TLS authentication")
}
func (c *Controller) Shutdown() {
+92
View File
@@ -94,6 +94,20 @@ func TestConfigReloader(t *testing.T) {
test.WaitTillServerReady(baseURL)
// verify initial startup authentication logs
initialData, err := os.ReadFile(logFile.Name())
So(err, ShouldBeNil)
So(string(initialData), ShouldContainSubstring, "configuration settings")
// verify authentication methods status messages are present in initial startup
verifyAuthenticationLogs(initialData, map[string]bool{
"bearer authentication": false,
"basic authentication (htpasswd)": true,
"basic authentication (LDAP)": false,
"basic authentication (API key)": false,
"OpenID authentication": false,
"mutual TLS authentication": false,
})
content = fmt.Sprintf(`{
"distSpecVersion": "1.1.1",
"storage": {
@@ -156,6 +170,15 @@ func TestConfigReloader(t *testing.T) {
So(string(data), ShouldContainSubstring, "loaded new configuration settings")
So(string(data), ShouldContainSubstring, "\"Users\":[\"alice\"]")
So(string(data), ShouldContainSubstring, "\"Actions\":[\"read\",\"create\",\"update\",\"delete\"]")
// verify authentication methods status messages are present
verifyAuthenticationLogs(data, map[string]bool{
"bearer authentication": false,
"basic authentication (htpasswd)": true,
"basic authentication (LDAP)": false,
"basic authentication (API key)": false,
"OpenID authentication": false,
"mutual TLS authentication": false,
})
})
Convey("reload gc config", t, func(c C) {
@@ -211,6 +234,20 @@ func TestConfigReloader(t *testing.T) {
test.WaitTillServerReady(baseURL)
// verify initial startup authentication logs (no auth configured)
initialData, err := os.ReadFile(logFile.Name())
So(err, ShouldBeNil)
So(string(initialData), ShouldContainSubstring, "configuration settings")
// verify authentication methods status messages are present in initial startup
verifyAuthenticationLogs(initialData, map[string]bool{
"bearer authentication": false,
"basic authentication (htpasswd)": false,
"basic authentication (LDAP)": false,
"basic authentication (API key)": false,
"OpenID authentication": false,
"mutual TLS authentication": false,
})
content = fmt.Sprintf(`{
"distSpecVersion": "1.1.1",
"storage": {
@@ -263,6 +300,15 @@ func TestConfigReloader(t *testing.T) {
So(string(data), ShouldContainSubstring, "\"Dedupe\":true")
So(string(data), ShouldNotContainSubstring, "\"GC\":false")
So(string(data), ShouldNotContainSubstring, "\"Dedupe\":false")
// verify authentication methods status messages are present
verifyAuthenticationLogs(data, map[string]bool{
"bearer authentication": false,
"basic authentication (htpasswd)": false,
"basic authentication (LDAP)": false,
"basic authentication (API key)": false,
"OpenID authentication": false,
"mutual TLS authentication": false,
})
})
Convey("reload sync config", t, func(c C) {
@@ -330,6 +376,20 @@ func TestConfigReloader(t *testing.T) {
test.WaitTillServerReady(baseURL)
// verify initial startup authentication logs (no auth configured)
initialData, err := os.ReadFile(logFile.Name())
So(err, ShouldBeNil)
So(string(initialData), ShouldContainSubstring, "configuration settings")
// verify authentication methods status messages are present in initial startup
verifyAuthenticationLogs(initialData, map[string]bool{
"bearer authentication": false,
"basic authentication (htpasswd)": false,
"basic authentication (LDAP)": false,
"basic authentication (API key)": false,
"OpenID authentication": false,
"mutual TLS authentication": false,
})
content = fmt.Sprintf(`{
"distSpecVersion": "1.1.1",
"storage": {
@@ -396,6 +456,15 @@ func TestConfigReloader(t *testing.T) {
So(string(data), ShouldContainSubstring, "\"Prefix\":\"zot-cve-test\"")
So(string(data), ShouldContainSubstring, "\"Regex\":\"tag\"")
So(string(data), ShouldContainSubstring, "\"Semver\":false")
// verify authentication methods status messages are present
verifyAuthenticationLogs(data, map[string]bool{
"bearer authentication": false,
"basic authentication (htpasswd)": false,
"basic authentication (LDAP)": false,
"basic authentication (API key)": false,
"OpenID authentication": false,
"mutual TLS authentication": false,
})
})
Convey("reload scrub and CVE config", t, func(c C) {
@@ -453,6 +522,20 @@ func TestConfigReloader(t *testing.T) {
test.WaitTillServerReady(baseURL)
// verify initial startup authentication logs (no auth configured)
initialData, err := os.ReadFile(logFile.Name())
So(err, ShouldBeNil)
So(string(initialData), ShouldContainSubstring, "configuration settings")
// verify authentication methods status messages are present in initial startup
verifyAuthenticationLogs(initialData, map[string]bool{
"bearer authentication": false,
"basic authentication (htpasswd)": false,
"basic authentication (LDAP)": false,
"basic authentication (API key)": false,
"OpenID authentication": false,
"mutual TLS authentication": false,
})
content = fmt.Sprintf(`{
"distSpecVersion": "1.1.1",
"storage": {
@@ -509,6 +592,15 @@ func TestConfigReloader(t *testing.T) {
So(string(data), ShouldContainSubstring, "\"UpdateInterval\":18000000000000")
So(string(data), ShouldContainSubstring, "\"Scrub\":null")
So(string(data), ShouldContainSubstring, "\"DBRepository\":\"another/unreachable/trivy/url2\"")
// verify authentication methods status messages are present
verifyAuthenticationLogs(data, map[string]bool{
"bearer authentication": false,
"basic authentication (htpasswd)": false,
"basic authentication (LDAP)": false,
"basic authentication (API key)": false,
"OpenID authentication": false,
"mutual TLS authentication": false,
})
// Just verify the new URL appears in the logs to confirm config reload worked and ignore
// the order of json message formatting that can change independent of this functional
+70
View File
@@ -6,6 +6,7 @@ import (
"os"
"path"
"path/filepath"
"strings"
"testing"
"time"
@@ -19,6 +20,53 @@ import (
. "zotregistry.dev/zot/v2/pkg/test/common"
)
// checkAuthLogEntry checks if a log entry with the given message has the expected enabled value.
func checkAuthLogEntry(logData []byte, message string, expectedEnabled bool) bool {
//nolint:modernize // strings.Split is compatible with older Go versions
for _, line := range strings.Split(string(logData), "\n") {
if line == "" {
continue
}
var logEntry map[string]any
if err := json.Unmarshal([]byte(line), &logEntry); err != nil {
continue
}
if msg, ok := logEntry["message"].(string); ok && msg == message {
if enabled, ok := logEntry["enabled"].(bool); ok {
return enabled == expectedEnabled
}
}
}
return false
}
// verifyAuthenticationLogs verifies that all authentication method log messages are present
// and that each method has the expected enabled status.
// expectedAuth maps authentication method names to their expected enabled status (true/false).
func verifyAuthenticationLogs(data []byte, expectedAuth map[string]bool) {
authMethods := []string{
"bearer authentication",
"basic authentication (htpasswd)",
"basic authentication (LDAP)",
"basic authentication (API key)",
"OpenID authentication",
"mutual TLS authentication",
}
// Verify all authentication method messages are present
for _, method := range authMethods {
So(string(data), ShouldContainSubstring, method)
}
// Verify each authentication method has the expected enabled status
for method, expectedEnabled := range expectedAuth {
So(checkAuthLogEntry(data, method, expectedEnabled), ShouldBeTrue)
}
}
func TestServerUsage(t *testing.T) {
oldArgs := os.Args
@@ -2031,6 +2079,17 @@ func TestServeAPIKey(t *testing.T) {
defer os.Remove(logPath) // clean up
So(string(data), ShouldContainSubstring, "\"APIKey\":true")
// verify configuration settings message is present
So(string(data), ShouldContainSubstring, "configuration settings")
// verify authentication methods status messages are present
verifyAuthenticationLogs(data, map[string]bool{
"bearer authentication": false,
"basic authentication (htpasswd)": false,
"basic authentication (LDAP)": false,
"basic authentication (API key)": true,
"OpenID authentication": false,
"mutual TLS authentication": false,
})
})
Convey("apikey disabled", t, func(c C) {
@@ -2058,6 +2117,17 @@ func TestServeAPIKey(t *testing.T) {
defer os.Remove(logPath) // clean up
So(string(data), ShouldContainSubstring, "\"APIKey\":false")
// verify configuration settings message is present
So(string(data), ShouldContainSubstring, "configuration settings")
// verify authentication methods status messages are present
verifyAuthenticationLogs(data, map[string]bool{
"bearer authentication": false,
"basic authentication (htpasswd)": false,
"basic authentication (LDAP)": false,
"basic authentication (API key)": false,
"OpenID authentication": false,
"mutual TLS authentication": false,
})
})
}