Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "auth0_clients" data source for listing multiple clients with filtering #1080

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
47 changes: 47 additions & 0 deletions docs/data-sources/clients.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
page_title: "Data Source: auth0_clients"
description: |-
Data source to retrieve a list of Auth0 application clients with optional filtering.
---

# Data Source: auth0_clients

Data source to retrieve a list of Auth0 application clients with optional filtering.



<!-- schema generated by tfplugindocs -->
## Schema

### Optional

- `app_types` (Set of String) Filter clients by application types.
- `is_first_party` (Boolean) Filter clients by first party status.
- `name_filter` (String) Filter clients by name (partial matches supported).

### Read-Only

- `clients` (List of Object) List of clients matching the filter criteria. (see [below for nested schema](#nestedatt--clients))
- `id` (String) The ID of this resource.

<a id="nestedatt--clients"></a>
### Nested Schema for `clients`

Read-Only:

- `allowed_clients` (List of String)
- `allowed_logout_urls` (List of String)
- `allowed_origins` (List of String)
- `app_type` (String)
- `callbacks` (List of String)
- `client_id` (String)
- `client_metadata` (Map of String)
- `client_secret` (String)
- `description` (String)
- `grant_types` (List of String)
- `is_first_party` (Boolean)
- `is_token_endpoint_ip_header_trusted` (Boolean)
- `name` (String)
- `web_origins` (List of String)


39 changes: 34 additions & 5 deletions internal/acctest/http_recorder.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,27 +108,56 @@ func redactDomain(i *cassette.Interaction, domain string) {
}

func redactSensitiveDataInClient(t *testing.T, i *cassette.Interaction, domain string) {
create := i.Request.URL == "https://"+domain+"/api/v2/clients" &&
baseURL := "https://" + domain + "/api/v2/clients"
urlPath := strings.Split(i.Request.URL, "?")[0] // Strip query params

create := i.Request.URL == baseURL &&
i.Request.Method == http.MethodPost

read := strings.Contains(i.Request.URL, "https://"+domain+"/api/v2/clients/") &&
readList := urlPath == baseURL &&
i.Request.Method == http.MethodGet

readOne := strings.Contains(i.Request.URL, baseURL+"/") &&
!strings.Contains(i.Request.URL, "credentials") &&
i.Request.Method == http.MethodGet

update := strings.Contains(i.Request.URL, "https://"+domain+"/api/v2/clients/") &&
update := strings.Contains(i.Request.URL, baseURL+"/") &&
!strings.Contains(i.Request.URL, "credentials") &&
i.Request.Method == http.MethodPatch

if create || read || update {
if create || readList || readOne || update {
if i.Response.Code == http.StatusNotFound {
return
}

redacted := "[REDACTED]"

// Handle list response
if readList {
var response management.ClientList
err := json.Unmarshal([]byte(i.Response.Body), &response)
require.NoError(t, err)

for _, client := range response.Clients {
client.SigningKeys = []map[string]string{
{"cert": redacted},
}
if client.GetClientSecret() != "" {
client.ClientSecret = &redacted
}
}

responseBody, err := json.Marshal(response)
require.NoError(t, err)
i.Response.Body = string(responseBody)
return
}

// Handle single client response
var client management.Client
err := json.Unmarshal([]byte(i.Response.Body), &client)
require.NoError(t, err)

redacted := "[REDACTED]"
client.SigningKeys = []map[string]string{
{"cert": redacted},
}
Expand Down
18 changes: 10 additions & 8 deletions internal/auth0/client/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
internalValidation "github.com/auth0/terraform-provider-auth0/internal/validation"
)

var ValidAppTypes = []string{

Check warning on line 18 in internal/auth0/client/resource.go

View workflow job for this annotation

GitHub Actions / Checks

exported: exported var ValidAppTypes should have comment or be unexported (revive)
"native", "spa", "regular_web", "non_interactive", "rms",
"box", "cloudbees", "concur", "dropbox", "mscrm", "echosign",
"egnyte", "newrelic", "office365", "salesforce", "sentry",
"sharepoint", "slack", "springcm", "sso_integration", "zendesk", "zoom",
}

// NewResource will return a new auth0_client resource.
func NewResource() *schema.Resource {
return &schema.Resource{
Expand Down Expand Up @@ -53,14 +60,9 @@
Description: "List of audiences/realms for SAML protocol. Used by the wsfed addon.",
},
"app_type": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{
"native", "spa", "regular_web", "non_interactive", "rms",
"box", "cloudbees", "concur", "dropbox", "mscrm", "echosign",
"egnyte", "newrelic", "office365", "salesforce", "sentry",
"sharepoint", "slack", "springcm", "sso_integration", "zendesk", "zoom",
}, false),
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice(ValidAppTypes, false),
Description: "Type of application the client represents. Possible values are: `native`, `spa`, " +
"`regular_web`, `non_interactive`, `sso_integration`. Specific SSO integrations types accepted " +
"as well are: `rms`, `box`, `cloudbees`, `concur`, `dropbox`, `mscrm`, `echosign`, `egnyte`, " +
Expand Down
161 changes: 161 additions & 0 deletions internal/auth0/clients/data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package clients

import (
"context"
"crypto/sha256"
"fmt"
"strings"

"github.com/auth0/go-auth0/management"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"

"github.com/auth0/terraform-provider-auth0/internal/auth0/client"
"github.com/auth0/terraform-provider-auth0/internal/config"
)

// NewDataSource will return a new auth0_clients data source.
func NewDataSource() *schema.Resource {
return &schema.Resource{
ReadContext: readClientsForDataSource,
Description: "Data source to retrieve a list of Auth0 application clients with optional filtering.",
Schema: map[string]*schema.Schema{
"name_filter": {
Type: schema.TypeString,
Optional: true,
Description: "Filter clients by name (partial matches supported).",
},
"app_types": {
Type: schema.TypeSet,
Optional: true,
Description: "Filter clients by application types.",
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice(client.ValidAppTypes, false),
},
},
"is_first_party": {
Type: schema.TypeBool,
Optional: true,
Description: "Filter clients by first party status.",
},
"clients": {
Type: schema.TypeList,
Computed: true,
Description: "List of clients matching the filter criteria.",
Elem: &schema.Resource{
Schema: CoreClientDataSourceSchema(),
},
},
},
}
}

func CoreClientDataSourceSchema() map[string]*schema.Schema {

Check warning on line 55 in internal/auth0/clients/data_source.go

View workflow job for this annotation

GitHub Actions / Checks

exported: exported function CoreClientDataSourceSchema should have comment or be unexported (revive)
devin-brenton marked this conversation as resolved.
Show resolved Hide resolved
clientSchema := client.NewDataSource().Schema

// Remove unused fields from the client schema

Check failure on line 58 in internal/auth0/clients/data_source.go

View workflow job for this annotation

GitHub Actions / Checks

Comment should end in a period (godot)
fieldsToRemove := []string{
"client_aliases",
"logo_uri",
"oidc_conformant",
"oidc_backchannel_logout_urls",
"organization_usage",
"organization_require_behavior",
"cross_origin_auth",
"cross_origin_loc",
"custom_login_page_on",
"custom_login_page",
"form_template",
"require_pushed_authorization_requests",
"mobile",
"initiate_login_uri",
"native_social_login",
"refresh_token",
"signing_keys",
"encryption_key",
"sso",
"sso_disabled",
"jwt_configuration",
"addons",
"default_organization",
"compliance_level",
"require_proof_of_possession",
"token_endpoint_auth_method",
"signed_request_object",
"client_authentication_methods",
}

for _, field := range fieldsToRemove {
delete(clientSchema, field)
}

return clientSchema
}

func readClientsForDataSource(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
api := meta.(*config.Config).GetAPI()

nameFilter := data.Get("name_filter").(string)
appTypesSet := data.Get("app_types").(*schema.Set)
isFirstParty := data.Get("is_first_party").(bool)

appTypes := make([]string, 0, appTypesSet.Len())
for _, v := range appTypesSet.List() {
appTypes = append(appTypes, v.(string))
}

var clients []*management.Client

params := []management.RequestOption{
management.PerPage(100),
}

if len(appTypes) > 0 {
params = append(params, management.Parameter("app_type", strings.Join(appTypes, ",")))
}
if isFirstParty {
params = append(params, management.Parameter("is_first_party", "true"))
}

var page int
for {
// Add current page parameter

Check failure on line 124 in internal/auth0/clients/data_source.go

View workflow job for this annotation

GitHub Actions / Checks

Comment should end in a period (godot)
params = append(params, management.Page(page))

list, err := api.Client.List(ctx, params...)
if err != nil {
return diag.FromErr(err)
}

for _, client := range list.Clients {
if nameFilter == "" || strings.Contains(client.GetName(), nameFilter) {
clients = append(clients, client)
}
}

if !list.HasNext() {
break
}

// Remove the page parameter and increment for next iteration

Check failure on line 142 in internal/auth0/clients/data_source.go

View workflow job for this annotation

GitHub Actions / Checks

Comment should end in a period (godot)
params = params[:len(params)-1]
page++
}

filterID := generateFilterID(nameFilter, appTypes, isFirstParty)
data.SetId(filterID)

if err := flattenClientList(data, clients); err != nil {
return diag.FromErr(err)
}

return nil
}

func generateFilterID(nameFilter string, appTypes []string, isFirstParty bool) string {
h := sha256.New()
h.Write([]byte(fmt.Sprintf("%s-%v-%v", nameFilter, appTypes, isFirstParty)))
return fmt.Sprintf("clients-%x", h.Sum(nil))
}
Loading
Loading