From 9b7a811f848ef307ffa399876ff203ae3774b106 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Tue, 26 Mar 2019 12:32:57 +0100 Subject: [PATCH 1/7] New Resource: `azurerm_api_management_authorization_server` --- azurerm/config.go | 33 +- azurerm/provider.go | 1 + ...arm_api_management_authorization_server.go | 484 ++++++++++++++++++ ...pi_management_authorization_server_test.go | 234 +++++++++ website/azurerm.erb | 4 + ...agement_authorization_server.html.markdown | 108 ++++ 6 files changed, 850 insertions(+), 14 deletions(-) create mode 100644 azurerm/resource_arm_api_management_authorization_server.go create mode 100644 azurerm/resource_arm_api_management_authorization_server_test.go create mode 100644 website/docs/r/api_management_authorization_server.html.markdown diff --git a/azurerm/config.go b/azurerm/config.go index b4c5ee445226..d77fd2135119 100644 --- a/azurerm/config.go +++ b/azurerm/config.go @@ -127,20 +127,21 @@ type ArmClient struct { redisPatchSchedulesClient redis.PatchSchedulesClient // API Management - apiManagementApiClient apimanagement.APIClient - apiManagementApiOperationsClient apimanagement.APIOperationClient - apiManagementCertificatesClient apimanagement.CertificateClient - apiManagementGroupClient apimanagement.GroupClient - apiManagementGroupUsersClient apimanagement.GroupUserClient - apiManagementLoggerClient apimanagement.LoggerClient - apiManagementOpenIdConnectClient apimanagement.OpenIDConnectProviderClient - apiManagementProductsClient apimanagement.ProductClient - apiManagementProductApisClient apimanagement.ProductAPIClient - apiManagementProductGroupsClient apimanagement.ProductGroupClient - apiManagementPropertyClient apimanagement.PropertyClient - apiManagementServiceClient apimanagement.ServiceClient - apiManagementSubscriptionsClient apimanagement.SubscriptionClient - apiManagementUsersClient apimanagement.UserClient + apiManagementApiClient apimanagement.APIClient + apiManagementApiOperationsClient apimanagement.APIOperationClient + apiManagementAuthorizationServersClient apimanagement.AuthorizationServerClient + apiManagementCertificatesClient apimanagement.CertificateClient + apiManagementGroupClient apimanagement.GroupClient + apiManagementGroupUsersClient apimanagement.GroupUserClient + apiManagementLoggerClient apimanagement.LoggerClient + apiManagementOpenIdConnectClient apimanagement.OpenIDConnectProviderClient + apiManagementProductsClient apimanagement.ProductClient + apiManagementProductApisClient apimanagement.ProductAPIClient + apiManagementProductGroupsClient apimanagement.ProductGroupClient + apiManagementPropertyClient apimanagement.PropertyClient + apiManagementServiceClient apimanagement.ServiceClient + apiManagementSubscriptionsClient apimanagement.SubscriptionClient + apiManagementUsersClient apimanagement.UserClient // Application Insights appInsightsClient appinsights.ComponentsClient @@ -509,6 +510,10 @@ func (c *ArmClient) registerApiManagementServiceClients(endpoint, subscriptionId c.configureClient(&apiOperationsClient.Client, auth) c.apiManagementApiOperationsClient = apiOperationsClient + authorizationServersClient := apimanagement.NewAuthorizationServerClientWithBaseURI(endpoint, subscriptionId) + c.configureClient(&authorizationServersClient.Client, auth) + c.apiManagementAuthorizationServersClient = authorizationServersClient + certificatesClient := apimanagement.NewCertificateClientWithBaseURI(endpoint, subscriptionId) c.configureClient(&certificatesClient.Client, auth) c.apiManagementCertificatesClient = certificatesClient diff --git a/azurerm/provider.go b/azurerm/provider.go index fdfd7e6dc4e4..d2cf7aa3f1d9 100644 --- a/azurerm/provider.go +++ b/azurerm/provider.go @@ -171,6 +171,7 @@ func Provider() terraform.ResourceProvider { "azurerm_api_management": resourceArmApiManagementService(), "azurerm_api_management_api": resourceArmApiManagementApi(), "azurerm_api_management_api_operation": resourceArmApiManagementApiOperation(), + "azurerm_api_management_authorization_server": resourceArmApiManagementAuthorizationServer(), "azurerm_api_management_certificate": resourceArmApiManagementCertificate(), "azurerm_api_management_group": resourceArmApiManagementGroup(), "azurerm_api_management_group_user": resourceArmApiManagementGroupUser(), diff --git a/azurerm/resource_arm_api_management_authorization_server.go b/azurerm/resource_arm_api_management_authorization_server.go new file mode 100644 index 000000000000..825d236670a4 --- /dev/null +++ b/azurerm/resource_arm_api_management_authorization_server.go @@ -0,0 +1,484 @@ +package azurerm + +import ( + "fmt" + "log" + + "github.com/Azure/azure-sdk-for-go/services/apimanagement/mgmt/2018-01-01/apimanagement" + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceArmApiManagementAuthorizationServer() *schema.Resource { + return &schema.Resource{ + Create: resourceArmApiManagementAuthorizationServerCreateUpdate, + Read: resourceArmApiManagementAuthorizationServerRead, + Update: resourceArmApiManagementAuthorizationServerCreateUpdate, + Delete: resourceArmApiManagementAuthorizationServerDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "name": azure.SchemaApiManagementChildName(), + + "api_management_name": azure.SchemaApiManagementName(), + + "resource_group_name": resourceGroupNameSchema(), + + "authorization_endpoint": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, + }, + + "client_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, + }, + + "client_registration_endpoint": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, + }, + + "display_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, + }, + + "grant_types": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(apimanagement.AuthorizationCode), + string(apimanagement.ClientCredentials), + string(apimanagement.Implicit), + string(apimanagement.ResourceOwnerPassword), + }, false), + }, + Set: schema.HashString, + }, + + // Optional + "authorization_methods": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(apimanagement.DELETE), + string(apimanagement.GET), + string(apimanagement.HEAD), + string(apimanagement.OPTIONS), + string(apimanagement.PATCH), + string(apimanagement.POST), + string(apimanagement.PUT), + string(apimanagement.TRACE), + }, false), + }, + Set: schema.HashString, + }, + + "bearer_token_sending_methods": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(apimanagement.AuthorizationHeader), + string(apimanagement.Query), + }, false), + }, + Set: schema.HashString, + }, + + "client_authentication_method": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(apimanagement.Basic), + string(apimanagement.Body), + }, false), + }, + Set: schema.HashString, + }, + + "client_secret": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + }, + + "default_scope": { + Type: schema.TypeString, + Optional: true, + }, + + "description": { + Type: schema.TypeString, + Optional: true, + }, + + "resource_owner_username": { + Type: schema.TypeString, + Optional: true, + }, + + "resource_owner_password": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + }, + + "support_state": { + Type: schema.TypeBool, + Optional: true, + }, + + "token_body_parameter": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, + }, + "value": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, + }, + }, + }, + }, + + "token_endpoint": { + Type: schema.TypeString, + Optional: true, + }, + }, + } +} + +func resourceArmApiManagementAuthorizationServerCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).apiManagementAuthorizationServersClient + ctx := meta.(*ArmClient).StopContext + + resourceGroup := d.Get("resource_group_name").(string) + serviceName := d.Get("api_management_name").(string) + name := d.Get("name").(string) + + if requireResourcesToBeImported && d.IsNewResource() { + existing, err := client.Get(ctx, resourceGroup, serviceName, name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("Error checking for presence of existing Authorization Server %q (API Management Service %q / Resource Group %q): %s", name, serviceName, resourceGroup, err) + } + } + + if existing.ID != nil && *existing.ID != "" { + return tf.ImportAsExistsError("azurerm_api_management_authorization_server", *existing.ID) + } + } + + authorizationEndpoint := d.Get("authorization_endpoint").(string) + clientId := d.Get("client_id").(string) + clientRegistrationEndpoint := d.Get("client_registration_endpoint").(string) + displayName := d.Get("display_name").(string) + grantTypesRaw := d.Get("grant_types").(*schema.Set).List() + grantTypes := expandApiManagementAuthorizationServerGrantTypes(grantTypesRaw) + + authorizationMethodsRaw := d.Get("authorization_methods").(*schema.Set).List() + authorizationMethods := expandApiManagementAuthorizationServerAuthorizationMethods(authorizationMethodsRaw) + bearerTokenSendingMethodsRaw := d.Get("bearer_token_sending_methods").(*schema.Set).List() + bearerTokenSendingMethods := expandApiManagementAuthorizationServerBearerTokenSendingMethods(bearerTokenSendingMethodsRaw) + clientAuthenticationMethodsRaw := d.Get("client_authentication_method").(*schema.Set).List() + clientAuthenticationMethods := expandApiManagementAuthorizationServerClientAuthenticationMethods(clientAuthenticationMethodsRaw) + clientSecret := d.Get("client_secret").(string) + defaultScope := d.Get("default_scope").(string) + description := d.Get("description").(string) + resourceOwnerPassword := d.Get("resource_owner_password").(string) + resourceOwnerUsername := d.Get("resource_owner_username").(string) + supportState := d.Get("support_state").(bool) + tokenBodyParametersRaw := d.Get("token_body_parameter").([]interface{}) + tokenBodyParameters := expandApiManagementAuthorizationServerTokenBodyParameters(tokenBodyParametersRaw) + tokenEndpoint := d.Get("token_endpoint").(string) + + params := apimanagement.AuthorizationServerContract{ + AuthorizationServerContractProperties: &apimanagement.AuthorizationServerContractProperties{ + // Required + AuthorizationEndpoint: utils.String(authorizationEndpoint), + ClientID: utils.String(clientId), + ClientRegistrationEndpoint: utils.String(clientRegistrationEndpoint), + DisplayName: utils.String(displayName), + GrantTypes: grantTypes, + + // Optional + AuthorizationMethods: authorizationMethods, + BearerTokenSendingMethods: bearerTokenSendingMethods, + ClientAuthenticationMethod: clientAuthenticationMethods, + ClientSecret: utils.String(clientSecret), + DefaultScope: utils.String(defaultScope), + Description: utils.String(description), + ResourceOwnerPassword: utils.String(resourceOwnerPassword), + ResourceOwnerUsername: utils.String(resourceOwnerUsername), + SupportState: utils.Bool(supportState), + TokenBodyParameters: tokenBodyParameters, + TokenEndpoint: utils.String(tokenEndpoint), + }, + } + + if _, err := client.CreateOrUpdate(ctx, resourceGroup, serviceName, name, params, ""); err != nil { + return fmt.Errorf("Error creating/updating Authorization Server %q (API Management Service %q / Resource Group %q): %+v", name, serviceName, resourceGroup, err) + } + + read, err := client.Get(ctx, resourceGroup, serviceName, name) + if err != nil { + return fmt.Errorf("Error retrieving Authorization Server %q (API Management Service %q / Resource Group %q): %+v", name, serviceName, resourceGroup, err) + } + + if read.ID == nil { + return fmt.Errorf("Cannot read ID for Authorization Server %q (API Management Service %q / Resource Group %q)", name, serviceName, resourceGroup) + } + + d.SetId(*read.ID) + return resourceArmApiManagementAuthorizationServerRead(d, meta) +} + +func resourceArmApiManagementAuthorizationServerRead(d *schema.ResourceData, meta interface{}) error { + ctx := meta.(*ArmClient).StopContext + client := meta.(*ArmClient).apiManagementAuthorizationServersClient + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + + resourceGroup := id.ResourceGroup + serviceName := id.Path["service"] + name := id.Path["authorizationServers"] + + resp, err := client.Get(ctx, resourceGroup, serviceName, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[DEBUG] Authorization Server %q (API Management Service %q / Resource Group %q) does not exist - removing from state!", name, serviceName, resourceGroup) + d.SetId("") + return nil + } + + return fmt.Errorf("Error retrieving Authorization Server %q (API Management Service %q / Resource Group %q): %+v", name, serviceName, resourceGroup, err) + } + + d.Set("api_management_name", serviceName) + d.Set("name", name) + d.Set("resource_group_name", resourceGroup) + + if props := resp.AuthorizationServerContractProperties; props != nil { + d.Set("authorization_endpoint", props.AuthorizationEndpoint) + d.Set("client_id", props.ClientID) + d.Set("client_registration_endpoint", props.ClientRegistrationEndpoint) + d.Set("client_secret", props.ClientSecret) + d.Set("default_scope", props.DefaultScope) + d.Set("description", props.Description) + d.Set("display_name", props.DisplayName) + d.Set("resource_owner_password", props.ResourceOwnerPassword) + d.Set("resource_owner_username", props.ResourceOwnerUsername) + d.Set("support_state", props.SupportState) + d.Set("token_endpoint", props.TokenEndpoint) + + if err := d.Set("authorization_methods", flattenApiManagementAuthorizationServerAuthorizationMethods(props.AuthorizationMethods)); err != nil { + return fmt.Errorf("Error flattening `authorization_methods`: %+v", err) + } + + if err := d.Set("bearer_token_sending_methods", flattenApiManagementAuthorizationServerBearerTokenSendingMethods(props.BearerTokenSendingMethods)); err != nil { + return fmt.Errorf("Error flattening `bearer_token_sending_methods`: %+v", err) + } + + if err := d.Set("client_authentication_method", flattenApiManagementAuthorizationServerClientAuthenticationMethods(props.ClientAuthenticationMethod)); err != nil { + return fmt.Errorf("Error flattening `client_authentication_method`: %+v", err) + } + + if err := d.Set("grant_types", flattenApiManagementAuthorizationServerGrantTypes(props.GrantTypes)); err != nil { + return fmt.Errorf("Error flattening `grant_types`: %+v", err) + } + + if err := d.Set("token_body_parameter", flattenApiManagementAuthorizationServerTokenBodyParameters(props.TokenBodyParameters)); err != nil { + return fmt.Errorf("Error flattening `token_body_parameter`: %+v", err) + } + } + + return nil +} + +func resourceArmApiManagementAuthorizationServerDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*ArmClient).apiManagementAuthorizationServersClient + ctx := meta.(*ArmClient).StopContext + + id, err := parseAzureResourceID(d.Id()) + if err != nil { + return err + } + + resourceGroup := id.ResourceGroup + serviceName := id.Path["service"] + name := id.Path["authorizationServers"] + + if resp, err := client.Delete(ctx, resourceGroup, serviceName, name, ""); err != nil { + if !utils.ResponseWasNotFound(resp) { + return fmt.Errorf("Error deleting Authorization Server %q (API Management Service %q / Resource Group %q): %s", name, serviceName, resourceGroup, err) + } + } + + return nil +} + +func expandApiManagementAuthorizationServerGrantTypes(input []interface{}) *[]apimanagement.GrantType { + outputs := make([]apimanagement.GrantType, 0) + + for _, v := range input { + grantType := apimanagement.GrantType(v.(string)) + outputs = append(outputs, grantType) + } + + return &outputs +} + +func flattenApiManagementAuthorizationServerGrantTypes(input *[]apimanagement.GrantType) []interface{} { + outputs := make([]interface{}, 0) + if input == nil { + return outputs + } + + for _, v := range *input { + outputs = append(outputs, string(v)) + } + + return outputs +} + +func expandApiManagementAuthorizationServerAuthorizationMethods(input []interface{}) *[]apimanagement.AuthorizationMethod { + outputs := make([]apimanagement.AuthorizationMethod, 0) + + for _, v := range input { + grantType := apimanagement.AuthorizationMethod(v.(string)) + outputs = append(outputs, grantType) + } + + return &outputs +} + +func flattenApiManagementAuthorizationServerAuthorizationMethods(input *[]apimanagement.AuthorizationMethod) []interface{} { + outputs := make([]interface{}, 0) + if input == nil { + return outputs + } + + for _, v := range *input { + outputs = append(outputs, string(v)) + } + + return outputs +} + +func expandApiManagementAuthorizationServerBearerTokenSendingMethods(input []interface{}) *[]apimanagement.BearerTokenSendingMethod { + outputs := make([]apimanagement.BearerTokenSendingMethod, 0) + + for _, v := range input { + grantType := apimanagement.BearerTokenSendingMethod(v.(string)) + outputs = append(outputs, grantType) + } + + return &outputs +} + +func flattenApiManagementAuthorizationServerBearerTokenSendingMethods(input *[]apimanagement.BearerTokenSendingMethod) []interface{} { + outputs := make([]interface{}, 0) + if input == nil { + return outputs + } + + for _, v := range *input { + outputs = append(outputs, string(v)) + } + + return outputs +} + +func expandApiManagementAuthorizationServerClientAuthenticationMethods(input []interface{}) *[]apimanagement.ClientAuthenticationMethod { + outputs := make([]apimanagement.ClientAuthenticationMethod, 0) + + for _, v := range input { + grantType := apimanagement.ClientAuthenticationMethod(v.(string)) + outputs = append(outputs, grantType) + } + + return &outputs +} + +func flattenApiManagementAuthorizationServerClientAuthenticationMethods(input *[]apimanagement.ClientAuthenticationMethod) []interface{} { + outputs := make([]interface{}, 0) + if input == nil { + return outputs + } + + for _, v := range *input { + outputs = append(outputs, string(v)) + } + + return outputs +} + +func expandApiManagementAuthorizationServerTokenBodyParameters(input []interface{}) *[]apimanagement.TokenBodyParameterContract { + outputs := make([]apimanagement.TokenBodyParameterContract, 0) + + for _, v := range input { + vs := v.(map[string]interface{}) + name := vs["name"].(string) + value := vs["value"].(string) + + output := apimanagement.TokenBodyParameterContract{ + Name: utils.String(name), + Value: utils.String(value), + } + outputs = append(outputs, output) + } + + return &outputs +} + +func flattenApiManagementAuthorizationServerTokenBodyParameters(input *[]apimanagement.TokenBodyParameterContract) []interface{} { + outputs := make([]interface{}, 0) + if input == nil { + return outputs + } + + for _, v := range *input { + output := make(map[string]interface{}) + + if v.Name != nil { + output["name"] = *v.Name + } + + if v.Value != nil { + output["value"] = *v.Value + } + + outputs = append(outputs, output) + } + + return outputs +} diff --git a/azurerm/resource_arm_api_management_authorization_server_test.go b/azurerm/resource_arm_api_management_authorization_server_test.go new file mode 100644 index 000000000000..7c4f9e668786 --- /dev/null +++ b/azurerm/resource_arm_api_management_authorization_server_test.go @@ -0,0 +1,234 @@ +package azurerm + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func TestAccAzureRMAPIManagementAuthorizationServer_basic(t *testing.T) { + resourceName := "azurerm_api_management_authorization_server.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAPIManagementAuthorizationServerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMAPIManagementAuthorizationServer_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAPIManagementAuthorizationServerExists(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMAPIManagementAuthorizationServer_requiresImport(t *testing.T) { + if !requireResourcesToBeImported { + t.Skip("Skipping since resources aren't required to be imported") + return + } + + resourceName := "azurerm_api_management_authorization_server.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAPIManagementAuthorizationServerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMAPIManagementAuthorizationServer_basic(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAPIManagementAuthorizationServerExists(resourceName), + ), + }, + { + Config: testAccAzureRMAPIManagementAuthorizationServer_requiresImport(ri, location), + ExpectError: testRequiresImportError("azurerm_api_management_authorization_server"), + }, + }, + }) +} + +func TestAccAzureRMAPIManagementAuthorizationServer_complete(t *testing.T) { + resourceName := "azurerm_api_management_authorization_server.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMAPIManagementAuthorizationServerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMAPIManagementAuthorizationServer_complete(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAPIManagementAuthorizationServerExists(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testCheckAzureRMAPIManagementAuthorizationServerDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*ArmClient).apiManagementAuthorizationServersClient + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_api_management_authorization_server" { + continue + } + + name := rs.Primary.Attributes["name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + serviceName := rs.Primary.Attributes["api_management_name"] + + ctx := testAccProvider.Meta().(*ArmClient).StopContext + resp, err := client.Get(ctx, resourceGroup, serviceName, name) + + if err != nil { + if !utils.ResponseWasNotFound(resp.Response) { + return err + } + } + + return nil + } + return nil +} + +func testCheckAzureRMAPIManagementAuthorizationServerExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + name := rs.Primary.Attributes["name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + serviceName := rs.Primary.Attributes["api_management_name"] + + client := testAccProvider.Meta().(*ArmClient).apiManagementAuthorizationServersClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + resp, err := client.Get(ctx, resourceGroup, serviceName, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: Authorization Server %q (API Management Service %q / Resource Group %q) does not exist", name, serviceName, resourceGroup) + } + return fmt.Errorf("Bad: Get on apiManagementAuthorizationServersClient: %+v", err) + } + + return nil + } +} + +func testAccAzureRMAPIManagementAuthorizationServer_basic(rInt int, location string) string { + template := testAccAzureRMAPIManagementAuthorizationServer_template(rInt, location) + return fmt.Sprintf(` +%s + +resource "azurerm_api_management_authorization_server" "test" { + name = "acctestauthsrv-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + api_management_name = "${azurerm_api_management.test.name}" + display_name = "Test Group" + authorization_endpoint = "https://azacctest.hashicorptest.com/client/authorize" + client_id = "42424242-4242-4242-4242-424242424242" + client_registration_endpoint = "https://azacctest.hashicorptest.com/client/register" + grant_types = [ + "authorizationCode", + ] +} +`, template, rInt) +} + +func testAccAzureRMAPIManagementAuthorizationServer_requiresImport(rInt int, location string) string { + template := testAccAzureRMAPIManagementAuthorizationServer_basic(rInt, location) + return fmt.Sprintf(` +%s + +resource "azurerm_api_management_authorization_server" "import" { + name = "${azurerm_api_management_authorization_server.test.name}" + resource_group_name = "${azurerm_api_management_authorization_server.test.resource_group_name}" + api_management_name = "${azurerm_api_management_authorization_server.test.api_management_name}" + display_name = "${azurerm_api_management_authorization_server.test.display_name}" + authorization_endpoint = "${azurerm_api_management_authorization_server.test.authorization_endpoint}" + client_id = "${azurerm_api_management_authorization_server.test.client_id}" + client_registration_endpoint = "${azurerm_api_management_authorization_server.test.client_registration_endpoint}" + grant_types = "${azurerm_api_management_authorization_server.test.grant_types}" +} +`, template) +} + +func testAccAzureRMAPIManagementAuthorizationServer_complete(rInt int, location string) string { + template := testAccAzureRMAPIManagementAuthorizationServer_template(rInt, location) + return fmt.Sprintf(` +%s + +resource "azurerm_api_management_authorization_server" "test" { + name = "acctestauthsrv-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + api_management_name = "${azurerm_api_management.test.name}" + display_name = "Test Group" + authorization_endpoint = "https://azacctest.hashicorptest.com/client/authorize" + client_id = "42424242-4242-4242-4242-424242424242" + client_registration_endpoint = "https://azacctest.hashicorptest.com/client/register" + grant_types = [ + "authorizationCode", + ] + + authorization_methods = [ + "GET", + "POST", + ] + bearer_token_sending_methods = [ + "authorizationHeader" + ] + client_secret = "n1n3-m0re-s3a5on5-m0r1y" + default_scope = "read write" + token_endpoint = "" + resource_owner_username = "rick" + resource_owner_password = "C-193P" + support_state = true +} +`, template, rInt) +} + +func testAccAzureRMAPIManagementAuthorizationServer_template(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_api_management" "test" { + name = "acctestAM-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + publisher_name = "pub1" + publisher_email = "pub1@email.com" + + sku { + name = "Developer" + capacity = 1 + } +} +`, rInt, location, rInt) +} diff --git a/website/azurerm.erb b/website/azurerm.erb index c1eef03cbbbd..b02e67b5ce54 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -346,6 +346,10 @@ azurerm_api_management_api_operation + > + azurerm_api_management_authorization_server + + > azurerm_api_management_certificate diff --git a/website/docs/r/api_management_authorization_server.html.markdown b/website/docs/r/api_management_authorization_server.html.markdown new file mode 100644 index 000000000000..a785e577ac49 --- /dev/null +++ b/website/docs/r/api_management_authorization_server.html.markdown @@ -0,0 +1,108 @@ +--- +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_api_management_authorization_server" +sidebar_current: "docs-azurerm-resource-api-management-authorization-server" +description: |- + Manages an Authorization Server within an API Management Service. +--- + +# azurerm_api_management_authorization_server + +Manages an Authorization Server within an API Management Service. + + +## Example Usage + +```hcl +data "azurerm_api_management_api" "example" { + name = "search-api" + api_management_name = "search-api-management" + resource_group_name = "search-service" + revision = "2" +} + +resource "azurerm_api_management_authorization_server" "example" { + name = "test-server" + api_management_name = "${data.azurerm_api_management.example.name}" + resource_group_name = "${data.azurerm_api_management.example.resource_group_name}" + display_name = "Test Server" + authorization_endpoint = "https://example.mydomain.com/client/authorize" + client_id = "42424242-4242-4242-4242-424242424242" + client_registration_endpoint = "https://example.mydomain.com/client/register" + grant_types = [ + "authorizationCode", + ] +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of this Authorization Server. Changing this forces a new resource to be created. + +* `api_management_name` - (Required) The name of the API Management Service in which this Authorization Server should be created. Changing this forces a new resource to be created. + +* `resource_group_name` - (Required) The name of the Resource Group in which the API Management Service exists. Changing this forces a new resource to be created. + +* `authorization_endpoint` - (Required) The OAUTH Authorization Endpoint. + +* `client_id` - (Required) The Client/App ID registered with this Authorization Server. + +* `client_registration_endpoint` - (Required) The URI of page where Client/App Registration is performed for this Authorization Server. + +* `display_name` - (Required) The user-friendly name of this Authorization Server. + +* `grant_types` - (Required) Form of Authorization Grants required when requesting an Access Token. Possible values are `authorizationCode`, `clientCredentials`, `implicit` and `resourceOwnerPassword`. + +--- + +* `authorization_methods` - (Optional) The HTTP Verbs supported by the Authorization Endpoint. Possible values are `DELETE`, `GET`, `HEAD`, `OPTIONS`, `PATCH`, `POST`, `PUT` and `TRACE`. + +-> **NOTE:** If set, `GET` must always be present. + +* `bearer_token_sending_methods` - (Optional) The mechanism by which Access Tokens are passed to the API. Possible values are `authorizationHeader` and `query`. + +* `client_authentication_method` - (Optional) The Authentication Methods supported by the Token endpoint of this Authorization Server.. Possible values are `Basic` and `Body`. + +* `client_secret` - (Optional) The Client/App Secret registered with this Authorization Server. + +* `default_scope` - (Optional) The Default Scope used when requesting an Access Token, specified as a string containing space-delimited values. + +* `description` - (Optional) A description of the Authorization Server, which may contain HTML formatting tags. + +* `resource_owner_password` - (Optional) The password associated with the Resource Owner. + +-> **NOTE:** This can only be specified when `grant_type` includes `resourceOwnerPassword`. + +* `resource_owner_username` - (Optional) The username associated with the Resource Owner. + +-> **NOTE:** This can only be specified when `grant_type` includes `resourceOwnerPassword`. + +* `support_state` - (Optional) Does this Authorization Server support State? If this is set to `true` the client may use the state parameter to raise protocol security. + +* `token_body_parameters` - (Optional) A `token_body_parameters` block as defined below. + +* `token_endpoint` - (Optional) The OAUTH Token Endpoint. + +--- + +A `token_body_parameter` block supports the following: + +* `name` - (Required) The Name of the Parameter. + +* `value` - (Required) The Value of the Parameter. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The ID of the API Management Authorization Server. + +## Import + +API Management Group Users can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_api_management_authorization_server.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.ApiManagement/service/service1/authorizationServers/server1 +``` From e590fc642c7cbfc3507d6cf7c59bece4470d6fd0 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Tue, 26 Mar 2019 13:43:19 +0100 Subject: [PATCH 2/7] Fixing the example for APIM Operations --- website/docs/r/api_management_api_operation.html.markdown | 2 +- .../docs/r/api_management_authorization_server.html.markdown | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/api_management_api_operation.html.markdown b/website/docs/r/api_management_api_operation.html.markdown index 3ca27336c687..5405959ce7cd 100644 --- a/website/docs/r/api_management_api_operation.html.markdown +++ b/website/docs/r/api_management_api_operation.html.markdown @@ -13,7 +13,7 @@ Manages an API Operation within an API Management Service. ## Example Usage ```hcl -data "azurerm_api_management_api" "test" { +data "azurerm_api_management_api" "example" { name = "search-api" api_management_name = "search-api-management" resource_group_name = "search-service" diff --git a/website/docs/r/api_management_authorization_server.html.markdown b/website/docs/r/api_management_authorization_server.html.markdown index a785e577ac49..adfebee48dc6 100644 --- a/website/docs/r/api_management_authorization_server.html.markdown +++ b/website/docs/r/api_management_authorization_server.html.markdown @@ -101,7 +101,7 @@ In addition to all arguments above, the following attributes are exported: ## Import -API Management Group Users can be imported using the `resource id`, e.g. +API Management Authorization Servers can be imported using the `resource id`, e.g. ```shell terraform import azurerm_api_management_authorization_server.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.ApiManagement/service/service1/authorizationServers/server1 From 8fbb9cfee937703d1133a88f9b784ea57d5e6878 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Tue, 26 Mar 2019 19:54:53 +0100 Subject: [PATCH 3/7] Conditionally setting the optional fields --- ...arm_api_management_authorization_server.go | 24 ++++++++++++------- ...pi_management_authorization_server_test.go | 15 ++++++------ 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/azurerm/resource_arm_api_management_authorization_server.go b/azurerm/resource_arm_api_management_authorization_server.go index 825d236670a4..31401d5edff4 100644 --- a/azurerm/resource_arm_api_management_authorization_server.go +++ b/azurerm/resource_arm_api_management_authorization_server.go @@ -202,10 +202,6 @@ func resourceArmApiManagementAuthorizationServerCreateUpdate(d *schema.ResourceD grantTypesRaw := d.Get("grant_types").(*schema.Set).List() grantTypes := expandApiManagementAuthorizationServerGrantTypes(grantTypesRaw) - authorizationMethodsRaw := d.Get("authorization_methods").(*schema.Set).List() - authorizationMethods := expandApiManagementAuthorizationServerAuthorizationMethods(authorizationMethodsRaw) - bearerTokenSendingMethodsRaw := d.Get("bearer_token_sending_methods").(*schema.Set).List() - bearerTokenSendingMethods := expandApiManagementAuthorizationServerBearerTokenSendingMethods(bearerTokenSendingMethodsRaw) clientAuthenticationMethodsRaw := d.Get("client_authentication_method").(*schema.Set).List() clientAuthenticationMethods := expandApiManagementAuthorizationServerClientAuthenticationMethods(clientAuthenticationMethodsRaw) clientSecret := d.Get("client_secret").(string) @@ -216,7 +212,6 @@ func resourceArmApiManagementAuthorizationServerCreateUpdate(d *schema.ResourceD supportState := d.Get("support_state").(bool) tokenBodyParametersRaw := d.Get("token_body_parameter").([]interface{}) tokenBodyParameters := expandApiManagementAuthorizationServerTokenBodyParameters(tokenBodyParametersRaw) - tokenEndpoint := d.Get("token_endpoint").(string) params := apimanagement.AuthorizationServerContract{ AuthorizationServerContractProperties: &apimanagement.AuthorizationServerContractProperties{ @@ -228,8 +223,6 @@ func resourceArmApiManagementAuthorizationServerCreateUpdate(d *schema.ResourceD GrantTypes: grantTypes, // Optional - AuthorizationMethods: authorizationMethods, - BearerTokenSendingMethods: bearerTokenSendingMethods, ClientAuthenticationMethod: clientAuthenticationMethods, ClientSecret: utils.String(clientSecret), DefaultScope: utils.String(defaultScope), @@ -238,10 +231,25 @@ func resourceArmApiManagementAuthorizationServerCreateUpdate(d *schema.ResourceD ResourceOwnerUsername: utils.String(resourceOwnerUsername), SupportState: utils.Bool(supportState), TokenBodyParameters: tokenBodyParameters, - TokenEndpoint: utils.String(tokenEndpoint), }, } + authorizationMethodsRaw := d.Get("authorization_methods").(*schema.Set).List() + if len(authorizationMethodsRaw) > 0 { + authorizationMethods := expandApiManagementAuthorizationServerAuthorizationMethods(authorizationMethodsRaw) + params.AuthorizationServerContractProperties.AuthorizationMethods = authorizationMethods + } + + bearerTokenSendingMethodsRaw := d.Get("bearer_token_sending_methods").(*schema.Set).List() + if len(bearerTokenSendingMethodsRaw) > 0 { + bearerTokenSendingMethods := expandApiManagementAuthorizationServerBearerTokenSendingMethods(bearerTokenSendingMethodsRaw) + params.AuthorizationServerContractProperties.BearerTokenSendingMethods = bearerTokenSendingMethods + } + + if tokenEndpoint := d.Get("token_endpoint").(string); tokenEndpoint != "" { + params.AuthorizationServerContractProperties.TokenEndpoint = utils.String(tokenEndpoint) + } + if _, err := client.CreateOrUpdate(ctx, resourceGroup, serviceName, name, params, ""); err != nil { return fmt.Errorf("Error creating/updating Authorization Server %q (API Management Service %q / Resource Group %q): %+v", name, serviceName, resourceGroup, err) } diff --git a/azurerm/resource_arm_api_management_authorization_server_test.go b/azurerm/resource_arm_api_management_authorization_server_test.go index 7c4f9e668786..8456e2822102 100644 --- a/azurerm/resource_arm_api_management_authorization_server_test.go +++ b/azurerm/resource_arm_api_management_authorization_server_test.go @@ -193,20 +193,19 @@ resource "azurerm_api_management_authorization_server" "test" { grant_types = [ "authorizationCode", ] - - authorization_methods = [ + authorization_methods = [ "GET", "POST", ] bearer_token_sending_methods = [ "authorizationHeader" ] - client_secret = "n1n3-m0re-s3a5on5-m0r1y" - default_scope = "read write" - token_endpoint = "" - resource_owner_username = "rick" - resource_owner_password = "C-193P" - support_state = true + client_secret = "n1n3-m0re-s3a5on5-m0r1y" + default_scope = "read write" + token_endpoint = "https://azacctest.hashicorptest.com/client/token" + resource_owner_username = "rick" + resource_owner_password = "C-193P" + support_state = true } `, template, rInt) } From 3ba8fd222c3f21c19aa5c1201f72c378253006e7 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Thu, 28 Mar 2019 23:19:01 +0100 Subject: [PATCH 4/7] switching to an implicit grant --- .../resource_arm_api_management_authorization_server_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/resource_arm_api_management_authorization_server_test.go b/azurerm/resource_arm_api_management_authorization_server_test.go index 8456e2822102..5b4b23a0080c 100644 --- a/azurerm/resource_arm_api_management_authorization_server_test.go +++ b/azurerm/resource_arm_api_management_authorization_server_test.go @@ -153,7 +153,7 @@ resource "azurerm_api_management_authorization_server" "test" { client_id = "42424242-4242-4242-4242-424242424242" client_registration_endpoint = "https://azacctest.hashicorptest.com/client/register" grant_types = [ - "authorizationCode", + "implicit", ] } `, template, rInt) From d5a0a476917b798c4bcabf16069697760fa3c25e Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 29 Mar 2019 07:25:05 +0100 Subject: [PATCH 5/7] r/api_management_auth_server: always sending the `authorization_methods` field --- ...resource_arm_api_management_authorization_server_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/azurerm/resource_arm_api_management_authorization_server_test.go b/azurerm/resource_arm_api_management_authorization_server_test.go index 5b4b23a0080c..169eef875fdc 100644 --- a/azurerm/resource_arm_api_management_authorization_server_test.go +++ b/azurerm/resource_arm_api_management_authorization_server_test.go @@ -155,6 +155,9 @@ resource "azurerm_api_management_authorization_server" "test" { grant_types = [ "implicit", ] + authorization_methods = [ + "GET", + ] } `, template, rInt) } @@ -173,6 +176,9 @@ resource "azurerm_api_management_authorization_server" "import" { client_id = "${azurerm_api_management_authorization_server.test.client_id}" client_registration_endpoint = "${azurerm_api_management_authorization_server.test.client_registration_endpoint}" grant_types = "${azurerm_api_management_authorization_server.test.grant_types}" + authorization_methods = [ + "GET", + ] } `, template) } From c03be344254f52301f8880cf6ec05f5f90f24e76 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 29 Mar 2019 07:58:33 +0100 Subject: [PATCH 6/7] r/api_management_auth_server: making auth_methods required --- ...arm_api_management_authorization_server.go | 38 +++++++++---------- ...agement_authorization_server.html.markdown | 12 +++--- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/azurerm/resource_arm_api_management_authorization_server.go b/azurerm/resource_arm_api_management_authorization_server.go index 31401d5edff4..0afe4e500a90 100644 --- a/azurerm/resource_arm_api_management_authorization_server.go +++ b/azurerm/resource_arm_api_management_authorization_server.go @@ -35,6 +35,25 @@ func resourceArmApiManagementAuthorizationServer() *schema.Resource { Required: true, ValidateFunc: validate.NoEmptyStrings, }, + + "authorization_methods": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(apimanagement.DELETE), + string(apimanagement.GET), + string(apimanagement.HEAD), + string(apimanagement.OPTIONS), + string(apimanagement.PATCH), + string(apimanagement.POST), + string(apimanagement.PUT), + string(apimanagement.TRACE), + }, false), + }, + Set: schema.HashString, + }, "client_id": { Type: schema.TypeString, @@ -70,25 +89,6 @@ func resourceArmApiManagementAuthorizationServer() *schema.Resource { }, // Optional - "authorization_methods": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validation.StringInSlice([]string{ - string(apimanagement.DELETE), - string(apimanagement.GET), - string(apimanagement.HEAD), - string(apimanagement.OPTIONS), - string(apimanagement.PATCH), - string(apimanagement.POST), - string(apimanagement.PUT), - string(apimanagement.TRACE), - }, false), - }, - Set: schema.HashString, - }, - "bearer_token_sending_methods": { Type: schema.TypeSet, Optional: true, diff --git a/website/docs/r/api_management_authorization_server.html.markdown b/website/docs/r/api_management_authorization_server.html.markdown index adfebee48dc6..1feafdd5d863 100644 --- a/website/docs/r/api_management_authorization_server.html.markdown +++ b/website/docs/r/api_management_authorization_server.html.markdown @@ -39,11 +39,11 @@ resource "azurerm_api_management_authorization_server" "example" { The following arguments are supported: -* `name` - (Required) The name of this Authorization Server. Changing this forces a new resource to be created. - * `api_management_name` - (Required) The name of the API Management Service in which this Authorization Server should be created. Changing this forces a new resource to be created. -* `resource_group_name` - (Required) The name of the Resource Group in which the API Management Service exists. Changing this forces a new resource to be created. +* `authorization_methods` - (Required) The HTTP Verbs supported by the Authorization Endpoint. Possible values are `DELETE`, `GET`, `HEAD`, `OPTIONS`, `PATCH`, `POST`, `PUT` and `TRACE`. + +-> **NOTE:** `GET` must always be present. * `authorization_endpoint` - (Required) The OAUTH Authorization Endpoint. @@ -55,11 +55,11 @@ The following arguments are supported: * `grant_types` - (Required) Form of Authorization Grants required when requesting an Access Token. Possible values are `authorizationCode`, `clientCredentials`, `implicit` and `resourceOwnerPassword`. ---- +* `name` - (Required) The name of this Authorization Server. Changing this forces a new resource to be created. -* `authorization_methods` - (Optional) The HTTP Verbs supported by the Authorization Endpoint. Possible values are `DELETE`, `GET`, `HEAD`, `OPTIONS`, `PATCH`, `POST`, `PUT` and `TRACE`. +* `resource_group_name` - (Required) The name of the Resource Group in which the API Management Service exists. Changing this forces a new resource to be created. --> **NOTE:** If set, `GET` must always be present. +--- * `bearer_token_sending_methods` - (Optional) The mechanism by which Access Tokens are passed to the API. Possible values are `authorizationHeader` and `query`. From 1d10d55dfc847401c7fe829fc8dc2b48cee932ca Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 29 Mar 2019 10:04:01 +0100 Subject: [PATCH 7/7] Fixing the linting --- azurerm/resource_arm_api_management_authorization_server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/resource_arm_api_management_authorization_server.go b/azurerm/resource_arm_api_management_authorization_server.go index 0afe4e500a90..cdf9ef23c1dd 100644 --- a/azurerm/resource_arm_api_management_authorization_server.go +++ b/azurerm/resource_arm_api_management_authorization_server.go @@ -35,7 +35,7 @@ func resourceArmApiManagementAuthorizationServer() *schema.Resource { Required: true, ValidateFunc: validate.NoEmptyStrings, }, - + "authorization_methods": { Type: schema.TypeSet, Required: true,