Skip to content

Commit 1b3c082

Browse files
mgyongyosidmihai
andauthored
SSO: Improve Azure AD validation (#1390)
* improve oauth2 validation * remove old code and fix azuread validations * fix config for azuread in tests * fix configs with validation errors in sso tests * fix linter * prefix new validator functions with sso --------- Co-authored-by: Mihai Doarna <[email protected]>
1 parent 6dcd6e6 commit 1b3c082

File tree

2 files changed

+106
-40
lines changed

2 files changed

+106
-40
lines changed

internal/resources/grafana/resource_sso_settings.go

Lines changed: 77 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -454,40 +454,55 @@ func getSettingsFromResourceData(d *schema.ResourceData, settingsKey string) (ma
454454
return nil, fmt.Errorf("no valid settings found for the provider %s", d.Get(providerKey).(string))
455455
}
456456

457-
func validateOAuth2Settings(provider string, settings map[string]any) error {
458-
authURL := settings["auth_url"].(string)
459-
tokenURL := settings["token_url"].(string)
460-
apiURL := settings["api_url"].(string)
457+
type validateFunc func(settingsMap map[string]any, provider string) error
458+
459+
var validationsByProvider = map[string][]validateFunc{
460+
"azuread": {
461+
ssoValidateNotEmpty("auth_url"),
462+
ssoValidateNotEmpty("token_url"),
463+
ssoValidateEmpty("api_url"),
464+
ssoValidateURL("auth_url"),
465+
ssoValidateURL("token_url"),
466+
},
467+
"generic_oauth": {
468+
ssoValidateNotEmpty("auth_url"),
469+
ssoValidateNotEmpty("token_url"),
470+
ssoValidateNotEmpty("api_url"),
471+
ssoValidateURL("auth_url"),
472+
ssoValidateURL("token_url"),
473+
ssoValidateURL("api_url"),
474+
},
475+
"okta": {
476+
ssoValidateNotEmpty("auth_url"),
477+
ssoValidateNotEmpty("token_url"),
478+
ssoValidateNotEmpty("api_url"),
479+
ssoValidateURL("auth_url"),
480+
ssoValidateURL("token_url"),
481+
ssoValidateURL("api_url"),
482+
},
483+
"github": {
484+
ssoValidateEmpty("auth_url"),
485+
ssoValidateEmpty("token_url"),
486+
ssoValidateEmpty("api_url"),
487+
},
488+
"gitlab": {
489+
ssoValidateEmpty("auth_url"),
490+
ssoValidateEmpty("token_url"),
491+
ssoValidateEmpty("api_url"),
492+
},
493+
"google": {
494+
ssoValidateEmpty("auth_url"),
495+
ssoValidateEmpty("token_url"),
496+
ssoValidateEmpty("api_url"),
497+
},
498+
}
461499

462-
switch provider {
463-
case "github", "gitlab", "google":
464-
if authURL != "" {
465-
return fmt.Errorf("auth_url must be empty for the provider %s", provider)
466-
}
467-
if tokenURL != "" {
468-
return fmt.Errorf("token_url must be empty for the provider %s", provider)
469-
}
470-
if apiURL != "" {
471-
return fmt.Errorf("api_url must be empty for the provider %s", provider)
472-
}
473-
case "azuread", "generic_oauth", "okta":
474-
if authURL == "" {
475-
return fmt.Errorf("auth_url must be set for the provider %s", provider)
476-
}
477-
if !isValidURL(authURL) {
478-
return fmt.Errorf("auth_url must be a valid http/https URL")
479-
}
480-
if tokenURL == "" {
481-
return fmt.Errorf("token_url must be set for the provider %s", provider)
482-
}
483-
if !isValidURL(tokenURL) {
484-
return fmt.Errorf("token_url must be a valid http/https URL")
485-
}
486-
if apiURL == "" {
487-
return fmt.Errorf("api_url must be set for the provider %s", provider)
488-
}
489-
if !isValidURL(apiURL) {
490-
return fmt.Errorf("api_url must be a valid http/https URL")
500+
func validateOAuth2Settings(provider string, settings map[string]any) error {
501+
validators := validationsByProvider[provider]
502+
for _, validateF := range validators {
503+
err := validateF(settings, provider)
504+
if err != nil {
505+
return err
491506
}
492507
}
493508

@@ -599,3 +614,32 @@ func isValidURL(actual string) bool {
599614
}
600615
return strings.HasPrefix(parsed.Scheme, "http") && parsed.Host != ""
601616
}
617+
618+
func ssoValidateNotEmpty(key string) validateFunc {
619+
return func(settingsMap map[string]any, provider string) error {
620+
if settingsMap[key] == "" {
621+
return fmt.Errorf("%s must be set for the provider %s", key, provider)
622+
}
623+
624+
return nil
625+
}
626+
}
627+
628+
func ssoValidateEmpty(key string) validateFunc {
629+
return func(settingsMap map[string]any, provider string) error {
630+
if settingsMap[key].(string) != "" {
631+
return fmt.Errorf("%s must be empty for the provider %s", key, provider)
632+
}
633+
634+
return nil
635+
}
636+
}
637+
638+
func ssoValidateURL(key string) validateFunc {
639+
return func(settingsMap map[string]any, provider string) error {
640+
if !isValidURL(settingsMap[key].(string)) {
641+
return fmt.Errorf("%s must be a valid http/https URL for the provider %s", key, provider)
642+
}
643+
return nil
644+
}
645+
}

internal/resources/grafana/resource_sso_settings_test.go

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,13 @@ func checkSsoSettingsReset(api *client.GrafanaHTTPAPI, provider string, defaultS
236236
func testConfigForProvider(provider string, prefix string) string {
237237
urls := ""
238238
switch provider {
239-
case "azuread", "generic_oauth", "okta":
239+
case "generic_oauth", "okta":
240240
urls = `auth_url = "https://myidp.com/oauth/authorize"
241241
token_url = "https://myidp.com/oauth/token"
242242
api_url = "https://myidp.com/oauth/userinfo"`
243+
case "azuread":
244+
urls = `auth_url = "https://myidp.com/oauth/authorize"
245+
token_url = "https://myidp.com/oauth/token"`
243246
}
244247

245248
return fmt.Sprintf(`resource "grafana_sso_settings" "%[2]s_sso_settings" {
@@ -308,12 +311,31 @@ const testConfigWithInvalidCustomField = `resource "grafana_sso_settings" "sso_s
308311
var testConfigsWithValidationErrors = []string{
309312
// no token_url provided for azuread
310313
`resource "grafana_sso_settings" "azure_sso_settings" {
311-
provider_name = "azuread"
312-
oauth2_settings {
313-
client_id = "client_id"
314-
auth_url = "https://login.microsoftonline.com/12345/oauth2/v2.0/authorize"
315-
}
316-
}`,
314+
provider_name = "azuread"
315+
oauth2_settings {
316+
client_id = "client_id"
317+
auth_url = "https://login.microsoftonline.com/12345/oauth2/v2.0/authorize"
318+
}
319+
}`,
320+
// api_url is not empty for azuread
321+
`resource "grafana_sso_settings" "azure_sso_settings" {
322+
provider_name = "azuread"
323+
oauth2_settings {
324+
client_id = "client_id"
325+
auth_url = "https://login.microsoftonline.com/12345/oauth2/v2.0/authorize"
326+
token_url = "https://login.microsoftonline.com/12345/oauth2/v2.0/token"
327+
api_url = "https://login.microsoftonline.com/12345/oauth2/v2.0/user"
328+
}
329+
}`,
330+
// token_url is not a valid url for azuread
331+
`resource "grafana_sso_settings" "azure_sso_settings" {
332+
provider_name = "azuread"
333+
oauth2_settings {
334+
client_id = "client_id"
335+
auth_url = "https://login.microsoftonline.com/12345/oauth2/v2.0/authorize"
336+
token_url = "this-is-an-invalid-url"
337+
}
338+
}`,
317339
// invalid auth_url provided for okta
318340
`resource "grafana_sso_settings" "okta_sso_settings" {
319341
provider_name = "okta"

0 commit comments

Comments
 (0)