diff --git a/docs/data-sources/action_configuration.md b/docs/data-sources/action_configuration.md index 667cd7d..e0ebc1c 100644 --- a/docs/data-sources/action_configuration.md +++ b/docs/data-sources/action_configuration.md @@ -30,4 +30,5 @@ data "authsignal_action_configuration" "test" { - `default_user_action_result` (String) The default action behavior if no rules match. (i.e 'CHALLENGE') - `last_action_created_at` (String) The date of when an action was last tracked for any user. +- `messaging_templates` (String) Optional messaging templates to be shown in Authsignal's pre-built UI. - `tenant_id` (String) The ID of your tenant. This can be found in the admin portal. diff --git a/docs/index.md b/docs/index.md index c2cb3ba..48eccc0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -15,11 +15,13 @@ description: |- ```terraform # Configuration-based authentication provider "authsignal" { - // For production systems please configure these as environment variables in your CI/CD process. - host = "https://authsignal.com/not-a-real-endpoint" - tenant_id = "123" - api_secret = "helloworld" + # For production systems please configure these as environment variables in your CI/CD process. + host = "https://api.authsignal.com/v1/management" # AUTHSIGNAL_HOST + tenant_id = "123" # AUTHSIGNAL_TENANT_ID + api_secret = "helloworld" # AUTHSIGNAL_API_SECRET } + +# These values can be found under the `Settings -> API keys` section of Authsignal's admin portal. ``` diff --git a/docs/resources/action_configuration.md b/docs/resources/action_configuration.md index 3fea94b..f4e1ebf 100644 --- a/docs/resources/action_configuration.md +++ b/docs/resources/action_configuration.md @@ -28,6 +28,10 @@ resource "authsignal_action_configuration" "terraform-provider-test" { - `action_code` (String) The name of the action that users perform which you will track. (e.g 'login') - `default_user_action_result` (String) The default action behavior if no rules match. (i.e 'CHALLENGE') +### Optional + +- `messaging_templates` (String) Optional messaging templates to be shown in Authsignal's pre-built UI. + ### Read-Only - `last_action_created_at` (String) The date of when an action was last tracked for any user. diff --git a/examples/provider/provider.tf b/examples/provider/provider.tf index f0b786c..7ed56c6 100644 --- a/examples/provider/provider.tf +++ b/examples/provider/provider.tf @@ -1,7 +1,9 @@ # Configuration-based authentication provider "authsignal" { - // For production systems please configure these as environment variables in your CI/CD process. - host = "https://authsignal.com/not-a-real-endpoint" - tenant_id = "123" - api_secret = "helloworld" + # For production systems please configure these as environment variables in your CI/CD process. + host = "https://api.authsignal.com/v1/management" # AUTHSIGNAL_HOST + tenant_id = "123" # AUTHSIGNAL_TENANT_ID + api_secret = "helloworld" # AUTHSIGNAL_API_SECRET } + +# These values can be found under the `Settings -> API keys` section of Authsignal's admin portal. diff --git a/go.mod b/go.mod index e3cae96..90a66c0 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/authsignal/terraform-provider-authsignal go 1.22.0 require ( - github.com/authsignal/authsignal-management-go/v2 v2.0.1 + github.com/authsignal/authsignal-management-go/v2 v2.1.0 github.com/hashicorp/terraform-plugin-docs v0.18.0 github.com/hashicorp/terraform-plugin-framework v1.7.0 github.com/hashicorp/terraform-plugin-framework-validators v0.12.0 diff --git a/go.sum b/go.sum index 035d987..869fb49 100644 --- a/go.sum +++ b/go.sum @@ -19,8 +19,8 @@ github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/authsignal/authsignal-management-go/v2 v2.0.1 h1:KQL4UNCaPNQUPf3zKQOiyJazBFInop5NNhgr7shKazs= -github.com/authsignal/authsignal-management-go/v2 v2.0.1/go.mod h1:vRrL3bs794IPmy6BMbbmYCyf/QydU8Bg5cgZpCc4G9Q= +github.com/authsignal/authsignal-management-go/v2 v2.1.0 h1:dg2RaLru412uE2O+18WPGq5io44BC7pgkYCi2qC4+pE= +github.com/authsignal/authsignal-management-go/v2 v2.1.0/go.mod h1:vRrL3bs794IPmy6BMbbmYCyf/QydU8Bg5cgZpCc4G9Q= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= diff --git a/internal/provider/action_configuration_data_source.go b/internal/provider/action_configuration_data_source.go index 96c2e5b..01e4e02 100644 --- a/internal/provider/action_configuration_data_source.go +++ b/internal/provider/action_configuration_data_source.go @@ -2,6 +2,7 @@ package provider import ( "context" + "encoding/json" "fmt" "github.com/authsignal/authsignal-management-go/v2" @@ -29,6 +30,7 @@ type actionConfigurationDataSourceModel struct { TenantId types.String `tfsdk:"tenant_id"` DefaultUserActionResult types.String `tfsdk:"default_user_action_result"` LastActionCreatedAt types.String `tfsdk:"last_action_created_at"` + MessagingTemplates types.String `tfsdk:"messaging_templates"` } func (d *actionConfigurationDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { @@ -54,6 +56,10 @@ func (d *actionConfigurationDataSource) Schema(_ context.Context, _ datasource.S Description: "The ID of your tenant. This can be found in the admin portal.", Computed: true, }, + "messaging_templates": schema.StringAttribute{ + Description: "Optional messaging templates to be shown in Authsignal's pre-built UI.", + Computed: true, + }, }, } } @@ -77,6 +83,15 @@ func (d *actionConfigurationDataSource) Read(ctx context.Context, req datasource return } + messagingTemplatesJson, err := json.Marshal(actionConfiguration.MessagingTemplates) + if err != nil { + resp.Diagnostics.AddError( + "Unable to marshal messaging templates", + err.Error(), + ) + return + } + actionConfigurationState := actionConfigurationDataSourceModel{ ActionCode: types.StringValue(actionConfiguration.ActionCode), TenantId: types.StringValue(actionConfiguration.TenantId), @@ -84,6 +99,10 @@ func (d *actionConfigurationDataSource) Read(ctx context.Context, req datasource LastActionCreatedAt: types.StringValue(actionConfiguration.LastActionCreatedAt), } + if actionConfiguration.MessagingTemplates != nil { + actionConfigurationState.MessagingTemplates = types.StringValue(string(messagingTemplatesJson)) + } + diags2 := resp.State.Set(ctx, &actionConfigurationState) resp.Diagnostics.Append(diags2...) diff --git a/internal/provider/action_configuration_resource.go b/internal/provider/action_configuration_resource.go index b26d5b0..824cb6f 100644 --- a/internal/provider/action_configuration_resource.go +++ b/internal/provider/action_configuration_resource.go @@ -2,6 +2,7 @@ package provider import ( "context" + "encoding/json" "fmt" "github.com/authsignal/authsignal-management-go/v2" @@ -35,6 +36,7 @@ type actionConfigurationResourceModel struct { LastActionCreatedAt types.String `tfsdk:"last_action_created_at"` TenantId types.String `tfsdk:"tenant_id"` DefaultUserActionResult types.String `tfsdk:"default_user_action_result"` + MessagingTemplates types.String `tfsdk:"messaging_templates"` } func (r *actionConfigurationResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { @@ -69,6 +71,10 @@ func (r *actionConfigurationResource) Schema(_ context.Context, _ resource.Schem stringplanmodifier.UseStateForUnknown(), }, }, + "messaging_templates": schema.StringAttribute{ + Description: "Optional messaging templates to be shown in Authsignal's pre-built UI.", + Optional: true, + }, }, } } @@ -81,6 +87,19 @@ func (r *actionConfigurationResource) Create(ctx context.Context, req resource.C return } + var messagingTemplatesJson authsignal.MessagingTemplates + + if len(string(plan.MessagingTemplates.ValueString())) > 0 { + err := json.Unmarshal([]byte(plan.MessagingTemplates.ValueString()), &messagingTemplatesJson) + if err != nil { + resp.Diagnostics.AddError( + "Unable to unmarshal messaging templates", + err.Error(), + ) + return + } + } + var actionConfigurationToCreate = authsignal.ActionConfiguration{} var actionConfigurationActionCode = plan.ActionCode.ValueString() @@ -93,6 +112,10 @@ func (r *actionConfigurationResource) Create(ctx context.Context, req resource.C actionConfigurationToCreate.DefaultUserActionResult = authsignal.SetValue(actionConfigurationDefaultUserActionResult) } + if len(string(plan.MessagingTemplates.ValueString())) > 0 { + actionConfigurationToCreate.MessagingTemplates = authsignal.SetValue(messagingTemplatesJson) + } + actionConfiguration, err := r.client.CreateActionConfiguration(actionConfigurationToCreate) if err != nil { resp.Diagnostics.AddError( @@ -132,10 +155,25 @@ func (r *actionConfigurationResource) Read(ctx context.Context, req resource.Rea return } + messagingTemplatesJson, err := json.Marshal(actionConfiguration.MessagingTemplates) + if err != nil { + resp.Diagnostics.AddError( + "Unable to marshal messaging templates", + err.Error(), + ) + return + } + state.DefaultUserActionResult = types.StringValue(actionConfiguration.DefaultUserActionResult) state.LastActionCreatedAt = types.StringValue(actionConfiguration.LastActionCreatedAt) state.TenantId = types.StringValue(actionConfiguration.TenantId) + if actionConfiguration.MessagingTemplates != nil { + state.MessagingTemplates = types.StringValue(string(messagingTemplatesJson)) + } else { + state.MessagingTemplates = types.StringNull() + } + diags = resp.State.Set(ctx, &state) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -151,14 +189,9 @@ func (r *actionConfigurationResource) Update(ctx context.Context, req resource.U return } - var actionConfigurationToUpdate = authsignal.ActionConfiguration{} + var messagingTemplatesJson authsignal.MessagingTemplates - var actionConfigurationActionCode = plan.ActionCode.ValueString() - if len(actionConfigurationActionCode) > 0 { - actionConfigurationToUpdate.ActionCode = authsignal.SetValue(actionConfigurationActionCode) - } else { - actionConfigurationToUpdate.ActionCode = authsignal.SetNull(actionConfigurationActionCode) - } + var actionConfigurationToUpdate = authsignal.ActionConfiguration{} var actionConfigurationDefaultUserActionResult = plan.DefaultUserActionResult.ValueString() if len(actionConfigurationDefaultUserActionResult) > 0 { @@ -167,11 +200,26 @@ func (r *actionConfigurationResource) Update(ctx context.Context, req resource.U actionConfigurationToUpdate.DefaultUserActionResult = authsignal.SetNull(actionConfigurationDefaultUserActionResult) } - _, err := r.client.UpdateActionConfiguration(plan.ActionCode.ValueString(), actionConfigurationToUpdate) - if err != nil { + if len(string(plan.MessagingTemplates.ValueString())) > 0 { + err := json.Unmarshal([]byte(plan.MessagingTemplates.ValueString()), &messagingTemplatesJson) + if err != nil { + resp.Diagnostics.AddError( + "Unable to unmarshal messaging templates", + err.Error(), + ) + return + } + + actionConfigurationToUpdate.MessagingTemplates = authsignal.SetValue(messagingTemplatesJson) + } else { + actionConfigurationToUpdate.MessagingTemplates = authsignal.SetNull(messagingTemplatesJson) + } + + _, err2 := r.client.UpdateActionConfiguration(plan.ActionCode.ValueString(), actionConfigurationToUpdate) + if err2 != nil { resp.Diagnostics.AddError( "Error Updating Authsignal action configuration", - "Could not update action configuration, unexpected error: "+err.Error(), + "Could not update action configuration, unexpected error: "+err2.Error(), ) return } diff --git a/internal/provider/action_configuration_resource_test.go b/internal/provider/action_configuration_resource_test.go index 4dc1728..ffa19e3 100644 --- a/internal/provider/action_configuration_resource_test.go +++ b/internal/provider/action_configuration_resource_test.go @@ -24,6 +24,25 @@ func TestAccActionConfigurationResource(t *testing.T) { resource.TestCheckResourceAttr("authsignal_action_configuration.test", "tenant_id", "ec3910e7-ab32-479e-b58b-36a122631d58"), ), }, + { + Config: ` + resource "authsignal_action_configuration" "test-templates" { + action_code = "terraform-acceptance-test-templates" + default_user_action_result = "ALLOW" + messaging_templates = jsonencode({ + "en": { + "defaultTemplate": "hello world" + } + }) + } + `, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("authsignal_action_configuration.test-templates", "action_code", "terraform-acceptance-test-templates"), + resource.TestCheckResourceAttr("authsignal_action_configuration.test-templates", "default_user_action_result", "ALLOW"), + resource.TestCheckResourceAttr("authsignal_action_configuration.test-templates", "tenant_id", "ec3910e7-ab32-479e-b58b-36a122631d58"), + resource.TestCheckResourceAttr("authsignal_action_configuration.test-templates", "messaging_templates", "{\"en\":{\"defaultTemplate\":\"hello world\"}}"), + ), + }, // Update and Read testing { Config: ` @@ -38,6 +57,25 @@ func TestAccActionConfigurationResource(t *testing.T) { resource.TestCheckResourceAttr("authsignal_action_configuration.test", "tenant_id", "ec3910e7-ab32-479e-b58b-36a122631d58"), ), }, + { + Config: ` + resource "authsignal_action_configuration" "test-templates" { + action_code = "terraform-acceptance-test-templates" + default_user_action_result = "ALLOW" + messaging_templates = jsonencode({ + "fr": { + "defaultTemplate": "bonjour" + } + }) + } + `, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("authsignal_action_configuration.test-templates", "action_code", "terraform-acceptance-test-templates"), + resource.TestCheckResourceAttr("authsignal_action_configuration.test-templates", "default_user_action_result", "ALLOW"), + resource.TestCheckResourceAttr("authsignal_action_configuration.test-templates", "tenant_id", "ec3910e7-ab32-479e-b58b-36a122631d58"), + resource.TestCheckResourceAttr("authsignal_action_configuration.test-templates", "messaging_templates", "{\"fr\":{\"defaultTemplate\":\"bonjour\"}}"), + ), + }, // Delete testing automatically occurs in TestCase }, }) diff --git a/internal/provider/rule_resource.go b/internal/provider/rule_resource.go index 1340b19..b39aefc 100644 --- a/internal/provider/rule_resource.go +++ b/internal/provider/rule_resource.go @@ -161,7 +161,7 @@ func (r *ruleResource) Create(ctx context.Context, req resource.CreateRequest, r err := json.Unmarshal([]byte(plan.Conditions.ValueString()), &conditionsJson) if err != nil { resp.Diagnostics.AddError( - "Unable to marshall conditions", + "Unable to marshal conditions", err.Error(), ) return @@ -252,7 +252,7 @@ func (r *ruleResource) Read(ctx context.Context, req resource.ReadRequest, resp conditionsJson, err := json.Marshal(rule.Conditions) if err != nil { resp.Diagnostics.AddError( - "Unable to marshall conditions", + "Unable to marshal conditions", err.Error(), ) return @@ -264,15 +264,25 @@ func (r *ruleResource) Read(ctx context.Context, req resource.ReadRequest, resp state.Type = types.StringValue(rule.Type) state.VerificationMethods = verificationMethodsList state.PromptToEnrollVerificationMethods = promptToEnrollVerificationMethodsList - state.Conditions = types.StringValue(string(conditionsJson)) + state.TenantId = types.StringValue(rule.TenantId) if len(rule.Description) > 0 { state.Description = types.StringValue(rule.Description) + } else { + state.Description = types.StringNull() } if len(rule.DefaultVerificationMethod) > 0 { state.DefaultVerificationMethod = types.StringValue(rule.DefaultVerificationMethod) + } else { + state.DefaultVerificationMethod = types.StringNull() + } + + if rule.Conditions != nil { + state.Conditions = types.StringValue(string(conditionsJson)) + } else { + state.Conditions = types.StringNull() } diags = resp.State.Set(ctx, &state) @@ -309,7 +319,7 @@ func (r *ruleResource) Update(ctx context.Context, req resource.UpdateRequest, r err2 := json.Unmarshal([]byte(plan.Conditions.ValueString()), &conditionsJson) if err2 != nil { resp.Diagnostics.AddError( - "Unable to marshall conditions", + "Unable to marshal conditions", err2.Error(), ) return