diff --git a/azuread/data_application.go b/azuread/data_application.go index fa31a49e2a..c5b15fd359 100644 --- a/azuread/data_application.go +++ b/azuread/data_application.go @@ -79,6 +79,8 @@ func dataApplication() *schema.Resource { Computed: true, }, + "app_roles": graph.SchemaAppRoles(), + "required_resource_access": { Type: schema.TypeList, Computed: true, @@ -193,6 +195,10 @@ func dataApplicationRead(d *schema.ResourceData, meta interface{}) error { d.Set("type", "webapp/api") } + if err := d.Set("app_roles", graph.FlattenAppRoles(app.AppRoles)); err != nil { + return fmt.Errorf("Error setting `app_roles`: %+v", err) + } + if err := d.Set("group_membership_claims", app.GroupMembershipClaims); err != nil { return fmt.Errorf("Error setting `group_membership_claims`: %+v", err) } diff --git a/azuread/data_application_test.go b/azuread/data_application_test.go index bef04cd035..8baf38a103 100644 --- a/azuread/data_application_test.go +++ b/azuread/data_application_test.go @@ -30,6 +30,7 @@ func TestAccAzureADApplicationDataSource_byObjectId(t *testing.T) { resource.TestCheckResourceAttr(dataSourceName, "reply_urls.#", "0"), resource.TestCheckResourceAttr(dataSourceName, "required_resource_access.#", "0"), resource.TestCheckResourceAttr(dataSourceName, "type", "webapp/api"), + resource.TestCheckResourceAttr(dataSourceName, "app_roles.#", "0"), resource.TestCheckResourceAttr(dataSourceName, "oauth2_allow_implicit_flow", "false"), resource.TestCheckResourceAttr(dataSourceName, "oauth2_permissions.#", "1"), resource.TestCheckResourceAttr(dataSourceName, "oauth2_permissions.0.admin_consent_description", fmt.Sprintf("Allow the application to access %s on behalf of the signed-in user.", fmt.Sprintf("acctest%s", id))), diff --git a/azuread/data_service_principal.go b/azuread/data_service_principal.go index 3c1261c806..2586562da1 100644 --- a/azuread/data_service_principal.go +++ b/azuread/data_service_principal.go @@ -40,6 +40,8 @@ func dataServicePrincipal() *schema.Resource { ConflictsWith: []string{"object_id", "display_name"}, }, + "app_roles": graph.SchemaAppRoles(), + "oauth2_permissions": graph.SchemaOauth2Permissions(), }, } @@ -129,6 +131,10 @@ func dataSourceActiveDirectoryServicePrincipalRead(d *schema.ResourceData, meta d.Set("display_name", sp.DisplayName) d.Set("object_id", sp.ObjectID) + if err := d.Set("app_roles", graph.FlattenAppRoles(sp.AppRoles)); err != nil { + return fmt.Errorf("Error setting `app_roles`: %+v", err) + } + if err := d.Set("oauth2_permissions", graph.FlattenOauth2Permissions(sp.Oauth2Permissions)); err != nil { return fmt.Errorf("Error setting `oauth2_permissions`: %+v", err) } diff --git a/azuread/data_service_principal_test.go b/azuread/data_service_principal_test.go index bf2a31afd8..8990b957bb 100644 --- a/azuread/data_service_principal_test.go +++ b/azuread/data_service_principal_test.go @@ -24,6 +24,7 @@ func TestAccAzureADServicePrincipalDataSource_byApplicationId(t *testing.T) { resource.TestCheckResourceAttrSet(dataSourceName, "application_id"), resource.TestCheckResourceAttrSet(dataSourceName, "object_id"), resource.TestCheckResourceAttrSet(dataSourceName, "display_name"), + resource.TestCheckResourceAttr(dataSourceName, "app_roles.#", "0"), resource.TestCheckResourceAttr(dataSourceName, "oauth2_permissions.#", "1"), resource.TestCheckResourceAttr(dataSourceName, "oauth2_permissions.0.admin_consent_description", fmt.Sprintf("Allow the application to access %s on behalf of the signed-in user.", fmt.Sprintf("acctestspa%s", id))), ), diff --git a/azuread/helpers/graph/application.go b/azuread/helpers/graph/application.go index 12f5f2dff5..ce6b9c36fd 100644 --- a/azuread/helpers/graph/application.go +++ b/azuread/helpers/graph/application.go @@ -5,6 +5,50 @@ import ( "github.com/hashicorp/terraform/helper/schema" ) +func SchemaAppRoles() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + + "allowed_member_types": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + + "description": { + Type: schema.TypeString, + Computed: true, + }, + + "display_name": { + Type: schema.TypeString, + Computed: true, + }, + + "is_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + + "value": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + } +} + func SchemaOauth2Permissions() *schema.Schema { return &schema.Schema{ Type: schema.TypeList, @@ -56,6 +100,38 @@ func SchemaOauth2Permissions() *schema.Schema { } } +func FlattenAppRoles(in *[]graphrbac.AppRole) []interface{} { + if in == nil { + return []interface{}{} + } + + appRoles := make([]interface{}, 0) + for _, role := range *in { + appRole := make(map[string]interface{}) + if role.ID != nil { + appRole["id"] = *role.ID + } + if role.AllowedMemberTypes != nil { + appRole["allowed_member_types"] = *role.AllowedMemberTypes + } + if role.Description != nil { + appRole["description"] = *role.Description + } + if role.DisplayName != nil { + appRole["display_name"] = *role.DisplayName + } + if role.IsEnabled != nil { + appRole["is_enabled"] = *role.IsEnabled + } + if role.Value != nil { + appRole["value"] = *role.Value + } + appRoles = append(appRoles, appRole) + } + + return appRoles +} + func FlattenOauth2Permissions(in *[]graphrbac.OAuth2Permission) []map[string]interface{} { if in == nil { return []map[string]interface{}{} diff --git a/azuread/resource_application.go b/azuread/resource_application.go index ec147af9f0..58d4b961bb 100644 --- a/azuread/resource_application.go +++ b/azuread/resource_application.go @@ -396,7 +396,7 @@ func resourceApplicationRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("Error setting `required_resource_access`: %+v", err) } - if err := d.Set("app_role", flattenADApplicationAppRoles(app.AppRoles)); err != nil { + if err := d.Set("app_role", graph.FlattenAppRoles(app.AppRoles)); err != nil { return fmt.Errorf("Error setting `app_role`: %+v", err) } @@ -553,35 +553,3 @@ func expandADApplicationAppRoles(i interface{}) *[]graphrbac.AppRole { return &output } - -func flattenADApplicationAppRoles(in *[]graphrbac.AppRole) []interface{} { - if in == nil { - return []interface{}{} - } - - appRoles := make([]interface{}, 0) - for _, role := range *in { - appRole := make(map[string]interface{}) - if role.ID != nil { - appRole["id"] = *role.ID - } - if role.AllowedMemberTypes != nil { - appRole["allowed_member_types"] = *role.AllowedMemberTypes - } - if role.Description != nil { - appRole["description"] = *role.Description - } - if role.DisplayName != nil { - appRole["display_name"] = *role.DisplayName - } - if role.IsEnabled != nil { - appRole["is_enabled"] = *role.IsEnabled - } - if role.Value != nil { - appRole["value"] = *role.Value - } - appRoles = append(appRoles, appRole) - } - - return appRoles -} diff --git a/website/docs/d/application.html.markdown b/website/docs/d/application.html.markdown index 02dd5724e4..2704640ef8 100644 --- a/website/docs/d/application.html.markdown +++ b/website/docs/d/application.html.markdown @@ -54,6 +54,8 @@ output "azure_ad_object_id" { * `oauth2_permissions` - A collection of OAuth 2.0 permission scopes that the web API (resource) app exposes to client apps. Each permission is covered by a `oauth2_permission` block as documented below. +* `app_roles` - A collection of `app_role` blocks as documented below. For more information https://docs.microsoft.com/en-us/azure/architecture/multitenant-identity/app-roles + --- `required_resource_access` block exports the following: @@ -89,3 +91,19 @@ output "azure_ad_object_id" { * `user_consent_display_name` - The display name of the user consent * `value` - The name of this permission + +--- + +`app_role` block exports the following: + +* `id` - The unique identifier of the `app_role`. + +* `allowed_member_types` - Specifies whether this app role definition can be assigned to users and groups, or to other applications (that are accessing this application in daemon service scenarios). Possible values are: `User` and `Application`, or both. + +* `description` - Permission help text that appears in the admin app assignment and consent experiences. + +* `display_name` - Display name for the permission that appears in the admin consent and app assignment experiences. + +* `is_enabled` - Determines if the app role is enabled. + +* `value` - Specifies the value of the roles claim that the application should expect in the authentication and access tokens. diff --git a/website/docs/d/service_principal.html.markdown b/website/docs/d/service_principal.html.markdown index 0311777ab1..863cba746d 100644 --- a/website/docs/d/service_principal.html.markdown +++ b/website/docs/d/service_principal.html.markdown @@ -49,6 +49,8 @@ The following arguments are supported: -> **NOTE:** At least one of `application_id`, `display_name` or `object_id` must be specified. +* `app_roles` - A collection of `app_role` blocks as documented below. For more information https://docs.microsoft.com/en-us/azure/architecture/multitenant-identity/app-roles + * `oauth2_permissions` - A collection of OAuth 2.0 permissions exposed by the associated application. Each permission is covered by a `oauth2_permission` block as documented below. ## Attributes Reference @@ -76,3 +78,19 @@ The following attributes are exported: * `user_consent_display_name` - The display name of the user consent * `value` - The name of this permission + +--- + +`app_role` block exports the following: + +* `id` - The unique identifier of the `app_role`. + +* `allowed_member_types` - Specifies whether this app role definition can be assigned to users and groups, or to other applications (that are accessing this application in daemon service scenarios). Possible values are: `User` and `Application`, or both. + +* `description` - Permission help text that appears in the admin app assignment and consent experiences. + +* `display_name` - Display name for the permission that appears in the admin consent and app assignment experiences. + +* `is_enabled` - Determines if the app role is enabled. + +* `value` - Specifies the value of the roles claim that the application should expect in the authentication and access tokens.