-
Notifications
You must be signed in to change notification settings - Fork 301
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New resource: azuread_pre_authorized_application
- Loading branch information
1 parent
7d7c740
commit 99e9a0e
Showing
4 changed files
with
465 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
--- | ||
subcategory: "Applications" | ||
--- | ||
|
||
# Resource: azuread_pre_authorized_application | ||
|
||
Manages client applications that are pre-authorized with the specified permissions to access an application's APIs without requiring user consent. | ||
|
||
## Example Usage | ||
|
||
```terraform | ||
resource "azuread_application" "authorized" { | ||
display_name = "example-authorized-app" | ||
} | ||
resource "azuread_application" "authorizer" { | ||
display_name = "example-authorizing-app" | ||
api { | ||
oauth2_permission_scope { | ||
admin_consent_description = "Administer the application" | ||
admin_consent_display_name = "Administer" | ||
enabled = true | ||
id = "ced9c4c3-c273-4f0f-ac71-a20377b90f9c" | ||
type = "Admin" | ||
value = "administer" | ||
} | ||
oauth2_permission_scope { | ||
admin_consent_description = "Access the application" | ||
admin_consent_display_name = "Access" | ||
enabled = true | ||
id = "2d5e07ca-664d-4d9b-ad61-ec07fd215213" | ||
type = "User" | ||
user_consent_description = "Access the application" | ||
user_consent_display_name = "Access" | ||
value = "user_impersonation" | ||
} | ||
} | ||
} | ||
resource "azuread_pre_authorized_application" "example" { | ||
application_object_id = azuread_application.authorizer.object_id | ||
authorized_app_id = azuread_application.authorized.application_id | ||
permission_ids = ["ced9c4c3-c273-4f0f-ac71-a20377b90f9c", "2d5e07ca-664d-4d9b-ad61-ec07fd215213"] | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
The following arguments are supported: | ||
|
||
* `application_object_id` - (Required) The object ID of the application for which permissions are being authorized. Changing this field forces a new resource to be created. | ||
* `authorized_application_id` - (Optional) The application ID (client ID) of the application being authorized. Changing this field forces a new resource to be created. | ||
* `permission_ids` - (Required) A set of permission scope IDs required by the authorized application. | ||
|
||
## Attributes Reference | ||
|
||
In addition to all arguments above, the following attributes are exported: | ||
|
||
*No additional attributes are exported* | ||
|
||
## Import | ||
|
||
Pre-authorized applications can be imported using the object ID of the authorizing application and the application ID of the application being authorized, e.g. | ||
|
||
```shell | ||
terraform import azuread_pre_authorized_application.example 00000000-0000-0000-0000-000000000000/preAuthorizedApplication/11111111-1111-1111-1111-111111111111 | ||
``` | ||
|
||
-> **NOTE:** This ID format is unique to Terraform and is composed of the authorizing application's object ID, the string "preAuthorizedApplication" and the authorized application's application ID (client ID) in the format `{ObjectId}/preAuthorizedApplication/{ApplicationId}`. |
258 changes: 258 additions & 0 deletions
258
internal/services/applications/pre_authorized_application_resource.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,258 @@ | ||
package applications | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"log" | ||
"net/http" | ||
"strings" | ||
"time" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
"github.com/manicminer/hamilton/msgraph" | ||
|
||
"github.com/hashicorp/terraform-provider-azuread/internal/clients" | ||
"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/utils" | ||
"github.com/hashicorp/terraform-provider-azuread/internal/validate" | ||
) | ||
|
||
func preAuthorizedApplicationResource() *schema.Resource { | ||
return &schema.Resource{ | ||
CreateContext: preAuthorizedApplicationResourceCreate, | ||
ReadContext: preAuthorizedApplicationResourceRead, | ||
UpdateContext: preAuthorizedApplicationResourceUpdate, | ||
DeleteContext: preAuthorizedApplicationResourceDelete, | ||
|
||
Timeouts: &schema.ResourceTimeout{ | ||
Create: schema.DefaultTimeout(5 * time.Minute), | ||
Read: schema.DefaultTimeout(5 * time.Minute), | ||
Update: schema.DefaultTimeout(5 * time.Minute), | ||
Delete: schema.DefaultTimeout(5 * time.Minute), | ||
}, | ||
|
||
Importer: tf.ValidateResourceIDPriorToImport(func(id string) error { | ||
_, err := parse.PreAuthorizedApplicationID(id) | ||
return err | ||
}), | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"application_object_id": { | ||
Description: "The object ID of the application to which this pre-authorized application should be added", | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
ValidateDiagFunc: validate.UUID, | ||
}, | ||
|
||
"authorized_app_id": { | ||
Description: "The application ID of the pre-authorized application", | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
ValidateDiagFunc: validate.UUID, | ||
}, | ||
|
||
"permission_ids": { | ||
Description: "The IDs of the permission scopes required by the pre-authorized application", | ||
Type: schema.TypeSet, | ||
Required: true, | ||
Elem: &schema.Schema{ | ||
Type: schema.TypeString, | ||
ValidateDiagFunc: validate.UUID, | ||
}, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func preAuthorizedApplicationResourceCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
client := meta.(*clients.Client).Applications.ApplicationsClient | ||
id := parse.NewPreAuthorizedApplicationID(d.Get("application_object_id").(string), d.Get("authorized_app_id").(string)) | ||
|
||
tf.LockByName(applicationResourceName, id.ObjectId) | ||
defer tf.UnlockByName(applicationResourceName, id.ObjectId) | ||
|
||
app, status, err := client.Get(ctx, id.ObjectId) | ||
if err != nil { | ||
if status == http.StatusNotFound { | ||
return tf.ErrorDiagPathF(nil, "application_object_id", "Application with object ID %q was not found", id.ObjectId) | ||
} | ||
return tf.ErrorDiagPathF(err, "application_object_id", "Retrieving application with object ID %q", id.ObjectId) | ||
} | ||
if app == nil || app.ID == nil { | ||
return tf.ErrorDiagF(errors.New("nil application or application with nil ID was returned"), "API error retrieving application with object ID %q", id.ObjectId) | ||
} | ||
|
||
newPreAuthorizedApps := make([]msgraph.ApiPreAuthorizedApplication, 0) | ||
if app.Api != nil && app.Api.PreAuthorizedApplications != nil { | ||
for _, a := range *app.Api.PreAuthorizedApplications { | ||
if a.AppId != nil && strings.EqualFold(*a.AppId, id.AppId) { | ||
return tf.ImportAsExistsDiag("azuread_pre_authorized_application", id.String()) | ||
} | ||
newPreAuthorizedApps = append(newPreAuthorizedApps, a) | ||
} | ||
} | ||
|
||
newPreAuthorizedApps = append(newPreAuthorizedApps, msgraph.ApiPreAuthorizedApplication{ | ||
AppId: utils.String(id.AppId), | ||
PermissionIds: tf.ExpandStringSlicePtr(d.Get("permission_ids").(*schema.Set).List()), | ||
}) | ||
|
||
properties := msgraph.Application{ | ||
ID: app.ID, | ||
Api: &msgraph.ApplicationApi{ | ||
PreAuthorizedApplications: &newPreAuthorizedApps, | ||
}, | ||
} | ||
|
||
if _, err := client.Update(ctx, properties); err != nil { | ||
return tf.ErrorDiagF(err, "Adding pre-authorized application %q for application with object ID %q", id.AppId, id.ObjectId) | ||
} | ||
|
||
d.SetId(id.String()) | ||
|
||
return preAuthorizedApplicationResourceRead(ctx, d, meta) | ||
} | ||
|
||
func preAuthorizedApplicationResourceUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
client := meta.(*clients.Client).Applications.ApplicationsClient | ||
id, err := parse.PreAuthorizedApplicationID(d.Id()) | ||
if err != nil { | ||
return tf.ErrorDiagPathF(err, "id", "Parsing pre-authorized application ID %q", d.Id()) | ||
} | ||
|
||
tf.LockByName(applicationResourceName, id.ObjectId) | ||
defer tf.UnlockByName(applicationResourceName, id.ObjectId) | ||
|
||
app, status, err := client.Get(ctx, id.ObjectId) | ||
if err != nil { | ||
if status == http.StatusNotFound { | ||
return tf.ErrorDiagPathF(nil, "application_object_id", "Application with object ID %q was not found", id.ObjectId) | ||
} | ||
return tf.ErrorDiagPathF(err, "application_object_id", "Retrieving application with object ID %q", id.ObjectId) | ||
} | ||
if app == nil || app.ID == nil { | ||
return tf.ErrorDiagF(errors.New("nil application or application with nil ID was returned"), "API error retrieving application with object ID %q", id.ObjectId) | ||
} | ||
if app.Api == nil || app.Api.PreAuthorizedApplications == nil { | ||
return tf.ErrorDiagF(errors.New("application with nil preAuthorizedApplications was returned"), "API error retrieving application with object ID %q", id.ObjectId) | ||
} | ||
|
||
found := false | ||
newPreAuthorizedApps := *app.Api.PreAuthorizedApplications | ||
for i, a := range newPreAuthorizedApps { | ||
if a.AppId != nil && strings.EqualFold(*a.AppId, id.AppId) { | ||
found = true | ||
newPreAuthorizedApps[i].PermissionIds = tf.ExpandStringSlicePtr(d.Get("permission_ids").(*schema.Set).List()) | ||
break | ||
} | ||
} | ||
if !found { | ||
return tf.ErrorDiagF(fmt.Errorf("could not match an existing preAuthorizedApplication for %q", id.AppId), "retrieving application with object ID %q", id.ObjectId) | ||
} | ||
|
||
properties := msgraph.Application{ | ||
ID: app.ID, | ||
Api: &msgraph.ApplicationApi{ | ||
PreAuthorizedApplications: &newPreAuthorizedApps, | ||
}, | ||
} | ||
|
||
if _, err := client.Update(ctx, properties); err != nil { | ||
return tf.ErrorDiagF(err, "Updating pre-authorized application %q for application with object ID %q", id.AppId, id.ObjectId) | ||
} | ||
|
||
return preAuthorizedApplicationResourceRead(ctx, d, meta) | ||
} | ||
|
||
func preAuthorizedApplicationResourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
client := meta.(*clients.Client).Applications.ApplicationsClient | ||
id, err := parse.PreAuthorizedApplicationID(d.Id()) | ||
if err != nil { | ||
return tf.ErrorDiagPathF(err, "id", "Parsing pre-authorized application ID %q", d.Id()) | ||
} | ||
|
||
app, status, err := client.Get(ctx, id.ObjectId) | ||
if err != nil { | ||
if status == http.StatusNotFound { | ||
log.Printf("[DEBUG] Application with ID %q for pre-authorized application %q was not found - removing from state!", id.ObjectId, id.AppId) | ||
d.SetId("") | ||
return nil | ||
} | ||
return tf.ErrorDiagPathF(err, "application_object_id", "Retrieving Application with object ID %q", id.ObjectId) | ||
} | ||
if app == nil || app.ID == nil { | ||
return tf.ErrorDiagF(errors.New("nil application or application with nil ID was returned"), "API error retrieving application with object ID %q", id.ObjectId) | ||
} | ||
if app.Api == nil || app.Api.PreAuthorizedApplications == nil { | ||
return tf.ErrorDiagF(errors.New("application with nil preAuthorizedApplications was returned"), "API error retrieving application with object ID %q", id.ObjectId) | ||
} | ||
|
||
var preAuthorizedApp *msgraph.ApiPreAuthorizedApplication | ||
for _, a := range *app.Api.PreAuthorizedApplications { | ||
if a.AppId != nil && strings.EqualFold(*a.AppId, id.AppId) { | ||
preAuthorizedApp = &a | ||
break | ||
} | ||
} | ||
if preAuthorizedApp == nil { | ||
log.Printf("[DEBUG] No matching preAuthorizedApplication for ID %q - removing from state!", id) | ||
d.SetId("") | ||
return nil | ||
} | ||
|
||
d.Set("application_object_id", id.ObjectId) | ||
d.Set("authorized_app_id", id.AppId) | ||
d.Set("permission_ids", tf.FlattenStringSlicePtr(preAuthorizedApp.PermissionIds)) | ||
|
||
return nil | ||
} | ||
|
||
func preAuthorizedApplicationResourceDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
client := meta.(*clients.Client).Applications.ApplicationsClient | ||
id, err := parse.PreAuthorizedApplicationID(d.Id()) | ||
if err != nil { | ||
return tf.ErrorDiagPathF(err, "id", "Parsing pre-authorized application ID %q", d.Id()) | ||
} | ||
|
||
app, status, err := client.Get(ctx, id.ObjectId) | ||
if err != nil { | ||
if status == http.StatusNotFound { | ||
log.Printf("[DEBUG] Application with ID %q for pre-authorized application %q was not found - removing from state!", id.ObjectId, id.AppId) | ||
d.SetId("") | ||
return nil | ||
} | ||
return tf.ErrorDiagPathF(err, "application_object_id", "Retrieving Application with object ID %q", id.ObjectId) | ||
} | ||
if app == nil || app.ID == nil { | ||
return tf.ErrorDiagF(errors.New("nil application or application with nil ID was returned"), "API error retrieving application with object ID %q", id.ObjectId) | ||
} | ||
if app.Api == nil || app.Api.PreAuthorizedApplications == nil { | ||
return tf.ErrorDiagF(errors.New("application with nil preAuthorizedApplications was returned"), "API error retrieving application with object ID %q", id.ObjectId) | ||
} | ||
|
||
newPreAuthorizedApps := make([]msgraph.ApiPreAuthorizedApplication, 0) | ||
for _, a := range *app.Api.PreAuthorizedApplications { | ||
if a.AppId != nil && !strings.EqualFold(*a.AppId, id.AppId) { | ||
newPreAuthorizedApps = append(newPreAuthorizedApps, a) | ||
break | ||
} | ||
} | ||
|
||
properties := msgraph.Application{ | ||
ID: app.ID, | ||
Api: &msgraph.ApplicationApi{ | ||
PreAuthorizedApplications: &newPreAuthorizedApps, | ||
}, | ||
} | ||
|
||
if _, err := client.Update(ctx, properties); err != nil { | ||
return tf.ErrorDiagF(err, "Removing pre-authorized application %q from application with object ID %q", id.AppId, id.ObjectId) | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.