diff --git a/docs/resources/stage_redirect.md b/docs/resources/stage_redirect.md new file mode 100644 index 00000000..37bfdbc0 --- /dev/null +++ b/docs/resources/stage_redirect.md @@ -0,0 +1,55 @@ +--- +page_title: "authentik_stage_redirect Resource - terraform-provider-authentik" +subcategory: "Flows & Stages" +description: |- + +--- + +# authentik_stage_redirect (Resource) + + + +## Example Usage + +```terraform +# Create a static redirect stage + +resource "authentik_stage_redirect" "static" { + name = "static-redirect" + mode = "static" + target_static = "https://goauthentik.io" +} + +# Create a flow redirect stage + +data "authentik_flow" "default-authorization-flow" { + slug = "default-provider-authorization-implicit-consent" +} + +resource "authentik_stage_redirect" "flow" { + name = "flow-redirect" + mode = "flow" + target_flow = data.authentik_flow.default-authorization-flow.id +} +``` + + +## Schema + +### Required + +- `name` (String) + +### Optional + +- `keep_context` (Boolean) Defaults to `true`. +- `mode` (String) Allowed values: + - `static` + - `flow` + Defaults to `flow`. +- `target_flow` (String) +- `target_static` (String) + +### Read-Only + +- `id` (String) The ID of this resource. diff --git a/examples/resources/authentik_stage_redirect/resource.tf b/examples/resources/authentik_stage_redirect/resource.tf new file mode 100644 index 00000000..441e72c6 --- /dev/null +++ b/examples/resources/authentik_stage_redirect/resource.tf @@ -0,0 +1,19 @@ +# Create a static redirect stage + +resource "authentik_stage_redirect" "static" { + name = "static-redirect" + mode = "static" + target_static = "https://goauthentik.io" +} + +# Create a flow redirect stage + +data "authentik_flow" "default-authorization-flow" { + slug = "default-provider-authorization-implicit-consent" +} + +resource "authentik_stage_redirect" "flow" { + name = "flow-redirect" + mode = "flow" + target_flow = data.authentik_flow.default-authorization-flow.id +} diff --git a/internal/provider/provider.go b/internal/provider/provider.go index d8d9f7c4..99cefa86 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -156,6 +156,7 @@ func Provider(version string, testing bool) *schema.Provider { "authentik_stage_password": tr(resourceStagePassword), "authentik_stage_prompt_field": tr(resourceStagePromptField), "authentik_stage_prompt": tr(resourceStagePrompt), + "authentik_stage_redirect": tr(resourceStageRedirect), "authentik_stage_source": tr(resourceStageSource), "authentik_stage_user_delete": tr(resourceStageUserDelete), "authentik_stage_user_login": tr(resourceStageUserLogin), diff --git a/internal/provider/resource_stage_redirect.go b/internal/provider/resource_stage_redirect.go new file mode 100644 index 00000000..f4f9ce2b --- /dev/null +++ b/internal/provider/resource_stage_redirect.go @@ -0,0 +1,118 @@ +package provider + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + api "goauthentik.io/api/v3" +) + +func resourceStageRedirect() *schema.Resource { + return &schema.Resource{ + Description: "Flows & Stages --- ", + CreateContext: resourceStageRedirectCreate, + ReadContext: resourceStageRedirectRead, + UpdateContext: resourceStageRedirectUpdate, + DeleteContext: resourceStageRedirectDelete, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "mode": { + Type: schema.TypeString, + Optional: true, + Default: api.REDIRECTSTAGEMODEENUM_FLOW, + Description: EnumToDescription(api.AllowedRedirectStageModeEnumEnumValues), + ValidateDiagFunc: StringInEnum(api.AllowedRedirectStageModeEnumEnumValues), + }, + "keep_context": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "target_static": { + Type: schema.TypeString, + Optional: true, + }, + "target_flow": { + Type: schema.TypeString, + Optional: true, + }, + }, + } +} + +func resourceStageRedirectSchemaToProvider(d *schema.ResourceData) *api.RedirectStageRequest { + r := api.RedirectStageRequest{ + Name: d.Get("name").(string), + Mode: api.RedirectStageModeEnum(d.Get("mode").(string)), + KeepContext: api.PtrBool(d.Get("keep_context").(bool)), + } + + if target, targetSet := d.GetOk("target_static"); targetSet { + r.TargetStatic = api.PtrString(target.(string)) + } + if target, targetSet := d.GetOk("target_flow"); targetSet { + r.TargetFlow.Set(api.PtrString(target.(string))) + } + return &r +} + +func resourceStageRedirectCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + c := m.(*APIClient) + + r := resourceStageRedirectSchemaToProvider(d) + + res, hr, err := c.client.StagesApi.StagesRedirectCreate(ctx).RedirectStageRequest(*r).Execute() + if err != nil { + return httpToDiag(d, hr, err) + } + + d.SetId(res.Pk) + return resourceStageRedirectRead(ctx, d, m) +} + +func resourceStageRedirectRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + var diags diag.Diagnostics + c := m.(*APIClient) + + res, hr, err := c.client.StagesApi.StagesRedirectRetrieve(ctx, d.Id()).Execute() + if err != nil { + return httpToDiag(d, hr, err) + } + + setWrapper(d, "name", res.Name) + setWrapper(d, "mode", res.Mode) + setWrapper(d, "keep_context", res.KeepContext) + setWrapper(d, "target_flow", res.TargetFlow.Get()) + setWrapper(d, "target_static", res.TargetStatic) + return diags +} + +func resourceStageRedirectUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + c := m.(*APIClient) + + app := resourceStageRedirectSchemaToProvider(d) + + res, hr, err := c.client.StagesApi.StagesRedirectUpdate(ctx, d.Id()).RedirectStageRequest(*app).Execute() + if err != nil { + return httpToDiag(d, hr, err) + } + + d.SetId(res.Pk) + return resourceStageRedirectRead(ctx, d, m) +} + +func resourceStageRedirectDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + c := m.(*APIClient) + hr, err := c.client.StagesApi.StagesRedirectDestroy(ctx, d.Id()).Execute() + if err != nil { + return httpToDiag(d, hr, err) + } + return diag.Diagnostics{} +} diff --git a/internal/provider/resource_stage_redirect_test.go b/internal/provider/resource_stage_redirect_test.go new file mode 100644 index 00000000..f503425f --- /dev/null +++ b/internal/provider/resource_stage_redirect_test.go @@ -0,0 +1,41 @@ +package provider + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccResourceStageRedirect(t *testing.T) { + rName := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + resource.UnitTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: testAccResourceStageRedirect(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("authentik_stage_redirect.name", "name", rName), + ), + }, + { + Config: testAccResourceStageRedirect(rName + "test"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("authentik_stage_redirect.name", "name", rName+"test"), + ), + }, + }, + }) +} + +func testAccResourceStageRedirect(name string) string { + return fmt.Sprintf(` +resource "authentik_stage_redirect" "name" { + name = "%[1]s" + mode = "static" + target_static = "https://goauthentik.io" +} +`, name) +}