mirror of
https://github.com/project-zot/zot.git
synced 2026-06-15 11:37:56 +08:00
Read OpenID credentials from file (#3244)
* feat: read OpenID credentials from file Signed-off-by: Uwe Jäger <uwe.jaeger@valiton.com> * feat: allow credentials file and secret in config to keep BC Signed-off-by: Uwe Jäger <uwe.jaeger@valiton.com> --------- Signed-off-by: Uwe Jäger <uwe.jaeger@valiton.com>
This commit is contained in:
@@ -402,7 +402,7 @@ verify-config: _verify-config verify-config-warnings verify-config-commited
|
||||
.PHONY: _verify-config
|
||||
_verify-config: binary
|
||||
rm -f output.txt
|
||||
$(foreach file, $(filter-out examples/config-ldap-credentials.json, $(wildcard examples/config-*)), ./bin/zot-$(OS)-$(ARCH) verify $(file) 2>&1 | tee -a output.txt || exit 1;)
|
||||
$(foreach file, $(filter-out $(wildcard examples/config-*-credentials.json), $(wildcard examples/config-*)), ./bin/zot-$(OS)-$(ARCH) verify $(file) 2>&1 | tee -a output.txt || exit 1;)
|
||||
|
||||
.PHONY: verify-config-warnings
|
||||
verify-config-warnings: _verify-config
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"clientid": "client_id",
|
||||
"clientsecret": "client_secret"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"clientid": "client_id",
|
||||
"clientsecret": "client_secret"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"clientid": "client_id",
|
||||
"clientsecret": "client_secret"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"clientid": "client_id",
|
||||
"clientsecret": "client_secret"
|
||||
}
|
||||
@@ -18,28 +18,24 @@
|
||||
"openid": {
|
||||
"providers": {
|
||||
"github": {
|
||||
"clientid": "client_id",
|
||||
"clientsecret": "client_secret",
|
||||
"credentialsFile": "examples/config-openid-github-credentials.json",
|
||||
"keypath": "",
|
||||
"scopes": ["read:org", "user", "repo"]
|
||||
},
|
||||
"google": {
|
||||
"credentialsFile": "examples/config-openid-google-credentials.json",
|
||||
"issuer": "https://accounts.google.com",
|
||||
"clientid": "client_id",
|
||||
"clientsecret": "client_secret",
|
||||
"scopes": ["openid", "email"]
|
||||
},
|
||||
"gitlab": {
|
||||
"issuer": "https://gitlab.com",
|
||||
"clientid": "client_id",
|
||||
"clientsecret": "client_secret",
|
||||
"credentialsFile": "examples/config-openid-gitlab-credentials.json",
|
||||
"scopes": ["openid", "read_api", "read_user", "profile", "email"]
|
||||
},
|
||||
"oidc": {
|
||||
"name": "Corporate SSO",
|
||||
"issuer": "http://127.0.0.1:5556/dex",
|
||||
"clientid": "client_id",
|
||||
"clientsecret": "client_secret",
|
||||
"credentialsFile": "examples/config-openid-oidc-credentials.json",
|
||||
"scopes": ["openid", "user", "email", "groups"]
|
||||
}
|
||||
}
|
||||
|
||||
+6
-5
@@ -614,18 +614,19 @@ func getRelyingPartyArgs(cfg *config.Config, provider string, hashKey, encryptKe
|
||||
log.Panic().Err(zerr.ErrOpenIDProviderDoesNotExist).Str("provider", provider).Msg("")
|
||||
}
|
||||
|
||||
clientID := cfg.HTTP.Auth.OpenID.Providers[provider].ClientID
|
||||
clientSecret := cfg.HTTP.Auth.OpenID.Providers[provider].ClientSecret
|
||||
providerConfig := cfg.HTTP.Auth.OpenID.Providers[provider]
|
||||
clientID := providerConfig.ClientID
|
||||
clientSecret := providerConfig.ClientSecret
|
||||
|
||||
scopes := cfg.HTTP.Auth.OpenID.Providers[provider].Scopes
|
||||
scopes := providerConfig.Scopes
|
||||
// openid scope must be the first one in list
|
||||
if !zcommon.Contains(scopes, oidc.ScopeOpenID) && config.IsOpenIDSupported(provider) {
|
||||
scopes = append([]string{oidc.ScopeOpenID}, scopes...)
|
||||
}
|
||||
|
||||
port := cfg.HTTP.Port
|
||||
issuer := cfg.HTTP.Auth.OpenID.Providers[provider].Issuer
|
||||
keyPath := cfg.HTTP.Auth.OpenID.Providers[provider].KeyPath
|
||||
issuer := providerConfig.Issuer
|
||||
keyPath := providerConfig.KeyPath
|
||||
baseURL := net.JoinHostPort(cfg.HTTP.Address, port)
|
||||
|
||||
callback := constants.CallbackBasePath + "/" + provider
|
||||
|
||||
@@ -94,13 +94,19 @@ type OpenIDConfig struct {
|
||||
Providers map[string]OpenIDProviderConfig
|
||||
}
|
||||
|
||||
type OpenIDProviderConfig struct {
|
||||
Name string
|
||||
type OpenIDCredentials struct {
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
KeyPath string
|
||||
Issuer string
|
||||
Scopes []string
|
||||
}
|
||||
|
||||
type OpenIDProviderConfig struct {
|
||||
CredentialsFile string
|
||||
Name string
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
KeyPath string
|
||||
Issuer string
|
||||
Scopes []string
|
||||
}
|
||||
|
||||
type MethodRatelimitConfig struct {
|
||||
|
||||
@@ -863,6 +863,12 @@ func LoadConfiguration(config *config.Config, configPath string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := updateOpenIDConfig(config); err != nil {
|
||||
log.Error().Err(err).Msg("failed to read openid provider config file(s)")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
if err := loadSessionKeys(config); err != nil {
|
||||
log.Error().Err(err).Msg("failed to read sessionKeysFile")
|
||||
|
||||
@@ -926,6 +932,32 @@ func updateLDAPConfig(conf *config.Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateOpenIDConfig(conf *config.Config) error {
|
||||
if conf.HTTP.Auth == nil || conf.HTTP.Auth.OpenID == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for name, provider := range conf.HTTP.Auth.OpenID.Providers {
|
||||
if provider.CredentialsFile != "" {
|
||||
var newOpenIDCredentials config.OpenIDCredentials
|
||||
|
||||
if err := readSecretFile(provider.CredentialsFile, &newOpenIDCredentials, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
provider.ClientID = newOpenIDCredentials.ClientID
|
||||
provider.ClientSecret = newOpenIDCredentials.ClientSecret
|
||||
|
||||
conf.HTTP.Auth.OpenID.Providers[name] = provider
|
||||
} else {
|
||||
log.Warn().Str("provider", name).
|
||||
Msg("deprecated: use the new OpenID provider credentialsfile instead of clientid and clientsecret.")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func readSecretFile(path string, v any, checkUnsetFields bool) error { //nolint: varnamelen
|
||||
viperInstance := viper.NewWithOptions(viper.KeyDelimiter("::"))
|
||||
|
||||
|
||||
+65
-11
@@ -1232,7 +1232,7 @@ storage:
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Test verify oauth2 config with missing parameter", t, func(c C) {
|
||||
Convey("Test verify oauth2 config with missing parameter scopes", t, func(c C) {
|
||||
tmpfile, err := os.CreateTemp("", "zot-test*.json")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@@ -1252,6 +1252,26 @@ storage:
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Test verify oauth2 config with missing parameter clientid", t, func(c C) {
|
||||
tmpfile, err := os.CreateTemp("", "zot-test*.json")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
defer os.Remove(tmpfile.Name()) // clean up
|
||||
|
||||
content := []byte(`{"distSpecVersion":"1.1.1","storage":{"rootDirectory":"/tmp/zot"},
|
||||
"http":{"address":"127.0.0.1","port":"8080","realm":"zot",
|
||||
"auth":{"openid":{"providers":{"github":{"scopes":["openid"]}}}}},
|
||||
"log":{"level":"debug"}}`)
|
||||
_, err = tmpfile.Write(content)
|
||||
So(err, ShouldBeNil)
|
||||
err = tmpfile.Close()
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
os.Args = []string{"cli_test", "verify", tmpfile.Name()}
|
||||
err = cli.NewServerRootCmd().Execute()
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Test verify openid config with unsupported provider", t, func(c C) {
|
||||
tmpfile, err := os.CreateTemp("", "zot-test*.json")
|
||||
So(err, ShouldBeNil)
|
||||
@@ -1278,11 +1298,27 @@ storage:
|
||||
|
||||
defer os.Remove(tmpfile.Name()) // clean up
|
||||
|
||||
content := []byte(`{"distSpecVersion":"1.1.1","storage":{"rootDirectory":"/tmp/zot"},
|
||||
"http":{"address":"127.0.0.1","port":"8080","realm":"zot",
|
||||
"auth":{"openid":{"providers":{"oidc":{"issuer":"http://127.0.0.1:5556/dex",
|
||||
"clientid":"client_id","scopes":["openid"]}}}}},
|
||||
"log":{"level":"debug"}}`)
|
||||
tmpCredsFile, err := os.CreateTemp("", "zot-cred*.json")
|
||||
So(err, ShouldBeNil)
|
||||
defer os.Remove(tmpCredsFile.Name())
|
||||
|
||||
content := []byte(`{
|
||||
"clientid":"client-id",
|
||||
"clientsecret":"client-secret"
|
||||
}`)
|
||||
|
||||
_, err = tmpCredsFile.Write(content)
|
||||
So(err, ShouldBeNil)
|
||||
err = tmpCredsFile.Close()
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
content = []byte(fmt.Sprintf(`{"distSpecVersion":"1.1.1","storage":{"rootDirectory":"/tmp/zot"},
|
||||
"http":{"address":"127.0.0.1","port":"8080","realm":"zot",
|
||||
"auth":{"openid":{"providers":{"oidc":{"issuer":"http://127.0.0.1:5556/dex",
|
||||
"credentialsFile":"%s","scopes":["openid"]}}}}},
|
||||
"log":{"level":"debug"}}`,
|
||||
tmpCredsFile.Name()),
|
||||
)
|
||||
_, err = tmpfile.Write(content)
|
||||
So(err, ShouldBeNil)
|
||||
err = tmpfile.Close()
|
||||
@@ -1641,13 +1677,31 @@ func TestApiKeyConfig(t *testing.T) {
|
||||
tmpfile, err := os.CreateTemp("", "zot-test*.json")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
defer os.Remove(tmpfile.Name()) // clean up
|
||||
|
||||
tmpCredsFile, err := os.CreateTemp("", "zot-cred*.json")
|
||||
So(err, ShouldBeNil)
|
||||
defer os.Remove(tmpCredsFile.Name())
|
||||
|
||||
content := []byte(`{
|
||||
"clientid":"client-id",
|
||||
"clientsecret":"client-secret"
|
||||
}`)
|
||||
|
||||
_, err = tmpCredsFile.Write(content)
|
||||
So(err, ShouldBeNil)
|
||||
err = tmpCredsFile.Close()
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
defer os.Remove(tmpfile.Name())
|
||||
|
||||
content := []byte(`{"distSpecVersion":"1.1.1","storage":{"rootDirectory":"/tmp/zot"},
|
||||
"http":{"address":"127.0.0.1","port":"8080","realm":"zot",
|
||||
"auth":{"openid":{"providers":{"oidc":{"issuer":"http://127.0.0.1:5556/dex",
|
||||
"clientid":"client_id","scopes":["openid"]}}}}},
|
||||
"log":{"level":"debug"}}`)
|
||||
content = []byte(fmt.Sprintf(`{"distSpecVersion":"1.1.1","storage":{"rootDirectory":"/tmp/zot"},
|
||||
"http":{"address":"127.0.0.1","port":"8080","realm":"zot",
|
||||
"auth":{"openid":{"providers":{"oidc":{"issuer":"http://127.0.0.1:5556/dex",
|
||||
"credentialsFile":"%s","scopes":["openid"]}}}}},
|
||||
"log":{"level":"debug"}}`,
|
||||
tmpCredsFile.Name()),
|
||||
)
|
||||
|
||||
err = os.WriteFile(tmpfile.Name(), content, 0o0600)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@@ -14,6 +14,14 @@ function setup() {
|
||||
# Setup zot server
|
||||
local zot_root_dir=${BATS_FILE_TMPDIR}/zot
|
||||
local zot_config_file=${BATS_FILE_TMPDIR}/zot_config.json
|
||||
local zot_openid_credentials_file=${BATS_FILE_TMPDIR}/openid_credentials.json
|
||||
|
||||
cat > ${zot_openid_credentials_file}<<EOF
|
||||
{
|
||||
"clientid": "zot-client",
|
||||
"clientsecret": "ZXhhbXBsZS1hcHAtc2VjcmV0"
|
||||
}
|
||||
EOF
|
||||
|
||||
echo ${zot_root_dir} >&3
|
||||
|
||||
@@ -57,8 +65,7 @@ function setup() {
|
||||
"providers": {
|
||||
"oidc": {
|
||||
"issuer": "http://127.0.0.1:5556/dex",
|
||||
"clientid": "zot-client",
|
||||
"clientsecret": "ZXhhbXBsZS1hcHAtc2VjcmV0",
|
||||
"credentialsfile": "${zot_openid_credentials_file}",
|
||||
"scopes": ["openid", "email", "groups"]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user