Skip to content

Commit 59c82ca

Browse files
authored
SSO: Fix and improve SAML validations (#1542)
* fix and improve SAML validations * fix indentation
1 parent 4111273 commit 59c82ca

File tree

2 files changed

+56
-27
lines changed

2 files changed

+56
-27
lines changed

internal/resources/grafana/resource_sso_settings.go

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -536,11 +536,11 @@ func UpdateSSOSettings(ctx context.Context, d *schema.ResourceData, meta interfa
536536
}
537537

538538
settings = mergeCustomFields(settings)
539+
}
539540

540-
err = validateOAuth2Settings(provider, settings)
541-
if err != nil {
542-
return diag.FromErr(err)
543-
}
541+
err = validateSSOSettings(provider, settings)
542+
if err != nil {
543+
return diag.FromErr(err)
544544
}
545545

546546
ssoSettings := models.UpdateProviderSettingsParamsBody{
@@ -681,9 +681,15 @@ var validationsByProvider = map[string][]validateFunc{
681681
ssoValidateEmpty("token_url"),
682682
ssoValidateEmpty("api_url"),
683683
},
684+
"saml": {
685+
ssoValidateOnlyOneOf("certificate", "certificate_path"),
686+
ssoValidateOnlyOneOf("private_key", "private_key_path"),
687+
ssoValidateOnlyOneOf("idp_metadata", "idp_metadata_path", "idp_metadata_url"),
688+
ssoValidateURL("idp_metadata_url"),
689+
},
684690
}
685691

686-
func validateOAuth2Settings(provider string, settings map[string]any) error {
692+
func validateSSOSettings(provider string, settings map[string]any) error {
687693
validators := validationsByProvider[provider]
688694
for _, validateF := range validators {
689695
err := validateF(settings, provider)
@@ -823,9 +829,27 @@ func ssoValidateEmpty(key string) validateFunc {
823829

824830
func ssoValidateURL(key string) validateFunc {
825831
return func(settingsMap map[string]any, provider string) error {
826-
if !isValidURL(settingsMap[key].(string)) {
832+
if settingsMap[key].(string) != "" && !isValidURL(settingsMap[key].(string)) {
827833
return fmt.Errorf("%s must be a valid http/https URL for the provider %s", key, provider)
828834
}
829835
return nil
830836
}
831837
}
838+
839+
func ssoValidateOnlyOneOf(keys ...string) validateFunc {
840+
return func(settingsMap map[string]any, provider string) error {
841+
configuredKeys := 0
842+
843+
for _, key := range keys {
844+
if settingsMap[key].(string) != "" {
845+
configuredKeys++
846+
}
847+
}
848+
849+
if configuredKeys != 1 {
850+
return fmt.Errorf("exactly one of %v must be configured for provider %s", keys, provider)
851+
}
852+
853+
return nil
854+
}
855+
}

internal/resources/grafana/resource_sso_settings_test.go

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -82,23 +82,13 @@ func TestSSOSettings_basic_saml(t *testing.T) {
8282
CheckDestroy: checkSsoSettingsReset(api, provider, defaultSettings.Payload),
8383
Steps: []resource.TestStep{
8484
{
85-
Config: testConfigForSamlProvider("new"),
85+
Config: testConfigForSamlProvider,
8686
Check: resource.ComposeTestCheckFunc(
8787
resource.TestCheckResourceAttr(resourceName, "provider_name", provider),
8888
resource.TestCheckResourceAttr(resourceName, "saml_settings.#", "1"),
89-
resource.TestCheckResourceAttr(resourceName, "saml_settings.0.certificate_path", "/var/certificate_new"),
90-
resource.TestCheckResourceAttr(resourceName, "saml_settings.0.private_key_path", "/var/private_key_new"),
91-
resource.TestCheckResourceAttr(resourceName, "saml_settings.0.idp_metadata_path", "/var/idp_metadata_new"),
92-
),
93-
},
94-
{
95-
Config: testConfigForSamlProvider("updated"),
96-
Check: resource.ComposeTestCheckFunc(
97-
resource.TestCheckResourceAttr(resourceName, "provider_name", provider),
98-
resource.TestCheckResourceAttr(resourceName, "saml_settings.#", "1"),
99-
resource.TestCheckResourceAttr(resourceName, "saml_settings.0.certificate_path", "/var/certificate_updated"),
100-
resource.TestCheckResourceAttr(resourceName, "saml_settings.0.private_key_path", "/var/private_key_updated"),
101-
resource.TestCheckResourceAttr(resourceName, "saml_settings.0.idp_metadata_path", "/var/idp_metadata_updated"),
89+
resource.TestCheckResourceAttr(resourceName, "saml_settings.0.certificate_path", "devenv/docker/blocks/auth/saml-enterprise/cert.crt"),
90+
resource.TestCheckResourceAttr(resourceName, "saml_settings.0.private_key_path", "devenv/docker/blocks/auth/saml-enterprise/key.pem"),
91+
resource.TestCheckResourceAttr(resourceName, "saml_settings.0.idp_metadata_url", "https://nexus.microsoftonline-p.com/federationmetadata/saml20/federationmetadata.xml"),
10292
),
10393
},
10494
{
@@ -305,16 +295,15 @@ func testConfigForOAuth2Provider(provider string, prefix string) string {
305295
}`, prefix, provider, urls)
306296
}
307297

308-
func testConfigForSamlProvider(prefix string) string {
309-
return fmt.Sprintf(`resource "grafana_sso_settings" "saml_sso_settings" {
298+
// the SAML configuration needs a valid certificate, private_key and idp_metadata to be accepted by Grafana API
299+
const testConfigForSamlProvider = `resource "grafana_sso_settings" "saml_sso_settings" {
310300
provider_name = "saml"
311301
saml_settings {
312-
certificate_path = "/var/certificate_%[1]s"
313-
private_key_path = "/var/private_key_%[1]s"
314-
idp_metadata_path = "/var/idp_metadata_%[1]s"
302+
certificate_path = "devenv/docker/blocks/auth/saml-enterprise/cert.crt"
303+
private_key_path = "devenv/docker/blocks/auth/saml-enterprise/key.pem"
304+
idp_metadata_url = "https://nexus.microsoftonline-p.com/federationmetadata/saml20/federationmetadata.xml"
315305
}
316-
}`, prefix)
317-
}
306+
}`
318307

319308
const testConfigWithCustomFields = `resource "grafana_sso_settings" "sso_settings" {
320309
provider_name = "github"
@@ -453,5 +442,21 @@ var testConfigsWithValidationErrors = []string{
453442
client_id = "client_id"
454443
api_url = "https://login.microsoftonline.com/12345/oauth2/v2.0/userinfo"
455444
}
445+
}`,
446+
// certificate and certificate_path are both configured for saml
447+
`resource "grafana_sso_settings" "saml_sso_settings" {
448+
provider_name = "saml"
449+
saml_settings {
450+
certificate = "this-is-a-valid-certificate"
451+
certificate_path = "/valid/certificate/path"
452+
}
453+
}`,
454+
// missing idp_metadata for saml
455+
`resource "grafana_sso_settings" "saml_sso_settings" {
456+
provider_name = "saml"
457+
saml_settings {
458+
certificate = "this-is-a-valid-certificate"
459+
private_key = "this-is-a-valid-private-key"
460+
}
456461
}`,
457462
}

0 commit comments

Comments
 (0)