diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..811a8cb --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,2 @@ +ARG IMAGE=bullseye +FROM --platform=amd64 mcr.microsoft.com/devcontainers/${IMAGE} diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..fa8d3bd --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,28 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.245.0/containers/python-3 +{ + "name": "ms-identity-python-webapp", + "build": { + "dockerfile": "Dockerfile", + "args": { + "IMAGE": "python:3.10" + } + }, + "features": { + "ghcr.io/devcontainers/features/azure-cli:1": {} + }, + // Configure tool-specific properties. + "customizations": { + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "ms-python.python", + "ms-python.vscode-pylance" + ] + }, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [5000, 50505], + + // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + "remoteUser": "vscode" +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 77994da..d90730a 100644 --- a/.gitignore +++ b/.gitignore @@ -105,3 +105,5 @@ venv.bak/ # flask session files flask_session/ + +.azure/ \ No newline at end of file diff --git a/AppCreationScripts/AppCreationScripts.md b/AppCreationScripts/AppCreationScripts.md deleted file mode 100644 index 864fb28..0000000 --- a/AppCreationScripts/AppCreationScripts.md +++ /dev/null @@ -1,146 +0,0 @@ -# Registering sample apps with the Microsoft identity platform and updating configuration files using PowerShell - -## Overview - -### Quick summary - -1. On Windows, run PowerShell as **Administrator** and navigate to the root of the cloned directory -1. In PowerShell run: - - ```PowerShell - Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process -Force - ``` - -1. Run the script to create your Azure AD application and configure the code of the sample application accordingly. - - ```PowerShell - cd .\AppCreationScripts\ - .\Configure.ps1 -TenantId "your test tenant's id" -AzureEnvironmentName "[Optional] - Azure environment, defaults to 'Global'" - ``` - -### More details - -- [Goal of the provided scripts](#goal-of-the-provided-scripts) - - [Presentation of the scripts](#presentation-of-the-scripts) - - [Usage pattern for tests and DevOps scenarios](#usage-pattern-for-tests-and-DevOps-scenarios) -- [How to use the app creation scripts?](#how-to-use-the-app-creation-scripts) - - [Pre-requisites](#pre-requisites) - - [Run the script and start running](#run-the-script-and-start-running) - - [Four ways to run the script](#four-ways-to-run-the-script) - - [Option 1 (interactive)](#option-1-interactive) - - [Option 2 (Interactive, but create apps in a specified tenant)](#option-3-Interactive-but-create-apps-in-a-specified-tenant) - - [Running the script on Azure Sovereign clouds](#running-the-script-on-Azure-Sovereign-clouds) - -## Goal of the provided scripts - -### Presentation of the scripts - -This sample comes with two PowerShell scripts, which automate the creation of the Azure Active Directory applications, and the configuration of the code for this sample. Once you run them, you will only need to build the solution and you are good to test. - -These scripts are: - -- `Configure.ps1` which: - - creates Azure AD applications and their related objects (permissions, dependencies, secrets, app roles), - - changes the configuration files in the sample projects. - - creates a summary file named `createdApps.html` in the folder from which you ran the script, and containing, for each Azure AD application it created: - - the identifier of the application - - the AppId of the application - - the url of its registration in the [Azure portal](https://portal.azure.com). - -- `Cleanup.ps1` which cleans-up the Azure AD objects created by `Configure.ps1`. Note that this script does not revert the changes done in the configuration files, though. You will need to undo the change from source control (from Visual Studio, or from the command line using, for instance, `git reset`). - -### Usage pattern for tests and DevOps scenarios - -The `Configure.ps1` will stop if it tries to create an Azure AD application which already exists in the tenant. For this, if you are using the script to try/test the sample, or in DevOps scenarios, you might want to run `Cleanup.ps1` just before `Configure.ps1`. This is what is shown in the steps below. - -## How to use the app creation scripts? - -### Pre-requisites - -1. Open PowerShell (On Windows, press `Windows-R` and type `PowerShell` in the search window) -1. Navigate to the root directory of the project. -1. Until you change it, the default [Execution Policy](https:/go.microsoft.com/fwlink/?LinkID=135170) for scripts is usually `Restricted`. In order to run the PowerShell script you need to set the Execution Policy to `RemoteSigned`. You can set this just for the current PowerShell process by running the command: - - ```PowerShell - Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process - ``` - -### (Optionally) install Microsoft.Graph.Applications PowerShell modules - -The scripts install the required PowerShell module (Microsoft.Graph.Applications) for the current user if needed. However, if you want to install if for all users on the machine, you can follow the following steps: - -1. If you have never done it already, in the PowerShell window, install the Microsoft.Graph.Applications PowerShell modules. For this: - - 1. Open PowerShell as admin (On Windows, Search Powershell in the search bar, right click on it and select **Run as administrator**). - 2. Type: - - ```PowerShell - Install-Module Microsoft.Graph.Applications - ``` - - or if you cannot be administrator on your machine, run: - - ```PowerShell - Install-Module Microsoft.Graph.Applications -Scope CurrentUser - ``` - -### Run the script and start running - -1. Go to the `AppCreationScripts` sub-folder. From the folder where you cloned the repo, - - ```PowerShell - cd AppCreationScripts - ``` - -1. Run the scripts. See below for the [four options](#four-ways-to-run-the-script) to do that. - -You're done! - -### Two ways to run the script - -We advise four ways of running the script: - -- Interactive: you will be prompted for credentials, and the scripts decide in which tenant to create the objects, -- Interactive in specific tenant: you will provide the tenant in which you want to create the objects and then you will be prompted for credentials, and the scripts will create the objects, - -Here are the details on how to do this. - -#### Option 1 (interactive) - -- Just run ``.\Configure.ps1``, and you will be prompted to sign-in (email address, password, and if needed MFA). -- The script will be run as the signed-in user and will use the tenant in which the user is defined. - -Note that the script will choose the tenant in which to create the applications, based on the user. Also to run the `Cleanup.ps1` script, you will need to re-sign-in. - -#### Option 2 (Interactive, but create apps in a specified tenant) - - if you want to create the apps in a particular tenant, you can use the following option: - -- Open the [Azure portal](https://portal.azure.com) -- Select the Azure Active directory you are interested in (in the combo-box below your name on the top right of the browser window) -- Find the "Active Directory" object in this tenant -- Go to **Properties** and copy the content of the **Directory Id** property -- Then use the full syntax to run the scripts: - -```PowerShell -$tenantId = "yourTenantIdGuid" -. .\Cleanup.ps1 -TenantId $tenantId -. .\Configure.ps1 -TenantId $tenantId -``` - -### Running the script on Azure Sovereign clouds - -All the four options listed above can be used on any Azure Sovereign clouds. By default, the script targets `AzureCloud`, but it can be changed using the parameter `-AzureEnvironmentName`. - -The acceptable values for this parameter are: - -- AzureCloud -- AzureChinaCloud -- AzureUSGovernment - -Example: - - ```PowerShell - . .\Cleanup.ps1 -AzureEnvironmentName "AzureUSGovernment" - . .\Configure.ps1 -AzureEnvironmentName "AzureUSGovernment" - ``` \ No newline at end of file diff --git a/AppCreationScripts/Cleanup.ps1 b/AppCreationScripts/Cleanup.ps1 deleted file mode 100644 index d1b1fe6..0000000 --- a/AppCreationScripts/Cleanup.ps1 +++ /dev/null @@ -1,139 +0,0 @@ - -[CmdletBinding()] -param( - [Parameter(Mandatory = $False, HelpMessage = 'Tenant ID (This is a GUID which represents the "Directory ID" of the AzureAD tenant into which you want to create the apps')] - [string] $tenantId, - [Parameter(Mandatory = $False, HelpMessage = 'Azure environment to use while running the script. Default = Global')] - [string] $azureEnvironmentName -) - - -Function Cleanup { - if (!$azureEnvironmentName) { - $azureEnvironmentName = "Global" - } - - <# - .Description - This function removes the Azure AD applications for the sample. These applications were created by the Configure.ps1 script - #> - - # $tenantId is the Active Directory Tenant. This is a GUID which represents the "Directory ID" of the AzureAD tenant - # into which you want to create the apps. Look it up in the Azure portal in the "Properties" of the Azure AD. - - # Connect to the Microsoft Graph API - Write-Host "Connecting to Microsoft Graph" - - - if ($tenantId -eq "") { - Connect-MgGraph -Scopes "User.Read.All Organization.Read.All Application.ReadWrite.All" -Environment $azureEnvironmentName - } - else { - Connect-MgGraph -TenantId $tenantId -Scopes "User.Read.All Organization.Read.All Application.ReadWrite.All" -Environment $azureEnvironmentName - } - - $context = Get-MgContext - $tenantId = $context.TenantId - - # Get the user running the script - $currentUserPrincipalName = $context.Account - $user = Get-MgUser -Filter "UserPrincipalName eq '$($context.Account)'" - - # get the tenant we signed in to - $Tenant = Get-MgOrganization - $tenantName = $Tenant.DisplayName - - $verifiedDomain = $Tenant.VerifiedDomains | where { $_.Isdefault -eq $true } - $verifiedDomainName = $verifiedDomain.Name - $tenantId = $Tenant.Id - - Write-Host ("Connected to Tenant {0} ({1}) as account '{2}'. Domain is '{3}'" -f $Tenant.DisplayName, $Tenant.Id, $currentUserPrincipalName, $verifiedDomainName) - - # Removes the applications - Write-Host "Cleaning-up applications from tenant '$tenantId'" - - Write-Host "Removing 'webApp' (WebApp-RolesClaims) if needed" - try { - Get-MgApplication -Filter "DisplayName eq 'WebApp-RolesClaims'" | ForEach-Object { Remove-MgApplication -ApplicationId $_.Id } - } - catch { - $message = $_ - Write-Warning $Error[0] - Write-Host "Unable to remove the application 'WebApp-RolesClaims'. Error is $message. Try deleting manually." -ForegroundColor White -BackgroundColor Red - } - - Write-Host "Making sure there are no more (WebApp-RolesClaims) applications found, will remove if needed..." - $apps = Get-MgApplication -Filter "DisplayName eq 'WebApp-RolesClaims'" | Format-List Id, DisplayName, AppId, SignInAudience, PublisherDomain - - if ($apps) { - Remove-MgApplication -ApplicationId $apps.Id - } - - foreach ($app in $apps) { - Remove-MgApplication -ApplicationId $app.Id - Write-Host "Removed WebApp-RolesClaims.." - } - - # also remove service principals of this app - try { - Get-MgServicePrincipal -filter "DisplayName eq 'WebApp-RolesClaims'" | ForEach-Object { Remove-MgServicePrincipal -ServicePrincipalId $_.Id -Confirm:$false } - } - catch { - $message = $_ - Write-Warning $Error[0] - Write-Host "Unable to remove ServicePrincipal 'WebApp-RolesClaims'. Error is $message. Try deleting manually from Enterprise applications." -ForegroundColor White -BackgroundColor Red - } -} - -# Pre-requisites -if ($null -eq (Get-Module -ListAvailable -Name "Microsoft.Graph")) { - Install-Module "Microsoft.Graph" -Scope CurrentUser -} - -#Import-Module Microsoft.Graph - -if ($null -eq (Get-Module -ListAvailable -Name "Microsoft.Graph.Authentication")) { - Install-Module "Microsoft.Graph.Authentication" -Scope CurrentUser -} - -Import-Module Microsoft.Graph.Authentication - -if ($null -eq (Get-Module -ListAvailable -Name "Microsoft.Graph.Identity.DirectoryManagement")) { - Install-Module "Microsoft.Graph.Identity.DirectoryManagement" -Scope CurrentUser -} - -Import-Module Microsoft.Graph.Identity.DirectoryManagement - -if ($null -eq (Get-Module -ListAvailable -Name "Microsoft.Graph.Applications")) { - Install-Module "Microsoft.Graph.Applications" -Scope CurrentUser -} - -Import-Module Microsoft.Graph.Applications - -if ($null -eq (Get-Module -ListAvailable -Name "Microsoft.Graph.Groups")) { - Install-Module "Microsoft.Graph.Groups" -Scope CurrentUser -} - -Import-Module Microsoft.Graph.Groups - -if ($null -eq (Get-Module -ListAvailable -Name "Microsoft.Graph.Users")) { - Install-Module "Microsoft.Graph.Users" -Scope CurrentUser -} - -Import-Module Microsoft.Graph.Users - -$ErrorActionPreference = "Stop" - - -try { - Cleanup -tenantId $tenantId -environment $azureEnvironmentName -} -catch { - $_.Exception.ToString() | out-host - $message = $_ - Write-Warning $Error[0] - Write-Host "Unable to register apps. Error is $message." -ForegroundColor White -BackgroundColor Red -} - -Write-Host "Disconnecting from tenant" -Disconnect-MgGraph \ No newline at end of file diff --git a/AppCreationScripts/Configure.ps1 b/AppCreationScripts/Configure.ps1 deleted file mode 100644 index 3c58ced..0000000 --- a/AppCreationScripts/Configure.ps1 +++ /dev/null @@ -1,208 +0,0 @@ -[CmdletBinding()] -param( - [Parameter(Mandatory = $False, HelpMessage = 'Tenant ID (This is a GUID which represents the "Directory ID" of the AzureAD tenant into which you want to create the apps')] - [string] $tenantId, - [Parameter(Mandatory = $False, HelpMessage = 'Azure environment to use while running the script. Default = Global')] - [string] $azureEnvironmentName -) - -<# - This script creates the Azure AD applications needed for this sample and updates the configuration files - for the visual Studio projects from the data in the Azure AD applications. - In case you don't have Microsoft.Graph.Applications already installed, the script will automatically install it for the current user - - There are two ways to run this script. For more information, read the AppCreationScripts.md file in the same folder as this script. -#> - -<#.Description - This function takes a string input as a single line, matches a key value and replaces with the replacement value -#> -Function ReplaceInLine([string] $line, [string] $key, [string] $value) { - $index = $line.IndexOf($key) - if ($index -ige 0) { - $index2 = $index + $key.Length - $line = $line.Substring(0, $index) + $value + $line.Substring($index2) - } - return $line -} - -<#.Description - This function takes a dictionary of keys to search and their replacements and replaces the placeholders in a text file -#> -Function UpdateTextFile([string] $configFilePath, [System.Collections.HashTable] $dictionary) { - # Check if text file exists. If not, copy .env.sample. - if (!(Test-Path $configFilePath)) { - Copy-Item "$configFilePath.sample" $configFilePath - } - $lines = Get-Content $configFilePath - $index = 0 - while ($index -lt $lines.Length) { - $line = $lines[$index] - foreach ($key in $dictionary.Keys) { - if ($line.Contains($key)) { - $lines[$index] = ReplaceInLine $line $key $dictionary[$key] - } - } - $index++ - } - - Set-Content -Path $configFilePath -Value $lines -Force -} - -<#.Description - Primary entry method to create and configure app registrations -#> -Function ConfigureApplications { - $isOpenSSl = 'N' #temporary disable open certificate creation - - <#.Description - This function creates the Azure AD applications for the sample in the provided Azure AD tenant and updates the - configuration files in the client and service project of the visual studio solution (App.Config and Web.Config) - so that they are consistent with the Applications parameters - #> - - if (!$azureEnvironmentName) { - $azureEnvironmentName = "Global" - } - - # Connect to the Microsoft Graph API, non-interactive is not supported for the moment (Oct 2021) - Write-Host "Connecting to Microsoft Graph" - if ($tenantId -eq "") { - Connect-MgGraph -Scopes "User.Read.All Organization.Read.All Application.ReadWrite.All" -Environment $azureEnvironmentName - } - else { - Connect-MgGraph -TenantId $tenantId -Scopes "User.Read.All Organization.Read.All Application.ReadWrite.All" -Environment $azureEnvironmentName - } - - $context = Get-MgContext - $tenantId = $context.TenantId - - # Get the user running the script - $currentUserPrincipalName = $context.Account - $user = Get-MgUser -Filter "UserPrincipalName eq '$($context.Account)'" - - # get the tenant we signed in to - $Tenant = Get-MgOrganization - $tenantName = $Tenant.DisplayName - - $verifiedDomain = $Tenant.VerifiedDomains | Where-Object { $_.Isdefault -eq $true } - $verifiedDomainName = $verifiedDomain.Name - $tenantId = $Tenant.Id - - Write-Host ("Connected to Tenant {0} ({1}) as account '{2}'. Domain is '{3}'" -f $Tenant.DisplayName, $Tenant.Id, $currentUserPrincipalName, $verifiedDomainName) - - # Create the webApp AAD application - Write-Host "Creating the AAD application (WebApp)" - # create the application - $webAppAadApplication = New-MgApplication -DisplayName "WebApp" ` - -Web ` - @{ ` - RedirectUris = "http://localhost:5000/getAToken"; ` - HomePageUrl = "https://localhost:5000/"; ` - LogoutUrl = "https://localhost:5000/logout"; ` - - } ` - -SignInAudience AzureADandPersonalMicrosoftAccount ` - #end of command - - #add a secret to the application - $pwdCredential = Add-MgApplicationPassword -ApplicationId $webAppAadApplication.Id -PasswordCredential $key - $webAppAppKey = $pwdCredential.SecretText - - $currentAppId = $webAppAadApplication.AppId - $currentAppObjectId = $webAppAadApplication.Id - - $tenantName = (Get-MgApplication -ApplicationId $currentAppObjectId).PublisherDomain - #Update-MgApplication -ApplicationId $currentAppObjectId -IdentifierUris @("https://$tenantName/WebApp") - - # create the service principal of the newly created application - $webAppServicePrincipal = New-MgServicePrincipal -AppId $currentAppId -Tags { WindowsAzureActiveDirectoryIntegratedApp } - - # add the user running the script as an app owner if needed - $owner = Get-MgApplicationOwner -ApplicationId $currentAppObjectId - if ($null -eq $owner) { - New-MgApplicationOwnerByRef -ApplicationId $currentAppObjectId -BodyParameter = @{"@odata.id" = "htps://graph.microsoft.com/v1.0/directoryObjects/$user.ObjectId" } - Write-Host "'$($user.UserPrincipalName)' added as an application owner to app '$($webAppServicePrincipal.DisplayName)'" - } - Write-Host "Done creating the webApp application (WebApp)" - - # URL of the AAD application in the Azure portal - # Future? $webAppPortalUrl = "https://portal.azure.com/#@"+$tenantName+"/blade/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/Overview/appId/"+$currentAppId+"/objectId/"+$currentAppObjectId+"/isMSAApp/" - $webAppPortalUrl = "https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/Overview/appId/" + $currentAppId + "/isMSAApp~/false" - - # print the registered app portal URL for any further navigation - Write-Host "Successfully registered and configured that app registration for 'WebApp' at `n $webAppPortalUrl" -ForegroundColor Green - - # Update config file for 'webApp' - # $configFile = $pwd.Path + "\..\appsettings.json" - $configFile = $pwd.Path + "\..\.env" - - $dictionary = @{ "" = $webAppAadApplication.AppId; "" = $webAppAppKey; "" = $tenantName }; - - Write-Host "Updating the sample config '$configFile' with the following config values:" -ForegroundColor Yellow - $dictionary - Write-Host "-----------------" - - UpdateTextFile -configFilePath $configFile -dictionary $dictionary - - if ($isOpenSSL -eq 'Y') { - Write-Host -ForegroundColor Green "------------------------------------------------------------------------------------------------" - Write-Host "You have generated certificate using OpenSSL so follow below steps: " - Write-Host "Install the certificate on your system from current folder." - Write-Host -ForegroundColor Green "------------------------------------------------------------------------------------------------" - } -} # end of ConfigureApplications function - -# Pre-requisites - -if ($null -eq (Get-Module -ListAvailable -Name "Microsoft.Graph")) { - Install-Module "Microsoft.Graph" -Scope CurrentUser -} - -#Import-Module Microsoft.Graph - -if ($null -eq (Get-Module -ListAvailable -Name "Microsoft.Graph.Authentication")) { - Install-Module "Microsoft.Graph.Authentication" -Scope CurrentUser -} - -Import-Module Microsoft.Graph.Authentication - -if ($null -eq (Get-Module -ListAvailable -Name "Microsoft.Graph.Identity.DirectoryManagement")) { - Install-Module "Microsoft.Graph.Identity.DirectoryManagement" -Scope CurrentUser -} - -Import-Module Microsoft.Graph.Identity.DirectoryManagement - -if ($null -eq (Get-Module -ListAvailable -Name "Microsoft.Graph.Applications")) { - Install-Module "Microsoft.Graph.Applications" -Scope CurrentUser -} - -Import-Module Microsoft.Graph.Applications - -if ($null -eq (Get-Module -ListAvailable -Name "Microsoft.Graph.Groups")) { - Install-Module "Microsoft.Graph.Groups" -Scope CurrentUser -} - -Import-Module Microsoft.Graph.Groups - -if ($null -eq (Get-Module -ListAvailable -Name "Microsoft.Graph.Users")) { - Install-Module "Microsoft.Graph.Users" -Scope CurrentUser -} - -Import-Module Microsoft.Graph.Users - -$ErrorActionPreference = "Stop" - -# Run interactively (will ask you for the tenant ID) - -try { - ConfigureApplications -tenantId $tenantId -environment $azureEnvironmentName -} -catch { - $_.Exception.ToString() | out-host - $message = $_ - Write-Warning $Error[0] - Write-Host "Unable to register apps. Error is $message." -ForegroundColor White -BackgroundColor Red -} -Write-Host "Disconnecting from tenant" -Disconnect-MgGraph \ No newline at end of file diff --git a/AppCreationScripts/sample.json b/AppCreationScripts/sample.json deleted file mode 100644 index 6a37e6f..0000000 --- a/AppCreationScripts/sample.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "Sample": { - "RepositoryUrl": "https://github.com/Azure-Samples/ms-identity-python-webapp", - "Title": "Integrating Microsoft Identity Platform with a Python web application", - "Level": 300, - "Client": "Python Web Application", - "Service": "Microsoft Graph", - "Endpoint": "Microsoft identity platform (formerly Azure AD v2.0)" - }, - - /* - This section describes the Azure AD Applications to configure, and their dependencies - */ - "AADApps": [ - { - "Id": "pythonwebapp", - "Name": "python-webapp", - "Kind": "WebApp", /* SinglePageApplication, WebApp, Mobile, UWP, Desktop, Daemon, WebApi, Browserless */ - "Audience": "AzureADandPersonalMicrosoftAccount", /* AzureADMyOrg, AzureADMultipleOrgs, AzureADandPersonalMicrosoftAccount, PersonalMicrosoftAccount */ - "PasswordCredentials": "Auto", - "RequiredResourcesAccess": [ - { - "Resource": "Microsoft Graph", - "DelegatedPermissions": [ - "User.ReadBasic.All" - ] - } - ], - "ReplyUrls": "http://localhost:5000/getAToken" - } - ], - - /* - This section describes how to update the code in configuration files from the apps coordinates, once the apps - are created in Azure AD. - Each section describes a configuration file, for one of the apps, it's type (XML, JSon, plain text), its location - with respect to the root of the sample, and the mappping (which string in the config file is mapped to which value - */ - "CodeConfiguration": [ - { - "App": "pythonwebapp", - "SettingKind": "Replace", - "SettingFile": "\\..\\.env", - "Mappings": [ - { - "key": "", - "value": "$tenantName" - }, - { - "key": "", - "value": ".AppKey" - }, - { - "key": "", - "value": ".AppId" - } - ] - } - ] -} diff --git a/README.md b/README.md index 42037ae..692fc63 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ To get started with this sample, you have two options: * Use the Azure portal to create the Azure AD applications and related objects. Follow the steps in [Quickstart: Add sign-in with Microsoft to a Python web app](https://docs.microsoft.com/azure/active-directory/develop/web-app-quickstart?pivots=devlang-python). -* Use PowerShell scripts that automatically create the Azure AD applications and related objects (passwords, permissions, dependencies) for you, and then modify the configuration files. Follow the steps in the [App Creation Scripts README](./AppCreationScripts/AppCreationScripts.md). +* Use shell scripts that use the Azure CLI to automatically create the Azure AD applications and related objects, and then create the *.env* file. Follow the steps in the [App Creation Scripts README](./scripts/AppCreationScripts.md). # Deployment diff --git a/scripts/AppCreationScripts.md b/scripts/AppCreationScripts.md new file mode 100644 index 0000000..52ae864 --- /dev/null +++ b/scripts/AppCreationScripts.md @@ -0,0 +1,44 @@ +# Registering sample apps with the Microsoft identity platform using the Azure CLI + +## Overview + +This directory includes two scripts to aid in the process of registering an app with the Microsoft identity platform +and configuring this sample app with the appropriate environment variables. + +* *configure.sh*: A bash script that uses the Azure CLI to register an app, generate a client secret, and grant Microsoft Graph API permissions. It then stores the `CLIENT_ID`, `CLIENT_SECRET`, and `TENANT_ID` in a *.env* file locally. +* *cleanup.sh*: A bash script that uses the Azure CLI to delete the app registration based off the variables inside *.env*. + +## Prerequisites + +To run these scripts, you need: + +1. An environment to run Bash scripts +2. [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) +3. An Azure account with the permission to create app registrations + +If you open this project inside a Dev Container in VS Code or inside Github Codespaces, you don't need to install anything. + +## Running the configuration script + + +Run this script to set up the app registration: + +``` +./scripts/configure.sh +``` + +⚠️ Running the script will override the local *.env* file (if one exists) with new values. + +You can optionally specify a tenant ID if your account has multiple tenants and you'd like to register an app in the specified tenant. + +``` +./configure.sh +``` + +## Run the cleanup script + +This script takes no arguments, as it retrieves everything from the local *.env*: + +``` +./cleanup.sh +``` \ No newline at end of file diff --git a/scripts/cleanup.sh b/scripts/cleanup.sh new file mode 100755 index 0000000..9975071 --- /dev/null +++ b/scripts/cleanup.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# Read in the variables from .env +source .env + +# Find and delete the service principal for that app registration +sp_id=$(az ad sp list --filter "appId eq '"$CLIENT_ID"'" --query "[0].id" --output tsv) + +if [ -z "$sp_id" ]; then + echo "Service principal with ID $sp_id does not exist." + exit 1 +else + echo "Attempting to delete service principal with ID $sp_id" + az ad sp delete --id $sp_id +fi + +# Delete the app registration +echo "Attempting to delete app with ID $CLIENT_ID" +az ad app delete --id $CLIENT_ID + +echo "All associated resources are cleaned up." diff --git a/scripts/configure.sh b/scripts/configure.sh new file mode 100755 index 0000000..bc5c375 --- /dev/null +++ b/scripts/configure.sh @@ -0,0 +1,51 @@ +#!/bin/bash +az extension add --name account + +tenant_arg=$1 +if [ -n "$tenant_arg" ]; then + echo "Attempting login to Azure with tenant ID $tenant_arg..." + az login --allow-no-subscriptions --tenant $tenant_arg --output none +else + echo "Attempting login to Azure..." + az login --allow-no-subscriptions --output none +fi + +tenant_id=$(az account show --query tenantId --output tsv) + +echo "Attempting app registration creation..." +client_id=$(az ad app create --display-name "WebApp$RANDOM$RANDOM" \ + --web-redirect-uris "http://localhost:5000/getAToken" \ + --web-home-page-url "https://localhost:5000/" \ + --sign-in-audience AzureADandPersonalMicrosoftAccount \ + --query appId --output tsv) + +echo "Attempting to add a client secret to app $client_id ..." +client_secret=$(az ad app credential reset --id $client_id \ + --append --display-name "WebAppSecret" \ + --query password --output tsv) + +echo "Attempting to grant permissions for app $client_id to Microsoft Graph API User.ReadBasic.All..." +az ad app permission add --id $client_id \ + --api 00000003-0000-0000-c000-000000000000 \ + --api-permissions b340eb25-3456-403f-be2f-af7a0d370277=Scope \ + --only-show-errors --output none + +az ad sp create --id $client_id --output none + +az ad app permission grant --id $client_id \ + --api 00000003-0000-0000-c000-000000000000 \ + --scope User.ReadBasic.All \ + --output none + +# Delete .env file if it exists, otherwise create it +echo "Creating .env file..." +if [ -f .env ]; then + > .env +fi + +echo "Writing configuration to .env file..." +echo "CLIENT_ID=$client_id" >> .env +echo "CLIENT_SECRET=$client_secret" >> .env +echo "TENANT_ID=$tenant_id" >> .env + +echo "Configuration complete."