diff --git a/examples/okta_app_saml_app_settings/README.md b/examples/okta_app_saml_app_settings/README.md new file mode 100644 index 000000000..92aeea8b8 --- /dev/null +++ b/examples/okta_app_saml_app_settings/README.md @@ -0,0 +1,5 @@ +# okta_app_saml_app_settings + +This resource represents App Settings of an Okta SAML Application. For more information see the [API docs](https://developer.okta.com/docs/api/resources/apps#add-custom-saml-application) + +- Example [can be found here](./preconfigured.tf) diff --git a/examples/okta_app_saml_app_settings/preconfigured.tf b/examples/okta_app_saml_app_settings/preconfigured.tf new file mode 100644 index 000000000..f8cf08221 --- /dev/null +++ b/examples/okta_app_saml_app_settings/preconfigured.tf @@ -0,0 +1,21 @@ +resource "okta_app_saml" "test" { + preconfigured_app = "amazon_aws" + label = "testAcc_replace_with_uuid" + status = "ACTIVE" +} + +resource "okta_app_saml_app_settings" "test" { + app_id = okta_app_saml.test.id + settings = jsonencode( + { + "appFilter" : "okta", + "awsEnvironmentType" : "aws.amazon", + "groupFilter" : "aws_(?{{accountid}}\\\\d+)_(?{{role}}[a-zA-Z0-9+=,.@\\\\-_]+)", + "joinAllRoles" : false, + "loginURL" : "https://console.aws.amazon.com/ec2/home", + "roleValuePattern" : "arn:aws:iam::$${accountid}:saml-provider/OKTA,arn:aws:iam::$${accountid}:role/$${role}", + "sessionDuration" : 7600, + "useGroupMapping" : false + } + ) +} diff --git a/examples/okta_app_saml_app_settings/preconfigured_updated.tf b/examples/okta_app_saml_app_settings/preconfigured_updated.tf new file mode 100644 index 000000000..87e6eaa85 --- /dev/null +++ b/examples/okta_app_saml_app_settings/preconfigured_updated.tf @@ -0,0 +1,21 @@ +resource "okta_app_saml" "test" { + preconfigured_app = "amazon_aws" + label = "testAcc_replace_with_uuid" + status = "ACTIVE" +} + +resource "okta_app_saml_app_settings" "test" { + app_id = okta_app_saml.test.id + settings = jsonencode( + { + "appFilter" : "okta", + "awsEnvironmentType" : "aws.amazon", + "groupFilter" : "aws_(?{{accountid}}\\\\d+)_(?{{role}}[a-zA-Z0-9+=,.@\\\\-_]+)", + "joinAllRoles" : false, + "loginURL" : "https://console.aws.amazon.com/ec2/home", + "roleValuePattern" : "arn:aws:iam::$${accountid}:saml-provider/OKTA,arn:aws:iam::$${accountid}:role/$${role}", + "sessionDuration" : 3200, + "useGroupMapping" : false + } + ) +} diff --git a/okta/app.go b/okta/app.go index 6e72566e3..ffa57c664 100644 --- a/okta/app.go +++ b/okta/app.go @@ -315,7 +315,7 @@ func buildAppSettings(d *schema.ResourceData) *okta.ApplicationSettingsApplicati if appSettings, ok := d.GetOk("app_settings_json"); ok { payload := map[string]interface{}{} _ = json.Unmarshal([]byte(appSettings.(string)), &payload) - settings = okta.ApplicationSettingsApplication(payload) + settings = payload } return &settings } diff --git a/okta/provider.go b/okta/provider.go index ea5d36e4f..ced9b5414 100644 --- a/okta/provider.go +++ b/okta/provider.go @@ -26,6 +26,7 @@ const ( appOAuthAPIScope = "okta_app_oauth_api_scope" appOAuthRedirectURI = "okta_app_oauth_redirect_uri" appSaml = "okta_app_saml" + appSamlAppSettings = "okta_app_saml_app_settings" appSecurePasswordStore = "okta_app_secure_password_store" appSwa = "okta_app_swa" appSharedCredentials = "okta_app_shared_credentials" @@ -199,6 +200,7 @@ func Provider() *schema.Provider { appOAuthAPIScope: resourceAppOAuthAPIScope(), appOAuthRedirectURI: resourceAppOAuthRedirectURI(), appSaml: resourceAppSaml(), + appSamlAppSettings: resourceAppSamlAppSettings(), appSecurePasswordStore: resourceAppSecurePasswordStore(), appSwa: resourceAppSwa(), appSharedCredentials: resourceAppSharedCredentials(), diff --git a/okta/provider_sweeper_test.go b/okta/provider_sweeper_test.go index 8b6c86323..46046aaba 100644 --- a/okta/provider_sweeper_test.go +++ b/okta/provider_sweeper_test.go @@ -40,6 +40,7 @@ func TestMain(m *testing.M) { setupSweeper(networkZone, sweepNetworkZones) setupSweeper(inlineHook, sweepInlineHooks) setupSweeper(userType, sweepUserTypes) + setupSweeper(behavior, sweepBehaviors) // add zones sweeper resource.TestMain(m) diff --git a/okta/resource_okta_app_saml_app_settings.go b/okta/resource_okta_app_saml_app_settings.go new file mode 100644 index 000000000..36c1647b9 --- /dev/null +++ b/okta/resource_okta_app_saml_app_settings.go @@ -0,0 +1,105 @@ +package okta + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +func resourceAppSamlAppSettings() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceAppSamlSettingsCreate, + ReadContext: resourceAppSamlSettingsRead, + UpdateContext: resourceAppSamlSettingsUpdate, + DeleteContext: resourceAppSamlSettingsDelete, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + Schema: map[string]*schema.Schema{ + "app_id": { + Type: schema.TypeString, + Required: true, + Description: "Application ID", + ForceNew: true, + }, + "settings": { + Type: schema.TypeString, + Required: true, + Description: "Application settings in JSON format", + ValidateDiagFunc: stringIsJSON, + StateFunc: normalizeDataJSON, + }, + }, + } +} + +func resourceAppSamlSettingsCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + id, err := updateOrCreateAppSettings(ctx, d, m) + if err != nil { + return diag.FromErr(err) + } + d.SetId(id) + return resourceAppSamlSettingsRead(ctx, d, m) +} + +func resourceAppSamlSettingsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + app := okta.NewSamlApplication() + err := fetchApp(ctx, d, m, app) + if err != nil { + return diag.Errorf("failed to get SAML application: %v", err) + } + if app.Id == "" { + d.SetId("") + return nil + } + flatMap := map[string]interface{}{} + for key, val := range *app.Settings.App { + if str, ok := val.(string); ok { + if str != "" { + flatMap[key] = str + } + } else if val != nil { + flatMap[key] = val + } + } + payload, _ := json.Marshal(flatMap) + _ = d.Set("settings", string(payload)) + _ = d.Set("app_id", app.Id) + return nil +} + +func resourceAppSamlSettingsUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + _, err := updateOrCreateAppSettings(ctx, d, m) + if err != nil { + return diag.FromErr(err) + } + return resourceAppSamlSettingsRead(ctx, d, m) +} + +func updateOrCreateAppSettings(ctx context.Context, d *schema.ResourceData, m interface{}) (string, error) { + app := okta.NewSamlApplication() + appID := d.Get("app_id").(string) + err := fetchAppByID(ctx, appID, m, app) + if err != nil { + return "", fmt.Errorf("failed to get SAML application: %v", err) + } + if app.Id == "" { + return "", fmt.Errorf("application with id %s does not exist", appID) + } + settings := make(okta.ApplicationSettingsApplication) + _ = json.Unmarshal([]byte(d.Get("settings").(string)), &settings) + app.Settings.App = &settings + _, _, err = getOktaClientFromMetadata(m).Application.UpdateApplication(ctx, appID, app) + if err != nil { + return "", fmt.Errorf("failed to update SAML application's settings: %v", err) + } + return app.Id, nil +} + +func resourceAppSamlSettingsDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + return nil +} diff --git a/okta/resource_okta_app_saml_app_settings_test.go b/okta/resource_okta_app_saml_app_settings_test.go new file mode 100644 index 000000000..e3b278a9c --- /dev/null +++ b/okta/resource_okta_app_saml_app_settings_test.go @@ -0,0 +1,73 @@ +package okta + +import ( + "context" + "encoding/json" + "fmt" + "reflect" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/okta/okta-sdk-golang/v2/okta" +) + +func TestAccAppSamlAppSettings_crud(t *testing.T) { + ri := acctest.RandInt() + mgr := newFixtureManager(appSamlAppSettings) + preconfigured := mgr.GetFixtures("preconfigured.tf", ri, t) + updated := mgr.GetFixtures("preconfigured_updated.tf", ri, t) + resourceName := fmt.Sprintf("%s.test", appSamlAppSettings) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: testAccProvidersFactories, + CheckDestroy: createCheckResourceDestroy(appSaml, createDoesAppExist(okta.NewSamlApplication())), + Steps: []resource.TestStep{ + { + Config: preconfigured, + Check: resource.ComposeTestCheckFunc( + checkAppSamlAppSettingsExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "settings", "{\"appFilter\":\"okta\",\"awsEnvironmentType\":\"aws.amazon\",\"groupFilter\":\"aws_(?{{accountid}}\\\\\\\\d+)_(?{{role}}[a-zA-Z0-9+=,.@\\\\\\\\-_]+)\",\"joinAllRoles\":false,\"loginURL\":\"https://console.aws.amazon.com/ec2/home\",\"roleValuePattern\":\"arn:aws:iam::${accountid}:saml-provider/OKTA,arn:aws:iam::${accountid}:role/${role}\",\"sessionDuration\":7600,\"useGroupMapping\":false}"), + ), + }, + { + Config: updated, + Check: resource.ComposeTestCheckFunc( + checkAppSamlAppSettingsExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "settings", "{\"appFilter\":\"okta\",\"awsEnvironmentType\":\"aws.amazon\",\"groupFilter\":\"aws_(?{{accountid}}\\\\\\\\d+)_(?{{role}}[a-zA-Z0-9+=,.@\\\\\\\\-_]+)\",\"joinAllRoles\":false,\"loginURL\":\"https://console.aws.amazon.com/ec2/home\",\"roleValuePattern\":\"arn:aws:iam::${accountid}:saml-provider/OKTA,arn:aws:iam::${accountid}:role/${role}\",\"sessionDuration\":3200,\"useGroupMapping\":false}"), + ), + }, + }, + }) +} + +func checkAppSamlAppSettingsExists(name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + missingErr := fmt.Errorf("resource not found: %s", name) + rs, ok := s.RootModule().Resources[name] + if !ok { + return missingErr + } + appID := rs.Primary.Attributes["app_id"] + client := getOktaClientFromMetadata(testAccProvider.Meta()) + app := okta.NewSamlApplication() + _, _, err := client.Application.GetApplication(context.Background(), appID, app, nil) + if err != nil { + return err + } + settings := make(okta.ApplicationSettingsApplication) + _ = json.Unmarshal([]byte(rs.Primary.Attributes["settings"]), &settings) + for k, v := range *app.Settings.App { + if v == nil { + delete(*app.Settings.App, k) + } + } + e := reflect.DeepEqual(*app.Settings.App, settings) + if !e { + return fmt.Errorf("settings are not equal: actual: %+v , expected: %+v", *app.Settings.App, settings) + } + return nil + } +} diff --git a/okta/resource_okta_behavior_test.go b/okta/resource_okta_behavior_test.go index 574400f88..7088fc6f0 100644 --- a/okta/resource_okta_behavior_test.go +++ b/okta/resource_okta_behavior_test.go @@ -7,8 +7,23 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/okta/okta-sdk-golang/v2/okta/query" ) +func sweepBehaviors(client *testClient) error { + var errorList []error + behaviors, _, err := client.apiSupplement.ListBehaviors(context.Background(), &query.Params{Q: testResourcePrefix}) + if err != nil { + return err + } + for _, b := range behaviors { + if _, err := client.apiSupplement.DeleteBehavior(context.Background(), b.ID); err != nil { + errorList = append(errorList, err) + } + } + return condenseError(errorList) +} + func TestAccOktaBehavior(t *testing.T) { ri := acctest.RandInt() mgr := newFixtureManager(behavior) diff --git a/okta/resource_okta_group_rule_test.go b/okta/resource_okta_group_rule_test.go index 155b8a3f0..98fe47251 100644 --- a/okta/resource_okta_group_rule_test.go +++ b/okta/resource_okta_group_rule_test.go @@ -14,7 +14,7 @@ import ( func sweepGroupRules(client *testClient) error { var errorList []error // Should never need to deal with pagination - rules, _, err := client.oktaClient.Group.ListGroupRules(context.Background(), &query.Params{Limit: 300}) + rules, _, err := client.oktaClient.Group.ListGroupRules(context.Background(), &query.Params{Limit: defaultPaginationLimit}) if err != nil { return err } diff --git a/website/docs/r/app_auto_login.html.markdown b/website/docs/r/app_auto_login.html.markdown index d4fe5862b..afda38398 100644 --- a/website/docs/r/app_auto_login.html.markdown +++ b/website/docs/r/app_auto_login.html.markdown @@ -8,8 +8,6 @@ description: |- # okta_app_auto_login -Creates an Auto Login Okta Application. - This resource allows you to create and configure an Auto Login Okta Application. ## Example Usage diff --git a/website/docs/r/app_basic_auth.html.markdown b/website/docs/r/app_basic_auth.html.markdown index 25d85ed27..610b7e538 100644 --- a/website/docs/r/app_basic_auth.html.markdown +++ b/website/docs/r/app_basic_auth.html.markdown @@ -8,8 +8,6 @@ description: |- # okta_app_basic_auth -Creates a Basic Auth Application. - This resource allows you to create and configure a Basic Auth Application. ## Example Usage diff --git a/website/docs/r/app_bookmark.html.markdown b/website/docs/r/app_bookmark.html.markdown index 87810426e..69f584cd3 100644 --- a/website/docs/r/app_bookmark.html.markdown +++ b/website/docs/r/app_bookmark.html.markdown @@ -8,8 +8,6 @@ description: |- # okta_app_bookmark -Creates a Bookmark Application. - This resource allows you to create and configure a Bookmark Application. ## Example Usage diff --git a/website/docs/r/app_oauth.html.markdown b/website/docs/r/app_oauth.html.markdown index ea3bb338b..06d26a89d 100644 --- a/website/docs/r/app_oauth.html.markdown +++ b/website/docs/r/app_oauth.html.markdown @@ -8,8 +8,6 @@ description: |- # okta_app_oauth -Creates an OIDC Application. - This resource allows you to create and configure an OIDC Application. ## Example Usage diff --git a/website/docs/r/app_saml.html.markdown b/website/docs/r/app_saml.html.markdown index 5ebe12b8c..02caf712a 100644 --- a/website/docs/r/app_saml.html.markdown +++ b/website/docs/r/app_saml.html.markdown @@ -3,14 +3,12 @@ layout: 'okta' page_title: 'Okta: okta_app_saml' sidebar_current: 'docs-okta-resource-app-saml' description: |- - Creates an SAML Application. + Creates a SAML Application. --- # okta_app_saml -Creates an SAML Application. - -This resource allows you to create and configure an SAML Application. +This resource allows you to create and configure a SAML Application. ## Example Usage diff --git a/website/docs/r/app_saml_app_settings.html.markdown b/website/docs/r/app_saml_app_settings.html.markdown new file mode 100644 index 000000000..40b765fe5 --- /dev/null +++ b/website/docs/r/app_saml_app_settings.html.markdown @@ -0,0 +1,54 @@ +--- +layout: 'okta' +page_title: 'Okta: okta_app_saml_app_settings' +sidebar_current: 'docs-okta-resource-app-saml-app-settings' +description: |- + Manages app settings of the SAML application. +--- + +# okta_app_saml_app_settings + +This resource allows you to manage app settings of the SAML Application . It's basically the same as +`app_settings_json` field in `okta_app_saml` resource and can be used in cases where settings require to be managed separately. + +## Example Usage + +```hcl +resource "okta_app_saml" "test" { + preconfigured_app = "amazon_aws" + label = "Amazon AWS" + status = "ACTIVE" +} + +resource "okta_app_saml_app_settings" "test" { + app_id = okta_app_saml.test.id + settings = jsonencode( + { + "appFilter" : "okta", + "awsEnvironmentType" : "aws.amazon", + "groupFilter" : "aws_(?{{accountid}}\\\\d+)_(?{{role}}[a-zA-Z0-9+=,.@\\\\-_]+)", + "joinAllRoles" : false, + "loginURL" : "https://console.aws.amazon.com/ec2/home", + "roleValuePattern" : "arn:aws:iam::$${accountid}:saml-provider/OKTA,arn:aws:iam::$${accountid}:role/$${role}", + "sessionDuration" : 3200, + "useGroupMapping" : false + } + ) +} +``` + +## Argument Reference + +The following arguments are supported: + +- `app_id` - (Required) ID of the application. + +- `settings` - (Required) Application settings in JSON format. + +## Import + +A settings for the SAML App can be imported via the Okta ID. + +``` +$ terraform import okta_app_saml_app_settings.example +``` diff --git a/website/docs/r/app_secure_password_store.html.markdown b/website/docs/r/app_secure_password_store.html.markdown index 7a6176416..30ddaf108 100644 --- a/website/docs/r/app_secure_password_store.html.markdown +++ b/website/docs/r/app_secure_password_store.html.markdown @@ -8,8 +8,6 @@ description: |- # okta_app_secure_password_store -Creates a Secure Password Store Application. - This resource allows you to create and configure a Secure Password Store Application. ## Example Usage diff --git a/website/docs/r/app_shared_credentials.html.markdown b/website/docs/r/app_shared_credentials.html.markdown index 946327f20..fc8492081 100644 --- a/website/docs/r/app_shared_credentials.html.markdown +++ b/website/docs/r/app_shared_credentials.html.markdown @@ -8,8 +8,6 @@ description: |- # okta_app_shared_credentials -Creates a SWA shared credentials app. - This resource allows you to create and configure SWA shared credentials app. ## Example Usage diff --git a/website/docs/r/app_swa.html.markdown b/website/docs/r/app_swa.html.markdown index f95f99162..10e472a9a 100644 --- a/website/docs/r/app_swa.html.markdown +++ b/website/docs/r/app_swa.html.markdown @@ -3,14 +3,12 @@ layout: 'okta' page_title: 'Okta: okta_app_swa' sidebar_current: 'docs-okta-resource-app-swa' description: |- - Creates an SWA Application. + Creates a SWA Application. --- # okta_app_swa -Creates an SWA Application. - -This resource allows you to create and configure an SWA Application. +This resource allows you to create and configure a SWA Application. ## Example Usage diff --git a/website/docs/r/app_three_field.html.markdown b/website/docs/r/app_three_field.html.markdown index b08fc4364..0259d95d2 100644 --- a/website/docs/r/app_three_field.html.markdown +++ b/website/docs/r/app_three_field.html.markdown @@ -8,8 +8,6 @@ description: |- # okta_app_three_field -Creates a Three Field Application. - This resource allows you to create and configure a Three Field Application. ## Example Usage diff --git a/website/docs/r/behavior.html.markdown b/website/docs/r/behavior.html.markdown index 2900aa128..c1959e2ea 100644 --- a/website/docs/r/behavior.html.markdown +++ b/website/docs/r/behavior.html.markdown @@ -8,8 +8,6 @@ description: |- # okta_behavior -Creates different types of behavior. - This resource allows you to create and configure a behavior. ## Example Usage diff --git a/website/docs/r/domain_verification.html.markdown b/website/docs/r/domain_verification.html.markdown index 51d4a901b..5b19d31f0 100644 --- a/website/docs/r/domain_verification.html.markdown +++ b/website/docs/r/domain_verification.html.markdown @@ -9,7 +9,7 @@ description: |- # okta_domain_verification Verifies the Domain. This is replacement for the `verify` field from the `okta_domain` resource. The resource won't be -created if the domain could not be verified. The provided will make several requests to verify the domain until +created if the domain could not be verified. The provider will make several requests to verify the domain until the API returns `VERIFIED` verification status. ## Example Usage