mirror of
https://github.com/netbirdio/netbird.git
synced 2025-02-16 18:21:24 +01:00
Automatically load IdP OIDC configuration (#847)
This commit is contained in:
parent
e4c28f64fa
commit
2c50d7af1e
@ -396,6 +396,12 @@ func loadMgmtConfig(mgmtConfigPath string) (*server.Config, error) {
|
||||
}
|
||||
log.Infof("loaded OIDC configuration from the provided IDP configuration endpoint: %s", oidcEndpoint)
|
||||
|
||||
log.Infof("configuring IdpManagerConfig.OIDCConfig.Issuer with a new value %s,", oidcConfig.Issuer)
|
||||
config.IdpManagerConfig.OIDCConfig.Issuer = strings.TrimRight(oidcConfig.Issuer, "/")
|
||||
|
||||
log.Infof("configuring IdpManagerConfig.OIDCConfig.TokenEndpoint with a new value %s,", oidcConfig.TokenEndpoint)
|
||||
config.IdpManagerConfig.OIDCConfig.TokenEndpoint = oidcConfig.TokenEndpoint
|
||||
|
||||
log.Infof("overriding HttpConfig.AuthIssuer with a new value %s, previously configured value: %s",
|
||||
oidcConfig.Issuer, config.HttpConfig.AuthIssuer)
|
||||
config.HttpConfig.AuthIssuer = oidcConfig.Issuer
|
||||
@ -441,7 +447,7 @@ type OIDCConfigResponse struct {
|
||||
func fetchOIDCConfig(oidcEndpoint string) (OIDCConfigResponse, error) {
|
||||
res, err := http.Get(oidcEndpoint)
|
||||
if err != nil {
|
||||
return OIDCConfigResponse{}, fmt.Errorf("failed fetching OIDC configuration fro mendpoint %s %v", oidcEndpoint, err)
|
||||
return OIDCConfigResponse{}, fmt.Errorf("failed fetching OIDC configuration from endpoint %s %v", oidcEndpoint, err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
|
@ -32,10 +32,10 @@ type Auth0Manager struct {
|
||||
// Auth0ClientConfig auth0 manager client configurations
|
||||
type Auth0ClientConfig struct {
|
||||
Audience string
|
||||
AuthIssuer string
|
||||
AuthIssuer string `json:"-"`
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
GrantType string
|
||||
GrantType string `json:"-"`
|
||||
}
|
||||
|
||||
// auth0JWTRequest payload struct to request a JWT Token
|
||||
@ -110,7 +110,8 @@ type auth0Profile struct {
|
||||
}
|
||||
|
||||
// NewAuth0Manager creates a new instance of the Auth0Manager
|
||||
func NewAuth0Manager(config Auth0ClientConfig, appMetrics telemetry.AppMetrics) (*Auth0Manager, error) {
|
||||
func NewAuth0Manager(oidcConfig OIDCConfig, config Auth0ClientConfig,
|
||||
appMetrics telemetry.AppMetrics) (*Auth0Manager, error) {
|
||||
|
||||
httpTransport := http.DefaultTransport.(*http.Transport).Clone()
|
||||
httpTransport.MaxIdleConns = 5
|
||||
@ -121,17 +122,19 @@ func NewAuth0Manager(config Auth0ClientConfig, appMetrics telemetry.AppMetrics)
|
||||
}
|
||||
|
||||
helper := JsonParser{}
|
||||
config.AuthIssuer = oidcConfig.TokenEndpoint
|
||||
config.GrantType = "client_credentials"
|
||||
|
||||
if config.ClientID == "" || config.ClientSecret == "" || config.GrantType == "" || config.Audience == "" || config.AuthIssuer == "" {
|
||||
return nil, fmt.Errorf("auth0 idp configuration is not complete")
|
||||
if config.ClientID == "" {
|
||||
return nil, fmt.Errorf("auth0 IdP configuration is incomplete, clientID is missing")
|
||||
}
|
||||
|
||||
if config.GrantType != "client_credentials" {
|
||||
return nil, fmt.Errorf("auth0 idp configuration failed. Grant Type should be client_credentials")
|
||||
if config.ClientSecret == "" {
|
||||
return nil, fmt.Errorf("auth0 IdP configuration is incomplete, ClientSecret is missing")
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(strings.ToLower(config.AuthIssuer), "https://") {
|
||||
return nil, fmt.Errorf("auth0 idp configuration failed. AuthIssuer should contain https://")
|
||||
if config.Audience == "" {
|
||||
return nil, fmt.Errorf("auth0 IdP configuration is incomplete, Audience is missing")
|
||||
}
|
||||
|
||||
credentials := &Auth0Credentials{
|
||||
|
@ -459,26 +459,9 @@ func TestNewAuth0Manager(t *testing.T) {
|
||||
testCase3Config := defaultTestConfig
|
||||
testCase3Config.AuthIssuer = "abc-auth0.eu.auth0.com"
|
||||
|
||||
testCase3 := test{
|
||||
name: "Wrong Auth Issuer Format",
|
||||
inputConfig: testCase3Config,
|
||||
assertErrFunc: require.Error,
|
||||
assertErrFuncMessage: "should return error when wrong auth issuer format",
|
||||
}
|
||||
|
||||
testCase4Config := defaultTestConfig
|
||||
testCase4Config.GrantType = "spa"
|
||||
|
||||
testCase4 := test{
|
||||
name: "Wrong Grant Type",
|
||||
inputConfig: testCase4Config,
|
||||
assertErrFunc: require.Error,
|
||||
assertErrFuncMessage: "should return error when wrong grant type",
|
||||
}
|
||||
|
||||
for _, testCase := range []test{testCase1, testCase2, testCase3, testCase4} {
|
||||
for _, testCase := range []test{testCase1, testCase2} {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
_, err := NewAuth0Manager(testCase.inputConfig, &telemetry.MockAppMetrics{})
|
||||
_, err := NewAuth0Manager(OIDCConfig{}, testCase.inputConfig, &telemetry.MockAppMetrics{})
|
||||
testCase.assertErrFunc(t, err, testCase.assertErrFuncMessage)
|
||||
})
|
||||
}
|
||||
|
@ -37,12 +37,13 @@ type AzureManager struct {
|
||||
|
||||
// AzureClientConfig azure manager client configurations.
|
||||
type AzureClientConfig struct {
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
GraphAPIEndpoint string
|
||||
ObjectID string
|
||||
TokenEndpoint string
|
||||
GrantType string
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
ObjectID string
|
||||
|
||||
GraphAPIEndpoint string `json:"-"`
|
||||
TokenEndpoint string `json:"-"`
|
||||
GrantType string `json:"-"`
|
||||
}
|
||||
|
||||
// AzureCredentials azure authentication information.
|
||||
@ -74,7 +75,8 @@ type azureExtension struct {
|
||||
}
|
||||
|
||||
// NewAzureManager creates a new instance of the AzureManager.
|
||||
func NewAzureManager(config AzureClientConfig, appMetrics telemetry.AppMetrics) (*AzureManager, error) {
|
||||
func NewAzureManager(oidcConfig OIDCConfig, config AzureClientConfig,
|
||||
appMetrics telemetry.AppMetrics) (*AzureManager, error) {
|
||||
httpTransport := http.DefaultTransport.(*http.Transport).Clone()
|
||||
httpTransport.MaxIdleConns = 5
|
||||
|
||||
@ -84,13 +86,20 @@ func NewAzureManager(config AzureClientConfig, appMetrics telemetry.AppMetrics)
|
||||
}
|
||||
|
||||
helper := JsonParser{}
|
||||
config.TokenEndpoint = oidcConfig.TokenEndpoint
|
||||
config.GraphAPIEndpoint = "https://graph.microsoft.com"
|
||||
config.GrantType = "client_credentials"
|
||||
|
||||
if config.ClientID == "" || config.ClientSecret == "" || config.GrantType == "" || config.GraphAPIEndpoint == "" || config.TokenEndpoint == "" {
|
||||
return nil, fmt.Errorf("azure idp configuration is not complete")
|
||||
if config.ClientID == "" {
|
||||
return nil, fmt.Errorf("azure IdP configuration is incomplete, clientID is missing")
|
||||
}
|
||||
|
||||
if config.GrantType != "client_credentials" {
|
||||
return nil, fmt.Errorf("azure idp configuration failed. Grant Type should be client_credentials")
|
||||
if config.ClientSecret == "" {
|
||||
return nil, fmt.Errorf("azure IdP configuration is incomplete, ClientSecret is missing")
|
||||
}
|
||||
|
||||
if config.ObjectID == "" {
|
||||
return nil, fmt.Errorf("azure IdP configuration is incomplete, ObjectID is missing")
|
||||
}
|
||||
|
||||
credentials := &AzureCredentials{
|
||||
|
@ -19,9 +19,17 @@ type Manager interface {
|
||||
GetUserByEmail(email string) ([]*UserData, error)
|
||||
}
|
||||
|
||||
// OIDCConfig specifies configuration for OpenID Connect provider
|
||||
// These configurations are automatically loaded from the OIDC endpoint
|
||||
type OIDCConfig struct {
|
||||
Issuer string
|
||||
TokenEndpoint string
|
||||
}
|
||||
|
||||
// Config an idp configuration struct to be loaded from management server's config file
|
||||
type Config struct {
|
||||
ManagerType string
|
||||
OIDCConfig OIDCConfig `json:"-"`
|
||||
Auth0ClientCredentials Auth0ClientConfig
|
||||
AzureClientCredentials AzureClientConfig
|
||||
KeycloakClientCredentials KeycloakClientConfig
|
||||
@ -74,13 +82,13 @@ func NewManager(config Config, appMetrics telemetry.AppMetrics) (Manager, error)
|
||||
case "none", "":
|
||||
return nil, nil
|
||||
case "auth0":
|
||||
return NewAuth0Manager(config.Auth0ClientCredentials, appMetrics)
|
||||
return NewAuth0Manager(config.OIDCConfig, config.Auth0ClientCredentials, appMetrics)
|
||||
case "azure":
|
||||
return NewAzureManager(config.AzureClientCredentials, appMetrics)
|
||||
return NewAzureManager(config.OIDCConfig, config.AzureClientCredentials, appMetrics)
|
||||
case "keycloak":
|
||||
return NewKeycloakManager(config.KeycloakClientCredentials, appMetrics)
|
||||
return NewKeycloakManager(config.OIDCConfig, config.KeycloakClientCredentials, appMetrics)
|
||||
case "zitadel":
|
||||
return NewZitadelManager(config.ZitadelClientCredentials, appMetrics)
|
||||
return NewZitadelManager(config.OIDCConfig, config.ZitadelClientCredentials, appMetrics)
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid manager type: %s", config.ManagerType)
|
||||
}
|
||||
|
@ -37,8 +37,8 @@ type KeycloakClientConfig struct {
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
AdminEndpoint string
|
||||
TokenEndpoint string
|
||||
GrantType string
|
||||
TokenEndpoint string `json:"-"`
|
||||
GrantType string `json:"-"`
|
||||
}
|
||||
|
||||
// KeycloakCredentials keycloak authentication information.
|
||||
@ -82,7 +82,8 @@ type keycloakProfile struct {
|
||||
}
|
||||
|
||||
// NewKeycloakManager creates a new instance of the KeycloakManager.
|
||||
func NewKeycloakManager(config KeycloakClientConfig, appMetrics telemetry.AppMetrics) (*KeycloakManager, error) {
|
||||
func NewKeycloakManager(oidcConfig OIDCConfig, config KeycloakClientConfig,
|
||||
appMetrics telemetry.AppMetrics) (*KeycloakManager, error) {
|
||||
httpTransport := http.DefaultTransport.(*http.Transport).Clone()
|
||||
httpTransport.MaxIdleConns = 5
|
||||
|
||||
@ -92,13 +93,19 @@ func NewKeycloakManager(config KeycloakClientConfig, appMetrics telemetry.AppMet
|
||||
}
|
||||
|
||||
helper := JsonParser{}
|
||||
config.TokenEndpoint = oidcConfig.TokenEndpoint
|
||||
config.GrantType = "client_credentials"
|
||||
|
||||
if config.ClientID == "" || config.ClientSecret == "" || config.GrantType == "" || config.AdminEndpoint == "" || config.TokenEndpoint == "" {
|
||||
return nil, fmt.Errorf("keycloak idp configuration is not complete")
|
||||
if config.ClientID == "" {
|
||||
return nil, fmt.Errorf("keycloak IdP configuration is incomplete, clientID is missing")
|
||||
}
|
||||
|
||||
if config.GrantType != "client_credentials" {
|
||||
return nil, fmt.Errorf("keycloak idp configuration failed. Grant Type should be client_credentials")
|
||||
if config.ClientSecret == "" {
|
||||
return nil, fmt.Errorf("keycloak IdP configuration is incomplete, ClientSecret is missing")
|
||||
}
|
||||
|
||||
if config.AdminEndpoint == "" {
|
||||
return nil, fmt.Errorf("keycloak IdP configuration is incomplete, AdminEndpoint is missing")
|
||||
}
|
||||
|
||||
credentials := &KeycloakCredentials{
|
||||
|
@ -46,19 +46,19 @@ func TestNewKeycloakManager(t *testing.T) {
|
||||
assertErrFuncMessage: "should return error when field empty",
|
||||
}
|
||||
|
||||
testCase5Config := defaultTestConfig
|
||||
testCase5Config.GrantType = "authorization_code"
|
||||
testCase3Config := defaultTestConfig
|
||||
testCase3Config.ClientSecret = ""
|
||||
|
||||
testCase5 := test{
|
||||
name: "Wrong GrantType",
|
||||
inputConfig: testCase5Config,
|
||||
testCase3 := test{
|
||||
name: "Missing ClientSecret Configuration",
|
||||
inputConfig: testCase3Config,
|
||||
assertErrFunc: require.Error,
|
||||
assertErrFuncMessage: "should return error when wrong grant type",
|
||||
assertErrFuncMessage: "should return error when field empty",
|
||||
}
|
||||
|
||||
for _, testCase := range []test{testCase1, testCase2, testCase5} {
|
||||
for _, testCase := range []test{testCase1, testCase2, testCase3} {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
_, err := NewKeycloakManager(testCase.inputConfig, &telemetry.MockAppMetrics{})
|
||||
_, err := NewKeycloakManager(OIDCConfig{}, testCase.inputConfig, &telemetry.MockAppMetrics{})
|
||||
testCase.assertErrFunc(t, err, testCase.assertErrFuncMessage)
|
||||
})
|
||||
}
|
||||
|
@ -30,9 +30,9 @@ type ZitadelManager struct {
|
||||
type ZitadelClientConfig struct {
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
GrantType string
|
||||
TokenEndpoint string
|
||||
ManagementEndpoint string
|
||||
GrantType string `json:"-"`
|
||||
TokenEndpoint string `json:"-"`
|
||||
ManagementEndpoint string `json:"-"`
|
||||
}
|
||||
|
||||
// ZitadelCredentials zitadel authentication information.
|
||||
@ -85,7 +85,8 @@ type zitadelProfile struct {
|
||||
}
|
||||
|
||||
// NewZitadelManager creates a new instance of the ZitadelManager.
|
||||
func NewZitadelManager(config ZitadelClientConfig, appMetrics telemetry.AppMetrics) (*ZitadelManager, error) {
|
||||
func NewZitadelManager(oidcConfig OIDCConfig, config ZitadelClientConfig,
|
||||
appMetrics telemetry.AppMetrics) (*ZitadelManager, error) {
|
||||
httpTransport := http.DefaultTransport.(*http.Transport).Clone()
|
||||
httpTransport.MaxIdleConns = 5
|
||||
|
||||
@ -95,6 +96,9 @@ func NewZitadelManager(config ZitadelClientConfig, appMetrics telemetry.AppMetri
|
||||
}
|
||||
|
||||
helper := JsonParser{}
|
||||
config.TokenEndpoint = oidcConfig.TokenEndpoint
|
||||
config.ManagementEndpoint = fmt.Sprintf("%s/management/v1", oidcConfig.Issuer)
|
||||
config.GrantType = "client_credentials"
|
||||
|
||||
if config.ClientID == "" {
|
||||
return nil, fmt.Errorf("zitadel IdP configuration is incomplete, clientID is missing")
|
||||
@ -104,18 +108,6 @@ func NewZitadelManager(config ZitadelClientConfig, appMetrics telemetry.AppMetri
|
||||
return nil, fmt.Errorf("zitadel IdP configuration is incomplete, ClientSecret is missing")
|
||||
}
|
||||
|
||||
if config.TokenEndpoint == "" {
|
||||
return nil, fmt.Errorf("zitadel IdP configuration is incomplete, TokenEndpoint is missing")
|
||||
}
|
||||
|
||||
if config.ManagementEndpoint == "" {
|
||||
return nil, fmt.Errorf("zitadel IdP configuration is incomplete, ManagementEndpoint is missing")
|
||||
}
|
||||
|
||||
if config.GrantType != "client_credentials" {
|
||||
return nil, fmt.Errorf("zitadel idp configuration failed. Grant Type should be client_credentials")
|
||||
}
|
||||
|
||||
credentials := &ZitadelCredentials{
|
||||
clientConfig: config,
|
||||
httpClient: httpClient,
|
||||
|
@ -45,19 +45,19 @@ func TestNewZitadelManager(t *testing.T) {
|
||||
assertErrFuncMessage: "should return error when field empty",
|
||||
}
|
||||
|
||||
testCase5Config := defaultTestConfig
|
||||
testCase5Config.GrantType = "authorization_code"
|
||||
testCase3Config := defaultTestConfig
|
||||
testCase3Config.ClientSecret = ""
|
||||
|
||||
testCase5 := test{
|
||||
name: "Wrong GrantType",
|
||||
inputConfig: testCase5Config,
|
||||
testCase3 := test{
|
||||
name: "Missing ClientSecret Configuration",
|
||||
inputConfig: testCase3Config,
|
||||
assertErrFunc: require.Error,
|
||||
assertErrFuncMessage: "should return error when wrong grant type",
|
||||
assertErrFuncMessage: "should return error when field empty",
|
||||
}
|
||||
|
||||
for _, testCase := range []test{testCase1, testCase2, testCase5} {
|
||||
for _, testCase := range []test{testCase1, testCase2, testCase3} {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
_, err := NewZitadelManager(testCase.inputConfig, &telemetry.MockAppMetrics{})
|
||||
_, err := NewZitadelManager(OIDCConfig{}, testCase.inputConfig, &telemetry.MockAppMetrics{})
|
||||
testCase.assertErrFunc(t, err, testCase.assertErrFuncMessage)
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user