forked from hashicorp/terraform-provider-azuread
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ Add Claims Mapping Policy Resource
Adds support for the claims mapping policy resource so these can be managed with Terraform. Related to: - manicminer/hamilton#147 - hashicorp#644 - https://docs.microsoft.com/en-us/graph/api/resources/claimsmappingpolicy?view=graph-rest-1.0
- Loading branch information
1 parent
6ee8709
commit 6298318
Showing
5 changed files
with
325 additions
and
0 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,72 @@ | ||
--- | ||
subcategory: "Policies" | ||
--- | ||
|
||
# Resource: claims_mapping_policy | ||
|
||
Manages a Claims Mapping Policy within Azure Active Directory. | ||
|
||
## API Permissions | ||
|
||
The following API permissions are required in order to use this resource. | ||
|
||
When authenticated with a service principal, this resource requires the following application roles: `Policy.ReadWrite.ApplicationConfiguration` | ||
|
||
When authenticated with a user principal, this resource requires one of the following directory roles: `Application Administrator` or `Global Administrator` | ||
|
||
## Example Usage | ||
|
||
```terraform | ||
resource "azuread_claims_mapping_policy" "test" { | ||
definition = [ | ||
jsonencode( | ||
{ | ||
ClaimsMappingPolicy = { | ||
ClaimsSchema = [ | ||
{ | ||
ID = "employeeid" | ||
JwtClaimType = "name" | ||
SamlClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" | ||
Source = "user" | ||
}, | ||
{ | ||
ID = "tenantcountry" | ||
JwtClaimType = "country" | ||
SamlClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/country" | ||
Source = "company" | ||
} | ||
] | ||
IncludeBasicClaimSet = "true" | ||
Version = 1 | ||
} | ||
} | ||
), | ||
] | ||
description = "hcl-created-policy" | ||
display_name = "hcl-create-policy" | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
The following arguments are supported: | ||
|
||
* `definition` - (Required) The claims mapping policy. This is a JSON formatted | ||
string, for which the [`jsonencode()` function](https://www.terraform.io/language/functions/jsonencode) | ||
can be used. | ||
* `description` - (Required) The description for this Claims Mapping Policy. | ||
* `display_name` - (Required) The friendly name for this Claims Mapping Policy. | ||
|
||
## Attributes Reference | ||
|
||
In addition to all arguments above, the following attributes are exported: | ||
|
||
* `id` - The ID of the Claims Mapping Policy. | ||
|
||
## Import | ||
|
||
Claims Mapping Policy can be imported using the `id`, e.g. | ||
|
||
```shell | ||
terraform import azuread_claims_mapping_policy.id 00000000-0000-0000-0000-000000000000 | ||
``` |
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
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
162 changes: 162 additions & 0 deletions
162
internal/services/serviceprincipals/service_principal_claims_mapping_policy.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,162 @@ | ||
package serviceprincipals | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"log" | ||
"net/http" | ||
|
||
"github.com/hashicorp/go-uuid" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
"github.com/hashicorp/terraform-provider-azuread/internal/clients" | ||
"github.com/hashicorp/terraform-provider-azuread/internal/tf" | ||
"github.com/manicminer/hamilton/msgraph" | ||
"github.com/manicminer/hamilton/odata" | ||
) | ||
|
||
func servicePrincipalClaimsMappingPolicy() *schema.Resource { | ||
return &schema.Resource{ | ||
CreateContext: servicePrincipalClaimsMappingPolicyResourceCreate, | ||
ReadContext: servicePrincipalClaimsMappingPolicyResourceRead, | ||
UpdateContext: servicePrincipalClaimsMappingPolicyResourceUpdate, | ||
DeleteContext: servicePrincipalClaimsMappingPolicyResourceDelete, | ||
|
||
Importer: tf.ValidateResourceIDPriorToImport(func(id string) error { | ||
if _, err := uuid.ParseUUID(id); err != nil { | ||
return fmt.Errorf("specified ID (%q) is not valid: %s", id, err) | ||
} | ||
return nil | ||
}), | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"id": { | ||
Description: "Unique identifier for this policy", | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
|
||
"definition": { | ||
Description: "A string collection containing a JSON string " + | ||
"that defines the rules and settings for this policy.", | ||
Type: schema.TypeList, | ||
Required: true, | ||
Elem: &schema.Schema{ | ||
Type: schema.TypeString, | ||
}, | ||
}, | ||
|
||
"display_name": { | ||
Description: "Display name for this policy", | ||
Type: schema.TypeString, | ||
Required: true, | ||
}, | ||
|
||
"description": { | ||
Description: "Description for this policy", | ||
Optional: true, | ||
Type: schema.TypeString, | ||
Required: false, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func servicePrincipalClaimsMappingPolicyResourceCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
client := meta.(*clients.Client).ServicePrincipals.ClaimsMappingPolicyClient | ||
var definitions []string | ||
for _, v := range d.Get("definition").([]interface{}) { | ||
definitions = append(definitions, v.(string)) | ||
} | ||
|
||
displayName := d.Get("display_name").(string) | ||
|
||
claimsMappingPolicy := msgraph.ClaimsMappingPolicy{ | ||
Definition: &definitions, | ||
DisplayName: &displayName, | ||
} | ||
policy, _, err := client.Create(ctx, claimsMappingPolicy) | ||
if err != nil { | ||
return tf.ErrorDiagF(err, "Could not create ClaimsMappingPolicy %q", displayName) | ||
} | ||
|
||
if policy != nil { | ||
d.SetId(*policy.ID) | ||
} | ||
|
||
return servicePrincipalClaimsMappingPolicyResourceRead(ctx, d, meta) | ||
} | ||
|
||
func servicePrincipalClaimsMappingPolicyResourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
client := meta.(*clients.Client).ServicePrincipals.ClaimsMappingPolicyClient | ||
objectId := d.Id() | ||
|
||
policy, status, err := client.Get(ctx, objectId, odata.Query{}) | ||
if err != nil { | ||
if status == http.StatusNotFound { | ||
log.Printf("[DEBUG] Claims Mapping Policy with Object ID %q was not found - removing from state!", objectId) | ||
d.SetId("") | ||
return nil | ||
} | ||
|
||
return tf.ErrorDiagF(err, "retrieving Claims Mapping Policy with object ID: %q", d.Id()) | ||
} | ||
|
||
tf.Set(d, "id", policy.ID) | ||
tf.Set(d, "definition", policy.Definition) | ||
tf.Set(d, "display_name", policy.DisplayName) | ||
|
||
return nil | ||
} | ||
|
||
func servicePrincipalClaimsMappingPolicyResourceUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
client := meta.(*clients.Client).ServicePrincipals.ClaimsMappingPolicyClient | ||
objectId := d.Id() | ||
|
||
var definitions []string | ||
for _, v := range d.Get("definition").([]interface{}) { | ||
definitions = append(definitions, v.(string)) | ||
} | ||
|
||
displayName := d.Get("display_name").(string) | ||
|
||
claimsMappingPolicy := msgraph.ClaimsMappingPolicy{ | ||
DirectoryObject: msgraph.DirectoryObject{ | ||
ID: &objectId, | ||
}, | ||
Definition: &definitions, | ||
DisplayName: &displayName, | ||
} | ||
_, err := client.Update(ctx, claimsMappingPolicy) | ||
if err != nil { | ||
return tf.ErrorDiagF(err, "Could not update ClaimsMappingPolicy %q", displayName) | ||
} | ||
|
||
return servicePrincipalClaimsMappingPolicyResourceRead(ctx, d, meta) | ||
} | ||
|
||
func servicePrincipalClaimsMappingPolicyResourceDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
client := meta.(*clients.Client).ServicePrincipals.ClaimsMappingPolicyClient | ||
objectId := d.Id() | ||
|
||
_, status, err := client.Get(ctx, objectId, odata.Query{}) | ||
if err != nil { | ||
if status == http.StatusNotFound { | ||
return tf.ErrorDiagPathF( | ||
fmt.Errorf( | ||
"Claims Mapping Policy was not found"), | ||
"id", "Retrieving Claims Mapping Policy with object ID %q", | ||
objectId, | ||
) | ||
} | ||
|
||
return tf.ErrorDiagPathF(err, "id", "Retrieving Claims Mapping Policy with object ID %q", objectId) | ||
} | ||
|
||
status, err = client.Delete(ctx, objectId) | ||
if err != nil { | ||
return tf.ErrorDiagF(err, "Deleting Claims Mapping Policy with object ID %q, received status %d", objectId, status) | ||
} | ||
|
||
return nil | ||
} |
85 changes: 85 additions & 0 deletions
85
internal/services/serviceprincipals/service_principal_claims_mapping_policy_test.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,85 @@ | ||
package serviceprincipals_test | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/http" | ||
"regexp" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform" | ||
"github.com/hashicorp/terraform-provider-azuread/internal/acceptance" | ||
"github.com/hashicorp/terraform-provider-azuread/internal/acceptance/check" | ||
"github.com/hashicorp/terraform-provider-azuread/internal/clients" | ||
"github.com/manicminer/hamilton/odata" | ||
) | ||
|
||
type ServicePrincipalClaimsMappingPolicy struct{} | ||
|
||
func TestClaimsMappingPolicy_basic(t *testing.T) { | ||
data := acceptance.BuildTestData(t, "azuread_claims_mapping_policy", "test") | ||
r := ServicePrincipalClaimsMappingPolicy{} | ||
updatedRegex, _ := regexp.Compile(`updated`) | ||
|
||
data.ResourceTest(t, r, []resource.TestStep{ | ||
{ | ||
Config: r.basicClaimsMappingPolicy(data), | ||
Check: resource.ComposeTestCheckFunc( | ||
check.That(data.ResourceName).ExistsInAzure(r), | ||
), | ||
}, | ||
{ | ||
Config: r.updateClaimsMappingPolicy(data), | ||
Check: resource.ComposeTestCheckFunc( | ||
check.That(data.ResourceName).ExistsInAzure(r), | ||
check.That(data.ResourceName).Key("display_name").MatchesRegex(updatedRegex), | ||
), | ||
}, | ||
}) | ||
} | ||
|
||
func (ServicePrincipalClaimsMappingPolicy) basicClaimsMappingPolicy(data acceptance.TestData) string { | ||
return fmt.Sprintf(` | ||
provider "azuread" {} | ||
resource "azuread_claims_mapping_policy" "test" { | ||
definition = [ | ||
"{\"ClaimsMappingPolicy\":{\"Version\":1,\"IncludeBasicClaimSet\":\"false\",\"ClaimsSchema\": [{\"Source\":\"user\",\"ID\":\"employeeid\",\"SamlClaimType\":\"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name\",\"JwtClaimType\":\"name\"},{\"Source\":\"company\",\"ID\":\"tenantcountry\",\"SamlClaimType\":\"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/country\",\"JwtClaimType\":\"country\"}]}}" | ||
] | ||
description = "%[1]s" | ||
display_name = "integration-%[1]s" | ||
} | ||
`, data.RandomString) | ||
} | ||
|
||
func (ServicePrincipalClaimsMappingPolicy) updateClaimsMappingPolicy(data acceptance.TestData) string { | ||
return fmt.Sprintf(` | ||
provider "azuread" {} | ||
resource "azuread_claims_mapping_policy" "test" { | ||
definition = [ | ||
"{\"ClaimsMappingPolicy\":{\"Version\":1,\"IncludeBasicClaimSet\":\"true\",\"ClaimsSchema\": [{\"Source\":\"user\",\"ID\":\"employeeid\",\"SamlClaimType\":\"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name\",\"JwtClaimType\":\"name\"},{\"Source\":\"company\",\"ID\":\"tenantcountry\",\"SamlClaimType\":\"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/country\",\"JwtClaimType\":\"country\"}]}}" | ||
] | ||
description = "%[1]s updated" | ||
display_name = "integration-%[1]s-updated" | ||
} | ||
`, data.RandomString) | ||
} | ||
|
||
func (r ServicePrincipalClaimsMappingPolicy) Exists(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) (*bool, error) { | ||
client := clients.ServicePrincipals.ClaimsMappingPolicyClient | ||
client.BaseClient.DisableRetries = true | ||
|
||
exists := false | ||
_, status, err := client.Get(ctx, state.ID, odata.Query{}) | ||
if err != nil { | ||
if status == http.StatusNotFound { | ||
return nil, fmt.Errorf("Claims mapping policy with object ID %q does not exist", state.ID) | ||
} | ||
return &exists, fmt.Errorf("failed to retrieve claims mapping policy with object ID %q: %+v", state.ID, err) | ||
} | ||
|
||
exists = true | ||
return &exists, nil | ||
} |