Skip to content

Commit

Permalink
Added support for Required Resource Access Type within provider `azur…
Browse files Browse the repository at this point in the history
…ead_application`
  • Loading branch information
Gerard Paulke authored and Gerard Paulke committed Jan 22, 2019
1 parent 284b949 commit a4cb158
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 0 deletions.
121 changes: 121 additions & 0 deletions azuread/resource_application.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,41 @@ func resourceApplication() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},

"required_resource_access": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"resource_app_id": {
Type: schema.TypeString,
Required: true,
},

"resource_access": {
Type: schema.TypeList,
Required: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"id": {
Type: schema.TypeString,
Required: true,
},

"type": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice(
[]string{"scope", "role"},
true, // ignore case
),
},
},
},
},
},
},
},
},
}
}
Expand All @@ -89,6 +124,7 @@ func resourceApplicationCreate(d *schema.ResourceData, meta interface{}) error {
IdentifierUris: expandADApplicationIdentifierUris(d),
ReplyUrls: expandADApplicationReplyUrls(d),
AvailableToOtherTenants: p.Bool(d.Get("available_to_other_tenants").(bool)),
RequiredResourceAccess: expandADApplicationRequiredResourceAccess(d),
}

if v, ok := d.GetOk("oauth2_allow_implicit_flow"); ok {
Expand Down Expand Up @@ -139,6 +175,10 @@ func resourceApplicationUpdate(d *schema.ResourceData, meta interface{}) error {
properties.Oauth2AllowImplicitFlow = p.Bool(oauth)
}

if d.HasChange("required_resource_access") {
properties.RequiredResourceAccess = expandADApplicationRequiredResourceAccess(d)
}

if _, err := client.Patch(ctx, d.Id(), properties); err != nil {
return fmt.Errorf("Error patching Azure AD Application with ID %q: %+v", d.Id(), err)
}
Expand Down Expand Up @@ -183,6 +223,14 @@ func resourceApplicationRead(d *schema.ResourceData, meta interface{}) error {
return fmt.Errorf("Error setting `reply_urls`: %+v", err)
}

requiredResourceAccesses := make([]graphrbac.RequiredResourceAccess, 0)
if s := *resp.RequiredResourceAccess; s != nil {
requiredResourceAccesses = s
}
if err := d.Set("required_resource_access", flattenADApplicationRequiredResourceAccess(&requiredResourceAccesses)); err != nil {
return fmt.Errorf("Error setting `required_resource_access`: %+v", err)
}

return nil
}

Expand Down Expand Up @@ -242,3 +290,76 @@ func expandADApplicationReplyUrls(d *schema.ResourceData) *[]string {

return &urls
}

func expandADApplicationRequiredResourceAccess(d *schema.ResourceData) *[]graphrbac.RequiredResourceAccess {
requiredResourcesAccesses := d.Get("required_resource_access").(*schema.Set).List()
result := make([]graphrbac.RequiredResourceAccess, 0)

for _, raw := range requiredResourcesAccesses {
requiredResourceAccess := raw.(map[string]interface{})

resource_app_id := requiredResourceAccess["resource_app_id"].(string)

result = append(result,
graphrbac.RequiredResourceAccess{
ResourceAppID: &resource_app_id,
ResourceAccess: expandADApplicationResourceAccess(
requiredResourceAccess["resource_access"].([]interface{}),
),
},
)
}
return &result
}

func expandADApplicationResourceAccess(in []interface{}) *[]graphrbac.ResourceAccess {
var resourceAccesses []graphrbac.ResourceAccess
for _, resource_access_raw := range in {
resource_access := resource_access_raw.(map[string]interface{})

resourceId := resource_access["id"].(string)
resourceType := resource_access["type"].(string)

resourceAccesses = append(resourceAccesses,
graphrbac.ResourceAccess{
ID: &resourceId,
Type: &resourceType,
},
)
}

return &resourceAccesses
}

func flattenADApplicationRequiredResourceAccess(in *[]graphrbac.RequiredResourceAccess) []map[string]interface{} {
result := make([]map[string]interface{}, 0, len(*in))

if in != nil {
for _, requiredResourceAccess := range *in {
resource := make(map[string]interface{})
resource["resource_app_id"] = string(*requiredResourceAccess.ResourceAppID)

if *requiredResourceAccess.ResourceAccess != nil {
resource["resource_access"] = flattenADApplicationResourceAccess(requiredResourceAccess.ResourceAccess)
}

result = append(result, resource)
}
}

return result
}

func flattenADApplicationResourceAccess(in *[]graphrbac.ResourceAccess) []map[string]interface{} {
accesses := make([]map[string]interface{}, 0)

for _, resourceAccess := range *in {
accesses = append(accesses,
map[string]interface{}{
"id": *resourceAccess.ID,
"type": *resourceAccess.Type,
},
)
}
return accesses
}
26 changes: 26 additions & 0 deletions azuread/resource_application_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ func TestAccAzureADApplication_complete(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "homepage", fmt.Sprintf("https://homepage-%s", id)),
resource.TestCheckResourceAttr(resourceName, "identifier_uris.#", "1"),
resource.TestCheckResourceAttr(resourceName, "reply_urls.#", "1"),
resource.TestCheckResourceAttr(resourceName, "required_resource_access.#", "2"),
resource.TestCheckResourceAttrSet(resourceName, "application_id"),
),
},
Expand Down Expand Up @@ -120,6 +121,7 @@ func TestAccAzureADApplication_update(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "homepage", fmt.Sprintf("https://homepage-%s", updatedId)),
resource.TestCheckResourceAttr(resourceName, "identifier_uris.#", "1"),
resource.TestCheckResourceAttr(resourceName, "reply_urls.#", "1"),
resource.TestCheckResourceAttr(resourceName, "required_resource_access.#", "2"),
),
},
},
Expand Down Expand Up @@ -198,6 +200,30 @@ resource "azuread_application" "test" {
identifier_uris = ["http://%s.hashicorptest.com"]
reply_urls = ["http://%s.hashicorptest.com"]
oauth2_allow_implicit_flow = true
required_resource_access {
resource_app_id = "00000003-0000-0000-c000-000000000000"
resource_access {
id = "7ab1d382-f21e-4acd-a863-ba3e13f7da61"
type = "Role"
}
resource_access {
id = "e1fe6dd8-ba31-4d61-89e7-88639da4683d"
type = "Scope"
}
resource_access {
id = "06da0dbc-49e2-44d2-8312-53f166ab848a"
type = "Scope"
}
}
required_resource_access {
resource_app_id = "00000002-0000-0000-c000-000000000000"
resource_access {
id = "311a71cc-e848-46a1-bdf8-97ff7156d8e6"
type = "Scope"
}
}
}
`, id, id, id, id)
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 45 additions & 0 deletions website/docs/r/application.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,33 @@ resource "azuread_application" "test" {
reply_urls = ["https://replyurl"]
available_to_other_tenants = false
oauth2_allow_implicit_flow = true
required_resource_access {
resource_app_id = "00000003-0000-0000-c000-000000000000"
resource_access {
id = "..."
type = "Role"
}
resource_access {
id = "..."
type = "Scope"
}
resource_access {
id = "..."
type = "Scope"
}
}
required_resource_access {
resource_app_id = "00000002-0000-0000-c000-000000000000"
resource_access {
id = ".."
type = "Scope"
}
}
}
```

Expand All @@ -42,6 +69,24 @@ The following arguments are supported:

* `oauth2_allow_implicit_flow` - (Optional) Does this Azure AD Application allow OAuth2.0 implicit flow tokens? Defaults to `false`.

* `required_resource_access` - (Optional) A collection of required_resource_access blocks as documented below. Specifies resources that this application requires access to and the set of OAuth permission scopes and application roles that it needs under each of those resources. This pre-configuration of required resource access drives the consent experience.

---

`required_resource_access` supports the following:

* `resource_app_id` - (Required) The unique identifier for the resource that the application requires access to. This should be equal to the appId declared on the target resource application.

* `resource_access"` - (Required) A collection of resource_access blocks as documented below

---

`resource_access` supports the following:

* `id` - (Required) The unique identifier for one of the OAuth2Permission or AppRole instances that the resource application exposes.

* `type` - (Required) Specifies whether the id property references an OAuth2Permission or an AppRole. Possible values are "scope" or "role".

## Attributes Reference

The following attributes are exported:
Expand Down

0 comments on commit a4cb158

Please sign in to comment.