Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 51 additions & 28 deletions internal/auth0/client/expand.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package client

import (
"encoding/json"
"fmt"

"github.com/auth0/go-auth0"
"github.com/auth0/go-auth0/management"
Expand All @@ -11,12 +11,7 @@ import (
"github.com/auth0/terraform-provider-auth0/internal/value"
)

type nilableClient struct {
management.Client
DefaultOrganization *management.ClientDefaultOrganization `json:"default_organization"`
}

func expandClient(data *schema.ResourceData) (interface{}, error) {
func expandClient(data *schema.ResourceData) (*management.Client, error) {
config := data.GetRawConfig()

client := &management.Client{
Expand Down Expand Up @@ -53,6 +48,7 @@ func expandClient(data *schema.ResourceData) (interface{}, error) {
Addons: expandClientAddons(data),
NativeSocialLogin: expandClientNativeSocialLogin(data),
Mobile: expandClientMobile(data),
DefaultOrganization: expandDefaultOrganization(data),
}

if data.IsNewResource() && client.IsTokenEndpointIPHeaderTrusted != nil {
Expand All @@ -68,48 +64,75 @@ func expandClient(data *schema.ResourceData) (interface{}, error) {
}
}

defaultOrg := config.GetAttr("default_organization")
defaultConfig := data.GetRawConfig().GetAttr("default_organization")

if !defaultOrg.IsNull() && defaultOrg.LengthInt() > 0 {
if defaultOrg.AsValueSlice()[0].GetAttr("disable").True() {
clientJSON, err := json.Marshal(client)
if err != nil {
return nil, err
}
for _, item := range defaultConfig.AsValueSlice() {
disable := item.GetAttr("disable")
organizationID := item.GetAttr("organization_id")
flows := item.GetAttr("flows")

nilableClient := nilableClient{}
if err := json.Unmarshal(clientJSON, &nilableClient); err != nil {
return nil, err
if !disable.IsNull() && disable.True() {
if (!flows.IsNull() && flows.LengthInt() > 0) || (!organizationID.IsNull() && organizationID.AsString() != "") {
return nil, fmt.Errorf("cannot set both disable and either flows/organization_id")
}
nilableClient.DefaultOrganization = nil
return nilableClient, nil
}
client.DefaultOrganization = expandDefaultOrganization(data)
}

return client, nil
}

func expandDefaultOrganization(data *schema.ResourceData) *management.ClientDefaultOrganization {
var defaultOrg management.ClientDefaultOrganization

defaultOrganizationConfig := data.GetRawConfig().GetAttr("default_organization")
if defaultOrganizationConfig.IsNull() {
if !data.IsNewResource() && !data.HasChange("default_organization") {
return nil
}
var defaultOrg management.ClientDefaultOrganization

defaultOrganizationConfig.ForEachElement(func(_ cty.Value, config cty.Value) (stop bool) {
defaultOrg.Flows = value.Strings(config.GetAttr("flows"))
defaultOrg.OrganizationID = value.String(config.GetAttr("organization_id"))
config := data.GetRawConfig().GetAttr("default_organization")
if config.IsNull() || config.ForEachElement(func(_ cty.Value, cfg cty.Value) (stop bool) {
disable := cfg.GetAttr("disable")
if !disable.IsNull() && disable.True() {
stop = true
} else {
defaultOrg.Flows = value.Strings(cfg.GetAttr("flows"))
defaultOrg.OrganizationID = value.String(cfg.GetAttr("organization_id"))
}
return stop
})
}) {
// We forced an early return because it was disabled.
return nil
}
if defaultOrg == (management.ClientDefaultOrganization{}) {
return nil
}

return &defaultOrg
}

func isDefaultOrgNull(data *schema.ResourceData) bool {
if !data.IsNewResource() && !data.HasChange("default_organization") {
return false
}
empty := true
config := data.GetRawConfig()
defaultOrgConfig := config.GetAttr("default_organization")
if defaultOrgConfig.IsNull() || defaultOrgConfig.ForEachElement(func(_ cty.Value, cfg cty.Value) (stop bool) {
disable := cfg.GetAttr("disable")
flows := cfg.GetAttr("flows")
organizationID := cfg.GetAttr("organization_id")

if (!disable.IsNull() && disable.True()) || (flows.IsNull() && organizationID.IsNull()) {
stop = true
} else {
empty = false
}
return stop
}) {
// We forced an early return because it was disabled.
return true
}
return empty
}

func expandOIDCBackchannelLogout(data *schema.ResourceData) *management.OIDCBackchannelLogout {
raw := data.GetRawConfig().GetAttr("oidc_backchannel_logout_urls")

Expand Down
80 changes: 31 additions & 49 deletions internal/auth0/client/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package client

import (
"context"
"encoding/json"
"net/http"
"time"

"github.com/auth0/go-auth0/management"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
Expand Down Expand Up @@ -1277,30 +1277,28 @@ func NewResource() *schema.Resource {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Description: "Configure and associate an organization with the Client",
Computed: true,
Description: "Configure and associate an organization with the Client",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"flows": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
RequiredWith: []string{"default_organization.0.organization_id"},
ConflictsWith: []string{"default_organization.0.disable"},
Description: "Definition of the flow that needs to be configured. Eg. client_credentials",
Type: schema.TypeList,
Optional: true,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
Description: "Definition of the flow that needs to be configured. Eg. client_credentials",
},
"organization_id": {
Type: schema.TypeString,
Optional: true,
RequiredWith: []string{"default_organization.0.flows"},
ConflictsWith: []string{"default_organization.0.disable"},
Description: "The unique identifier of the organization",
Type: schema.TypeString,
Optional: true,
Computed: true,
Description: "The unique identifier of the organization",
},
"disable": {
Type: schema.TypeBool,
Optional: true,
ConflictsWith: []string{"default_organization.0.organization_id", "default_organization.0.flows"},
Description: "If set, the `default_organization` will be removed.",
Type: schema.TypeBool,
Optional: true,
Computed: true,
Description: "If set, the `default_organization` will be removed.",
},
},
},
Expand All @@ -1313,27 +1311,15 @@ func createClient(ctx context.Context, data *schema.ResourceData, meta interface
api := meta.(*config.Config).GetAPI()
client, err := expandClient(data)

if err != nil {
return diag.FromErr(err)
}
err = api.Request(ctx, http.MethodPost, api.URI("clients"), client)
if err != nil {
return diag.FromErr(err)
}

baseClient := management.Client{}
clientJSON, err := json.Marshal(client)

if err != nil {
return diag.FromErr(err)
}

if err = json.Unmarshal(clientJSON, &baseClient); err != nil {
if err := api.Client.Create(ctx, client); err != nil {
return diag.FromErr(err)
}

data.SetId(baseClient.GetClientID())

data.SetId(client.GetClientID())
return readClient(ctx, data, meta)
}

Expand All @@ -1357,20 +1343,8 @@ func updateClient(ctx context.Context, data *schema.ResourceData, meta interface
return diag.FromErr(err)
}

baseClient := management.Client{}
clientJSON, err := json.Marshal(client)

if err != nil {
return diag.FromErr(err)
}

if err = json.Unmarshal(clientJSON, &baseClient); err != nil {
return diag.FromErr(err)
}

if clientHasChange(&baseClient) {
if baseClient.GetAddons() != nil {
// In case we are switching addons, we need to be able to clear out the previous config.
if clientHasChange(client) {
if client.GetAddons() != nil {
resetAddons := &management.Client{
Addons: &management.ClientAddons{},
}
Expand All @@ -1379,12 +1353,20 @@ func updateClient(ctx context.Context, data *schema.ResourceData, meta interface
}
}

err = api.Request(ctx, http.MethodPatch, api.URI("clients", data.Id()), client)
if err != nil {
return diag.FromErr(err)
if err := api.Client.Update(ctx, data.Id(), client); err != nil {
return diag.FromErr(internalError.HandleAPIError(data, err))
}
}

time.Sleep(200 * time.Millisecond)

if isDefaultOrgNull(data) {
if err := api.Request(ctx, http.MethodPatch, api.URI("clients", data.Id()), map[string]interface{}{
"default_organization": nil,
}); err != nil {
return diag.FromErr(err)
}
}
}
return readClient(ctx, data, meta)
}

Expand Down
16 changes: 8 additions & 8 deletions internal/auth0/client/resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2388,14 +2388,6 @@ resource "auth0_client" "my_client" {
func TestAccClientWithDefaultOrganization(t *testing.T) {
acctest.Test(t, resource.TestCase{
Steps: []resource.TestStep{
{
Config: acctest.ParseTestName(testAccUpdateClientDefaultOrganizationFlowsOnly, t.Name()),
ExpectError: regexp.MustCompile("Error: Missing required argument"),
},
{
Config: acctest.ParseTestName(testAccUpdateClientDefaultOrganizationOrgIDOnly, t.Name()),
ExpectError: regexp.MustCompile("Error: Missing required argument"),
},
{
Config: acctest.ParseTestName(testAccCreateClientWithDefaultOrganization, t.Name()),
Check: resource.ComposeTestCheckFunc(
Expand Down Expand Up @@ -2424,6 +2416,14 @@ func TestAccClientWithDefaultOrganization(t *testing.T) {
resource.TestCheckResourceAttr("auth0_client.my_client", "default_organization.0.organization_id", ""),
),
},
{
Config: acctest.ParseTestName(testAccUpdateClientDefaultOrganizationFlowsOnly, t.Name()),
ExpectError: regexp.MustCompile("400 Bad Request"),
},
{
Config: acctest.ParseTestName(testAccUpdateClientDefaultOrganizationOrgIDOnly, t.Name()),
ExpectError: regexp.MustCompile("400 Bad Request"),
},
},
})
}
Loading