From bb574a7cf62c995a78501e1b35acd56144051f14 Mon Sep 17 00:00:00 2001 From: anotherRedbeard <34103220+anotherRedbeard@users.noreply.github.com> Date: Mon, 26 Aug 2024 11:07:19 -0500 Subject: [PATCH] feat: avm/res/apim-management/service/identity-provider Add contentLibrary property to the Identity Provider apim module (#3067) ## Description This pull request includes several updates to the API management service configuration files, focusing on adding a new `clientLibrary` parameter and simplifying the codebase by using optional chaining and nullish coalescing operators. ### Additions: * Added `clientLibrary` parameter to the identity provider configuration in `README.md`, `main.bicep`, and `main.json` files. This parameter specifies the client library to be used in the developer portal and is applicable to AAD and AAD B2C Identity Providers. [[1]](diffhunk://#diff-9ddb8330ed79263d6e746d65e3b3257b4505f97927a1629181a76f1c5b6a6613R340) [[2]](diffhunk://#diff-9ddb8330ed79263d6e746d65e3b3257b4505f97927a1629181a76f1c5b6a6613R583) [[3]](diffhunk://#diff-9ddb8330ed79263d6e746d65e3b3257b4505f97927a1629181a76f1c5b6a6613R898) [[4]](diffhunk://#diff-9ddb8330ed79263d6e746d65e3b3257b4505f97927a1629181a76f1c5b6a6613R1119) [[5]](diffhunk://#diff-43eea61a91298ae7bef3d481f3173899f538a8965ed5dd2f3dcc969831f9ac1fR41) [[6]](diffhunk://#diff-43eea61a91298ae7bef3d481f3173899f538a8965ed5dd2f3dcc969831f9ac1fR95-R110) [[7]](diffhunk://#diff-a4a02b7176d3a8c138078d850f9eb87c6ff174240e076fad16f2828e81d95984R17-R24) [[8]](diffhunk://#diff-a4a02b7176d3a8c138078d850f9eb87c6ff174240e076fad16f2828e81d95984R78) [[9]](diffhunk://#diff-16e9f7f16068d75fc42585c3dff1869a905e7ae9623294ef13e0012ff8e8cfe4R42-R53) [[10]](diffhunk://#diff-16e9f7f16068d75fc42585c3dff1869a905e7ae9623294ef13e0012ff8e8cfe4R136) ### Code Simplification: * Replaced `contains` checks with optional chaining and nullish coalescing operators in `main.bicep` and `main.json` files to simplify the code and improve readability. [[1]](diffhunk://#diff-8f2edf3d1f48cf6c680a1183f0e64d26c87c0ceb60ca907ed141beb343d1c762L145-R145) [[2]](diffhunk://#diff-2ca925a05c195f083f978183605a2057d590ad2b8bfe530789ee04df61e7af40L273-R275) [[3]](diffhunk://#diff-0f11bdd53cbb4764551480ccb25116f6805372f2ad26f15c7d01f0eb8624fabaL302-R302) [[4]](diffhunk://#diff-0f11bdd53cbb4764551480ccb25116f6805372f2ad26f15c7d01f0eb8624fabaL314-R327) [[5]](diffhunk://#diff-0f11bdd53cbb4764551480ccb25116f6805372f2ad26f15c7d01f0eb8624fabaL416-R406) [[6]](diffhunk://#diff-0f11bdd53cbb4764551480ccb25116f6805372f2ad26f15c7d01f0eb8624fabaL440-R421) [[7]](diffhunk://#diff-0f11bdd53cbb4764551480ccb25116f6805372f2ad26f15c7d01f0eb8624fabaL458-R439) [[8]](diffhunk://#diff-0f11bdd53cbb4764551480ccb25116f6805372f2ad26f15c7d01f0eb8624fabaL484-R461) [[9]](diffhunk://#diff-0f11bdd53cbb4764551480ccb25116f6805372f2ad26f15c7d01f0eb8624fabaL494-R479) [[10]](diffhunk://#diff-af393a2ffcf4cca471b3ed98bb92055747cf64a3a95f05fd5c7ea5597468a8d8L1059-R1061) [[11]](diffhunk://#diff-af393a2ffcf4cca471b3ed98bb92055747cf64a3a95f05fd5c7ea5597468a8d8L1435-R1439) ### Metadata Updates: * Updated `_generator` metadata in various `main.json` files to reflect the new template hash values. [[1]](diffhunk://#diff-2ca925a05c195f083f978183605a2057d590ad2b8bfe530789ee04df61e7af40L9-R9) [[2]](diffhunk://#diff-16e9f7f16068d75fc42585c3dff1869a905e7ae9623294ef13e0012ff8e8cfe4L8-R8) [[3]](diffhunk://#diff-af393a2ffcf4cca471b3ed98bb92055747cf64a3a95f05fd5c7ea5597468a8d8L9-R9) [[4]](diffhunk://#diff-af393a2ffcf4cca471b3ed98bb92055747cf64a3a95f05fd5c7ea5597468a8d8L795-R795) These changes aim to enhance the maintainability and functionality of the API management service configuration. ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.api-management.service](https://github.com/anotherRedbeard/bicep-registry-modules/actions/workflows/avm.res.api-management.service.yml/badge.svg)](https://github.com/anotherRedbeard/bicep-registry-modules/actions/workflows/avm.res.api-management.service.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [x ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [x ] Update to documentation ## Checklist - [x ] I'm sure there are no other open Pull Requests for the same update/change - [ x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x ] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: anotherRedbeard Co-authored-by: anotherRedbeard Co-authored-by: Tony Box --- avm/res/api-management/service/README.md | 4 + avm/res/api-management/service/api/main.bicep | 2 +- avm/res/api-management/service/api/main.json | 6 +- .../service/identity-provider/README.md | 15 ++ .../service/identity-provider/main.bicep | 8 + .../service/identity-provider/main.json | 32 ++- avm/res/api-management/service/main.bicep | 103 ++++----- avm/res/api-management/service/main.json | 199 +++++++++++++----- .../service/tests/e2e/max/main.test.bicep | 1 + .../tests/e2e/waf-aligned/main.test.bicep | 1 + avm/res/api-management/service/version.json | 2 +- 11 files changed, 254 insertions(+), 119 deletions(-) diff --git a/avm/res/api-management/service/README.md b/avm/res/api-management/service/README.md index c2a78b25c3..1a74dba710 100644 --- a/avm/res/api-management/service/README.md +++ b/avm/res/api-management/service/README.md @@ -337,6 +337,7 @@ module service 'br/public:avm/res/api-management/service:' = { ] authority: '' clientId: 'apimClientid' + clientLibrary: 'MSAL-2' clientSecret: 'apimSlientSecret' name: 'aad' signinTenant: 'mytenant.onmicrosoft.com' @@ -579,6 +580,7 @@ module service 'br/public:avm/res/api-management/service:' = { ], "authority": "", "clientId": "apimClientid", + "clientLibrary": "MSAL-2", "clientSecret": "apimSlientSecret", "name": "aad", "signinTenant": "mytenant.onmicrosoft.com" @@ -893,6 +895,7 @@ module service 'br/public:avm/res/api-management/service:' = { ] authority: '' clientId: 'apimClientid' + clientLibrary: 'MSAL-2' clientSecret: '' name: 'aad' signinTenant: 'mytenant.onmicrosoft.com' @@ -1113,6 +1116,7 @@ module service 'br/public:avm/res/api-management/service:' = { ], "authority": "", "clientId": "apimClientid", + "clientLibrary": "MSAL-2", "clientSecret": "", "name": "aad", "signinTenant": "mytenant.onmicrosoft.com" diff --git a/avm/res/api-management/service/api/main.bicep b/avm/res/api-management/service/api/main.bicep index f3cf6a2b3c..6b83aae577 100644 --- a/avm/res/api-management/service/api/main.bicep +++ b/avm/res/api-management/service/api/main.bicep @@ -142,7 +142,7 @@ module policy 'policy/main.bicep' = [ params: { apiManagementServiceName: apiManagementServiceName apiName: api.name - format: contains(policy, 'format') ? policy.format : 'xml' + format: policy.?format ?? 'xml' value: policy.value } } diff --git a/avm/res/api-management/service/api/main.json b/avm/res/api-management/service/api/main.json index e94c21cc8f..970b83350d 100644 --- a/avm/res/api-management/service/api/main.json +++ b/avm/res/api-management/service/api/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "13121653397859804060" + "templateHash": "17160750790361326516" }, "name": "API Management Service APIs", "description": "This module deploys an API Management Service API.", @@ -270,7 +270,9 @@ "apiName": { "value": "[parameters('name')]" }, - "format": "[if(contains(coalesce(parameters('policies'), createArray())[copyIndex()], 'format'), createObject('value', coalesce(parameters('policies'), createArray())[copyIndex()].format), createObject('value', 'xml'))]", + "format": { + "value": "[coalesce(tryGet(coalesce(parameters('policies'), createArray())[copyIndex()], 'format'), 'xml')]" + }, "value": { "value": "[coalesce(parameters('policies'), createArray())[copyIndex()].value]" } diff --git a/avm/res/api-management/service/identity-provider/README.md b/avm/res/api-management/service/identity-provider/README.md index efbbbae18b..eb33eef785 100644 --- a/avm/res/api-management/service/identity-provider/README.md +++ b/avm/res/api-management/service/identity-provider/README.md @@ -38,6 +38,7 @@ This module deploys an API Management Service Identity Provider. | :-- | :-- | :-- | | [`allowedTenants`](#parameter-allowedtenants) | array | List of Allowed Tenants when configuring Azure Active Directory login. - string. | | [`authority`](#parameter-authority) | string | OpenID Connect discovery endpoint hostname for AAD or AAD B2C. | +| [`clientLibrary`](#parameter-clientlibrary) | string | The client library to be used in the developer portal. Only applies to AAD and AAD B2C Identity Provider. | | [`passwordResetPolicyName`](#parameter-passwordresetpolicyname) | string | Password Reset Policy Name. Only applies to AAD B2C Identity Provider. | | [`profileEditingPolicyName`](#parameter-profileeditingpolicyname) | string | Profile Editing Policy Name. Only applies to AAD B2C Identity Provider. | | [`signInPolicyName`](#parameter-signinpolicyname) | string | Signin Policy Name. Only applies to AAD B2C Identity Provider. | @@ -91,6 +92,20 @@ OpenID Connect discovery endpoint hostname for AAD or AAD B2C. - Type: string - Default: `''` +### Parameter: `clientLibrary` + +The client library to be used in the developer portal. Only applies to AAD and AAD B2C Identity Provider. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'ADAL' + 'MSAL-2' + ] + ``` + ### Parameter: `passwordResetPolicyName` Password Reset Policy Name. Only applies to AAD B2C Identity Provider. diff --git a/avm/res/api-management/service/identity-provider/main.bicep b/avm/res/api-management/service/identity-provider/main.bicep index 0c6ec2ebcb..8306fe54c9 100644 --- a/avm/res/api-management/service/identity-provider/main.bicep +++ b/avm/res/api-management/service/identity-provider/main.bicep @@ -14,6 +14,13 @@ param authority string = '' @description('Conditional. Client ID of the Application in the external Identity Provider. Required if identity provider is used.') param clientId string = '' +@description('Optional. The client library to be used in the developer portal. Only applies to AAD and AAD B2C Identity Provider.') +@allowed([ + 'ADAL' + 'MSAL-2' +]) +param clientLibrary string? + @description('Conditional. Client secret of the Application in external Identity Provider, used to authenticate login request. Required if identity provider is used.') @secure() param clientSecret string = '' @@ -67,6 +74,7 @@ resource identityProvider 'Microsoft.ApiManagement/service/identityProviders@202 profileEditingPolicyName: isAadB2C ? profileEditingPolicyName : null passwordResetPolicyName: isAadB2C ? passwordResetPolicyName : null clientId: clientId + clientLibrary: clientLibrary clientSecret: clientSecret } } diff --git a/avm/res/api-management/service/identity-provider/main.json b/avm/res/api-management/service/identity-provider/main.json index a6563d4a31..f9e6cbe086 100644 --- a/avm/res/api-management/service/identity-provider/main.json +++ b/avm/res/api-management/service/identity-provider/main.json @@ -1,11 +1,12 @@ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "13129392765749462635" + "templateHash": "12757169124799431378" }, "name": "API Management Service Identity Providers", "description": "This module deploys an API Management Service Identity Provider.", @@ -39,6 +40,17 @@ "description": "Conditional. Client ID of the Application in the external Identity Provider. Required if identity provider is used." } }, + "clientLibrary": { + "type": "string", + "nullable": true, + "allowedValues": [ + "ADAL", + "MSAL-2" + ], + "metadata": { + "description": "Optional. The client library to be used in the developer portal. Only applies to AAD and AAD B2C Identity Provider." + } + }, "clientSecret": { "type": "securestring", "defaultValue": "", @@ -106,8 +118,14 @@ "variables": { "isAadB2C": "[equals(parameters('type'), 'aadB2C')]" }, - "resources": [ - { + "resources": { + "service": { + "existing": true, + "type": "Microsoft.ApiManagement/service", + "apiVersion": "2023-05-01-preview", + "name": "[parameters('apiManagementServiceName')]" + }, + "identityProvider": { "type": "Microsoft.ApiManagement/service/identityProviders", "apiVersion": "2022-08-01", "name": "[format('{0}/{1}', parameters('apiManagementServiceName'), parameters('name'))]", @@ -121,10 +139,14 @@ "profileEditingPolicyName": "[if(variables('isAadB2C'), parameters('profileEditingPolicyName'), null())]", "passwordResetPolicyName": "[if(variables('isAadB2C'), parameters('passwordResetPolicyName'), null())]", "clientId": "[parameters('clientId')]", + "clientLibrary": "[parameters('clientLibrary')]", "clientSecret": "[parameters('clientSecret')]" - } + }, + "dependsOn": [ + "service" + ] } - ], + }, "outputs": { "resourceId": { "type": "string", diff --git a/avm/res/api-management/service/main.bicep b/avm/res/api-management/service/main.bicep index f78d4be2a0..2ee1c95c75 100644 --- a/avm/res/api-management/service/main.bicep +++ b/avm/res/api-management/service/main.bicep @@ -299,7 +299,7 @@ module service_apiVersionSets 'api-version-set/main.bicep' = [ params: { apiManagementServiceName: service.name name: apiVersionSet.name - properties: contains(apiVersionSet, 'properties') ? apiVersionSet.properties : {} + properties: apiVersionSet.?properties ?? {} } } ] @@ -311,40 +311,20 @@ module service_authorizationServers 'authorization-server/main.bicep' = [ apiManagementServiceName: service.name name: authorizationServer.name authorizationEndpoint: authorizationServer.authorizationEndpoint - authorizationMethods: contains(authorizationServer, 'authorizationMethods') - ? authorizationServer.authorizationMethods - : [ - 'GET' - ] - bearerTokenSendingMethods: contains(authorizationServer, 'bearerTokenSendingMethods') - ? authorizationServer.bearerTokenSendingMethods - : [ - 'authorizationHeader' - ] - clientAuthenticationMethod: contains(authorizationServer, 'clientAuthenticationMethod') - ? authorizationServer.clientAuthenticationMethod - : [ - 'Basic' - ] + authorizationMethods: authorizationServer.?authorizationMethods ?? ['GET'] + bearerTokenSendingMethods: authorizationServer.?bearerTokenSendingMethods ?? ['authorizationHeader'] + clientAuthenticationMethod: authorizationServer.?clientAuthenticationMethod ?? ['Basic'] clientId: authorizationServer.clientId clientSecret: authorizationServer.clientSecret - clientRegistrationEndpoint: contains(authorizationServer, 'clientRegistrationEndpoint') - ? authorizationServer.clientRegistrationEndpoint - : '' - defaultScope: contains(authorizationServer, 'defaultScope') ? authorizationServer.defaultScope : '' + clientRegistrationEndpoint: authorizationServer.?clientRegistrationEndpoint ?? '' + defaultScope: authorizationServer.?defaultScope ?? '' grantTypes: authorizationServer.grantTypes - resourceOwnerPassword: contains(authorizationServer, 'resourceOwnerPassword') - ? authorizationServer.resourceOwnerPassword - : '' - resourceOwnerUsername: contains(authorizationServer, 'resourceOwnerUsername') - ? authorizationServer.resourceOwnerUsername - : '' - serverDescription: contains(authorizationServer, 'serverDescription') ? authorizationServer.serverDescription : '' - supportState: contains(authorizationServer, 'supportState') ? authorizationServer.supportState : false - tokenBodyParameters: contains(authorizationServer, 'tokenBodyParameters') - ? authorizationServer.tokenBodyParameters - : [] - tokenEndpoint: contains(authorizationServer, 'tokenEndpoint') ? authorizationServer.tokenEndpoint : '' + resourceOwnerPassword: authorizationServer.?resourceOwnerPassword ?? '' + resourceOwnerUsername: authorizationServer.?resourceOwnerUsername ?? '' + serverDescription: authorizationServer.?serverDescription ?? '' + supportState: authorizationServer.?supportState ?? false + tokenBodyParameters: authorizationServer.?tokenBodyParameters ?? [] + tokenEndpoint: authorizationServer.?tokenEndpoint ?? '' } } ] @@ -413,20 +393,17 @@ module service_identityProviders 'identity-provider/main.bicep' = [ params: { apiManagementServiceName: service.name name: identityProvider.name - allowedTenants: contains(identityProvider, 'allowedTenants') ? identityProvider.allowedTenants : [] - authority: contains(identityProvider, 'authority') ? identityProvider.authority : '' - clientId: contains(identityProvider, 'clientId') ? identityProvider.clientId : '' - clientSecret: contains(identityProvider, 'clientSecret') ? identityProvider.clientSecret : '' - passwordResetPolicyName: contains(identityProvider, 'passwordResetPolicyName') - ? identityProvider.passwordResetPolicyName - : '' - profileEditingPolicyName: contains(identityProvider, 'profileEditingPolicyName') - ? identityProvider.profileEditingPolicyName - : '' - signInPolicyName: contains(identityProvider, 'signInPolicyName') ? identityProvider.signInPolicyName : '' - signInTenant: contains(identityProvider, 'signInTenant') ? identityProvider.signInTenant : '' - signUpPolicyName: contains(identityProvider, 'signUpPolicyName') ? identityProvider.signUpPolicyName : '' - type: contains(identityProvider, 'type') ? identityProvider.type : 'aad' + allowedTenants: identityProvider.?allowedTenants ?? [] + authority: identityProvider.?authority ?? '' + clientId: identityProvider.?clientId ?? '' + clientLibrary: identityProvider.?clientLibrary ?? '' + clientSecret: identityProvider.?clientSecret ?? '' + passwordResetPolicyName: identityProvider.?passwordResetPolicyName ?? '' + profileEditingPolicyName: identityProvider.?profileEditingPolicyName ?? '' + signInPolicyName: identityProvider.?signInPolicyName ?? '' + signInTenant: identityProvider.?signInTenant ?? '' + signUpPolicyName: identityProvider.?signUpPolicyName ?? '' + type: identityProvider.?type ?? 'aad' } } ] @@ -437,11 +414,11 @@ module service_loggers 'loggers/main.bicep' = [ params: { name: logger.name apiManagementServiceName: service.name - credentials: contains(logger, 'credentials') ? logger.credentials : {} - isBuffered: contains(logger, 'isBuffered') ? logger.isBuffered : true - loggerDescription: contains(logger, 'loggerDescription') ? logger.loggerDescription : '' - loggerType: contains(logger, 'loggerType') ? logger.loggerType : 'azureMonitor' - targetResourceId: contains(logger, 'targetResourceId') ? logger.targetResourceId : '' + credentials: logger.?credentials ?? {} + isBuffered: logger.?isBuffered ?? true + loggerDescription: logger.?loggerDescription ?? '' + loggerType: logger.?loggerType ?? 'azureMonitor' + targetResourceId: logger.?targetResourceId ?? '' } dependsOn: [ service_namedValues @@ -455,11 +432,11 @@ module service_namedValues 'named-value/main.bicep' = [ params: { apiManagementServiceName: service.name displayName: namedValue.displayName - keyVault: contains(namedValue, 'keyVault') ? namedValue.keyVault : {} + keyVault: namedValue.?keyVault ?? {} name: namedValue.name tags: namedValue.?tags // Note: these are not resource tags - secret: contains(namedValue, 'secret') ? namedValue.secret : false - value: contains(namedValue, 'value') ? namedValue.value : newGuidValue + secret: namedValue.?secret ?? false + value: namedValue.?value ?? newGuidValue } } ] @@ -481,7 +458,7 @@ module service_policies 'policy/main.bicep' = [ params: { apiManagementServiceName: service.name value: policy.value - format: contains(policy, 'format') ? policy.format : 'xml' + format: policy.?format ?? 'xml' } } ] @@ -491,15 +468,15 @@ module service_products 'product/main.bicep' = [ name: '${uniqueString(deployment().name, location)}-Apim-Product-${index}' params: { apiManagementServiceName: service.name - apis: contains(product, 'apis') ? product.apis : [] - approvalRequired: contains(product, 'approvalRequired') ? product.approvalRequired : false - groups: contains(product, 'groups') ? product.groups : [] + apis: product.?apis ?? [] + approvalRequired: product.?approvalRequired ?? false + groups: product.?groups ?? [] name: product.name - description: contains(product, 'description') ? product.description : '' - state: contains(product, 'state') ? product.state : 'published' - subscriptionRequired: contains(product, 'subscriptionRequired') ? product.subscriptionRequired : false - subscriptionsLimit: contains(product, 'subscriptionsLimit') ? product.subscriptionsLimit : 1 - terms: contains(product, 'terms') ? product.terms : '' + description: product.?description ?? '' + state: product.?state ?? 'published' + subscriptionRequired: product.?subscriptionRequired ?? false + subscriptionsLimit: product.?subscriptionsLimit ?? 1 + terms: product.?terms ?? '' } dependsOn: [ service_apis diff --git a/avm/res/api-management/service/main.json b/avm/res/api-management/service/main.json index bf4c30828b..fdb9002616 100644 --- a/avm/res/api-management/service/main.json +++ b/avm/res/api-management/service/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "17512486952547559585" + "templateHash": "17385483787660298242" }, "name": "API Management Services", "description": "This module deploys an API Management Service. The default deployment is set to use a Premium SKU to align with Microsoft WAF-aligned best practices. In most cases, non-prod deployments should use a lower-tier SKU.", @@ -792,7 +792,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "13121653397859804060" + "templateHash": "17160750790361326516" }, "name": "API Management Service APIs", "description": "This module deploys an API Management Service API.", @@ -1056,7 +1056,9 @@ "apiName": { "value": "[parameters('name')]" }, - "format": "[if(contains(coalesce(parameters('policies'), createArray())[copyIndex()], 'format'), createObject('value', coalesce(parameters('policies'), createArray())[copyIndex()].format), createObject('value', 'xml'))]", + "format": { + "value": "[coalesce(tryGet(coalesce(parameters('policies'), createArray())[copyIndex()], 'format'), 'xml')]" + }, "value": { "value": "[coalesce(parameters('policies'), createArray())[copyIndex()].value]" } @@ -1432,7 +1434,9 @@ "name": { "value": "[parameters('apiVersionSets')[copyIndex()].name]" }, - "properties": "[if(contains(parameters('apiVersionSets')[copyIndex()], 'properties'), createObject('value', parameters('apiVersionSets')[copyIndex()].properties), createObject('value', createObject()))]" + "properties": { + "value": "[coalesce(tryGet(parameters('apiVersionSets')[copyIndex()], 'properties'), createObject())]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -1529,26 +1533,48 @@ "authorizationEndpoint": { "value": "[variables('authorizationServerList')[copyIndex()].authorizationEndpoint]" }, - "authorizationMethods": "[if(contains(variables('authorizationServerList')[copyIndex()], 'authorizationMethods'), createObject('value', variables('authorizationServerList')[copyIndex()].authorizationMethods), createObject('value', createArray('GET')))]", - "bearerTokenSendingMethods": "[if(contains(variables('authorizationServerList')[copyIndex()], 'bearerTokenSendingMethods'), createObject('value', variables('authorizationServerList')[copyIndex()].bearerTokenSendingMethods), createObject('value', createArray('authorizationHeader')))]", - "clientAuthenticationMethod": "[if(contains(variables('authorizationServerList')[copyIndex()], 'clientAuthenticationMethod'), createObject('value', variables('authorizationServerList')[copyIndex()].clientAuthenticationMethod), createObject('value', createArray('Basic')))]", + "authorizationMethods": { + "value": "[coalesce(tryGet(variables('authorizationServerList')[copyIndex()], 'authorizationMethods'), createArray('GET'))]" + }, + "bearerTokenSendingMethods": { + "value": "[coalesce(tryGet(variables('authorizationServerList')[copyIndex()], 'bearerTokenSendingMethods'), createArray('authorizationHeader'))]" + }, + "clientAuthenticationMethod": { + "value": "[coalesce(tryGet(variables('authorizationServerList')[copyIndex()], 'clientAuthenticationMethod'), createArray('Basic'))]" + }, "clientId": { "value": "[variables('authorizationServerList')[copyIndex()].clientId]" }, "clientSecret": { "value": "[variables('authorizationServerList')[copyIndex()].clientSecret]" }, - "clientRegistrationEndpoint": "[if(contains(variables('authorizationServerList')[copyIndex()], 'clientRegistrationEndpoint'), createObject('value', variables('authorizationServerList')[copyIndex()].clientRegistrationEndpoint), createObject('value', ''))]", - "defaultScope": "[if(contains(variables('authorizationServerList')[copyIndex()], 'defaultScope'), createObject('value', variables('authorizationServerList')[copyIndex()].defaultScope), createObject('value', ''))]", + "clientRegistrationEndpoint": { + "value": "[coalesce(tryGet(variables('authorizationServerList')[copyIndex()], 'clientRegistrationEndpoint'), '')]" + }, + "defaultScope": { + "value": "[coalesce(tryGet(variables('authorizationServerList')[copyIndex()], 'defaultScope'), '')]" + }, "grantTypes": { "value": "[variables('authorizationServerList')[copyIndex()].grantTypes]" }, - "resourceOwnerPassword": "[if(contains(variables('authorizationServerList')[copyIndex()], 'resourceOwnerPassword'), createObject('value', variables('authorizationServerList')[copyIndex()].resourceOwnerPassword), createObject('value', ''))]", - "resourceOwnerUsername": "[if(contains(variables('authorizationServerList')[copyIndex()], 'resourceOwnerUsername'), createObject('value', variables('authorizationServerList')[copyIndex()].resourceOwnerUsername), createObject('value', ''))]", - "serverDescription": "[if(contains(variables('authorizationServerList')[copyIndex()], 'serverDescription'), createObject('value', variables('authorizationServerList')[copyIndex()].serverDescription), createObject('value', ''))]", - "supportState": "[if(contains(variables('authorizationServerList')[copyIndex()], 'supportState'), createObject('value', variables('authorizationServerList')[copyIndex()].supportState), createObject('value', false()))]", - "tokenBodyParameters": "[if(contains(variables('authorizationServerList')[copyIndex()], 'tokenBodyParameters'), createObject('value', variables('authorizationServerList')[copyIndex()].tokenBodyParameters), createObject('value', createArray()))]", - "tokenEndpoint": "[if(contains(variables('authorizationServerList')[copyIndex()], 'tokenEndpoint'), createObject('value', variables('authorizationServerList')[copyIndex()].tokenEndpoint), createObject('value', ''))]" + "resourceOwnerPassword": { + "value": "[coalesce(tryGet(variables('authorizationServerList')[copyIndex()], 'resourceOwnerPassword'), '')]" + }, + "resourceOwnerUsername": { + "value": "[coalesce(tryGet(variables('authorizationServerList')[copyIndex()], 'resourceOwnerUsername'), '')]" + }, + "serverDescription": { + "value": "[coalesce(tryGet(variables('authorizationServerList')[copyIndex()], 'serverDescription'), '')]" + }, + "supportState": { + "value": "[coalesce(tryGet(variables('authorizationServerList')[copyIndex()], 'supportState'), false())]" + }, + "tokenBodyParameters": { + "value": "[coalesce(tryGet(variables('authorizationServerList')[copyIndex()], 'tokenBodyParameters'), createArray())]" + }, + "tokenEndpoint": { + "value": "[coalesce(tryGet(variables('authorizationServerList')[copyIndex()], 'tokenEndpoint'), '')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -2330,25 +2356,49 @@ "name": { "value": "[parameters('identityProviders')[copyIndex()].name]" }, - "allowedTenants": "[if(contains(parameters('identityProviders')[copyIndex()], 'allowedTenants'), createObject('value', parameters('identityProviders')[copyIndex()].allowedTenants), createObject('value', createArray()))]", - "authority": "[if(contains(parameters('identityProviders')[copyIndex()], 'authority'), createObject('value', parameters('identityProviders')[copyIndex()].authority), createObject('value', ''))]", - "clientId": "[if(contains(parameters('identityProviders')[copyIndex()], 'clientId'), createObject('value', parameters('identityProviders')[copyIndex()].clientId), createObject('value', ''))]", - "clientSecret": "[if(contains(parameters('identityProviders')[copyIndex()], 'clientSecret'), createObject('value', parameters('identityProviders')[copyIndex()].clientSecret), createObject('value', ''))]", - "passwordResetPolicyName": "[if(contains(parameters('identityProviders')[copyIndex()], 'passwordResetPolicyName'), createObject('value', parameters('identityProviders')[copyIndex()].passwordResetPolicyName), createObject('value', ''))]", - "profileEditingPolicyName": "[if(contains(parameters('identityProviders')[copyIndex()], 'profileEditingPolicyName'), createObject('value', parameters('identityProviders')[copyIndex()].profileEditingPolicyName), createObject('value', ''))]", - "signInPolicyName": "[if(contains(parameters('identityProviders')[copyIndex()], 'signInPolicyName'), createObject('value', parameters('identityProviders')[copyIndex()].signInPolicyName), createObject('value', ''))]", - "signInTenant": "[if(contains(parameters('identityProviders')[copyIndex()], 'signInTenant'), createObject('value', parameters('identityProviders')[copyIndex()].signInTenant), createObject('value', ''))]", - "signUpPolicyName": "[if(contains(parameters('identityProviders')[copyIndex()], 'signUpPolicyName'), createObject('value', parameters('identityProviders')[copyIndex()].signUpPolicyName), createObject('value', ''))]", - "type": "[if(contains(parameters('identityProviders')[copyIndex()], 'type'), createObject('value', parameters('identityProviders')[copyIndex()].type), createObject('value', 'aad'))]" + "allowedTenants": { + "value": "[coalesce(tryGet(parameters('identityProviders')[copyIndex()], 'allowedTenants'), createArray())]" + }, + "authority": { + "value": "[coalesce(tryGet(parameters('identityProviders')[copyIndex()], 'authority'), '')]" + }, + "clientId": { + "value": "[coalesce(tryGet(parameters('identityProviders')[copyIndex()], 'clientId'), '')]" + }, + "clientLibrary": { + "value": "[coalesce(tryGet(parameters('identityProviders')[copyIndex()], 'clientLibrary'), '')]" + }, + "clientSecret": { + "value": "[coalesce(tryGet(parameters('identityProviders')[copyIndex()], 'clientSecret'), '')]" + }, + "passwordResetPolicyName": { + "value": "[coalesce(tryGet(parameters('identityProviders')[copyIndex()], 'passwordResetPolicyName'), '')]" + }, + "profileEditingPolicyName": { + "value": "[coalesce(tryGet(parameters('identityProviders')[copyIndex()], 'profileEditingPolicyName'), '')]" + }, + "signInPolicyName": { + "value": "[coalesce(tryGet(parameters('identityProviders')[copyIndex()], 'signInPolicyName'), '')]" + }, + "signInTenant": { + "value": "[coalesce(tryGet(parameters('identityProviders')[copyIndex()], 'signInTenant'), '')]" + }, + "signUpPolicyName": { + "value": "[coalesce(tryGet(parameters('identityProviders')[copyIndex()], 'signUpPolicyName'), '')]" + }, + "type": { + "value": "[coalesce(tryGet(parameters('identityProviders')[copyIndex()], 'type'), 'aad')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "13129392765749462635" + "templateHash": "12757169124799431378" }, "name": "API Management Service Identity Providers", "description": "This module deploys an API Management Service Identity Provider.", @@ -2382,6 +2432,17 @@ "description": "Conditional. Client ID of the Application in the external Identity Provider. Required if identity provider is used." } }, + "clientLibrary": { + "type": "string", + "nullable": true, + "allowedValues": [ + "ADAL", + "MSAL-2" + ], + "metadata": { + "description": "Optional. The client library to be used in the developer portal. Only applies to AAD and AAD B2C Identity Provider." + } + }, "clientSecret": { "type": "securestring", "defaultValue": "", @@ -2449,8 +2510,14 @@ "variables": { "isAadB2C": "[equals(parameters('type'), 'aadB2C')]" }, - "resources": [ - { + "resources": { + "service": { + "existing": true, + "type": "Microsoft.ApiManagement/service", + "apiVersion": "2023-05-01-preview", + "name": "[parameters('apiManagementServiceName')]" + }, + "identityProvider": { "type": "Microsoft.ApiManagement/service/identityProviders", "apiVersion": "2022-08-01", "name": "[format('{0}/{1}', parameters('apiManagementServiceName'), parameters('name'))]", @@ -2464,10 +2531,14 @@ "profileEditingPolicyName": "[if(variables('isAadB2C'), parameters('profileEditingPolicyName'), null())]", "passwordResetPolicyName": "[if(variables('isAadB2C'), parameters('passwordResetPolicyName'), null())]", "clientId": "[parameters('clientId')]", + "clientLibrary": "[parameters('clientLibrary')]", "clientSecret": "[parameters('clientSecret')]" - } + }, + "dependsOn": [ + "service" + ] } - ], + }, "outputs": { "resourceId": { "type": "string", @@ -2517,11 +2588,21 @@ "apiManagementServiceName": { "value": "[parameters('name')]" }, - "credentials": "[if(contains(parameters('loggers')[copyIndex()], 'credentials'), createObject('value', parameters('loggers')[copyIndex()].credentials), createObject('value', createObject()))]", - "isBuffered": "[if(contains(parameters('loggers')[copyIndex()], 'isBuffered'), createObject('value', parameters('loggers')[copyIndex()].isBuffered), createObject('value', true()))]", - "loggerDescription": "[if(contains(parameters('loggers')[copyIndex()], 'loggerDescription'), createObject('value', parameters('loggers')[copyIndex()].loggerDescription), createObject('value', ''))]", - "loggerType": "[if(contains(parameters('loggers')[copyIndex()], 'loggerType'), createObject('value', parameters('loggers')[copyIndex()].loggerType), createObject('value', 'azureMonitor'))]", - "targetResourceId": "[if(contains(parameters('loggers')[copyIndex()], 'targetResourceId'), createObject('value', parameters('loggers')[copyIndex()].targetResourceId), createObject('value', ''))]" + "credentials": { + "value": "[coalesce(tryGet(parameters('loggers')[copyIndex()], 'credentials'), createObject())]" + }, + "isBuffered": { + "value": "[coalesce(tryGet(parameters('loggers')[copyIndex()], 'isBuffered'), true())]" + }, + "loggerDescription": { + "value": "[coalesce(tryGet(parameters('loggers')[copyIndex()], 'loggerDescription'), '')]" + }, + "loggerType": { + "value": "[coalesce(tryGet(parameters('loggers')[copyIndex()], 'loggerType'), 'azureMonitor')]" + }, + "targetResourceId": { + "value": "[coalesce(tryGet(parameters('loggers')[copyIndex()], 'targetResourceId'), '')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -2650,15 +2731,21 @@ "displayName": { "value": "[parameters('namedValues')[copyIndex()].displayName]" }, - "keyVault": "[if(contains(parameters('namedValues')[copyIndex()], 'keyVault'), createObject('value', parameters('namedValues')[copyIndex()].keyVault), createObject('value', createObject()))]", + "keyVault": { + "value": "[coalesce(tryGet(parameters('namedValues')[copyIndex()], 'keyVault'), createObject())]" + }, "name": { "value": "[parameters('namedValues')[copyIndex()].name]" }, "tags": { "value": "[tryGet(parameters('namedValues')[copyIndex()], 'tags')]" }, - "secret": "[if(contains(parameters('namedValues')[copyIndex()], 'secret'), createObject('value', parameters('namedValues')[copyIndex()].secret), createObject('value', false()))]", - "value": "[if(contains(parameters('namedValues')[copyIndex()], 'value'), createObject('value', parameters('namedValues')[copyIndex()].value), createObject('value', parameters('newGuidValue')))]" + "secret": { + "value": "[coalesce(tryGet(parameters('namedValues')[copyIndex()], 'secret'), false())]" + }, + "value": { + "value": "[coalesce(tryGet(parameters('namedValues')[copyIndex()], 'value'), parameters('newGuidValue'))]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -2897,7 +2984,9 @@ "value": { "value": "[parameters('policies')[copyIndex()].value]" }, - "format": "[if(contains(parameters('policies')[copyIndex()], 'format'), createObject('value', parameters('policies')[copyIndex()].format), createObject('value', 'xml'))]" + "format": { + "value": "[coalesce(tryGet(parameters('policies')[copyIndex()], 'format'), 'xml')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -3003,17 +3092,33 @@ "apiManagementServiceName": { "value": "[parameters('name')]" }, - "apis": "[if(contains(parameters('products')[copyIndex()], 'apis'), createObject('value', parameters('products')[copyIndex()].apis), createObject('value', createArray()))]", - "approvalRequired": "[if(contains(parameters('products')[copyIndex()], 'approvalRequired'), createObject('value', parameters('products')[copyIndex()].approvalRequired), createObject('value', false()))]", - "groups": "[if(contains(parameters('products')[copyIndex()], 'groups'), createObject('value', parameters('products')[copyIndex()].groups), createObject('value', createArray()))]", + "apis": { + "value": "[coalesce(tryGet(parameters('products')[copyIndex()], 'apis'), createArray())]" + }, + "approvalRequired": { + "value": "[coalesce(tryGet(parameters('products')[copyIndex()], 'approvalRequired'), false())]" + }, + "groups": { + "value": "[coalesce(tryGet(parameters('products')[copyIndex()], 'groups'), createArray())]" + }, "name": { "value": "[parameters('products')[copyIndex()].name]" }, - "description": "[if(contains(parameters('products')[copyIndex()], 'description'), createObject('value', parameters('products')[copyIndex()].description), createObject('value', ''))]", - "state": "[if(contains(parameters('products')[copyIndex()], 'state'), createObject('value', parameters('products')[copyIndex()].state), createObject('value', 'published'))]", - "subscriptionRequired": "[if(contains(parameters('products')[copyIndex()], 'subscriptionRequired'), createObject('value', parameters('products')[copyIndex()].subscriptionRequired), createObject('value', false()))]", - "subscriptionsLimit": "[if(contains(parameters('products')[copyIndex()], 'subscriptionsLimit'), createObject('value', parameters('products')[copyIndex()].subscriptionsLimit), createObject('value', 1))]", - "terms": "[if(contains(parameters('products')[copyIndex()], 'terms'), createObject('value', parameters('products')[copyIndex()].terms), createObject('value', ''))]" + "description": { + "value": "[coalesce(tryGet(parameters('products')[copyIndex()], 'description'), '')]" + }, + "state": { + "value": "[coalesce(tryGet(parameters('products')[copyIndex()], 'state'), 'published')]" + }, + "subscriptionRequired": { + "value": "[coalesce(tryGet(parameters('products')[copyIndex()], 'subscriptionRequired'), false())]" + }, + "subscriptionsLimit": { + "value": "[coalesce(tryGet(parameters('products')[copyIndex()], 'subscriptionsLimit'), 1)]" + }, + "terms": { + "value": "[coalesce(tryGet(parameters('products')[copyIndex()], 'terms'), '')]" + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", diff --git a/avm/res/api-management/service/tests/e2e/max/main.test.bicep b/avm/res/api-management/service/tests/e2e/max/main.test.bicep index 39628c62ba..2989495645 100644 --- a/avm/res/api-management/service/tests/e2e/max/main.test.bicep +++ b/avm/res/api-management/service/tests/e2e/max/main.test.bicep @@ -171,6 +171,7 @@ module testDeployment '../../../main.bicep' = [ { name: 'aad' clientId: 'apimClientid' + clientLibrary: 'MSAL-2' clientSecret: 'apimSlientSecret' authority: split(environment().authentication.loginEndpoint, '/')[2] signinTenant: 'mytenant.onmicrosoft.com' diff --git a/avm/res/api-management/service/tests/e2e/waf-aligned/main.test.bicep b/avm/res/api-management/service/tests/e2e/waf-aligned/main.test.bicep index 35fac0d255..ccf1f295b4 100644 --- a/avm/res/api-management/service/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/api-management/service/tests/e2e/waf-aligned/main.test.bicep @@ -161,6 +161,7 @@ module testDeployment '../../../main.bicep' = [ { name: 'aad' clientId: 'apimClientid' + clientLibrary: 'MSAL-2' clientSecret: customSecret authority: split(environment().authentication.loginEndpoint, '/')[2] signinTenant: 'mytenant.onmicrosoft.com' diff --git a/avm/res/api-management/service/version.json b/avm/res/api-management/service/version.json index c177b1bb58..3f863a2bec 100644 --- a/avm/res/api-management/service/version.json +++ b/avm/res/api-management/service/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.3", + "version": "0.4", "pathFilters": [ "./main.json" ]