diff --git a/docs/resources/application.md b/docs/resources/application.md index 1b9c969805..ca47d71928 100644 --- a/docs/resources/application.md +++ b/docs/resources/application.md @@ -26,6 +26,7 @@ data "azuread_client_config" "current" {} resource "azuread_application" "example" { display_name = "example" identifier_uris = ["api://example-app"] + logo_image = filebase64("/path/to/logo.png") owners = [data.azuread_client_config.current.object_id] sign_in_audience = "AzureADMultipleOrgs" @@ -163,6 +164,7 @@ The following arguments are supported: * `fallback_public_client_enabled` - (Optional) Specifies whether the application is a public client. Appropriate for apps using token grant flows that don't use a redirect URI. Defaults to `false`. * `group_membership_claims` - (Optional) Configures the `groups` claim issued in a user or OAuth 2.0 access token that the app expects. Possible values are `None`, `SecurityGroup`, `DirectoryRole`, `ApplicationGroup` or `All`. * `identifier_uris` - (Optional) A set of user-defined URI(s) that uniquely identify an application within its Azure AD tenant, or within a verified custom domain if the application is multi-tenant. +* `logo_image` - (Optional) A logo image to upload for the application, as a raw base64-encoded string. The image should be in gif, jpeg or png format. Note that once an image has been uploaded, it is not possible to remove it without replacing it with another image. * `marketing_url` - (Optional) URL of the application's marketing page. * `oauth2_post_response_required` - (Optional) Specifies whether, as part of OAuth 2.0 token requests, Azure AD allows POST requests, as opposed to GET requests. Defaults to `false`, which specifies that only GET requests are allowed. * `optional_claims` - (Optional) An `optional_claims` block as documented below. @@ -299,7 +301,7 @@ In addition to all arguments above, the following attributes are exported: * `app_role_ids` - A mapping of app role values to app role IDs, intended to be useful when referencing app roles in other resources in your configuration. * `application_id` - The Application ID (also called Client ID). * `disabled_by_microsoft` - Whether Microsoft has disabled the registered application. If the application is disabled, this will be a string indicating the status/reason, e.g. `DisabledDueToViolationOfServicesAgreement` -* `logo_url` - CDN URL to the application's logo. +* `logo_url` - CDN URL to the application's logo, as uploaded with the `logo_image` property. * `oauth2_permission_scope_ids` - A mapping of OAuth2.0 permission scope values to scope IDs, intended to be useful when referencing permission scopes in other resources in your configuration. * `object_id` - The application's object ID. * `publisher_domain` - The verified publisher domain for the application. diff --git a/internal/services/applications/application_resource.go b/internal/services/applications/application_resource.go index 88c02eed2d..2bab45c98a 100644 --- a/internal/services/applications/application_resource.go +++ b/internal/services/applications/application_resource.go @@ -295,6 +295,13 @@ func applicationResource() *schema.Resource { }, }, + "logo_image": { + Description: "Base64 encoded logo image in gif, png or jpeg format", + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsBase64, + }, + "marketing_url": { Description: "URL of the application's marketing page", Type: schema.TypeString, @@ -600,6 +607,11 @@ func applicationResourceCustomizeDiff(ctx context.Context, diff *schema.Resource diff.SetNewComputed("oauth2_permission_scope_ids") } + // If the logo image changes, the CDN URL will change + if diff.HasChange("logo_image") { + diff.SetNewComputed("logo_url") + } + // The following validation is taken from https://docs.microsoft.com/en-gb/azure/active-directory/develop/supported-accounts-validation // These apply only when personal account sign-ins are enabled for an application, and are enforced at plan time to avoid breaking existing // applications that change from AAD (corporate) account sign-ins to personal account sign-ins @@ -838,6 +850,16 @@ func applicationResourceCreate(ctx context.Context, d *schema.ResourceData, meta } } + var imageContentType string + var imageData []byte + if v, ok := d.GetOk("logo_image"); ok && v != "" { + var err error + imageContentType, imageData, err = applicationParseLogoImage(v.(string)) + if err != nil { + return tf.ErrorDiagPathF(err, "image", "Could not decode image data") + } + } + if templateId != "" { // Instantiate application from template gallery and return via the update function properties := msgraph.ApplicationTemplate{ @@ -958,6 +980,14 @@ func applicationResourceCreate(ctx context.Context, d *schema.ResourceData, meta } } + // Upload the application image + if imageContentType != "" && len(imageData) > 0 { + _, err := client.UploadLogo(ctx, d.Id(), imageContentType, imageData) + if err != nil { + return tf.ErrorDiagF(err, "Could not upload logo image for application with object ID: %q", d.Id()) + } + } + return applicationResourceRead(ctx, d, meta) } @@ -986,6 +1016,16 @@ func applicationResourceUpdate(ctx context.Context, d *schema.ResourceData, meta } } + var imageContentType string + var imageData []byte + if v, ok := d.GetOk("logo_image"); ok && v != "" && d.HasChange("logo_image") { + var err error + imageContentType, imageData, err = applicationParseLogoImage(v.(string)) + if err != nil { + return tf.ErrorDiagPathF(err, "image", "Could not decode image data") + } + } + properties := msgraph.Application{ DirectoryObject: msgraph.DirectoryObject{ ID: utils.String(applicationId), @@ -1061,6 +1101,14 @@ func applicationResourceUpdate(ctx context.Context, d *schema.ResourceData, meta } } + // Upload the application image + if imageContentType != "" && len(imageData) > 0 { + _, err := client.UploadLogo(ctx, d.Id(), imageContentType, imageData) + if err != nil { + return tf.ErrorDiagF(err, "Could not upload logo image for application with object ID: %q", d.Id()) + } + } + return applicationResourceRead(ctx, d, meta) } @@ -1111,6 +1159,12 @@ func applicationResourceRead(ctx context.Context, d *schema.ResourceData, meta i tf.Set(d, "terms_of_service_url", app.Info.TermsOfServiceUrl) } + logoImage := "" + if v := d.Get("logo_image").(string); v != "" { + logoImage = v + } + tf.Set(d, "logo_image", logoImage) + preventDuplicates := false if v := d.Get("prevent_duplicate_names").(bool); v { preventDuplicates = v diff --git a/internal/services/applications/application_resource_test.go b/internal/services/applications/application_resource_test.go index 89d8610b3d..4cc85a5081 100644 --- a/internal/services/applications/application_resource_test.go +++ b/internal/services/applications/application_resource_test.go @@ -441,6 +441,35 @@ func TestAccApplication_related(t *testing.T) { }) } +func TestAccApplication_logo(t *testing.T) { + data := acceptance.BuildTestData(t, "azuread_application", "test") + r := ApplicationResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.logo(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("logo"), + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.logo(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("logo"), + }) +} + func (r ApplicationResource) Exists(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) (*bool, error) { client := clients.Applications.ApplicationsClient client.BaseClient.DisableRetries = true @@ -1270,3 +1299,14 @@ resource "azuread_application" "test" { } `, data.RandomInteger) } + +func (r ApplicationResource) logo(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azuread" {} + +resource "azuread_application" "test" { + display_name = "acctest-APP-%[1]d" + logo_image = "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" // thisisfine +} +`, data.RandomInteger) +} diff --git a/internal/services/applications/applications.go b/internal/services/applications/applications.go index 792f02428f..7408f191b8 100644 --- a/internal/services/applications/applications.go +++ b/internal/services/applications/applications.go @@ -2,9 +2,11 @@ package applications import ( "context" + "encoding/base64" "fmt" "net/http" "reflect" + "strings" "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -295,6 +297,18 @@ func applicationFindByName(ctx context.Context, client *msgraph.ApplicationsClie return &result, nil } +func applicationParseLogoImage(encodedImage string) (string, []byte, error) { + imageData, err := base64.StdEncoding.DecodeString(strings.TrimSpace(encodedImage)) + if err != nil { + return "", nil, err + } + contentType := http.DetectContentType(imageData) + if !strings.HasPrefix(contentType, "image/") { + return "", nil, fmt.Errorf("unrecognised MIME type detected: %q", contentType) + } + return contentType, imageData, nil +} + func applicationValidateRolesScopes(appRoles, oauth2Permissions []interface{}) error { var ids, values []string