diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 4116448..0000000 --- a/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -FROM mcr.microsoft.com/powershell:ubuntu-18.04 - -WORKDIR /app - -RUN pwsh -Command "Install-Module -Name powershell-yaml -Repository PSGallery" - -COPY . . - -ENTRYPOINT ["pwsh", "/app/entrypoint.ps1"] \ No newline at end of file diff --git a/README.md b/README.md index af376e7..9d1fe9b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # GitHub Action for Deploying Azure AD B2C custom policies -This is a fork of the [azure-ad-b2c/deploy-trustframework-policy](https://github.com/azure-ad-b2c/deploy-trustframework-policy) repository to add in additional error handling and other QOL improvements. +This is a fork of the [azure-ad-b2c/deploy-trustframework-policy](https://github.com/azure-ad-b2c/deploy-trustframework-policy) repository to convert it into a PowerShell-based composite action to account for better error handling. Use this GitHub Action to deploy an [Azure AD B2C custom policy](https://docs.microsoft.com/azure/active-directory-b2c/custom-policy-overview) into your Azure Active Directory B2C tenant using the [Microsoft Graph API](https://docs.microsoft.com/graph/api/resources/trustframeworkpolicy?view=graph-rest-beta). If the policy does not yet exist, it will be created. If the policy already exists, it will be replaced. @@ -30,10 +30,6 @@ git clone https://github.com/Andrews-McMeel-Universal/deploy-trustframework-poli ```yaml on: push -env: - clientId: 00000000-0000-0000-0000-000000000000 - tenant: my-tenant.onmicrosoft.com - jobs: build-and-deploy: runs-on: ubuntu-latest @@ -45,68 +41,14 @@ jobs: with: folder: "./Policies" files: "TrustFrameworkBase.xml,TrustFrameworkExtensions.xml,SignUpOrSignin.xml" - tenant: ${{ env.tenant }} - clientId: ${{ env.clientId }} + tenant: my-tenant.onmicrosoft.com + clientId: 00000000-0000-0000-0000-000000000000 clientSecret: ${{ secrets.clientSecret }} renumberSteps: false ``` --- -## Building the Project - -### Packaging the Project - -To update new version you must package this GitHub Action. Use the following commands to package the project: - -```bash -npm run-script build -npm run-script package -``` - -You can find more information about these scripts in the [package.json](package.json) file. For example: - -```json -"scripts": { - "build": "tsc", - "format": "prettier --write **/*.ts", - "format-check": "prettier --check **/*.ts", - "lint": "eslint src/**/*.ts", - "package": "ncc build --source-map --license licenses.txt", - "test": "jest", - "all": "npm run build && npm run format && npm run lint && npm run package && npm test" - } -``` - -After the build is completed, you can see that the JavaScript files under the [dist](dist) folder changed with the latest version of your TypeScript code. - -### Build issues - -The GitHub build runs the scrips as described above. The `lint` script runs the [eslint](https://eslint.org/) command. This command analyzes your code to quickly find problems. You can change the settings of the eslint command in the [.eslintrc.json](.eslintrc.json) file. The following example suppresses some of the errors: - -```json -"rules": { - "i18n-text/no-en": 0, - "import/named": "warn", - "github/no-then": "warn", - "eslint-comments/no-use": "off", - "import/no-namespace": "off", - "no-unused-vars": "off", -``` - -### Test the action - -When you commit a change to any branch or a PR, the [test.yml](.github/workflows/test.yml) workflow runs with `clientId` parameter set to `test`. The `test` value indicates to the GitHub Action to exit the test successfully. We exit the test because because the required parameters are not configured in this repo. - -To test the GitHub Action create your own repo, add the workflow. Then configure the [uses](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsuses) to point to your branch, fork, or commit. The following example demonstrate how to configure the workflow to use the latest commit in the `vNext` branch. - -```bash -- name: 'Upload custom policies' - uses: azure-ad-b2c/deploy-trustframework-policy@vNext -``` - ---- - ## Reusable Workflow Integration Once a pull request is merged into _main_, you can create a new release to use it as a reusable workflow. To create a new release, follow the instructions in this guide: [Creating a Release](https://amuniversal.atlassian.net/wiki/spaces/TD/pages/3452043300/Creating+a+new+GitHub+Release#Creating-a-release) diff --git a/action.yaml b/action.yaml index c5f9595..c26dede 100644 --- a/action.yaml +++ b/action.yaml @@ -1,6 +1,6 @@ name: Deploy B2C Custom Policy -description: A GitHub Action for deploying Azure AD B2C policies using the Microsoft Graph API +description: A PowerShell-based GitHub Action for deploying Azure AD B2C policies using the Microsoft Graph API author: Azure AD B2C GitHub Community @@ -29,5 +29,82 @@ inputs: required: true runs: - using: "docker" - image: "Dockerfile" + using: "composite" + steps: + # Adapted from the PowerShell script in Microsoft's Docs: https://learn.microsoft.com/en-us/azure/active-directory-b2c/deploy-custom-policies-devops + - name: Run Deploy Policy Script + uses: azure/powershell@v1 + with: + inlineScript: | + $Folder = "${{ inputs.folder }}" + $Files = "${{ inputs.files }}" + $TenantDomain = "${{ inputs.tenantDomain }}" + $TenantId = "${{ inputs.tenantId }}" + $ClientID = "${{ inputs.clientId }}" + $ClientSecret = "${{ inputs.clientSecret }}" + + try { + $body = @{grant_type = "client_credentials"; scope = "https://graph.microsoft.com/.default"; client_id = $ClientID; client_secret = $ClientSecret } + + $response = Invoke-RestMethod -Uri https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token -Method Post -Body $body + $token = $response.access_token + + $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" + $headers.Add("Content-Type", 'application/xml') + $headers.Add("Authorization", 'Bearer ' + $token) + + # Get the list of files to upload + $filesArray = $Files.Split(",") + + Foreach ($file in $filesArray) { + + $filePath = $Folder + $file.Trim() + + # Check if file exists + $FileExists = Test-Path -Path $filePath -PathType Leaf + + if ($FileExists) { + $policycontent = Get-Content $filePath -Encoding UTF8 + + # Optional: Change the content of the policy. For example, replace the tenant-name with your tenant name. + $policycontent = $policycontent.Replace("your-tenant.onmicrosoft.com", "$TenantDomain") + + + # Get the policy name from the XML document + $match = Select-String -InputObject $policycontent -Pattern '(?<=\bPolicyId=")[^"]*' + + If ($match.matches.groups.count -ge 1) { + $PolicyId = $match.matches.groups[0].value + + Write-Output "Uploading the $PolicyId policy..." + + $graphuri = 'https://graph.microsoft.com/beta/trustframework/policies/' + $PolicyId + '/$value' + $content = [System.Text.Encoding]::UTF8.GetBytes($policycontent) + $response = Invoke-RestMethod -Uri $graphuri -Method Put -Body $content -Headers $headers -ContentType "application/xml; charset=utf-8" + + Write-Output "Policy $PolicyId uploaded successfully." + } + } + else { + $warning = "File " + $filePath + " couldn't be not found." + Write-Warning -Message $warning + } + } + } + catch { + Write-Output "StatusCode:" $_.Exception.Response.StatusCode.value__ + + $_ + + $streamReader = [System.IO.StreamReader]::new($_.Exception.Response.GetResponseStream()) + $streamReader.BaseStream.Position = 0 + $streamReader.DiscardBufferedData() + $errResp = $streamReader.ReadToEnd() + $streamReader.Close() + + $ErrResp + + exit 1 + } + exit 0 + azPSVersion: "latest" diff --git a/entrypoint.ps1 b/entrypoint.ps1 deleted file mode 100644 index fcdf946..0000000 --- a/entrypoint.ps1 +++ /dev/null @@ -1,75 +0,0 @@ -[Cmdletbinding()] -Param( - [string]$ClientID = (Get-Content ".env" | Out-String | ConvertFrom-StringData).AZURE_B2C_CLIENT_ID, - [string]$ClientSecret = (Get-Content ".env" | Out-String | ConvertFrom-StringData).AZURE_B2C_CLIENT_SECRET, - [string]$TenantId = (Get-Content ".env" | Out-String | ConvertFrom-StringData).AZURE_B2C_TENANT_ID, - [string]$Folder = "./dist/custom-policies/", - [string]$Files = (Get-ChildItem "dist/custom-policies" | ForEach-Object { $_.name }) -join ',', - [string]$TenantName = (Get-Content ".env" | Out-String | ConvertFrom-StringData).AZURE_B2C_DOMAIN -) - -try { - $body = @{grant_type = "client_credentials"; scope = "https://graph.microsoft.com/.default"; client_id = $ClientID; client_secret = $ClientSecret } - - $response = Invoke-RestMethod -Uri https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token -Method Post -Body $body - $token = $response.access_token - - $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" - $headers.Add("Content-Type", 'application/xml') - $headers.Add("Authorization", 'Bearer ' + $token) - - # Get the list of files to upload - $filesArray = $Files.Split(",") - - Foreach ($file in $filesArray) { - - $filePath = $Folder + $file.Trim() - - # Check if file exists - $FileExists = Test-Path -Path $filePath -PathType Leaf - - if ($FileExists) { - $policycontent = Get-Content $filePath -Encoding UTF8 - - # Optional: Change the content of the policy. For example, replace the tenant-name with your tenant name. - $policycontent = $policycontent.Replace("your-tenant.onmicrosoft.com", "$TenantName") - - - # Get the policy name from the XML document - $match = Select-String -InputObject $policycontent -Pattern '(?<=\bPolicyId=")[^"]*' - - If ($match.matches.groups.count -ge 1) { - $PolicyId = $match.matches.groups[0].value - - Write-Output "Uploading the $PolicyId policy..." - - $graphuri = 'https://graph.microsoft.com/beta/trustframework/policies/' + $PolicyId + '/$value' - $content = [System.Text.Encoding]::UTF8.GetBytes($policycontent) - $response = Invoke-RestMethod -Uri $graphuri -Method Put -Body $content -Headers $headers -ContentType "application/xml; charset=utf-8" - - Write-Output "Policy $PolicyId uploaded successfully." - } - } - else { - $warning = "File " + $filePath + " couldn't be not found." - Write-Warning -Message $warning - } - } -} -catch { - Write-Output "StatusCode:" $_.Exception.Response.StatusCode.value__ - - $_ - - $streamReader = [System.IO.StreamReader]::new($_.Exception.Response.GetResponseStream()) - $streamReader.BaseStream.Position = 0 - $streamReader.DiscardBufferedData() - $errResp = $streamReader.ReadToEnd() - $streamReader.Close() - - $ErrResp - - exit 1 -} - -exit 0 \ No newline at end of file