From eec952c1bb41ce4aa4f3738e479eab4ae73e6b7e Mon Sep 17 00:00:00 2001 From: Alexander Beyderman Date: Sat, 25 Sep 2021 03:36:12 -0400 Subject: [PATCH 01/19] values for Woodgrove tenant debugging --- AppCreationScripts/Cleanup.ps1 | 2 +- AppCreationScripts/Configure.ps1 | 2 +- AppCreationScripts/appsetup.ps1 | 7 ++ AppCreationScripts/createdApps.html | 4 + TodoListClient/.config/dotnet-tools.json | 12 ++ .../mssql1.arm.json | 81 +++++++++++++ .../profile.arm.json | 113 ++++++++++++++++++ .../mssql1.arm.json | 81 +++++++++++++ .../profile.arm.json | 113 ++++++++++++++++++ ...ies.AuthContextDotNetApp - Web Deploy.json | 10 ++ ...ListClient20210921173525 - Web Deploy.json | 10 ++ .../Properties/serviceDependencies.json | 4 + TodoListClient/TodoListClient.csproj | 4 + TodoListClient/appsettings.json | 8 +- 14 files changed, 445 insertions(+), 6 deletions(-) create mode 100644 AppCreationScripts/appsetup.ps1 create mode 100644 AppCreationScripts/createdApps.html create mode 100644 TodoListClient/.config/dotnet-tools.json create mode 100644 TodoListClient/Properties/ServiceDependencies/AuthContextDotNetApp - Web Deploy/mssql1.arm.json create mode 100644 TodoListClient/Properties/ServiceDependencies/AuthContextDotNetApp - Web Deploy/profile.arm.json create mode 100644 TodoListClient/Properties/ServiceDependencies/TodoListClient20210921173525 - Web Deploy/mssql1.arm.json create mode 100644 TodoListClient/Properties/ServiceDependencies/TodoListClient20210921173525 - Web Deploy/profile.arm.json create mode 100644 TodoListClient/Properties/serviceDependencies.AuthContextDotNetApp - Web Deploy.json create mode 100644 TodoListClient/Properties/serviceDependencies.TodoListClient20210921173525 - Web Deploy.json diff --git a/AppCreationScripts/Cleanup.ps1 b/AppCreationScripts/Cleanup.ps1 index 25adc2a..e5a8d91 100644 --- a/AppCreationScripts/Cleanup.ps1 +++ b/AppCreationScripts/Cleanup.ps1 @@ -7,7 +7,7 @@ param( [string] $azureEnvironmentName ) -#Requires -Modules AzureAD -RunAsAdministrator +#Requires -Modules AzureAD if ($null -eq (Get-Module -ListAvailable -Name "AzureAD")) { diff --git a/AppCreationScripts/Configure.ps1 b/AppCreationScripts/Configure.ps1 index 11887f7..f178b65 100644 --- a/AppCreationScripts/Configure.ps1 +++ b/AppCreationScripts/Configure.ps1 @@ -7,7 +7,7 @@ param( [string] $azureEnvironmentName ) -#Requires -Modules AzureAD -RunAsAdministrator +#Requires -Modules AzureAD <# This script creates the Azure AD applications needed for this sample and updates the configuration files diff --git a/AppCreationScripts/appsetup.ps1 b/AppCreationScripts/appsetup.ps1 new file mode 100644 index 0000000..b020f9c --- /dev/null +++ b/AppCreationScripts/appsetup.ps1 @@ -0,0 +1,7 @@ +Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process -Force +$secpasswd = ConvertTo-SecureString "Abeyd@123" -AsPlainText -Force +$mycreds = New-Object System.Management.Automation.PSCredential ("alexbeyd@alexbdev.onmicrosoft.com", $secpasswd) +$tenantId = "859c0fc9-4300-47be-b473-597fa2fc2104" + +.\Cleanup.ps1 -Credential $mycreds -TenantId $tenantId +.\Configure.ps1 -Credential $mycreds -TenantId $tenantId \ No newline at end of file diff --git a/AppCreationScripts/createdApps.html b/AppCreationScripts/createdApps.html new file mode 100644 index 0000000..1138db3 --- /dev/null +++ b/AppCreationScripts/createdApps.html @@ -0,0 +1,4 @@ + + + +
ApplicationAppIdUrl in the Azure portal
clientd56cce6d-baca-4f88-9e00-9bb11eb92b28TodoListClient-authContext-webapp
diff --git a/TodoListClient/.config/dotnet-tools.json b/TodoListClient/.config/dotnet-tools.json new file mode 100644 index 0000000..337014b --- /dev/null +++ b/TodoListClient/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-ef": { + "version": "5.0.10", + "commands": [ + "dotnet-ef" + ] + } + } +} \ No newline at end of file diff --git a/TodoListClient/Properties/ServiceDependencies/AuthContextDotNetApp - Web Deploy/mssql1.arm.json b/TodoListClient/Properties/ServiceDependencies/AuthContextDotNetApp - Web Deploy/mssql1.arm.json new file mode 100644 index 0000000..cafc6c8 --- /dev/null +++ b/TodoListClient/Properties/ServiceDependencies/AuthContextDotNetApp - Web Deploy/mssql1.arm.json @@ -0,0 +1,81 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "resourceGroupName": { + "type": "string", + "defaultValue": "Thefirstresourcegroup", + "metadata": { + "_parameterType": "resourceGroup", + "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." + } + }, + "resourceGroupLocation": { + "type": "string", + "defaultValue": "eastus", + "metadata": { + "_parameterType": "location", + "description": "Location of the resource group. Resource groups could have different location than resources." + } + }, + "resourceLocation": { + "type": "string", + "defaultValue": "[parameters('resourceGroupLocation')]", + "metadata": { + "_parameterType": "location", + "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/resourceGroups", + "name": "[parameters('resourceGroupName')]", + "location": "[parameters('resourceGroupLocation')]", + "apiVersion": "2019-10-01" + }, + { + "type": "Microsoft.Resources/deployments", + "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat('TodoListClient_db', subscription().subscriptionId)))]", + "resourceGroup": "[parameters('resourceGroupName')]", + "apiVersion": "2019-10-01", + "dependsOn": [ + "[parameters('resourceGroupName')]" + ], + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "kind": "v12.0", + "location": "[parameters('resourceLocation')]", + "name": "todolistclientdbserver", + "type": "Microsoft.Sql/servers", + "apiVersion": "2017-10-01-preview" + }, + { + "sku": { + "name": "Standard", + "tier": "Standard", + "capacity": 10 + }, + "kind": "v12.0,user", + "location": "[parameters('resourceLocation')]", + "name": "todolistclientdbserver/TodoListClient_db", + "type": "Microsoft.Sql/servers/databases", + "apiVersion": "2017-10-01-preview", + "dependsOn": [ + "todolistclientdbserver" + ] + } + ] + } + } + } + ], + "metadata": { + "_dependencyType": "mssql.azure" + } +} \ No newline at end of file diff --git a/TodoListClient/Properties/ServiceDependencies/AuthContextDotNetApp - Web Deploy/profile.arm.json b/TodoListClient/Properties/ServiceDependencies/AuthContextDotNetApp - Web Deploy/profile.arm.json new file mode 100644 index 0000000..35023cf --- /dev/null +++ b/TodoListClient/Properties/ServiceDependencies/AuthContextDotNetApp - Web Deploy/profile.arm.json @@ -0,0 +1,113 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_dependencyType": "appService.windows" + }, + "parameters": { + "resourceGroupName": { + "type": "string", + "defaultValue": "Thefirstresourcegroup", + "metadata": { + "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." + } + }, + "resourceGroupLocation": { + "type": "string", + "defaultValue": "eastus", + "metadata": { + "description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support." + } + }, + "resourceName": { + "type": "string", + "defaultValue": "AuthContextDotNetApp", + "metadata": { + "description": "Name of the main resource to be created by this template." + } + }, + "resourceLocation": { + "type": "string", + "defaultValue": "[parameters('resourceGroupLocation')]", + "metadata": { + "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." + } + } + }, + "variables": { + "appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", + "appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]" + }, + "resources": [ + { + "type": "Microsoft.Resources/resourceGroups", + "name": "[parameters('resourceGroupName')]", + "location": "[parameters('resourceGroupLocation')]", + "apiVersion": "2019-10-01" + }, + { + "type": "Microsoft.Resources/deployments", + "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", + "resourceGroup": "[parameters('resourceGroupName')]", + "apiVersion": "2019-10-01", + "dependsOn": [ + "[parameters('resourceGroupName')]" + ], + "properties": { + "mode": "Incremental", + "template": { + "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "location": "[parameters('resourceLocation')]", + "name": "[parameters('resourceName')]", + "type": "Microsoft.Web/sites", + "apiVersion": "2015-08-01", + "tags": { + "[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty" + }, + "dependsOn": [ + "[variables('appServicePlan_ResourceId')]" + ], + "kind": "app", + "properties": { + "name": "[parameters('resourceName')]", + "kind": "app", + "httpsOnly": true, + "reserved": false, + "serverFarmId": "[variables('appServicePlan_ResourceId')]", + "siteConfig": { + "metadata": [ + { + "name": "CURRENT_STACK", + "value": "dotnetcore" + } + ] + } + }, + "identity": { + "type": "SystemAssigned" + } + }, + { + "location": "[parameters('resourceLocation')]", + "name": "[variables('appServicePlan_name')]", + "type": "Microsoft.Web/serverFarms", + "apiVersion": "2015-08-01", + "sku": { + "name": "S1", + "tier": "Standard", + "family": "S", + "size": "S1" + }, + "properties": { + "name": "[variables('appServicePlan_name')]" + } + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/TodoListClient/Properties/ServiceDependencies/TodoListClient20210921173525 - Web Deploy/mssql1.arm.json b/TodoListClient/Properties/ServiceDependencies/TodoListClient20210921173525 - Web Deploy/mssql1.arm.json new file mode 100644 index 0000000..cafc6c8 --- /dev/null +++ b/TodoListClient/Properties/ServiceDependencies/TodoListClient20210921173525 - Web Deploy/mssql1.arm.json @@ -0,0 +1,81 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "resourceGroupName": { + "type": "string", + "defaultValue": "Thefirstresourcegroup", + "metadata": { + "_parameterType": "resourceGroup", + "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." + } + }, + "resourceGroupLocation": { + "type": "string", + "defaultValue": "eastus", + "metadata": { + "_parameterType": "location", + "description": "Location of the resource group. Resource groups could have different location than resources." + } + }, + "resourceLocation": { + "type": "string", + "defaultValue": "[parameters('resourceGroupLocation')]", + "metadata": { + "_parameterType": "location", + "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/resourceGroups", + "name": "[parameters('resourceGroupName')]", + "location": "[parameters('resourceGroupLocation')]", + "apiVersion": "2019-10-01" + }, + { + "type": "Microsoft.Resources/deployments", + "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat('TodoListClient_db', subscription().subscriptionId)))]", + "resourceGroup": "[parameters('resourceGroupName')]", + "apiVersion": "2019-10-01", + "dependsOn": [ + "[parameters('resourceGroupName')]" + ], + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "kind": "v12.0", + "location": "[parameters('resourceLocation')]", + "name": "todolistclientdbserver", + "type": "Microsoft.Sql/servers", + "apiVersion": "2017-10-01-preview" + }, + { + "sku": { + "name": "Standard", + "tier": "Standard", + "capacity": 10 + }, + "kind": "v12.0,user", + "location": "[parameters('resourceLocation')]", + "name": "todolistclientdbserver/TodoListClient_db", + "type": "Microsoft.Sql/servers/databases", + "apiVersion": "2017-10-01-preview", + "dependsOn": [ + "todolistclientdbserver" + ] + } + ] + } + } + } + ], + "metadata": { + "_dependencyType": "mssql.azure" + } +} \ No newline at end of file diff --git a/TodoListClient/Properties/ServiceDependencies/TodoListClient20210921173525 - Web Deploy/profile.arm.json b/TodoListClient/Properties/ServiceDependencies/TodoListClient20210921173525 - Web Deploy/profile.arm.json new file mode 100644 index 0000000..3fa6997 --- /dev/null +++ b/TodoListClient/Properties/ServiceDependencies/TodoListClient20210921173525 - Web Deploy/profile.arm.json @@ -0,0 +1,113 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_dependencyType": "appService.windows" + }, + "parameters": { + "resourceGroupName": { + "type": "string", + "defaultValue": "Thefirstresourcegroup", + "metadata": { + "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." + } + }, + "resourceGroupLocation": { + "type": "string", + "defaultValue": "eastus", + "metadata": { + "description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support." + } + }, + "resourceName": { + "type": "string", + "defaultValue": "TodoListClient20210921173525", + "metadata": { + "description": "Name of the main resource to be created by this template." + } + }, + "resourceLocation": { + "type": "string", + "defaultValue": "[parameters('resourceGroupLocation')]", + "metadata": { + "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." + } + } + }, + "variables": { + "appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", + "appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]" + }, + "resources": [ + { + "type": "Microsoft.Resources/resourceGroups", + "name": "[parameters('resourceGroupName')]", + "location": "[parameters('resourceGroupLocation')]", + "apiVersion": "2019-10-01" + }, + { + "type": "Microsoft.Resources/deployments", + "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", + "resourceGroup": "[parameters('resourceGroupName')]", + "apiVersion": "2019-10-01", + "dependsOn": [ + "[parameters('resourceGroupName')]" + ], + "properties": { + "mode": "Incremental", + "template": { + "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "location": "[parameters('resourceLocation')]", + "name": "[parameters('resourceName')]", + "type": "Microsoft.Web/sites", + "apiVersion": "2015-08-01", + "tags": { + "[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty" + }, + "dependsOn": [ + "[variables('appServicePlan_ResourceId')]" + ], + "kind": "app", + "properties": { + "name": "[parameters('resourceName')]", + "kind": "app", + "httpsOnly": true, + "reserved": false, + "serverFarmId": "[variables('appServicePlan_ResourceId')]", + "siteConfig": { + "metadata": [ + { + "name": "CURRENT_STACK", + "value": "dotnetcore" + } + ] + } + }, + "identity": { + "type": "SystemAssigned" + } + }, + { + "location": "[parameters('resourceLocation')]", + "name": "[variables('appServicePlan_name')]", + "type": "Microsoft.Web/serverFarms", + "apiVersion": "2015-08-01", + "sku": { + "name": "S1", + "tier": "Standard", + "family": "S", + "size": "S1" + }, + "properties": { + "name": "[variables('appServicePlan_name')]" + } + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/TodoListClient/Properties/serviceDependencies.AuthContextDotNetApp - Web Deploy.json b/TodoListClient/Properties/serviceDependencies.AuthContextDotNetApp - Web Deploy.json new file mode 100644 index 0000000..594e299 --- /dev/null +++ b/TodoListClient/Properties/serviceDependencies.AuthContextDotNetApp - Web Deploy.json @@ -0,0 +1,10 @@ +{ + "dependencies": { + "mssql1": { + "resourceId": "/subscriptions/[parameters('subscriptionId')]/resourceGroups/[parameters('resourceGroupName')]/providers/Microsoft.Sql/servers/todolistclientdbserver/databases/TodoListClient_db", + "type": "mssql.azure", + "connectionId": "ConnectionStrings:DefaultConnection", + "secretStore": "AzureAppSettings" + } + } +} \ No newline at end of file diff --git a/TodoListClient/Properties/serviceDependencies.TodoListClient20210921173525 - Web Deploy.json b/TodoListClient/Properties/serviceDependencies.TodoListClient20210921173525 - Web Deploy.json new file mode 100644 index 0000000..d76bb87 --- /dev/null +++ b/TodoListClient/Properties/serviceDependencies.TodoListClient20210921173525 - Web Deploy.json @@ -0,0 +1,10 @@ +{ + "dependencies": { + "mssql1": { + "resourceId": "/subscriptions/[parameters('subscriptionId')]/resourcegroups/[parameters('resourceGroupName')]/providers/Microsoft.Sql/servers/todolistclientdbserver/databases/TodoListClient_db", + "type": "mssql.azure", + "connectionId": "ConnectionStrings:DefaultConnection", + "secretStore": "AzureAppSettings" + } + } +} \ No newline at end of file diff --git a/TodoListClient/Properties/serviceDependencies.json b/TodoListClient/Properties/serviceDependencies.json index a4e7aa3..5d53e15 100644 --- a/TodoListClient/Properties/serviceDependencies.json +++ b/TodoListClient/Properties/serviceDependencies.json @@ -2,6 +2,10 @@ "dependencies": { "secrets1": { "type": "secrets" + }, + "mssql1": { + "type": "mssql", + "connectionId": "ConnectionStrings:DefaultConnection" } } } \ No newline at end of file diff --git a/TodoListClient/TodoListClient.csproj b/TodoListClient/TodoListClient.csproj index 894805b..ddd29ad 100644 --- a/TodoListClient/TodoListClient.csproj +++ b/TodoListClient/TodoListClient.csproj @@ -21,6 +21,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/TodoListClient/appsettings.json b/TodoListClient/appsettings.json index 21e7df9..eeeeab5 100644 --- a/TodoListClient/appsettings.json +++ b/TodoListClient/appsettings.json @@ -1,9 +1,9 @@ { "AzureAd": { "Instance": "https://login.microsoftonline.com/", - "Domain": "[Enter the domain of your tenant, e.g. contoso.onmicrosoft.com]", - "TenantId": "[Enter 'common', or 'organizations' or the Tenant Id (Obtained from the Azure portal. Select 'Endpoints' from the 'App registrations' blade and use the GUID in any of the URLs), e.g. da41245a5-11b3-996c-00a8-4d99re19f292]", - "ClientId": "[Enter the Client Id (Application ID obtained from the Azure portal), e.g. ba74781c2-53c2-442a-97c2-3d60re42f403]", + "Domain": "woodgrove.ms", + "TenantId": "536279f6-15cc-45f2-be2d-61e352b51eef", + "ClientId": "d56cce6d-baca-4f88-9e00-9bb11eb92b28", "CallbackPath": "/signin-oidc", "SignedOutCallbackPath ": "/signout-callback-oidc", @@ -11,7 +11,7 @@ "ClientCapabilities": [ "cp1" ], // To call an API - "ClientSecret": "[Copy the client secret added to the app from the Azure portal]", + "ClientSecret": "o9rMRJc4Wsp+TE5lxOpuoFM70r7JYSzPxNnoan1ZxRc=", "ClientCertificates": "[or Enter the certificate details]" }, "GraphBeta": { From cb8e3114451c9e7c14d61d72545019a0c954ab00 Mon Sep 17 00:00:00 2001 From: Alexander Beyderman Date: Mon, 27 Sep 2021 15:09:01 -0400 Subject: [PATCH 02/19] debugging bad user experience --- .../Controllers/TodoListController.cs | 2 ++ TodoListClient/TodoListClient.csproj | 11 +++++---- WebApp-Uses-CA-AuthContext.sln | 24 +++++++++++++++++++ 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/TodoListClient/Controllers/TodoListController.cs b/TodoListClient/Controllers/TodoListController.cs index 6464969..0ec08f5 100644 --- a/TodoListClient/Controllers/TodoListController.cs +++ b/TodoListClient/Controllers/TodoListController.cs @@ -89,6 +89,8 @@ public ActionResult Create([Bind("Title,Owner")] Todo todo) { string claimsChallenge = CheckForRequiredAuthContext(Request.Method); + //_postData = todo; + if (!string.IsNullOrWhiteSpace(claimsChallenge)) { _consentHandler.ChallengeUser(new string[] { "user.read" }, claimsChallenge); diff --git a/TodoListClient/TodoListClient.csproj b/TodoListClient/TodoListClient.csproj index ddd29ad..1b1e50b 100644 --- a/TodoListClient/TodoListClient.csproj +++ b/TodoListClient/TodoListClient.csproj @@ -25,16 +25,19 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - + - + + + + + diff --git a/WebApp-Uses-CA-AuthContext.sln b/WebApp-Uses-CA-AuthContext.sln index 36137c8..0268876 100644 --- a/WebApp-Uses-CA-AuthContext.sln +++ b/WebApp-Uses-CA-AuthContext.sln @@ -11,6 +11,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TodoListClient", "TodoListClient\TodoListClient.csproj", "{8F331CE4-767D-488D-A33B-E6F129ABC198}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Identity.Web", "..\..\AzureAD\microsoft-identity-web\src\Microsoft.Identity.Web\Microsoft.Identity.Web.csproj", "{FD55C071-48D1-4FE8-8B1D-773E067FEC91}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Identity.Web.UI", "..\..\AzureAD\microsoft-identity-web\src\Microsoft.Identity.Web.UI\Microsoft.Identity.Web.UI.csproj", "{20535D28-C2F4-4975-9982-A18E7141DA53}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Identity.Web.Certificate", "..\..\AzureAD\microsoft-identity-web\src\Microsoft.Identity.Web.Certificate\Microsoft.Identity.Web.Certificate.csproj", "{1E0B96CD-FDBF-482C-996A-775F691D984E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Identity.Web.TokenCache", "..\..\AzureAD\microsoft-identity-web\src\Microsoft.Identity.Web.TokenCache\Microsoft.Identity.Web.TokenCache.csproj", "{7885DFBB-0D20-4115-86E2-709C2E12253B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,6 +29,22 @@ Global {8F331CE4-767D-488D-A33B-E6F129ABC198}.Debug|Any CPU.Build.0 = Debug|Any CPU {8F331CE4-767D-488D-A33B-E6F129ABC198}.Release|Any CPU.ActiveCfg = Release|Any CPU {8F331CE4-767D-488D-A33B-E6F129ABC198}.Release|Any CPU.Build.0 = Release|Any CPU + {FD55C071-48D1-4FE8-8B1D-773E067FEC91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FD55C071-48D1-4FE8-8B1D-773E067FEC91}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FD55C071-48D1-4FE8-8B1D-773E067FEC91}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FD55C071-48D1-4FE8-8B1D-773E067FEC91}.Release|Any CPU.Build.0 = Release|Any CPU + {20535D28-C2F4-4975-9982-A18E7141DA53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {20535D28-C2F4-4975-9982-A18E7141DA53}.Debug|Any CPU.Build.0 = Debug|Any CPU + {20535D28-C2F4-4975-9982-A18E7141DA53}.Release|Any CPU.ActiveCfg = Release|Any CPU + {20535D28-C2F4-4975-9982-A18E7141DA53}.Release|Any CPU.Build.0 = Release|Any CPU + {1E0B96CD-FDBF-482C-996A-775F691D984E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1E0B96CD-FDBF-482C-996A-775F691D984E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1E0B96CD-FDBF-482C-996A-775F691D984E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1E0B96CD-FDBF-482C-996A-775F691D984E}.Release|Any CPU.Build.0 = Release|Any CPU + {7885DFBB-0D20-4115-86E2-709C2E12253B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7885DFBB-0D20-4115-86E2-709C2E12253B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7885DFBB-0D20-4115-86E2-709C2E12253B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7885DFBB-0D20-4115-86E2-709C2E12253B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 96c1943e43de10c80e3905368eaa848b73b7c4a1 Mon Sep 17 00:00:00 2001 From: Alexander Beyderman Date: Tue, 7 Dec 2021 16:43:01 -0500 Subject: [PATCH 03/19] latest publish to Woodgrove --- TodoListClient/Controllers/AdminController.cs | 12 +- .../mssql1.arm.json | 82 +++++++++++++ .../profile.arm.json | 113 ++++++++++++++++++ ...cies.TodoListClient-Test - Web Deploy.json | 10 ++ TodoListClient/TodoListClient.csproj | 7 +- TodoListClient/Views/Admin/Index.cshtml | 5 + TodoListClient/Views/Admin/ViewDetails.cshtml | 2 +- TodoListClient/Views/Home/Index.cshtml | 4 + TodoListClient/appsettings.json | 4 +- WebApp-Uses-CA-AuthContext.sln | 24 ---- 10 files changed, 232 insertions(+), 31 deletions(-) create mode 100644 TodoListClient/Properties/ServiceDependencies/TodoListClient-Test - Web Deploy/mssql1.arm.json create mode 100644 TodoListClient/Properties/ServiceDependencies/TodoListClient-Test - Web Deploy/profile.arm.json create mode 100644 TodoListClient/Properties/serviceDependencies.TodoListClient-Test - Web Deploy.json diff --git a/TodoListClient/Controllers/AdminController.cs b/TodoListClient/Controllers/AdminController.cs index 3273810..de41006 100644 --- a/TodoListClient/Controllers/AdminController.cs +++ b/TodoListClient/Controllers/AdminController.cs @@ -125,12 +125,22 @@ public IActionResult ViewDetails() return View(authContexts); } + /// + /// Delete an configuration item by key + /// + /// Always will be in form of AuthContextId_Operation + /// public ActionResult Delete(string id) { + var authContextId = id.Split("_")[0]; + var operationName = id.Split("_")[1]; + AuthContext authContext = null; using (var commonDBContext = new CommonDBContext(_configuration)) { - authContext = commonDBContext.AuthContext.FirstOrDefault(x => x.AuthContextId == id && x.TenantId == TenantId); + authContext = commonDBContext + .AuthContext + .FirstOrDefault(x => x.AuthContextId == authContextId && x.Operation == operationName && x.TenantId == TenantId); } return View(authContext); } diff --git a/TodoListClient/Properties/ServiceDependencies/TodoListClient-Test - Web Deploy/mssql1.arm.json b/TodoListClient/Properties/ServiceDependencies/TodoListClient-Test - Web Deploy/mssql1.arm.json new file mode 100644 index 0000000..f11fdc0 --- /dev/null +++ b/TodoListClient/Properties/ServiceDependencies/TodoListClient-Test - Web Deploy/mssql1.arm.json @@ -0,0 +1,82 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "resourceGroupName": { + "type": "string", + "defaultValue": "Thefirstresourcegroup", + "metadata": { + "_parameterType": "resourceGroup", + "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." + } + }, + "resourceGroupLocation": { + "type": "string", + "defaultValue": "eastus", + "metadata": { + "_parameterType": "location", + "description": "Location of the resource group. Resource groups could have different location than resources." + } + }, + "resourceLocation": { + "type": "string", + "defaultValue": "[parameters('resourceGroupLocation')]", + "metadata": { + "_parameterType": "location", + "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." + } + } + }, + "resources": [ + { + "type": "Microsoft.Resources/resourceGroups", + "name": "[parameters('resourceGroupName')]", + "location": "[parameters('resourceGroupLocation')]", + "apiVersion": "2019-10-01" + }, + { + "type": "Microsoft.Resources/deployments", + "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat('TodoListClient_db', subscription().subscriptionId)))]", + "resourceGroup": "[parameters('resourceGroupName')]", + "apiVersion": "2019-10-01", + "dependsOn": [ + "[parameters('resourceGroupName')]" + ], + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "kind": "v12.0", + "location": "[parameters('resourceLocation')]", + "name": "todolistclientdbserver", + "type": "Microsoft.Sql/servers", + "apiVersion": "2017-10-01-preview" + }, + { + "sku": { + "name": "GP_S_Gen5", + "tier": "GeneralPurpose", + "family": "Gen5", + "capacity": 1 + }, + "kind": "v12.0,user,vcore,serverless", + "location": "[parameters('resourceLocation')]", + "name": "todolistclientdbserver/TodoListClient_db", + "type": "Microsoft.Sql/servers/databases", + "apiVersion": "2017-10-01-preview", + "dependsOn": [ + "todolistclientdbserver" + ] + } + ] + } + } + } + ], + "metadata": { + "_dependencyType": "mssql.azure" + } +} \ No newline at end of file diff --git a/TodoListClient/Properties/ServiceDependencies/TodoListClient-Test - Web Deploy/profile.arm.json b/TodoListClient/Properties/ServiceDependencies/TodoListClient-Test - Web Deploy/profile.arm.json new file mode 100644 index 0000000..f17a0b6 --- /dev/null +++ b/TodoListClient/Properties/ServiceDependencies/TodoListClient-Test - Web Deploy/profile.arm.json @@ -0,0 +1,113 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_dependencyType": "appService.windows" + }, + "parameters": { + "resourceGroupName": { + "type": "string", + "defaultValue": "Thefirstresourcegroup", + "metadata": { + "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." + } + }, + "resourceGroupLocation": { + "type": "string", + "defaultValue": "eastus", + "metadata": { + "description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support." + } + }, + "resourceName": { + "type": "string", + "defaultValue": "TodoListClient-Test", + "metadata": { + "description": "Name of the main resource to be created by this template." + } + }, + "resourceLocation": { + "type": "string", + "defaultValue": "[parameters('resourceGroupLocation')]", + "metadata": { + "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." + } + } + }, + "variables": { + "appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", + "appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]" + }, + "resources": [ + { + "type": "Microsoft.Resources/resourceGroups", + "name": "[parameters('resourceGroupName')]", + "location": "[parameters('resourceGroupLocation')]", + "apiVersion": "2019-10-01" + }, + { + "type": "Microsoft.Resources/deployments", + "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", + "resourceGroup": "[parameters('resourceGroupName')]", + "apiVersion": "2019-10-01", + "dependsOn": [ + "[parameters('resourceGroupName')]" + ], + "properties": { + "mode": "Incremental", + "template": { + "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "location": "[parameters('resourceLocation')]", + "name": "[parameters('resourceName')]", + "type": "Microsoft.Web/sites", + "apiVersion": "2015-08-01", + "tags": { + "[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty" + }, + "dependsOn": [ + "[variables('appServicePlan_ResourceId')]" + ], + "kind": "app", + "properties": { + "name": "[parameters('resourceName')]", + "kind": "app", + "httpsOnly": true, + "reserved": false, + "serverFarmId": "[variables('appServicePlan_ResourceId')]", + "siteConfig": { + "metadata": [ + { + "name": "CURRENT_STACK", + "value": "dotnetcore" + } + ] + } + }, + "identity": { + "type": "SystemAssigned" + } + }, + { + "location": "[parameters('resourceLocation')]", + "name": "[variables('appServicePlan_name')]", + "type": "Microsoft.Web/serverFarms", + "apiVersion": "2015-08-01", + "sku": { + "name": "S1", + "tier": "Standard", + "family": "S", + "size": "S1" + }, + "properties": { + "name": "[variables('appServicePlan_name')]" + } + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/TodoListClient/Properties/serviceDependencies.TodoListClient-Test - Web Deploy.json b/TodoListClient/Properties/serviceDependencies.TodoListClient-Test - Web Deploy.json new file mode 100644 index 0000000..594e299 --- /dev/null +++ b/TodoListClient/Properties/serviceDependencies.TodoListClient-Test - Web Deploy.json @@ -0,0 +1,10 @@ +{ + "dependencies": { + "mssql1": { + "resourceId": "/subscriptions/[parameters('subscriptionId')]/resourceGroups/[parameters('resourceGroupName')]/providers/Microsoft.Sql/servers/todolistclientdbserver/databases/TodoListClient_db", + "type": "mssql.azure", + "connectionId": "ConnectionStrings:DefaultConnection", + "secretStore": "AzureAppSettings" + } + } +} \ No newline at end of file diff --git a/TodoListClient/TodoListClient.csproj b/TodoListClient/TodoListClient.csproj index 1b1e50b..6ad077c 100644 --- a/TodoListClient/TodoListClient.csproj +++ b/TodoListClient/TodoListClient.csproj @@ -27,15 +27,16 @@ - + + + - - + diff --git a/TodoListClient/Views/Admin/Index.cshtml b/TodoListClient/Views/Admin/Index.cshtml index 7fc963b..c8c4396 100644 --- a/TodoListClient/Views/Admin/Index.cshtml +++ b/TodoListClient/Views/Admin/Index.cshtml @@ -3,6 +3,11 @@ ViewData["Title"] = "Index"; } +
+
+

Configure Azure AD Step-up authentication

+
+

Admin

Select Create Or Fetch button to perform following steps: diff --git a/TodoListClient/Views/Admin/ViewDetails.cshtml b/TodoListClient/Views/Admin/ViewDetails.cshtml index dc2aff8..59dac81 100644 --- a/TodoListClient/Views/Admin/ViewDetails.cshtml +++ b/TodoListClient/Views/Admin/ViewDetails.cshtml @@ -43,7 +43,7 @@ @item.Operation - @Html.ActionLink("Delete", "Delete", new { id = @item.AuthContextId }) + @Html.ActionLink("Delete", "Delete", new { id = @item.AuthContextId + "_" + @item.Operation }) diff --git a/TodoListClient/Views/Home/Index.cshtml b/TodoListClient/Views/Home/Index.cshtml index 6fb485b..9ce2e52 100644 --- a/TodoListClient/Views/Home/Index.cshtml +++ b/TodoListClient/Views/Home/Index.cshtml @@ -1,6 +1,10 @@ @{ ViewData["Title"] = "Home Page"; } +
+
+

Microsoft Azure AD Step-up authentication demo

+
@if (!User.Identity.IsAuthenticated) {

diff --git a/TodoListClient/appsettings.json b/TodoListClient/appsettings.json index eeeeab5..f21bf2c 100644 --- a/TodoListClient/appsettings.json +++ b/TodoListClient/appsettings.json @@ -3,7 +3,7 @@ "Instance": "https://login.microsoftonline.com/", "Domain": "woodgrove.ms", "TenantId": "536279f6-15cc-45f2-be2d-61e352b51eef", - "ClientId": "d56cce6d-baca-4f88-9e00-9bb11eb92b28", + "ClientId": "95e3ec56-1a5e-42c8-b88b-68fa26cca5b2", "CallbackPath": "/signin-oidc", "SignedOutCallbackPath ": "/signout-callback-oidc", @@ -11,7 +11,7 @@ "ClientCapabilities": [ "cp1" ], // To call an API - "ClientSecret": "o9rMRJc4Wsp+TE5lxOpuoFM70r7JYSzPxNnoan1ZxRc=", + "ClientSecret": "O4k7Q~sjVge64sVD-YnXxrqLO~Dlnl2RpJMdq", "ClientCertificates": "[or Enter the certificate details]" }, "GraphBeta": { diff --git a/WebApp-Uses-CA-AuthContext.sln b/WebApp-Uses-CA-AuthContext.sln index 0268876..36137c8 100644 --- a/WebApp-Uses-CA-AuthContext.sln +++ b/WebApp-Uses-CA-AuthContext.sln @@ -11,14 +11,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TodoListClient", "TodoListClient\TodoListClient.csproj", "{8F331CE4-767D-488D-A33B-E6F129ABC198}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Identity.Web", "..\..\AzureAD\microsoft-identity-web\src\Microsoft.Identity.Web\Microsoft.Identity.Web.csproj", "{FD55C071-48D1-4FE8-8B1D-773E067FEC91}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Identity.Web.UI", "..\..\AzureAD\microsoft-identity-web\src\Microsoft.Identity.Web.UI\Microsoft.Identity.Web.UI.csproj", "{20535D28-C2F4-4975-9982-A18E7141DA53}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Identity.Web.Certificate", "..\..\AzureAD\microsoft-identity-web\src\Microsoft.Identity.Web.Certificate\Microsoft.Identity.Web.Certificate.csproj", "{1E0B96CD-FDBF-482C-996A-775F691D984E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Identity.Web.TokenCache", "..\..\AzureAD\microsoft-identity-web\src\Microsoft.Identity.Web.TokenCache\Microsoft.Identity.Web.TokenCache.csproj", "{7885DFBB-0D20-4115-86E2-709C2E12253B}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -29,22 +21,6 @@ Global {8F331CE4-767D-488D-A33B-E6F129ABC198}.Debug|Any CPU.Build.0 = Debug|Any CPU {8F331CE4-767D-488D-A33B-E6F129ABC198}.Release|Any CPU.ActiveCfg = Release|Any CPU {8F331CE4-767D-488D-A33B-E6F129ABC198}.Release|Any CPU.Build.0 = Release|Any CPU - {FD55C071-48D1-4FE8-8B1D-773E067FEC91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FD55C071-48D1-4FE8-8B1D-773E067FEC91}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FD55C071-48D1-4FE8-8B1D-773E067FEC91}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FD55C071-48D1-4FE8-8B1D-773E067FEC91}.Release|Any CPU.Build.0 = Release|Any CPU - {20535D28-C2F4-4975-9982-A18E7141DA53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {20535D28-C2F4-4975-9982-A18E7141DA53}.Debug|Any CPU.Build.0 = Debug|Any CPU - {20535D28-C2F4-4975-9982-A18E7141DA53}.Release|Any CPU.ActiveCfg = Release|Any CPU - {20535D28-C2F4-4975-9982-A18E7141DA53}.Release|Any CPU.Build.0 = Release|Any CPU - {1E0B96CD-FDBF-482C-996A-775F691D984E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1E0B96CD-FDBF-482C-996A-775F691D984E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1E0B96CD-FDBF-482C-996A-775F691D984E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1E0B96CD-FDBF-482C-996A-775F691D984E}.Release|Any CPU.Build.0 = Release|Any CPU - {7885DFBB-0D20-4115-86E2-709C2E12253B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7885DFBB-0D20-4115-86E2-709C2E12253B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7885DFBB-0D20-4115-86E2-709C2E12253B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7885DFBB-0D20-4115-86E2-709C2E12253B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 977f98897c1562d54dc0b80c1650572945993b82 Mon Sep 17 00:00:00 2001 From: Alexander Beyderman Date: Tue, 15 Mar 2022 13:40:47 -0400 Subject: [PATCH 04/19] improved UI, fixed challenge user flow for all actions, cleanup/refactoring --- .../Controllers/TodoListController.cs | 133 +++++++++++++----- TodoListClient/Models/TodoItem.cs | 4 +- TodoListClient/Views/TodoList/Delete.cshtml | 3 +- TodoListClient/Views/TodoList/Details.cshtml | 6 +- TodoListClient/Views/TodoList/Edit.cshtml | 9 +- 5 files changed, 111 insertions(+), 44 deletions(-) diff --git a/TodoListClient/Controllers/TodoListController.cs b/TodoListClient/Controllers/TodoListController.cs index fbfaf2f..58d5b4b 100644 --- a/TodoListClient/Controllers/TodoListController.cs +++ b/TodoListClient/Controllers/TodoListController.cs @@ -58,27 +58,26 @@ public ActionResult Details(int id) // GET: TodoList/Create public ActionResult Create() { - string claimsChallenge = CheckForRequiredAuthContext(Request.Method); - - if (!string.IsNullOrWhiteSpace(claimsChallenge)) + if (ChallengeUser(Request.Method)) { - _consentHandler.ChallengeUser(new string[] { "user.read" }, claimsChallenge); - - return new EmptyResult(); + return RedirectToAction("Create"); } - var todoObject = TodoSessionState(SessionAction.Get); + //get todo from session state (if available then this means we were redirected from POST and have to save this todo) + var todoFromSessionState = TodoSessionState(SessionAction.Get); - if (todoObject != null && todoObject.IsInitialized()) + if (todoFromSessionState != null && todoFromSessionState.IsInitialized) { - PersistTodo(todoObject); + SaveToDatabase(todoFromSessionState); + //clean session state TodoSessionState(SessionAction.Set); return RedirectToAction("Index"); } Todo todo = new Todo() { Owner = HttpContext.User.Identity.Name }; + return View(todo); } @@ -87,20 +86,19 @@ public ActionResult Create() [ValidateAntiForgeryToken] public ActionResult Create([Bind("Title,Owner")] Todo todo) { + //add owner accountid to new todo todo.AccountId = HttpContext.User.GetMsalAccountId(); + todo.Owner = HttpContext.User.Identity.Name; - string claimsChallenge = CheckForRequiredAuthContext(Request.Method); - - if (!string.IsNullOrWhiteSpace(claimsChallenge)) + if (ChallengeUser(Request.Method)) { - _consentHandler.ChallengeUser(new string[] { "user.read" }, claimsChallenge); - + //save in session state before redirecting to GET handler TodoSessionState(SessionAction.Set, todo); - return new EmptyResult(); + return RedirectToAction("Create"); } - PersistTodo(new Todo() { Owner = HttpContext.User.Identity.Name, Title = todo.Title, AccountId = todo.AccountId }); + SaveToDatabase(new Todo() { Owner = todo.Owner, Title = todo.Title, AccountId = todo.AccountId }); return RedirectToAction("Index"); } @@ -108,7 +106,22 @@ public ActionResult Create([Bind("Title,Owner")] Todo todo) // GET: TodoList/Edit/5 public ActionResult Edit(int id) { - return View(_commonDBContext.Todo.FirstOrDefault(t => t.Id == id)); + //get todo from session state (if available then this means we were redirected from POST and have to update this todo) + var todoFromSessionState = TodoSessionState(SessionAction.Get); + + if (todoFromSessionState != null && todoFromSessionState.IsInitialized && todoFromSessionState.Id == id) + { + UpdateDatabase(todoFromSessionState); + + //clean session state + TodoSessionState(SessionAction.Set); + + return RedirectToAction("Index"); + } + else + { + return View(_commonDBContext.Todo.FirstOrDefault(t => t.Id == id)); + } } // POST: TodoList/Edit/5 @@ -116,7 +129,6 @@ public ActionResult Edit(int id) [ValidateAntiForgeryToken] public ActionResult Edit(int id, [Bind("Id,Title,Owner")] Todo todo) { - //await _todoListService.EditAsync(todo); if (id != todo.Id) { return NotFound(); @@ -124,8 +136,15 @@ public ActionResult Edit(int id, [Bind("Id,Title,Owner")] Todo todo) todo.AccountId = HttpContext.User.GetMsalAccountId(); - _commonDBContext.Todo.Update(todo); - _commonDBContext.SaveChanges(); + if (ChallengeUser(Request.Method)) + { + //save in session state before redirecting to GET handler + TodoSessionState(SessionAction.Set, todo); + + return RedirectToAction("Edit"); + } + + UpdateDatabase(todo); return RedirectToAction("Index"); } @@ -133,7 +152,22 @@ public ActionResult Edit(int id, [Bind("Id,Title,Owner")] Todo todo) // GET: TodoList/Delete/5 public ActionResult Delete(int id) { - return View(_commonDBContext.Todo.FirstOrDefault(t => t.Id == id)); + //get todo from session state (if available then this means we were redirected from POST and have to save this todo) + var todoFromSessionState = TodoSessionState(SessionAction.Get); + + if (todoFromSessionState != null && todoFromSessionState.Id == id) + { + DeleteFromDatabase(todoFromSessionState); + + //clean session state + TodoSessionState(SessionAction.Set); + + return RedirectToAction("Index"); + } + else + { + return View(_commonDBContext.Todo.FirstOrDefault(t => t.Id == id)); + } } // POST: TodoList/Delete/5 @@ -141,19 +175,19 @@ public ActionResult Delete(int id) [ValidateAntiForgeryToken] public ActionResult Delete(int id, [Bind("Id,Title,Owner")] Todo todo) { - string claimsChallenge = CheckForRequiredAuthContext("Delete"); - - if (!string.IsNullOrWhiteSpace(claimsChallenge)) + if (ChallengeUser(HttpMethods.Delete)) { - _consentHandler.ChallengeUser(new string[] { "user.read" }, claimsChallenge); - return new EmptyResult(); + //save in session state before redirecting to GET handler + TodoSessionState(SessionAction.Set, new Todo { Id = id }); + + return RedirectToAction("Delete"); } - var todo2 = _commonDBContext.Todo.Find(id); - if (todo2 != null) + //make sure the received todo is inside database before deleting + var todoFromDb = _commonDBContext.Todo.Find(id); + if (todoFromDb != null) { - _commonDBContext.Todo.Remove(todo2); - _commonDBContext.SaveChanges(); + DeleteFromDatabase(todoFromDb); } return RedirectToAction("Index"); @@ -188,16 +222,27 @@ public string CheckForRequiredAuthContext(string method) if (acrsClaim?.Value != savedAuthContextId) { claimsChallenge = "{\"id_token\":{\"acrs\":{\"essential\":true,\"value\":\"" + savedAuthContextId + "\"}}}"; - } } return claimsChallenge; } - private void PersistTodo(Todo todo) + private void DeleteFromDatabase(Todo todoToRemove) + { + _commonDBContext.Todo.Remove(todoToRemove); + _commonDBContext.SaveChanges(); + } + + private void SaveToDatabase(Todo todoToSave) + { + _commonDBContext.Todo.Add(todoToSave); + _commonDBContext.SaveChanges(); + } + + private void UpdateDatabase(Todo todoToUpdate) { - _commonDBContext.Todo.Add(todo); + _commonDBContext.Todo.Update(todoToUpdate); _commonDBContext.SaveChanges(); } @@ -227,6 +272,28 @@ private Todo TodoSessionState(SessionAction action, Todo todo = null) return todo; } + ///

+ /// Create a user challenge for the specified scope if it was requested by CAE + /// + /// + /// + private bool ChallengeUser(string actionName) + { + string claimsChallenge = CheckForRequiredAuthContext(actionName); + + if (!string.IsNullOrWhiteSpace(claimsChallenge)) + { + _consentHandler.ChallengeUser(new string[] { "user.read" }, claimsChallenge); + + return true; + } + + return false; + } + + /// + /// Enumerator to distingush between session state actions + /// private enum SessionAction { Set, diff --git a/TodoListClient/Models/TodoItem.cs b/TodoListClient/Models/TodoItem.cs index 0cab635..3949e7c 100644 --- a/TodoListClient/Models/TodoItem.cs +++ b/TodoListClient/Models/TodoItem.cs @@ -12,9 +12,9 @@ public class Todo public string AccountId { get; set; } //Return true only if both Title and Owners are not empty strings - public bool IsInitialized() + public bool IsInitialized { - return !string.IsNullOrEmpty(Title) && !string.IsNullOrEmpty(Owner) && !string.IsNullOrEmpty(AccountId); + get { return !string.IsNullOrEmpty(Title) && !string.IsNullOrEmpty(Owner) && !string.IsNullOrEmpty(AccountId); } } } } diff --git a/TodoListClient/Views/TodoList/Delete.cshtml b/TodoListClient/Views/TodoList/Delete.cshtml index b2f304c..f7b6148 100644 --- a/TodoListClient/Views/TodoList/Delete.cshtml +++ b/TodoListClient/Views/TodoList/Delete.cshtml @@ -1,10 +1,9 @@ @model TodoListClient.Models.Todo - @{ ViewData["Title"] = "Delete"; } -

Delete ToDo

+

Delete ToDo

Are you sure you want to delete this?

diff --git a/TodoListClient/Views/TodoList/Details.cshtml b/TodoListClient/Views/TodoList/Details.cshtml index 0261e67..93a833b 100644 --- a/TodoListClient/Views/TodoList/Details.cshtml +++ b/TodoListClient/Views/TodoList/Details.cshtml @@ -2,12 +2,16 @@ @{ ViewData["Title"] = "Details"; + var todoId = Model.Id; }

ToDo Details

- Create New + @Html.ActionLink("Create","Create") | + @Html.ActionLink("Back to List", "Index") | + @Html.ActionLink("Edit", "Edit", new { id = todoId }) | + @Html.ActionLink("Delete", "Delete", new { id = todoId })

diff --git a/TodoListClient/Views/TodoList/Edit.cshtml b/TodoListClient/Views/TodoList/Edit.cshtml index 98927a8..3a505ca 100644 --- a/TodoListClient/Views/TodoList/Edit.cshtml +++ b/TodoListClient/Views/TodoList/Edit.cshtml @@ -5,7 +5,7 @@

Edit ToDo

-
+
@@ -20,12 +20,9 @@
- + | + Back to List
- - From a8d5c9f293a8667b718d6e4da26579672dd5144a Mon Sep 17 00:00:00 2001 From: Alexander Beyderman Date: Wed, 1 Jun 2022 12:14:09 -0400 Subject: [PATCH 05/19] reset for appsetting.json --- TodoListClient/appsettings.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/TodoListClient/appsettings.json b/TodoListClient/appsettings.json index f21bf2c..4839d09 100644 --- a/TodoListClient/appsettings.json +++ b/TodoListClient/appsettings.json @@ -1,9 +1,9 @@ { "AzureAd": { "Instance": "https://login.microsoftonline.com/", - "Domain": "woodgrove.ms", - "TenantId": "536279f6-15cc-45f2-be2d-61e352b51eef", - "ClientId": "95e3ec56-1a5e-42c8-b88b-68fa26cca5b2", + "Domain": "[Enter the domain of your tenant, e.g. contoso.onmicrosoft.com]", + "TenantId": "[Enter 'common', or 'organizations' or the Tenant Id (Obtained from the Azure portal. Select 'Endpoints' from the 'App registrations' blade and use the GUID in any of the URLs), e.g. da41245a5-11b3-996c-00a8-4d99re19f292]", + "ClientId": "[Enter the Client Id (Application ID obtained from the Azure portal), e.g. ba74781c2-53c2-442a-97c2-3d60re42f403]", "CallbackPath": "/signin-oidc", "SignedOutCallbackPath ": "/signout-callback-oidc", @@ -11,7 +11,7 @@ "ClientCapabilities": [ "cp1" ], // To call an API - "ClientSecret": "O4k7Q~sjVge64sVD-YnXxrqLO~Dlnl2RpJMdq", + "ClientSecret": "[Copy the client secret added to the app from the Azure portal]", "ClientCertificates": "[or Enter the certificate details]" }, "GraphBeta": { @@ -19,7 +19,7 @@ "Scopes": "Policy.Read.ConditionalAccess Policy.ReadWrite.ConditionalAccess" }, "ConnectionStrings": { - "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=CommonDBContext;Trusted_Connection=True;MultipleActiveResultSets=true" + "DefaultConnection": "your database connection string here" }, "Logging": { "LogLevel": { From 69650874c07639dcb3314c748dbbb3c425ea1844 Mon Sep 17 00:00:00 2001 From: Alexander Beyderman Date: Wed, 1 Jun 2022 12:15:42 -0400 Subject: [PATCH 06/19] updated appsettings.json for pulish to Azure --- TodoListClient/appsettings.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/TodoListClient/appsettings.json b/TodoListClient/appsettings.json index 4839d09..f21bf2c 100644 --- a/TodoListClient/appsettings.json +++ b/TodoListClient/appsettings.json @@ -1,9 +1,9 @@ { "AzureAd": { "Instance": "https://login.microsoftonline.com/", - "Domain": "[Enter the domain of your tenant, e.g. contoso.onmicrosoft.com]", - "TenantId": "[Enter 'common', or 'organizations' or the Tenant Id (Obtained from the Azure portal. Select 'Endpoints' from the 'App registrations' blade and use the GUID in any of the URLs), e.g. da41245a5-11b3-996c-00a8-4d99re19f292]", - "ClientId": "[Enter the Client Id (Application ID obtained from the Azure portal), e.g. ba74781c2-53c2-442a-97c2-3d60re42f403]", + "Domain": "woodgrove.ms", + "TenantId": "536279f6-15cc-45f2-be2d-61e352b51eef", + "ClientId": "95e3ec56-1a5e-42c8-b88b-68fa26cca5b2", "CallbackPath": "/signin-oidc", "SignedOutCallbackPath ": "/signout-callback-oidc", @@ -11,7 +11,7 @@ "ClientCapabilities": [ "cp1" ], // To call an API - "ClientSecret": "[Copy the client secret added to the app from the Azure portal]", + "ClientSecret": "O4k7Q~sjVge64sVD-YnXxrqLO~Dlnl2RpJMdq", "ClientCertificates": "[or Enter the certificate details]" }, "GraphBeta": { @@ -19,7 +19,7 @@ "Scopes": "Policy.Read.ConditionalAccess Policy.ReadWrite.ConditionalAccess" }, "ConnectionStrings": { - "DefaultConnection": "your database connection string here" + "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=CommonDBContext;Trusted_Connection=True;MultipleActiveResultSets=true" }, "Logging": { "LogLevel": { From 77eeca00d358a90b829e0a8e60f30bde0837d2f1 Mon Sep 17 00:00:00 2001 From: Alexander Beyderman Date: Wed, 1 Jun 2022 12:51:29 -0400 Subject: [PATCH 07/19] updated packages --- .../profile.arm.json | 113 ++++++++++++++++++ TodoListClient/TodoListClient.csproj | 16 +-- 2 files changed, 121 insertions(+), 8 deletions(-) create mode 100644 TodoListClient/Properties/ServiceDependencies/AlexToDoListTest - Web Deploy/profile.arm.json diff --git a/TodoListClient/Properties/ServiceDependencies/AlexToDoListTest - Web Deploy/profile.arm.json b/TodoListClient/Properties/ServiceDependencies/AlexToDoListTest - Web Deploy/profile.arm.json new file mode 100644 index 0000000..856593c --- /dev/null +++ b/TodoListClient/Properties/ServiceDependencies/AlexToDoListTest - Web Deploy/profile.arm.json @@ -0,0 +1,113 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_dependencyType": "compute.appService.windows" + }, + "parameters": { + "resourceGroupName": { + "type": "string", + "defaultValue": "Thefirstresourcegroup", + "metadata": { + "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." + } + }, + "resourceGroupLocation": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support." + } + }, + "resourceName": { + "type": "string", + "defaultValue": "AlexToDoListTest", + "metadata": { + "description": "Name of the main resource to be created by this template." + } + }, + "resourceLocation": { + "type": "string", + "defaultValue": "[parameters('resourceGroupLocation')]", + "metadata": { + "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." + } + } + }, + "variables": { + "appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", + "appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]" + }, + "resources": [ + { + "type": "Microsoft.Resources/resourceGroups", + "name": "[parameters('resourceGroupName')]", + "location": "[parameters('resourceGroupLocation')]", + "apiVersion": "2019-10-01" + }, + { + "type": "Microsoft.Resources/deployments", + "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", + "resourceGroup": "[parameters('resourceGroupName')]", + "apiVersion": "2019-10-01", + "dependsOn": [ + "[parameters('resourceGroupName')]" + ], + "properties": { + "mode": "Incremental", + "template": { + "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "location": "[parameters('resourceLocation')]", + "name": "[parameters('resourceName')]", + "type": "Microsoft.Web/sites", + "apiVersion": "2015-08-01", + "tags": { + "[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty" + }, + "dependsOn": [ + "[variables('appServicePlan_ResourceId')]" + ], + "kind": "app", + "properties": { + "name": "[parameters('resourceName')]", + "kind": "app", + "httpsOnly": true, + "reserved": false, + "serverFarmId": "[variables('appServicePlan_ResourceId')]", + "siteConfig": { + "metadata": [ + { + "name": "CURRENT_STACK", + "value": "dotnetcore" + } + ] + } + }, + "identity": { + "type": "SystemAssigned" + } + }, + { + "location": "[parameters('resourceLocation')]", + "name": "[variables('appServicePlan_name')]", + "type": "Microsoft.Web/serverFarms", + "apiVersion": "2015-08-01", + "sku": { + "name": "S1", + "tier": "Standard", + "family": "S", + "size": "S1" + }, + "properties": { + "name": "[variables('appServicePlan_name')]" + } + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/TodoListClient/TodoListClient.csproj b/TodoListClient/TodoListClient.csproj index 81c7b99..f42b702 100644 --- a/TodoListClient/TodoListClient.csproj +++ b/TodoListClient/TodoListClient.csproj @@ -18,16 +18,16 @@ - + - - + + - - - - - + + + + + From 050e49f57a80226e0695358836168e1728268f68 Mon Sep 17 00:00:00 2001 From: Alexander Beyderman Date: Wed, 1 Jun 2022 13:40:07 -0400 Subject: [PATCH 08/19] updated publish settings --- .../Properties/PublishProfiles/Woodgrove Deploy.pubxml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/TodoListClient/Properties/PublishProfiles/Woodgrove Deploy.pubxml b/TodoListClient/Properties/PublishProfiles/Woodgrove Deploy.pubxml index 3cfe0b4..8458e54 100644 --- a/TodoListClient/Properties/PublishProfiles/Woodgrove Deploy.pubxml +++ b/TodoListClient/Properties/PublishProfiles/Woodgrove Deploy.pubxml @@ -18,7 +18,7 @@ by editing this MSBuild file. In order to learn more about this please visit htt authcontextdotnetapp.scm.azurewebsites.net:443 AuthContextDotNetApp - true + false WMSVC true true @@ -26,5 +26,7 @@ by editing this MSBuild file. In order to learn more about this please visit htt <_SavePWD>true <_DestinationType>AzureWebSite false + net6.0 + false \ No newline at end of file From 0199c48b33e014c414a3476f69f1010e0045e901 Mon Sep 17 00:00:00 2001 From: Alexander Beyderman Date: Wed, 1 Jun 2022 15:02:09 -0400 Subject: [PATCH 09/19] Revert "updated appsettings.json for pulish to Azure" This reverts commit 69650874c07639dcb3314c748dbbb3c425ea1844. --- TodoListClient/appsettings.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/TodoListClient/appsettings.json b/TodoListClient/appsettings.json index f21bf2c..4839d09 100644 --- a/TodoListClient/appsettings.json +++ b/TodoListClient/appsettings.json @@ -1,9 +1,9 @@ { "AzureAd": { "Instance": "https://login.microsoftonline.com/", - "Domain": "woodgrove.ms", - "TenantId": "536279f6-15cc-45f2-be2d-61e352b51eef", - "ClientId": "95e3ec56-1a5e-42c8-b88b-68fa26cca5b2", + "Domain": "[Enter the domain of your tenant, e.g. contoso.onmicrosoft.com]", + "TenantId": "[Enter 'common', or 'organizations' or the Tenant Id (Obtained from the Azure portal. Select 'Endpoints' from the 'App registrations' blade and use the GUID in any of the URLs), e.g. da41245a5-11b3-996c-00a8-4d99re19f292]", + "ClientId": "[Enter the Client Id (Application ID obtained from the Azure portal), e.g. ba74781c2-53c2-442a-97c2-3d60re42f403]", "CallbackPath": "/signin-oidc", "SignedOutCallbackPath ": "/signout-callback-oidc", @@ -11,7 +11,7 @@ "ClientCapabilities": [ "cp1" ], // To call an API - "ClientSecret": "O4k7Q~sjVge64sVD-YnXxrqLO~Dlnl2RpJMdq", + "ClientSecret": "[Copy the client secret added to the app from the Azure portal]", "ClientCertificates": "[or Enter the certificate details]" }, "GraphBeta": { @@ -19,7 +19,7 @@ "Scopes": "Policy.Read.ConditionalAccess Policy.ReadWrite.ConditionalAccess" }, "ConnectionStrings": { - "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=CommonDBContext;Trusted_Connection=True;MultipleActiveResultSets=true" + "DefaultConnection": "your database connection string here" }, "Logging": { "LogLevel": { From a796faa2f55b8cb335393adbf9066a1f546b0d2c Mon Sep 17 00:00:00 2001 From: Alexander Beyderman Date: Fri, 10 Jun 2022 12:49:16 -0400 Subject: [PATCH 10/19] updated retry when database have to wake up --- .../Controllers/TodoListController.cs | 20 ++++++++++++++++++- TodoListClient/Startup.cs | 20 +++++++++++++++++-- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/TodoListClient/Controllers/TodoListController.cs b/TodoListClient/Controllers/TodoListController.cs index 58d5b4b..99ee8d1 100644 --- a/TodoListClient/Controllers/TodoListController.cs +++ b/TodoListClient/Controllers/TodoListController.cs @@ -46,7 +46,25 @@ public ActionResult Index() //reset session on every entry to TODO's list TodoSessionState(SessionAction.Set); - return View(_commonDBContext.Todo.Where(l => l.AccountId.Equals(HttpContext.User.GetMsalAccountId())).ToList()); + //serveless database should have time to wake up + var retryTimes = 3; + while (retryTimes-- > 0) + { + try + { + return View(_commonDBContext.Todo.Where(l => l.AccountId.Equals(HttpContext.User.GetMsalAccountId())).ToList()); + } + catch (Exception) + { + //throw exception if database didn't wakeup after 3 attempts + if (retryTimes == 0) + { + throw; + } + } + } + + return View(); } // GET: TodoList/Details/5 diff --git a/TodoListClient/Startup.cs b/TodoListClient/Startup.cs index 6f99a12..2ad0de9 100644 --- a/TodoListClient/Startup.cs +++ b/TodoListClient/Startup.cs @@ -89,8 +89,24 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) using (var serviceScope = app.ApplicationServices.GetService().CreateScope()) { - var context = serviceScope.ServiceProvider.GetRequiredService(); - context.Database.EnsureCreated(); + //serveless database should have time to wake up + var retryTimes = 3; + while (retryTimes-- > 0) + { + try + { + var context = serviceScope.ServiceProvider.GetRequiredService(); + context.Database.EnsureCreated(); + } + catch (Exception) + { + //throw exception if database didn't wakeup after 3 attempts + if (retryTimes == 0) + { + throw; + } + } + } } if (env.IsDevelopment()) From 891341b153059969b84d2fd55b82a3fad5fb4d3b Mon Sep 17 00:00:00 2001 From: Alexander Beyderman Date: Tue, 28 Jun 2022 18:55:35 -0400 Subject: [PATCH 11/19] fix for npt redirecting --- TodoListClient/Controllers/TodoListController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TodoListClient/Controllers/TodoListController.cs b/TodoListClient/Controllers/TodoListController.cs index 99ee8d1..32a4c9c 100644 --- a/TodoListClient/Controllers/TodoListController.cs +++ b/TodoListClient/Controllers/TodoListController.cs @@ -198,7 +198,7 @@ public ActionResult Delete(int id, [Bind("Id,Title,Owner")] Todo todo) //save in session state before redirecting to GET handler TodoSessionState(SessionAction.Set, new Todo { Id = id }); - return RedirectToAction("Delete"); + return View(); // RedirectToAction("Delete"); } //make sure the received todo is inside database before deleting From a733a563d3dcb4cddae53f5ef03456966299142e Mon Sep 17 00:00:00 2001 From: Alexander Beyderman Date: Tue, 28 Jun 2022 19:05:58 -0400 Subject: [PATCH 12/19] fixed version --- AppCreationScripts/apps.json | 67 ----------- AppCreationScripts/appsetup.ps1 | 7 -- AppCreationScripts/createdApps.html | 4 - .../Controllers/TodoListController.cs | 4 +- .../PublishProfiles/Woodgrove Deploy.pubxml | 32 ----- .../profile.arm.json | 113 ------------------ .../mssql1.arm.json | 81 ------------- .../profile.arm.json | 113 ------------------ .../mssql1.arm.json | 82 ------------- .../profile.arm.json | 113 ------------------ .../mssql1.arm.json | 81 ------------- .../profile.arm.json | 113 ------------------ .../Woodgrove Deploy/profile.arm.json | 113 ------------------ TodoListClient/TodoListClient.csproj | 1 + 14 files changed, 3 insertions(+), 921 deletions(-) delete mode 100644 AppCreationScripts/apps.json delete mode 100644 AppCreationScripts/appsetup.ps1 delete mode 100644 AppCreationScripts/createdApps.html delete mode 100644 TodoListClient/Properties/PublishProfiles/Woodgrove Deploy.pubxml delete mode 100644 TodoListClient/Properties/ServiceDependencies/AlexToDoListTest - Web Deploy/profile.arm.json delete mode 100644 TodoListClient/Properties/ServiceDependencies/AuthContextDotNetApp - Web Deploy/mssql1.arm.json delete mode 100644 TodoListClient/Properties/ServiceDependencies/AuthContextDotNetApp - Web Deploy/profile.arm.json delete mode 100644 TodoListClient/Properties/ServiceDependencies/TodoListClient-Test - Web Deploy/mssql1.arm.json delete mode 100644 TodoListClient/Properties/ServiceDependencies/TodoListClient-Test - Web Deploy/profile.arm.json delete mode 100644 TodoListClient/Properties/ServiceDependencies/TodoListClient20210921173525 - Web Deploy/mssql1.arm.json delete mode 100644 TodoListClient/Properties/ServiceDependencies/TodoListClient20210921173525 - Web Deploy/profile.arm.json delete mode 100644 TodoListClient/Properties/ServiceDependencies/Woodgrove Deploy/profile.arm.json diff --git a/AppCreationScripts/apps.json b/AppCreationScripts/apps.json deleted file mode 100644 index 2706190..0000000 --- a/AppCreationScripts/apps.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "Sample": { - "Title": "This sample demonstrates using the Conditional Access auth context to perform step-up authentication for high-privilege and sensitive operations in a web app.", - "Level": 300, - "Client": "ASP.NET Core Web App" - }, - "AppRegistrations": [ - { - "x-ms-id": "client", - "x-ms-name": "TodoListClient-authContext-webapp", - "x-ms-version": "2.0", - "replyUrlsWithType": [ - { - "url": "https://localhost:44321/", - "type": "Web" - }, - { - "url": " https://localhost:44321/signin-oidc", - "type": "Web" - } ], - "oauth2AllowImplicitFlow": false, - "oauth2AllowIdTokenImplicitFlow": false, - "requiredResourceAccess": [ - { - "x-ms-resourceAppName": "Microsoft Graph", - "resourceAppId": "00000003-0000-0000-c000-000000000000", - "resourceAccess": [ - { - "id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d", - "type": "Scope", - "x-ms-name": "User.Read" - }, - { - "id": "unknown", - "type": "Scope", - "x-ms-name": "Policy.Read.ConditionalAccess" - }, - { - "id": "unknown", - "type": "Scope", - "x-ms-name": "Policy.ReadWrite.ConditionalAccess" - } ] - } - ], - "codeConfigurations": [ - { - "settingFile": "/TodoListClient/appsettings.json", - "replaceTokens": - { - /** - * Note: The following 'key-value' pairs are for illustration only; you may - * not have all of them in your configuration file. Azure portal will replace - * the values (i.e. text) below with the actual app credentials. - * Finally, don't forget to remove this comment. - */ - "appId": "Enter_the_Application_Id_Here", - "redirectUri": "Enter_the_Redirect_Uri_Here", - "tenantId": "Enter_the_Tenant_Info_Here", - "clientSecret": "Enter_the_Client_Secret_Here", - "authorityEndpointHost": "Enter_the_Cloud_Instance_Id_Here", - "msgraphEndpointHost": "Enter_the_Graph_Endpoint_Here", - "signInAudience": "Enter_the_Sign-in_Audience_Here" - } - } ] - } - ] -} diff --git a/AppCreationScripts/appsetup.ps1 b/AppCreationScripts/appsetup.ps1 deleted file mode 100644 index b020f9c..0000000 --- a/AppCreationScripts/appsetup.ps1 +++ /dev/null @@ -1,7 +0,0 @@ -Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process -Force -$secpasswd = ConvertTo-SecureString "Abeyd@123" -AsPlainText -Force -$mycreds = New-Object System.Management.Automation.PSCredential ("alexbeyd@alexbdev.onmicrosoft.com", $secpasswd) -$tenantId = "859c0fc9-4300-47be-b473-597fa2fc2104" - -.\Cleanup.ps1 -Credential $mycreds -TenantId $tenantId -.\Configure.ps1 -Credential $mycreds -TenantId $tenantId \ No newline at end of file diff --git a/AppCreationScripts/createdApps.html b/AppCreationScripts/createdApps.html deleted file mode 100644 index 1138db3..0000000 --- a/AppCreationScripts/createdApps.html +++ /dev/null @@ -1,4 +0,0 @@ -
- - -
ApplicationAppIdUrl in the Azure portal
clientd56cce6d-baca-4f88-9e00-9bb11eb92b28TodoListClient-authContext-webapp
diff --git a/TodoListClient/Controllers/TodoListController.cs b/TodoListClient/Controllers/TodoListController.cs index 32a4c9c..ac33fb5 100644 --- a/TodoListClient/Controllers/TodoListController.cs +++ b/TodoListClient/Controllers/TodoListController.cs @@ -113,7 +113,7 @@ public ActionResult Create([Bind("Title,Owner")] Todo todo) //save in session state before redirecting to GET handler TodoSessionState(SessionAction.Set, todo); - return RedirectToAction("Create"); + return View(); } SaveToDatabase(new Todo() { Owner = todo.Owner, Title = todo.Title, AccountId = todo.AccountId }); @@ -159,7 +159,7 @@ public ActionResult Edit(int id, [Bind("Id,Title,Owner")] Todo todo) //save in session state before redirecting to GET handler TodoSessionState(SessionAction.Set, todo); - return RedirectToAction("Edit"); + return View(); } UpdateDatabase(todo); diff --git a/TodoListClient/Properties/PublishProfiles/Woodgrove Deploy.pubxml b/TodoListClient/Properties/PublishProfiles/Woodgrove Deploy.pubxml deleted file mode 100644 index 8458e54..0000000 --- a/TodoListClient/Properties/PublishProfiles/Woodgrove Deploy.pubxml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - MSDeploy - /subscriptions/9ac91505-2026-4193-a58c-05a599583f61/resourceGroups/Thefirstresourcegroup/providers/Microsoft.Web/sites/AuthContextDotNetApp - Thefirstresourcegroup - AzureWebSite - Release - Any CPU - https://authcontextdotnetapp.azurewebsites.net - true - false - 8f331ce4-767d-488d-a33b-e6f129abc198 - authcontextdotnetapp.scm.azurewebsites.net:443 - AuthContextDotNetApp - - false - WMSVC - true - true - $AuthContextDotNetApp - <_SavePWD>true - <_DestinationType>AzureWebSite - false - net6.0 - false - - \ No newline at end of file diff --git a/TodoListClient/Properties/ServiceDependencies/AlexToDoListTest - Web Deploy/profile.arm.json b/TodoListClient/Properties/ServiceDependencies/AlexToDoListTest - Web Deploy/profile.arm.json deleted file mode 100644 index 856593c..0000000 --- a/TodoListClient/Properties/ServiceDependencies/AlexToDoListTest - Web Deploy/profile.arm.json +++ /dev/null @@ -1,113 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_dependencyType": "compute.appService.windows" - }, - "parameters": { - "resourceGroupName": { - "type": "string", - "defaultValue": "Thefirstresourcegroup", - "metadata": { - "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." - } - }, - "resourceGroupLocation": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support." - } - }, - "resourceName": { - "type": "string", - "defaultValue": "AlexToDoListTest", - "metadata": { - "description": "Name of the main resource to be created by this template." - } - }, - "resourceLocation": { - "type": "string", - "defaultValue": "[parameters('resourceGroupLocation')]", - "metadata": { - "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." - } - } - }, - "variables": { - "appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", - "appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]" - }, - "resources": [ - { - "type": "Microsoft.Resources/resourceGroups", - "name": "[parameters('resourceGroupName')]", - "location": "[parameters('resourceGroupLocation')]", - "apiVersion": "2019-10-01" - }, - { - "type": "Microsoft.Resources/deployments", - "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", - "resourceGroup": "[parameters('resourceGroupName')]", - "apiVersion": "2019-10-01", - "dependsOn": [ - "[parameters('resourceGroupName')]" - ], - "properties": { - "mode": "Incremental", - "template": { - "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [ - { - "location": "[parameters('resourceLocation')]", - "name": "[parameters('resourceName')]", - "type": "Microsoft.Web/sites", - "apiVersion": "2015-08-01", - "tags": { - "[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty" - }, - "dependsOn": [ - "[variables('appServicePlan_ResourceId')]" - ], - "kind": "app", - "properties": { - "name": "[parameters('resourceName')]", - "kind": "app", - "httpsOnly": true, - "reserved": false, - "serverFarmId": "[variables('appServicePlan_ResourceId')]", - "siteConfig": { - "metadata": [ - { - "name": "CURRENT_STACK", - "value": "dotnetcore" - } - ] - } - }, - "identity": { - "type": "SystemAssigned" - } - }, - { - "location": "[parameters('resourceLocation')]", - "name": "[variables('appServicePlan_name')]", - "type": "Microsoft.Web/serverFarms", - "apiVersion": "2015-08-01", - "sku": { - "name": "S1", - "tier": "Standard", - "family": "S", - "size": "S1" - }, - "properties": { - "name": "[variables('appServicePlan_name')]" - } - } - ] - } - } - } - ] -} \ No newline at end of file diff --git a/TodoListClient/Properties/ServiceDependencies/AuthContextDotNetApp - Web Deploy/mssql1.arm.json b/TodoListClient/Properties/ServiceDependencies/AuthContextDotNetApp - Web Deploy/mssql1.arm.json deleted file mode 100644 index cafc6c8..0000000 --- a/TodoListClient/Properties/ServiceDependencies/AuthContextDotNetApp - Web Deploy/mssql1.arm.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "resourceGroupName": { - "type": "string", - "defaultValue": "Thefirstresourcegroup", - "metadata": { - "_parameterType": "resourceGroup", - "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." - } - }, - "resourceGroupLocation": { - "type": "string", - "defaultValue": "eastus", - "metadata": { - "_parameterType": "location", - "description": "Location of the resource group. Resource groups could have different location than resources." - } - }, - "resourceLocation": { - "type": "string", - "defaultValue": "[parameters('resourceGroupLocation')]", - "metadata": { - "_parameterType": "location", - "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." - } - } - }, - "resources": [ - { - "type": "Microsoft.Resources/resourceGroups", - "name": "[parameters('resourceGroupName')]", - "location": "[parameters('resourceGroupLocation')]", - "apiVersion": "2019-10-01" - }, - { - "type": "Microsoft.Resources/deployments", - "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat('TodoListClient_db', subscription().subscriptionId)))]", - "resourceGroup": "[parameters('resourceGroupName')]", - "apiVersion": "2019-10-01", - "dependsOn": [ - "[parameters('resourceGroupName')]" - ], - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [ - { - "kind": "v12.0", - "location": "[parameters('resourceLocation')]", - "name": "todolistclientdbserver", - "type": "Microsoft.Sql/servers", - "apiVersion": "2017-10-01-preview" - }, - { - "sku": { - "name": "Standard", - "tier": "Standard", - "capacity": 10 - }, - "kind": "v12.0,user", - "location": "[parameters('resourceLocation')]", - "name": "todolistclientdbserver/TodoListClient_db", - "type": "Microsoft.Sql/servers/databases", - "apiVersion": "2017-10-01-preview", - "dependsOn": [ - "todolistclientdbserver" - ] - } - ] - } - } - } - ], - "metadata": { - "_dependencyType": "mssql.azure" - } -} \ No newline at end of file diff --git a/TodoListClient/Properties/ServiceDependencies/AuthContextDotNetApp - Web Deploy/profile.arm.json b/TodoListClient/Properties/ServiceDependencies/AuthContextDotNetApp - Web Deploy/profile.arm.json deleted file mode 100644 index 35023cf..0000000 --- a/TodoListClient/Properties/ServiceDependencies/AuthContextDotNetApp - Web Deploy/profile.arm.json +++ /dev/null @@ -1,113 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_dependencyType": "appService.windows" - }, - "parameters": { - "resourceGroupName": { - "type": "string", - "defaultValue": "Thefirstresourcegroup", - "metadata": { - "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." - } - }, - "resourceGroupLocation": { - "type": "string", - "defaultValue": "eastus", - "metadata": { - "description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support." - } - }, - "resourceName": { - "type": "string", - "defaultValue": "AuthContextDotNetApp", - "metadata": { - "description": "Name of the main resource to be created by this template." - } - }, - "resourceLocation": { - "type": "string", - "defaultValue": "[parameters('resourceGroupLocation')]", - "metadata": { - "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." - } - } - }, - "variables": { - "appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", - "appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]" - }, - "resources": [ - { - "type": "Microsoft.Resources/resourceGroups", - "name": "[parameters('resourceGroupName')]", - "location": "[parameters('resourceGroupLocation')]", - "apiVersion": "2019-10-01" - }, - { - "type": "Microsoft.Resources/deployments", - "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", - "resourceGroup": "[parameters('resourceGroupName')]", - "apiVersion": "2019-10-01", - "dependsOn": [ - "[parameters('resourceGroupName')]" - ], - "properties": { - "mode": "Incremental", - "template": { - "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [ - { - "location": "[parameters('resourceLocation')]", - "name": "[parameters('resourceName')]", - "type": "Microsoft.Web/sites", - "apiVersion": "2015-08-01", - "tags": { - "[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty" - }, - "dependsOn": [ - "[variables('appServicePlan_ResourceId')]" - ], - "kind": "app", - "properties": { - "name": "[parameters('resourceName')]", - "kind": "app", - "httpsOnly": true, - "reserved": false, - "serverFarmId": "[variables('appServicePlan_ResourceId')]", - "siteConfig": { - "metadata": [ - { - "name": "CURRENT_STACK", - "value": "dotnetcore" - } - ] - } - }, - "identity": { - "type": "SystemAssigned" - } - }, - { - "location": "[parameters('resourceLocation')]", - "name": "[variables('appServicePlan_name')]", - "type": "Microsoft.Web/serverFarms", - "apiVersion": "2015-08-01", - "sku": { - "name": "S1", - "tier": "Standard", - "family": "S", - "size": "S1" - }, - "properties": { - "name": "[variables('appServicePlan_name')]" - } - } - ] - } - } - } - ] -} \ No newline at end of file diff --git a/TodoListClient/Properties/ServiceDependencies/TodoListClient-Test - Web Deploy/mssql1.arm.json b/TodoListClient/Properties/ServiceDependencies/TodoListClient-Test - Web Deploy/mssql1.arm.json deleted file mode 100644 index f11fdc0..0000000 --- a/TodoListClient/Properties/ServiceDependencies/TodoListClient-Test - Web Deploy/mssql1.arm.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "resourceGroupName": { - "type": "string", - "defaultValue": "Thefirstresourcegroup", - "metadata": { - "_parameterType": "resourceGroup", - "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." - } - }, - "resourceGroupLocation": { - "type": "string", - "defaultValue": "eastus", - "metadata": { - "_parameterType": "location", - "description": "Location of the resource group. Resource groups could have different location than resources." - } - }, - "resourceLocation": { - "type": "string", - "defaultValue": "[parameters('resourceGroupLocation')]", - "metadata": { - "_parameterType": "location", - "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." - } - } - }, - "resources": [ - { - "type": "Microsoft.Resources/resourceGroups", - "name": "[parameters('resourceGroupName')]", - "location": "[parameters('resourceGroupLocation')]", - "apiVersion": "2019-10-01" - }, - { - "type": "Microsoft.Resources/deployments", - "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat('TodoListClient_db', subscription().subscriptionId)))]", - "resourceGroup": "[parameters('resourceGroupName')]", - "apiVersion": "2019-10-01", - "dependsOn": [ - "[parameters('resourceGroupName')]" - ], - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [ - { - "kind": "v12.0", - "location": "[parameters('resourceLocation')]", - "name": "todolistclientdbserver", - "type": "Microsoft.Sql/servers", - "apiVersion": "2017-10-01-preview" - }, - { - "sku": { - "name": "GP_S_Gen5", - "tier": "GeneralPurpose", - "family": "Gen5", - "capacity": 1 - }, - "kind": "v12.0,user,vcore,serverless", - "location": "[parameters('resourceLocation')]", - "name": "todolistclientdbserver/TodoListClient_db", - "type": "Microsoft.Sql/servers/databases", - "apiVersion": "2017-10-01-preview", - "dependsOn": [ - "todolistclientdbserver" - ] - } - ] - } - } - } - ], - "metadata": { - "_dependencyType": "mssql.azure" - } -} \ No newline at end of file diff --git a/TodoListClient/Properties/ServiceDependencies/TodoListClient-Test - Web Deploy/profile.arm.json b/TodoListClient/Properties/ServiceDependencies/TodoListClient-Test - Web Deploy/profile.arm.json deleted file mode 100644 index f17a0b6..0000000 --- a/TodoListClient/Properties/ServiceDependencies/TodoListClient-Test - Web Deploy/profile.arm.json +++ /dev/null @@ -1,113 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_dependencyType": "appService.windows" - }, - "parameters": { - "resourceGroupName": { - "type": "string", - "defaultValue": "Thefirstresourcegroup", - "metadata": { - "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." - } - }, - "resourceGroupLocation": { - "type": "string", - "defaultValue": "eastus", - "metadata": { - "description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support." - } - }, - "resourceName": { - "type": "string", - "defaultValue": "TodoListClient-Test", - "metadata": { - "description": "Name of the main resource to be created by this template." - } - }, - "resourceLocation": { - "type": "string", - "defaultValue": "[parameters('resourceGroupLocation')]", - "metadata": { - "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." - } - } - }, - "variables": { - "appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", - "appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]" - }, - "resources": [ - { - "type": "Microsoft.Resources/resourceGroups", - "name": "[parameters('resourceGroupName')]", - "location": "[parameters('resourceGroupLocation')]", - "apiVersion": "2019-10-01" - }, - { - "type": "Microsoft.Resources/deployments", - "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", - "resourceGroup": "[parameters('resourceGroupName')]", - "apiVersion": "2019-10-01", - "dependsOn": [ - "[parameters('resourceGroupName')]" - ], - "properties": { - "mode": "Incremental", - "template": { - "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [ - { - "location": "[parameters('resourceLocation')]", - "name": "[parameters('resourceName')]", - "type": "Microsoft.Web/sites", - "apiVersion": "2015-08-01", - "tags": { - "[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty" - }, - "dependsOn": [ - "[variables('appServicePlan_ResourceId')]" - ], - "kind": "app", - "properties": { - "name": "[parameters('resourceName')]", - "kind": "app", - "httpsOnly": true, - "reserved": false, - "serverFarmId": "[variables('appServicePlan_ResourceId')]", - "siteConfig": { - "metadata": [ - { - "name": "CURRENT_STACK", - "value": "dotnetcore" - } - ] - } - }, - "identity": { - "type": "SystemAssigned" - } - }, - { - "location": "[parameters('resourceLocation')]", - "name": "[variables('appServicePlan_name')]", - "type": "Microsoft.Web/serverFarms", - "apiVersion": "2015-08-01", - "sku": { - "name": "S1", - "tier": "Standard", - "family": "S", - "size": "S1" - }, - "properties": { - "name": "[variables('appServicePlan_name')]" - } - } - ] - } - } - } - ] -} \ No newline at end of file diff --git a/TodoListClient/Properties/ServiceDependencies/TodoListClient20210921173525 - Web Deploy/mssql1.arm.json b/TodoListClient/Properties/ServiceDependencies/TodoListClient20210921173525 - Web Deploy/mssql1.arm.json deleted file mode 100644 index cafc6c8..0000000 --- a/TodoListClient/Properties/ServiceDependencies/TodoListClient20210921173525 - Web Deploy/mssql1.arm.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "resourceGroupName": { - "type": "string", - "defaultValue": "Thefirstresourcegroup", - "metadata": { - "_parameterType": "resourceGroup", - "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." - } - }, - "resourceGroupLocation": { - "type": "string", - "defaultValue": "eastus", - "metadata": { - "_parameterType": "location", - "description": "Location of the resource group. Resource groups could have different location than resources." - } - }, - "resourceLocation": { - "type": "string", - "defaultValue": "[parameters('resourceGroupLocation')]", - "metadata": { - "_parameterType": "location", - "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." - } - } - }, - "resources": [ - { - "type": "Microsoft.Resources/resourceGroups", - "name": "[parameters('resourceGroupName')]", - "location": "[parameters('resourceGroupLocation')]", - "apiVersion": "2019-10-01" - }, - { - "type": "Microsoft.Resources/deployments", - "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat('TodoListClient_db', subscription().subscriptionId)))]", - "resourceGroup": "[parameters('resourceGroupName')]", - "apiVersion": "2019-10-01", - "dependsOn": [ - "[parameters('resourceGroupName')]" - ], - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [ - { - "kind": "v12.0", - "location": "[parameters('resourceLocation')]", - "name": "todolistclientdbserver", - "type": "Microsoft.Sql/servers", - "apiVersion": "2017-10-01-preview" - }, - { - "sku": { - "name": "Standard", - "tier": "Standard", - "capacity": 10 - }, - "kind": "v12.0,user", - "location": "[parameters('resourceLocation')]", - "name": "todolistclientdbserver/TodoListClient_db", - "type": "Microsoft.Sql/servers/databases", - "apiVersion": "2017-10-01-preview", - "dependsOn": [ - "todolistclientdbserver" - ] - } - ] - } - } - } - ], - "metadata": { - "_dependencyType": "mssql.azure" - } -} \ No newline at end of file diff --git a/TodoListClient/Properties/ServiceDependencies/TodoListClient20210921173525 - Web Deploy/profile.arm.json b/TodoListClient/Properties/ServiceDependencies/TodoListClient20210921173525 - Web Deploy/profile.arm.json deleted file mode 100644 index 3fa6997..0000000 --- a/TodoListClient/Properties/ServiceDependencies/TodoListClient20210921173525 - Web Deploy/profile.arm.json +++ /dev/null @@ -1,113 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_dependencyType": "appService.windows" - }, - "parameters": { - "resourceGroupName": { - "type": "string", - "defaultValue": "Thefirstresourcegroup", - "metadata": { - "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." - } - }, - "resourceGroupLocation": { - "type": "string", - "defaultValue": "eastus", - "metadata": { - "description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support." - } - }, - "resourceName": { - "type": "string", - "defaultValue": "TodoListClient20210921173525", - "metadata": { - "description": "Name of the main resource to be created by this template." - } - }, - "resourceLocation": { - "type": "string", - "defaultValue": "[parameters('resourceGroupLocation')]", - "metadata": { - "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." - } - } - }, - "variables": { - "appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", - "appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]" - }, - "resources": [ - { - "type": "Microsoft.Resources/resourceGroups", - "name": "[parameters('resourceGroupName')]", - "location": "[parameters('resourceGroupLocation')]", - "apiVersion": "2019-10-01" - }, - { - "type": "Microsoft.Resources/deployments", - "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", - "resourceGroup": "[parameters('resourceGroupName')]", - "apiVersion": "2019-10-01", - "dependsOn": [ - "[parameters('resourceGroupName')]" - ], - "properties": { - "mode": "Incremental", - "template": { - "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [ - { - "location": "[parameters('resourceLocation')]", - "name": "[parameters('resourceName')]", - "type": "Microsoft.Web/sites", - "apiVersion": "2015-08-01", - "tags": { - "[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty" - }, - "dependsOn": [ - "[variables('appServicePlan_ResourceId')]" - ], - "kind": "app", - "properties": { - "name": "[parameters('resourceName')]", - "kind": "app", - "httpsOnly": true, - "reserved": false, - "serverFarmId": "[variables('appServicePlan_ResourceId')]", - "siteConfig": { - "metadata": [ - { - "name": "CURRENT_STACK", - "value": "dotnetcore" - } - ] - } - }, - "identity": { - "type": "SystemAssigned" - } - }, - { - "location": "[parameters('resourceLocation')]", - "name": "[variables('appServicePlan_name')]", - "type": "Microsoft.Web/serverFarms", - "apiVersion": "2015-08-01", - "sku": { - "name": "S1", - "tier": "Standard", - "family": "S", - "size": "S1" - }, - "properties": { - "name": "[variables('appServicePlan_name')]" - } - } - ] - } - } - } - ] -} \ No newline at end of file diff --git a/TodoListClient/Properties/ServiceDependencies/Woodgrove Deploy/profile.arm.json b/TodoListClient/Properties/ServiceDependencies/Woodgrove Deploy/profile.arm.json deleted file mode 100644 index d1c4e12..0000000 --- a/TodoListClient/Properties/ServiceDependencies/Woodgrove Deploy/profile.arm.json +++ /dev/null @@ -1,113 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_dependencyType": "compute.appService.windows" - }, - "parameters": { - "resourceGroupName": { - "type": "string", - "defaultValue": "Thefirstresourcegroup", - "metadata": { - "description": "Name of the resource group for the resource. It is recommended to put resources under same resource group for better tracking." - } - }, - "resourceGroupLocation": { - "type": "string", - "defaultValue": "eastus", - "metadata": { - "description": "Location of the resource group. Resource groups could have different location than resources, however by default we use API versions from latest hybrid profile which support all locations for resource types we support." - } - }, - "resourceName": { - "type": "string", - "defaultValue": "AuthContextDotNetApp", - "metadata": { - "description": "Name of the main resource to be created by this template." - } - }, - "resourceLocation": { - "type": "string", - "defaultValue": "[parameters('resourceGroupLocation')]", - "metadata": { - "description": "Location of the resource. By default use resource group's location, unless the resource provider is not supported there." - } - } - }, - "variables": { - "appServicePlan_name": "[concat('Plan', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", - "appServicePlan_ResourceId": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', parameters('resourceGroupName'), '/providers/Microsoft.Web/serverFarms/', variables('appServicePlan_name'))]" - }, - "resources": [ - { - "type": "Microsoft.Resources/resourceGroups", - "name": "[parameters('resourceGroupName')]", - "location": "[parameters('resourceGroupLocation')]", - "apiVersion": "2019-10-01" - }, - { - "type": "Microsoft.Resources/deployments", - "name": "[concat(parameters('resourceGroupName'), 'Deployment', uniqueString(concat(parameters('resourceName'), subscription().subscriptionId)))]", - "resourceGroup": "[parameters('resourceGroupName')]", - "apiVersion": "2019-10-01", - "dependsOn": [ - "[parameters('resourceGroupName')]" - ], - "properties": { - "mode": "Incremental", - "template": { - "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [ - { - "location": "[parameters('resourceLocation')]", - "name": "[parameters('resourceName')]", - "type": "Microsoft.Web/sites", - "apiVersion": "2015-08-01", - "tags": { - "[concat('hidden-related:', variables('appServicePlan_ResourceId'))]": "empty" - }, - "dependsOn": [ - "[variables('appServicePlan_ResourceId')]" - ], - "kind": "app", - "properties": { - "name": "[parameters('resourceName')]", - "kind": "app", - "httpsOnly": true, - "reserved": false, - "serverFarmId": "[variables('appServicePlan_ResourceId')]", - "siteConfig": { - "metadata": [ - { - "name": "CURRENT_STACK", - "value": "dotnetcore" - } - ] - } - }, - "identity": { - "type": "SystemAssigned" - } - }, - { - "location": "[parameters('resourceLocation')]", - "name": "[variables('appServicePlan_name')]", - "type": "Microsoft.Web/serverFarms", - "apiVersion": "2015-08-01", - "sku": { - "name": "S1", - "tier": "Standard", - "family": "S", - "size": "S1" - }, - "properties": { - "name": "[variables('appServicePlan_name')]" - } - } - ] - } - } - } - ] -} \ No newline at end of file diff --git a/TodoListClient/TodoListClient.csproj b/TodoListClient/TodoListClient.csproj index f42b702..af17854 100644 --- a/TodoListClient/TodoListClient.csproj +++ b/TodoListClient/TodoListClient.csproj @@ -32,6 +32,7 @@ + From d97a1a2649e3a0099bee64d7f0f5acc3e96a3081 Mon Sep 17 00:00:00 2001 From: Alexander Beyderman Date: Tue, 28 Jun 2022 22:08:27 -0400 Subject: [PATCH 13/19] double challenge when going back on page --- .../Controllers/TodoListController.cs | 29 +++++-------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/TodoListClient/Controllers/TodoListController.cs b/TodoListClient/Controllers/TodoListController.cs index ac33fb5..9dbc1af 100644 --- a/TodoListClient/Controllers/TodoListController.cs +++ b/TodoListClient/Controllers/TodoListController.cs @@ -76,22 +76,13 @@ public ActionResult Details(int id) // GET: TodoList/Create public ActionResult Create() { - if (ChallengeUser(Request.Method)) - { - return RedirectToAction("Create"); - } - //get todo from session state (if available then this means we were redirected from POST and have to save this todo) var todoFromSessionState = TodoSessionState(SessionAction.Get); if (todoFromSessionState != null && todoFromSessionState.IsInitialized) { - SaveToDatabase(todoFromSessionState); - - //clean session state TodoSessionState(SessionAction.Set); - - return RedirectToAction("Index"); + return Create(todoFromSessionState); } Todo todo = new Todo() { Owner = HttpContext.User.Identity.Name }; @@ -108,7 +99,7 @@ public ActionResult Create([Bind("Title,Owner")] Todo todo) todo.AccountId = HttpContext.User.GetMsalAccountId(); todo.Owner = HttpContext.User.Identity.Name; - if (ChallengeUser(Request.Method)) + if (ChallengeUser(HttpMethods.Post)) { //save in session state before redirecting to GET handler TodoSessionState(SessionAction.Set, todo); @@ -130,11 +121,7 @@ public ActionResult Edit(int id) if (todoFromSessionState != null && todoFromSessionState.IsInitialized && todoFromSessionState.Id == id) { UpdateDatabase(todoFromSessionState); - - //clean session state - TodoSessionState(SessionAction.Set); - - return RedirectToAction("Index"); + return Edit(todoFromSessionState.Id, todoFromSessionState); } else { @@ -154,7 +141,7 @@ public ActionResult Edit(int id, [Bind("Id,Title,Owner")] Todo todo) todo.AccountId = HttpContext.User.GetMsalAccountId(); - if (ChallengeUser(Request.Method)) + if (ChallengeUser(HttpMethods.Post)) { //save in session state before redirecting to GET handler TodoSessionState(SessionAction.Set, todo); @@ -175,12 +162,9 @@ public ActionResult Delete(int id) if (todoFromSessionState != null && todoFromSessionState.Id == id) { - DeleteFromDatabase(todoFromSessionState); - //clean session state TodoSessionState(SessionAction.Set); - - return RedirectToAction("Index"); + return Delete(todoFromSessionState.Id, todoFromSessionState); } else { @@ -198,7 +182,7 @@ public ActionResult Delete(int id, [Bind("Id,Title,Owner")] Todo todo) //save in session state before redirecting to GET handler TodoSessionState(SessionAction.Set, new Todo { Id = id }); - return View(); // RedirectToAction("Delete"); + return View(); } //make sure the received todo is inside database before deleting @@ -297,6 +281,7 @@ private Todo TodoSessionState(SessionAction action, Todo todo = null) /// private bool ChallengeUser(string actionName) { + //get challenge from token or from session state string claimsChallenge = CheckForRequiredAuthContext(actionName); if (!string.IsNullOrWhiteSpace(claimsChallenge)) From 8cd4d5e64e394f888e42998a1042fbc5644d9d53 Mon Sep 17 00:00:00 2001 From: Alexander Beyderman Date: Tue, 5 Jul 2022 15:42:18 -0400 Subject: [PATCH 14/19] cleanup and updated versions --- ...ies.AuthContextDotNetApp - Web Deploy.json | 10 ------- ...cies.TodoListClient-Test - Web Deploy.json | 10 ------- ...ListClient20210921173525 - Web Deploy.json | 10 ------- .../Properties/serviceDependencies.json | 11 -------- .../Properties/serviceDependencies.local.json | 7 ----- TodoListClient/TodoListClient.csproj | 26 +++++++++---------- 6 files changed, 13 insertions(+), 61 deletions(-) delete mode 100644 TodoListClient/Properties/serviceDependencies.AuthContextDotNetApp - Web Deploy.json delete mode 100644 TodoListClient/Properties/serviceDependencies.TodoListClient-Test - Web Deploy.json delete mode 100644 TodoListClient/Properties/serviceDependencies.TodoListClient20210921173525 - Web Deploy.json delete mode 100644 TodoListClient/Properties/serviceDependencies.json delete mode 100644 TodoListClient/Properties/serviceDependencies.local.json diff --git a/TodoListClient/Properties/serviceDependencies.AuthContextDotNetApp - Web Deploy.json b/TodoListClient/Properties/serviceDependencies.AuthContextDotNetApp - Web Deploy.json deleted file mode 100644 index 594e299..0000000 --- a/TodoListClient/Properties/serviceDependencies.AuthContextDotNetApp - Web Deploy.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "dependencies": { - "mssql1": { - "resourceId": "/subscriptions/[parameters('subscriptionId')]/resourceGroups/[parameters('resourceGroupName')]/providers/Microsoft.Sql/servers/todolistclientdbserver/databases/TodoListClient_db", - "type": "mssql.azure", - "connectionId": "ConnectionStrings:DefaultConnection", - "secretStore": "AzureAppSettings" - } - } -} \ No newline at end of file diff --git a/TodoListClient/Properties/serviceDependencies.TodoListClient-Test - Web Deploy.json b/TodoListClient/Properties/serviceDependencies.TodoListClient-Test - Web Deploy.json deleted file mode 100644 index 594e299..0000000 --- a/TodoListClient/Properties/serviceDependencies.TodoListClient-Test - Web Deploy.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "dependencies": { - "mssql1": { - "resourceId": "/subscriptions/[parameters('subscriptionId')]/resourceGroups/[parameters('resourceGroupName')]/providers/Microsoft.Sql/servers/todolistclientdbserver/databases/TodoListClient_db", - "type": "mssql.azure", - "connectionId": "ConnectionStrings:DefaultConnection", - "secretStore": "AzureAppSettings" - } - } -} \ No newline at end of file diff --git a/TodoListClient/Properties/serviceDependencies.TodoListClient20210921173525 - Web Deploy.json b/TodoListClient/Properties/serviceDependencies.TodoListClient20210921173525 - Web Deploy.json deleted file mode 100644 index d76bb87..0000000 --- a/TodoListClient/Properties/serviceDependencies.TodoListClient20210921173525 - Web Deploy.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "dependencies": { - "mssql1": { - "resourceId": "/subscriptions/[parameters('subscriptionId')]/resourcegroups/[parameters('resourceGroupName')]/providers/Microsoft.Sql/servers/todolistclientdbserver/databases/TodoListClient_db", - "type": "mssql.azure", - "connectionId": "ConnectionStrings:DefaultConnection", - "secretStore": "AzureAppSettings" - } - } -} \ No newline at end of file diff --git a/TodoListClient/Properties/serviceDependencies.json b/TodoListClient/Properties/serviceDependencies.json deleted file mode 100644 index 5d53e15..0000000 --- a/TodoListClient/Properties/serviceDependencies.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "dependencies": { - "secrets1": { - "type": "secrets" - }, - "mssql1": { - "type": "mssql", - "connectionId": "ConnectionStrings:DefaultConnection" - } - } -} \ No newline at end of file diff --git a/TodoListClient/Properties/serviceDependencies.local.json b/TodoListClient/Properties/serviceDependencies.local.json deleted file mode 100644 index 09b109b..0000000 --- a/TodoListClient/Properties/serviceDependencies.local.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "dependencies": { - "secrets1": { - "type": "secrets.user" - } - } -} \ No newline at end of file diff --git a/TodoListClient/TodoListClient.csproj b/TodoListClient/TodoListClient.csproj index af17854..c031751 100644 --- a/TodoListClient/TodoListClient.csproj +++ b/TodoListClient/TodoListClient.csproj @@ -8,31 +8,31 @@ + + + + + <_WebToolingArtifacts Remove="Properties\ServiceDependencies\**" /> - + - - + + - - - - - - - - - - + + + + + From 42c6ee81d2fdcbc39d434063ec3c33b713ff2963 Mon Sep 17 00:00:00 2001 From: Alexander Beyderman Date: Tue, 5 Jul 2022 15:46:55 -0400 Subject: [PATCH 15/19] more cleanup --- TodoListClient/.config/dotnet-tools.json | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 TodoListClient/.config/dotnet-tools.json diff --git a/TodoListClient/.config/dotnet-tools.json b/TodoListClient/.config/dotnet-tools.json deleted file mode 100644 index 337014b..0000000 --- a/TodoListClient/.config/dotnet-tools.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "version": 1, - "isRoot": true, - "tools": { - "dotnet-ef": { - "version": "5.0.10", - "commands": [ - "dotnet-ef" - ] - } - } -} \ No newline at end of file From ac6fbf32d00d38b5a3fca6183ca960e0b4e504c2 Mon Sep 17 00:00:00 2001 From: kalyankrishna1 Date: Wed, 13 Jul 2022 22:50:33 -0700 Subject: [PATCH 16/19] Minor refactor and edits --- .gitignore | 3 + README.md | 105 ++++++++---------- ReadmeFiles/Teams icon 1.png | Bin 0 -> 14609 bytes .../Controllers/TodoListController.cs | 78 ++++++++----- TodoListClient/Startup.cs | 56 ++++++---- TodoListClient/appsettings.json | 2 +- 6 files changed, 134 insertions(+), 110 deletions(-) create mode 100644 ReadmeFiles/Teams icon 1.png diff --git a/.gitignore b/.gitignore index dfcfd56..2553e8d 100644 --- a/.gitignore +++ b/.gitignore @@ -348,3 +348,6 @@ MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ +/TodoListClient/Properties/ServiceDependencies/CAAuthNContextAppDemo - Web Deploy +/TodoListClient/Properties/serviceDependencies.CAAuthNContextAppDemo - Web Deploy.json +/AppCreationScripts/createdApps.html diff --git a/README.md b/README.md index de0ccea..0dd4308 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ description: "This sample demonstrates using the Conditional Access auth context This code sample uses the Conditional Access Auth Context to demand a higher bar of authentication for certain high-privileged and sensitive operations in a Web App. > To use the CA Auth context in a Web API, please try the [Use the Conditional Access auth context to perform step-up authentication for high-privilege operations in a Web API](https://github.com/Azure-Samples/ms-identity-ca-auth-context/blob/main/README.md) code sample - + ## Scenario 1. The client ASP.NET Core Web App uses the [Microsoft.Identity.Web](https://aka.ms/microsoft-identity-web) and Microsoft Authentication Library for .NET ([MSAL.NET](https://aka.ms/msal-net)) to sign-in a user with **Azure AD**. @@ -40,7 +40,7 @@ This code sample uses the Conditional Access Auth Context to demand a higher bar ![Overview](./ReadmeFiles/topology.png) > :information_source: Check out the recorded session on this topic: [Use Conditional Access Auth Context in your app for step-up authentication](https://www.youtube.com/watch?v=_iO7CfoktTY&ab_channel=Microsoft365Community) -> + ## Prerequisites - [Visual Studio](https://visualstudio.microsoft.com/downloads/) @@ -149,6 +149,8 @@ Open the project in your IDE (like Visual Studio or Visual Studio Code) to confi 1. Find the key `ClientId` and replace the existing value with the application ID (clientId) of `TodoListClient-authContext-webapp` app copied from the Azure portal. 1. Find the key `ClientSecret` and replace the existing value with the key you saved during the creation of `TodoListClient-authContext-webapp` copied from the Azure portal. + > You'd note in the *appsettings.json* file that Microsoft Graph settings are for the beta version of Microsoft Graph. This is because the API is only available in MS Graph beta at the time of writing this sample. You would update your code to use the MS Graph production (v1.0) version when the API becomes GA. + ## Running the sample > For Visual Studio Users @@ -223,6 +225,12 @@ If an operation was saved for a certain authContext and there is a CA policy con .AddInMemoryTokenCaches(); ``` + We also add a class that helps us when working with Microsoft Graph using the following line + + ```csharp + services.AddScoped(); + ``` + 1. In `AdminController.cs`, the method **GetAuthenticationContextValues** returns a default set of AuthN context values for the app to work with, either from Graph or a default hard coded set. ```csharp @@ -237,20 +245,15 @@ If an operation was saved for a certain authContext and there is a CA policy con string sessionKey = "ACRS"; - if (HttpContext.Session.Get>(sessionKey) != default) - { + if (HttpContext.Session.Get>(sessionKey) != default) { dictACRValues = HttpContext.Session.Get>(sessionKey); } - else - { + else { var existingAuthContexts = await _authContextClassReferencesOperations.ListAuthenticationContextClassReferencesAsync(); - if (existingAuthContexts.Count() > 0) - { + if (existingAuthContexts.Count() > 0) { dictACRValues.Clear(); - - foreach (var authContext in existingAuthContexts) - { + foreach (var authContext in existingAuthContexts) { dictACRValues.Add(authContext.Id, authContext.DisplayName); } @@ -342,7 +345,7 @@ If an operation was saved for a certain authContext and there is a CA policy con 1. In `TodoListController.cs`, the method **CheckForRequiredAuthContext** retrieves the acrsvalues from database for the request method. Then checks if the access token has `acrs` claim with acrsValue. If does not exists then it creates a **claims** payload to be sent back to Azure AD. ```csharp - public string CheckForRequiredAuthContext(string method) + public string CheckForRequiredAuthContext(string method) { string claimsChallenge = string.Empty; @@ -364,17 +367,13 @@ If an operation was saved for a certain authContext and there is a CA policy con if (acrsClaim?.Value != savedAuthContextId) { claimsChallenge = "{\"id_token\":{\"acrs\":{\"essential\":true,\"value\":\"" + savedAuthContextId + "\"}}}"; - } - } - - return claimsChallenge; - } + } ``` ### Code for the Web App (TodoListClient) -Methods in `TodoListController.cs` challenges the user to re-authenticate if a claims payload is returned by the CheckforRequiredAuthContext(): +Methods in `TodoListController.cs` challenges the user to re-authenticate if a claims payload is returned by the *CheckforRequiredAuthContext()*: ```csharp string claimsChallenge = CheckForRequiredAuthContext("Delete"); @@ -395,55 +394,45 @@ Take a look into the example of using session state. ```csharp // GET: TodoList/Create - public ActionResult Create() - { - string claimsChallenge = CheckForRequiredAuthContext(Request.Method); - if (!string.IsNullOrWhiteSpace(claimsChallenge)) - { - _consentHandler.ChallengeUser(new string[] { "user.read" }, claimsChallenge); - return new EmptyResult(); - } - var todoObject = TodoSessionState(SessionAction.Get); - if (todo != null && todoObject.IsInitialized()) - { - PersistTodo(todoObject); - TodoSessionState(SessionAction.Set); - return RedirectToAction("Index"); - } - Todo todo = new Todo() { Owner = HttpContext.User.Identity.Name }; - return View(todo); - } - // POST: TodoList/Create - [HttpPost] - [ValidateAntiForgeryToken] public ActionResult Create([Bind("Title,Owner")] Todo todo) { - string claimsChallenge = CheckForRequiredAuthContext(Request.Method); - if (!string.IsNullOrWhiteSpace(claimsChallenge)) + //add owner accountid to new todo + todo.AccountId = HttpContext.User.GetMsalAccountId(); + todo.Owner = GetCurrentUsersName(); + + if (ChallengeUser(HttpMethods.Post)) { - _consentHandler.ChallengeUser(new string[] { "user.read" }, claimsChallenge); + //save in session state before redirecting to GET handler TodoSessionState(SessionAction.Set, todo); - return new EmptyResult(); + + return View(); } - PersistTodo(new Todo() { Owner = HttpContext.User.Identity.Name, Title = todo.Title }); + + SaveToDoToDatabase(new Todo() { Owner = todo.Owner, Title = todo.Title, AccountId = todo.AccountId }); + return RedirectToAction("Index"); } - private Todo TodoSessionState(SessionAction action, Todo todo = null) + // POST: TodoList/Delete + public ActionResult Delete(int id, [Bind("Id,Title,Owner")] Todo todo) { - string todoObject = "Todo"; - switch (action) - { - case SessionAction.Set: - HttpContext.Session.SetString(todoObject, todo != null ? JsonSerializer.Serialize(todo) : ""); - break; - case SessionAction.Get: - var obj = HttpContext.Session.GetString(todoObject); - return !string.IsNullOrEmpty(obj) ? JsonSerializer.Deserialize(obj) : null; - default: - break; - } - return todo; + if (ChallengeUser(HttpMethods.Delete)) + { + //save in session state before redirecting to GET handler + TodoSessionState(SessionAction.Set, new Todo { Id = id }); + + return View(); + } + + //make sure the received todo is inside database before deleting + var todoFromDb = _commonDBContext.Todo.Find(id); + if (todoFromDb != null) + { + DeleteToDoFromDatabase(todoFromDb); + } + + return RedirectToAction("Index"); } + ``` ## More information diff --git a/ReadmeFiles/Teams icon 1.png b/ReadmeFiles/Teams icon 1.png new file mode 100644 index 0000000000000000000000000000000000000000..ca866fb53d6702805f24d1c9f4cead003e278a01 GIT binary patch literal 14609 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 Hu0mjfx2+`R literal 0 HcmV?d00001 diff --git a/TodoListClient/Controllers/TodoListController.cs b/TodoListClient/Controllers/TodoListController.cs index 9dbc1af..87b598a 100644 --- a/TodoListClient/Controllers/TodoListController.cs +++ b/TodoListClient/Controllers/TodoListController.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Security.Claims; using System.Text.Json; +using Microsoft.EntityFrameworkCore; using TodoListClient.Models; namespace TodoListClient.Controllers @@ -23,12 +24,47 @@ public TodoListController(IHttpContextAccessor contextAccessor, IConfiguration c _configuration = configuration; _commonDBContext = commonDBContext; this._consentHandler = consentHandler; + + EnsureDatabaseIsAwakeAndAvailable(); + } + + /// + /// Makes sure Database is available + /// + /// + private void EnsureDatabaseIsAwakeAndAvailable() + { + + // give the database some time to wake up + var retryTimes = 3; + while (retryTimes-- > 0) + { + try + { + _commonDBContext.Todo.Take(2); + } + catch (Exception) + { + //throw exception if database didn't wakeup after 3 attempts + if (retryTimes == 0) + { + throw new Exception( + "Unable to reach the database after multiple tries. The app will not be able to function as expected."); + } + } + } + } + + private string GetCurrentUsersName() + { + return HttpContext?.User?.Identity?.Name; } // GET: api/values [HttpGet] public IEnumerable Get() { + EnsureDatabaseIsAwakeAndAvailable(); return _commonDBContext.Todo.ToList(); } @@ -46,25 +82,9 @@ public ActionResult Index() //reset session on every entry to TODO's list TodoSessionState(SessionAction.Set); - //serveless database should have time to wake up - var retryTimes = 3; - while (retryTimes-- > 0) - { - try - { - return View(_commonDBContext.Todo.Where(l => l.AccountId.Equals(HttpContext.User.GetMsalAccountId())).ToList()); - } - catch (Exception) - { - //throw exception if database didn't wakeup after 3 attempts - if (retryTimes == 0) - { - throw; - } - } - } + EnsureDatabaseIsAwakeAndAvailable(); - return View(); + return View(_commonDBContext.Todo.Where(l => l.AccountId.Equals(HttpContext.User.GetMsalAccountId())).ToList()); } // GET: TodoList/Details/5 @@ -85,7 +105,7 @@ public ActionResult Create() return Create(todoFromSessionState); } - Todo todo = new Todo() { Owner = HttpContext.User.Identity.Name }; + Todo todo = new Todo() { Owner = GetCurrentUsersName() }; return View(todo); } @@ -97,7 +117,7 @@ public ActionResult Create([Bind("Title,Owner")] Todo todo) { //add owner accountid to new todo todo.AccountId = HttpContext.User.GetMsalAccountId(); - todo.Owner = HttpContext.User.Identity.Name; + todo.Owner = GetCurrentUsersName(); if (ChallengeUser(HttpMethods.Post)) { @@ -107,7 +127,7 @@ public ActionResult Create([Bind("Title,Owner")] Todo todo) return View(); } - SaveToDatabase(new Todo() { Owner = todo.Owner, Title = todo.Title, AccountId = todo.AccountId }); + SaveToDoToDatabase(new Todo() { Owner = todo.Owner, Title = todo.Title, AccountId = todo.AccountId }); return RedirectToAction("Index"); } @@ -120,7 +140,7 @@ public ActionResult Edit(int id) if (todoFromSessionState != null && todoFromSessionState.IsInitialized && todoFromSessionState.Id == id) { - UpdateDatabase(todoFromSessionState); + UpdateToDoInDatabase(todoFromSessionState); return Edit(todoFromSessionState.Id, todoFromSessionState); } else @@ -149,7 +169,7 @@ public ActionResult Edit(int id, [Bind("Id,Title,Owner")] Todo todo) return View(); } - UpdateDatabase(todo); + UpdateToDoInDatabase(todo); return RedirectToAction("Index"); } @@ -189,7 +209,7 @@ public ActionResult Delete(int id, [Bind("Id,Title,Owner")] Todo todo) var todoFromDb = _commonDBContext.Todo.Find(id); if (todoFromDb != null) { - DeleteFromDatabase(todoFromDb); + DeleteToDoFromDatabase(todoFromDb); } return RedirectToAction("Index"); @@ -230,19 +250,19 @@ public string CheckForRequiredAuthContext(string method) return claimsChallenge; } - private void DeleteFromDatabase(Todo todoToRemove) + private void DeleteToDoFromDatabase(Todo todoToRemove) { _commonDBContext.Todo.Remove(todoToRemove); _commonDBContext.SaveChanges(); } - private void SaveToDatabase(Todo todoToSave) + private void SaveToDoToDatabase(Todo todoToSave) { _commonDBContext.Todo.Add(todoToSave); _commonDBContext.SaveChanges(); } - private void UpdateDatabase(Todo todoToUpdate) + private void UpdateToDoInDatabase(Todo todoToUpdate) { _commonDBContext.Todo.Update(todoToUpdate); _commonDBContext.SaveChanges(); @@ -286,7 +306,7 @@ private bool ChallengeUser(string actionName) if (!string.IsNullOrWhiteSpace(claimsChallenge)) { - _consentHandler.ChallengeUser(new string[] { "user.read" }, claimsChallenge); + _consentHandler.ChallengeUser(new string[] { _configuration["GraphBeta:Scopes"] }, claimsChallenge); return true; } @@ -295,7 +315,7 @@ private bool ChallengeUser(string actionName) } /// - /// Enumerator to distingush between session state actions + /// Enumerator to distinguish between session state actions /// private enum SessionAction { diff --git a/TodoListClient/Startup.cs b/TodoListClient/Startup.cs index 2ad0de9..edd0349 100644 --- a/TodoListClient/Startup.cs +++ b/TodoListClient/Startup.cs @@ -14,6 +14,7 @@ using Microsoft.Identity.Web.UI; using TodoListClient.Models; using System; +using System.IdentityModel.Tokens.Jwt; using Microsoft.EntityFrameworkCore; namespace TodoListClient @@ -55,7 +56,7 @@ public void ConfigureServices(IServiceCollection services) // By default, the claims mapping will map claim names in the old format to accommodate older SAML applications. // 'http://schemas.microsoft.com/ws/2008/06/identity/claims/role' instead of 'roles' // This flag ensures that the ClaimsIdentity claims collection will be built from the claims in the token - // JwtSecurityTokenHandler.DefaultMapInboundClaims = false; + JwtSecurityTokenHandler.DefaultMapInboundClaims = false; // Adds Microsoft Identity platform (AAD v2.0) support to authenticate users services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) @@ -87,27 +88,7 @@ public void ConfigureServices(IServiceCollection services) public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { - using (var serviceScope = app.ApplicationServices.GetService().CreateScope()) - { - //serveless database should have time to wake up - var retryTimes = 3; - while (retryTimes-- > 0) - { - try - { - var context = serviceScope.ServiceProvider.GetRequiredService(); - context.Database.EnsureCreated(); - } - catch (Exception) - { - //throw exception if database didn't wakeup after 3 attempts - if (retryTimes == 0) - { - throw; - } - } - } - } + EnsureDatabaseAvailability(app); if (env.IsDevelopment()) { @@ -145,5 +126,36 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) endpoints.MapRazorPages(); }); } + + /// + /// Hits the Datbase multiple times to ensure that its waken up and available for the app + /// + /// + /// + private static void EnsureDatabaseAvailability(IApplicationBuilder app) + { + using (var serviceScope = app.ApplicationServices.GetService().CreateScope()) + { + // give the database should have time to wake up + var retryTimes = 3; + while (retryTimes-- > 0) + { + try + { + var context = serviceScope.ServiceProvider.GetRequiredService(); + context.Database.EnsureCreated(); + } + catch (Exception) + { + //throw exception if database didn't wakeup after 3 attempts + if (retryTimes == 0) + { + throw new Exception( + "Unable to reach the database after multiple tries. The app will not be able to function as expected."); + } + } + } + } + } } } \ No newline at end of file diff --git a/TodoListClient/appsettings.json b/TodoListClient/appsettings.json index 4839d09..8ceabe1 100644 --- a/TodoListClient/appsettings.json +++ b/TodoListClient/appsettings.json @@ -19,7 +19,7 @@ "Scopes": "Policy.Read.ConditionalAccess Policy.ReadWrite.ConditionalAccess" }, "ConnectionStrings": { - "DefaultConnection": "your database connection string here" + "DefaultConnection": "your database connection string here" // For example, "Server=(localdb)\\mssqllocaldb;Database=CommonDBContext;Trusted_Connection=True;MultipleActiveResultSets=true" }, "Logging": { "LogLevel": { From f4050117436f0b5f3bacca70e871a42728d53222 Mon Sep 17 00:00:00 2001 From: Alexander Beyderman Date: Thu, 14 Jul 2022 16:41:36 -0400 Subject: [PATCH 17/19] cleanup --- TodoListClient/Controllers/HomeController.cs | 7 ------- TodoListClient/Controllers/TodoListController.cs | 11 +++++++---- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/TodoListClient/Controllers/HomeController.cs b/TodoListClient/Controllers/HomeController.cs index cc3ed33..89f429d 100644 --- a/TodoListClient/Controllers/HomeController.cs +++ b/TodoListClient/Controllers/HomeController.cs @@ -9,13 +9,6 @@ namespace TodoListClient.Controllers [Authorize] public class HomeController : Controller { - private readonly ITokenAcquisition tokenAcquisition; - - public HomeController(ITokenAcquisition tokenAcquisition) - { - this.tokenAcquisition = tokenAcquisition; - } - public IActionResult Index() { return View(); diff --git a/TodoListClient/Controllers/TodoListController.cs b/TodoListClient/Controllers/TodoListController.cs index 87b598a..2b14c2a 100644 --- a/TodoListClient/Controllers/TodoListController.cs +++ b/TodoListClient/Controllers/TodoListController.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Security.Claims; using System.Text.Json; -using Microsoft.EntityFrameworkCore; using TodoListClient.Models; namespace TodoListClient.Controllers @@ -19,12 +18,16 @@ public class TodoListController : Controller private IConfiguration _configuration; private readonly MicrosoftIdentityConsentAndConditionalAccessHandler _consentHandler; + private string _msalAccountId; + public TodoListController(IHttpContextAccessor contextAccessor, IConfiguration configuration, CommonDBContext commonDBContext, MicrosoftIdentityConsentAndConditionalAccessHandler consentHandler) { _configuration = configuration; _commonDBContext = commonDBContext; this._consentHandler = consentHandler; + _msalAccountId = HttpContext.User.GetMsalAccountId(); + EnsureDatabaseIsAwakeAndAvailable(); } @@ -84,7 +87,7 @@ public ActionResult Index() EnsureDatabaseIsAwakeAndAvailable(); - return View(_commonDBContext.Todo.Where(l => l.AccountId.Equals(HttpContext.User.GetMsalAccountId())).ToList()); + return View(_commonDBContext.Todo.Where(l => l.AccountId.Equals(_msalAccountId)).ToList()); } // GET: TodoList/Details/5 @@ -116,7 +119,7 @@ public ActionResult Create() public ActionResult Create([Bind("Title,Owner")] Todo todo) { //add owner accountid to new todo - todo.AccountId = HttpContext.User.GetMsalAccountId(); + todo.AccountId = _msalAccountId; todo.Owner = GetCurrentUsersName(); if (ChallengeUser(HttpMethods.Post)) @@ -159,7 +162,7 @@ public ActionResult Edit(int id, [Bind("Id,Title,Owner")] Todo todo) return NotFound(); } - todo.AccountId = HttpContext.User.GetMsalAccountId(); + todo.AccountId = _msalAccountId; if (ChallengeUser(HttpMethods.Post)) { From ba080b00e4d2102b592655e35e1223093775d985 Mon Sep 17 00:00:00 2001 From: Kalyan Krishna Date: Mon, 18 Jul 2022 19:28:30 -0700 Subject: [PATCH 18/19] Minor error enhancement --- AppCreationScripts/AppCreationScripts.md | 101 ++----- AppCreationScripts/Cleanup.ps1 | 77 +++-- AppCreationScripts/Configure.ps1 | 277 ++++++++---------- AppCreationScripts/sample.json | 7 +- .../Controllers/TodoListController.cs | 4 +- TodoListClient/Startup.cs | 5 +- TodoListClient/appsettings.json | 2 +- 7 files changed, 198 insertions(+), 275 deletions(-) diff --git a/AppCreationScripts/AppCreationScripts.md b/AppCreationScripts/AppCreationScripts.md index 7512ab4..6e60a27 100644 --- a/AppCreationScripts/AppCreationScripts.md +++ b/AppCreationScripts/AppCreationScripts.md @@ -1,45 +1,35 @@ -# Registering the sample apps with the Microsoft identity platform and updating the configuration files using PowerShell +# 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. 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. (Other ways of running the scripts are described below) +1. Run the script to create your Azure AD application and configure the code of the sample application accordingly. ```PowerShell cd .\AppCreationScripts\ - .\Configure.ps1 + .\Configure.ps1 -TenantId "your test tenant's id" -AzureEnvironmentName "[Optional] - Azure environment, defaults to 'Global'" ``` -1. Open the Visual Studio solution and click start - ### More details -The following paragraphs: - -- [Registering the sample apps with the Microsoft identity platform and updating the configuration files using PowerShell](#Registering-the-sample-apps-with-the-Microsoft-identity-platform-and-updating-the-configuration-files-using-PowerShell) - - [Overview](#Overview) - - [Quick summary](#Quick-summary) - - [More details](#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 (non-interactive)](#Option-2-non-interactive) - - [Option 3 (Interactive, but create apps in a specified tenant)](#Option-3-Interactive-but-create-apps-in-a-specified-tenant) - - [Option 4 (non-interactive, and create apps in a specified tenant)](#Option-4-non-interactive-and-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](#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 @@ -50,14 +40,14 @@ This sample comes with two PowerShell scripts, which automate the creation of th These scripts are: - `Configure.ps1` which: - - creates Azure AD applications and their related objects (permissions, dependencies, secrets), - - changes the configuration files in the C# and JavaScript projects. + - 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). +- `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 @@ -75,23 +65,23 @@ The `Configure.ps1` will stop if it tries to create an Azure AD application whic Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process ``` -### (Optionally) install AzureAD PowerShell modules +### (Optionally) install Microsoft.Graph.Applications PowerShell modules -The scripts install the required PowerShell module (AzureAD) 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: +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 AzureAD PowerShell modules. For this: +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). + 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 AzureAD + Install-Module Microsoft.Graph.Applications ``` or if you cannot be administrator on your machine, run: - + ```PowerShell - Install-Module AzureAD -Scope CurrentUser + Install-Module Microsoft.Graph.Applications -Scope CurrentUser ``` ### Run the script and start running @@ -106,44 +96,29 @@ The scripts install the required PowerShell module (AzureAD) for the current use 1. Open the Visual Studio solution, and in the solution's context menu, choose **Set Startup Projects**. 1. select **Start** for the projects -You're done. this just works! +You're done! -### Four ways to run the script +### 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, -- non-interactive: you will provide 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, -- non-interactive in specific tenant: you will provide tenant in which you want to create the objects and credentials, and the scripts will 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). +- 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 (non-interactive) - -When you know the identity and credentials of the user in the name of whom you want to create the applications, you can use the non-interactive approach. It's more adapted to DevOps. Here is an example of script you'd want to run in a PowerShell Window - -```PowerShell -$secpasswd = ConvertTo-SecureString "[Password here]" -AsPlainText -Force -$mycreds = New-Object System.Management.Automation.PSCredential ("[login@tenantName here]", $secpasswd) -. .\Cleanup.ps1 -Credential $mycreds -. .\Configure.ps1 -Credential $mycreds -``` - -Of course, in real life, you might already get the password as a `SecureString`. You might also want to get the password from KeyVault. - -#### Option 3 (Interactive, but create apps in a specified tenant) +#### 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) +- 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 @@ -155,21 +130,9 @@ $tenantId = "yourTenantIdGuid" . .\Configure.ps1 -TenantId $tenantId ``` -#### Option 4 (non-interactive, and create apps in a specified tenant) - -This option combines option 2 and option 3: it creates the application in a specific tenant. See option 3 for the way to get the tenant Id. Then run: - -```PowerShell -$secpasswd = ConvertTo-SecureString "[Password here]" -AsPlainText -Force -$mycreds = New-Object System.Management.Automation.PSCredential ("[login@tenantName here]", $secpasswd) -$tenantId = "yourTenantIdGuid" -. .\Cleanup.ps1 -Credential $mycreds -TenantId $tenantId -. .\Configure.ps1 -Credential $mycreds -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`. +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: diff --git a/AppCreationScripts/Cleanup.ps1 b/AppCreationScripts/Cleanup.ps1 index e5a8d91..334888f 100644 --- a/AppCreationScripts/Cleanup.ps1 +++ b/AppCreationScripts/Cleanup.ps1 @@ -1,26 +1,17 @@ + [CmdletBinding()] param( - [PSCredential] $Credential, [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 (it defaults to AzureCloud)')] + [Parameter(Mandatory=$False, HelpMessage='Azure environment to use while running the script. Default = Global')] [string] $azureEnvironmentName ) -#Requires -Modules AzureAD - - -if ($null -eq (Get-Module -ListAvailable -Name "AzureAD")) { - Install-Module "AzureAD" -Scope CurrentUser -} -Import-Module AzureAD -$ErrorActionPreference = "Stop" - Function Cleanup { if (!$azureEnvironmentName) { - $azureEnvironmentName = "AzureCloud" + $azureEnvironmentName = "Global" } <# @@ -31,63 +22,63 @@ Function Cleanup # $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. - # Login to Azure PowerShell (interactive if credentials are not already provided: - # you'll need to sign-in with creds enabling your to create apps in the tenant) - if (!$Credential -and $TenantId) - { - $creds = Connect-AzureAD -TenantId $tenantId -AzureEnvironmentName $azureEnvironmentName + # Connect to the Microsoft Graph API + Write-Host "Connecting to Microsoft Graph" + if ($tenantId -eq "") { + Connect-MgGraph -Scopes "Application.ReadWrite.All" -Environment $azureEnvironmentName + $tenantId = (Get-MgContext).TenantId } - else - { - if (!$TenantId) - { - $creds = Connect-AzureAD -Credential $Credential -AzureEnvironmentName $azureEnvironmentName - } - else - { - $creds = Connect-AzureAD -TenantId $tenantId -Credential $Credential -AzureEnvironmentName $azureEnvironmentName - } - } - - if (!$tenantId) - { - $tenantId = $creds.Tenant.Id + else { + Connect-MgGraph -TenantId $tenantId -Scopes "Application.ReadWrite.All" -Environment $azureEnvironmentName } - $tenant = Get-AzureADTenantDetail - $tenantName = ($tenant.VerifiedDomains | Where-Object { $_._Default -eq $True }).Name # Removes the applications - Write-Host "Cleaning-up applications from tenant '$tenantName'" + Write-Host "Cleaning-up applications from tenant '$tenantId'" Write-Host "Removing 'client' (TodoListClient-authContext-webapp) if needed" try { - Get-AzureADApplication -Filter "DisplayName eq 'TodoListClient-authContext-webapp'" | ForEach-Object {Remove-AzureADApplication -ObjectId $_.ObjectId } + Get-MgApplication -Filter "DisplayName eq 'TodoListClient-authContext-webapp'" | ForEach-Object {Remove-MgApplication -ApplicationId $_.Id } } catch { - Write-Host "Unable to remove the 'TodoListClient-authContext-webapp' . Try deleting manually." -ForegroundColor White -BackgroundColor Red + Write-Host "Unable to remove the application 'TodoListClient-authContext-webapp' . Try deleting manually." -ForegroundColor White -BackgroundColor Red } - $apps = Get-AzureADApplication -Filter "DisplayName eq 'TodoListClient-authContext-webapp'" + + Write-Host "Making sure there are no more (TodoListClient-authContext-webapp) applications found, will remove if needed..." + $apps = Get-MgApplication -Filter "DisplayName eq 'TodoListClient-authContext-webapp'" + if ($apps) { - Remove-AzureADApplication -ObjectId $apps.ObjectId + Remove-MgApplication -ApplicationId $apps.Id } foreach ($app in $apps) { - Remove-AzureADApplication -ObjectId $app.ObjectId + Remove-MgApplication -ApplicationId $app.Id Write-Host "Removed TodoListClient-authContext-webapp.." } + # also remove service principals of this app try { - Get-AzureADServicePrincipal -filter "DisplayName eq 'TodoListClient-authContext-webapp'" | ForEach-Object {Remove-AzureADServicePrincipal -ObjectId $_.Id -Confirm:$false} + Get-MgServicePrincipal -filter "DisplayName eq 'TodoListClient-authContext-webapp'" | ForEach-Object {Remove-MgServicePrincipal -ApplicationId $_.Id -Confirm:$false} } catch { - Write-Host "Unable to remove ServicePrincipal 'TodoListClient-authContext-webapp' . Try deleting manually from Enterprise applications." -ForegroundColor White -BackgroundColor Red + Write-Host "Unable to remove ServicePrincipal 'TodoListClient-authContext-webapp' . Try deleting manually from Enterprise applications." -ForegroundColor White -BackgroundColor Red } } -Cleanup -Credential $Credential -tenantId $TenantId \ No newline at end of file +if ($null -eq (Get-Module -ListAvailable -Name "Microsoft.Graph.Applications")) { + Install-Module "Microsoft.Graph.Applications" -Scope CurrentUser +} +Import-Module Microsoft.Graph.Applications +$ErrorActionPreference = "Stop" + + +Cleanup -tenantId $tenantId -environment $azureEnvironmentName + +Write-Host "Disconnecting from tenant" +Disconnect-MgGraph + diff --git a/AppCreationScripts/Configure.ps1 b/AppCreationScripts/Configure.ps1 index f178b65..5bb5380 100644 --- a/AppCreationScripts/Configure.ps1 +++ b/AppCreationScripts/Configure.ps1 @@ -1,49 +1,32 @@ + [CmdletBinding()] param( - [PSCredential] $Credential, [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 (it defaults to AzureCloud)')] + [Parameter(Mandatory=$False, HelpMessage='Azure environment to use while running the script. Default = Global')] [string] $azureEnvironmentName ) -#Requires -Modules AzureAD - <# 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. - Before running this script you need to install the AzureAD cmdlets as an administrator. - For this: - 1) Run Powershell as an administrator - 2) in the PowerShell window, type: Install-Module AzureAD - + In case you don't have Microsoft.Graph.Applications already installed, the script will automatically install it for the current user + There are four ways to run this script. For more information, read the AppCreationScripts.md file in the same folder as this script. #> -# Create a password that can be used as an application key -Function ComputePassword -{ - $aesManaged = New-Object "System.Security.Cryptography.AesManaged" - $aesManaged.Mode = [System.Security.Cryptography.CipherMode]::CBC - $aesManaged.Padding = [System.Security.Cryptography.PaddingMode]::Zeros - $aesManaged.BlockSize = 128 - $aesManaged.KeySize = 256 - $aesManaged.GenerateKey() - return [System.Convert]::ToBase64String($aesManaged.Key) -} - # Create an application key # See https://www.sabin.io/blog/adding-an-azure-active-directory-application-and-key-using-powershell/ -Function CreateAppKey([DateTime] $fromDate, [double] $durationInYears, [string]$pw) +Function CreateAppKey([DateTime] $fromDate, [double] $durationInMonths) { - $endDate = $fromDate.AddYears($durationInYears) - $keyId = (New-Guid).ToString(); - $key = New-Object Microsoft.Open.AzureAD.Model.PasswordCredential - $key.StartDate = $fromDate - $key.EndDate = $endDate - $key.Value = $pw - $key.KeyId = $keyId + $key = New-Object Microsoft.Graph.PowerShell.Models.MicrosoftGraphPasswordCredential + + $key.StartDateTime = $fromDate + $key.EndDateTime = $fromDate.AddMonths($durationInMonths) + $key.KeyId = (New-Guid).ToString() + $key.DisplayName = "app secret" + return $key } @@ -53,19 +36,19 @@ Function CreateAppKey([DateTime] $fromDate, [double] $durationInYears, [string]$ Function AddResourcePermission($requiredAccess, ` $exposedPermissions, [string]$requiredAccesses, [string]$permissionType) { - foreach($permission in $requiredAccesses.Trim().Split("|")) + foreach($permission in $requiredAccesses.Trim().Split("|")) + { + foreach($exposedPermission in $exposedPermissions) { - foreach($exposedPermission in $exposedPermissions) - { - if ($exposedPermission.Value -eq $permission) - { - $resourceAccess = New-Object Microsoft.Open.AzureAD.Model.ResourceAccess - $resourceAccess.Type = $permissionType # Scope = Delegated permissions | Role = Application permissions - $resourceAccess.Id = $exposedPermission.Id # Read directory data - $requiredAccess.ResourceAccess.Add($resourceAccess) - } - } + if ($exposedPermission.Value -eq $permission) + { + $resourceAccess = New-Object Microsoft.Graph.PowerShell.Models.MicrosoftGraphResourceAccess + $resourceAccess.Type = $permissionType # Scope = Delegated permissions | Role = Application permissions + $resourceAccess.Id = $exposedPermission.Id # Read directory data + $requiredAccess.ResourceAccess += $resourceAccess + } } + } } # @@ -80,17 +63,17 @@ Function GetRequiredPermissions([string] $applicationDisplayName, [string] $requ } else { - $sp = Get-AzureADServicePrincipal -Filter "DisplayName eq '$applicationDisplayName'" + $sp = Get-MgServicePrincipal -Filter "DisplayName eq '$applicationDisplayName'" } $appid = $sp.AppId - $requiredAccess = New-Object Microsoft.Open.AzureAD.Model.RequiredResourceAccess + $requiredAccess = New-Object Microsoft.Graph.PowerShell.Models.MicrosoftGraphRequiredResourceAccess $requiredAccess.ResourceAppId = $appid - $requiredAccess.ResourceAccess = New-Object System.Collections.Generic.List[Microsoft.Open.AzureAD.Model.ResourceAccess] + $requiredAccess.ResourceAccess = New-Object System.Collections.Generic.List[Microsoft.Graph.PowerShell.Models.MicrosoftGraphResourceAccess] # $sp.Oauth2Permissions | Select Id,AdminConsentDisplayName,Value: To see the list of all the Delegated permissions for the application: if ($requiredDelegatedPermissions) { - AddResourcePermission $requiredAccess -exposedPermissions $sp.Oauth2Permissions -requiredAccesses $requiredDelegatedPermissions -permissionType "Scope" + AddResourcePermission $requiredAccess -exposedPermissions $sp.Oauth2PermissionScopes -requiredAccesses $requiredDelegatedPermissions -permissionType "Scope" } # $sp.AppRoles | Select Id,AdminConsentDisplayName,Value: To see the list of all the Application permissions for the application @@ -104,16 +87,14 @@ Function GetRequiredPermissions([string] $applicationDisplayName, [string] $requ Function UpdateLine([string] $line, [string] $value) { - $index = $line.IndexOf('=') - $delimiter = ';' - if ($index -eq -1) - { - $index = $line.IndexOf(':') - $delimiter = ',' - } + $index = $line.IndexOf(':') + $lineEnd = '' + + if($line[$line.Length - 1] -eq ','){ $lineEnd = ',' } + if ($index -ige 0) { - $line = $line.Substring(0, $index+1) + " "+'"'+$value+'"'+$delimiter + $line = $line.Substring(0, $index+1) + " " + '"' + $value+ '"' + $lineEnd } return $line } @@ -138,137 +119,121 @@ Function UpdateTextFile([string] $configFilePath, [System.Collections.HashTable] Set-Content -Path $configFilePath -Value $lines -Force } -Set-Content -Value "" -Path createdApps.html -Add-Content -Value "" -Path createdApps.html - -$ErrorActionPreference = "Stop" - Function ConfigureApplications { -<#.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 -#> - $commonendpoint = "common" + <#.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 = "AzureCloud" + $azureEnvironmentName = "Global" } - # $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. - - # Login to Azure PowerShell (interactive if credentials are not already provided: - # you'll need to sign-in with creds enabling your to create apps in the tenant) - if (!$Credential -and $TenantId) - { - $creds = Connect-AzureAD -TenantId $tenantId -AzureEnvironmentName $azureEnvironmentName + # 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 "Application.ReadWrite.All" -Environment $azureEnvironmentName + $tenantId = (Get-MgContext).TenantId } - else - { - if (!$TenantId) - { - $creds = Connect-AzureAD -Credential $Credential -AzureEnvironmentName $azureEnvironmentName - } - else - { - $creds = Connect-AzureAD -TenantId $tenantId -Credential $Credential -AzureEnvironmentName $azureEnvironmentName - } + else { + Connect-MgGraph -TenantId $tenantId -Scopes "Application.ReadWrite.All" -Environment $azureEnvironmentName } - - if (!$tenantId) - { - $tenantId = $creds.Tenant.Id - } - - $tenant = Get-AzureADTenantDetail - $tenantName = ($tenant.VerifiedDomains | Where { $_._Default -eq $True }).Name - - # Get the user running the script to add the user as the app owner - $user = Get-AzureADUser -ObjectId $creds.Account.Id - # Create the client AAD application Write-Host "Creating the AAD application (TodoListClient-authContext-webapp)" - # Get a 2 years application key for the client Application - $pw = ComputePassword + # Get a 6 months application key for the client Application $fromDate = [DateTime]::Now; - $key = CreateAppKey -fromDate $fromDate -durationInYears 2 -pw $pw - $clientAppKey = $pw + $key = CreateAppKey -fromDate $fromDate -durationInMonths 6 + + # create the application - $clientAadApplication = New-AzureADApplication -DisplayName "TodoListClient-authContext-webapp" ` - -HomePage "https://localhost:44321/" ` - -LogoutUrl "https://localhost:44321/signout-oidc" ` - -ReplyUrls "https://localhost:44321/", "https://localhost:44321/signin-oidc" ` - -IdentifierUris "https://$tenantName/TodoListClient-authContext-webapp" ` - -PasswordCredentials $key ` - -PublicClient $False - - # create the service principal of the newly created application - $currentAppId = $clientAadApplication.AppId - $clientServicePrincipal = New-AzureADServicePrincipal -AppId $currentAppId -Tags {WindowsAzureActiveDirectoryIntegratedApp} - - # add the user running the script as an app owner if needed - $owner = Get-AzureADApplicationOwner -ObjectId $clientAadApplication.ObjectId - if ($owner -eq $null) - { - Add-AzureADApplicationOwner -ObjectId $clientAadApplication.ObjectId -RefObjectId $user.ObjectId + $clientAadApplication = New-MgApplication -DisplayName "TodoListClient-authContext-webapp" ` + -Web ` + @{ ` + RedirectUris = "https://localhost:44321/", "https://localhost:44321/signin-oidc"; ` + HomePageUrl = "https://localhost:44321/"; ` + LogoutUrl = "https://localhost:44321/signout-oidc"; ` + } ` + -SignInAudience AzureADMyOrg ` + #end of command + #add a secret to the application + $pwdCredential = Add-MgApplicationPassword -ApplicationId $clientAadApplication.Id -PasswordCredential $key + $clientAppKey = $pwdCredential.SecretText + + $tenantName = (Get-MgApplication -ApplicationId $clientAadApplication.Id).PublisherDomain + Update-MgApplication -ApplicationId $clientAadApplication.Id -IdentifierUris @("https://$tenantName/TodoListClient-authContext-webapp") + + # create the service principal of the newly created application + $currentAppId = $clientAadApplication.AppId + $clientServicePrincipal = New-MgServicePrincipal -AppId $currentAppId -Tags {WindowsAzureActiveDirectoryIntegratedApp} + + # add the user running the script as an app owner if needed + $owner = Get-MgApplicationOwner -ApplicationId $clientAadApplication.Id + if ($owner -eq $null) + { + New-MgApplicationOwnerByRef -ApplicationId $clientAadApplication.Id -BodyParameter = @{"@odata.id" = "htps://graph.microsoft.com/v1.0/directoryObjects/$user.ObjectId"} Write-Host "'$($user.UserPrincipalName)' added as an application owner to app '$($clientServicePrincipal.DisplayName)'" - } - - - Write-Host "Done creating the client application (TodoListClient-authContext-webapp)" - - # URL of the AAD application in the Azure portal - # Future? $clientPortalUrl = "https://portal.azure.com/#@"+$tenantName+"/blade/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/Overview/appId/"+$clientAadApplication.AppId+"/objectId/"+$clientAadApplication.ObjectId+"/isMSAApp/" - $clientPortalUrl = "https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/CallAnAPI/appId/"+$clientAadApplication.AppId+"/objectId/"+$clientAadApplication.ObjectId+"/isMSAApp/" - Add-Content -Value "" -Path createdApps.html - - $requiredResourcesAccess = New-Object System.Collections.Generic.List[Microsoft.Open.AzureAD.Model.RequiredResourceAccess] - - # Add Required Resources Access (from 'client' to 'Microsoft Graph') - Write-Host "Getting access from 'client' to 'Microsoft Graph'" - $requiredPermissions = GetRequiredPermissions -applicationDisplayName "Microsoft Graph" ` - -requiredDelegatedPermissions "User.Read|Policy.Read.ConditionalAccess|Policy.ReadWrite.ConditionalAccess" ` - - $requiredResourcesAccess.Add($requiredPermissions) - + } + Write-Host "Done creating the client application (TodoListClient-authContext-webapp)" - Set-AzureADApplication -ObjectId $clientAadApplication.ObjectId -RequiredResourceAccess $requiredResourcesAccess - Write-Host "Granted permissions." + # URL of the AAD application in the Azure portal + # Future? $clientPortalUrl = "https://portal.azure.com/#@"+$tenantName+"/blade/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/Overview/appId/"+$clientAadApplication.AppId+"/objectId/"+$clientAadApplication.Id+"/isMSAApp/" + $clientPortalUrl = "https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/CallAnAPI/appId/"+$clientAadApplication.AppId+"/objectId/"+$clientAadApplication.Id+"/isMSAApp/" + Add-Content -Value "" -Path createdApps.html + $requiredResourcesAccess = New-Object System.Collections.Generic.List[Microsoft.Graph.PowerShell.Models.MicrosoftGraphRequiredResourceAccess] - # Update config file for 'client' - $configFile = $pwd.Path + "\..\TodoListClient\appsettings.json" - Write-Host "Updating the sample code ($configFile)" - $dictionary = @{ "Domain" = $tenantName;"TenantId" = $tenantId;"ClientId" = $clientAadApplication.AppId;"ClientSecret" = $clientAppKey }; - UpdateTextFile -configFilePath $configFile -dictionary $dictionary - Write-Host "" - Write-Host -ForegroundColor Green "------------------------------------------------------------------------------------------------" - Write-Host "IMPORTANT: Please follow the instructions below to complete a few manual step(s) in the Azure portal": - Write-Host "- For 'client'" - Write-Host " - Navigate to '$clientPortalUrl'" - Write-Host " - Navigate to the API Permissions page and select 'Grant admin consent for (your tenant)'" -ForegroundColor Red + + # Add Required Resources Access (from 'client' to 'Microsoft Graph') + Write-Host "Getting access from 'client' to 'Microsoft Graph'" + $requiredPermissions = GetRequiredPermissions -applicationDisplayName "Microsoft Graph" ` + -requiredDelegatedPermissions "User.Read|Policy.Read.ConditionalAccess|Policy.ReadWrite.ConditionalAccess" ` + - Write-Host -ForegroundColor Green "------------------------------------------------------------------------------------------------" - if($isOpenSSL -eq 'Y') - { + $requiredResourcesAccess.Add($requiredPermissions) + Update-MgApplication -ApplicationId $clientAadApplication.Id -RequiredResourceAccess $requiredResourcesAccess + Write-Host "Granted permissions." + + # Update config file for 'client' + $configFile = $pwd.Path + "\..\TodoListClient\appsettings.json" + $dictionary = @{ "Domain" = $tenantName;"TenantId" = $tenantId;"ClientId" = $clientAadApplication.AppId;"ClientSecret" = $clientAppKey }; + + Write-Host "Updating the sample code ($configFile)" + + UpdateTextFile -configFilePath $configFile -dictionary $dictionary + Write-Host -ForegroundColor Green "------------------------------------------------------------------------------------------------" + Write-Host "IMPORTANT: Please follow the instructions below to complete a few manual step(s) in the Azure portal": + Write-Host "- For client" + Write-Host " - Navigate to $clientPortalUrl" + Write-Host " - Navigate to the API Permissions page and select 'Grant admin consent for (your tenant)'" -ForegroundColor Red + Write-Host -ForegroundColor Green "------------------------------------------------------------------------------------------------" + 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 "------------------------------------------------------------------------------------------------" - } - Add-Content -Value "
ApplicationAppIdUrl in the Azure portal
client$currentAppIdTodoListClient-authContext-webapp
client$currentAppIdTodoListClient-authContext-webapp
" -Path createdApps.html + } + Add-Content -Value "" -Path createdApps.html } # Pre-requisites -if ((Get-Module -ListAvailable -Name "AzureAD") -eq $null) { - Install-Module "AzureAD" -Scope CurrentUser +if ($null -eq (Get-Module -ListAvailable -Name "Microsoft.Graph.Applications")) { + Install-Module "Microsoft.Graph.Applications" -Scope CurrentUser } -Import-Module AzureAD +Import-Module Microsoft.Graph.Applications + +Set-Content -Value "" -Path createdApps.html +Add-Content -Value "" -Path createdApps.html + +$ErrorActionPreference = "Stop" # Run interactively (will ask you for the tenant ID) -ConfigureApplications -Credential $Credential -tenantId $TenantId \ No newline at end of file +ConfigureApplications -tenantId $tenantId -environment $azureEnvironmentName + +Write-Host "Disconnecting from tenant" +Disconnect-MgGraph \ No newline at end of file diff --git a/AppCreationScripts/sample.json b/AppCreationScripts/sample.json index 8c6190a..bfa6a1e 100644 --- a/AppCreationScripts/sample.json +++ b/AppCreationScripts/sample.json @@ -1,10 +1,13 @@ { "Sample": { - "Title": "This sample demonstrates using the Conditional Access auth context to perform step-up authentication for high-privilege and sensitive operations in a web app.", + "Title": "Use the Conditional Access auth context to perform step-up authentication for high-privilege operations in a Web app", "Level": 300, "Client": "ASP.NET Core Web App", "RepositoryUrl": "ms-identity-dotnetcore-ca-auth-context-app", - "Endpoint": "AAD v2.0" + "Endpoint": "AAD v2.0", + "Description":"This sample demonstrates using the Conditional Access auth context to perform step-up authentication for high-privilege and sensitive operations in a web app.", + "Languages": [ "csharp" ], + "Products": [ "aspnet-core", "azure-active-directory", "ms-graph" ] }, /* diff --git a/TodoListClient/Controllers/TodoListController.cs b/TodoListClient/Controllers/TodoListController.cs index 2b14c2a..0b887b0 100644 --- a/TodoListClient/Controllers/TodoListController.cs +++ b/TodoListClient/Controllers/TodoListController.cs @@ -46,13 +46,13 @@ private void EnsureDatabaseIsAwakeAndAvailable() { _commonDBContext.Todo.Take(2); } - catch (Exception) + catch (Exception ex) { //throw exception if database didn't wakeup after 3 attempts if (retryTimes == 0) { throw new Exception( - "Unable to reach the database after multiple tries. The app will not be able to function as expected."); + $"Unable to reach the database after multiple tries. The app will not be able to function as expected. {ex}"); } } } diff --git a/TodoListClient/Startup.cs b/TodoListClient/Startup.cs index edd0349..07ac0bb 100644 --- a/TodoListClient/Startup.cs +++ b/TodoListClient/Startup.cs @@ -145,14 +145,15 @@ private static void EnsureDatabaseAvailability(IApplicationBuilder app) var context = serviceScope.ServiceProvider.GetRequiredService(); context.Database.EnsureCreated(); } - catch (Exception) + catch (Exception ex) { //throw exception if database didn't wakeup after 3 attempts if (retryTimes == 0) { throw new Exception( - "Unable to reach the database after multiple tries. The app will not be able to function as expected."); + $"Unable to reach the database after multiple tries. The app will not be able to function as expected. {ex}"); } + } } } diff --git a/TodoListClient/appsettings.json b/TodoListClient/appsettings.json index 8ceabe1..5e15537 100644 --- a/TodoListClient/appsettings.json +++ b/TodoListClient/appsettings.json @@ -19,7 +19,7 @@ "Scopes": "Policy.Read.ConditionalAccess Policy.ReadWrite.ConditionalAccess" }, "ConnectionStrings": { - "DefaultConnection": "your database connection string here" // For example, "Server=(localdb)\\mssqllocaldb;Database=CommonDBContext;Trusted_Connection=True;MultipleActiveResultSets=true" + "DefaultConnection": "your database connection string here" // For example, "Server=(localdb)\\MSSQLLocalDB;Integrated Security=true" }, "Logging": { "LogLevel": { From f4bb268e13ffe9aeb37e1f4e127dc55e0c4dd84b Mon Sep 17 00:00:00 2001 From: Alexander Beyderman Date: Tue, 19 Jul 2022 15:30:26 -0400 Subject: [PATCH 19/19] update --- TodoListClient/Controllers/TodoListController.cs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/TodoListClient/Controllers/TodoListController.cs b/TodoListClient/Controllers/TodoListController.cs index 0b887b0..6fd49d9 100644 --- a/TodoListClient/Controllers/TodoListController.cs +++ b/TodoListClient/Controllers/TodoListController.cs @@ -18,15 +18,11 @@ public class TodoListController : Controller private IConfiguration _configuration; private readonly MicrosoftIdentityConsentAndConditionalAccessHandler _consentHandler; - private string _msalAccountId; - public TodoListController(IHttpContextAccessor contextAccessor, IConfiguration configuration, CommonDBContext commonDBContext, MicrosoftIdentityConsentAndConditionalAccessHandler consentHandler) { _configuration = configuration; _commonDBContext = commonDBContext; - this._consentHandler = consentHandler; - - _msalAccountId = HttpContext.User.GetMsalAccountId(); + _consentHandler = consentHandler; EnsureDatabaseIsAwakeAndAvailable(); } @@ -87,7 +83,7 @@ public ActionResult Index() EnsureDatabaseIsAwakeAndAvailable(); - return View(_commonDBContext.Todo.Where(l => l.AccountId.Equals(_msalAccountId)).ToList()); + return View(_commonDBContext.Todo.Where(l => l.AccountId.Equals(HttpContext.User.GetMsalAccountId())).ToList()); } // GET: TodoList/Details/5 @@ -119,7 +115,7 @@ public ActionResult Create() public ActionResult Create([Bind("Title,Owner")] Todo todo) { //add owner accountid to new todo - todo.AccountId = _msalAccountId; + todo.AccountId = HttpContext.User.GetMsalAccountId(); todo.Owner = GetCurrentUsersName(); if (ChallengeUser(HttpMethods.Post)) @@ -162,7 +158,7 @@ public ActionResult Edit(int id, [Bind("Id,Title,Owner")] Todo todo) return NotFound(); } - todo.AccountId = _msalAccountId; + todo.AccountId = HttpContext.User.GetMsalAccountId(); if (ChallengeUser(HttpMethods.Post)) {
ApplicationAppIdUrl in the Azure portal