Skip to content

Commit

Permalink
New Resource: azuread_application_known_clients
Browse files Browse the repository at this point in the history
  • Loading branch information
manicminer committed Oct 17, 2023
1 parent b429b08 commit aa54277
Show file tree
Hide file tree
Showing 4 changed files with 501 additions and 0 deletions.
241 changes: 241 additions & 0 deletions internal/services/applications/application_known_clients_resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package applications

import (
"context"
"fmt"
"net/http"
"time"

"github.com/hashicorp/go-azure-helpers/lang/pointer"
"github.com/hashicorp/go-azure-sdk/sdk/odata"
"github.com/hashicorp/terraform-provider-azuread/internal/sdk"
"github.com/hashicorp/terraform-provider-azuread/internal/services/applications/parse"
"github.com/hashicorp/terraform-provider-azuread/internal/tf"
"github.com/hashicorp/terraform-provider-azuread/internal/tf/pluginsdk"
"github.com/hashicorp/terraform-provider-azuread/internal/tf/validation"
"github.com/manicminer/hamilton/msgraph"
)

type ApplicationKnownClientsModel struct {
ApplicationId string `tfschema:"application_id"`
KnownClientIds []string `tfschema:"known_client_ids"`
}

type ApplicationKnownClientsResource struct{}

func (r ApplicationKnownClientsResource) IDValidationFunc() pluginsdk.SchemaValidateFunc {
return parse.ValidateKnownClientsID
}

var _ sdk.ResourceWithUpdate = ApplicationKnownClientsResource{}

func (r ApplicationKnownClientsResource) ResourceType() string {
return "azuread_application_known_clients"
}

func (r ApplicationKnownClientsResource) ModelObject() interface{} {
return &ApplicationKnownClientsModel{}
}

func (r ApplicationKnownClientsResource) Arguments() map[string]*pluginsdk.Schema {
return map[string]*pluginsdk.Schema{
"application_id": {
Description: "The resource ID of the application to which this API access is granted",
Type: pluginsdk.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: parse.ValidateApplicationID,
},

"known_client_ids": {
Description: "A list of known client IDs, used for bundling consent if you have a solution that includes an API and a client application",
Type: pluginsdk.TypeSet,
Required: true,
Elem: &pluginsdk.Schema{
Type: pluginsdk.TypeString,
ValidateFunc: validation.IsUUID,
},
},
}
}

func (r ApplicationKnownClientsResource) Attributes() map[string]*pluginsdk.Schema {
return map[string]*pluginsdk.Schema{}
}

func (r ApplicationKnownClientsResource) Create() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 10 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.Applications.ApplicationsClient
client.BaseClient.DisableRetries = true
defer func() { client.BaseClient.DisableRetries = false }()

var model ApplicationKnownClientsModel
if err := metadata.Decode(&model); err != nil {
return fmt.Errorf("decoding: %+v", err)
}

applicationId, err := parse.ParseApplicationID(model.ApplicationId)
if err != nil {
return err
}

id := parse.NewKnownClientsID(applicationId.ApplicationId)

tf.LockByName(applicationResourceName, id.ApplicationId)
defer tf.UnlockByName(applicationResourceName, id.ApplicationId)

result, _, err := client.Get(ctx, applicationId.ApplicationId, odata.Query{})
if err != nil {
return fmt.Errorf("retrieving %s: %+v", applicationId, err)
}
if result == nil {
return fmt.Errorf("retrieving %s: result was nil", applicationId)
}

// Check for existing known clients
if result.Api != nil && result.Api.KnownClientApplications != nil && len(*result.Api.KnownClientApplications) > 0 {
return metadata.ResourceRequiresImport(r.ResourceType(), id)
}

properties := msgraph.Application{
DirectoryObject: msgraph.DirectoryObject{
Id: &id.ApplicationId,
},
Api: &msgraph.ApplicationApi{
KnownClientApplications: pointer.To(model.KnownClientIds),
},
}

if _, err = client.Update(ctx, properties); err != nil {
return fmt.Errorf("creating %s: %+v", id, err)
}

metadata.SetID(id)
return nil
},
}
}

func (r ApplicationKnownClientsResource) Read() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 5 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.Applications.ApplicationsClient
client.BaseClient.DisableRetries = true
defer func() { client.BaseClient.DisableRetries = false }()

id, err := parse.ParseKnownClientsID(metadata.ResourceData.Id())
if err != nil {
return err
}

applicationId := parse.NewApplicationID(id.ApplicationId)

tf.LockByName(applicationResourceName, id.ApplicationId)
defer tf.UnlockByName(applicationResourceName, id.ApplicationId)

result, status, err := client.Get(ctx, id.ApplicationId, odata.Query{})
if err != nil {
if status == http.StatusNotFound {
return metadata.MarkAsGone(id)
}
return fmt.Errorf("retrieving %s: %+v", id, err)
}
if result == nil {
return fmt.Errorf("retrieving %s: result was nil", id)
}
if result.Api == nil || result.Api.KnownClientApplications == nil {
return metadata.MarkAsGone(id)
}

state := ApplicationKnownClientsModel{
ApplicationId: applicationId.ID(),
KnownClientIds: pointer.From(result.Api.KnownClientApplications),
}

return metadata.Encode(&state)
},
}
}

func (r ApplicationKnownClientsResource) Update() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 10 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.Applications.ApplicationsClient

id, err := parse.ParseKnownClientsID(metadata.ResourceData.Id())
if err != nil {
return err
}

applicationId := parse.NewApplicationID(id.ApplicationId)

var model ApplicationKnownClientsModel
if err := metadata.Decode(&model); err != nil {
return fmt.Errorf("decoding: %+v", err)
}

tf.LockByName(applicationResourceName, id.ApplicationId)
defer tf.UnlockByName(applicationResourceName, id.ApplicationId)

properties := msgraph.Application{
DirectoryObject: msgraph.DirectoryObject{
Id: &applicationId.ApplicationId,
},
Api: &msgraph.ApplicationApi{
KnownClientApplications: pointer.To(model.KnownClientIds),
},
}

_, err = client.Update(ctx, properties)
if err != nil {
return fmt.Errorf("updating %s: %+v", id, err)
}

return nil
},
}
}

func (r ApplicationKnownClientsResource) Delete() sdk.ResourceFunc {
return sdk.ResourceFunc{
Timeout: 5 * time.Minute,
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
client := metadata.Client.Applications.ApplicationsClient
client.BaseClient.DisableRetries = true
defer func() { client.BaseClient.DisableRetries = false }()

id, err := parse.ParseKnownClientsID(metadata.ResourceData.Id())
if err != nil {
return err
}

applicationId := parse.NewApplicationID(id.ApplicationId)

tf.LockByName(applicationResourceName, id.ApplicationId)
defer tf.UnlockByName(applicationResourceName, id.ApplicationId)

properties := msgraph.Application{
DirectoryObject: msgraph.DirectoryObject{
Id: &applicationId.ApplicationId,
},
Api: &msgraph.ApplicationApi{
KnownClientApplications: &[]string{},
},
}

_, err = client.Update(ctx, properties)
if err != nil {
return fmt.Errorf("deleting %s: %+v", id, err)
}

return nil
},
}
}
Loading

0 comments on commit aa54277

Please sign in to comment.