From 7e32c213a88902de52a353014d703929c4410a96 Mon Sep 17 00:00:00 2001 From: Tujit Bora Date: Tue, 29 Oct 2024 15:38:32 +0530 Subject: [PATCH 1/2] removed common_configs & redundant code moved to resource_base Attribute common_configs removed as we introduce app custom module. Redundant code in resources schema, configure & metadata moved to resource_base. --- docs/resources/app.md | 223 +- internal/resources/app_model.go | 8 - internal/resources/app_schema.go | 2241 +++++++---------- internal/resources/resource_app.go | 335 +-- internal/resources/resource_app_test.go | 283 +-- internal/resources/resource_base.go | 103 + internal/resources/resource_consent.go | 128 +- internal/resources/resource_consent_group.go | 110 +- .../resources/resource_consent_version.go | 192 +- .../resources/resource_custom_provider.go | 347 ++- internal/resources/resource_group_type.go | 146 +- internal/resources/resource_hosted_page.go | 215 +- .../resources/resource_password_policy.go | 128 +- .../resources/resource_registration_field.go | 570 ++--- internal/resources/resource_role.go | 95 +- internal/resources/resource_scope.go | 191 +- internal/resources/resource_scope_group.go | 114 +- .../resources/resource_social_provider.go | 308 ++- internal/resources/resource_template.go | 224 +- internal/resources/resource_template_group.go | 339 ++- internal/resources/resource_template_test.go | 10 +- internal/resources/resource_user_group.go | 219 +- internal/resources/resource_webhook.go | 274 +- templates/resources/app.md.tmpl | 73 +- 24 files changed, 2981 insertions(+), 3895 deletions(-) create mode 100644 internal/resources/resource_base.go diff --git a/docs/resources/app.md b/docs/resources/app.md index 490fe94..6db1819 100644 --- a/docs/resources/app.md +++ b/docs/resources/app.md @@ -114,23 +114,60 @@ Alternatively, you can resolve the issue by deleting the existing state of the s However, this approach can be risky, so please proceed with caution. Ensure you only delete the specific resource from the state file that is causing the error, not the entire file or any other resources. -### V3 App Resource Highlights: - -- The resource app can now be set up with minimal configuration. The following parameters are the only required ones to create an app. -In the [schema](#schema) section, only client_name is shown as **required** because the other attributes can be configured in common_configs. -However, each attribute must appear either in the main configuration block or in common_configs. `client_name` cannot be part of common_configs. - - - client_name - - client_type - - company_name - - company_address - - company_website - - allowed_scopes - - redirect_uris - - allowed_logout_urls -- Attribute `common_configs` added to share same configuration across multiple apps. Pleas check the samples in **examples** directory that demonstrates the use of `common_configs`. -- If you need to override any specific attribute for a particular resource where the same attribute is available in `common_configs`, you can supply the main configuration attribute directly within the resource block. -- If your configuration involves a single resource or if the common configuration attributes are not shared across multiple resources we do not suggest using `common_configs`. +From version 3.3.0, the attribute `common_configs` is not supported anymore. Instead, we encourage you to use the custom module **terraform-cidaas-app**. +The module provides a variable with the same name `common_configs` which +supports all the attributes in the resource app except `client_name`. With this module you can avoid the repeated configuration and assign the common properties +of multiple apps to a common variable and inherit the properties. + +Link to the custom module https://github.com/Cidaas/terraform-cidaas-app + +##### Module usage: + +```hcl +// local.tfvars +common_configs = { + client_type = "SINGLE_PAGE" + company_address = "Wimsheim" + company_name = "WidasConcepts GmbH" + company_address = "Maybachstraße 2, 71299 Wimsheim, Germany" + company_website = "https://widas.com" + redirect_uris = [ + "https://cidaas.de/callback", + ] + allowed_logout_urls = [ + "https://cidaas.de/logout" + ] + allowed_scopes = [ + "openid", + ] +} + +// main.tf +provider "cidaas" { + base_url = "https://cidaas.de" +} + +module "app1" { + source = "git@github.com:Cidaas/terraform-cidaas-app.git" + + providers = { + cidaas = cidaas + } + client_name = "Demo App" + common_configs = var.common_configs +} + +module "app2" { + source = "git@github.com:Cidaas/terraform-cidaas-app.git" + providers = { + cidaas = cidaas + } + client_name = "Demo IOS App" + client_type = "IOS" + common_configs = var.common_configs +} +``` +You can explore more on the module in the github repo. ## Example Usage(V3 configuration) @@ -317,14 +354,19 @@ resource "cidaas_app" "sample" { } ``` -For more samples on common_configs, please refer to the examples folder. - ## Schema ### Required +- `allowed_logout_urls` (Set of String) Allowed logout URLs for OAuth2 client. +- `allowed_scopes` (Set of String) The URL of the company website. allowed_scopes is a required attribute. It must be provided in the main config or common_config - `client_name` (String) Name of the client. +- `client_type` (String) The type of the client. The allowed values are SINGLE_PAGE, REGULAR_WEB, NON_INTERACTIVEIOS, ANDROID, WINDOWS_MOBILE, DESKTOP, MOBILE, DEVICE and THIRD_PARTY +- `company_address` (String) The company address. +- `company_name` (String) The name of the company that the client belongs to. +- `company_website` (String) The URL of the company website. +- `redirect_uris` (Set of String) Redirect URIs for OAuth2 client. ### Optional @@ -337,11 +379,9 @@ For more samples on common_configs, please refer to the examples folder. - `allow_login_with` (Set of String) allow_login_with is used to specify the preferred methods of login allowed for a client. Allowed values are EMAIL, MOBILE and USER_NAMEThe default is set to `['EMAIL', 'MOBILE', 'USER_NAME']`. - `allowed_fields` (Set of String) - `allowed_groups` (Attributes List) (see [below for nested schema](#nestedatt--allowed_groups)) -- `allowed_logout_urls` (Set of String) Allowed logout URLs for OAuth2 client. - `allowed_mfa` (Set of String) - `allowed_origins` (Set of String) List of the origins allowed to access the client. - `allowed_roles` (Set of String) -- `allowed_scopes` (Set of String) The URL of the company website. allowed_scopes is a required attribute. It must be provided in the main config or common_config - `allowed_web_origins` (Set of String) List of the web origins allowed to access the client. - `always_ask_mfa` (Boolean) - `application_meta_data` (Map of String) A map to add metadata of a client. @@ -358,13 +398,8 @@ For more samples on common_configs, please refer to the examples folder. - `client_display_name` (String) The display name of the client. - `client_id` (String) The client_id is the unqique identifier of the app. It's an optional attribute. If not provided, cidaas will gererate one for you and the state will be updated with the same - `client_secret` (String, Sensitive) The client_id is the unqique identifier of the app. It's an optional attribute. If not provided, cidaas will gererate one for you and the state will be updated with the same -- `client_type` (String) The type of the client. The allowed values are SINGLE_PAGE, REGULAR_WEB, NON_INTERACTIVEIOS, ANDROID, WINDOWS_MOBILE, DESKTOP, MOBILE, DEVICE and THIRD_PARTY - `client_uri` (String) -- `common_configs` (Attributes) The `common_configs` attribute is used for sharing the same configuration across multiple cidaas_app resources. It is a map of some attributes from the main configuration. Please check the list of the attributes that it supports in the common_confis section. if an attribute is available both common_config and main config then attribute from the main config will be considered to create an app (see [below for nested schema](#nestedatt--common_configs)) - `communication_medium_verification` (String) -- `company_address` (String) The company address. -- `company_name` (String) The name of the company that the client belongs to. -- `company_website` (String) The URL of the company website. - `consent_page_group` (String) - `consent_refs` (Set of String) - `contacts` (Set of String) The contacts of the client. @@ -419,7 +454,6 @@ For more samples on common_configs, please refer to the examples folder. - `policy_uri` (String) The URL to the policy of a client. - `post_logout_redirect_uris` (Set of String) - `primary_color` (String) The primary color of the client. e.g., `#ef4923`. The value must be a valid hex colorThe default is set to `#f7941d`. -- `redirect_uris` (Set of String) Redirect URIs for OAuth2 client. - `refresh_token_lifetime_in_seconds` (Number) The lifetime of the refresh token in seconds. Default is 15780000 seconds. - `register_with_login_information` (Boolean) Register with login information. Default is set to `false` while creating an app. - `registration_access_token` (String) @@ -515,141 +549,6 @@ Optional: - -### Nested Schema for `common_configs` - -Optional: - -- `accent_color` (String) -- `ad_providers` (Attributes List) (see [below for nested schema](#nestedatt--common_configs--ad_providers)) -- `allow_guest_login` (Boolean) -- `allow_login_with` (Set of String) -- `allowed_groups` (Attributes List) (see [below for nested schema](#nestedatt--common_configs--allowed_groups)) -- `allowed_logout_urls` (Set of String) -- `allowed_mfa` (Set of String) -- `allowed_origins` (Set of String) -- `allowed_roles` (Set of String) -- `allowed_scopes` (Set of String) -- `allowed_web_origins` (Set of String) -- `always_ask_mfa` (Boolean) -- `auto_login_after_register` (Boolean) -- `bot_provider` (String) -- `client_type` (String) -- `company_address` (String) -- `company_name` (String) -- `company_website` (String) -- `custom_providers` (Attributes List) (see [below for nested schema](#nestedatt--common_configs--custom_providers)) -- `default_max_age` (Number) -- `default_roles` (Set of String) -- `default_scopes` (Set of String) -- `editable` (Boolean) -- `email_verification_required` (Boolean) -- `enable_classical_provider` (Boolean) -- `enable_deduplication` (Boolean) -- `enable_passwordless_auth` (Boolean) -- `enabled` (Boolean) -- `fds_enabled` (Boolean) -- `grant_types` (Set of String) -- `hosted_page_group` (String) -- `id_token_lifetime_in_seconds` (Number) -- `is_hybrid_app` (Boolean) -- `is_remember_me_selected` (Boolean) -- `login_providers` (Set of String) -- `logo_align` (String) -- `media_type` (String) -- `mfa` (Attributes) (see [below for nested schema](#nestedatt--common_configs--mfa)) -- `operations_allowed_groups` (Attributes List) (see [below for nested schema](#nestedatt--common_configs--operations_allowed_groups)) -- `pending_scopes` (Set of String) -- `primary_color` (String) -- `redirect_uris` (Set of String) -- `refresh_token_lifetime_in_seconds` (Number) -- `register_with_login_information` (Boolean) -- `response_types` (Set of String) -- `saml_providers` (Attributes List) (see [below for nested schema](#nestedatt--common_configs--saml_providers)) -- `social_providers` (Attributes List) (see [below for nested schema](#nestedatt--common_configs--social_providers)) -- `template_group_id` (String) -- `token_lifetime_in_seconds` (Number) -- `webfinger` (String) - - -### Nested Schema for `common_configs.ad_providers` - -Optional: - -- `display_name` (String) -- `domains` (Set of String) -- `is_provider_visible` (Boolean) -- `logo_url` (String) -- `provider_name` (String) -- `type` (String) - - - -### Nested Schema for `common_configs.allowed_groups` - -Optional: - -- `default_roles` (Set of String) -- `group_id` (String) -- `roles` (Set of String) - - - -### Nested Schema for `common_configs.custom_providers` - -Optional: - -- `display_name` (String) -- `domains` (Set of String) -- `is_provider_visible` (Boolean) -- `logo_url` (String) -- `provider_name` (String) -- `type` (String) - - - -### Nested Schema for `common_configs.mfa` - -Optional: - -- `allowed_methods` (Set of String) -- `setting` (String) -- `time_interval_in_seconds` (Number) - - - -### Nested Schema for `common_configs.operations_allowed_groups` - -Optional: - -- `default_roles` (Set of String) -- `group_id` (String) -- `roles` (Set of String) - - - -### Nested Schema for `common_configs.saml_providers` - -Optional: - -- `display_name` (String) -- `domains` (Set of String) -- `is_provider_visible` (Boolean) -- `logo_url` (String) -- `provider_name` (String) -- `type` (String) - - - -### Nested Schema for `common_configs.social_providers` - -Optional: - -- `provider_name` (String) -- `social_id` (String) - - - ### Nested Schema for `custom_providers` diff --git a/internal/resources/app_model.go b/internal/resources/app_model.go index 70c8148..24078a2 100644 --- a/internal/resources/app_model.go +++ b/internal/resources/app_model.go @@ -168,10 +168,6 @@ type AppConfig struct { suggestVerificationMethods *SuggestVerificationMethods groupRoleRestriction *GroupRoleRestriction basicSettings *BasicSettings - - CommonConfigs types.Object `tfsdk:"common_configs"` - - commonConfigs *CommonConfigs } type AllowedGroups struct { @@ -335,10 +331,6 @@ func (w *AppConfig) ExtractAppConfigs(ctx context.Context) diag.Diagnostics { w.mobileSettings = &AppMobileSettings{} diags = w.MobileSettings.As(ctx, w.mobileSettings, basetypes.ObjectAsOptions{}) } - if !w.CommonConfigs.IsNull() && !w.CommonConfigs.IsUnknown() { - w.commonConfigs = &CommonConfigs{} - diags = w.CommonConfigs.As(ctx, w.commonConfigs, basetypes.ObjectAsOptions{}) - } if !w.SocialProviders.IsNull() && !w.SocialProviders.IsUnknown() { w.socialProviders = make([]*SocialProviderData, 0, len(w.SocialProviders.Elements())) diags = w.SocialProviders.ElementsAs(ctx, &w.socialProviders, false) diff --git a/internal/resources/app_schema.go b/internal/resources/app_schema.go index d7772a8..e89053a 100644 --- a/internal/resources/app_schema.go +++ b/internal/resources/app_schema.go @@ -1,14 +1,12 @@ package resources import ( - "context" "regexp" "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default" @@ -24,1445 +22,1136 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) -func (r *AppResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { - resp.Schema = schema.Schema{ - MarkdownDescription: "The App resource allows creation and management of clients in Cidaas system." + - " When creating a client with a custom `client_id` and `client_secret` you can include the configuration in the resource." + - " If not provided, Cidaas will generate a set for you. `client_secret` is sensitive data." + - " Refer to the article [Terraform Sensitive Variables](https://developer.hashicorp.com/terraform/tutorials/configuration-language/sensitive-variables) to properly handle sensitive information." + - "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + - "\n- cidaas:apps_read" + - "\n- cidaas:apps_write" + - "\n- cidaas:apps_delete", - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - MarkdownDescription: "The ID of the resource.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "client_type": schema.StringAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The type of the client. The allowed values are " + - "SINGLE_PAGE, REGULAR_WEB, NON_INTERACTIVE" + - "IOS, ANDROID, WINDOWS_MOBILE, DESKTOP, MOBILE, DEVICE and THIRD_PARTY", - Validators: []validator.String{ - stringvalidator.OneOf([]string{ - "SINGLE_PAGE", "REGULAR_WEB", "NON_INTERACTIVE", - "IOS", "ANDROID", "WINDOWS_MOBILE", "DESKTOP", "MOBILE", "DEVICE", "THIRD_PARTY", - }...), - }, - }, - "accent_color": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The accent color of the client. e.g., `#f7941d`. The value must be a valid hex color" + - "The default is set to `#ef4923`.", - Validators: []validator.String{ - stringvalidator.RegexMatches( - regexp.MustCompile(`^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$`), - "accent_color must be a valid hex color", - ), - }, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "primary_color": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The primary color of the client. e.g., `#ef4923`. The value must be a valid hex color" + - "The default is set to `#f7941d`.", - Validators: []validator.String{ - stringvalidator.RegexMatches( - regexp.MustCompile(`^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$`), - "must be a valid hex color", - ), - }, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "media_type": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The media type of the client. e.g., `IMAGE`. Allowed values are VIDEO and IMAGE" + - "The default is set to `IMAGE`.", - Validators: []validator.String{ - stringvalidator.OneOf([]string{"VIDEO", "IMAGE"}...), - }, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "content_align": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The alignment of the content of the client. e.g., `CENTER`. Allowed values are CENTER, LEFT and RIGHT" + - "The default is set to `CENTER`.", - Validators: []validator.String{ - stringvalidator.OneOf([]string{"CENTER", "LEFT", "RIGHT"}...), - }, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "allow_login_with": schema.SetAttribute{ - ElementType: types.StringType, - Computed: true, - Optional: true, - MarkdownDescription: "allow_login_with is used to specify the preferred methods of login allowed for a client. Allowed values are EMAIL, MOBILE and USER_NAME" + - "The default is set to `['EMAIL', 'MOBILE', 'USER_NAME']`.", - Validators: []validator.Set{ - setvalidator.ValueStringsAre( - stringvalidator.OneOf([]string{"EMAIL", "MOBILE", "USER_NAME"}...), - ), - }, - Default: setdefault.StaticValue(basetypes.NewSetValueMust(types.StringType, []attr.Value{ - types.StringValue("EMAIL"), types.StringValue("MOBILE"), types.StringValue("USER_NAME"), - })), - }, - "redirect_uris": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - Computed: true, - MarkdownDescription: "Redirect URIs for OAuth2 client.", - }, - "allowed_logout_urls": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - Computed: true, - MarkdownDescription: "Allowed logout URLs for OAuth2 client.", - }, - "enable_deduplication": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Enable deduplication.", - Default: booldefault.StaticBool(false), - }, - "auto_login_after_register": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Automatically login after registration. Default is set to `false` while creating an app.", - Default: booldefault.StaticBool(false), - }, - "enable_passwordless_auth": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Enable passwordless authentication. Default is set to `true` while creating an app.", - Default: booldefault.StaticBool(true), - }, - "register_with_login_information": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Register with login information. Default is set to `false` while creating an app.", - Default: booldefault.StaticBool(false), - }, - "allow_disposable_email": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Allow disposable email addresses. Default is set to `false` while creating an app.", - Default: booldefault.StaticBool(false), - }, - "validate_phone_number": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "if enabled, phone number is validaed. Default is set to `false` while creating an app.", - Default: booldefault.StaticBool(false), - }, - "fds_enabled": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Flag to enable or disable fraud detection system. By default, it is enabled when a client is created", - Default: booldefault.StaticBool(true), - }, - "hosted_page_group": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "Hosted page group.", - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "client_name": schema.StringAttribute{ - Required: true, - MarkdownDescription: "Name of the client.", - }, - "client_display_name": schema.StringAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The display name of the client.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "company_name": schema.StringAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The name of the company that the client belongs to.", - }, - "company_address": schema.StringAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The company address.", - }, - "company_website": schema.StringAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The URL of the company website.", - }, - "allowed_scopes": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - Computed: true, - MarkdownDescription: "The URL of the company website. allowed_scopes is a required attribute. It must be provided in the main config or common_config", - }, - "response_types": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - Computed: true, - MarkdownDescription: "The response types of the client. The default value is set to `['code','token', 'id_token']`", - Default: setdefault.StaticValue(basetypes.NewSetValueMust(types.StringType, []attr.Value{ - types.StringValue("code"), types.StringValue("token"), types.StringValue("id_token"), - })), - }, - "grant_types": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - Computed: true, - MarkdownDescription: "The grant types of the client. The default value is set to `['implicit','authorization_code', 'password', 'refresh_token']`", - Default: setdefault.StaticValue(basetypes.NewSetValueMust(types.StringType, []attr.Value{ - types.StringValue("implicit"), types.StringValue("authorization_code"), types.StringValue("password"), types.StringValue("refresh_token"), - })), - }, - // common_config attr - "login_providers": schema.SetAttribute{ - ElementType: types.StringType, - MarkdownDescription: "With this attribute one can setup login provider to the client.", - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.Set{ - setplanmodifier.UseStateForUnknown(), - }, - }, - "additional_access_token_payload": schema.SetAttribute{ - ElementType: types.StringType, - MarkdownDescription: "Access token payload definition.", - Optional: true, - }, - "required_fields": schema.SetAttribute{ - ElementType: types.StringType, - MarkdownDescription: "The required fields while registering to the client.", - Optional: true, - }, - "is_hybrid_app": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Flag to set if your app is hybrid or not. Default is set to `false`. Set to `true` to make your app hybrid.", - Default: booldefault.StaticBool(false), - }, - // common_config attr - "allowed_web_origins": schema.SetAttribute{ - ElementType: types.StringType, - MarkdownDescription: "List of the web origins allowed to access the client.", - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.Set{ - setplanmodifier.UseStateForUnknown(), - }, +var resourceAppSchema = schema.Schema{ + MarkdownDescription: "The App resource allows creation and management of clients in Cidaas system." + + " When creating a client with a custom `client_id` and `client_secret` you can include the configuration in the resource." + + " If not provided, Cidaas will generate a set for you. `client_secret` is sensitive data." + + " Refer to the article [Terraform Sensitive Variables](https://developer.hashicorp.com/terraform/tutorials/configuration-language/sensitive-variables) to properly handle sensitive information." + + "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + + "\n- cidaas:apps_read" + + "\n- cidaas:apps_write" + + "\n- cidaas:apps_delete", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The ID of the resource.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - // common_config attr - "allowed_origins": schema.SetAttribute{ - ElementType: types.StringType, - MarkdownDescription: "List of the origins allowed to access the client.", - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.Set{ - setplanmodifier.UseStateForUnknown(), - }, + }, + "client_type": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The type of the client. The allowed values are " + + "SINGLE_PAGE, REGULAR_WEB, NON_INTERACTIVE" + + "IOS, ANDROID, WINDOWS_MOBILE, DESKTOP, MOBILE, DEVICE and THIRD_PARTY", + Validators: []validator.String{ + stringvalidator.OneOf([]string{ + "SINGLE_PAGE", "REGULAR_WEB", "NON_INTERACTIVE", + "IOS", "ANDROID", "WINDOWS_MOBILE", "DESKTOP", "MOBILE", "DEVICE", "THIRD_PARTY", + }...), }, - // cidaas faulty api, so marked this attribute as computed - "mobile_settings": schema.SingleNestedAttribute{ - Optional: true, - Computed: true, - Attributes: map[string]schema.Attribute{ - "team_id": schema.StringAttribute{ - Optional: true, - }, - "bundle_id": schema.StringAttribute{ - Optional: true, - }, - "package_name": schema.StringAttribute{ - Optional: true, - }, - "key_hash": schema.StringAttribute{ - Optional: true, - }, - }, - Default: objectdefault.StaticValue( - types.ObjectValueMust( - map[string]attr.Type{ - "team_id": types.StringType, - "bundle_id": types.StringType, - "package_name": types.StringType, - "key_hash": types.StringType, - }, - map[string]attr.Value{ - "team_id": types.StringNull(), - "bundle_id": types.StringNull(), - "package_name": types.StringNull(), - "key_hash": types.StringNull(), - }, - ), + }, + "accent_color": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The accent color of the client. e.g., `#f7941d`. The value must be a valid hex color" + + "The default is set to `#ef4923`.", + Validators: []validator.String{ + stringvalidator.RegexMatches( + regexp.MustCompile(`^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$`), + "accent_color must be a valid hex color", ), }, - "default_max_age": schema.Int64Attribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The default maximum age for the token in seconds. Default is 86400 seconds (24 hours).", - Default: int64default.StaticInt64(86400), - }, - "token_lifetime_in_seconds": schema.Int64Attribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The lifetime of the token in seconds. Default is 86400 seconds (24 hours).", - Default: int64default.StaticInt64(86400), - }, - "id_token_lifetime_in_seconds": schema.Int64Attribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The lifetime of the id_token in seconds. Default is 86400 seconds (24 hours).", - Default: int64default.StaticInt64(86400), - }, - "refresh_token_lifetime_in_seconds": schema.Int64Attribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The lifetime of the refresh token in seconds. Default is 15780000 seconds.", - Default: int64default.StaticInt64(15780000), - }, - "template_group_id": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The id of the template group to be configured for commenication. Default is set to the system default group.", - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "client_id": schema.StringAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The client_id is the unqique identifier of the app. It's an optional attribute." + - " If not provided, cidaas will gererate one for you and the state will be updated with the same", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "client_secret": schema.StringAttribute{ - Optional: true, - Computed: true, - Sensitive: true, - MarkdownDescription: "The client_id is the unqique identifier of the app. It's an optional attribute." + - " If not provided, cidaas will gererate one for you and the state will be updated with the same", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "policy_uri": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The URL to the policy of a client.", - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "tos_uri": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The URL to the TOS of a client.", - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "imprint_uri": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The URL to the imprint page.", - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "contacts": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - MarkdownDescription: "The contacts of the client.", - }, - "token_endpoint_auth_method": schema.StringAttribute{ - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "token_endpoint_auth_signing_alg": schema.StringAttribute{ - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "default_acr_values": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - }, - "editable": schema.BoolAttribute{ - Optional: true, - Computed: true, - Default: booldefault.StaticBool(true), - MarkdownDescription: "Flag to define if your client is editable or not. Default is `true`.", - }, - "web_message_uris": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - MarkdownDescription: "A list of URLs for web messages used.", - }, - "social_providers": schema.ListNestedAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "A list of social identity providers that users can authenticate with. Examples: Google, Facebook etc...", - NestedObject: schema.NestedAttributeObject{ - Attributes: map[string]schema.Attribute{ - "provider_name": schema.StringAttribute{ - Optional: true, - }, - "social_id": schema.StringAttribute{ - Optional: true, - }, - }, - }, - Default: listdefault.StaticValue(types.ListValueMust( - types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "provider_name": types.StringType, - "social_id": types.StringType, - }, - }, []attr.Value{})), - }, - "custom_providers": schema.ListNestedAttribute{ - Optional: true, - // if empty and common_config has it's value then assigned the same. so marked computed - Computed: true, - MarkdownDescription: "A list of custom identity providers that users can authenticate with. A custom provider can be created with the help of the resource cidaas_custom_provider.", - NestedObject: providerMetadDataSchema, - Default: listdefault.StaticValue(types.ListValueMust( - types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "provider_name": types.StringType, - "display_name": types.StringType, - "logo_url": types.StringType, - "type": types.StringType, - "is_provider_visible": types.BoolType, - "domains": types.SetType{ElemType: types.StringType}, - }, - }, []attr.Value{})), - }, - "saml_providers": schema.ListNestedAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "A list of SAML identity providers that users can authenticate with.", - NestedObject: providerMetadDataSchema, - Default: listdefault.StaticValue(types.ListValueMust( - types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "provider_name": types.StringType, - "display_name": types.StringType, - "logo_url": types.StringType, - "type": types.StringType, - "is_provider_visible": types.BoolType, - "domains": types.SetType{ElemType: types.StringType}, - }, - }, []attr.Value{})), - }, - "ad_providers": schema.ListNestedAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "A list of Active Directory identity providers that users can authenticate with.", - NestedObject: providerMetadDataSchema, - Default: listdefault.StaticValue(types.ListValueMust( - types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "provider_name": types.StringType, - "display_name": types.StringType, - "logo_url": types.StringType, - "type": types.StringType, - "is_provider_visible": types.BoolType, - "domains": types.SetType{ElemType: types.StringType}, - }, - }, []attr.Value{})), - }, - "jwe_enabled": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Flag to specify whether JSON Web Encryption (JWE) should be enabled for encrypting data.", - Default: booldefault.StaticBool(false), - }, - "user_consent": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Specifies whether user consent is required or not. Default is `false`", - Default: booldefault.StaticBool(false), - }, - "allowed_groups": schema.ListNestedAttribute{ - Optional: true, - Computed: true, - NestedObject: allowedGroupsSchema, - Default: listdefault.StaticValue(types.ListValueMust( - types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "group_id": types.StringType, - "roles": types.SetType{ElemType: types.StringType}, - "default_roles": types.SetType{ElemType: types.StringType}, - }, - }, []attr.Value{})), - }, - "operations_allowed_groups": schema.ListNestedAttribute{ - Optional: true, - Computed: true, - NestedObject: allowedGroupsSchema, - Default: listdefault.StaticValue(types.ListValueMust( - types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "group_id": types.StringType, - "roles": types.SetType{ElemType: types.StringType}, - "default_roles": types.SetType{ElemType: types.StringType}, - }, - }, []attr.Value{})), - }, - "enabled": schema.BoolAttribute{ - Optional: true, - Computed: true, - Default: booldefault.StaticBool(true), - }, - "allowed_fields": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - }, - "always_ask_mfa": schema.BoolAttribute{ - Optional: true, - Computed: true, - Default: booldefault.StaticBool(false), - }, - "smart_mfa": schema.BoolAttribute{ - Optional: true, - Computed: true, - Default: booldefault.StaticBool(false), - }, - // common_config attr - "allowed_mfa": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.Set{ - setplanmodifier.UseStateForUnknown(), - }, - }, - "captcha_ref": schema.StringAttribute{ - Optional: true, - }, - "captcha_refs": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "consent_refs": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - }, - "communication_medium_verification": schema.StringAttribute{ - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "email_verification_required": schema.BoolAttribute{ - Optional: true, - Computed: true, - Default: booldefault.StaticBool(true), - }, - "mobile_number_verification_required": schema.BoolAttribute{ - Optional: true, - Computed: true, - Default: booldefault.StaticBool(false), - }, - // common_config attr - "allowed_roles": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.Set{ - setplanmodifier.UseStateForUnknown(), - }, - }, - // common_config attr - "default_roles": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.Set{ - setplanmodifier.UseStateForUnknown(), - }, - }, - "enable_classical_provider": schema.BoolAttribute{ - Optional: true, - Computed: true, - Default: booldefault.StaticBool(true), - }, - "is_remember_me_selected": schema.BoolAttribute{ - Optional: true, - Computed: true, - Default: booldefault.StaticBool(true), - }, - "enable_bot_detection": schema.BoolAttribute{ - Optional: true, - Computed: true, - Default: booldefault.StaticBool(false), - }, - "bot_provider": schema.StringAttribute{ - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "allow_guest_login_groups": schema.ListNestedAttribute{ - Optional: true, - Computed: true, - NestedObject: allowedGroupsSchema, - Default: listdefault.StaticValue(types.ListValueMust( - types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "group_id": types.StringType, - "roles": types.SetType{ElemType: types.StringType}, - "default_roles": types.SetType{ElemType: types.StringType}, - }, - }, []attr.Value{})), - }, - "is_login_success_page_enabled": schema.BoolAttribute{ - Optional: true, - Computed: true, - Default: booldefault.StaticBool(false), - }, - "is_register_success_page_enabled": schema.BoolAttribute{ - Optional: true, - Computed: true, - Default: booldefault.StaticBool(false), - }, - "group_ids": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - }, - "is_group_login_selection_enabled": schema.BoolAttribute{ - Optional: true, - Computed: true, - Default: booldefault.StaticBool(false), - }, - "group_selection": schema.SingleNestedAttribute{ - Optional: true, - // cidaas faulty api, so marked this attribute as computed - Computed: true, - Attributes: map[string]schema.Attribute{ - "always_show_group_selection": schema.BoolAttribute{ - Optional: true, - }, - "selectable_groups": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - }, - "selectable_group_types": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - }, - }, - Default: objectdefault.StaticValue( - types.ObjectValueMust( - map[string]attr.Type{ - "always_show_group_selection": types.BoolType, - "selectable_groups": types.SetType{ElemType: types.StringType}, - "selectable_group_types": types.SetType{ElemType: types.StringType}, - }, - map[string]attr.Value{ - "always_show_group_selection": types.BoolNull(), - "selectable_groups": types.SetNull(types.StringType), - "selectable_group_types": types.SetNull(types.StringType), - }, - ), + }, + "primary_color": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The primary color of the client. e.g., `#ef4923`. The value must be a valid hex color" + + "The default is set to `#f7941d`.", + Validators: []validator.String{ + stringvalidator.RegexMatches( + regexp.MustCompile(`^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$`), + "must be a valid hex color", ), }, - "group_types": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - }, - "backchannel_logout_uri": schema.StringAttribute{ - Optional: true, - }, - "post_logout_redirect_uris": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - }, - "logo_align": schema.StringAttribute{ - Optional: true, - Validators: []validator.String{ - stringvalidator.OneOf([]string{"CENTER", "LEFT", "RIGHT"}...), - }, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "mfa": schema.SingleNestedAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Configuration settings for Multi-Factor Authentication (MFA).", - Attributes: map[string]schema.Attribute{ - "setting": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "Specifies the Multi-Factor Authentication (MFA) setting. Allowed values are 'OFF', 'ALWAYS', 'SMART', 'TIME_BASED' and 'SMART_PLUS_TIME_BASED'.", - Validators: []validator.String{ - stringvalidator.OneOf([]string{"OFF", "ALWAYS", "SMART", "TIME_BASED", "SMART_PLUS_TIME_BASED"}...), - }, - }, - "time_interval_in_seconds": schema.Int64Attribute{ - Optional: true, - MarkdownDescription: "Optional time interval in seconds for time-based Multi-Factor Authentication.", - }, - "allowed_methods": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - MarkdownDescription: "Optional set of allowed MFA methods.", - }, - }, - PlanModifiers: []planmodifier.Object{ - objectplanmodifier.UseStateForUnknown(), - }, - }, - "webfinger": schema.StringAttribute{ - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "logo_uri": schema.StringAttribute{ - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "initiate_login_uri": schema.StringAttribute{ - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "registration_client_uri": schema.StringAttribute{ - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "registration_access_token": schema.StringAttribute{ - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "client_uri": schema.StringAttribute{ - Optional: true, - }, - "jwks_uri": schema.StringAttribute{ - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "jwks": schema.StringAttribute{ - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + }, + "media_type": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The media type of the client. e.g., `IMAGE`. Allowed values are VIDEO and IMAGE" + + "The default is set to `IMAGE`.", + Validators: []validator.String{ + stringvalidator.OneOf([]string{"VIDEO", "IMAGE"}...), }, - "sector_identifier_uri": schema.StringAttribute{ - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "subject_type": schema.StringAttribute{ - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + }, + "content_align": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The alignment of the content of the client. e.g., `CENTER`. Allowed values are CENTER, LEFT and RIGHT" + + "The default is set to `CENTER`.", + Validators: []validator.String{ + stringvalidator.OneOf([]string{"CENTER", "LEFT", "RIGHT"}...), }, - "id_token_signed_response_alg": schema.StringAttribute{ - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "id_token_encrypted_response_alg": schema.StringAttribute{ - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + }, + "allow_login_with": schema.SetAttribute{ + ElementType: types.StringType, + Computed: true, + Optional: true, + MarkdownDescription: "allow_login_with is used to specify the preferred methods of login allowed for a client. Allowed values are EMAIL, MOBILE and USER_NAME" + + "The default is set to `['EMAIL', 'MOBILE', 'USER_NAME']`.", + Validators: []validator.Set{ + setvalidator.ValueStringsAre( + stringvalidator.OneOf([]string{"EMAIL", "MOBILE", "USER_NAME"}...), + ), }, - "id_token_encrypted_response_enc": schema.StringAttribute{ - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + Default: setdefault.StaticValue(basetypes.NewSetValueMust(types.StringType, []attr.Value{ + types.StringValue("EMAIL"), types.StringValue("MOBILE"), types.StringValue("USER_NAME"), + })), + }, + "redirect_uris": schema.SetAttribute{ + ElementType: types.StringType, + Required: true, + MarkdownDescription: "Redirect URIs for OAuth2 client.", + }, + "allowed_logout_urls": schema.SetAttribute{ + ElementType: types.StringType, + Required: true, + MarkdownDescription: "Allowed logout URLs for OAuth2 client.", + }, + "enable_deduplication": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Enable deduplication.", + Default: booldefault.StaticBool(false), + }, + "auto_login_after_register": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Automatically login after registration. Default is set to `false` while creating an app.", + Default: booldefault.StaticBool(false), + }, + "enable_passwordless_auth": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Enable passwordless authentication. Default is set to `true` while creating an app.", + Default: booldefault.StaticBool(true), + }, + "register_with_login_information": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Register with login information. Default is set to `false` while creating an app.", + Default: booldefault.StaticBool(false), + }, + "allow_disposable_email": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Allow disposable email addresses. Default is set to `false` while creating an app.", + Default: booldefault.StaticBool(false), + }, + "validate_phone_number": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "if enabled, phone number is validaed. Default is set to `false` while creating an app.", + Default: booldefault.StaticBool(false), + }, + "fds_enabled": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Flag to enable or disable fraud detection system. By default, it is enabled when a client is created", + Default: booldefault.StaticBool(true), + }, + "hosted_page_group": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Hosted page group.", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "userinfo_signed_response_alg": schema.StringAttribute{ - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + }, + "client_name": schema.StringAttribute{ + Required: true, + MarkdownDescription: "Name of the client.", + }, + "client_display_name": schema.StringAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The display name of the client.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "userinfo_encrypted_response_alg": schema.StringAttribute{ - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + }, + "company_name": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The name of the company that the client belongs to.", + }, + "company_address": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The company address.", + }, + "company_website": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The URL of the company website.", + }, + "allowed_scopes": schema.SetAttribute{ + ElementType: types.StringType, + Required: true, + MarkdownDescription: "The URL of the company website. allowed_scopes is a required attribute. It must be provided in the main config or common_config", + }, + "response_types": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + MarkdownDescription: "The response types of the client. The default value is set to `['code','token', 'id_token']`", + Default: setdefault.StaticValue(basetypes.NewSetValueMust(types.StringType, []attr.Value{ + types.StringValue("code"), types.StringValue("token"), types.StringValue("id_token"), + })), + }, + "grant_types": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + MarkdownDescription: "The grant types of the client. The default value is set to `['implicit','authorization_code', 'password', 'refresh_token']`", + Default: setdefault.StaticValue(basetypes.NewSetValueMust(types.StringType, []attr.Value{ + types.StringValue("implicit"), types.StringValue("authorization_code"), types.StringValue("password"), types.StringValue("refresh_token"), + })), + }, + // common_config attr + "login_providers": schema.SetAttribute{ + ElementType: types.StringType, + MarkdownDescription: "With this attribute one can setup login provider to the client.", + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.Set{ + setplanmodifier.UseStateForUnknown(), }, - "userinfo_encrypted_response_enc": schema.StringAttribute{ - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + }, + "additional_access_token_payload": schema.SetAttribute{ + ElementType: types.StringType, + MarkdownDescription: "Access token payload definition.", + Optional: true, + }, + "required_fields": schema.SetAttribute{ + ElementType: types.StringType, + MarkdownDescription: "The required fields while registering to the client.", + Optional: true, + }, + "is_hybrid_app": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Flag to set if your app is hybrid or not. Default is set to `false`. Set to `true` to make your app hybrid.", + Default: booldefault.StaticBool(false), + }, + // common_config attr + "allowed_web_origins": schema.SetAttribute{ + ElementType: types.StringType, + MarkdownDescription: "List of the web origins allowed to access the client.", + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.Set{ + setplanmodifier.UseStateForUnknown(), }, - "request_object_signing_alg": schema.StringAttribute{ - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + }, + // common_config attr + "allowed_origins": schema.SetAttribute{ + ElementType: types.StringType, + MarkdownDescription: "List of the origins allowed to access the client.", + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.Set{ + setplanmodifier.UseStateForUnknown(), }, - "request_object_encryption_alg": schema.StringAttribute{ - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), + }, + // cidaas faulty api, so marked this attribute as computed + "mobile_settings": schema.SingleNestedAttribute{ + Optional: true, + Computed: true, + Attributes: map[string]schema.Attribute{ + "team_id": schema.StringAttribute{ + Optional: true, }, - }, - "request_object_encryption_enc": schema.StringAttribute{ - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), + "bundle_id": schema.StringAttribute{ + Optional: true, }, - }, - "request_uris": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - }, - "description": schema.StringAttribute{ - Optional: true, - }, - // common_config attr - "default_scopes": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.Set{ - setplanmodifier.UseStateForUnknown(), + "package_name": schema.StringAttribute{ + Optional: true, }, - }, - // common_config attr - "pending_scopes": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - Computed: true, - PlanModifiers: []planmodifier.Set{ - setplanmodifier.UseStateForUnknown(), + "key_hash": schema.StringAttribute{ + Optional: true, }, }, - "consent_page_group": schema.StringAttribute{ - Optional: true, - }, - "password_policy_ref": schema.StringAttribute{ - Optional: true, - }, - "blocking_mechanism_ref": schema.StringAttribute{ - Optional: true, - }, - "sub": schema.StringAttribute{ - Optional: true, - }, - "role": schema.StringAttribute{ - Optional: true, - }, - "mfa_configuration": schema.StringAttribute{ - Optional: true, - }, - "suggest_mfa": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - }, - // cidaas faulty api, so marked this attribute as computed - "login_spi": schema.SingleNestedAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "A map defining the Login SPI configuration.", - Attributes: map[string]schema.Attribute{ - "oauth_client_id": schema.StringAttribute{ - Optional: true, + Default: objectdefault.StaticValue( + types.ObjectValueMust( + map[string]attr.Type{ + "team_id": types.StringType, + "bundle_id": types.StringType, + "package_name": types.StringType, + "key_hash": types.StringType, }, - "spi_url": schema.StringAttribute{ - Optional: true, + map[string]attr.Value{ + "team_id": types.StringNull(), + "bundle_id": types.StringNull(), + "package_name": types.StringNull(), + "key_hash": types.StringNull(), }, - }, - Default: objectdefault.StaticValue( - types.ObjectValueMust( - map[string]attr.Type{ - "oauth_client_id": types.StringType, - "spi_url": types.StringType, - }, - map[string]attr.Value{ - "oauth_client_id": types.StringNull(), - "spi_url": types.StringNull(), - }, - ), ), + ), + }, + "default_max_age": schema.Int64Attribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The default maximum age for the token in seconds. Default is 86400 seconds (24 hours).", + Default: int64default.StaticInt64(86400), + }, + "token_lifetime_in_seconds": schema.Int64Attribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The lifetime of the token in seconds. Default is 86400 seconds (24 hours).", + Default: int64default.StaticInt64(86400), + }, + "id_token_lifetime_in_seconds": schema.Int64Attribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The lifetime of the id_token in seconds. Default is 86400 seconds (24 hours).", + Default: int64default.StaticInt64(86400), + }, + "refresh_token_lifetime_in_seconds": schema.Int64Attribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The lifetime of the refresh token in seconds. Default is 15780000 seconds.", + Default: int64default.StaticInt64(15780000), + }, + "template_group_id": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The id of the template group to be configured for commenication. Default is set to the system default group.", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "background_uri": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The URL to the background image of the client.", - }, - "video_url": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The URL to the video of the client.", - }, - "bot_captcha_ref": schema.StringAttribute{ - Optional: true, + }, + "client_id": schema.StringAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The client_id is the unqique identifier of the app. It's an optional attribute." + + " If not provided, cidaas will gererate one for you and the state will be updated with the same", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "application_meta_data": schema.MapAttribute{ - ElementType: types.StringType, - Optional: true, - MarkdownDescription: "A map to add metadata of a client.", + }, + "client_secret": schema.StringAttribute{ + Optional: true, + Computed: true, + Sensitive: true, + MarkdownDescription: "The client_id is the unqique identifier of the app. It's an optional attribute." + + " If not provided, cidaas will gererate one for you and the state will be updated with the same", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "allow_guest_login": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Flag to specify whether guest users are allowed to access functionalities of the client." + - " Default is set to `false`", - Default: booldefault.StaticBool(false), + }, + "policy_uri": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The URL to the policy of a client.", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "require_auth_time": schema.BoolAttribute{ - Optional: true, - Computed: true, - Default: booldefault.StaticBool(false), - MarkdownDescription: "Boolean flag to specify whether the auth_time claim is REQUIRED in a id token.", + }, + "tos_uri": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The URL to the TOS of a client.", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "enable_login_spi": schema.BoolAttribute{ - Optional: true, - Computed: true, - Default: booldefault.StaticBool(false), - MarkdownDescription: "If enabled, the login service verifies whether login spi responsded with success only then it issues a token.", + }, + "imprint_uri": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The URL to the imprint page.", + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "backchannel_logout_session_required": schema.BoolAttribute{ - Optional: true, - Computed: true, - Default: booldefault.StaticBool(false), - MarkdownDescription: "If enabled, client applications or RPs must support session management through backchannel logout.", + }, + "contacts": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + MarkdownDescription: "The contacts of the client.", + }, + "token_endpoint_auth_method": schema.StringAttribute{ + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "suggest_verification_methods": schema.SingleNestedAttribute{ - Optional: true, - MarkdownDescription: "Configuration for verification methods.", - Attributes: map[string]schema.Attribute{ - "mandatory_config": schema.SingleNestedAttribute{ - Optional: true, - MarkdownDescription: "Configuration for mandatory verification methods.", - Attributes: map[string]schema.Attribute{ - "methods": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - MarkdownDescription: "List of mandatory verification methods.", - }, - "range": schema.StringAttribute{ - Optional: true, - Validators: []validator.String{ - stringvalidator.OneOf("ONEOF", "ALLOF"), - }, - MarkdownDescription: "The range type for mandatory methods. Allowed value is one of ALLOF or ONEOF.", - }, - "skip_until": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The date and time until which the mandatory methods can be skipped.", - }, - }, - }, - "optional_config": schema.SingleNestedAttribute{ - Optional: true, - MarkdownDescription: "Configuration for optional verification methods", - Attributes: map[string]schema.Attribute{ - "methods": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - MarkdownDescription: "List of optional verification methods.", - }, - }, - }, - "skip_duration_in_days": schema.Int32Attribute{ - Optional: true, - MarkdownDescription: "The number of days for which the verification methods can be skipped (default is 7 days).", - }, - }, + }, + "token_endpoint_auth_signing_alg": schema.StringAttribute{ + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "group_role_restriction": schema.SingleNestedAttribute{ - Optional: true, + }, + "default_acr_values": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + }, + "editable": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(true), + MarkdownDescription: "Flag to define if your client is editable or not. Default is `true`.", + }, + "web_message_uris": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + MarkdownDescription: "A list of URLs for web messages used.", + }, + "social_providers": schema.ListNestedAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "A list of social identity providers that users can authenticate with. Examples: Google, Facebook etc...", + NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ - "match_condition": schema.StringAttribute{ + "provider_name": schema.StringAttribute{ Optional: true, - Validators: []validator.String{ - stringvalidator.OneOf("and", "or"), - }, - MarkdownDescription: "The match condition for the role restriction", }, - "filters": schema.ListNestedAttribute{ - Optional: true, - MarkdownDescription: "An array of group role filters.", - NestedObject: schema.NestedAttributeObject{ - Attributes: map[string]schema.Attribute{ - "group_id": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The unique ID of the user group.", - }, - "role_filter": schema.SingleNestedAttribute{ - Optional: true, - MarkdownDescription: "A filter for roles within the group.", - Attributes: map[string]schema.Attribute{ - "match_condition": schema.StringAttribute{ - Optional: true, - Validators: []validator.String{ - stringvalidator.OneOf("and", "or"), - }, - MarkdownDescription: "The match condition for the roles (AND or OR).", - }, - "roles": schema.SetAttribute{ - Optional: true, - MarkdownDescription: "An array of role names.", - ElementType: types.StringType, - }, - }, - }, - }, - }, + "social_id": schema.StringAttribute{ + Optional: true, }, }, }, - "basic_settings": schema.SingleNestedAttribute{ - Optional: true, - Attributes: map[string]schema.Attribute{ - "client_id": schema.StringAttribute{ - Computed: true, - MarkdownDescription: "Unique client ID of the app", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + Default: listdefault.StaticValue(types.ListValueMust( + types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "provider_name": types.StringType, + "social_id": types.StringType, }, - "redirect_uris": schema.SetAttribute{ - Computed: true, - ElementType: types.StringType, - MarkdownDescription: "An array of redirect URIs for the app where the app should be redirected after successful login", - }, - "allowed_logout_urls": schema.SetAttribute{ - Computed: true, - ElementType: types.StringType, - MarkdownDescription: "An array of allowed logout URLs for the app where the app should be redirected after successful logout", + }, []attr.Value{})), + }, + "custom_providers": schema.ListNestedAttribute{ + Optional: true, + // if empty and common_config has it's value then assigned the same. so marked computed + Computed: true, + MarkdownDescription: "A list of custom identity providers that users can authenticate with. A custom provider can be created with the help of the resource cidaas_custom_provider.", + NestedObject: providerMetadDataSchema, + Default: listdefault.StaticValue(types.ListValueMust( + types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "provider_name": types.StringType, + "display_name": types.StringType, + "logo_url": types.StringType, + "type": types.StringType, + "is_provider_visible": types.BoolType, + "domains": types.SetType{ElemType: types.StringType}, }, - "allowed_scopes": schema.SetAttribute{ - Computed: true, - ElementType: types.StringType, - MarkdownDescription: "Allowed scopes for the app", + }, []attr.Value{})), + }, + "saml_providers": schema.ListNestedAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "A list of SAML identity providers that users can authenticate with.", + NestedObject: providerMetadDataSchema, + Default: listdefault.StaticValue(types.ListValueMust( + types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "provider_name": types.StringType, + "display_name": types.StringType, + "logo_url": types.StringType, + "type": types.StringType, + "is_provider_visible": types.BoolType, + "domains": types.SetType{ElemType: types.StringType}, }, - "client_secrets": schema.ListNestedAttribute{ - Optional: true, - MarkdownDescription: "An array of client secret data (Max size is 2)", - NestedObject: schema.NestedAttributeObject{ - Attributes: map[string]schema.Attribute{ - "client_secret": schema.StringAttribute{ - Optional: true, - Computed: true, - Sensitive: true, - MarkdownDescription: "Secret key for the client ID", - }, - "client_secret_expires_at": schema.Int64Attribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The time when the clientsecret expires", - }, - }, - }, - Validators: []validator.List{ - listvalidator.SizeAtMost(2), - }, + }, []attr.Value{})), + }, + "ad_providers": schema.ListNestedAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "A list of Active Directory identity providers that users can authenticate with.", + NestedObject: providerMetadDataSchema, + Default: listdefault.StaticValue(types.ListValueMust( + types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "provider_name": types.StringType, + "display_name": types.StringType, + "logo_url": types.StringType, + "type": types.StringType, + "is_provider_visible": types.BoolType, + "domains": types.SetType{ElemType: types.StringType}, }, - }, - }, - "common_configs": commonConfigSchema, + }, []attr.Value{})), }, - } -} - -var providerMetadDataSchema = schema.NestedAttributeObject{ - Attributes: map[string]schema.Attribute{ - "provider_name": schema.StringAttribute{ - Optional: true, + "jwe_enabled": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Flag to specify whether JSON Web Encryption (JWE) should be enabled for encrypting data.", + Default: booldefault.StaticBool(false), }, - "display_name": schema.StringAttribute{ - Optional: true, + "user_consent": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Specifies whether user consent is required or not. Default is `false`", + Default: booldefault.StaticBool(false), }, - "logo_url": schema.StringAttribute{ - Optional: true, + "allowed_groups": schema.ListNestedAttribute{ + Optional: true, + Computed: true, + NestedObject: allowedGroupsSchema, + Default: listdefault.StaticValue(types.ListValueMust( + types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "group_id": types.StringType, + "roles": types.SetType{ElemType: types.StringType}, + "default_roles": types.SetType{ElemType: types.StringType}, + }, + }, []attr.Value{})), }, - "type": schema.StringAttribute{ - Optional: true, + "operations_allowed_groups": schema.ListNestedAttribute{ + Optional: true, + Computed: true, + NestedObject: allowedGroupsSchema, + Default: listdefault.StaticValue(types.ListValueMust( + types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "group_id": types.StringType, + "roles": types.SetType{ElemType: types.StringType}, + "default_roles": types.SetType{ElemType: types.StringType}, + }, + }, []attr.Value{})), }, - "is_provider_visible": schema.BoolAttribute{ + "enabled": schema.BoolAttribute{ Optional: true, + Computed: true, + Default: booldefault.StaticBool(true), }, - "domains": schema.SetAttribute{ + "allowed_fields": schema.SetAttribute{ ElementType: types.StringType, Optional: true, }, - }, -} - -var allowedGroupsSchema = schema.NestedAttributeObject{ - Attributes: map[string]schema.Attribute{ - "group_id": schema.StringAttribute{ + "always_ask_mfa": schema.BoolAttribute{ Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), }, - "roles": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, + "smart_mfa": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), }, - "default_roles": schema.SetAttribute{ + // common_config attr + "allowed_mfa": schema.SetAttribute{ ElementType: types.StringType, Optional: true, - }, - }, -} - -var commonConfigSchema = schema.SingleNestedAttribute{ - Optional: true, - MarkdownDescription: "The `common_configs` attribute is used for sharing the same configuration across multiple cidaas_app resources." + - " It is a map of some attributes from the main configuration." + - " Please check the list of the attributes that it supports in the common_confis section." + - " if an attribute is available both common_config and main config then attribute from the main config will be considered to create an app", - Attributes: map[string]schema.Attribute{ - "company_name": schema.StringAttribute{ - Optional: true, - }, - "company_website": schema.StringAttribute{ - Optional: true, - }, - "client_type": schema.StringAttribute{ - Optional: true, - Validators: []validator.String{ - stringvalidator.OneOf([]string{ - "SINGLE_PAGE", "REGULAR_WEB", "NON_INTERACTIVE", - "IOS", "ANDROID", "WINDOWS_MOBILE", "DESKTOP", "MOBILE", "DEVICE", "THIRD_PARTY", - }...), + Computed: true, + PlanModifiers: []planmodifier.Set{ + setplanmodifier.UseStateForUnknown(), }, }, - "company_address": schema.StringAttribute{ + "captcha_ref": schema.StringAttribute{ Optional: true, }, - "allowed_scopes": schema.SetAttribute{ + "captcha_refs": schema.SetAttribute{ ElementType: types.StringType, Optional: true, }, - "redirect_uris": schema.SetAttribute{ + "consent_refs": schema.SetAttribute{ ElementType: types.StringType, Optional: true, }, - "allowed_logout_urls": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - }, - "allowed_web_origins": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - }, - "allowed_origins": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - }, - "login_providers": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - }, - "default_scopes": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, + "communication_medium_verification": schema.StringAttribute{ + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, - "pending_scopes": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, + "email_verification_required": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(true), }, - "allowed_mfa": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, + "mobile_number_verification_required": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), }, + // common_config attr "allowed_roles": schema.SetAttribute{ ElementType: types.StringType, Optional: true, + Computed: true, + PlanModifiers: []planmodifier.Set{ + setplanmodifier.UseStateForUnknown(), + }, }, + // common_config attr "default_roles": schema.SetAttribute{ ElementType: types.StringType, Optional: true, - }, - "social_providers": schema.ListNestedAttribute{ - Optional: true, - NestedObject: schema.NestedAttributeObject{ - Attributes: map[string]schema.Attribute{ - "provider_name": schema.StringAttribute{ - Optional: true, - }, - "social_id": schema.StringAttribute{ - Optional: true, - }, - }, + Computed: true, + PlanModifiers: []planmodifier.Set{ + setplanmodifier.UseStateForUnknown(), }, }, - "custom_providers": schema.ListNestedAttribute{ + "enable_classical_provider": schema.BoolAttribute{ Optional: true, - NestedObject: schema.NestedAttributeObject{ - Attributes: map[string]schema.Attribute{ - "provider_name": schema.StringAttribute{ - Optional: true, - }, - "display_name": schema.StringAttribute{ - Optional: true, - }, - "logo_url": schema.StringAttribute{ - Optional: true, - }, - "type": schema.StringAttribute{ - Optional: true, - }, - "is_provider_visible": schema.BoolAttribute{ - Optional: true, - }, - "domains": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - }, - }, - }, + Computed: true, + Default: booldefault.StaticBool(true), }, - "saml_providers": schema.ListNestedAttribute{ - Optional: true, - NestedObject: schema.NestedAttributeObject{ - Attributes: map[string]schema.Attribute{ - "provider_name": schema.StringAttribute{ - Optional: true, - }, - "display_name": schema.StringAttribute{ - Optional: true, - }, - "logo_url": schema.StringAttribute{ - Optional: true, - }, - "type": schema.StringAttribute{ - Optional: true, - }, - "is_provider_visible": schema.BoolAttribute{ - Optional: true, - }, - "domains": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - }, - }, - }, + "is_remember_me_selected": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(true), }, - "ad_providers": schema.ListNestedAttribute{ + "enable_bot_detection": schema.BoolAttribute{ Optional: true, - NestedObject: schema.NestedAttributeObject{ - Attributes: map[string]schema.Attribute{ - "provider_name": schema.StringAttribute{ - Optional: true, - }, - "display_name": schema.StringAttribute{ - Optional: true, - }, - "logo_url": schema.StringAttribute{ - Optional: true, - }, - "type": schema.StringAttribute{ - Optional: true, - }, - "is_provider_visible": schema.BoolAttribute{ - Optional: true, - }, - "domains": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - }, - }, + Computed: true, + Default: booldefault.StaticBool(false), + }, + "bot_provider": schema.StringAttribute{ + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, }, - "allowed_groups": schema.ListNestedAttribute{ + "allow_guest_login_groups": schema.ListNestedAttribute{ Optional: true, + Computed: true, NestedObject: allowedGroupsSchema, + Default: listdefault.StaticValue(types.ListValueMust( + types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "group_id": types.StringType, + "roles": types.SetType{ElemType: types.StringType}, + "default_roles": types.SetType{ElemType: types.StringType}, + }, + }, []attr.Value{})), }, - "operations_allowed_groups": schema.ListNestedAttribute{ - Optional: true, - NestedObject: allowedGroupsSchema, + "is_login_success_page_enabled": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), }, - "accent_color": schema.StringAttribute{ + "is_register_success_page_enabled": schema.BoolAttribute{ Optional: true, - Validators: []validator.String{ - stringvalidator.RegexMatches( - regexp.MustCompile(`^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$`), - "must be a valid hex color", - ), - }, + Computed: true, + Default: booldefault.StaticBool(false), }, - "primary_color": schema.StringAttribute{ + "group_ids": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + }, + "is_group_login_selection_enabled": schema.BoolAttribute{ Optional: true, - Validators: []validator.String{ - stringvalidator.RegexMatches( - regexp.MustCompile(`^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$`), - "must be a valid hex color", - ), - }, + Computed: true, + Default: booldefault.StaticBool(false), }, - "media_type": schema.StringAttribute{ + "group_selection": schema.SingleNestedAttribute{ Optional: true, - Validators: []validator.String{ - stringvalidator.OneOf([]string{"VIDEO", "IMAGE"}...), + // cidaas faulty api, so marked this attribute as computed + Computed: true, + Attributes: map[string]schema.Attribute{ + "always_show_group_selection": schema.BoolAttribute{ + Optional: true, + }, + "selectable_groups": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + }, + "selectable_group_types": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + }, }, + Default: objectdefault.StaticValue( + types.ObjectValueMust( + map[string]attr.Type{ + "always_show_group_selection": types.BoolType, + "selectable_groups": types.SetType{ElemType: types.StringType}, + "selectable_group_types": types.SetType{ElemType: types.StringType}, + }, + map[string]attr.Value{ + "always_show_group_selection": types.BoolNull(), + "selectable_groups": types.SetNull(types.StringType), + "selectable_group_types": types.SetNull(types.StringType), + }, + ), + ), }, - "hosted_page_group": schema.StringAttribute{ - Optional: true, + "group_types": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, }, - "template_group_id": schema.StringAttribute{ + "backchannel_logout_uri": schema.StringAttribute{ Optional: true, }, - "bot_provider": schema.StringAttribute{ - Optional: true, + "post_logout_redirect_uris": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, }, "logo_align": schema.StringAttribute{ Optional: true, Validators: []validator.String{ stringvalidator.OneOf([]string{"CENTER", "LEFT", "RIGHT"}...), }, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "mfa": schema.SingleNestedAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Configuration settings for Multi-Factor Authentication (MFA).", + Attributes: map[string]schema.Attribute{ + "setting": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Specifies the Multi-Factor Authentication (MFA) setting. Allowed values are 'OFF', 'ALWAYS', 'SMART', 'TIME_BASED' and 'SMART_PLUS_TIME_BASED'.", + Validators: []validator.String{ + stringvalidator.OneOf([]string{"OFF", "ALWAYS", "SMART", "TIME_BASED", "SMART_PLUS_TIME_BASED"}...), + }, + }, + "time_interval_in_seconds": schema.Int64Attribute{ + Optional: true, + MarkdownDescription: "Optional time interval in seconds for time-based Multi-Factor Authentication.", + }, + "allowed_methods": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + MarkdownDescription: "Optional set of allowed MFA methods.", + }, + }, + PlanModifiers: []planmodifier.Object{ + objectplanmodifier.UseStateForUnknown(), + }, }, "webfinger": schema.StringAttribute{ Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, - "default_max_age": schema.Int64Attribute{ + "logo_uri": schema.StringAttribute{ Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, - "token_lifetime_in_seconds": schema.Int64Attribute{ + "initiate_login_uri": schema.StringAttribute{ Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, - "id_token_lifetime_in_seconds": schema.Int64Attribute{ + "registration_client_uri": schema.StringAttribute{ Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, - "refresh_token_lifetime_in_seconds": schema.Int64Attribute{ + "registration_access_token": schema.StringAttribute{ Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, - "allow_guest_login": schema.BoolAttribute{ + "client_uri": schema.StringAttribute{ Optional: true, }, - "enable_deduplication": schema.BoolAttribute{ + "jwks_uri": schema.StringAttribute{ + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "jwks": schema.StringAttribute{ Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, - "auto_login_after_register": schema.BoolAttribute{ + "sector_identifier_uri": schema.StringAttribute{ Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, - "enable_passwordless_auth": schema.BoolAttribute{ + "subject_type": schema.StringAttribute{ Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, - "register_with_login_information": schema.BoolAttribute{ + "id_token_signed_response_alg": schema.StringAttribute{ Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, - "fds_enabled": schema.BoolAttribute{ + "id_token_encrypted_response_alg": schema.StringAttribute{ Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, - "is_hybrid_app": schema.BoolAttribute{ + "id_token_encrypted_response_enc": schema.StringAttribute{ Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, - "editable": schema.BoolAttribute{ + "userinfo_signed_response_alg": schema.StringAttribute{ Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, - "enabled": schema.BoolAttribute{ + "userinfo_encrypted_response_alg": schema.StringAttribute{ Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, - "always_ask_mfa": schema.BoolAttribute{ + "userinfo_encrypted_response_enc": schema.StringAttribute{ Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, - "email_verification_required": schema.BoolAttribute{ + "request_object_signing_alg": schema.StringAttribute{ Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, - "enable_classical_provider": schema.BoolAttribute{ + "request_object_encryption_alg": schema.StringAttribute{ Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, - "is_remember_me_selected": schema.BoolAttribute{ + "request_object_encryption_enc": schema.StringAttribute{ Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, - "response_types": schema.SetAttribute{ + "request_uris": schema.SetAttribute{ ElementType: types.StringType, Optional: true, }, - "grant_types": schema.SetAttribute{ + "description": schema.StringAttribute{ + Optional: true, + }, + // common_config attr + "default_scopes": schema.SetAttribute{ ElementType: types.StringType, Optional: true, + Computed: true, + PlanModifiers: []planmodifier.Set{ + setplanmodifier.UseStateForUnknown(), + }, }, - "allow_login_with": schema.SetAttribute{ + // common_config attr + "pending_scopes": schema.SetAttribute{ ElementType: types.StringType, Optional: true, - Validators: []validator.Set{ - setvalidator.ValueStringsAre( - stringvalidator.OneOf([]string{"EMAIL", "MOBILE", "USER_NAME"}...), + Computed: true, + PlanModifiers: []planmodifier.Set{ + setplanmodifier.UseStateForUnknown(), + }, + }, + "consent_page_group": schema.StringAttribute{ + Optional: true, + }, + "password_policy_ref": schema.StringAttribute{ + Optional: true, + }, + "blocking_mechanism_ref": schema.StringAttribute{ + Optional: true, + }, + "sub": schema.StringAttribute{ + Optional: true, + }, + "role": schema.StringAttribute{ + Optional: true, + }, + "mfa_configuration": schema.StringAttribute{ + Optional: true, + }, + "suggest_mfa": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + }, + // cidaas faulty api, so marked this attribute as computed + "login_spi": schema.SingleNestedAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "A map defining the Login SPI configuration.", + Attributes: map[string]schema.Attribute{ + "oauth_client_id": schema.StringAttribute{ + Optional: true, + }, + "spi_url": schema.StringAttribute{ + Optional: true, + }, + }, + Default: objectdefault.StaticValue( + types.ObjectValueMust( + map[string]attr.Type{ + "oauth_client_id": types.StringType, + "spi_url": types.StringType, + }, + map[string]attr.Value{ + "oauth_client_id": types.StringNull(), + "spi_url": types.StringNull(), + }, ), + ), + }, + "background_uri": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The URL to the background image of the client.", + }, + "video_url": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The URL to the video of the client.", + }, + "bot_captcha_ref": schema.StringAttribute{ + Optional: true, + }, + "application_meta_data": schema.MapAttribute{ + ElementType: types.StringType, + Optional: true, + MarkdownDescription: "A map to add metadata of a client.", + }, + "allow_guest_login": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Flag to specify whether guest users are allowed to access functionalities of the client." + + " Default is set to `false`", + Default: booldefault.StaticBool(false), + }, + "require_auth_time": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), + MarkdownDescription: "Boolean flag to specify whether the auth_time claim is REQUIRED in a id token.", + }, + "enable_login_spi": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), + MarkdownDescription: "If enabled, the login service verifies whether login spi responsded with success only then it issues a token.", + }, + "backchannel_logout_session_required": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), + MarkdownDescription: "If enabled, client applications or RPs must support session management through backchannel logout.", + }, + "suggest_verification_methods": schema.SingleNestedAttribute{ + Optional: true, + MarkdownDescription: "Configuration for verification methods.", + Attributes: map[string]schema.Attribute{ + "mandatory_config": schema.SingleNestedAttribute{ + Optional: true, + MarkdownDescription: "Configuration for mandatory verification methods.", + Attributes: map[string]schema.Attribute{ + "methods": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + MarkdownDescription: "List of mandatory verification methods.", + }, + "range": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOf("ONEOF", "ALLOF"), + }, + MarkdownDescription: "The range type for mandatory methods. Allowed value is one of ALLOF or ONEOF.", + }, + "skip_until": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The date and time until which the mandatory methods can be skipped.", + }, + }, + }, + "optional_config": schema.SingleNestedAttribute{ + Optional: true, + MarkdownDescription: "Configuration for optional verification methods", + Attributes: map[string]schema.Attribute{ + "methods": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + MarkdownDescription: "List of optional verification methods.", + }, + }, + }, + "skip_duration_in_days": schema.Int32Attribute{ + Optional: true, + MarkdownDescription: "The number of days for which the verification methods can be skipped (default is 7 days).", + }, }, }, - "mfa": schema.SingleNestedAttribute{ + "group_role_restriction": schema.SingleNestedAttribute{ Optional: true, Attributes: map[string]schema.Attribute{ - "setting": schema.StringAttribute{ + "match_condition": schema.StringAttribute{ Optional: true, Validators: []validator.String{ - stringvalidator.OneOf([]string{"OFF", "ALWAYS", "SMART", "TIME_BASED", "SMART_PLUS_TIME_BASED"}...), + stringvalidator.OneOf("and", "or"), }, + MarkdownDescription: "The match condition for the role restriction", }, - "time_interval_in_seconds": schema.Int64Attribute{ - Optional: true, + "filters": schema.ListNestedAttribute{ + Optional: true, + MarkdownDescription: "An array of group role filters.", + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "group_id": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The unique ID of the user group.", + }, + "role_filter": schema.SingleNestedAttribute{ + Optional: true, + MarkdownDescription: "A filter for roles within the group.", + Attributes: map[string]schema.Attribute{ + "match_condition": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.OneOf("and", "or"), + }, + MarkdownDescription: "The match condition for the roles (AND or OR).", + }, + "roles": schema.SetAttribute{ + Optional: true, + MarkdownDescription: "An array of role names.", + ElementType: types.StringType, + }, + }, + }, + }, + }, }, - "allowed_methods": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, + }, + }, + "basic_settings": schema.SingleNestedAttribute{ + Optional: true, + Attributes: map[string]schema.Attribute{ + "client_id": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "Unique client ID of the app", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "redirect_uris": schema.SetAttribute{ + Computed: true, + ElementType: types.StringType, + MarkdownDescription: "An array of redirect URIs for the app where the app should be redirected after successful login", + }, + "allowed_logout_urls": schema.SetAttribute{ + Computed: true, + ElementType: types.StringType, + MarkdownDescription: "An array of allowed logout URLs for the app where the app should be redirected after successful logout", + }, + "allowed_scopes": schema.SetAttribute{ + Computed: true, + ElementType: types.StringType, + MarkdownDescription: "Allowed scopes for the app", + }, + "client_secrets": schema.ListNestedAttribute{ + Optional: true, + MarkdownDescription: "An array of client secret data (Max size is 2)", + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "client_secret": schema.StringAttribute{ + Optional: true, + Computed: true, + Sensitive: true, + MarkdownDescription: "Secret key for the client ID", + }, + "client_secret_expires_at": schema.Int64Attribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The time when the clientsecret expires", + }, + }, + }, + Validators: []validator.List{ + listvalidator.SizeAtMost(2), + }, }, }, }, }, } + +var providerMetadDataSchema = schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "provider_name": schema.StringAttribute{ + Optional: true, + }, + "display_name": schema.StringAttribute{ + Optional: true, + }, + "logo_url": schema.StringAttribute{ + Optional: true, + }, + "type": schema.StringAttribute{ + Optional: true, + }, + "is_provider_visible": schema.BoolAttribute{ + Optional: true, + }, + "domains": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + }, + }, +} + +var allowedGroupsSchema = schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "group_id": schema.StringAttribute{ + Optional: true, + }, + "roles": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + }, + "default_roles": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + }, + }, +} diff --git a/internal/resources/resource_app.go b/internal/resources/resource_app.go index 37f8693..0da1c65 100644 --- a/internal/resources/resource_app.go +++ b/internal/resources/resource_app.go @@ -2,42 +2,25 @@ package resources import ( "context" - "fmt" - "github.com/Cidaas/terraform-provider-cidaas/helpers/cidaas" "github.com/Cidaas/terraform-provider-cidaas/helpers/util" - "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" - "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) type AppResource struct { - cidaasClient *cidaas.Client + BaseResource } func NewAppResource() resource.Resource { - return &AppResource{} -} - -func (r *AppResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_app" -} - -func (r *AppResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - if req.ProviderData == nil { - return + return &AppResource{ + BaseResource: NewBaseResource( + BaseResourceConfig{ + Name: RESOURCE_APP, + Schema: &resourceAppSchema, + }, + ), } - client, ok := req.ProviderData.(*cidaas.Client) - if !ok { - resp.Diagnostics.AddError( - "Unexpected Resource Configure Type", - fmt.Sprintf("Expected cidaas.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), - ) - return - } - r.cidaasClient = client } func (r *AppResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { @@ -118,305 +101,3 @@ func (r *AppResource) Delete(ctx context.Context, req resource.DeleteRequest, re func (r *AppResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { resource.ImportStatePassthroughID(ctx, path.Root("client_id"), req, resp) } - -func (r *AppResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { //nolint:gocognit - var config AppConfig - resp.Diagnostics.Append(req.Config.Get(ctx, &config)...) - resp.Diagnostics.Append(config.ExtractAppConfigs(ctx)...) - if resp.Diagnostics.HasError() { - return - } - if config.CommonConfigs.IsNull() || config.CommonConfigs.IsUnknown() { - return - } - - isClientTypeNull := false - isAllowedScopesNull := false - - // required params - if config.ClientType.IsNull() && (config.CommonConfigs.IsNull() || config.commonConfigs.ClientType.IsNull()) { - isClientTypeNull = true - resp.Diagnostics.AddError("Missing required argument", - "The 'client_type' argument is required but has not been configured. You can set the 'client_type' either directly in the main configuration or within the 'common_configs' attribute.", - ) - } - if config.CompanyName.IsNull() && (config.CommonConfigs.IsNull() || config.commonConfigs.CompanyName.IsNull()) { - resp.Diagnostics.AddError("Missing required argument", - "The 'company_name' argument is required but has not been configured. You can set the 'company_name' either directly in the main configuration or within the 'common_configs' attribute.", - ) - } - if config.CompanyAddress.IsNull() && (config.CommonConfigs.IsNull() || config.commonConfigs.CompanyAddress.IsNull()) { - resp.Diagnostics.AddError("Missing required argument", - "The 'company_address' argument is required but has not been configured. You can set the 'company_address' either directly in the main configuration or within the 'common_configs' attribute.", - ) - } - if config.CompanyWebsite.IsNull() && (config.CommonConfigs.IsNull() || config.commonConfigs.CompanyWebsite.IsNull()) { - resp.Diagnostics.AddError("Missing required argument", - "The 'company_website' argument is required but has not been configured. You can set the 'company_website' either directly in the main configuration or within the 'common_configs' attribute.", - ) - } - - if config.AllowedScopes.IsNull() && (config.CommonConfigs.IsNull() || config.commonConfigs.AllowedScopes.IsNull()) { - isAllowedScopesNull = true - resp.Diagnostics.AddError("Missing required argument", - "The 'allowed_scopes' argument is required but has not been configured. You can set the 'allowed_scopes' either directly in the main configuration or within the 'common_configs' attribute.", - ) - } - - if !isAllowedScopesNull { - allowedScopes := []string{} - if !config.AllowedScopes.IsNull() { - for _, v := range config.AllowedScopes.Elements() { - allowedScopes = append(allowedScopes, v.String()) - } - } else if !config.commonConfigs.AllowedScopes.IsNull() { - for _, v := range config.commonConfigs.AllowedScopes.Elements() { - allowedScopes = append(allowedScopes, v.String()) - } - } - if (!config.AllowedScopes.IsNull() || !config.commonConfigs.AllowedScopes.IsNull()) && len(allowedScopes) < 1 { - resp.Diagnostics.AddError("Unexpected Resource Configuration", - "The 'allowed_scopes' argument must contain at least one value.", - ) - } - } - - if !isClientTypeNull { - isRedirectURIReqired := false - validClientTypes := []string{"SINGLE_PAGE", "REGULAR_WEB", "THIRD_PARTY"} - if !config.ClientType.IsNull() { - isRedirectURIReqired = util.StringInSlice(config.ClientType.ValueString(), validClientTypes) - } else if !config.CommonConfigs.IsNull() && !config.commonConfigs.ClientType.IsNull() { - isRedirectURIReqired = util.StringInSlice(config.ClientType.ValueString(), validClientTypes) - } - if isRedirectURIReqired { - if config.RedirectURIS.IsNull() && (config.CommonConfigs.IsNull() || config.commonConfigs.RedirectUris.IsNull()) { - resp.Diagnostics.AddError("Missing required argument", - "The 'redirect_uris' argument is required but has not been configured. You can set the 'redirect_uris' either directly in the main configuration or within the 'common_configs' attribute.", - ) - } - - if config.AllowedLogoutUrls.IsNull() && (config.CommonConfigs.IsNull() || config.commonConfigs.AllowedLogoutUrls.IsNull()) { - resp.Diagnostics.AddError("Missing required argument", - "The 'allowed_logout_urls' argument is required but has not been configured. You can set the 'allowed_logout_urls' either directly in the main configuration or within the 'common_configs' attribute.", - ) - } - - redirectUrls := []string{} - if !config.RedirectURIS.IsNull() { - for _, v := range config.RedirectURIS.Elements() { - redirectUrls = append(redirectUrls, v.String()) - } - } else if !config.CommonConfigs.IsNull() && !config.commonConfigs.RedirectUris.IsNull() { - for _, v := range config.commonConfigs.RedirectUris.Elements() { - redirectUrls = append(redirectUrls, v.String()) - } - } - if (!config.RedirectURIS.IsNull() || (!config.CommonConfigs.IsNull() && !config.commonConfigs.RedirectUris.IsNull())) && len(redirectUrls) < 1 { - resp.Diagnostics.AddError("Unexpected Resource Configuration", - "The 'redirect_uris' argument must contain at least one URI.", - ) - } - - logoutUrls := []string{} - if !config.AllowedLogoutUrls.IsNull() { - for _, v := range config.AllowedLogoutUrls.Elements() { - logoutUrls = append(logoutUrls, v.String()) - } - } else if !config.CommonConfigs.IsNull() && !config.commonConfigs.AllowedLogoutUrls.IsNull() { - for _, v := range config.commonConfigs.AllowedLogoutUrls.Elements() { - logoutUrls = append(logoutUrls, v.String()) - } - } - if (!config.AllowedLogoutUrls.IsNull() || (!config.CommonConfigs.IsNull() && !config.commonConfigs.AllowedLogoutUrls.IsNull())) && len(logoutUrls) < 1 { - resp.Diagnostics.AddError("Unexpected Resource Configuration", - "The 'allowed_logout_urls' argument must contain at least one URI.", - ) - } - } - } -} - -func (r *AppResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { //nolint:gocognit - if req.Plan.Raw.IsNull() { - return - } - - var config, plan AppConfig - resp.Diagnostics.Append(req.Config.Get(ctx, &config)...) - resp.Diagnostics.Append(config.ExtractAppConfigs(ctx)...) - resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) - resp.Diagnostics.Append(plan.ExtractAppConfigs(ctx)...) - if resp.Diagnostics.HasError() { - return - } - if plan.CommonConfigs.IsNull() || plan.CommonConfigs.IsUnknown() || plan.commonConfigs == nil { - return - } - - if !config.CommonConfigs.IsNull() { - message := "\033[1mRecommendations:\033[0m\n\n" + - " - Utilize common_configs only when there are shared configuration attributes for multiple resources.\n" + - " - If you need to override any specific attribute for a particular resource, you can supply the main configuration attribute directly within the resource block.\n" + - " - If your configuration involves a single resource or if the common configuration attributes are not shared across multiple resources we do not suggest using common_configs." - - resp.Diagnostics.AddWarning( - `Use of common_configs`, - message, - ) - } - - updatePlanStringAttribute := func(planAttr, commonConfigAttr, configAttr *types.String) { - if (planAttr.IsNull() || planAttr.IsUnknown()) && !commonConfigAttr.IsNull() { - *planAttr = *commonConfigAttr - } - if !planAttr.IsNull() && !planAttr.IsUnknown() && configAttr.IsNull() && !commonConfigAttr.IsNull() && (planAttr.ValueString() == "" || planAttr.ValueString() != commonConfigAttr.ValueString()) { - *planAttr = *commonConfigAttr - } - } - - updateBoolAttribute := func(configAttr, planAttr, commonConfigAttr *types.Bool) { - if configAttr.IsNull() && !commonConfigAttr.IsNull() && !commonConfigAttr.Equal(planAttr) { - *planAttr = *commonConfigAttr - } - } - updatePlanStringAttribute(&plan.CompanyName, &plan.commonConfigs.CompanyName, &config.CompanyName) - updatePlanStringAttribute(&plan.CompanyWebsite, &plan.commonConfigs.CompanyWebsite, &config.CompanyWebsite) - updatePlanStringAttribute(&plan.CompanyAddress, &plan.commonConfigs.CompanyAddress, &config.CompanyAddress) - updatePlanStringAttribute(&plan.ClientType, &plan.commonConfigs.ClientType, &config.ClientType) - updatePlanStringAttribute(&plan.AccentColor, &plan.commonConfigs.AccentColor, &config.AccentColor) - updatePlanStringAttribute(&plan.PrimaryColor, &plan.commonConfigs.PrimaryColor, &config.PrimaryColor) - updatePlanStringAttribute(&plan.MediaType, &plan.commonConfigs.MediaType, &config.MediaType) - updatePlanStringAttribute(&plan.HostedPageGroup, &plan.commonConfigs.HostedPageGroup, &config.HostedPageGroup) - updatePlanStringAttribute(&plan.TemplateGroupID, &plan.commonConfigs.TemplateGroupID, &config.TemplateGroupID) - updatePlanStringAttribute(&plan.BotProvider, &plan.commonConfigs.BotProvider, &config.BotProvider) - updatePlanStringAttribute(&plan.LogoAlign, &plan.commonConfigs.LogoAlign, &config.LogoAlign) - updatePlanStringAttribute(&plan.Webfinger, &plan.commonConfigs.Webfinger, &config.Webfinger) - - // default int check - if config.DefaultMaxAge.IsNull() && !plan.commonConfigs.DefaultMaxAge.IsNull() && !plan.commonConfigs.DefaultMaxAge.Equal(plan.DefaultMaxAge) { - plan.DefaultMaxAge = plan.commonConfigs.DefaultMaxAge - } - if config.TokenLifetimeInSeconds.IsNull() && !plan.commonConfigs.TokenLifetimeInSeconds.IsNull() && !plan.commonConfigs.TokenLifetimeInSeconds.Equal(plan.TokenLifetimeInSeconds) { - plan.TokenLifetimeInSeconds = plan.commonConfigs.TokenLifetimeInSeconds - } - if config.IDTokenLifetimeInSeconds.IsNull() && !plan.commonConfigs.IDTokenLifetimeInSeconds.IsNull() && !plan.commonConfigs.IDTokenLifetimeInSeconds.Equal(plan.IDTokenLifetimeInSeconds) { - plan.IDTokenLifetimeInSeconds = plan.commonConfigs.IDTokenLifetimeInSeconds - } - if config.RefreshTokenLifetimeInSeconds.IsNull() && !plan.commonConfigs.RefreshTokenLifetimeInSeconds.IsNull() && !plan.commonConfigs.RefreshTokenLifetimeInSeconds.Equal(plan.RefreshTokenLifetimeInSeconds) { - plan.RefreshTokenLifetimeInSeconds = plan.commonConfigs.RefreshTokenLifetimeInSeconds - } - - // default bool check - updateBoolAttribute(&config.AllowGuestLogin, &plan.AllowGuestLogin, &plan.commonConfigs.AllowGuestLogin) - updateBoolAttribute(&config.EnableDeduplication, &plan.EnableDeduplication, &plan.commonConfigs.EnableDeduplication) - updateBoolAttribute(&config.AutoLoginAfterRegister, &plan.AutoLoginAfterRegister, &plan.commonConfigs.AutoLoginAfterRegister) - updateBoolAttribute(&config.EnablePasswordlessAuth, &plan.EnablePasswordlessAuth, &plan.commonConfigs.EnablePasswordlessAuth) - updateBoolAttribute(&config.RegisterWithLoginInformation, &plan.RegisterWithLoginInformation, &plan.commonConfigs.RegisterWithLoginInformation) - updateBoolAttribute(&config.FdsEnabled, &plan.FdsEnabled, &plan.commonConfigs.FdsEnabled) - updateBoolAttribute(&config.IsHybridApp, &plan.IsHybridApp, &plan.commonConfigs.IsHybridApp) - updateBoolAttribute(&config.Editable, &plan.Editable, &plan.commonConfigs.Editable) - updateBoolAttribute(&config.Enabled, &plan.Enabled, &plan.commonConfigs.Enabled) - updateBoolAttribute(&config.AlwaysAskMfa, &plan.AlwaysAskMfa, &plan.commonConfigs.AlwaysAskMfa) - updateBoolAttribute(&config.EmailVerificationRequired, &plan.EmailVerificationRequired, &plan.commonConfigs.EmailVerificationRequired) - updateBoolAttribute(&config.EnableClassicalProvider, &plan.EnableClassicalProvider, &plan.commonConfigs.EnableClassicalProvider) - updateBoolAttribute(&config.IsRememberMeSelected, &plan.IsRememberMeSelected, &plan.commonConfigs.IsRememberMeSelected) - - // set attributes - updateSetAttributes := func(configValue, commonConfigValue, planValue basetypes.SetValue, planField *basetypes.SetValue) { - if configValue.IsNull() { - if !commonConfigValue.IsNull() { - *planField = commonConfigValue - } else if !planValue.IsNull() && !planValue.IsUnknown() { - *planField = types.SetValueMust(types.StringType, []attr.Value{}) - } - } - } - - updateSetAttributes(config.AllowedScopes, config.commonConfigs.AllowedScopes, plan.AllowedScopes, &plan.AllowedScopes) - updateSetAttributes(config.RedirectURIS, config.commonConfigs.RedirectUris, plan.RedirectURIS, &plan.RedirectURIS) - updateSetAttributes(config.AllowedLogoutUrls, config.commonConfigs.AllowedLogoutUrls, plan.AllowedLogoutUrls, &plan.AllowedLogoutUrls) - updateSetAttributes(config.AllowedWebOrigins, config.commonConfigs.AllowedWebOrigins, plan.AllowedWebOrigins, &plan.AllowedWebOrigins) - updateSetAttributes(config.AllowedOrigins, config.commonConfigs.AllowedOrigins, plan.AllowedOrigins, &plan.AllowedOrigins) - updateSetAttributes(config.LoginProviders, config.commonConfigs.LoginProviders, plan.LoginProviders, &plan.LoginProviders) - updateSetAttributes(config.DefaultScopes, config.commonConfigs.DefaultScopes, plan.DefaultScopes, &plan.DefaultScopes) - updateSetAttributes(config.PendingScopes, config.commonConfigs.PendingScopes, plan.PendingScopes, &plan.PendingScopes) - updateSetAttributes(config.AllowedMfa, config.commonConfigs.AllowedMfa, plan.AllowedMfa, &plan.AllowedMfa) - updateSetAttributes(config.AllowedRoles, config.commonConfigs.AllowedRoles, plan.AllowedRoles, &plan.AllowedRoles) - updateSetAttributes(config.DefaultRoles, config.commonConfigs.DefaultRoles, plan.DefaultRoles, &plan.DefaultRoles) - - // has default set value - if config.ResponseTypes.IsNull() { - if !config.commonConfigs.ResponseTypes.IsNull() { - plan.ResponseTypes = config.commonConfigs.ResponseTypes - } else if !plan.ResponseTypes.IsNull() && !plan.ResponseTypes.IsUnknown() { - plan.ResponseTypes = basetypes.NewSetValueMust(types.StringType, []attr.Value{ - types.StringValue("code"), types.StringValue("token"), types.StringValue("id_token"), - }) - } - } - if config.GrantTypes.IsNull() { - if !config.commonConfigs.GrantTypes.IsNull() { - plan.GrantTypes = config.commonConfigs.GrantTypes - } else if !plan.GrantTypes.IsNull() && !plan.GrantTypes.IsUnknown() { - plan.GrantTypes = basetypes.NewSetValueMust(types.StringType, []attr.Value{ - types.StringValue("implicit"), types.StringValue("authorization_code"), types.StringValue("password"), types.StringValue("refresh_token"), - }) - } - } - - if config.AllowLoginWith.IsNull() { - if !config.commonConfigs.AllowLoginWith.IsNull() { - plan.AllowLoginWith = config.commonConfigs.AllowLoginWith - } else if !plan.AllowLoginWith.IsNull() && !plan.AllowLoginWith.IsUnknown() { - plan.AllowLoginWith = basetypes.NewSetValueMust(types.StringType, []attr.Value{ - types.StringValue("EMAIL"), types.StringValue("MOBILE"), types.StringValue("USER_NAME"), - }) - } - } - - if config.Mfa.IsNull() { - if !config.commonConfigs.Mfa.IsNull() { - plan.Mfa = plan.commonConfigs.Mfa - } else if !plan.Mfa.IsNull() && !plan.Mfa.IsUnknown() { - mfa := types.ObjectValueMust( - map[string]attr.Type{ - "setting": types.StringType, - "time_interval_in_seconds": types.Int64Type, - "allowed_methods": types.SetType{ElemType: types.StringType}, - }, - map[string]attr.Value{ - "setting": types.StringValue("OFF"), - "time_interval_in_seconds": types.Int64Null(), - "allowed_methods": types.SetNull(types.StringType), - }, - ) - plan.Mfa = mfa - } - } - - if config.SocialProviders.IsNull() && !config.commonConfigs.SocialProviders.IsNull() { - plan.SocialProviders = plan.commonConfigs.SocialProviders - } - - if config.CustomProviders.IsNull() && !config.commonConfigs.CustomProviders.IsNull() { - plan.CustomProviders = plan.commonConfigs.CustomProviders - } - - if config.SamlProviders.IsNull() && !config.commonConfigs.SamlProviders.IsNull() { - plan.SamlProviders = plan.commonConfigs.SamlProviders - } - - if config.AdProviders.IsNull() && !config.commonConfigs.AdProviders.IsNull() { - plan.AdProviders = plan.commonConfigs.AdProviders - } - - if config.AllowedGroups.IsNull() && !config.commonConfigs.AllowedGroups.IsNull() { - plan.AllowedGroups = plan.commonConfigs.AllowedGroups - } - - if config.OperationsAllowedGroups.IsNull() && !config.commonConfigs.OperationsAllowedGroups.IsNull() { - plan.OperationsAllowedGroups = plan.commonConfigs.OperationsAllowedGroups - } - resp.Plan.Set(ctx, plan) -} diff --git a/internal/resources/resource_app_test.go b/internal/resources/resource_app_test.go index 09e54f2..8de763c 100644 --- a/internal/resources/resource_app_test.go +++ b/internal/resources/resource_app_test.go @@ -13,7 +13,6 @@ const ( resourceApp = "cidaas_app.example" ) -// create, read and update test func TestApp_Basic(t *testing.T) { clientName := acctest.RandString(10) resource.Test(t, resource.TestCase{ @@ -40,187 +39,106 @@ func TestApp_Basic(t *testing.T) { func testAppConfig(clientName, companyWebsite string) string { return fmt.Sprintf(` - provider "cidaas" { - base_url = "%s" - } - # The config below has the list of common config and main config -resource "cidaas_app" "example" { - client_name = "%s" // unique - client_display_name = "Display Name of the app" // unique - content_align = "CENTER" // Default: CENTER - post_logout_redirect_uris = ["https://cidaas.com"] - logo_align = "CENTER" // Default: CENTER - allow_disposable_email = false // Default: false - validate_phone_number = false // Default: false - additional_access_token_payload = ["sample_payload"] - required_fields = ["email"] - mobile_settings = { - team_id = "sample-team-id" - bundle_id = "sample-bundle-id" - package_name = "sample-package-name" - key_hash = "sample-key-hash" - } - // for custom client credentials use client_id and client_secret, you can leave blank if you want cidaas to create a set for you - # client_id = "" - # client_secret = "" - policy_uri = "https://cidaas.com" - tos_uri = "https://cidaas.com" - imprint_uri = "https://cidaas.com" - contacts = ["support@cidas.de"] - token_endpoint_auth_method = "client_secret_post" // Default: client_secret_post - token_endpoint_auth_signing_alg = "RS256" // Default: RS256 - default_acr_values = ["default"] - web_message_uris = ["https://cidaas.com"] - allowed_fields = ["email"] - smart_mfa = false // Default: false - captcha_ref = "sample-captcha-ref" - captcha_refs = ["sample"] - consent_refs = ["sample"] - communication_medium_verification = "email_verification_required_on_usage" - mobile_number_verification_required = false // Default: false - enable_bot_detection = false // Default: false - allow_guest_login_groups = [{ - group_id = "developer101" - roles = ["developer", "qa", "admin"] - default_roles = ["developer"] - }] - is_login_success_page_enabled = false // Default: false - is_register_success_page_enabled = false // Default: false - group_ids = ["sample"] - is_group_login_selection_enabled = false // Default: false - group_selection = { - selectable_groups = ["developer-users"] - selectable_group_types = ["sample"] - } - group_types = ["sample"] - logo_uri = "https://cidaas.com" - initiate_login_uri = "https://cidaas.com" - registration_client_uri = "https://cidaas.com" - registration_access_token = "registration access token" - client_uri = "https://cidaas.com" - jwks_uri = "https://cidaas.com" - jwks = "https://cidaas.com/jwks" - sector_identifier_uri = "https://cidaas.com" - subject_type = "sample subject type" - id_token_signed_response_alg = "RS256" - id_token_encrypted_response_alg = "RS256" - id_token_encrypted_response_enc = "example" - userinfo_signed_response_alg = "RS256" - userinfo_encrypted_response_alg = "RS256" - userinfo_encrypted_response_enc = "example" - request_object_signing_alg = "RS256" - request_object_encryption_alg = "RS256" - request_object_encryption_enc = "userinfo_encrypted_response_enc" - request_uris = ["sample"] - description = "app description" - consent_page_group = "sample-consent-page-group" - password_policy_ref = "password-policy-ref" - blocking_mechanism_ref = "blocking-mechanism-ref" - sub = "sample-sub" - role = "sample-role" - mfa_configuration = "sample-configuration" - suggest_mfa = ["OFF"] - login_spi = { - oauth_client_id = "bcb-4a6b-9777-8a64abe6af" - spi_url = "https://cidaas.com/spi-url" - } - background_uri = "https://cidaas.com" - video_url = "https://cidaas.com" - bot_captcha_ref = "sample-bot-captcha-ref" - application_meta_data = { - status : "active" - version : "1.0.0" - } - // common config starts here. The attributes from common config can be part of main config - // if an attribute is available both common_config and main config then attribute from the main config will be considered to create an app - common_configs = { - client_type = "SINGLE_PAGE" - accent_color = "#ef4923" // Default: #ef4923 - primary_color = "#ef4923" // Default: #f7941d - media_type = "IMAGE" // Default: IMAGE - allow_login_with = ["EMAIL", "MOBILE", "USER_NAME"] // Default: ["EMAIL", "MOBILE", "USER_NAME"] - redirect_uris = ["https://cidaas.com"] - allowed_logout_urls = ["https://cidaas.com"] - enable_deduplication = true // Default: false - auto_login_after_register = true // Default: false - enable_passwordless_auth = false // Default: true - register_with_login_information = false // Default: false - fds_enabled = false // Default: true - hosted_page_group = "default" // Default: default - company_name = "Widas ID GmbH" - company_address = "01" - company_website = "%s" - allowed_scopes = ["openid", "cidaas:register", "profile"] - response_types = ["code", "token", "id_token"] // Default: ["code", "token", "id_token"] - grant_types = ["client_credentials"] // Default: ["implicit", "authorization_code", "password", "refresh_token"] - login_providers = ["login_provider1", "login_provider2"] - is_hybrid_app = true // Default: false - allowed_web_origins = ["https://cidaas.com"] - allowed_origins = ["https://cidaas.com"] - default_max_age = 86400 // Default: 86400 - token_lifetime_in_seconds = 86400 // Default: 86400 - id_token_lifetime_in_seconds = 86400 // Default: 86400 - refresh_token_lifetime_in_seconds = 15780000 // Default: 15780000 - template_group_id = "custtemp" // Default: default - editable = true // Default: true - social_providers = [{ - provider_name = "cidaas social provider" - social_id = "fdc63bd0-6044-4fa0-abff" - display_name = "cidaas" - }] - custom_providers = [{ - logo_url = "https://cidaas.com/logo-url" - provider_name = "sample-custom-provider" - display_name = "sample-custom-provider" - type = "CUSTOM_OPENID_CONNECT" - }] - saml_providers = [{ - logo_url = "https://cidaas.com/logo-url" - provider_name = "sample-sampl-provider" - display_name = "sample-sampl-provider" - type = "SAMPL_IDP_PROVIDER" - }] - ad_providers = [{ - logo_url = "https://cidaas.com/logo-url" - provider_name = "sample-ad-provider" - display_name = "sample-ad-provider" - type = "ADD_PROVIDER" - }] - jwe_enabled = true // Default: false - user_consent = true // Default: false - allowed_groups = [{ - group_id = "developer101" - roles = ["developer", "qa", "admin"] - default_roles = ["developer"] - }] - operations_allowed_groups = [{ - group_id = "developer101" - roles = ["developer", "qa", "admin"] - default_roles = ["developer"] - }] - enabled = true // Default: true - always_ask_mfa = true // Default: false - allowed_mfa = ["OFF"] - email_verification_required = true // Default: true - allowed_roles = ["sample"] - default_roles = ["sample"] - enable_classical_provider = true // Default: true - is_remember_me_selected = true // Default: true - bot_provider = "CIDAAS" // Default: CIDAAS - allow_guest_login = true // Default: false - # mfa Default: - # { - # setting = "OFF" - # } - mfa = { - setting = "OFF" + provider "cidaas" { + base_url = "%s" } - webfinger = "no_redirection" - default_scopes = ["sample"] - pending_scopes = ["sample"] - } -} - `, os.Getenv("BASE_URL"), clientName, companyWebsite) + # The config below has the list of common config and main config + resource "cidaas_app" "example" { + client_name = "%s" + client_type = "SINGLE_PAGE" + redirect_uris = ["https://cidaas.com"] + allowed_logout_urls = ["https://cidaas.com"] + company_name = "Widas ID GmbH" + company_address = "01" + company_website = "%s" + allowed_scopes = ["openid", "cidaas:register", "profile"] + client_display_name = "Display Name of the app" + content_align = "CENTER" + post_logout_redirect_uris = ["https://cidaas.com"] + logo_align = "CENTER" + allow_disposable_email = false + validate_phone_number = false + additional_access_token_payload = ["sample_payload"] + required_fields = ["email"] + mobile_settings = { + team_id = "sample-team-id" + bundle_id = "sample-bundle-id" + package_name = "sample-package-name" + key_hash = "sample-key-hash" + } + policy_uri = "https://cidaas.com" + tos_uri = "https://cidaas.com" + imprint_uri = "https://cidaas.com" + contacts = ["support@cidas.de"] + token_endpoint_auth_method = "client_secret_post" + token_endpoint_auth_signing_alg = "RS256" + default_acr_values = ["default"] + web_message_uris = ["https://cidaas.com"] + allowed_fields = ["email"] + smart_mfa = false + captcha_ref = "sample-captcha-ref" + captcha_refs = ["sample"] + consent_refs = ["sample"] + communication_medium_verification = "email_verification_required_on_usage" + mobile_number_verification_required = false + enable_bot_detection = false + allow_guest_login_groups = [{ + group_id = "developer101" + roles = ["developer", "qa", "admin"] + default_roles = ["developer"] + }] + is_login_success_page_enabled = false + is_register_success_page_enabled = false + group_ids = ["sample"] + is_group_login_selection_enabled = false + group_selection = { + selectable_groups = ["developer-users"] + selectable_group_types = ["sample"] + } + group_types = ["sample"] + logo_uri = "https://cidaas.com" + initiate_login_uri = "https://cidaas.com" + registration_client_uri = "https://cidaas.com" + registration_access_token = "registration access token" + client_uri = "https://cidaas.com" + jwks_uri = "https://cidaas.com" + jwks = "https://cidaas.com/jwks" + sector_identifier_uri = "https://cidaas.com" + subject_type = "sample subject type" + id_token_signed_response_alg = "RS256" + id_token_encrypted_response_alg = "RS256" + id_token_encrypted_response_enc = "example" + userinfo_signed_response_alg = "RS256" + userinfo_encrypted_response_alg = "RS256" + userinfo_encrypted_response_enc = "example" + request_object_signing_alg = "RS256" + request_object_encryption_alg = "RS256" + request_object_encryption_enc = "userinfo_encrypted_response_enc" + request_uris = ["sample"] + description = "app description" + consent_page_group = "sample-consent-page-group" + password_policy_ref = "password-policy-ref" + blocking_mechanism_ref = "blocking-mechanism-ref" + sub = "sample-sub" + role = "sample-role" + mfa_configuration = "sample-configuration" + suggest_mfa = ["OFF"] + login_spi = { + oauth_client_id = "bcb-4a6b-9777-8a64abe6af" + spi_url = "https://cidaas.com/spi-url" + } + background_uri = "https://cidaas.com" + video_url = "https://cidaas.com" + bot_captcha_ref = "sample-bot-captcha-ref" + application_meta_data = { + status : "active" + version : "1.0.0" + } + }`, + os.Getenv("BASE_URL"), + clientName, + companyWebsite, + ) } func TestApp_CommonConfig(t *testing.T) { @@ -237,7 +155,7 @@ func TestApp_CommonConfig(t *testing.T) { resource "cidaas_app" "example" { client_type = "SINGLE_PAGE" client_name = "%s" - client_display_name = "The client Terraform Example App is a sample application designed to demonstrate the configuration of the terraform cidaas_app resource." + client_display_name = "sample client" company_address = "12 Wimsheim, Germany" company_website = "https://cidaas.de" allowed_scopes = ["profile"] @@ -246,7 +164,6 @@ func TestApp_CommonConfig(t *testing.T) { redirect_uris = ["https://ciddas.com"] group_selection = {} login_spi = {} - common_configs = {} } `, acctest.BaseURL, clientName), Check: resource.ComposeAggregateTestCheckFunc( diff --git a/internal/resources/resource_base.go b/internal/resources/resource_base.go new file mode 100644 index 0000000..b32f597 --- /dev/null +++ b/internal/resources/resource_base.go @@ -0,0 +1,103 @@ +package resources + +import ( + "context" + "fmt" + + "github.com/Cidaas/terraform-provider-cidaas/helpers/cidaas" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" +) + +// nolint:revive +const ( + RESOURCE_APP = "cidaas_app" // nolint:stylecheck + RESOURCE_CONSENT_GROUP = "cidaas_consent_group" // nolint:stylecheck + RESOURCE_CONSENT_VERSION = "cidaas_consent_version" // nolint:stylecheck + RESOURCE_CONSENT = "cidaas_consent" // nolint:stylecheck + RESOURCE_CUSTOM_PROVIDER = "cidaas_custom_provider" // nolint:stylecheck + RESOURCE_GROUP_TYPE = "cidaas_group_type" // nolint:stylecheck + RESOURCE_HOSTED_PAGE = "cidaas_hosted_page" // nolint:stylecheck + RESOURCE_PASSWORD_POLICY = "cidaas_password_policy" // nolint:stylecheck + RESOURCE_REGISTRATION_FIELD = "cidaas_registration_field" // nolint:stylecheck + RESOURCE_ROLE = "cidaas_role" // nolint:stylecheck + RESOURCE_SCOPE_GROUP = "cidaas_scope_group" // nolint:stylecheck + RESOURCE_SCOPE = "cidaas_scope" // nolint:stylecheck + RESOURCE_SOCIAL_PROVIDER = "cidaas_social_provider" // nolint:stylecheck + RESOURCE_TEMPLATE_GROUP = "cidaas_template_group" // nolint:stylecheck + RESOURCE_TEMPLATE = "cidaas_template" // nolint:stylecheck + RESOURCE_USER_GROUP = "cidaas_user_groups" // nolint:stylecheck + RESOURCE_WEBHOOK = "cidaas_webhook" // nolint:stylecheck +) + +type BaseResourceConfig struct { + Name string + Schema *schema.Schema +} + +type BaseResource struct { + Config BaseResourceConfig + cidaasClient *cidaas.Client +} + +func NewBaseResource(cfg BaseResourceConfig) BaseResource { + return BaseResource{ + Config: cfg, + } +} + +func (r *BaseResource) Configure( + _ context.Context, + req resource.ConfigureRequest, + resp *resource.ConfigureResponse, +) { + // Prevent panic if the provider has not been configured + if req.ProviderData == nil { + return + } + + r.cidaasClient = GetResourceMeta(req, resp) + if resp.Diagnostics.HasError() { + return + } +} + +func GetResourceMeta( + req resource.ConfigureRequest, + resp *resource.ConfigureResponse, +) *cidaas.Client { + client, ok := req.ProviderData.(*cidaas.Client) + + if !ok { + resp.Diagnostics.AddError( + "Unexpected Resource Configure Type", + fmt.Sprintf("Expected cidaas.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + return nil + } + return client +} + +func (r *BaseResource) Metadata( + _ context.Context, + _ resource.MetadataRequest, + resp *resource.MetadataResponse, +) { + resp.TypeName = r.Config.Name +} + +func (r *BaseResource) Schema( + _ context.Context, + _ resource.SchemaRequest, + resp *resource.SchemaResponse, +) { + if r.Config.Schema == nil { + resp.Diagnostics.AddError( + "Missing Schema", + "Base resource was not provided a schema. "+ + "Please provide a Schema config attribute or implement, the Schema(...) function.", + ) + return + } + resp.Schema = *r.Config.Schema +} diff --git a/internal/resources/resource_consent.go b/internal/resources/resource_consent.go index 2da3d35..95e9278 100644 --- a/internal/resources/resource_consent.go +++ b/internal/resources/resource_consent.go @@ -21,7 +21,18 @@ import ( ) type ConsentResource struct { - cidaasClient *cidaas.Client + BaseResource +} + +func NewConsentResource() resource.Resource { + return &ConsentResource{ + BaseResource: NewBaseResource( + BaseResourceConfig{ + Name: RESOURCE_CONSENT, + Schema: &consentSchema, + }, + ), + } } type ConsentConfig struct { @@ -33,83 +44,58 @@ type ConsentConfig struct { UpdatedAt types.String `tfsdk:"updated_at"` } -func NewConsentResource() resource.Resource { - return &ConsentResource{} -} - -func (r *ConsentResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_consent" -} - -func (r *ConsentResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - if req.ProviderData == nil { - return - } - client, ok := req.ProviderData.(*cidaas.Client) - if !ok { - resp.Diagnostics.AddError( - "Unexpected Resource Configure Type", - fmt.Sprintf("Expected cidaas.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), - ) - return - } - r.cidaasClient = client -} - -func (r *ConsentResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { - resp.Schema = schema.Schema{ - MarkdownDescription: "The Consent resource in the provider allows you to manage different consents within a specific consent group in Cidaas." + - "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + - "\n- cidaas:tenant_consent_read" + - "\n- cidaas:tenant_consent_write" + - "\n- cidaas:tenant_consent_delete", - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - MarkdownDescription: "The unique identifier of the consent resource.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, +var consentSchema = schema.Schema{ + MarkdownDescription: "The Consent resource in the provider allows you to manage different consents within a specific consent group in Cidaas." + + "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + + "\n- cidaas:tenant_consent_read" + + "\n- cidaas:tenant_consent_write" + + "\n- cidaas:tenant_consent_delete", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The unique identifier of the consent resource.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "name": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The name of the consent.", - Validators: []validator.String{ - stringvalidator.LengthAtLeast(1), - }, - PlanModifiers: []planmodifier.String{ - &validators.UniqueIdentifier{}, - }, + }, + "name": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The name of the consent.", + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), }, - "consent_group_id": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The `consent_group_id` to which the consent belongs.", - Validators: []validator.String{ - stringvalidator.LengthAtLeast(1), - }, - PlanModifiers: []planmodifier.String{ - &validators.UniqueIdentifier{}, - }, + PlanModifiers: []planmodifier.String{ + &validators.UniqueIdentifier{}, }, - "enabled": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The flag to enable or disable a speicific consent. By default, the value is set to `true`", - Default: booldefault.StaticBool(true), + }, + "consent_group_id": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The `consent_group_id` to which the consent belongs.", + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), }, - "created_at": schema.StringAttribute{ - Computed: true, - MarkdownDescription: "The timestamp when the consent version was created.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + PlanModifiers: []planmodifier.String{ + &validators.UniqueIdentifier{}, }, - "updated_at": schema.StringAttribute{ - Computed: true, - MarkdownDescription: "The timestamp when the consent version was last updated.", + }, + "enabled": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The flag to enable or disable a speicific consent. By default, the value is set to `true`", + Default: booldefault.StaticBool(true), + }, + "created_at": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The timestamp when the consent version was created.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, }, - } + "updated_at": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The timestamp when the consent version was last updated.", + }, + }, } func (r *ConsentResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { diff --git a/internal/resources/resource_consent_group.go b/internal/resources/resource_consent_group.go index 751a23c..316dfa3 100644 --- a/internal/resources/resource_consent_group.go +++ b/internal/resources/resource_consent_group.go @@ -18,7 +18,18 @@ import ( ) type ConsentGroupResource struct { - cidaasClient *cidaas.Client + BaseResource +} + +func NewConsentGroupResource() resource.Resource { + return &ConsentGroupResource{ + BaseResource: NewBaseResource( + BaseResourceConfig{ + Name: RESOURCE_CONSENT_GROUP, + Schema: &consentGroupSchema, + }, + ), + } } type ConsentGroupConfig struct { @@ -29,72 +40,47 @@ type ConsentGroupConfig struct { UpdatedAt types.String `tfsdk:"updated_at"` } -func NewConsentGroupResource() resource.Resource { - return &ConsentGroupResource{} -} - -func (r *ConsentGroupResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_consent_group" -} - -func (r *ConsentGroupResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - if req.ProviderData == nil { - return - } - client, ok := req.ProviderData.(*cidaas.Client) - if !ok { - resp.Diagnostics.AddError( - "Unexpected Resource Configure Type", - fmt.Sprintf("Expected cidaas.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), - ) - return - } - r.cidaasClient = client -} - -func (r *ConsentGroupResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { - resp.Schema = schema.Schema{ - MarkdownDescription: "The Consent Group resource in the provider allows you to define and manage consent groups in Cidaas." + - "\n Consent Groups are useful to organize and manage consents by grouping related consent items together." + - "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + - "\n- cidaas:tenant_consent_read" + - "\n- cidaas:tenant_consent_write" + - "\n- cidaas:tenant_consent_delete", - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - MarkdownDescription: "The unique identifier of the consent group.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "group_name": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The name of the consent group.", - Validators: []validator.String{ - stringvalidator.LengthAtLeast(1), - }, - PlanModifiers: []planmodifier.String{ - &validators.UniqueIdentifier{}, - }, +var consentGroupSchema = schema.Schema{ + MarkdownDescription: "The Consent Group resource in the provider allows you to define and manage consent groups in Cidaas." + + "\n Consent Groups are useful to organize and manage consents by grouping related consent items together." + + "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + + "\n- cidaas:tenant_consent_read" + + "\n- cidaas:tenant_consent_write" + + "\n- cidaas:tenant_consent_delete", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The unique identifier of the consent group.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "description": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "Description of the consent group.", + }, + "group_name": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The name of the consent group.", + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), }, - "created_at": schema.StringAttribute{ - Computed: true, - MarkdownDescription: "The timestamp when the consent group was created.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + PlanModifiers: []planmodifier.String{ + &validators.UniqueIdentifier{}, }, - "updated_at": schema.StringAttribute{ - Computed: true, - MarkdownDescription: "The timestamp when the consent group was last updated.", + }, + "description": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Description of the consent group.", + }, + "created_at": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The timestamp when the consent group was created.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, }, - } + "updated_at": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The timestamp when the consent group was last updated.", + }, + }, } func (r *ConsentGroupResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { diff --git a/internal/resources/resource_consent_version.go b/internal/resources/resource_consent_version.go index f61a833..e08dff9 100644 --- a/internal/resources/resource_consent_version.go +++ b/internal/resources/resource_consent_version.go @@ -27,7 +27,18 @@ const ( ) type ConsentVersionResource struct { - cidaasClient *cidaas.Client + BaseResource +} + +func NewConsentVersionResource() resource.Resource { + return &ConsentVersionResource{ + BaseResource: NewBaseResource( + BaseResourceConfig{ + Name: RESOURCE_CONSENT_VERSION, + Schema: &consentversionSchema, + }, + ), + } } type ConsentVersionConfig struct { @@ -48,29 +59,6 @@ type ConsentLocale struct { URL types.String `tfsdk:"url"` } -func NewConsentVersionResource() resource.Resource { - return &ConsentVersionResource{} -} - -func (r *ConsentVersionResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_consent_version" -} - -func (r *ConsentVersionResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - if req.ProviderData == nil { - return - } - client, ok := req.ProviderData.(*cidaas.Client) - if !ok { - resp.Diagnostics.AddError( - "Unexpected Resource Configure Type", - fmt.Sprintf("Expected cidaas.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), - ) - return - } - r.cidaasClient = client -} - func (r *ConsentVersionResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, res *resource.ValidateConfigResponse) { var config ConsentVersionConfig res.Diagnostics.Append(req.Config.Get(ctx, &config)...) @@ -107,96 +95,94 @@ func (r *ConsentVersionResource) ValidateConfig(ctx context.Context, req resourc } } -func (r *ConsentVersionResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { - resp.Schema = schema.Schema{ - MarkdownDescription: "The Consent Version resource in the provider allows you to manage different versions of a specific consent in Cidaas." + - "\n This resource also supports managing consent versions across multiple locales enabling different configurations such as URLs and content for each locale." + - "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + - "\n- cidaas:tenant_consent_read" + - "\n- cidaas:tenant_consent_write" + - "\n- cidaas:tenant_consent_delete", - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - MarkdownDescription: "The unique identifier of the consent version.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, +var consentversionSchema = schema.Schema{ + MarkdownDescription: "The Consent Version resource in the provider allows you to manage different versions of a specific consent in Cidaas." + + "\n This resource also supports managing consent versions across multiple locales enabling different configurations such as URLs and content for each locale." + + "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + + "\n- cidaas:tenant_consent_read" + + "\n- cidaas:tenant_consent_write" + + "\n- cidaas:tenant_consent_delete", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The unique identifier of the consent version.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "consent_type": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "Specifies the type of consent. The allowed values are `SCOPES` or `URL`. It can not be updated for a specific consent version.", - Validators: []validator.String{ - stringvalidator.OneOf(SCOPES, URL), - }, - PlanModifiers: []planmodifier.String{ - validators.UniqueIdentifier{}, - }, + }, + "consent_type": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Specifies the type of consent. The allowed values are `SCOPES` or `URL`. It can not be updated for a specific consent version.", + Validators: []validator.String{ + stringvalidator.OneOf(SCOPES, URL), }, - "consent_id": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The `consent_id` for which the consent version is created. It can not be updated for a specific consent version.", - PlanModifiers: []planmodifier.String{ - validators.UniqueIdentifier{}, - }, + PlanModifiers: []planmodifier.String{ + validators.UniqueIdentifier{}, }, - "version": schema.Float64Attribute{ - Required: true, - MarkdownDescription: "The version number of the consent. It can not be updated for a specific consent version.", - PlanModifiers: []planmodifier.Float64{ - validators.ImmutableInt64Identifier{}, - }, + }, + "consent_id": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The `consent_id` for which the consent version is created. It can not be updated for a specific consent version.", + PlanModifiers: []planmodifier.String{ + validators.UniqueIdentifier{}, }, - "scopes": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - MarkdownDescription: "A set of scopes related to the consent. It can not be updated for a specific consent version." + - "\nNote that the attribute `scopes` is required only if the `consent_type` is set to **SCOPES**.", - PlanModifiers: []planmodifier.Set{ - validators.ImmutableSetIdentifier{}, - }, + }, + "version": schema.Float64Attribute{ + Required: true, + MarkdownDescription: "The version number of the consent. It can not be updated for a specific consent version.", + PlanModifiers: []planmodifier.Float64{ + validators.ImmutableInt64Identifier{}, }, - "required_fields": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - MarkdownDescription: "A set of fields that are required for the consent. It can not be updated for a specific consent version." + - "\nNote that the attribute `required_fields` is required only if the `consent_type` is set to **SCOPES**.", - PlanModifiers: []planmodifier.Set{ - validators.ImmutableSetIdentifier{}, - }, + }, + "scopes": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + MarkdownDescription: "A set of scopes related to the consent. It can not be updated for a specific consent version." + + "\nNote that the attribute `scopes` is required only if the `consent_type` is set to **SCOPES**.", + PlanModifiers: []planmodifier.Set{ + validators.ImmutableSetIdentifier{}, }, - "consent_locales": schema.SetNestedAttribute{ - NestedObject: schema.NestedAttributeObject{ - Attributes: map[string]schema.Attribute{ - "content": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The content of the consent version associated with a specific locale.", - }, - "locale": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The locale for which the consent version is created. e.g. `en-us`, `de`.", - Validators: []validator.String{ - stringvalidator.OneOf( - func() []string { - validLocals := make([]string, len(util.Locals)) //nolint:gofumpt - for i, locale := range util.Locals { - validLocals[i] = strings.ToLower(locale.LocaleString) - } - return validLocals - }()...), - }, - }, - "url": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The url to the consent page of the created consent version." + - "\nNote that the attribute `url` is required only if the `consent_type` is set to **URL**.", + }, + "required_fields": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + MarkdownDescription: "A set of fields that are required for the consent. It can not be updated for a specific consent version." + + "\nNote that the attribute `required_fields` is required only if the `consent_type` is set to **SCOPES**.", + PlanModifiers: []planmodifier.Set{ + validators.ImmutableSetIdentifier{}, + }, + }, + "consent_locales": schema.SetNestedAttribute{ + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "content": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The content of the consent version associated with a specific locale.", + }, + "locale": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The locale for which the consent version is created. e.g. `en-us`, `de`.", + Validators: []validator.String{ + stringvalidator.OneOf( + func() []string { + validLocals := make([]string, len(util.Locals)) //nolint:gofumpt + for i, locale := range util.Locals { + validLocals[i] = strings.ToLower(locale.LocaleString) + } + return validLocals + }()...), }, }, + "url": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The url to the consent page of the created consent version." + + "\nNote that the attribute `url` is required only if the `consent_type` is set to **URL**.", + }, }, - Required: true, }, + Required: true, }, - } + }, } func (cv *ConsentVersionConfig) extract(ctx context.Context) diag.Diagnostics { diff --git a/internal/resources/resource_custom_provider.go b/internal/resources/resource_custom_provider.go index 77227ed..a7ee1ad 100644 --- a/internal/resources/resource_custom_provider.go +++ b/internal/resources/resource_custom_provider.go @@ -2,7 +2,6 @@ package resources import ( "context" - "fmt" "strings" "github.com/Cidaas/terraform-provider-cidaas/helpers/cidaas" @@ -24,7 +23,18 @@ import ( ) type CustomProvider struct { - cidaasClient *cidaas.Client + BaseResource +} + +func NewCustomProvider() resource.Resource { + return &CustomProvider{ + BaseResource: NewBaseResource( + BaseResourceConfig{ + Name: RESOURCE_CUSTOM_PROVIDER, + Schema: &customProviderSchema, + }, + ), + } } type ProviderConfig struct { @@ -78,10 +88,6 @@ type UserInfoField struct { CustomFields types.Map `tfsdk:"custom_fields"` } -func NewCustomProvider() resource.Resource { - return &CustomProvider{} -} - func (pc *ProviderConfig) extract(ctx context.Context) diag.Diagnostics { var diags diag.Diagnostics if !pc.UserinfoFields.IsNull() { @@ -95,192 +101,171 @@ func (pc *ProviderConfig) extract(ctx context.Context) diag.Diagnostics { return diags } -func (r *CustomProvider) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_custom_provider" -} - -func (r *CustomProvider) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - if req.ProviderData == nil { - return - } - client, ok := req.ProviderData.(*cidaas.Client) - if !ok { - resp.Diagnostics.AddError( - "Unexpected Resource Configure Type", - fmt.Sprintf("Expected cidaas.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), - ) - return - } - r.cidaasClient = client -} - -func (r *CustomProvider) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { - resp.Schema = schema.Schema{ - MarkdownDescription: "This example demonstrates the configuration of a custom provider resource for interacting with Cidaas." + - "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + - "\n- cidaas:providers_read" + - "\n- cidaas:providers_write" + - "\n- cidaas:providers_delete", - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - MarkdownDescription: "The ID of the resource.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "provider_name": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The unique identifier of the custom provider. This cannot be updated for an existing state.", - PlanModifiers: []planmodifier.String{ - &validators.UniqueIdentifier{}, - }, - }, - "display_name": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The display name of the provider.", - }, - "logo_url": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The URL for the provider's logo.", +var customProviderSchema = schema.Schema{ + MarkdownDescription: "This example demonstrates the configuration of a custom provider resource for interacting with Cidaas." + + "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + + "\n- cidaas:providers_read" + + "\n- cidaas:providers_write" + + "\n- cidaas:providers_delete", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The ID of the resource.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "standard_type": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "Type of standard. Allowed values `OAUTH2` and `OPENID_CONNECT`.", - Validators: []validator.String{ - stringvalidator.OneOf([]string{"OPENID_CONNECT", "OAUTH2"}...), - }, - }, - "client_id": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The client ID of the provider.", - }, - "client_secret": schema.StringAttribute{ - Required: true, - Sensitive: true, - MarkdownDescription: "The client secret of the provider.", - }, - "authorization_endpoint": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The URL for authorization of the provider.", - }, - "token_endpoint": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The URL to generate token with this provider.", - }, - "userinfo_endpoint": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The URL to fetch user details using this provider.", - }, - // In plan Set deletes an existing record and create a whole new one, so preferred list. However, to allow only unique values use set - "scopes": schema.ListNestedAttribute{ - MarkdownDescription: "List of scopes of the provider with details", - NestedObject: schema.NestedAttributeObject{ - Attributes: map[string]schema.Attribute{ - "scope_name": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The name of the scope, e.g., `openid`, `profile`.", - }, - "required": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Indicates if the scope is required.", - Default: booldefault.StaticBool(false), - }, - "recommended": schema.BoolAttribute{ - MarkdownDescription: "Indicates if the scope is recommended.", - Optional: true, - Computed: true, - Default: booldefault.StaticBool(false), - }, - }, - }, - Optional: true, + }, + "provider_name": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The unique identifier of the custom provider. This cannot be updated for an existing state.", + PlanModifiers: []planmodifier.String{ + &validators.UniqueIdentifier{}, }, - "scope_display_label": schema.StringAttribute{ - Required: true, - MarkdownDescription: "Display label for the scope of the provider.", + }, + "display_name": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The display name of the provider.", + }, + "logo_url": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The URL for the provider's logo.", + }, + "standard_type": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Type of standard. Allowed values `OAUTH2` and `OPENID_CONNECT`.", + Validators: []validator.String{ + stringvalidator.OneOf([]string{"OPENID_CONNECT", "OAUTH2"}...), }, - "userinfo_fields": schema.SingleNestedAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Object containing various user information fields with their values." + - " The userinfo_fields section includes specific fields such as name, family_name, address, etc., along with custom_fields allowing additional user information customization", + }, + "client_id": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The client ID of the provider.", + }, + "client_secret": schema.StringAttribute{ + Required: true, + Sensitive: true, + MarkdownDescription: "The client secret of the provider.", + }, + "authorization_endpoint": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The URL for authorization of the provider.", + }, + "token_endpoint": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The URL to generate token with this provider.", + }, + "userinfo_endpoint": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The URL to fetch user details using this provider.", + }, + // In plan Set deletes an existing record and create a whole new one, so preferred list. However, to allow only unique values use set + "scopes": schema.ListNestedAttribute{ + MarkdownDescription: "List of scopes of the provider with details", + NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ - "name": schema.StringAttribute{ - Optional: true, - }, - "family_name": schema.StringAttribute{ - Optional: true, - }, - "given_name": schema.StringAttribute{ - Optional: true, + "scope_name": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The name of the scope, e.g., `openid`, `profile`.", }, - "middle_name": schema.StringAttribute{ - Optional: true, + "required": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Indicates if the scope is required.", + Default: booldefault.StaticBool(false), }, - "nickname": schema.StringAttribute{ - Optional: true, - }, - "preferred_username": schema.StringAttribute{ - Optional: true, - }, - "profile": schema.StringAttribute{ - Optional: true, - }, - "picture": schema.StringAttribute{ - Optional: true, - }, - "website": schema.StringAttribute{ - Optional: true, - }, - "gender": schema.StringAttribute{ - Optional: true, - }, - "birthdate": schema.StringAttribute{ - Optional: true, - }, - "zoneinfo": schema.StringAttribute{ - Optional: true, - }, - "locale": schema.StringAttribute{ - Optional: true, - }, - "updated_at": schema.StringAttribute{ - Optional: true, - }, - "email": schema.StringAttribute{ - Optional: true, - }, - "email_verified": schema.StringAttribute{ - Optional: true, - }, - "phone_number": schema.StringAttribute{ - Optional: true, - }, - "mobile_number": schema.StringAttribute{ - Optional: true, - }, - "address": schema.StringAttribute{ - Optional: true, - }, - "sub": schema.StringAttribute{ - Optional: true, - }, - "custom_fields": schema.MapAttribute{ - ElementType: types.StringType, - Optional: true, + "recommended": schema.BoolAttribute{ + MarkdownDescription: "Indicates if the scope is recommended.", + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), }, }, - Default: objectdefault.StaticValue(userInfoDefaultValue()), }, - "domains": schema.SetAttribute{ - ElementType: types.StringType, - MarkdownDescription: "The domains of the provider.", - Optional: true, + Optional: true, + }, + "scope_display_label": schema.StringAttribute{ + Required: true, + MarkdownDescription: "Display label for the scope of the provider.", + }, + "userinfo_fields": schema.SingleNestedAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Object containing various user information fields with their values." + + " The userinfo_fields section includes specific fields such as name, family_name, address, etc., along with custom_fields allowing additional user information customization", + Attributes: map[string]schema.Attribute{ + "name": schema.StringAttribute{ + Optional: true, + }, + "family_name": schema.StringAttribute{ + Optional: true, + }, + "given_name": schema.StringAttribute{ + Optional: true, + }, + "middle_name": schema.StringAttribute{ + Optional: true, + }, + "nickname": schema.StringAttribute{ + Optional: true, + }, + "preferred_username": schema.StringAttribute{ + Optional: true, + }, + "profile": schema.StringAttribute{ + Optional: true, + }, + "picture": schema.StringAttribute{ + Optional: true, + }, + "website": schema.StringAttribute{ + Optional: true, + }, + "gender": schema.StringAttribute{ + Optional: true, + }, + "birthdate": schema.StringAttribute{ + Optional: true, + }, + "zoneinfo": schema.StringAttribute{ + Optional: true, + }, + "locale": schema.StringAttribute{ + Optional: true, + }, + "updated_at": schema.StringAttribute{ + Optional: true, + }, + "email": schema.StringAttribute{ + Optional: true, + }, + "email_verified": schema.StringAttribute{ + Optional: true, + }, + "phone_number": schema.StringAttribute{ + Optional: true, + }, + "mobile_number": schema.StringAttribute{ + Optional: true, + }, + "address": schema.StringAttribute{ + Optional: true, + }, + "sub": schema.StringAttribute{ + Optional: true, + }, + "custom_fields": schema.MapAttribute{ + ElementType: types.StringType, + Optional: true, + }, }, + Default: objectdefault.StaticValue(userInfoDefaultValue()), }, - } + "domains": schema.SetAttribute{ + ElementType: types.StringType, + MarkdownDescription: "The domains of the provider.", + Optional: true, + }, + }, } func (r *CustomProvider) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { diff --git a/internal/resources/resource_group_type.go b/internal/resources/resource_group_type.go index f317f52..661ea08 100644 --- a/internal/resources/resource_group_type.go +++ b/internal/resources/resource_group_type.go @@ -1,4 +1,4 @@ -// user_group_category is changed to group_type +// previously user_group_category package resources import ( @@ -20,7 +20,18 @@ import ( ) type GroupTypeResource struct { - cidaasClient *cidaas.Client + BaseResource +} + +func NewGroupTypeResource() resource.Resource { + return &GroupTypeResource{ + BaseResource: NewBaseResource( + BaseResourceConfig{ + Name: RESOURCE_GROUP_TYPE, + Schema: &groupTypeSchema, + }, + ), + } } type GroupTypeConfig struct { @@ -33,92 +44,65 @@ type GroupTypeConfig struct { UpdatedAt types.String `tfsdk:"updated_at"` } -type allowedRolesValidator struct{} - -func NewGroupTypeResource() resource.Resource { - return &GroupTypeResource{} -} - -func (r *GroupTypeResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_group_type" -} - -func (r *GroupTypeResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - if req.ProviderData == nil { - return - } - client, ok := req.ProviderData.(*cidaas.Client) - if !ok { - resp.Diagnostics.AddError( - "Unexpected Resource Configure Type", - fmt.Sprintf("Expected cidaas.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), - ) - return - } - r.cidaasClient = client -} - -func (r *GroupTypeResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { - resp.Schema = schema.Schema{ - MarkdownDescription: "The Group Type, managed through the `cidaas_group_type` resource in the provider defines and configures categories for user groups within the Cidaas system." + - "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + - "\n- cidaas:group_type_read" + - "\n- cidaas:group_type_write" + - "\n- cidaas:group_type_delete", - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - Description: "The ID of the resource.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, +var groupTypeSchema = schema.Schema{ + MarkdownDescription: "The Group Type, managed through the `cidaas_group_type` resource in the provider defines and configures categories for user groups within the Cidaas system." + + "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + + "\n- cidaas:group_type_read" + + "\n- cidaas:group_type_write" + + "\n- cidaas:group_type_delete", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + Description: "The ID of the resource.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "role_mode": schema.StringAttribute{ - Required: true, - MarkdownDescription: "Determines the role mode for the user group type. Allowed values are `any_roles`, `no_roles`, `roles_required` and `allowed_roles`", - Validators: []validator.String{ - stringvalidator.OneOf([]string{"any_roles", "no_roles", "roles_required", "allowed_roles"}...), - }, + }, + "role_mode": schema.StringAttribute{ + Required: true, + MarkdownDescription: "Determines the role mode for the user group type. Allowed values are `any_roles`, `no_roles`, `roles_required` and `allowed_roles`", + Validators: []validator.String{ + stringvalidator.OneOf([]string{"any_roles", "no_roles", "roles_required", "allowed_roles"}...), }, - // TODO: description is a required parameter in admin ui - "description": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The `description` attribute provides details about the group type, explaining its purpose.", + }, + // TODO: description is a required parameter in admin ui + "description": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The `description` attribute provides details about the group type, explaining its purpose.", + }, + "group_type": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The unique identifier of the group type. This cannot be updated for an existing state.", + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), }, - "group_type": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The unique identifier of the group type. This cannot be updated for an existing state.", - Validators: []validator.String{ - stringvalidator.LengthAtLeast(1), - }, - PlanModifiers: []planmodifier.String{ - &validators.UniqueIdentifier{}, - }, + PlanModifiers: []planmodifier.String{ + &validators.UniqueIdentifier{}, }, - "allowed_roles": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - MarkdownDescription: "List of allowed roles in this group type.", - Validators: []validator.Set{ - &allowedRolesValidator{}, - }, + }, + "allowed_roles": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + MarkdownDescription: "List of allowed roles in this group type.", + Validators: []validator.Set{ + &allowedRolesValidator{}, }, - "created_at": schema.StringAttribute{ - Computed: true, - Description: "The timestamp when the resource was created.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + }, + "created_at": schema.StringAttribute{ + Computed: true, + Description: "The timestamp when the resource was created.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "updated_at": schema.StringAttribute{ - Computed: true, - Description: "The timestamp when the resource was last updated.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + }, + "updated_at": schema.StringAttribute{ + Computed: true, + Description: "The timestamp when the resource was last updated.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, }, - } + }, } func (r *GroupTypeResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { @@ -206,6 +190,8 @@ func (r *GroupTypeResource) ImportState(ctx context.Context, req resource.Import resource.ImportStatePassthroughID(ctx, path.Root("group_type"), req, resp) } +type allowedRolesValidator struct{} + func (v allowedRolesValidator) Description(_ context.Context) string { return "Validates allowed_roles if required" } diff --git a/internal/resources/resource_hosted_page.go b/internal/resources/resource_hosted_page.go index 59ccd45..5d4cefa 100644 --- a/internal/resources/resource_hosted_page.go +++ b/internal/resources/resource_hosted_page.go @@ -2,7 +2,6 @@ package resources import ( "context" - "fmt" "github.com/Cidaas/terraform-provider-cidaas/helpers/cidaas" "github.com/Cidaas/terraform-provider-cidaas/helpers/util" @@ -31,7 +30,18 @@ var allowedHotedPageIDs = []string{ const GroupOwner = "client" type HostedPageResource struct { - cidaasClient *cidaas.Client + BaseResource +} + +func NewHostedPageResource() resource.Resource { + return &HostedPageResource{ + BaseResource: NewBaseResource( + BaseResourceConfig{ + Name: RESOURCE_HOSTED_PAGE, + Schema: &hostedPageSchema, + }, + ), + } } type HostedPageConfig struct { @@ -51,10 +61,6 @@ type HostedPage struct { Content types.String `tfsdk:"content"` } -func NewHostedPageResource() resource.Resource { - return &HostedPageResource{} -} - func (h *HostedPageConfig) extractHostedPages(ctx context.Context) diag.Diagnostics { var diags diag.Diagnostics @@ -65,126 +71,105 @@ func (h *HostedPageConfig) extractHostedPages(ctx context.Context) diag.Diagnost return diags } -func (r *HostedPageResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_hosted_page" -} - -func (r *HostedPageResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - if req.ProviderData == nil { - return - } - client, ok := req.ProviderData.(*cidaas.Client) - if !ok { - resp.Diagnostics.AddError( - "Unexpected Resource Configure Type", - fmt.Sprintf("Expected cidaas.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), - ) - return - } - r.cidaasClient = client -} - -func (r *HostedPageResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { - resp.Schema = schema.Schema{ - MarkdownDescription: "The Hosted Page resource in the provider allows you to define and manage hosted pages within the Cidaas system." + - "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + - "\n- cidaas:hosted_pages_write" + - "\n- cidaas:hosted_pages_read" + - "\n- cidaas:hosted_pages_delete", - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - Description: "The ID of the resource.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, +var hostedPageSchema = schema.Schema{ + MarkdownDescription: "The Hosted Page resource in the provider allows you to define and manage hosted pages within the Cidaas system." + + "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + + "\n- cidaas:hosted_pages_write" + + "\n- cidaas:hosted_pages_read" + + "\n- cidaas:hosted_pages_delete", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + Description: "The ID of the resource.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "hosted_page_group_name": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The name of the hosted page group. This must be unique across the cidaas system and cannot be updated for an existing state.", - Validators: []validator.String{ - stringvalidator.LengthAtLeast(1), - }, - PlanModifiers: []planmodifier.String{ - &validators.UniqueIdentifier{}, - }, + }, + "hosted_page_group_name": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The name of the hosted page group. This must be unique across the cidaas system and cannot be updated for an existing state.", + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), }, - "default_locale": schema.StringAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The default locale for hosted pages e.g. `en-US`.", - Default: stringdefault.StaticString("en"), - Validators: []validator.String{ - stringvalidator.OneOf( - func() []string { - validLocals := make([]string, len(util.Locals)) - for i, locale := range util.Locals { - validLocals[i] = locale.LocaleString - } - return validLocals - }()...), - }, - // if hosted_page not found by the local provided in the hosted_pages map, the api throws ambigious data error. - // TODO: add a custom plan modifier later to validate the same and throw plan time error + PlanModifiers: []planmodifier.String{ + &validators.UniqueIdentifier{}, }, - "hosted_pages": schema.ListNestedAttribute{ - Required: true, - MarkdownDescription: "List of hosted pages with their respective attributes", - Validators: []validator.List{ - listvalidator.SizeAtLeast(1), - }, - NestedObject: schema.NestedAttributeObject{ - Attributes: map[string]schema.Attribute{ - "hosted_page_id": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The identifier for the hosted page, e.g., `register_success`.", - Validators: []validator.String{ - stringvalidator.OneOf(allowedHotedPageIDs...), - }, - }, - "locale": schema.StringAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The locale for the hosted page, e.g., `en-US`.", - Default: stringdefault.StaticString("en"), - Validators: []validator.String{ - stringvalidator.OneOf( - func() []string { - validLocals := make([]string, len(util.Locals)) - for i, locale := range util.Locals { - validLocals[i] = locale.LocaleString - } - return validLocals - }()...), - }, - }, - "url": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The URL for the hosted page.", + }, + "default_locale": schema.StringAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The default locale for hosted pages e.g. `en-US`.", + Default: stringdefault.StaticString("en"), + Validators: []validator.String{ + stringvalidator.OneOf( + func() []string { + validLocals := make([]string, len(util.Locals)) + for i, locale := range util.Locals { + validLocals[i] = locale.LocaleString + } + return validLocals + }()...), + }, + // if hosted_page not found by the local provided in the hosted_pages map, the api throws ambigious data error. + // TODO: add a custom plan modifier later to validate the same and throw plan time error + }, + "hosted_pages": schema.ListNestedAttribute{ + Required: true, + MarkdownDescription: "List of hosted pages with their respective attributes", + Validators: []validator.List{ + listvalidator.SizeAtLeast(1), + }, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "hosted_page_id": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The identifier for the hosted page, e.g., `register_success`.", + Validators: []validator.String{ + stringvalidator.OneOf(allowedHotedPageIDs...), }, - "content": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The conent of the hosted page.", + }, + "locale": schema.StringAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The locale for the hosted page, e.g., `en-US`.", + Default: stringdefault.StaticString("en"), + Validators: []validator.String{ + stringvalidator.OneOf( + func() []string { + validLocals := make([]string, len(util.Locals)) + for i, locale := range util.Locals { + validLocals[i] = locale.LocaleString + } + return validLocals + }()...), }, }, + "url": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The URL for the hosted page.", + }, + "content": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The conent of the hosted page.", + }, }, }, - "created_at": schema.StringAttribute{ - Computed: true, - Description: "The timestamp when the resource was created.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + }, + "created_at": schema.StringAttribute{ + Computed: true, + Description: "The timestamp when the resource was created.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "updated_at": schema.StringAttribute{ - Computed: true, - Description: "The timestamp when the resource was last updated.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + }, + "updated_at": schema.StringAttribute{ + Computed: true, + Description: "The timestamp when the resource was last updated.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, }, - } + }, } func (r *HostedPageResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { //nolint:dupl diff --git a/internal/resources/resource_password_policy.go b/internal/resources/resource_password_policy.go index 9ff1f13..c6d4614 100644 --- a/internal/resources/resource_password_policy.go +++ b/internal/resources/resource_password_policy.go @@ -16,7 +16,18 @@ import ( ) type PasswordPolicy struct { - cidaasClient *cidaas.Client + BaseResource +} + +func NewPasswordPolicy() resource.Resource { + return &PasswordPolicy{ + BaseResource: NewBaseResource( + BaseResourceConfig{ + Name: RESOURCE_PASSWORD_POLICY, + Schema: &passwordPolicySchema, + }, + ), + } } type PasswordPolicyConfig struct { @@ -29,80 +40,55 @@ type PasswordPolicyConfig struct { LowerAndUppercase types.Bool `tfsdk:"lower_and_uppercase"` } -func NewPasswordPolicy() resource.Resource { - return &PasswordPolicy{} -} - -func (r *PasswordPolicy) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_password_policy" -} - -func (r *PasswordPolicy) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - if req.ProviderData == nil { - return - } - client, ok := req.ProviderData.(*cidaas.Client) - if !ok { - resp.Diagnostics.AddError( - "Unexpected Resource Configure Type", - fmt.Sprintf("Expected cidaas.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), - ) - return - } - r.cidaasClient = client -} - -func (r *PasswordPolicy) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { - resp.Schema = schema.Schema{ - MarkdownDescription: "The Password Policy resource in the provider allows you to manage the password policy within the Cidaas." + - "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + - "\n- cidaas:password_policy_read" + - "\n- cidaas:password_policy_write" + - "\n- cidaas:password_policy_delete", - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - MarkdownDescription: "Unique identifier of the password policy.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "policy_name": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The name of the password policy.", - }, - "maximum_length": schema.Int64Attribute{ - Required: true, - MarkdownDescription: "The maximum length allowed for the password. The `maximum_length` must be at least sum of `minimum_length`, `no_of_special_chars`, `no_of_digits` and `lower_and_uppercase(1)` ", - Validators: []validator.Int64{ - int64validator.AtLeastSumOf( - path.MatchRoot("minimum_length"), - path.MatchRoot("no_of_special_chars"), - path.MatchRoot("no_of_digits"), - ), - }, +var passwordPolicySchema = schema.Schema{ + MarkdownDescription: "The Password Policy resource in the provider allows you to manage the password policy within the Cidaas." + + "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + + "\n- cidaas:password_policy_read" + + "\n- cidaas:password_policy_write" + + "\n- cidaas:password_policy_delete", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "Unique identifier of the password policy.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "minimum_length": schema.Int64Attribute{ - Required: true, - MarkdownDescription: "The minimum length required for the password. The `minimum_length` must be greater than or equal to 5.", - Validators: []validator.Int64{ - int64validator.AtLeast(5), - }, - }, - "no_of_special_chars": schema.Int64Attribute{ - Required: true, - MarkdownDescription: "The required number of special characters in the password.", - }, - "no_of_digits": schema.Int64Attribute{ - Required: true, - MarkdownDescription: "The required number of digits in the password.", + }, + "policy_name": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The name of the password policy.", + }, + "maximum_length": schema.Int64Attribute{ + Required: true, + MarkdownDescription: "The maximum length allowed for the password. The `maximum_length` must be at least sum of `minimum_length`, `no_of_special_chars`, `no_of_digits` and `lower_and_uppercase(1)` ", + Validators: []validator.Int64{ + int64validator.AtLeastSumOf( + path.MatchRoot("minimum_length"), + path.MatchRoot("no_of_special_chars"), + path.MatchRoot("no_of_digits"), + ), }, - "lower_and_uppercase": schema.BoolAttribute{ - Required: true, - MarkdownDescription: "Specifies whether the password must contain both lowercase and uppercase letters.", + }, + "minimum_length": schema.Int64Attribute{ + Required: true, + MarkdownDescription: "The minimum length required for the password. The `minimum_length` must be greater than or equal to 5.", + Validators: []validator.Int64{ + int64validator.AtLeast(5), }, }, - } + "no_of_special_chars": schema.Int64Attribute{ + Required: true, + MarkdownDescription: "The required number of special characters in the password.", + }, + "no_of_digits": schema.Int64Attribute{ + Required: true, + MarkdownDescription: "The required number of digits in the password.", + }, + "lower_and_uppercase": schema.BoolAttribute{ + Required: true, + MarkdownDescription: "Specifies whether the password must contain both lowercase and uppercase letters.", + }, + }, } func (r *PasswordPolicy) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { diff --git a/internal/resources/resource_registration_field.go b/internal/resources/resource_registration_field.go index 1f9a016..75030da 100644 --- a/internal/resources/resource_registration_field.go +++ b/internal/resources/resource_registration_field.go @@ -33,6 +33,21 @@ var allowedDataTypes = []string{ "TEXTAREA", "MOBILE", "CONSENT", "JSON_STRING", "USERNAME", "ARRAY", "GROUPING", "DAYDATE", } +type RegFieldResource struct { + BaseResource +} + +func NewRegFieldResource() resource.Resource { + return &RegFieldResource{ + BaseResource: NewBaseResource( + BaseResourceConfig{ + Name: RESOURCE_REGISTRATION_FIELD, + Schema: ®FieldSchema, + }, + ), + } +} + type RegFieldConfig struct { ID types.String `tfsdk:"id"` BaseDataType types.String `tfsdk:"base_data_type"` @@ -92,330 +107,301 @@ type FieldDefinition struct { InitialDate types.String `tfsdk:"initial_date"` } -type RegFieldResource struct { - cidaasClient *cidaas.Client -} - -func NewRegFieldResource() resource.Resource { - return &RegFieldResource{} -} - -func (r *RegFieldResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_registration_field" -} - -func (r *RegFieldResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - if req.ProviderData == nil { - return - } - client, ok := req.ProviderData.(*cidaas.Client) - if !ok { - resp.Diagnostics.AddError( - "Unexpected Resource Configure Type", - fmt.Sprintf("Expected cidaas.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), - ) - return - } - r.cidaasClient = client -} - -func (r *RegFieldResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { - resp.Schema = schema.Schema{ - MarkdownDescription: "The `cidaas_registration_page_field` in the provider allows management of registration fields in the Cidaas system." + - " This resource enables you to configure and customize the fields displayed during user registration." + - "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + - "\n- cidaas:field_setup_read" + - "\n- cidaas:field_setup_write" + - "\n- cidaas:field_setup_delete\n", - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - MarkdownDescription: "The ID of the resource", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, +var regFieldSchema = schema.Schema{ + MarkdownDescription: "The `cidaas_registration_page_field` in the provider allows management of registration fields in the Cidaas system." + + " This resource enables you to configure and customize the fields displayed during user registration." + + "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + + "\n- cidaas:field_setup_read" + + "\n- cidaas:field_setup_write" + + "\n- cidaas:field_setup_delete\n", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The ID of the resource", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - // "string", "double", "datetime", "bool", "array" - "base_data_type": schema.StringAttribute{ - Computed: true, - MarkdownDescription: "The base data type of the field. This is computed property.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "parent_group_id": schema.StringAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The ID of the parent registration group. Defaults to `DEFAULT` if not provided.", - Default: stringdefault.StaticString("DEFAULT"), - }, - "field_type": schema.StringAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Specifies whether the field type is `SYSTEM` or `CUSTOM`. Defaults to `CUSTOM`." + - " This cannot be modified for an existing resource. `SYSTEM` fields cannot be created but can be modified. To modify an existing field import it first and then update.", - Default: stringdefault.StaticString("CUSTOM"), - Validators: []validator.String{ - stringvalidator.OneOf([]string{"CUSTOM", "SYSTEM"}...), - }, - PlanModifiers: []planmodifier.String{ - &validators.UniqueIdentifier{}, - &fieldTypeModifier{}, - }, - }, - "data_type": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The data type of the field. This cannot be modified for an existing resource." + - fmt.Sprintf(" Allowed values are %s", func() string { - var temp string - for _, v := range allowedDataTypes { - temp += fmt.Sprintf("`%s`,", v) - } - return temp - }()), - Validators: []validator.String{ - stringvalidator.OneOf(allowedDataTypes...), - &dataTypeValidator{}, - }, - PlanModifiers: []planmodifier.String{ - &validators.UniqueIdentifier{}, - }, - }, - "field_key": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The unique identifier of the registration field. This cannot be modified for an existing resource.", - Validators: []validator.String{ - stringvalidator.LengthAtLeast(1), - }, - PlanModifiers: []planmodifier.String{ - &validators.UniqueIdentifier{}, - }, - }, - "required": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Flag to mark if a field is required in registration. Defaults set to `false`", - Default: booldefault.StaticBool(false), - Validators: []validator.Bool{ - &validateIsRequiredMsgAvailable{}, - }, - }, - "internal": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Flag to mark if a field is internal. Defaults set to `false`", - Default: booldefault.StaticBool(false), - }, - "claimable": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Flag to mark if a field is claimable. Defaults set to `true`", - Default: booldefault.StaticBool(true), - }, - "is_searchable": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Flag to mark if a field is searchable. Defaults set to `true`", - Default: booldefault.StaticBool(true), + }, + // "string", "double", "datetime", "bool", "array" + "base_data_type": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The base data type of the field. This is computed property.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "enabled": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Flag to mark if a field is enabled. Defaults set to `true`", - Default: booldefault.StaticBool(true), + }, + "parent_group_id": schema.StringAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The ID of the parent registration group. Defaults to `DEFAULT` if not provided.", + Default: stringdefault.StaticString("DEFAULT"), + }, + "field_type": schema.StringAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Specifies whether the field type is `SYSTEM` or `CUSTOM`. Defaults to `CUSTOM`." + + " This cannot be modified for an existing resource. `SYSTEM` fields cannot be created but can be modified. To modify an existing field import it first and then update.", + Default: stringdefault.StaticString("CUSTOM"), + Validators: []validator.String{ + stringvalidator.OneOf([]string{"CUSTOM", "SYSTEM"}...), }, - "unique": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Flag to mark if a field is unique. Defaults set to `false`", - Default: booldefault.StaticBool(false), + PlanModifiers: []planmodifier.String{ + &validators.UniqueIdentifier{}, + &fieldTypeModifier{}, }, - // set to true if you want the value should be reset by identity provider - "overwrite_with_null_value_from_social_provider": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Set to true if you want the value should be reset by identity provider. Defaults set to `false`", - Default: booldefault.StaticBool(false), + }, + "data_type": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The data type of the field. This cannot be modified for an existing resource." + + fmt.Sprintf(" Allowed values are %s", func() string { + var temp string + for _, v := range allowedDataTypes { + temp += fmt.Sprintf("`%s`,", v) + } + return temp + }()), + Validators: []validator.String{ + stringvalidator.OneOf(allowedDataTypes...), + &dataTypeValidator{}, }, - "read_only": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Flag to mark if a field is read only. Defaults set to `false`", - Default: booldefault.StaticBool(false), + PlanModifiers: []planmodifier.String{ + &validators.UniqueIdentifier{}, }, - "is_group": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Setting is_group to `true` creates a registration field group. Defaults set to `false`" + - " The data_type attribute must be set to TEXT when is_group is true. ", - Default: booldefault.StaticBool(false), - Validators: []validator.Bool{ - &isGroupValidator{}, - }, + }, + "field_key": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The unique identifier of the registration field. This cannot be modified for an existing resource.", + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), }, - "is_list": schema.BoolAttribute{ - Optional: true, - Computed: true, - Default: booldefault.StaticBool(false), + PlanModifiers: []planmodifier.String{ + &validators.UniqueIdentifier{}, }, - // optional: Order of the Field in the UI - "order": schema.Int64Attribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The attribute order is used to set the order of the Field in the UI. Defaults set to `1`", - Default: int64default.StaticInt64(1), - Validators: []validator.Int64{ - int64validator.AtLeast(1), - }, + }, + "required": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Flag to mark if a field is required in registration. Defaults set to `false`", + Default: booldefault.StaticBool(false), + Validators: []validator.Bool{ + &validateIsRequiredMsgAvailable{}, }, - "scopes": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - MarkdownDescription: "The scopes of the registration field.", + }, + "internal": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Flag to mark if a field is internal. Defaults set to `false`", + Default: booldefault.StaticBool(false), + }, + "claimable": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Flag to mark if a field is claimable. Defaults set to `true`", + Default: booldefault.StaticBool(true), + }, + "is_searchable": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Flag to mark if a field is searchable. Defaults set to `true`", + Default: booldefault.StaticBool(true), + }, + "enabled": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Flag to mark if a field is enabled. Defaults set to `true`", + Default: booldefault.StaticBool(true), + }, + "unique": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Flag to mark if a field is unique. Defaults set to `false`", + Default: booldefault.StaticBool(false), + }, + // set to true if you want the value should be reset by identity provider + "overwrite_with_null_value_from_social_provider": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Set to true if you want the value should be reset by identity provider. Defaults set to `false`", + Default: booldefault.StaticBool(false), + }, + "read_only": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Flag to mark if a field is read only. Defaults set to `false`", + Default: booldefault.StaticBool(false), + }, + "is_group": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Setting is_group to `true` creates a registration field group. Defaults set to `false`" + + " The data_type attribute must be set to TEXT when is_group is true. ", + Default: booldefault.StaticBool(false), + Validators: []validator.Bool{ + &isGroupValidator{}, }, - "consent_refs": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - MarkdownDescription: "List of consents(the ids of the consent in cidaas must be passed) in registration. The data type must be `CONSENT` in this case", + }, + "is_list": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), + }, + // optional: Order of the Field in the UI + "order": schema.Int64Attribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The attribute order is used to set the order of the Field in the UI. Defaults set to `1`", + Default: int64default.StaticInt64(1), + Validators: []validator.Int64{ + int64validator.AtLeast(1), }, - "local_texts": schema.ListNestedAttribute{ - Required: true, - MarkdownDescription: "The localized detail of the registration field.", - NestedObject: schema.NestedAttributeObject{ - Attributes: map[string]schema.Attribute{ - "locale": schema.StringAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The locale of the field. example: de-DE.", - Default: stringdefault.StaticString("en"), - Validators: []validator.String{ - stringvalidator.OneOf( - func() []string { - validLocals := make([]string, len(util.Locals)) - for i, locale := range util.Locals { - validLocals[i] = locale.LocaleString - } - return validLocals - }()...), - }, - }, - "name": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The name of the field in the local configured. for example: in **en-US** the name is `Sample Field` in de-DE `Beispielfeld`.", - }, - "max_length_msg": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "warning/error msg to show to the user when user exceeds the maximum character configured. This is applicable only for the attributes of base_data_type string.", - }, - "min_length_msg": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "warning/error msg to show to the user when user don't provide the minimum character required. This is applicable only for the attributes of base_data_type string.", - }, - "required_msg": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "When the flag required is set to true the required_msg must be provided. required_msg is shown if user does not provide a required field.", - }, - // optional: in case of datatype is RADIO, SELECT, MULTISELECT, etc. the localized attribute values are specified here - "attributes": schema.ListNestedAttribute{ - Optional: true, - MarkdownDescription: "The field attributes must be provided for the data_type SELECT, MULTISELECT and RADIO. it's an array of key value pairs. Example provided in the example section.", - NestedObject: schema.NestedAttributeObject{ - Attributes: map[string]schema.Attribute{ - "key": schema.StringAttribute{ - Required: true, - }, - "value": schema.StringAttribute{ - Required: true, - }, - }, - }, + }, + "scopes": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + MarkdownDescription: "The scopes of the registration field.", + }, + "consent_refs": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + MarkdownDescription: "List of consents(the ids of the consent in cidaas must be passed) in registration. The data type must be `CONSENT` in this case", + }, + "local_texts": schema.ListNestedAttribute{ + Required: true, + MarkdownDescription: "The localized detail of the registration field.", + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "locale": schema.StringAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The locale of the field. example: de-DE.", + Default: stringdefault.StaticString("en"), + Validators: []validator.String{ + stringvalidator.OneOf( + func() []string { + validLocals := make([]string, len(util.Locals)) + for i, locale := range util.Locals { + validLocals[i] = locale.LocaleString + } + return validLocals + }()...), }, - "consent_label": schema.SingleNestedAttribute{ - Optional: true, - MarkdownDescription: "required when data_type is CONSENT. Example provided in the example section.", + }, + "name": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The name of the field in the local configured. for example: in **en-US** the name is `Sample Field` in de-DE `Beispielfeld`.", + }, + "max_length_msg": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "warning/error msg to show to the user when user exceeds the maximum character configured. This is applicable only for the attributes of base_data_type string.", + }, + "min_length_msg": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "warning/error msg to show to the user when user don't provide the minimum character required. This is applicable only for the attributes of base_data_type string.", + }, + "required_msg": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "When the flag required is set to true the required_msg must be provided. required_msg is shown if user does not provide a required field.", + }, + // optional: in case of datatype is RADIO, SELECT, MULTISELECT, etc. the localized attribute values are specified here + "attributes": schema.ListNestedAttribute{ + Optional: true, + MarkdownDescription: "The field attributes must be provided for the data_type SELECT, MULTISELECT and RADIO. it's an array of key value pairs. Example provided in the example section.", + NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ - "label": schema.StringAttribute{ + "key": schema.StringAttribute{ Required: true, }, - "label_text": schema.StringAttribute{ + "value": schema.StringAttribute{ Required: true, }, }, }, }, - }, - }, - "field_definition": schema.SingleNestedAttribute{ - Optional: true, - Computed: true, - Attributes: map[string]schema.Attribute{ - "max_length": schema.Int64Attribute{ + "consent_label": schema.SingleNestedAttribute{ Optional: true, - MarkdownDescription: "The maximum length of a string type attribute.", - Validators: []validator.Int64{ - &validateIsMaxMinMsgAvailable{}, + MarkdownDescription: "required when data_type is CONSENT. Example provided in the example section.", + Attributes: map[string]schema.Attribute{ + "label": schema.StringAttribute{ + Required: true, + }, + "label_text": schema.StringAttribute{ + Required: true, + }, }, }, - "min_length": schema.Int64Attribute{ - Optional: true, - MarkdownDescription: "The minimum length of a string type attribute", - Validators: []validator.Int64{ - &validateIsMaxMinMsgAvailable{}, - }, + }, + }, + }, + "field_definition": schema.SingleNestedAttribute{ + Optional: true, + Computed: true, + Attributes: map[string]schema.Attribute{ + "max_length": schema.Int64Attribute{ + Optional: true, + MarkdownDescription: "The maximum length of a string type attribute.", + Validators: []validator.Int64{ + &validateIsMaxMinMsgAvailable{}, }, - "min_date": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The earliest date a user can select. Applicable only for DATE attributes. Example format: `2024-06-28T18:30:00Z`.", - Validators: []validator.String{ - &dateTypeValidator{}, - &dateValidator{}, - }, + }, + "min_length": schema.Int64Attribute{ + Optional: true, + MarkdownDescription: "The minimum length of a string type attribute", + Validators: []validator.Int64{ + &validateIsMaxMinMsgAvailable{}, }, - "max_date": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The maximum date a user can select. Applicable only for DATE attributes. Example format: `2024-06-28T18:30:00Z`.", - Validators: []validator.String{ - &dateTypeValidator{}, - &dateValidator{}, - }, + }, + "min_date": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The earliest date a user can select. Applicable only for DATE attributes. Example format: `2024-06-28T18:30:00Z`.", + Validators: []validator.String{ + &dateTypeValidator{}, + &dateValidator{}, }, - "initial_date_view": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The view of the calender. Applicable only for DATE attributes. Allowed values: `month`, `year` and `multi-year`", - Validators: []validator.String{ - &dateTypeValidator{}, - stringvalidator.OneOf("month", "year", "multi-year"), - }, + }, + "max_date": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The maximum date a user can select. Applicable only for DATE attributes. Example format: `2024-06-28T18:30:00Z`.", + Validators: []validator.String{ + &dateTypeValidator{}, + &dateValidator{}, }, - "initial_date": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The initial date. Applicable only for DATE attributes. Example format: `2024-06-28T18:30:00Z`.", - Validators: []validator.String{ - &dateTypeValidator{}, - &dateValidator{}, - }, + }, + "initial_date_view": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The view of the calender. Applicable only for DATE attributes. Allowed values: `month`, `year` and `multi-year`", + Validators: []validator.String{ + &dateTypeValidator{}, + stringvalidator.OneOf("month", "year", "multi-year"), }, }, - Default: objectdefault.StaticValue(types.ObjectValueMust( - map[string]attr.Type{ - "max_length": types.Int64Type, - "min_length": types.Int64Type, - "min_date": types.StringType, - "max_date": types.StringType, - "initial_date_view": types.StringType, - "initial_date": types.StringType, + "initial_date": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The initial date. Applicable only for DATE attributes. Example format: `2024-06-28T18:30:00Z`.", + Validators: []validator.String{ + &dateTypeValidator{}, + &dateValidator{}, }, - map[string]attr.Value{ - "max_length": types.Int64Null(), - "min_length": types.Int64Null(), - "min_date": types.StringNull(), - "max_date": types.StringNull(), - "initial_date_view": types.StringNull(), - "initial_date": types.StringNull(), - })), + }, }, + Default: objectdefault.StaticValue(types.ObjectValueMust( + map[string]attr.Type{ + "max_length": types.Int64Type, + "min_length": types.Int64Type, + "min_date": types.StringType, + "max_date": types.StringType, + "initial_date_view": types.StringType, + "initial_date": types.StringType, + }, + map[string]attr.Value{ + "max_length": types.Int64Null(), + "min_length": types.Int64Null(), + "min_date": types.StringNull(), + "max_date": types.StringNull(), + "initial_date_view": types.StringNull(), + "initial_date": types.StringNull(), + })), }, - } + }, } func (rfc *RegFieldConfig) ExtractConfigs(ctx context.Context) diag.Diagnostics { diff --git a/internal/resources/resource_role.go b/internal/resources/resource_role.go index c765af6..4554a56 100644 --- a/internal/resources/resource_role.go +++ b/internal/resources/resource_role.go @@ -2,7 +2,6 @@ package resources import ( "context" - "fmt" "github.com/Cidaas/terraform-provider-cidaas/helpers/cidaas" "github.com/Cidaas/terraform-provider-cidaas/helpers/util" @@ -16,7 +15,18 @@ import ( ) type RoleResource struct { - cidaasClient *cidaas.Client + BaseResource +} + +func NewRoleResource() resource.Resource { + return &RoleResource{ + BaseResource: NewBaseResource( + BaseResourceConfig{ + Name: RESOURCE_ROLE, + Schema: &roleSchema, + }, + ), + } } type Role struct { @@ -26,62 +36,37 @@ type Role struct { Role types.String `tfsdk:"role"` } -func NewRoleResource() resource.Resource { - return &RoleResource{} -} - -func (r *RoleResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_role" -} - -func (r *RoleResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - if req.ProviderData == nil { - return - } - client, ok := req.ProviderData.(*cidaas.Client) - if !ok { - resp.Diagnostics.AddError( - "Unexpected Resource Configure Type", - fmt.Sprintf("Expected cidaas.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), - ) - return - } - r.cidaasClient = client -} - -func (r *RoleResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { - resp.Schema = schema.Schema{ - MarkdownDescription: "The cidaas_role resource in Terraform facilitates the management of roles in Cidaas system." + - " This resource allows you to configure and define custom roles to suit your application's specific access control requirements." + - "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + - "\n- cidaas:roles_read" + - "\n- cidaas:roles_write" + - "\n- cidaas:roles_delete", - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - Description: "The ID of the role resource.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "role": schema.StringAttribute{ - Required: true, - Description: "The unique identifier of the role. The role name must be unique across the cidaas system and cannot be updated for an existing state.", - PlanModifiers: []planmodifier.String{ - &validators.UniqueIdentifier{}, - }, +var roleSchema = schema.Schema{ + MarkdownDescription: "The cidaas_role resource in Terraform facilitates the management of roles in Cidaas system." + + " This resource allows you to configure and define custom roles to suit your application's specific access control requirements." + + "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + + "\n- cidaas:roles_read" + + "\n- cidaas:roles_write" + + "\n- cidaas:roles_delete", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + Description: "The ID of the role resource.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "name": schema.StringAttribute{ - Optional: true, - Description: "The name of the role.", - }, - "description": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The `description` attribute provides details about the role, explaining its purpose.", + }, + "role": schema.StringAttribute{ + Required: true, + Description: "The unique identifier of the role. The role name must be unique across the cidaas system and cannot be updated for an existing state.", + PlanModifiers: []planmodifier.String{ + &validators.UniqueIdentifier{}, }, }, - } + "name": schema.StringAttribute{ + Optional: true, + Description: "The name of the role.", + }, + "description": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The `description` attribute provides details about the role, explaining its purpose.", + }, + }, } func (r *RoleResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { diff --git a/internal/resources/resource_scope.go b/internal/resources/resource_scope.go index ee0e25a..18051df 100644 --- a/internal/resources/resource_scope.go +++ b/internal/resources/resource_scope.go @@ -2,7 +2,6 @@ package resources import ( "context" - "fmt" "github.com/Cidaas/terraform-provider-cidaas/helpers/cidaas" "github.com/Cidaas/terraform-provider-cidaas/helpers/util" @@ -22,7 +21,18 @@ import ( ) type ScopeResource struct { - cidaasClient *cidaas.Client + BaseResource +} + +func NewScopeResource() resource.Resource { + return &ScopeResource{ + BaseResource: NewBaseResource( + BaseResourceConfig{ + Name: RESOURCE_SCOPE, + Schema: &scopeSchema, + }, + ), + } } type ScopeConfig struct { @@ -42,10 +52,6 @@ type LocalDescription struct { Description types.String `tfsdk:"description"` } -func NewScopeResource() resource.Resource { - return &ScopeResource{} -} - func (sc *ScopeConfig) extractLocalizedDescription(ctx context.Context) diag.Diagnostics { var diags diag.Diagnostics @@ -56,113 +62,92 @@ func (sc *ScopeConfig) extractLocalizedDescription(ctx context.Context) diag.Dia return diags } -func (r *ScopeResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_scope" -} - -func (r *ScopeResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - if req.ProviderData == nil { - return - } - client, ok := req.ProviderData.(*cidaas.Client) - if !ok { - resp.Diagnostics.AddError( - "Unexpected Resource Configure Type", - fmt.Sprintf("Expected cidaas.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), - ) - return - } - r.cidaasClient = client -} - -func (r *ScopeResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { - resp.Schema = schema.Schema{ - MarkdownDescription: "The Scope resource allows to manage scopes in Cidaas system. Scopes define the level of access and permissions granted to an application (client)." + - "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + - "\n- cidaas:scopes_read" + - "\n- cidaas:scopes_write" + - "\n- cidaas:scopes_delete", - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - Description: "The ID of the resource.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "security_level": schema.StringAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The security level of the scope, e.g., `PUBLIC`. Allowed values are `PUBLIC` and `CONFIDENTIAL`", - Validators: []validator.String{ - stringvalidator.OneOf([]string{"PUBLIC", "CONFIDENTIAL"}...), - }, - Default: stringdefault.StaticString("PUBLIC"), - }, - "scope_key": schema.StringAttribute{ - Required: true, - MarkdownDescription: "Unique identifier for the scope. This cannot be updated for an existing state.", - PlanModifiers: []planmodifier.String{ - // the destroy will throw the error too - validators.UniqueIdentifier{}, - }, +var scopeSchema = schema.Schema{ + MarkdownDescription: "The Scope resource allows to manage scopes in Cidaas system. Scopes define the level of access and permissions granted to an application (client)." + + "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + + "\n- cidaas:scopes_read" + + "\n- cidaas:scopes_write" + + "\n- cidaas:scopes_delete", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + Description: "The ID of the resource.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "group_name": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - MarkdownDescription: "List of scope_groups to associate the scope with.", - // group_name validator can be added by fetching the group_names using api + }, + "security_level": schema.StringAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The security level of the scope, e.g., `PUBLIC`. Allowed values are `PUBLIC` and `CONFIDENTIAL`", + Validators: []validator.String{ + stringvalidator.OneOf([]string{"PUBLIC", "CONFIDENTIAL"}...), }, - "required_user_consent": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Indicates whether user consent is required for the scope.", - Default: booldefault.StaticBool(false), + Default: stringdefault.StaticString("PUBLIC"), + }, + "scope_key": schema.StringAttribute{ + Required: true, + MarkdownDescription: "Unique identifier for the scope. This cannot be updated for an existing state.", + PlanModifiers: []planmodifier.String{ + // the destroy will throw the error too + validators.UniqueIdentifier{}, }, - "scope_owner": schema.StringAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The owner of the scope. e.g. `ADMIN`", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + }, + "group_name": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + MarkdownDescription: "List of scope_groups to associate the scope with.", + // group_name validator can be added by fetching the group_names using api + }, + "required_user_consent": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Indicates whether user consent is required for the scope.", + Default: booldefault.StaticBool(false), + }, + "scope_owner": schema.StringAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The owner of the scope. e.g. `ADMIN`", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "localized_descriptions": schema.ListNestedAttribute{ - Optional: true, - NestedObject: schema.NestedAttributeObject{ - Attributes: map[string]schema.Attribute{ - "locale": schema.StringAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The locale for the scope, e.g., `en-US`.", - Default: stringdefault.StaticString("en-US"), - Validators: []validator.String{ - stringvalidator.OneOf( - func() []string { - validLocals := make([]string, len(util.Locals)) - for i, locale := range util.Locals { - validLocals[i] = locale.LocaleString - } - return validLocals - }()...), - }, - }, - "title": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The title of the scope in the configured locale.", + }, + "localized_descriptions": schema.ListNestedAttribute{ + Optional: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "locale": schema.StringAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The locale for the scope, e.g., `en-US`.", + Default: stringdefault.StaticString("en-US"), + Validators: []validator.String{ + stringvalidator.OneOf( + func() []string { + validLocals := make([]string, len(util.Locals)) + for i, locale := range util.Locals { + validLocals[i] = locale.LocaleString + } + return validLocals + }()...), }, - "description": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The description of the scope in the configured locale.", - Validators: []validator.String{ - stringvalidator.LengthBetween(0, 256), - }, + }, + "title": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The title of the scope in the configured locale.", + }, + "description": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The description of the scope in the configured locale.", + Validators: []validator.String{ + stringvalidator.LengthBetween(0, 256), }, }, }, }, }, - } + }, } func (r *ScopeResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { diff --git a/internal/resources/resource_scope_group.go b/internal/resources/resource_scope_group.go index 202f660..3ef4942 100644 --- a/internal/resources/resource_scope_group.go +++ b/internal/resources/resource_scope_group.go @@ -2,7 +2,6 @@ package resources import ( "context" - "fmt" "github.com/Cidaas/terraform-provider-cidaas/helpers/cidaas" "github.com/Cidaas/terraform-provider-cidaas/helpers/util" @@ -18,7 +17,18 @@ import ( ) type ScopeGroupResource struct { - cidaasClient *cidaas.Client + BaseResource +} + +func NewScopeGroupResource() resource.Resource { + return &ScopeGroupResource{ + BaseResource: NewBaseResource( + BaseResourceConfig{ + Name: RESOURCE_SCOPE_GROUP, + Schema: &scopeGroupSchema, + }, + ), + } } type ScopeGroupConfig struct { @@ -29,74 +39,50 @@ type ScopeGroupConfig struct { UpdatedAt types.String `tfsdk:"updated_at"` } -func NewScopeGroupResource() resource.Resource { - return &ScopeGroupResource{} -} - -func (r *ScopeGroupResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_scope_group" -} - -func (r *ScopeGroupResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - if req.ProviderData == nil { - return - } - client, ok := req.ProviderData.(*cidaas.Client) - if !ok { - resp.Diagnostics.AddError( - "Unexpected Resource Configure Type", - fmt.Sprintf("Expected cidaas.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), - ) - return - } - r.cidaasClient = client -} - -func (r *ScopeGroupResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { - resp.Schema = schema.Schema{ - MarkdownDescription: "The cidaas_scope_group resource in the provider allows to manage Scope Groups in Cidaas system. Scope Groups help organize and group related scopes for better categorization and access control." + - "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + - "\n- cidaas:scopes_read" + - "\n- cidaas:scopes_write" + - "\n- cidaas:scopes_delete", - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - Description: "The ID of th resource.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, +var scopeGroupSchema = schema.Schema{ + MarkdownDescription: "The cidaas_scope_group resource in the provider allows to manage Scope Groups in Cidaas system." + + " Scope Groups help organize and group related scopes for better categorization and access control." + + "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + + "\n- cidaas:scopes_read" + + "\n- cidaas:scopes_write" + + "\n- cidaas:scopes_delete", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + Description: "The ID of th resource.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "group_name": schema.StringAttribute{ - Required: true, - Validators: []validator.String{ - stringvalidator.LengthAtLeast(1), - }, - PlanModifiers: []planmodifier.String{ - &validators.UniqueIdentifier{}, - }, - MarkdownDescription: "The name of the group. The group name must be unique across the cidaas system and cannot be updated for an existing state.", + }, + "group_name": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), }, - "description": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The `description` attribute provides details about the scope of the group, explaining its purpose.", + PlanModifiers: []planmodifier.String{ + &validators.UniqueIdentifier{}, }, - "created_at": schema.StringAttribute{ - Computed: true, - Description: "The timestamp when the resource was created.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + MarkdownDescription: "The name of the group. The group name must be unique across the cidaas system and cannot be updated for an existing state.", + }, + "description": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The `description` attribute provides details about the scope of the group, explaining its purpose.", + }, + "created_at": schema.StringAttribute{ + Computed: true, + Description: "The timestamp when the resource was created.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "updated_at": schema.StringAttribute{ - Computed: true, - Description: "The timestamp when the resource was last updated.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + }, + "updated_at": schema.StringAttribute{ + Computed: true, + Description: "The timestamp when the resource was last updated.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, }, - } + }, } func (r *ScopeGroupResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { diff --git a/internal/resources/resource_social_provider.go b/internal/resources/resource_social_provider.go index 62da515..0ed235f 100644 --- a/internal/resources/resource_social_provider.go +++ b/internal/resources/resource_social_provider.go @@ -36,7 +36,18 @@ var allowedProviders = []string{ } type SocialProvider struct { - cidaasClient *cidaas.Client + BaseResource +} + +func NewSocialProvider() resource.Resource { + return &SocialProvider{ + BaseResource: NewBaseResource( + BaseResourceConfig{ + Name: RESOURCE_SOCIAL_PROVIDER, + Schema: &socialProviderSchema, + }, + ), + } } type SocialProviderConfig struct { @@ -74,10 +85,6 @@ type UserInfoFields struct { IsSystemField types.Bool `tfsdk:"is_system_field"` } -func NewSocialProvider() resource.Resource { - return &SocialProvider{} -} - func (r *SocialProvider) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, res *resource.ValidateConfigResponse) { var config SocialProviderConfig res.Diagnostics.Append(req.Config.Get(ctx, &config)...) @@ -114,184 +121,163 @@ func (r *SocialProvider) ValidateConfig(ctx context.Context, req resource.Valida } } -func (r *SocialProvider) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_social_provider" -} - -func (r *SocialProvider) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - if req.ProviderData == nil { - return - } - client, ok := req.ProviderData.(*cidaas.Client) - if !ok { - resp.Diagnostics.AddError( - "Unexpected Resource Configure Type", - fmt.Sprintf("Expected cidaas.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), - ) - return - } - r.cidaasClient = client -} - -func (r *SocialProvider) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { - resp.Schema = schema.Schema{ - MarkdownDescription: "The `cidaas_social_provider` resource allows you to configure and manage social login providers within Cidaas." + - "\n Social login providers enable users to authenticate using their existing accounts from popular social platforms such as Google, Facebook, LinkedIn and others." + - "\n\n Ensure that the below scopes are assigned to the client:" + - "\n- cidaas:providers_read" + - "\n- cidaas:providers_write" + - "\n- cidaas:providers_delete", - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - MarkdownDescription: "The unique identifier of the social provider", - }, - "name": schema.StringAttribute{ - Required: true, - PlanModifiers: []planmodifier.String{ - &validators.UniqueIdentifier{}, - }, - MarkdownDescription: "The name of the social provider configuration. This should be unique within your Cidaas environment.", - }, - "provider_name": schema.StringAttribute{ - Required: true, - PlanModifiers: []planmodifier.String{ - &validators.UniqueIdentifier{}, - }, - Validators: []validator.String{ - stringvalidator.OneOf(allowedProviders...), - }, - MarkdownDescription: "The name of the social provider. Supported values include `google`, `facebook`, `linkedin` etc.", +var socialProviderSchema = schema.Schema{ + MarkdownDescription: "The `cidaas_social_provider` resource allows you to configure and manage social login providers within Cidaas." + + "\n Social login providers enable users to authenticate using their existing accounts from popular social platforms such as Google, Facebook, LinkedIn and others." + + "\n\n Ensure that the below scopes are assigned to the client:" + + "\n- cidaas:providers_read" + + "\n- cidaas:providers_write" + + "\n- cidaas:providers_delete", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "enabled": schema.BoolAttribute{ - Optional: true, - Computed: true, - Default: booldefault.StaticBool(false), - MarkdownDescription: "A flag to enable or disable the social provider configuration. Set to `true` to enable and `false` to disable.", - }, - "client_id": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The client ID provided by the social provider. This is used to authenticate your application with the social provider.", + MarkdownDescription: "The unique identifier of the social provider", + }, + "name": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + &validators.UniqueIdentifier{}, }, - "client_secret": schema.StringAttribute{ - Required: true, - Sensitive: true, - MarkdownDescription: "The client secret provided by the social provider. This is used alongside the client ID to authenticate your application with the social provider.", + MarkdownDescription: "The name of the social provider configuration. This should be unique within your Cidaas environment.", + }, + "provider_name": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + &validators.UniqueIdentifier{}, }, - "scopes": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - MarkdownDescription: "A list of scopes of the social provider.", + Validators: []validator.String{ + stringvalidator.OneOf(allowedProviders...), }, - "claims": schema.SingleNestedAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "A map defining required and optional claims to be requested from the social provider.", - Attributes: map[string]schema.Attribute{ - "required_claims": schema.SingleNestedAttribute{ - Optional: true, - MarkdownDescription: "Defines the claims that are required from the social provider.", - Attributes: map[string]schema.Attribute{ - "user_info": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - MarkdownDescription: "A list of user information claims that are required.", - }, - "id_token": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - MarkdownDescription: "A list of ID token claims that are required.", - }, + MarkdownDescription: "The name of the social provider. Supported values include `google`, `facebook`, `linkedin` etc.", + }, + "enabled": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), + MarkdownDescription: "A flag to enable or disable the social provider configuration. Set to `true` to enable and `false` to disable.", + }, + "client_id": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The client ID provided by the social provider. This is used to authenticate your application with the social provider.", + }, + "client_secret": schema.StringAttribute{ + Required: true, + Sensitive: true, + MarkdownDescription: "The client secret provided by the social provider. This is used alongside the client ID to authenticate your application with the social provider.", + }, + "scopes": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + MarkdownDescription: "A list of scopes of the social provider.", + }, + "claims": schema.SingleNestedAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "A map defining required and optional claims to be requested from the social provider.", + Attributes: map[string]schema.Attribute{ + "required_claims": schema.SingleNestedAttribute{ + Optional: true, + MarkdownDescription: "Defines the claims that are required from the social provider.", + Attributes: map[string]schema.Attribute{ + "user_info": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + MarkdownDescription: "A list of user information claims that are required.", }, - }, - "optional_claims": schema.SingleNestedAttribute{ - Optional: true, - MarkdownDescription: "Defines the claims that are optional from the social provider.", - Attributes: map[string]schema.Attribute{ - "user_info": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - MarkdownDescription: "A list of user information claims that are optional.", - }, - "id_token": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - MarkdownDescription: "A list of ID token claims that are optional.", - }, + "id_token": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + MarkdownDescription: "A list of ID token claims that are required.", }, }, }, - Default: objectdefault.StaticValue( - types.ObjectValueMust( - map[string]attr.Type{ - "required_claims": types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "user_info": types.SetType{ElemType: types.StringType}, - "id_token": types.SetType{ElemType: types.StringType}, - }, - }, - "optional_claims": types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "user_info": types.SetType{ElemType: types.StringType}, - "id_token": types.SetType{ElemType: types.StringType}, - }, - }, + "optional_claims": schema.SingleNestedAttribute{ + Optional: true, + MarkdownDescription: "Defines the claims that are optional from the social provider.", + Attributes: map[string]schema.Attribute{ + "user_info": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + MarkdownDescription: "A list of user information claims that are optional.", + }, + "id_token": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + MarkdownDescription: "A list of ID token claims that are optional.", }, - map[string]attr.Value{ - "required_claims": types.ObjectValueMust(map[string]attr.Type{ + }, + }, + }, + Default: objectdefault.StaticValue( + types.ObjectValueMust( + map[string]attr.Type{ + "required_claims": types.ObjectType{ + AttrTypes: map[string]attr.Type{ "user_info": types.SetType{ElemType: types.StringType}, "id_token": types.SetType{ElemType: types.StringType}, }, - map[string]attr.Value{ - "user_info": types.SetNull(types.StringType), - "id_token": types.SetNull(types.StringType), - }), - "optional_claims": types.ObjectValueMust(map[string]attr.Type{ + }, + "optional_claims": types.ObjectType{ + AttrTypes: map[string]attr.Type{ "user_info": types.SetType{ElemType: types.StringType}, "id_token": types.SetType{ElemType: types.StringType}, }, - map[string]attr.Value{ - "user_info": types.SetNull(types.StringType), - "id_token": types.SetNull(types.StringType), - }), - }), - ), - }, - "userinfo_fields": schema.ListNestedAttribute{ - Optional: true, - MarkdownDescription: "A list of user info fields to be mapped between the social provider and Cidaas.", - NestedObject: schema.NestedAttributeObject{ - Attributes: map[string]schema.Attribute{ - "inner_key": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The internal key used by Cidaas.", - }, - "external_key": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The external key used by the social provider.", }, - "is_custom_field": schema.BoolAttribute{ - Required: true, - MarkdownDescription: "A flag indicating whether the field is a custom field. Set to `true` if it is a custom field.", + }, + map[string]attr.Value{ + "required_claims": types.ObjectValueMust(map[string]attr.Type{ + "user_info": types.SetType{ElemType: types.StringType}, + "id_token": types.SetType{ElemType: types.StringType}, }, - "is_system_field": schema.BoolAttribute{ - Required: true, - MarkdownDescription: "A flag indicating whether the field is a system field. Set to `true` if it is a system field.", + map[string]attr.Value{ + "user_info": types.SetNull(types.StringType), + "id_token": types.SetNull(types.StringType), + }), + "optional_claims": types.ObjectValueMust(map[string]attr.Type{ + "user_info": types.SetType{ElemType: types.StringType}, + "id_token": types.SetType{ElemType: types.StringType}, }, + map[string]attr.Value{ + "user_info": types.SetNull(types.StringType), + "id_token": types.SetNull(types.StringType), + }), + }), + ), + }, + "userinfo_fields": schema.ListNestedAttribute{ + Optional: true, + MarkdownDescription: "A list of user info fields to be mapped between the social provider and Cidaas.", + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "inner_key": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The internal key used by Cidaas.", + }, + "external_key": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The external key used by the social provider.", + }, + "is_custom_field": schema.BoolAttribute{ + Required: true, + MarkdownDescription: "A flag indicating whether the field is a custom field. Set to `true` if it is a custom field.", + }, + "is_system_field": schema.BoolAttribute{ + Required: true, + MarkdownDescription: "A flag indicating whether the field is a system field. Set to `true` if it is a system field.", }, }, }, - "enabled_for_admin_portal": schema.BoolAttribute{ - Optional: true, - Computed: true, - Default: booldefault.StaticBool(false), - MarkdownDescription: "A flag to enable or disable the social provider for the admin portal. Set to `true` to enable and `false` to disable.", - }, }, - } + "enabled_for_admin_portal": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), + MarkdownDescription: "A flag to enable or disable the social provider for the admin portal. Set to `true` to enable and `false` to disable.", + }, + }, } func (r *SocialProvider) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { diff --git a/internal/resources/resource_template.go b/internal/resources/resource_template.go index 6f20437..88da0ec 100644 --- a/internal/resources/resource_template.go +++ b/internal/resources/resource_template.go @@ -43,142 +43,127 @@ type TemplateConfig struct { } type TemplateResource struct { - cidaasClient *cidaas.Client + BaseResource } func NewTemplateResource() resource.Resource { - return &TemplateResource{} -} - -func (r *TemplateResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_template" -} - -func (r *TemplateResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - if req.ProviderData == nil { - return - } - client, ok := req.ProviderData.(*cidaas.Client) - if !ok { - resp.Diagnostics.AddError( - "Unexpected Resource Configure Type", - fmt.Sprintf("Expected cidaas.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), - ) - return + return &TemplateResource{ + BaseResource: NewBaseResource( + BaseResourceConfig{ + Name: RESOURCE_TEMPLATE, + Schema: &templateSchema, + }, + ), } - r.cidaasClient = client - cidaasClient = client } -func (r *TemplateResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { - resp.Schema = schema.Schema{ - MarkdownDescription: "The Template resource in the provider is used to define and manage templates within the Cidaas system." + - " Templates are used for emails, SMS, IVR, and push notifications." + - "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + - "\n- cidaas:templates_read" + - "\n- cidaas:templates_write" + - "\n- cidaas:templates_delete", - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - Description: "The unique identifier of the template resource.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "locale": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The locale of the template. e.g. `en-us`, `en-uk`. Ensure the locale is set in lowercase. Find the allowed locales in the Allowed Locales section below. It cannot be updated for an existing state.", - Validators: []validator.String{ - stringvalidator.OneOf( - func() []string { - validLocals := make([]string, len(util.Locals)) - for i, locale := range util.Locals { - validLocals[i] = strings.ToLower(locale.LocaleString) - } - return validLocals - }()...), - }, - PlanModifiers: []planmodifier.String{ - &validators.UniqueIdentifier{}, - }, - }, - "template_key": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The unique name of the template. It cannot be updated for an existing state.", - Validators: []validator.String{ - stringvalidator.RegexMatches( - regexp.MustCompile(`^[A-Z0-9_-]+$`), - `must be a valid string consisting only of uppercase letters, digits (0-9), underscores (_), and hyphens (-). Example: SAMPLE, 12345, SAMPLE-TEMPLATE, SAMPLE_TEMPLATE, SAMPLE12345, SAMPLE-1234`, - ), - }, - PlanModifiers: []planmodifier.String{ - &validators.UniqueIdentifier{}, - }, - }, - "template_type": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The type of the template. Allowed template_types are EMAIL, SMS, IVR and PUSH. Template types are case sensitive. It cannot be updated for an existing state.", - Validators: []validator.String{ - stringvalidator.OneOf(allowedTemplateTypes...), - }, - PlanModifiers: []planmodifier.String{ - &validators.UniqueIdentifier{}, - }, +var templateSchema = schema.Schema{ + MarkdownDescription: "The Template resource in the provider is used to define and manage templates within the Cidaas system." + + " Templates are used for emails, SMS, IVR, and push notifications." + + "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + + "\n- cidaas:templates_read" + + "\n- cidaas:templates_write" + + "\n- cidaas:templates_delete", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + Description: "The unique identifier of the template resource.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "content": schema.StringAttribute{ - Required: true, - MarkdownDescription: "The content of the template.", + }, + "locale": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The locale of the template. e.g. `en-us`, `en-uk`. Ensure the locale is set in lowercase. Find the allowed locales in the Allowed Locales section below. It cannot be updated for an existing state.", + Validators: []validator.String{ + stringvalidator.OneOf( + func() []string { + validLocals := make([]string, len(util.Locals)) + for i, locale := range util.Locals { + validLocals[i] = strings.ToLower(locale.LocaleString) + } + return validLocals + }()...), }, - "subject": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "Applicable only for template_type EMAIL. It represents the subject of an email.", + PlanModifiers: []planmodifier.String{ + &validators.UniqueIdentifier{}, }, - "template_owner": schema.StringAttribute{ - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - MarkdownDescription: "The template owner of the template.", + }, + "template_key": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The unique name of the template. It cannot be updated for an existing state.", + Validators: []validator.String{ + stringvalidator.RegexMatches( + regexp.MustCompile(`^[A-Z0-9_-]+$`), + `must be a valid string consisting only of uppercase letters, digits (0-9), underscores (_), and hyphens (-). Example: SAMPLE, 12345, SAMPLE-TEMPLATE, SAMPLE_TEMPLATE, SAMPLE12345, SAMPLE-1234`, + ), }, - "usage_type": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The usage_type attribute specifies the specific use case or application for the template. Only applicable for SYSTEM templates." + - " It should be set to `GENERAL` when cidaas does not provide an allowed list of values.", - Computed: true, + PlanModifiers: []planmodifier.String{ + &validators.UniqueIdentifier{}, }, - "processing_type": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The processing_type attribute specifies the method by which the template information is processed and delivered. Only applicable for SYSTEM templates." + - " It should be set to `GENERAL` when cidaas does not provide an allowed list of values.", + }, + "template_type": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The type of the template. Allowed template_types are EMAIL, SMS, IVR and PUSH. Template types are case sensitive. It cannot be updated for an existing state.", + Validators: []validator.String{ + stringvalidator.OneOf(allowedTemplateTypes...), }, - "verification_type": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "The verification_type attribute defines the method used for verification. Only applicable for SYSTEM templates.", + PlanModifiers: []planmodifier.String{ + &validators.UniqueIdentifier{}, }, - "language": schema.StringAttribute{ - Computed: true, - MarkdownDescription: "The language based on the local provided in the configuration.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + }, + "content": schema.StringAttribute{ + Required: true, + MarkdownDescription: "The content of the template.", + }, + "subject": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Applicable only for template_type EMAIL. It represents the subject of an email.", + }, + "template_owner": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "group_id": schema.StringAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The `group_id` under which the configured template will be categorized. Only applicable for SYSTEM templates.", + MarkdownDescription: "The template owner of the template.", + }, + "usage_type": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The usage_type attribute specifies the specific use case or application for the template. Only applicable for SYSTEM templates." + + " It should be set to `GENERAL` when cidaas does not provide an allowed list of values.", + Computed: true, + }, + "processing_type": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The processing_type attribute specifies the method by which the template information is processed and delivered. Only applicable for SYSTEM templates." + + " It should be set to `GENERAL` when cidaas does not provide an allowed list of values.", + }, + "verification_type": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "The verification_type attribute defines the method used for verification. Only applicable for SYSTEM templates.", + }, + "language": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The language based on the local provided in the configuration.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "is_system_template": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "A boolean flag to decide between SYSTEM and CUSTOM template. When set to true the provider creates a SYSTEM template else CUSTOM", - Default: booldefault.StaticBool(false), - PlanModifiers: []planmodifier.Bool{ - &systemTemplateValidator{}, - }, + }, + "group_id": schema.StringAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The `group_id` under which the configured template will be categorized. Only applicable for SYSTEM templates.", + }, + "is_system_template": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "A boolean flag to decide between SYSTEM and CUSTOM template. When set to true the provider creates a SYSTEM template else CUSTOM", + Default: booldefault.StaticBool(false), + PlanModifiers: []planmodifier.Bool{ + &systemTemplateValidator{}, }, }, - } + }, } func (r *TemplateResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { @@ -214,6 +199,7 @@ func (r *TemplateResource) Create(ctx context.Context, req resource.CreateReques var plan, config TemplateConfig resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) resp.Diagnostics.Append(req.Config.Get(ctx, &config)...) + cidaasClient = r.cidaasClient // global variable cidaasClient is assigned here resp.Diagnostics.Append(validateSystemTemplateConfig(config)...) if resp.Diagnostics.HasError() { return diff --git a/internal/resources/resource_template_group.go b/internal/resources/resource_template_group.go index 7450b96..ad7d425 100644 --- a/internal/resources/resource_template_group.go +++ b/internal/resources/resource_template_group.go @@ -2,7 +2,6 @@ package resources import ( "context" - "fmt" "github.com/Cidaas/terraform-provider-cidaas/helpers/cidaas" "github.com/Cidaas/terraform-provider-cidaas/helpers/util" @@ -20,6 +19,21 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) +type TemplateGroupResource struct { + BaseResource +} + +func NewTemplateGroupResource() resource.Resource { + return &TemplateGroupResource{ + BaseResource: NewBaseResource( + BaseResourceConfig{ + Name: RESOURCE_TEMPLATE_GROUP, + Schema: &templateGroupSchema, + }, + ), + } +} + type TemplateGroupConfig struct { ID types.String `tfsdk:"id"` GroupID types.String `tfsdk:"group_id"` @@ -53,200 +67,171 @@ type IVRSenderConfig struct { SenderNames types.Set `tfsdk:"sender_names"` } -type TemplateGroupResource struct { - cidaasClient *cidaas.Client -} - -func NewTemplateGroupResource() resource.Resource { - return &TemplateGroupResource{} -} - -func (r *TemplateGroupResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_template_group" -} - -func (r *TemplateGroupResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - if req.ProviderData == nil { - return - } - client, ok := req.ProviderData.(*cidaas.Client) - if !ok { - resp.Diagnostics.AddError( - "Unexpected Resource Configure Type", - fmt.Sprintf("Expected cidaas.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), - ) - return - } - r.cidaasClient = client -} - -func (r *TemplateGroupResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { - resp.Schema = schema.Schema{ - MarkdownDescription: "The cidaas_template_group resource in the provider is used to define and manage templates groups within the Cidaas system." + - " Template Groups categorize your communication templates allowing you to map preferred templates to specific clients effectively." + - "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + - "\n- cidaas:templates_read" + - "\n- cidaas:templates_write" + - "\n- cidaas:templates_delete", - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - MarkdownDescription: "The ID of the resource", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, +var templateGroupSchema = schema.Schema{ + MarkdownDescription: "The cidaas_template_group resource in the provider is used to define and manage templates groups within the Cidaas system." + + " Template Groups categorize your communication templates allowing you to map preferred templates to specific clients effectively." + + "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + + "\n- cidaas:templates_read" + + "\n- cidaas:templates_write" + + "\n- cidaas:templates_delete", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The ID of the resource", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "group_id": schema.StringAttribute{ - Required: true, - Validators: []validator.String{ - stringvalidator.LengthAtMost(15), - }, - MarkdownDescription: "The group_id of the Template Group. The group_id is used to import an existing template group." + - " The maximum allowed length of a group_id is **15** characters.", + }, + "group_id": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.LengthAtMost(15), }, - "email_sender_config": schema.SingleNestedAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The `email_sender_config` is used to configure your email sender.", - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - MarkdownDescription: "The `ID` of the configured email sender.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "from_email": schema.StringAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The email from address from which the emails will be sent when the specific group is configured.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "from_name": schema.StringAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The `from_name` attribute is the display name that appears in the 'From' field of the emails.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + MarkdownDescription: "The group_id of the Template Group. The group_id is used to import an existing template group." + + " The maximum allowed length of a group_id is **15** characters.", + }, + "email_sender_config": schema.SingleNestedAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The `email_sender_config` is used to configure your email sender.", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The `ID` of the configured email sender.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "reply_to": schema.StringAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The `reply_to` attribute is the email address where replies should be directed.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + }, + "from_email": schema.StringAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The email from address from which the emails will be sent when the specific group is configured.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "sender_names": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - MarkdownDescription: "The `sender_names` attribute defines the names associated with email senders.", + }, + "from_name": schema.StringAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The `from_name` attribute is the display name that appears in the 'From' field of the emails.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, }, - Default: objectdefault.StaticValue(types.ObjectValueMust( - map[string]attr.Type{ - "id": types.StringType, - "from_email": types.StringType, - "from_name": types.StringType, - "reply_to": types.StringType, - "sender_names": types.SetType{ElemType: types.StringType}, + "reply_to": schema.StringAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The `reply_to` attribute is the email address where replies should be directed.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - map[string]attr.Value{ - "id": types.StringNull(), - "from_email": types.StringNull(), - "from_name": types.StringNull(), - "reply_to": types.StringNull(), - "sender_names": types.SetValueMust(types.StringType, []attr.Value{types.StringValue("SYSTEM")}), - })), + }, + "sender_names": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + MarkdownDescription: "The `sender_names` attribute defines the names associated with email senders.", + }, }, - "sms_sender_config": schema.SingleNestedAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The configuration of the SMS sender.", - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "from_name": schema.StringAttribute{ - Optional: true, - }, - "sender_names": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - }, + Default: objectdefault.StaticValue(types.ObjectValueMust( + map[string]attr.Type{ + "id": types.StringType, + "from_email": types.StringType, + "from_name": types.StringType, + "reply_to": types.StringType, + "sender_names": types.SetType{ElemType: types.StringType}, }, - Default: objectdefault.StaticValue(types.ObjectValueMust( - map[string]attr.Type{ - "id": types.StringType, - "from_name": types.StringType, - "sender_names": types.SetType{ElemType: types.StringType}, + map[string]attr.Value{ + "id": types.StringNull(), + "from_email": types.StringNull(), + "from_name": types.StringNull(), + "reply_to": types.StringNull(), + "sender_names": types.SetValueMust(types.StringType, []attr.Value{types.StringValue("SYSTEM")}), + })), + }, + "sms_sender_config": schema.SingleNestedAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The configuration of the SMS sender.", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - map[string]attr.Value{ - "id": types.StringNull(), - "from_name": types.StringNull(), - "sender_names": types.SetValueMust(types.StringType, []attr.Value{types.StringValue("SYSTEM")}), - })), + }, + "from_name": schema.StringAttribute{ + Optional: true, + }, + "sender_names": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + }, }, - "ivr_sender_config": schema.SingleNestedAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The configuration of the IVR sender.", - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "sender_names": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - }, + Default: objectdefault.StaticValue(types.ObjectValueMust( + map[string]attr.Type{ + "id": types.StringType, + "from_name": types.StringType, + "sender_names": types.SetType{ElemType: types.StringType}, }, - Default: objectdefault.StaticValue(types.ObjectValueMust( - map[string]attr.Type{ - "id": types.StringType, - "sender_names": types.SetType{ElemType: types.StringType}, + map[string]attr.Value{ + "id": types.StringNull(), + "from_name": types.StringNull(), + "sender_names": types.SetValueMust(types.StringType, []attr.Value{types.StringValue("SYSTEM")}), + })), + }, + "ivr_sender_config": schema.SingleNestedAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The configuration of the IVR sender.", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - map[string]attr.Value{ - "id": types.StringNull(), - "sender_names": types.SetValueMust(types.StringType, []attr.Value{types.StringValue("SYSTEM")}), - })), + }, + "sender_names": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + }, }, - "push_sender_config": schema.SingleNestedAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "The configuration of the PUSH notification sender.", - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - "sender_names": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, - }, + Default: objectdefault.StaticValue(types.ObjectValueMust( + map[string]attr.Type{ + "id": types.StringType, + "sender_names": types.SetType{ElemType: types.StringType}, }, - Default: objectdefault.StaticValue(types.ObjectValueMust( - map[string]attr.Type{ - "id": types.StringType, - "sender_names": types.SetType{ElemType: types.StringType}, + map[string]attr.Value{ + "id": types.StringNull(), + "sender_names": types.SetValueMust(types.StringType, []attr.Value{types.StringValue("SYSTEM")}), + })), + }, + "push_sender_config": schema.SingleNestedAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "The configuration of the PUSH notification sender.", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - map[string]attr.Value{ - "id": types.StringNull(), - "sender_names": types.SetValueMust(types.StringType, []attr.Value{types.StringValue("SYSTEM")}), - })), + }, + "sender_names": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + }, }, + Default: objectdefault.StaticValue(types.ObjectValueMust( + map[string]attr.Type{ + "id": types.StringType, + "sender_names": types.SetType{ElemType: types.StringType}, + }, + map[string]attr.Value{ + "id": types.StringNull(), + "sender_names": types.SetValueMust(types.StringType, []attr.Value{types.StringValue("SYSTEM")}), + })), }, - } + }, } func (tg *TemplateGroupConfig) ExtractConfigs(ctx context.Context) diag.Diagnostics { diff --git a/internal/resources/resource_template_test.go b/internal/resources/resource_template_test.go index 54c5896..235c28b 100644 --- a/internal/resources/resource_template_test.go +++ b/internal/resources/resource_template_test.go @@ -83,7 +83,7 @@ func testTemplateConfig(locale, templateKey, templateType, content string) strin template_type = "%s" content = "%s" } - `, acctest.BaseURL, locale, templateKey, templateType, content) + `, "https://automation-test.dev.cidaas.eu", locale, templateKey, templateType, content) } func checkTemplateDestroyed(s *terraform.State) error { @@ -170,7 +170,7 @@ func TestTemplate_MissingRequired(t *testing.T) { base_url = "%s" } resource "cidaas_template" "example" {} - `, acctest.BaseURL), + `, "https://automation-test.dev.cidaas.eu"), ExpectError: regexp.MustCompile(fmt.Sprintf(`"%s" is required`, v)), // TODO: full string validation }, }, @@ -201,7 +201,7 @@ func TestTemplate_SystemTemplateBasic(t *testing.T) { verification_type = "SMS" usage_type = "VERIFICATION_CONFIGURATION" } - `, acctest.BaseURL), + `, "https://automation-test.dev.cidaas.eu"), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr(resourceTemplate, "is_system_template", strconv.FormatBool(true)), resource.TestCheckResourceAttrSet(resourceTemplate, "id"), @@ -223,7 +223,7 @@ func TestTemplate_SystemTemplateBasic(t *testing.T) { verification_type = "SMS" usage_type = "VERIFICATION_CONFIGURATION" } - `, acctest.BaseURL), + `, "https://automation-test.dev.cidaas.eu"), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr(resourceTemplate, "content", "Hi {{name}}, here is the {{code}} to verify the user updated"), ), @@ -245,7 +245,7 @@ func TestTemplate_SystemTemplateBasic(t *testing.T) { verification_type = "SMS" usage_type = "VERIFICATION_CONFIGURATION" } - `, acctest.BaseURL), + `, "https://automation-test.dev.cidaas.eu"), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr(resourceTemplate, "content", "Hi {{name}}, here is the {{code}} to verify the user"), ), diff --git a/internal/resources/resource_user_group.go b/internal/resources/resource_user_group.go index 36b2004..70166f1 100644 --- a/internal/resources/resource_user_group.go +++ b/internal/resources/resource_user_group.go @@ -2,7 +2,6 @@ package resources import ( "context" - "fmt" "github.com/Cidaas/terraform-provider-cidaas/helpers/cidaas" "github.com/Cidaas/terraform-provider-cidaas/helpers/util" @@ -21,7 +20,18 @@ import ( ) type UserGroupResource struct { - cidaasClient *cidaas.Client + BaseResource +} + +func NewUserGroupResource() resource.Resource { + return &UserGroupResource{ + BaseResource: NewBaseResource( + BaseResourceConfig{ + Name: RESOURCE_USER_GROUP, + Schema: &userGroupSchema, + }, + ), + } } type UserGroupConfig struct { @@ -40,132 +50,107 @@ type UserGroupConfig struct { UpdatedAt types.String `tfsdk:"updated_at"` } -func NewUserGroupResource() resource.Resource { - return &UserGroupResource{} -} - -func (r *UserGroupResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_user_groups" -} - -func (r *UserGroupResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - if req.ProviderData == nil { - return - } - client, ok := req.ProviderData.(*cidaas.Client) - if !ok { - resp.Diagnostics.AddError( - "Unexpected Resource Configure Type", - fmt.Sprintf("Expected cidaas.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), - ) - return - } - r.cidaasClient = client -} - -func (r *UserGroupResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { - resp.Schema = schema.Schema{ - MarkdownDescription: "The cidaas_user_groups resource enables the creation of user groups in the cidaas system." + - " These groups allow users to be organized and assigned group-specific roles." + - "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + - "\n- cidaas:groups_write" + - "\n- cidaas:groups_read" + - "\n- cidaas:groups_delete", - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - Description: "The unique identifier of the user group resource.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, +var userGroupSchema = schema.Schema{ + MarkdownDescription: "The cidaas_user_groups resource enables the creation of user groups in the cidaas system." + + " These groups allow users to be organized and assigned group-specific roles." + + "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + + "\n- cidaas:groups_write" + + "\n- cidaas:groups_read" + + "\n- cidaas:groups_delete", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + Description: "The unique identifier of the user group resource.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "group_type": schema.StringAttribute{ - Required: true, - MarkdownDescription: "Type of the user group.", - Validators: []validator.String{ - stringvalidator.LengthAtLeast(1), - }, - }, - "group_id": schema.StringAttribute{ - Required: true, - MarkdownDescription: "Identifier for the user group.", - Validators: []validator.String{ - stringvalidator.LengthAtLeast(1), - }, - // ValidateFunc: validation.StringDoesNotContainAny(" "), - PlanModifiers: []planmodifier.String{ - &validators.UniqueIdentifier{}, - }, - }, - "group_name": schema.StringAttribute{ - Required: true, - MarkdownDescription: "Name of the user group.", - Validators: []validator.String{ - stringvalidator.LengthAtLeast(1), - }, - }, - "parent_id": schema.StringAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Identifier of the parent user group.", - Default: stringdefault.StaticString("root"), + }, + "group_type": schema.StringAttribute{ + Required: true, + MarkdownDescription: "Type of the user group.", + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), }, - "logo_url": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "URL for the user group's logo", + }, + "group_id": schema.StringAttribute{ + Required: true, + MarkdownDescription: "Identifier for the user group.", + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), }, - "description": schema.StringAttribute{ - Optional: true, - MarkdownDescription: "Description of the user group.", - Validators: []validator.String{ - stringvalidator.LengthAtMost(256), - }, + // ValidateFunc: validation.StringDoesNotContainAny(" "), + PlanModifiers: []planmodifier.String{ + &validators.UniqueIdentifier{}, }, - "make_first_user_admin": schema.BoolAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Indicates whether the first user should be made an admin.", - Default: booldefault.StaticBool(false), + }, + "group_name": schema.StringAttribute{ + Required: true, + MarkdownDescription: "Name of the user group.", + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), }, - "member_profile_visibility": schema.StringAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Visibility of member profiles. Allowed values `public` or `full`.", - Validators: []validator.String{ - stringvalidator.OneOf([]string{"public", "full"}...), - }, - Default: stringdefault.StaticString("public"), + }, + "parent_id": schema.StringAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Identifier of the parent user group.", + Default: stringdefault.StaticString("root"), + }, + "logo_url": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "URL for the user group's logo", + }, + "description": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Description of the user group.", + Validators: []validator.String{ + stringvalidator.LengthAtMost(256), }, - "none_member_profile_visibility": schema.StringAttribute{ - Optional: true, - Computed: true, - MarkdownDescription: "Visibility of non-member profiles. Allowed values `none` or `public`.", - Validators: []validator.String{ - stringvalidator.OneOf([]string{"none", "public"}...), - }, - Default: stringdefault.StaticString("none"), + }, + "make_first_user_admin": schema.BoolAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Indicates whether the first user should be made an admin.", + Default: booldefault.StaticBool(false), + }, + "member_profile_visibility": schema.StringAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Visibility of member profiles. Allowed values `public` or `full`.", + Validators: []validator.String{ + stringvalidator.OneOf([]string{"public", "full"}...), }, - "custom_fields": schema.MapAttribute{ - ElementType: types.StringType, - Optional: true, - MarkdownDescription: "Custom fields for the user group.", + Default: stringdefault.StaticString("public"), + }, + "none_member_profile_visibility": schema.StringAttribute{ + Optional: true, + Computed: true, + MarkdownDescription: "Visibility of non-member profiles. Allowed values `none` or `public`.", + Validators: []validator.String{ + stringvalidator.OneOf([]string{"none", "public"}...), }, - "created_at": schema.StringAttribute{ - Computed: true, - Description: "The timestamp when the resource was created.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + Default: stringdefault.StaticString("none"), + }, + "custom_fields": schema.MapAttribute{ + ElementType: types.StringType, + Optional: true, + MarkdownDescription: "Custom fields for the user group.", + }, + "created_at": schema.StringAttribute{ + Computed: true, + Description: "The timestamp when the resource was created.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "updated_at": schema.StringAttribute{ - Computed: true, - Description: "The timestamp when the resource was last updated.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + }, + "updated_at": schema.StringAttribute{ + Computed: true, + Description: "The timestamp when the resource was last updated.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, }, - } + }, } func (r *UserGroupResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { diff --git a/internal/resources/resource_webhook.go b/internal/resources/resource_webhook.go index 4d045d1..e425b2e 100644 --- a/internal/resources/resource_webhook.go +++ b/internal/resources/resource_webhook.go @@ -23,7 +23,18 @@ import ( ) type WebhookResource struct { - cidaasClient *cidaas.Client + BaseResource +} + +func NewWebhookResource() resource.Resource { + return &WebhookResource{ + BaseResource: NewBaseResource( + BaseResourceConfig{ + Name: RESOURCE_WEBHOOK, + Schema: &webhookSchema, + }, + ), + } } type WebhookConfig struct { @@ -52,10 +63,6 @@ type CidaasAuthConfig struct { ClientID types.String `tfsdk:"client_id"` } -func NewWebhookResource() resource.Resource { - return &WebhookResource{} -} - func (w *WebhookConfig) extractAuthConfigs(ctx context.Context) diag.Diagnostics { var diags diag.Diagnostics if !w.APIKeyConfig.IsNull() { @@ -73,164 +80,143 @@ func (w *WebhookConfig) extractAuthConfigs(ctx context.Context) diag.Diagnostics return diags } -func (r *WebhookResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_webhook" -} - -func (r *WebhookResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - if req.ProviderData == nil { - return - } - client, ok := req.ProviderData.(*cidaas.Client) - if !ok { - resp.Diagnostics.AddError( - "Unexpected Resource Configure Type", - fmt.Sprintf("Expected cidaas.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), - ) - return - } - r.cidaasClient = client -} - -func (r *WebhookResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { - resp.Schema = schema.Schema{ - MarkdownDescription: "The Webhook resource in the provider facilitates integration of webhooks in the Cidaas system." + - " This resource allows you to configure webhooks with different authentication options." + - "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + - "\n- cidaas:webhook_read" + - "\n- cidaas:webhook_write" + - "\n- cidaas:webhook_delete", - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - Description: "The unique identifier of the webhook resource.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, +var webhookSchema = schema.Schema{ + MarkdownDescription: "The Webhook resource in the provider facilitates integration of webhooks in the Cidaas system." + + " This resource allows you to configure webhooks with different authentication options." + + "\n\n Ensure that the below scopes are assigned to the client with the specified `client_id`:" + + "\n- cidaas:webhook_read" + + "\n- cidaas:webhook_write" + + "\n- cidaas:webhook_delete", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + Description: "The unique identifier of the webhook resource.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, - "auth_type": schema.StringAttribute{ - Required: true, - Description: "The attribute auth_type is to define how this url is secured from your end." + - "The allowed values are `APIKEY`, `TOTP` and `CIDAAS_OAUTH2`", - Validators: []validator.String{ - stringvalidator.OneOf(cidaas.AllowedAuthType...), - }, - PlanModifiers: []planmodifier.String{ - &configVerifier{}, - }, + }, + "auth_type": schema.StringAttribute{ + Required: true, + Description: "The attribute auth_type is to define how this url is secured from your end." + + "The allowed values are `APIKEY`, `TOTP` and `CIDAAS_OAUTH2`", + Validators: []validator.String{ + stringvalidator.OneOf(cidaas.AllowedAuthType...), }, - "url": schema.StringAttribute{ - Required: true, - Description: "The webhook url that needs to be called when an event occurs.", + PlanModifiers: []planmodifier.String{ + &configVerifier{}, }, - "events": schema.SetAttribute{ - ElementType: types.StringType, - Required: true, - Description: "A set of events that trigger the webhook.", - Validators: []validator.Set{ - setvalidator.SizeAtLeast(1), - setvalidator.ValueStringsAre( - stringvalidator.OneOf(cidaas.AllowedEvents...), - ), - }, + }, + "url": schema.StringAttribute{ + Required: true, + Description: "The webhook url that needs to be called when an event occurs.", + }, + "events": schema.SetAttribute{ + ElementType: types.StringType, + Required: true, + Description: "A set of events that trigger the webhook.", + Validators: []validator.Set{ + setvalidator.SizeAtLeast(1), + setvalidator.ValueStringsAre( + stringvalidator.OneOf(cidaas.AllowedEvents...), + ), }, - "apikey_config": schema.SingleNestedAttribute{ - Optional: true, - Description: "Configuration for API key-based authentication. It's a **required** parameter when the auth_type is APIKEY.", - Attributes: map[string]schema.Attribute{ - "placeholder": schema.StringAttribute{ - Required: true, - Description: "The attribute is the placeholder for the key which need to be passed as a query parameter or in the request header.", - Validators: []validator.String{ - stringvalidator.LengthAtLeast(1), - stringvalidator.RegexMatches( - regexp.MustCompile(`^[a-z]+$`), - "must contain only lowercase alphabets", - ), - }, + }, + "apikey_config": schema.SingleNestedAttribute{ + Optional: true, + Description: "Configuration for API key-based authentication. It's a **required** parameter when the auth_type is APIKEY.", + Attributes: map[string]schema.Attribute{ + "placeholder": schema.StringAttribute{ + Required: true, + Description: "The attribute is the placeholder for the key which need to be passed as a query parameter or in the request header.", + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), + stringvalidator.RegexMatches( + regexp.MustCompile(`^[a-z]+$`), + "must contain only lowercase alphabets", + ), }, - "placement": schema.StringAttribute{ - Required: true, - Description: "The placement of the API key in the request (e.g., query)." + - "The allowed value are `header` and `query`.", - Validators: []validator.String{ - stringvalidator.OneOf(cidaas.AllowedKeyPlacementValue...), - }, + }, + "placement": schema.StringAttribute{ + Required: true, + Description: "The placement of the API key in the request (e.g., query)." + + "The allowed value are `header` and `query`.", + Validators: []validator.String{ + stringvalidator.OneOf(cidaas.AllowedKeyPlacementValue...), }, - "key": schema.StringAttribute{ - Required: true, - Description: "The API key that will be used to authenticate the webhook request." + - "The key that will be passed in the request header or in query param as configured in the attribute `placement`", - Validators: []validator.String{ - stringvalidator.LengthAtLeast(1), - }, + }, + "key": schema.StringAttribute{ + Required: true, + Description: "The API key that will be used to authenticate the webhook request." + + "The key that will be passed in the request header or in query param as configured in the attribute `placement`", + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), }, }, }, - "totp_config": schema.SingleNestedAttribute{ - Optional: true, - Description: "Configuration for TOTP based authentication. It's a **required** parameter when the auth_type is TOTP.", - Attributes: map[string]schema.Attribute{ - "placeholder": schema.StringAttribute{ - Required: true, - Description: "A placeholder value for the TOTP.", - Validators: []validator.String{ - stringvalidator.LengthAtLeast(1), - stringvalidator.RegexMatches( - regexp.MustCompile(`^[a-z]+$`), - "must contain only lowercase alphabets", - ), - }, - }, - "placement": schema.StringAttribute{ - Required: true, - Description: "The placement of the TOTP in the request." + - "The allowed value are `header` and `query`.", - Validators: []validator.String{ - stringvalidator.OneOf(cidaas.AllowedKeyPlacementValue...), - }, + }, + "totp_config": schema.SingleNestedAttribute{ + Optional: true, + Description: "Configuration for TOTP based authentication. It's a **required** parameter when the auth_type is TOTP.", + Attributes: map[string]schema.Attribute{ + "placeholder": schema.StringAttribute{ + Required: true, + Description: "A placeholder value for the TOTP.", + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), + stringvalidator.RegexMatches( + regexp.MustCompile(`^[a-z]+$`), + "must contain only lowercase alphabets", + ), }, - "key": schema.StringAttribute{ - Required: true, - Description: "The key used for TOTP authentication.", - Validators: []validator.String{ - stringvalidator.LengthAtLeast(1), - }, + }, + "placement": schema.StringAttribute{ + Required: true, + Description: "The placement of the TOTP in the request." + + "The allowed value are `header` and `query`.", + Validators: []validator.String{ + stringvalidator.OneOf(cidaas.AllowedKeyPlacementValue...), }, }, - }, - "cidaas_auth_config": schema.SingleNestedAttribute{ - Optional: true, - Description: "Configuration for Cidaas authentication. It's a **required** parameter when the auth_type is CIDAAS_OAUTH2.", - Attributes: map[string]schema.Attribute{ - "client_id": schema.StringAttribute{ - Required: true, - Description: "The client ID for Cidaas authentication.", + "key": schema.StringAttribute{ + Required: true, + Description: "The key used for TOTP authentication.", + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), }, }, }, - "disable": schema.BoolAttribute{ - Optional: true, - Computed: true, - Description: "Flag to disable the webhook.", - Default: booldefault.StaticBool(false), - }, - "created_at": schema.StringAttribute{ - Computed: true, - Description: "The timestamp when the webhook was created.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), + }, + "cidaas_auth_config": schema.SingleNestedAttribute{ + Optional: true, + Description: "Configuration for Cidaas authentication. It's a **required** parameter when the auth_type is CIDAAS_OAUTH2.", + Attributes: map[string]schema.Attribute{ + "client_id": schema.StringAttribute{ + Required: true, + Description: "The client ID for Cidaas authentication.", }, }, - "updated_at": schema.StringAttribute{ - Computed: true, - Description: "The timestamp when the webhook was last updated.", - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, + }, + "disable": schema.BoolAttribute{ + Optional: true, + Computed: true, + Description: "Flag to disable the webhook.", + Default: booldefault.StaticBool(false), + }, + "created_at": schema.StringAttribute{ + Computed: true, + Description: "The timestamp when the webhook was created.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, }, - } + "updated_at": schema.StringAttribute{ + Computed: true, + Description: "The timestamp when the webhook was last updated.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + }, } func (r *WebhookResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { //nolint:dupl diff --git a/templates/resources/app.md.tmpl b/templates/resources/app.md.tmpl index a16b6e3..15e3f4a 100644 --- a/templates/resources/app.md.tmpl +++ b/templates/resources/app.md.tmpl @@ -107,30 +107,65 @@ Alternatively, you can resolve the issue by deleting the existing state of the s However, this approach can be risky, so please proceed with caution. Ensure you only delete the specific resource from the state file that is causing the error, not the entire file or any other resources. -### V3 App Resource Highlights: - -- The resource app can now be set up with minimal configuration. The following parameters are the only required ones to create an app. -In the [schema](#schema) section, only client_name is shown as **required** because the other attributes can be configured in common_configs. -However, each attribute must appear either in the main configuration block or in common_configs. `client_name` cannot be part of common_configs. - - - client_name - - client_type - - company_name - - company_address - - company_website - - allowed_scopes - - redirect_uris - - allowed_logout_urls -- Attribute `common_configs` added to share same configuration across multiple apps. Pleas check the samples in **examples** directory that demonstrates the use of `common_configs`. -- If you need to override any specific attribute for a particular resource where the same attribute is available in `common_configs`, you can supply the main configuration attribute directly within the resource block. -- If your configuration involves a single resource or if the common configuration attributes are not shared across multiple resources we do not suggest using `common_configs`. +From version 3.3.0, the attribute `common_configs` is not supported anymore. Instead, we encourage you to use the custom module **terraform-cidaas-app**. +The module provides a variable with the same name `common_configs` which +supports all the attributes in the resource app except `client_name`. With this module you can avoid the repeated configuration and assign the common properties +of multiple apps to a common variable and inherit the properties. + +Link to the custom module https://github.com/Cidaas/terraform-cidaas-app + +##### Module usage: + +```hcl +// local.tfvars +common_configs = { + client_type = "SINGLE_PAGE" + company_address = "Wimsheim" + company_name = "WidasConcepts GmbH" + company_address = "Maybachstraße 2, 71299 Wimsheim, Germany" + company_website = "https://widas.com" + redirect_uris = [ + "https://cidaas.de/callback", + ] + allowed_logout_urls = [ + "https://cidaas.de/logout" + ] + allowed_scopes = [ + "openid", + ] +} + +// main.tf +provider "cidaas" { + base_url = "https://cidaas.de" +} + +module "app1" { + source = "git@github.com:Cidaas/terraform-cidaas-app.git" + + providers = { + cidaas = cidaas + } + client_name = "Demo App" + common_configs = var.common_configs +} + +module "app2" { + source = "git@github.com:Cidaas/terraform-cidaas-app.git" + providers = { + cidaas = cidaas + } + client_name = "Demo IOS App" + client_type = "IOS" + common_configs = var.common_configs +} +``` +You can explore more on the module in the github repo. ## Example Usage(V3 configuration) {{ tffile "examples/resources/cidaas_app/resource.tf" }} -For more samples on common_configs, please refer to the examples folder. - {{ .SchemaMarkdown | trimspace }} ## Import From 6db955c42ece328faefb0004e63d76e93df8b788 Mon Sep 17 00:00:00 2001 From: Tujit Bora Date: Wed, 30 Oct 2024 12:33:41 +0530 Subject: [PATCH 2/2] readme, changelog & examples update --- CHANGELOG.md | 5 + README.md | 338 +++++------------- docs/resources/app.md | 115 ++---- examples/resources/cidaas_app/resource.tf | 113 +----- examples/resources/cidaas_app/sample1/app.tf | 201 ----------- .../resources/cidaas_app/sample1/local.tfvars | 16 + examples/resources/cidaas_app/sample1/main.tf | 26 ++ .../resources/cidaas_app/sample1/output.tf | 25 ++ .../resources/cidaas_app/sample1/terraform.tf | 9 + .../resources/cidaas_app/sample1/variable.tf | 193 ++++++++++ examples/resources/cidaas_app/sample2/main.tf | 89 ----- .../cidaas_app/sample2/modules/app.tf | 209 ----------- examples/resources/cidaas_app/sample3/main.tf | 12 - .../cidaas_app/sample3/modules/app.tf | 54 --- templates/resources/app.md.tmpl | 2 +- 15 files changed, 395 insertions(+), 1012 deletions(-) delete mode 100644 examples/resources/cidaas_app/sample1/app.tf create mode 100644 examples/resources/cidaas_app/sample1/local.tfvars create mode 100644 examples/resources/cidaas_app/sample1/main.tf create mode 100644 examples/resources/cidaas_app/sample1/output.tf create mode 100644 examples/resources/cidaas_app/sample1/terraform.tf create mode 100644 examples/resources/cidaas_app/sample1/variable.tf delete mode 100644 examples/resources/cidaas_app/sample2/main.tf delete mode 100644 examples/resources/cidaas_app/sample2/modules/app.tf delete mode 100644 examples/resources/cidaas_app/sample3/main.tf delete mode 100644 examples/resources/cidaas_app/sample3/modules/app.tf diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ef19d6..92b9cef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## Changelog +### 3.3.0 +#### Removed common_configs from resource app + +The attribute `common_configs` is removed from the resource cidaas_app as we introduce [terraform-cidaas-app](https://github.com/Cidaas/terraform-cidaas-app) module. + ### 3.2.0 #### Addition of datasources diff --git a/README.md b/README.md index 02e67c3..90d28cc 100644 --- a/README.md +++ b/README.md @@ -238,35 +238,85 @@ Alternatively, you can resolve the issue by deleting the existing state of the s However, this approach can be risky, so please proceed with caution. Ensure you only delete the specific resource from the state file that is causing the error, not the entire file or any other resources. -### V3 App Resource Highlights: - -- The resource app can now be set up with minimal configuration. The following parameters are the only required ones to create an app. -In the [schema](#schema) section, only client_name is shown as **required** because the other attributes can be configured in common_configs. -However, each attribute must appear either in the main configuration block or in common_configs. `client_name` cannot be part of common_configs. - - - client_name - - client_type - - company_name - - company_address - - company_website - - allowed_scopes - - redirect_uris - - allowed_logout_urls -- Attribute `common_configs` added to share same configuration across multiple apps. Pleas check the samples in **examples** directory that demonstrates the use of `common_configs`. -- If you need to override any specific attribute for a particular resource where the same attribute is available in `common_configs`, you can supply the main configuration attribute directly within the resource block. -- If your configuration involves a single resource or if the common configuration attributes are not shared across multiple resources we do not suggest using `common_configs`. +From version 3.3.0, the attribute `common_configs` is not supported anymore. Instead, we encourage you to use the custom module **terraform-cidaas-app**. +The module provides a variable with the same name `common_configs` which +supports all the attributes in the resource app except `client_name`. With this module you can avoid the repeated configuration and assign the common properties +of multiple apps to a common variable and inherit the properties. -## Example Usage(V3 configuration) +Link to the custom module https://github.com/Cidaas/terraform-cidaas-app -```terraform -# This sample demonstrates the use of both main configuration attributes and common_configs. -# It is important to note that configuring both simultaneously is not necessary. -# Please refer to the documentation of the app resource for more details. +##### Module usage: + +```hcl +// local.tfvars +common_configs = { + client_type = "SINGLE_PAGE" + company_address = "Wimsheim" + company_name = "WidasConcepts GmbH" + company_address = "Maybachstraße 2, 71299 Wimsheim, Germany" + company_website = "https://widas.com" + redirect_uris = [ + "https://cidaas.de/callback", + ] + allowed_logout_urls = [ + "https://cidaas.de/logout" + ] + allowed_scopes = [ + "openid", + ] +} + +// main.tf +provider "cidaas" { + base_url = "https://cidaas.de" +} + +module "app1" { + source = "git@github.com:Cidaas/terraform-cidaas-app.git" + + providers = { + cidaas = cidaas + } + client_name = "Demo App" + common_configs = var.common_configs +} + +module "app2" { + source = "git@github.com:Cidaas/terraform-cidaas-app.git" + providers = { + cidaas = cidaas + } + client_name = "Demo IOS App" + client_type = "IOS" + common_configs = var.common_configs +} +``` +You can explore more on the module in the github repo. + +## Example Usage +```terraform resource "cidaas_app" "sample" { client_name = "Test Terraform Application" // unique - client_display_name = "Display Name of the app" // unique - content_align = "CENTER" // Default: CENTER + client_type = "SINGLE_PAGE" + accent_color = "#ef4923" // Default: #ef4923 + primary_color = "#ef4923" // Default: #f7941d + media_type = "IMAGE" // Default: IMAGE + allow_login_with = ["EMAIL", "MOBILE", "USER_NAME"] // Default: ["EMAIL", "MOBILE", "USER_NAME"] + redirect_uris = ["https://cidaas.com"] + allowed_logout_urls = ["https://cidaas.com"] + enable_deduplication = true // Default: false + auto_login_after_register = true // Default: false + enable_passwordless_auth = false // Default: true + register_with_login_information = false // Default: false + fds_enabled = false // Default: true + hosted_page_group = "default" // Default: default + company_name = "Widas ID GmbH" + company_address = "01" + company_website = "https://cidaas.com" + allowed_scopes = ["openid", "cidaas:register", "profile"] + client_display_name = "Display Name of the app" // unique + content_align = "CENTER" // Default: CENTER post_logout_redirect_uris = ["https://cidaas.com"] logo_align = "CENTER" // Default: CENTER allow_disposable_email = false // Default: false @@ -350,105 +400,22 @@ resource "cidaas_app" "sample" { status : "active" version : "1.0.0" } - // common config starts here. The attributes from common config can be part of main config - // if an attribute is available both common_config and main config then attribute from the main config will be considered to create an app - common_configs = { - client_type = "SINGLE_PAGE" - accent_color = "#ef4923" // Default: #ef4923 - primary_color = "#ef4923" // Default: #f7941d - media_type = "IMAGE" // Default: IMAGE - allow_login_with = ["EMAIL", "MOBILE", "USER_NAME"] // Default: ["EMAIL", "MOBILE", "USER_NAME"] - redirect_uris = ["https://cidaas.com"] - allowed_logout_urls = ["https://cidaas.com"] - enable_deduplication = true // Default: false - auto_login_after_register = true // Default: false - enable_passwordless_auth = false // Default: true - register_with_login_information = false // Default: false - fds_enabled = false // Default: true - hosted_page_group = "default" // Default: default - company_name = "Widas ID GmbH" - company_address = "01" - company_website = "https://cidaas.com" - allowed_scopes = ["openid", "cidaas:register", "profile"] - response_types = ["code", "token", "id_token"] // Default: ["code", "token", "id_token"] - grant_types = ["client_credentials"] // Default: ["implicit", "authorization_code", "password", "refresh_token"] - login_providers = ["login_provider1", "login_provider2"] - is_hybrid_app = true // Default: false - allowed_web_origins = ["https://cidaas.com"] - allowed_origins = ["https://cidaas.com"] - default_max_age = 86400 // Default: 86400 - token_lifetime_in_seconds = 86400 // Default: 86400 - id_token_lifetime_in_seconds = 86400 // Default: 86400 - refresh_token_lifetime_in_seconds = 15780000 // Default: 15780000 - template_group_id = "custtemp" // Default: default - editable = true // Default: true - social_providers = [{ - provider_name = "cidaas social provider" - social_id = "fdc63bd0-6044-4fa0-abff" - display_name = "cidaas" - }] - custom_providers = [{ - logo_url = "https://cidaas.com/logo-url" - provider_name = "sample-custom-provider" - display_name = "sample-custom-provider" - type = "CUSTOM_OPENID_CONNECT" - }] - saml_providers = [{ - logo_url = "https://cidaas.com/logo-url" - provider_name = "sample-sampl-provider" - display_name = "sample-sampl-provider" - type = "SAMPL_IDP_PROVIDER" - }] - ad_providers = [{ - logo_url = "https://cidaas.com/logo-url" - provider_name = "sample-ad-provider" - display_name = "sample-ad-provider" - type = "ADD_PROVIDER" - }] - jwe_enabled = true // Default: false - user_consent = true // Default: false - allowed_groups = [{ - group_id = "developer101" - roles = ["developer", "qa", "admin"] - default_roles = ["developer"] - }] - operations_allowed_groups = [{ - group_id = "developer101" - roles = ["developer", "qa", "admin"] - default_roles = ["developer"] - }] - enabled = true // Default: true - always_ask_mfa = true // Default: false - allowed_mfa = ["OFF"] - email_verification_required = true // Default: true - allowed_roles = ["sample"] - default_roles = ["sample"] - enable_classical_provider = true // Default: true - is_remember_me_selected = true // Default: true - bot_provider = "CIDAAS" // Default: CIDAAS - allow_guest_login = true // Default: false - # mfa Default: - # { - # setting = "OFF" - # } - mfa = { - setting = "OFF" - } - webfinger = "no_redirection" - default_scopes = ["sample"] - pending_scopes = ["sample"] - } } ``` -For more samples on common_configs, please refer to the examples folder. - ## Schema ### Required +- `allowed_logout_urls` (Set of String) Allowed logout URLs for OAuth2 client. +- `allowed_scopes` (Set of String) The URL of the company website. allowed_scopes is a required attribute. It must be provided in the main config or common_config - `client_name` (String) Name of the client. +- `client_type` (String) The type of the client. The allowed values are SINGLE_PAGE, REGULAR_WEB, NON_INTERACTIVEIOS, ANDROID, WINDOWS_MOBILE, DESKTOP, MOBILE, DEVICE and THIRD_PARTY +- `company_address` (String) The company address. +- `company_name` (String) The name of the company that the client belongs to. +- `company_website` (String) The URL of the company website. +- `redirect_uris` (Set of String) Redirect URIs for OAuth2 client. ### Optional @@ -461,11 +428,9 @@ For more samples on common_configs, please refer to the examples folder. - `allow_login_with` (Set of String) allow_login_with is used to specify the preferred methods of login allowed for a client. Allowed values are EMAIL, MOBILE and USER_NAMEThe default is set to `['EMAIL', 'MOBILE', 'USER_NAME']`. - `allowed_fields` (Set of String) - `allowed_groups` (Attributes List) (see [below for nested schema](#nestedatt--allowed_groups)) -- `allowed_logout_urls` (Set of String) Allowed logout URLs for OAuth2 client. - `allowed_mfa` (Set of String) - `allowed_origins` (Set of String) List of the origins allowed to access the client. - `allowed_roles` (Set of String) -- `allowed_scopes` (Set of String) The URL of the company website. allowed_scopes is a required attribute. It must be provided in the main config or common_config - `allowed_web_origins` (Set of String) List of the web origins allowed to access the client. - `always_ask_mfa` (Boolean) - `application_meta_data` (Map of String) A map to add metadata of a client. @@ -482,13 +447,8 @@ For more samples on common_configs, please refer to the examples folder. - `client_display_name` (String) The display name of the client. - `client_id` (String) The client_id is the unqique identifier of the app. It's an optional attribute. If not provided, cidaas will gererate one for you and the state will be updated with the same - `client_secret` (String, Sensitive) The client_id is the unqique identifier of the app. It's an optional attribute. If not provided, cidaas will gererate one for you and the state will be updated with the same -- `client_type` (String) The type of the client. The allowed values are SINGLE_PAGE, REGULAR_WEB, NON_INTERACTIVEIOS, ANDROID, WINDOWS_MOBILE, DESKTOP, MOBILE, DEVICE and THIRD_PARTY - `client_uri` (String) -- `common_configs` (Attributes) The `common_configs` attribute is used for sharing the same configuration across multiple cidaas_app resources. It is a map of some attributes from the main configuration. Please check the list of the attributes that it supports in the common_confis section. if an attribute is available both common_config and main config then attribute from the main config will be considered to create an app (see [below for nested schema](#nestedatt--common_configs)) - `communication_medium_verification` (String) -- `company_address` (String) The company address. -- `company_name` (String) The name of the company that the client belongs to. -- `company_website` (String) The URL of the company website. - `consent_page_group` (String) - `consent_refs` (Set of String) - `contacts` (Set of String) The contacts of the client. @@ -543,7 +503,6 @@ For more samples on common_configs, please refer to the examples folder. - `policy_uri` (String) The URL to the policy of a client. - `post_logout_redirect_uris` (Set of String) - `primary_color` (String) The primary color of the client. e.g., `#ef4923`. The value must be a valid hex colorThe default is set to `#f7941d`. -- `redirect_uris` (Set of String) Redirect URIs for OAuth2 client. - `refresh_token_lifetime_in_seconds` (Number) The lifetime of the refresh token in seconds. Default is 15780000 seconds. - `register_with_login_information` (Boolean) Register with login information. Default is set to `false` while creating an app. - `registration_access_token` (String) @@ -639,141 +598,6 @@ Optional: - -### Nested Schema for `common_configs` - -Optional: - -- `accent_color` (String) -- `ad_providers` (Attributes List) (see [below for nested schema](#nestedatt--common_configs--ad_providers)) -- `allow_guest_login` (Boolean) -- `allow_login_with` (Set of String) -- `allowed_groups` (Attributes List) (see [below for nested schema](#nestedatt--common_configs--allowed_groups)) -- `allowed_logout_urls` (Set of String) -- `allowed_mfa` (Set of String) -- `allowed_origins` (Set of String) -- `allowed_roles` (Set of String) -- `allowed_scopes` (Set of String) -- `allowed_web_origins` (Set of String) -- `always_ask_mfa` (Boolean) -- `auto_login_after_register` (Boolean) -- `bot_provider` (String) -- `client_type` (String) -- `company_address` (String) -- `company_name` (String) -- `company_website` (String) -- `custom_providers` (Attributes List) (see [below for nested schema](#nestedatt--common_configs--custom_providers)) -- `default_max_age` (Number) -- `default_roles` (Set of String) -- `default_scopes` (Set of String) -- `editable` (Boolean) -- `email_verification_required` (Boolean) -- `enable_classical_provider` (Boolean) -- `enable_deduplication` (Boolean) -- `enable_passwordless_auth` (Boolean) -- `enabled` (Boolean) -- `fds_enabled` (Boolean) -- `grant_types` (Set of String) -- `hosted_page_group` (String) -- `id_token_lifetime_in_seconds` (Number) -- `is_hybrid_app` (Boolean) -- `is_remember_me_selected` (Boolean) -- `login_providers` (Set of String) -- `logo_align` (String) -- `media_type` (String) -- `mfa` (Attributes) (see [below for nested schema](#nestedatt--common_configs--mfa)) -- `operations_allowed_groups` (Attributes List) (see [below for nested schema](#nestedatt--common_configs--operations_allowed_groups)) -- `pending_scopes` (Set of String) -- `primary_color` (String) -- `redirect_uris` (Set of String) -- `refresh_token_lifetime_in_seconds` (Number) -- `register_with_login_information` (Boolean) -- `response_types` (Set of String) -- `saml_providers` (Attributes List) (see [below for nested schema](#nestedatt--common_configs--saml_providers)) -- `social_providers` (Attributes List) (see [below for nested schema](#nestedatt--common_configs--social_providers)) -- `template_group_id` (String) -- `token_lifetime_in_seconds` (Number) -- `webfinger` (String) - - -### Nested Schema for `common_configs.ad_providers` - -Optional: - -- `display_name` (String) -- `domains` (Set of String) -- `is_provider_visible` (Boolean) -- `logo_url` (String) -- `provider_name` (String) -- `type` (String) - - - -### Nested Schema for `common_configs.allowed_groups` - -Optional: - -- `default_roles` (Set of String) -- `group_id` (String) -- `roles` (Set of String) - - - -### Nested Schema for `common_configs.custom_providers` - -Optional: - -- `display_name` (String) -- `domains` (Set of String) -- `is_provider_visible` (Boolean) -- `logo_url` (String) -- `provider_name` (String) -- `type` (String) - - - -### Nested Schema for `common_configs.mfa` - -Optional: - -- `allowed_methods` (Set of String) -- `setting` (String) -- `time_interval_in_seconds` (Number) - - - -### Nested Schema for `common_configs.operations_allowed_groups` - -Optional: - -- `default_roles` (Set of String) -- `group_id` (String) -- `roles` (Set of String) - - - -### Nested Schema for `common_configs.saml_providers` - -Optional: - -- `display_name` (String) -- `domains` (Set of String) -- `is_provider_visible` (Boolean) -- `logo_url` (String) -- `provider_name` (String) -- `type` (String) - - - -### Nested Schema for `common_configs.social_providers` - -Optional: - -- `provider_name` (String) -- `social_id` (String) - - - ### Nested Schema for `custom_providers` diff --git a/docs/resources/app.md b/docs/resources/app.md index 6db1819..de2b204 100644 --- a/docs/resources/app.md +++ b/docs/resources/app.md @@ -169,17 +169,30 @@ module "app2" { ``` You can explore more on the module in the github repo. -## Example Usage(V3 configuration) +## Example Usage ```terraform -# This sample demonstrates the use of both main configuration attributes and common_configs. -# It is important to note that configuring both simultaneously is not necessary. -# Please refer to the documentation of the app resource for more details. - resource "cidaas_app" "sample" { client_name = "Test Terraform Application" // unique - client_display_name = "Display Name of the app" // unique - content_align = "CENTER" // Default: CENTER + client_type = "SINGLE_PAGE" + accent_color = "#ef4923" // Default: #ef4923 + primary_color = "#ef4923" // Default: #f7941d + media_type = "IMAGE" // Default: IMAGE + allow_login_with = ["EMAIL", "MOBILE", "USER_NAME"] // Default: ["EMAIL", "MOBILE", "USER_NAME"] + redirect_uris = ["https://cidaas.com"] + allowed_logout_urls = ["https://cidaas.com"] + enable_deduplication = true // Default: false + auto_login_after_register = true // Default: false + enable_passwordless_auth = false // Default: true + register_with_login_information = false // Default: false + fds_enabled = false // Default: true + hosted_page_group = "default" // Default: default + company_name = "Widas ID GmbH" + company_address = "01" + company_website = "https://cidaas.com" + allowed_scopes = ["openid", "cidaas:register", "profile"] + client_display_name = "Display Name of the app" // unique + content_align = "CENTER" // Default: CENTER post_logout_redirect_uris = ["https://cidaas.com"] logo_align = "CENTER" // Default: CENTER allow_disposable_email = false // Default: false @@ -263,94 +276,6 @@ resource "cidaas_app" "sample" { status : "active" version : "1.0.0" } - // common config starts here. The attributes from common config can be part of main config - // if an attribute is available both common_config and main config then attribute from the main config will be considered to create an app - common_configs = { - client_type = "SINGLE_PAGE" - accent_color = "#ef4923" // Default: #ef4923 - primary_color = "#ef4923" // Default: #f7941d - media_type = "IMAGE" // Default: IMAGE - allow_login_with = ["EMAIL", "MOBILE", "USER_NAME"] // Default: ["EMAIL", "MOBILE", "USER_NAME"] - redirect_uris = ["https://cidaas.com"] - allowed_logout_urls = ["https://cidaas.com"] - enable_deduplication = true // Default: false - auto_login_after_register = true // Default: false - enable_passwordless_auth = false // Default: true - register_with_login_information = false // Default: false - fds_enabled = false // Default: true - hosted_page_group = "default" // Default: default - company_name = "Widas ID GmbH" - company_address = "01" - company_website = "https://cidaas.com" - allowed_scopes = ["openid", "cidaas:register", "profile"] - response_types = ["code", "token", "id_token"] // Default: ["code", "token", "id_token"] - grant_types = ["client_credentials"] // Default: ["implicit", "authorization_code", "password", "refresh_token"] - login_providers = ["login_provider1", "login_provider2"] - is_hybrid_app = true // Default: false - allowed_web_origins = ["https://cidaas.com"] - allowed_origins = ["https://cidaas.com"] - default_max_age = 86400 // Default: 86400 - token_lifetime_in_seconds = 86400 // Default: 86400 - id_token_lifetime_in_seconds = 86400 // Default: 86400 - refresh_token_lifetime_in_seconds = 15780000 // Default: 15780000 - template_group_id = "custtemp" // Default: default - editable = true // Default: true - social_providers = [{ - provider_name = "cidaas social provider" - social_id = "fdc63bd0-6044-4fa0-abff" - display_name = "cidaas" - }] - custom_providers = [{ - logo_url = "https://cidaas.com/logo-url" - provider_name = "sample-custom-provider" - display_name = "sample-custom-provider" - type = "CUSTOM_OPENID_CONNECT" - }] - saml_providers = [{ - logo_url = "https://cidaas.com/logo-url" - provider_name = "sample-sampl-provider" - display_name = "sample-sampl-provider" - type = "SAMPL_IDP_PROVIDER" - }] - ad_providers = [{ - logo_url = "https://cidaas.com/logo-url" - provider_name = "sample-ad-provider" - display_name = "sample-ad-provider" - type = "ADD_PROVIDER" - }] - jwe_enabled = true // Default: false - user_consent = true // Default: false - allowed_groups = [{ - group_id = "developer101" - roles = ["developer", "qa", "admin"] - default_roles = ["developer"] - }] - operations_allowed_groups = [{ - group_id = "developer101" - roles = ["developer", "qa", "admin"] - default_roles = ["developer"] - }] - enabled = true // Default: true - always_ask_mfa = true // Default: false - allowed_mfa = ["OFF"] - email_verification_required = true // Default: true - allowed_roles = ["sample"] - default_roles = ["sample"] - enable_classical_provider = true // Default: true - is_remember_me_selected = true // Default: true - bot_provider = "CIDAAS" // Default: CIDAAS - allow_guest_login = true // Default: false - # mfa Default: - # { - # setting = "OFF" - # } - mfa = { - setting = "OFF" - } - webfinger = "no_redirection" - default_scopes = ["sample"] - pending_scopes = ["sample"] - } } ``` diff --git a/examples/resources/cidaas_app/resource.tf b/examples/resources/cidaas_app/resource.tf index 835d2b6..404a9f4 100644 --- a/examples/resources/cidaas_app/resource.tf +++ b/examples/resources/cidaas_app/resource.tf @@ -1,11 +1,24 @@ -# This sample demonstrates the use of both main configuration attributes and common_configs. -# It is important to note that configuring both simultaneously is not necessary. -# Please refer to the documentation of the app resource for more details. - resource "cidaas_app" "sample" { client_name = "Test Terraform Application" // unique - client_display_name = "Display Name of the app" // unique - content_align = "CENTER" // Default: CENTER + client_type = "SINGLE_PAGE" + accent_color = "#ef4923" // Default: #ef4923 + primary_color = "#ef4923" // Default: #f7941d + media_type = "IMAGE" // Default: IMAGE + allow_login_with = ["EMAIL", "MOBILE", "USER_NAME"] // Default: ["EMAIL", "MOBILE", "USER_NAME"] + redirect_uris = ["https://cidaas.com"] + allowed_logout_urls = ["https://cidaas.com"] + enable_deduplication = true // Default: false + auto_login_after_register = true // Default: false + enable_passwordless_auth = false // Default: true + register_with_login_information = false // Default: false + fds_enabled = false // Default: true + hosted_page_group = "default" // Default: default + company_name = "Widas ID GmbH" + company_address = "01" + company_website = "https://cidaas.com" + allowed_scopes = ["openid", "cidaas:register", "profile"] + client_display_name = "Display Name of the app" // unique + content_align = "CENTER" // Default: CENTER post_logout_redirect_uris = ["https://cidaas.com"] logo_align = "CENTER" // Default: CENTER allow_disposable_email = false // Default: false @@ -89,92 +102,4 @@ resource "cidaas_app" "sample" { status : "active" version : "1.0.0" } - // common config starts here. The attributes from common config can be part of main config - // if an attribute is available both common_config and main config then attribute from the main config will be considered to create an app - common_configs = { - client_type = "SINGLE_PAGE" - accent_color = "#ef4923" // Default: #ef4923 - primary_color = "#ef4923" // Default: #f7941d - media_type = "IMAGE" // Default: IMAGE - allow_login_with = ["EMAIL", "MOBILE", "USER_NAME"] // Default: ["EMAIL", "MOBILE", "USER_NAME"] - redirect_uris = ["https://cidaas.com"] - allowed_logout_urls = ["https://cidaas.com"] - enable_deduplication = true // Default: false - auto_login_after_register = true // Default: false - enable_passwordless_auth = false // Default: true - register_with_login_information = false // Default: false - fds_enabled = false // Default: true - hosted_page_group = "default" // Default: default - company_name = "Widas ID GmbH" - company_address = "01" - company_website = "https://cidaas.com" - allowed_scopes = ["openid", "cidaas:register", "profile"] - response_types = ["code", "token", "id_token"] // Default: ["code", "token", "id_token"] - grant_types = ["client_credentials"] // Default: ["implicit", "authorization_code", "password", "refresh_token"] - login_providers = ["login_provider1", "login_provider2"] - is_hybrid_app = true // Default: false - allowed_web_origins = ["https://cidaas.com"] - allowed_origins = ["https://cidaas.com"] - default_max_age = 86400 // Default: 86400 - token_lifetime_in_seconds = 86400 // Default: 86400 - id_token_lifetime_in_seconds = 86400 // Default: 86400 - refresh_token_lifetime_in_seconds = 15780000 // Default: 15780000 - template_group_id = "custtemp" // Default: default - editable = true // Default: true - social_providers = [{ - provider_name = "cidaas social provider" - social_id = "fdc63bd0-6044-4fa0-abff" - display_name = "cidaas" - }] - custom_providers = [{ - logo_url = "https://cidaas.com/logo-url" - provider_name = "sample-custom-provider" - display_name = "sample-custom-provider" - type = "CUSTOM_OPENID_CONNECT" - }] - saml_providers = [{ - logo_url = "https://cidaas.com/logo-url" - provider_name = "sample-sampl-provider" - display_name = "sample-sampl-provider" - type = "SAMPL_IDP_PROVIDER" - }] - ad_providers = [{ - logo_url = "https://cidaas.com/logo-url" - provider_name = "sample-ad-provider" - display_name = "sample-ad-provider" - type = "ADD_PROVIDER" - }] - jwe_enabled = true // Default: false - user_consent = true // Default: false - allowed_groups = [{ - group_id = "developer101" - roles = ["developer", "qa", "admin"] - default_roles = ["developer"] - }] - operations_allowed_groups = [{ - group_id = "developer101" - roles = ["developer", "qa", "admin"] - default_roles = ["developer"] - }] - enabled = true // Default: true - always_ask_mfa = true // Default: false - allowed_mfa = ["OFF"] - email_verification_required = true // Default: true - allowed_roles = ["sample"] - default_roles = ["sample"] - enable_classical_provider = true // Default: true - is_remember_me_selected = true // Default: true - bot_provider = "CIDAAS" // Default: CIDAAS - allow_guest_login = true // Default: false - # mfa Default: - # { - # setting = "OFF" - # } - mfa = { - setting = "OFF" - } - webfinger = "no_redirection" - default_scopes = ["sample"] - pending_scopes = ["sample"] - } } diff --git a/examples/resources/cidaas_app/sample1/app.tf b/examples/resources/cidaas_app/sample1/app.tf deleted file mode 100644 index 435cb54..0000000 --- a/examples/resources/cidaas_app/sample1/app.tf +++ /dev/null @@ -1,201 +0,0 @@ -terraform { - required_providers { - cidaas = { - source = "hashicorp.com/Cidaas/cidaas" - version = "3.0.0" - } - } -} - -provider "cidaas" { - base_url = "https://cidaas.de" -} -// For string attributes please don't provide value as empty string otherwise you will end up getting an error like below -# When applying changes to cidaas_app.sample, provider -# "provider[\"hashicorp.com/cidaas/cidaas\"]" produced an unexpected new value: -# .consent_page_group: was cty.StringVal(""), but now null. - -# This is a bug in the provider, which should be reported in the provider's own issue -# tracker. - -# For an attribute with default value, if not provided in the config then default will be considered while creating the app -# The default values of the attributes are shared next to the attributes - - -# The config below has the list of common config and main config -resource "cidaas_app" "sample" { - client_name = "Test Terraform Application" // unique - client_display_name = "Display Name of the app" // unique - content_align = "CENTER" // Default: CENTER - post_logout_redirect_uris = ["https://cidaas.com"] - logo_align = "CENTER" // Default: CENTER - allow_disposable_email = false // Default: false - validate_phone_number = false // Default: false - additional_access_token_payload = ["sample_payload"] - required_fields = ["email"] - mobile_settings = { - team_id = "sample-team-id" - bundle_id = "sample-bundle-id" - package_name = "sample-package-name" - key_hash = "sample-key-hash" - } - // for custom client credentials use client_id and client_secret, you can leave blank if you want cidaas to create a set for you - # client_id = "" - # client_secret = "" - policy_uri = "https://cidaas.com" - tos_uri = "https://cidaas.com" - imprint_uri = "https://cidaas.com" - contacts = ["support@cidas.de"] - token_endpoint_auth_method = "client_secret_post" // Default: client_secret_post - token_endpoint_auth_signing_alg = "RS256" // Default: RS256 - default_acr_values = ["default"] - web_message_uris = ["https://cidaas.com"] - allowed_fields = ["email"] - smart_mfa = false // Default: false - captcha_ref = "sample-captcha-ref" - captcha_refs = ["sample"] - consent_refs = ["sample"] - communication_medium_verification = "email_verification_required_on_usage" - mobile_number_verification_required = false // Default: false - enable_bot_detection = false // Default: false - allow_guest_login_groups = [{ - group_id = "developer101" - roles = ["developer", "qa", "admin"] - default_roles = ["developer"] - }] - is_login_success_page_enabled = false // Default: false - is_register_success_page_enabled = false // Default: false - group_ids = ["sample"] - is_group_login_selection_enabled = false // Default: false - group_selection = { - selectable_groups = ["developer-users"] - selectable_group_types = ["sample"] - } - group_types = ["sample"] - logo_uri = "https://cidaas.com" - initiate_login_uri = "https://cidaas.com" - registration_client_uri = "https://cidaas.com" - registration_access_token = "registration access token" - client_uri = "https://cidaas.com" - jwks_uri = "https://cidaas.com" - jwks = "https://cidaas.com/jwks" - sector_identifier_uri = "https://cidaas.com" - subject_type = "sample subject type" - id_token_signed_response_alg = "RS256" - id_token_encrypted_response_alg = "RS256" - id_token_encrypted_response_enc = "example" - userinfo_signed_response_alg = "RS256" - userinfo_encrypted_response_alg = "RS256" - userinfo_encrypted_response_enc = "example" - request_object_signing_alg = "RS256" - request_object_encryption_alg = "RS256" - request_object_encryption_enc = "userinfo_encrypted_response_enc" - request_uris = ["sample"] - description = "app description" - consent_page_group = "sample-consent-page-group" - password_policy_ref = "password-policy-ref" - blocking_mechanism_ref = "blocking-mechanism-ref" - sub = "sample-sub" - role = "sample-role" - mfa_configuration = "sample-configuration" - suggest_mfa = ["OFF"] - login_spi = { - oauth_client_id = "bcb-4a6b-9777-8a64abe6af" - spi_url = "https://cidaas.com/spi-url" - } - background_uri = "https://cidaas.com" - video_url = "https://cidaas.com" - bot_captcha_ref = "sample-bot-captcha-ref" - application_meta_data = { - status : "active" - version : "1.0.0" - } - // common config starts here. The attributes from common config can be part of main config - // if an attribute is available both common_config and main config then attribute from the main config will be considered to create an app - common_configs = { - client_type = "SINGLE_PAGE" - accent_color = "#ef4923" // Default: #ef4923 - primary_color = "#ef4923" // Default: #f7941d - media_type = "IMAGE" // Default: IMAGE - allow_login_with = ["EMAIL", "MOBILE", "USER_NAME"] // Default: ["EMAIL", "MOBILE", "USER_NAME"] - redirect_uris = ["https://cidaas.com"] - allowed_logout_urls = ["https://cidaas.com"] - enable_deduplication = true // Default: false - auto_login_after_register = true // Default: false - enable_passwordless_auth = false // Default: true - register_with_login_information = false // Default: false - fds_enabled = false // Default: true - hosted_page_group = "default" // Default: default - company_name = "Widas ID GmbH" - company_address = "01" - company_website = "https://cidaas.com" - allowed_scopes = ["openid", "cidaas:register", "profile"] - response_types = ["code", "token", "id_token"] // Default: ["code", "token", "id_token"] - grant_types = ["client_credentials"] // Default: ["implicit", "authorization_code", "password", "refresh_token"] - login_providers = ["login_provider1", "login_provider2"] - is_hybrid_app = true // Default: false - allowed_web_origins = ["https://cidaas.com"] - allowed_origins = ["https://cidaas.com"] - default_max_age = 86400 // Default: 86400 - token_lifetime_in_seconds = 86400 // Default: 86400 - id_token_lifetime_in_seconds = 86400 // Default: 86400 - refresh_token_lifetime_in_seconds = 15780000 // Default: 15780000 - template_group_id = "custtemp" // Default: default - editable = true // Default: true - social_providers = [{ - provider_name = "cidaas social provider" - social_id = "fdc63bd0-6044-4fa0-abff" - display_name = "cidaas" - }] - custom_providers = [{ - logo_url = "https://cidaas.com/logo-url" - provider_name = "sample-custom-provider" - display_name = "sample-custom-provider" - type = "CUSTOM_OPENID_CONNECT" - }] - saml_providers = [{ - logo_url = "https://cidaas.com/logo-url" - provider_name = "sample-sampl-provider" - display_name = "sample-sampl-provider" - type = "SAMPL_IDP_PROVIDER" - }] - ad_providers = [{ - logo_url = "https://cidaas.com/logo-url" - provider_name = "sample-ad-provider" - display_name = "sample-ad-provider" - type = "ADD_PROVIDER" - }] - jwe_enabled = true // Default: false - user_consent = true // Default: false - allowed_groups = [{ - group_id = "developer101" - roles = ["developer", "qa", "admin"] - default_roles = ["developer"] - }] - operations_allowed_groups = [{ - group_id = "developer101" - roles = ["developer", "qa", "admin"] - default_roles = ["developer"] - }] - enabled = true // Default: true - always_ask_mfa = true // Default: false - allowed_mfa = ["OFF"] - email_verification_required = true // Default: true - allowed_roles = ["sample"] - default_roles = ["sample"] - enable_classical_provider = true // Default: true - is_remember_me_selected = true // Default: true - bot_provider = "CIDAAS" // Default: CIDAAS - allow_guest_login = true // Default: false - # mfa Default: - # { - # setting = "OFF" - # } - mfa = { - setting = "OFF" - } - webfinger = "no_redirection" - default_scopes = ["sample"] - pending_scopes = ["sample"] - } -} diff --git a/examples/resources/cidaas_app/sample1/local.tfvars b/examples/resources/cidaas_app/sample1/local.tfvars new file mode 100644 index 0000000..6e1f968 --- /dev/null +++ b/examples/resources/cidaas_app/sample1/local.tfvars @@ -0,0 +1,16 @@ +common_configs = { + client_type = "SINGLE_PAGE" + company_address = "Maybachstraße 2, 71299 Wimsheim, Germany" + company_name = "WidasConcepts GmbH" + company_website = "https://widas.com" + redirect_uris = [ + "https://cidaas.de/home", + ] + allowed_logout_urls = [ + "https://cidaas.de/logout" + ] + allowed_scopes = [ + "openid", + ] + accent_color = "#FFFFFF" +} diff --git a/examples/resources/cidaas_app/sample1/main.tf b/examples/resources/cidaas_app/sample1/main.tf new file mode 100644 index 0000000..e048578 --- /dev/null +++ b/examples/resources/cidaas_app/sample1/main.tf @@ -0,0 +1,26 @@ +provider "cidaas" { + base_url = "https://cidaas.dev.de" +} + +module "app1" { + source = "git@github.com:Cidaas/terraform-cidaas-app.git" + + providers = { + cidaas = cidaas + } + + client_name = "Demo SP App" + common_configs = var.common_configs +} + +module "app2" { + source = "git@github.com:Cidaas/terraform-cidaas-app.git" + + providers = { + cidaas = cidaas + } + + client_name = "Test ISO App" + client_type = "IOS" + common_configs = var.common_configs +} diff --git a/examples/resources/cidaas_app/sample1/output.tf b/examples/resources/cidaas_app/sample1/output.tf new file mode 100644 index 0000000..ecaf19e --- /dev/null +++ b/examples/resources/cidaas_app/sample1/output.tf @@ -0,0 +1,25 @@ +output "app1_client_id" { + value = module.app1.client_id +} + +output "app2_client_id" { + value = module.app2.client_id +} + +output "app1_client_name" { + value = module.app1.client_name +} + +output "app2_client_name" { + value = module.app2.client_name +} + +output "app1_client_secret" { + value = module.app1.client_secret + sensitive = true +} + +output "app2_client_secret" { + value = module.app2.client_secret + sensitive = true +} diff --git a/examples/resources/cidaas_app/sample1/terraform.tf b/examples/resources/cidaas_app/sample1/terraform.tf new file mode 100644 index 0000000..0f903a1 --- /dev/null +++ b/examples/resources/cidaas_app/sample1/terraform.tf @@ -0,0 +1,9 @@ + +terraform { + required_providers { + cidaas = { + source = "cidaas/cidaas" + version = ">=3.2.0" + } + } +} diff --git a/examples/resources/cidaas_app/sample1/variable.tf b/examples/resources/cidaas_app/sample1/variable.tf new file mode 100644 index 0000000..1fafb10 --- /dev/null +++ b/examples/resources/cidaas_app/sample1/variable.tf @@ -0,0 +1,193 @@ +variable "common_configs" { + type = object({ + client_type = optional(string) + company_name = optional(string) + company_address = optional(string) + company_website = optional(string) + allowed_scopes = optional(list(string)) + redirect_uris = optional(list(string)) + allowed_logout_urls = optional(list(string)) + allowed_groups = optional(list(object({ + group_id = string + roles = list(string) + default_roles = list(string) + }))) + primary_color = optional(string) + media_type = optional(string) + content_align = optional(string) + allow_login_with = optional(list(string)) + enable_deduplication = optional(bool) + auto_login_after_register = optional(bool) + enable_passwordless_auth = optional(bool) + register_with_login_information = optional(bool) + allow_disposable_email = optional(bool) + validate_phone_number = optional(bool) + fds_enabled = optional(bool) + hosted_page_group = optional(string) + client_display_name = optional(string) + response_types = optional(list(string)) + grant_types = optional(list(string)) + login_providers = optional(list(string)) + additional_access_token_payload = optional(list(string)) + required_fields = optional(list(string)) + is_hybrid_app = optional(bool) + allowed_web_origins = optional(list(string)) + allowed_origins = optional(list(string)) + mobile_settings = optional(object({ + team_id = optional(string) + bundle_id = optional(string) + package_name = optional(string) + key_hash = optional(string) + })) + default_max_age = optional(number) + token_lifetime_in_seconds = optional(number) + id_token_lifetime_in_seconds = optional(number) + refresh_token_lifetime_in_seconds = optional(number) + template_group_id = optional(string) + client_id = optional(string) + client_secret = optional(string) + saml_providers = optional(list(object({ + provider_name = string + display_name = string + logo_url = optional(string) + type = string + is_provider_visible = optional(bool) + domains = optional(list(string)) + }))) + ad_providers = optional(list(object({ + provider_name = string + display_name = string + logo_url = optional(string) + type = string + is_provider_visible = optional(bool) + domains = optional(list(string)) + }))) + jwe_enabled = optional(bool) + user_consent = optional(bool) + operations_allowed_groups = optional(list(object({ + group_id = string + roles = list(string) + default_roles = list(string) + }))) + enabled = optional(bool) + allowed_fields = optional(list(string)) + always_ask_mfa = optional(bool) + smart_mfa = optional(bool) + allowed_mfa = optional(list(string)) + captcha_ref = optional(string) + captcha_refs = optional(list(string)) + consent_refs = optional(list(string)) + communication_medium_verification = optional(string) + email_verification_required = optional(bool) + mobile_number_verification_required = optional(bool) + allowed_roles = optional(list(string)) + default_roles = optional(list(string)) + enable_classical_provider = optional(bool) + is_remember_me_selected = optional(bool) + enable_bot_detection = optional(bool) + bot_provider = optional(string) + allow_guest_login_groups = optional(list(object({ + group_id = string + roles = list(string) + default_roles = list(string) + }))) + is_login_success_page_enabled = optional(bool) + is_register_success_page_enabled = optional(bool) + group_ids = optional(list(string)) + is_group_login_selection_enabled = optional(bool) + group_selection = optional(object({ + always_show_group_selection = optional(bool) + selectable_groups = optional(list(string)) + selectable_group_types = optional(list(string)) + })) + group_types = optional(list(string)) + backchannel_logout_uri = optional(string) + post_logout_redirect_uris = optional(list(string)) + userinfo_signed_response_alg = optional(string) + userinfo_encrypted_response_alg = optional(string) + userinfo_encrypted_response_enc = optional(string) + request_object_signing_alg = optional(string) + request_object_encryption_alg = optional(string) + request_object_encryption_enc = optional(string) + request_uris = optional(list(string)) + description = optional(string) + default_scopes = optional(list(string)) + pending_scopes = optional(list(string)) + consent_page_group = optional(string) + password_policy_ref = optional(string) + blocking_mechanism_ref = optional(string) + sub = optional(string) + role = optional(string) + mfa_configuration = optional(string) + suggest_mfa = optional(list(string)) + login_spi = optional(object({ + oauth_client_id = optional(string) + spi_url = optional(string) + })) + background_uri = optional(string) + video_url = optional(string) + bot_captcha_ref = optional(string) + application_meta_data = optional(map(string)) + allow_guest_login = optional(bool) + group_role_restriction = optional(object({ + match_condition = optional(string) + filters = optional(list(object({ + group_id = string + role_filter = object({ + match_condition = string + roles = list(string) + }) + }))) + })) + basic_settings = optional(object({ + client_secrets = optional(list(object({ + client_secret = optional(string) + client_secret_expires_at = optional(number) + }))) + })) + mfa = optional(object({ + setting = optional(string) + time_interval_in_seconds = optional(number) + allowed_methods = optional(list(string)) + })) + social_providers = optional(list(object({ + provider_name = optional(string) + social_id = optional(string) + }))) + custom_providers = optional(list(object({ + provider_name = optional(string) + display_name = optional(string) + logo_url = optional(string) + type = optional(string) + is_provider_visible = optional(bool) + domains = optional(list(string)) + }))) + accent_color = optional(string) + logo_align = optional(string) + webfinger = optional(string) + require_auth_time = optional(bool) + enable_login_spi = optional(bool) + backchannel_logout_session_required = optional(bool) + suggest_verification_methods = optional(object({ + mandatory_config = optional(object({ + methods = optional(list(string)) + range = optional(string) + skip_until = optional(string) + })) + optional_config = optional(object({ + methods = optional(list(string)) + })) + skip_duration_in_days = optional(number) + })) + policy_uri = optional(string) + tos_uri = optional(string) + imprint_uri = optional(string) + contacts = optional(list(string)) + token_endpoint_auth_method = optional(string) + token_endpoint_auth_signing_alg = optional(string) + default_acr_values = optional(list(string)) + editable = optional(bool) + web_message_uris = optional(list(string)) + }) + default = {} +} diff --git a/examples/resources/cidaas_app/sample2/main.tf b/examples/resources/cidaas_app/sample2/main.tf deleted file mode 100644 index e1fa570..0000000 --- a/examples/resources/cidaas_app/sample2/main.tf +++ /dev/null @@ -1,89 +0,0 @@ -module "shared_settings" { - source = "./modules" - common_config = { - client_type = "SINGLE_PAGE" - accent_color = "#ef4923" // Default: #ef4923 - primary_color = "#ef4923" // Default: #f7941d - media_type = "IMAGE" // Default: IMAGE - allow_login_with = ["EMAIL", "MOBILE", "USER_NAME"] // Default: ["EMAIL", "MOBILE", "USER_NAME"] - redirect_uris = ["https://cidaas.com"] - allowed_logout_urls = ["https://cidaas.com"] - enable_deduplication = true // Default: false - auto_login_after_register = true // Default: false - enable_passwordless_auth = false // Default: true - register_with_login_information = false // Default: false - fds_enabled = false // Default: true - hosted_page_group = "default" // Default: default - company_name = "Widas ID GmbH" - company_address = "01" - company_website = "https://cidaas.com" - allowed_scopes = ["openid", "cidaas:register", "profile"] - response_types = ["code", "token", "id_token"] // Default: ["code", "token", "id_token"] - grant_types = ["client_credentials"] // Default: ["implicit", "authorization_code", "password", "refresh_token"] - login_providers = ["login_provider1", "login_provider2"] - is_hybrid_app = true // Default: false - allowed_web_origins = ["https://cidaas.com"] - allowed_origins = ["https://cidaas.com"] - default_max_age = 86400 // Default: 86400 - token_lifetime_in_seconds = 86400 // Default: 86400 - id_token_lifetime_in_seconds = 86400 // Default: 86400 - refresh_token_lifetime_in_seconds = 15780000 // Default: 15780000 - template_group_id = "custtemp" // Default: default - editable = true // Default: true - social_providers = [{ - provider_name = "cidaas social provider" - social_id = "fdc63bd0-6044-4fa0-abff" - display_name = "cidaas" - }] - custom_providers = [{ - logo_url = "https://cidaas.com/logo-url" - provider_name = "sample-custom-provider" - display_name = "sample-custom-provider" - type = "CUSTOM_OPENID_CONNECT" - }] - saml_providers = [{ - logo_url = "https://cidaas.com/logo-url" - provider_name = "sample-sampl-provider" - display_name = "sample-sampl-provider" - type = "SAMPL_IDP_PROVIDER" - }] - ad_providers = [{ - logo_url = "https://cidaas.com/logo-url" - provider_name = "sample-ad-provider" - display_name = "sample-ad-provider" - type = "ADD_PROVIDER" - }] - jwe_enabled = true // Default: false - user_consent = true // Default: false - allowed_groups = [{ - group_id = "developer101" - roles = ["developer", "qa", "admin"] - default_roles = ["developer"] - }] - operations_allowed_groups = [{ - group_id = "developer101" - roles = ["developer", "qa", "admin"] - default_roles = ["developer"] - }] - enabled = true // Default: true - always_ask_mfa = true // Default: false - allowed_mfa = ["OFF"] - email_verification_required = true // Default: true - allowed_roles = ["sample"] - default_roles = ["sample"] - enable_classical_provider = true // Default: true - is_remember_me_selected = true // Default: true - bot_provider = "CIDAAS" // Default: CIDAAS - allow_guest_login = true // Default: false - # mfa Default: - # { - # setting = "OFF" - # } - mfa = { - setting = "OFF" - } - webfinger = "no_redirection" - default_scopes = ["sample"] - pending_scopes = ["sample"] - } -} diff --git a/examples/resources/cidaas_app/sample2/modules/app.tf b/examples/resources/cidaas_app/sample2/modules/app.tf deleted file mode 100644 index 10cc423..0000000 --- a/examples/resources/cidaas_app/sample2/modules/app.tf +++ /dev/null @@ -1,209 +0,0 @@ -variable "common_config" { - type = object({ - client_type = string - accent_color = string // Default: #ef4923 - primary_color = string // Default: #f7941d - media_type = string // Default: IMAGE - allow_login_with = set(string) // Default: ["EMAIL", "MOBILE", "USER_NAME"] - redirect_uris = set(string) - allowed_logout_urls = set(string) - enable_deduplication = bool // Default: false - auto_login_after_register = bool // Default: false - enable_passwordless_auth = bool // Default: true - register_with_login_information = bool // Default: false - fds_enabled = bool // Default: true - hosted_page_group = string // Default: default - company_name = string - company_address = string - company_website = string - allowed_scopes = set(string) - response_types = set(string) // Default: ["code", "token", "id_token"] - grant_types = set(string) // Default: ["implicit", "authorization_code", "password", "refresh_token"] - login_providers = set(string) - is_hybrid_app = bool // Default: false - allowed_web_origins = set(string) - allowed_origins = set(string) - default_max_age = number // Default: 86400 - token_lifetime_in_seconds = number // Default: 86400 - id_token_lifetime_in_seconds = number // Default: 86400 - refresh_token_lifetime_in_seconds = number // Default: 15780000 - template_group_id = string // Default: default - editable = bool // Default: true - social_providers = list(object({ - provider_name = string - social_id = string - display_name = string - })) - custom_providers = list(object({ - logo_url = string - provider_name = string - display_name = string - type = string - })) - saml_providers = list(object({ - logo_url = string - provider_name = string - display_name = string - type = string - })) - ad_providers = list(object({ - logo_url = string - provider_name = string - display_name = string - type = string - })) - jwe_enabled = bool // Default: false - user_consent = bool // Default: false - allowed_groups = list(object({ - group_id = string - roles = set(string) - default_roles = set(string) - })) - operations_allowed_groups = list(object({ - group_id = string - roles = set(string) - default_roles = set(string) - })) - enabled = bool // Default: true - always_ask_mfa = bool // Default: false - allowed_mfa = set(string) - email_verification_required = bool // Default: true - allowed_roles = set(string) - default_roles = set(string) - enable_classical_provider = bool // Default: true - is_remember_me_selected = bool // Default: true - bot_provider = string // Default: CIDAAS - allow_guest_login = bool // Default: false - # mfa Default: - # { - # setting = "OFF" - # } - mfa = object({ - setting = string - }) - webfinger = string - default_scopes = set(string) - pending_scopes = set(string) - }) -} - - - -terraform { - required_providers { - cidaas = { - source = "hashicorp.com/Cidaas/cidaas" - version = "3.0.0" - } - } -} - -provider "cidaas" { - base_url = "https://cidaas.de" -} -// For string attributes please don't provide value as empty string otherwise you will end up getting an error like below -# When applying changes to cidaas_app.sample, provider -# "provider[\"hashicorp.com/cidaas/cidaas\"]" produced an unexpected new value: -# .consent_page_group: was cty.StringVal(""), but now null. - -# This is a bug in the provider, which should be reported in the provider's own issue -# tracker. - -# For an attribute with default value, if not provided in the config then default will be considered while creating the app -# The default values of the attributes are shared next to the attributes - - -# The config below has the list of common config and main config -resource "cidaas_app" "sample" { - client_name = "Test Terraform Application" // unique - client_display_name = "Display Name of the app" // unique - content_align = "CENTER" // Default: CENTER - post_logout_redirect_uris = ["https://cidaas.com"] - logo_align = "CENTER" // Default: CENTER - allow_disposable_email = false // Default: false - validate_phone_number = false // Default: false - additional_access_token_payload = ["sample_payload"] - required_fields = ["email"] - mobile_settings = { - team_id = "sample-team-id" - bundle_id = "sample-bundle-id" - package_name = "sample-package-name" - key_hash = "sample-key-hash" - } - // for custom client credentials use client_id and client_secret, you can leave blank if you want cidaas to create a set for you - # client_id = "" - # client_secret = "" - policy_uri = "https://cidaas.com" - tos_uri = "https://cidaas.com" - imprint_uri = "https://cidaas.com" - contacts = ["support@cidas.de"] - token_endpoint_auth_method = "client_secret_post" // Default: client_secret_post - token_endpoint_auth_signing_alg = "RS256" // Default: RS256 - default_acr_values = ["default"] - web_message_uris = ["https://cidaas.com"] - allowed_fields = ["email"] - smart_mfa = false // Default: false - captcha_ref = "sample-captcha-ref" - captcha_refs = ["sample"] - consent_refs = ["sample"] - communication_medium_verification = "email_verification_required_on_usage" - mobile_number_verification_required = false // Default: false - enable_bot_detection = false // Default: false - allow_guest_login_groups = [{ - group_id = "developer101" - roles = ["developer", "qa", "admin"] - default_roles = ["developer"] - }] - is_login_success_page_enabled = false // Default: false - is_register_success_page_enabled = false // Default: false - group_ids = ["sample"] - is_group_login_selection_enabled = false // Default: false - group_selection = { - selectable_groups = ["developer-users"] - selectable_group_types = ["sample"] - } - group_types = ["sample"] - // api throws validation failed invalid backchanel logout url for an invalid url - # backchannel_logout_uri = "https://cidaas.com" - logo_uri = "https://cidaas.com" - initiate_login_uri = "https://cidaas.com" - registration_client_uri = "https://cidaas.com" - registration_access_token = "registration access token" - client_uri = "https://cidaas.com" - jwks_uri = "https://cidaas.com" - jwks = "https://cidaas.com/jwks" - sector_identifier_uri = "https://cidaas.com" - subject_type = "sample subject type" - id_token_signed_response_alg = "RS256" - id_token_encrypted_response_alg = "RS256" - id_token_encrypted_response_enc = "example" - userinfo_signed_response_alg = "RS256" - userinfo_encrypted_response_alg = "RS256" - userinfo_encrypted_response_enc = "example" - request_object_signing_alg = "RS256" - request_object_encryption_alg = "RS256" - request_object_encryption_enc = "userinfo_encrypted_response_enc" - request_uris = ["sample"] - description = "app description" - consent_page_group = "sample-consent-page-group" - password_policy_ref = "password-policy-ref" - blocking_mechanism_ref = "blocking-mechanism-ref" - sub = "sample-sub" - role = "sample-role" - mfa_configuration = "sample-configuration" - suggest_mfa = ["OFF"] - login_spi = { - oauth_client_id = "bcb-4a6b-9777-8a64abe6af" - spi_url = "https://cidaas.com/spi-url" - } - background_uri = "https://cidaas.com" - video_url = "https://cidaas.com" - bot_captcha_ref = "sample-bot-captcha-ref" - application_meta_data = { - status : "active" - version : "1.0.0" - } - // common config starts here. The attributes from common config can be part of main config - // if an attribute is available both common_config and main config then attribute from the main config will be considered to create an app - common_configs = var.common_config -} diff --git a/examples/resources/cidaas_app/sample3/main.tf b/examples/resources/cidaas_app/sample3/main.tf deleted file mode 100644 index b6e174d..0000000 --- a/examples/resources/cidaas_app/sample3/main.tf +++ /dev/null @@ -1,12 +0,0 @@ -module "shared_settings" { - source = "./modules" - common_config = { - client_type = "SINGLE_PAGE" - company_name = "Widas ID GmbH" - company_address = "01" - company_website = "https://cidaas.com" - allowed_scopes = ["openid", "cidaas:register", "profile"] - redirect_uris = ["https://cidaas.com"] - allowed_logout_urls = ["https://cidaas.com"] - } -} diff --git a/examples/resources/cidaas_app/sample3/modules/app.tf b/examples/resources/cidaas_app/sample3/modules/app.tf deleted file mode 100644 index d2ce1ed..0000000 --- a/examples/resources/cidaas_app/sample3/modules/app.tf +++ /dev/null @@ -1,54 +0,0 @@ - -# A sample with only the required fields to create an app -# The setup below will create multiple resources with the common config -# The default values will be set when the app is created - -variable "common_config" { - type = object({ - client_type = string - company_name = string - company_address = string - company_website = string - allowed_scopes = set(string) - redirect_uris = set(string) - allowed_logout_urls = set(string) - }) -} - -terraform { - required_providers { - cidaas = { - source = "hashicorp.com/Cidaas/cidaas" - version = "3.0.0" - } - } -} - -provider "cidaas" { - base_url = "https://cidaas.de" -} - -resource "cidaas_app" "sample_one" { - client_name = "Sample Terraform Application One" - common_configs = var.common_config -} - -resource "cidaas_app" "sample_two" { - client_name = "Sample Terraform Application Two" - common_configs = var.common_config -} - -# additional attribute client_display_name added -resource "cidaas_app" "sample_three" { - client_name = "Sample Terraform Application Three" - client_display_name = "Sample terraform display name" - common_configs = var.common_config -} - -# Here client_type will be overridden from SINGLE_PAGE(common_config.client_type) to IOS -resource "cidaas_app" "sample_four" { - client_name = "Sample Terraform Application Four" - client_type = "IOS" - common_configs = var.common_config -} - diff --git a/templates/resources/app.md.tmpl b/templates/resources/app.md.tmpl index 15e3f4a..4156664 100644 --- a/templates/resources/app.md.tmpl +++ b/templates/resources/app.md.tmpl @@ -162,7 +162,7 @@ module "app2" { ``` You can explore more on the module in the github repo. -## Example Usage(V3 configuration) +## Example Usage {{ tffile "examples/resources/cidaas_app/resource.tf" }}