diff --git a/management/cmd/management.go b/management/cmd/management.go index ca333b931..545d6840c 100644 --- a/management/cmd/management.go +++ b/management/cmd/management.go @@ -149,7 +149,7 @@ var ( } if key != "" { - log.Debugf("update config with activity store key") + log.Infof("update config with activity store key") config.DataStoreEncryptionKey = key err := updateMgmtConfig(mgmtConfig, config) if err != nil { @@ -466,7 +466,7 @@ func loadMgmtConfig(mgmtConfigPath string) (*server.Config, error) { } func updateMgmtConfig(path string, config *server.Config) error { - return util.WriteJson(path, config) + return util.DirectWriteJson(path, config) } // OIDCConfigResponse used for parsing OIDC config response diff --git a/management/server/idp/idp.go b/management/server/idp/idp.go index ea2231390..1e2ac658b 100644 --- a/management/server/idp/idp.go +++ b/management/server/idp/idp.go @@ -38,10 +38,10 @@ type Config struct { ManagerType string ClientConfig *ClientConfig ExtraConfig ExtraConfig - Auth0ClientCredentials Auth0ClientConfig - AzureClientCredentials AzureClientConfig - KeycloakClientCredentials KeycloakClientConfig - ZitadelClientCredentials ZitadelClientConfig + Auth0ClientCredentials *Auth0ClientConfig + AzureClientCredentials *AzureClientConfig + KeycloakClientCredentials *KeycloakClientConfig + ZitadelClientCredentials *ZitadelClientConfig } // ManagerCredentials interface that authenticates using the credential of each type of idp @@ -97,7 +97,7 @@ func NewManager(config Config, appMetrics telemetry.AppMetrics) (Manager, error) case "auth0": auth0ClientConfig := config.Auth0ClientCredentials if config.ClientConfig != nil { - auth0ClientConfig = Auth0ClientConfig{ + auth0ClientConfig = &Auth0ClientConfig{ Audience: config.ExtraConfig["Audience"], AuthIssuer: config.ClientConfig.Issuer, ClientID: config.ClientConfig.ClientID, @@ -106,11 +106,11 @@ func NewManager(config Config, appMetrics telemetry.AppMetrics) (Manager, error) } } - return NewAuth0Manager(auth0ClientConfig, appMetrics) + return NewAuth0Manager(*auth0ClientConfig, appMetrics) case "azure": azureClientConfig := config.AzureClientCredentials if config.ClientConfig != nil { - azureClientConfig = AzureClientConfig{ + azureClientConfig = &AzureClientConfig{ ClientID: config.ClientConfig.ClientID, ClientSecret: config.ClientConfig.ClientSecret, GrantType: config.ClientConfig.GrantType, @@ -120,11 +120,11 @@ func NewManager(config Config, appMetrics telemetry.AppMetrics) (Manager, error) } } - return NewAzureManager(azureClientConfig, appMetrics) + return NewAzureManager(*azureClientConfig, appMetrics) case "keycloak": keycloakClientConfig := config.KeycloakClientCredentials if config.ClientConfig != nil { - keycloakClientConfig = KeycloakClientConfig{ + keycloakClientConfig = &KeycloakClientConfig{ ClientID: config.ClientConfig.ClientID, ClientSecret: config.ClientConfig.ClientSecret, GrantType: config.ClientConfig.GrantType, @@ -133,11 +133,11 @@ func NewManager(config Config, appMetrics telemetry.AppMetrics) (Manager, error) } } - return NewKeycloakManager(keycloakClientConfig, appMetrics) + return NewKeycloakManager(*keycloakClientConfig, appMetrics) case "zitadel": zitadelClientConfig := config.ZitadelClientCredentials if config.ClientConfig != nil { - zitadelClientConfig = ZitadelClientConfig{ + zitadelClientConfig = &ZitadelClientConfig{ ClientID: config.ClientConfig.ClientID, ClientSecret: config.ClientConfig.ClientSecret, GrantType: config.ClientConfig.GrantType, @@ -146,7 +146,7 @@ func NewManager(config Config, appMetrics telemetry.AppMetrics) (Manager, error) } } - return NewZitadelManager(zitadelClientConfig, appMetrics) + return NewZitadelManager(*zitadelClientConfig, appMetrics) case "authentik": authentikConfig := AuthentikClientConfig{ Issuer: config.ClientConfig.Issuer, diff --git a/util/file.go b/util/file.go index 022841947..0cbfa37ab 100644 --- a/util/file.go +++ b/util/file.go @@ -5,6 +5,8 @@ import ( "io" "os" "path/filepath" + + log "github.com/sirupsen/logrus" ) // WriteJson writes JSON config object to a file creating parent directories if required @@ -54,6 +56,68 @@ func WriteJson(file string, obj interface{}) error { return nil } +// DirectWriteJson writes JSON config object to a file creating parent directories if required without creating a temporary file +func DirectWriteJson(file string, obj interface{}) error { + + _, _, err := prepareConfigFileDir(file) + if err != nil { + return err + } + + targetFile, err := openOrCreateFile(file) + if err != nil { + return err + } + + defer func() { + err = targetFile.Close() + if err != nil { + log.Errorf("failed to close file %s: %v", file, err) + } + }() + + // make it pretty + bs, err := json.MarshalIndent(obj, "", " ") + if err != nil { + return err + } + + err = targetFile.Truncate(0) + if err != nil { + return err + } + + _, err = targetFile.Write(bs) + if err != nil { + return err + } + + return nil +} + +func openOrCreateFile(file string) (*os.File, error) { + s, err := os.Stat(file) + if err == nil { + return os.OpenFile(file, os.O_WRONLY, s.Mode()) + } + + if !os.IsNotExist(err) { + return nil, err + } + + targetFile, err := os.Create(file) + if err != nil { + return nil, err + } + //no:lint + err = targetFile.Chmod(0640) + if err != nil { + _ = targetFile.Close() + return nil, err + } + return targetFile, nil +} + // ReadJson reads JSON config file and maps to a provided interface func ReadJson(file string, res interface{}) (interface{}, error) {