From 2b0dedcd1f64bc7fd66dc4f9abec91faf2e98cd0 Mon Sep 17 00:00:00 2001 From: Chris Werner <59959532+cilwerner@users.noreply.github.com> Date: Tue, 24 Jun 2025 17:01:08 +0100 Subject: [PATCH 01/11] major reorganisation --- .../web-api-azure-function}/.gitignore | 0 .../web-api-azure-function}/Api.csproj | 0 .../web-api-azure-function}/README.md | 0 .../web-api-azure-function}/greeting.cs | 0 .../web-api-azure-function}/host.json | 0 .../web-api-obo-client}/Api.csproj | 0 .../web-api-obo-client}/Program.cs | 0 .../web-api-obo-client}/README.md | 0 .../web-api-obo-client}/appsettings.json | 0 .../web-api-obo-user}/Api.csproj | 0 .../web-api-obo-user}/Program.cs | 0 .../web-api-obo-user}/README.md | 0 .../web-api-obo-user}/appsettings.json | 0 {web-api => 1-server-side/web-api}/Api.csproj | 0 {web-api => 1-server-side/web-api}/Program.cs | 0 .../web-api}/Properties/launchSettings.json | 0 {web-api => 1-server-side/web-api}/README.md | 0 .../web-api}/appsettings.json | 0 .../web-app-aspnet}/Pages/Error.cshtml | 0 .../web-app-aspnet}/Pages/Error.cshtml.cs | 0 .../web-app-aspnet}/Pages/Index.cshtml | 0 .../web-app-aspnet}/Pages/Index.cshtml.cs | 0 .../web-app-aspnet}/Pages/Privacy.cshtml | 0 .../web-app-aspnet}/Pages/Privacy.cshtml.cs | 0 .../Pages/Shared/_Layout.cshtml | 0 .../Pages/Shared/_Layout.cshtml.css | 0 .../Pages/Shared/_LoginPartial.cshtml | 0 .../Shared/_ValidationScriptsPartial.cshtml | 0 .../web-app-aspnet}/Pages/_ViewImports.cshtml | 0 .../web-app-aspnet}/Pages/_ViewStart.cshtml | 0 .../web-app-aspnet}/Program.cs | 0 .../Properties/launchSettings.json | 0 .../web-app-aspnet}/README.md | 0 .../web-app-aspnet}/WebApp.csproj | 0 .../web-app-aspnet}/appsettings.json | 0 .../web-app-aspnet}/media/app-signedin.png | Bin .../web-app-aspnet}/media/app-signedout.png | Bin .../web-app-aspnet}/wwwroot/css/site.css | 0 .../web-app-aspnet/wwwroot}/favicon.ico | Bin .../web-app-aspnet}/wwwroot/js/site.js | 0 .../wwwroot/lib/bootstrap/LICENSE | 0 .../lib/bootstrap/dist/css/bootstrap-grid.css | 0 .../bootstrap/dist/css/bootstrap-grid.css.map | 0 .../bootstrap/dist/css/bootstrap-grid.min.css | 0 .../dist/css/bootstrap-grid.min.css.map | 0 .../bootstrap/dist/css/bootstrap-grid.rtl.css | 0 .../dist/css/bootstrap-grid.rtl.css.map | 0 .../dist/css/bootstrap-grid.rtl.min.css | 0 .../dist/css/bootstrap-grid.rtl.min.css.map | 0 .../bootstrap/dist/css/bootstrap-reboot.css | 0 .../dist/css/bootstrap-reboot.css.map | 0 .../dist/css/bootstrap-reboot.min.css | 0 .../dist/css/bootstrap-reboot.min.css.map | 0 .../dist/css/bootstrap-reboot.rtl.css | 0 .../dist/css/bootstrap-reboot.rtl.css.map | 0 .../dist/css/bootstrap-reboot.rtl.min.css | 0 .../dist/css/bootstrap-reboot.rtl.min.css.map | 0 .../dist/css/bootstrap-utilities.css | 0 .../dist/css/bootstrap-utilities.css.map | 0 .../dist/css/bootstrap-utilities.min.css | 0 .../dist/css/bootstrap-utilities.min.css.map | 0 .../dist/css/bootstrap-utilities.rtl.css | 0 .../dist/css/bootstrap-utilities.rtl.css.map | 0 .../dist/css/bootstrap-utilities.rtl.min.css | 0 .../css/bootstrap-utilities.rtl.min.css.map | 0 .../lib/bootstrap/dist/css/bootstrap.css | 0 .../lib/bootstrap/dist/css/bootstrap.css.map | 0 .../lib/bootstrap/dist/css}/bootstrap.min.css | 0 .../bootstrap/dist/css}/bootstrap.min.css.map | 0 .../lib/bootstrap/dist/css/bootstrap.rtl.css | 0 .../bootstrap/dist/css/bootstrap.rtl.css.map | 0 .../bootstrap/dist/css/bootstrap.rtl.min.css | 0 .../dist/css/bootstrap.rtl.min.css.map | 0 .../lib/bootstrap/dist/js/bootstrap.bundle.js | 0 .../bootstrap/dist/js/bootstrap.bundle.js.map | 0 .../bootstrap/dist/js/bootstrap.bundle.min.js | 0 .../dist/js/bootstrap.bundle.min.js.map | 0 .../lib/bootstrap/dist/js/bootstrap.esm.js | 0 .../bootstrap/dist/js/bootstrap.esm.js.map | 0 .../bootstrap/dist/js/bootstrap.esm.min.js | 0 .../dist/js/bootstrap.esm.min.js.map | 0 .../lib/bootstrap/dist/js/bootstrap.js | 0 .../lib/bootstrap/dist/js/bootstrap.js.map | 0 .../lib/bootstrap/dist/js/bootstrap.min.js | 0 .../bootstrap/dist/js/bootstrap.min.js.map | 0 .../jquery-validation-unobtrusive/LICENSE.txt | 0 .../jquery.validate.unobtrusive.js | 0 .../jquery.validate.unobtrusive.min.js | 0 .../wwwroot/lib/jquery-validation/LICENSE.md | 0 .../dist/additional-methods.js | 0 .../dist/additional-methods.min.js | 0 .../jquery-validation/dist/jquery.validate.js | 0 .../dist/jquery.validate.min.js | 0 .../wwwroot/lib/jquery/LICENSE.txt | 0 .../wwwroot/lib/jquery/dist/jquery.js | 0 .../wwwroot/lib/jquery/dist/jquery.min.js | 0 .../wwwroot/lib/jquery/dist/jquery.min.map | 0 .../web-app-blazor-server}/App.razor | 0 .../BlazorServerWebApp.csproj | 0 .../web-app-blazor-server}/Pages/Index.razor | 0 .../web-app-blazor-server}/Pages/_Host.cshtml | 0 .../Pages/_Layout.cshtml | 0 .../web-app-blazor-server}/Program.cs | 0 .../Properties/launchSettings.json | 0 .../web-app-blazor-server}/README.md | 0 .../Shared/LoginDisplay.razor | 0 .../Shared/MainLayout.razor | 0 .../Shared/MainLayout.razor.css | 0 .../Shared/NavMenu.razor | 0 .../Shared/NavMenu.razor.css | 0 .../web-app-blazor-server}/_Imports.razor | 0 .../web-app-blazor-server}/app-signed-in.png | Bin .../web-app-blazor-server}/app-signed-out.png | Bin .../web-app-blazor-server}/appsettings.json | 0 .../wwwroot/css/bootstrap}/bootstrap.min.css | 0 .../css/bootstrap}/bootstrap.min.css.map | 0 .../wwwroot/css/open-iconic/FONT-LICENSE | 0 .../wwwroot/css/open-iconic/ICON-LICENSE | 0 .../wwwroot/css/open-iconic/README.md | 0 .../font/css/open-iconic-bootstrap.min.css | 0 .../open-iconic/font/fonts/open-iconic.eot | Bin .../open-iconic/font/fonts/open-iconic.otf | Bin .../open-iconic/font/fonts/open-iconic.svg | 0 .../open-iconic/font/fonts/open-iconic.ttf | Bin .../open-iconic/font/fonts/open-iconic.woff | Bin .../wwwroot/css/site.css | 0 .../wwwroot/favicon.ico | Bin .../spa-blazor-wasm}/App.razor | 0 .../spa-blazor-wasm}/BlazorWasm.csproj | 0 .../Pages/Authentication.razor | 0 .../spa-blazor-wasm}/Pages/Index.razor | 0 .../spa-blazor-wasm}/Program.cs | 0 .../spa-blazor-wasm}/README.md | 0 .../Shared/LoginDisplay.razor | 0 .../spa-blazor-wasm}/Shared/MainLayout.razor | 0 .../Shared/MainLayout.razor.css | 0 .../spa-blazor-wasm}/Shared/NavMenu.razor | 0 .../spa-blazor-wasm}/Shared/NavMenu.razor.css | 0 .../Shared/RedirectToLogin.razor | 0 .../spa-blazor-wasm}/_Imports.razor | 0 .../spa-blazor-wasm}/media/app-signedin.png | Bin .../spa-blazor-wasm}/media/app-signedout.png | Bin .../spa-blazor-wasm/media}/favicon.ico | Bin .../spa-blazor-wasm}/wwwroot/appsettings.json | 0 .../spa-blazor-wasm}/wwwroot/css/app.css | 0 .../wwwroot/css/bootstrap/bootstrap.min.css | 0 .../css/bootstrap/bootstrap.min.css.map | 0 .../wwwroot/css/open-iconic/FONT-LICENSE | 0 .../wwwroot/css/open-iconic/ICON-LICENSE | 0 .../wwwroot/css/open-iconic/README.md | 0 .../font/css/open-iconic-bootstrap.min.css | 0 .../open-iconic/font/fonts/open-iconic.eot | Bin .../open-iconic/font/fonts/open-iconic.otf | Bin .../open-iconic/font/fonts/open-iconic.svg | 0 .../open-iconic/font/fonts/open-iconic.ttf | Bin .../open-iconic/font/fonts/open-iconic.woff | Bin .../spa-blazor-wasm}/wwwroot/icon-192.png | Bin .../spa-blazor-wasm}/wwwroot/icon-512.png | Bin .../spa-blazor-wasm}/wwwroot/index.html | 0 .../spa-blazor-wasm}/wwwroot/manifest.json | 0 .../wwwroot/service-worker.js | 0 .../wwwroot/service-worker.published.js | 0 .../console-cli}/Program.cs | 0 .../console-cli}/README.md | 0 .../console-cli}/cli.csproj | 0 .../console-daemon}/Cli.csproj | 0 .../console-daemon}/Program.cs | 0 .../console-daemon}/README.md | 0 .../AppCreationScripts/AppCreationScripts.md | 166 + .../AppCreationScripts/Cleanup.ps1 | 80 + .../AppCreationScripts/Configure.ps1 | 225 + .../AppCreationScripts/sample.json | 53 + .../Console-DeviceCodeFlow-v2.sln | 25 + .../Console-DeviceCodeFlow-v2.csproj | 22 + .../Console-DeviceCodeFlow-v2/Program.cs | 123 + .../appsettings.json | 6 + 3-desktop/console-device-code-flow/Readme.md | 254 + .../ReadmeFiles/topology.png | Bin 0 -> 30935 bytes .../AppCreationScripts/AppCreationScripts.md | 166 + .../AppCreationScripts/Cleanup.ps1 | 77 + .../AppCreationScripts/Configure.ps1 | 224 + .../AppCreationScripts/sample.json | 52 + .../Console-Interactive-CustomWebUI.csproj | 25 + .../Program.cs | 161 + .../appsettings.json | 7 + .../Console-Interactive.sln | 25 + 3-desktop/console-html-browser/README.md | 255 + .../ReadmeFiles/failureMessage.png | Bin 0 -> 50277 bytes .../ReadmeFiles/successMessage.png | Bin 0 -> 20107 bytes .../ReadmeFiles/topology.png | Bin 0 -> 21730 bytes .../AppCreationScripts/AppCreationScripts.md | 166 + .../AppCreationScripts/Cleanup.ps1 | 77 + .../AppCreationScripts/Configure.ps1 | 224 + .../AppCreationScripts/sample.json | 52 + .../Console-TokenCache.sln | 25 + .../Console-TokenCache/CacheSettings.cs | 26 + .../Console-TokenCache.csproj | 24 + .../Console-TokenCache/Program.cs | 209 + .../Console-TokenCache/appsettings.json | 7 + .../README-national-clouds.md | 96 + .../README.md | 220 + .../AppCreationScripts/AppCreationScripts.md | 166 + .../AppCreationScripts/Cleanup.ps1 | 77 + .../AppCreationScripts/Configure.ps1 | 224 + .../AppCreationScripts/sample.json | 52 + .../Console-Interactive-Core.sln | 25 + .../Console-Interactive-CustomWebUI.csproj | 25 + .../CustomWebBrowser/CustomBrowserWebUi.cs | 166 + .../SingleMessageTcpListener.cs | 152 + .../Program.cs | 122 + .../appsettings.json | 7 + 3-desktop/console-web-browser/README.md | 255 + .../ReadmeFiles/failureMessage.png | Bin 0 -> 50277 bytes .../ReadmeFiles/successMessage.png | Bin 0 -> 20107 bytes .../ReadmeFiles/topology.png | Bin 0 -> 21730 bytes .../desktop-winforms}/.gitignore | 0 .../desktop-winforms}/MainWindow.Designer.cs | 0 .../desktop-winforms}/MainWindow.cs | 0 .../desktop-winforms}/MainWindow.resx | 0 .../desktop-winforms}/MsalExample.csproj | 0 .../desktop-winforms}/Program.cs | 0 .../desktop-winforms}/README.md | 0 .../desktop-winforms}/app-launch.png | Bin .../desktop-winforms}/app.png | Bin .../desktop-winui}/App.xaml | 0 .../desktop-winui}/App.xaml.cs | 0 .../Assets/LockScreenLogo.scale-200.png | Bin .../Assets/SplashScreen.scale-200.png | Bin .../Assets/Square150x150Logo.scale-200.png | Bin .../Assets/Square44x44Logo.scale-200.png | Bin ...x44Logo.targetsize-24_altform-unplated.png | Bin .../desktop-winui}/Assets/StoreLogo.png | Bin .../Assets/Wide310x150Logo.scale-200.png | Bin .../desktop-winui}/MainWindow.xaml | 0 .../desktop-winui}/MainWindow.xaml.cs | 0 .../desktop-winui}/Package.appxmanifest | 0 .../Properties/launchSettings.json | 0 .../desktop-winui}/README.md | 0 .../desktop-winui}/WinUIApp.csproj | 0 .../desktop-winui}/app-launch.png | Bin .../desktop-winui}/app.manifest | 0 .../desktop-winui}/app.png | Bin .../desktop-wpf}/App.xaml | 0 .../desktop-wpf}/App.xaml.cs | 0 .../desktop-wpf}/AssemblyInfo.cs | 0 .../desktop-wpf}/MainWindow.xaml | 0 .../desktop-wpf}/MainWindow.xaml.cs | 0 .../desktop-wpf}/MsalExample.csproj | 0 .../desktop-wpf}/README.md | 0 .../desktop-wpf}/app-launch.png | Bin .../desktop-wpf}/app.png | Bin {xplat-maui => 3-desktop/xplat-maui}/App.xaml | 54 +- .../xplat-maui}/App.xaml.cs | 28 +- .../xplat-maui}/MainPage.xaml | 126 +- .../xplat-maui}/MainPage.xaml.cs | 192 +- .../xplat-maui}/MauiProgram.cs | 40 +- .../Platforms/Android/AndroidManifest.xml | 64 +- .../Platforms/Android/MainActivity.cs | 48 +- .../Platforms/Android/MainApplication.cs | 36 +- .../Android/Resources/values/colors.xml | 10 +- .../Platforms/MacCatalyst/AppDelegate.cs | 22 +- .../Platforms/MacCatalyst/Info.plist | 60 +- .../Platforms/MacCatalyst/Program.cs | 28 +- .../xplat-maui}/Platforms/Windows/App.xaml | 16 +- .../xplat-maui}/Platforms/Windows/App.xaml.cs | 68 +- .../Platforms/Windows/Package.appxmanifest | 116 +- .../Platforms/Windows/app.manifest | 30 +- .../xplat-maui}/Platforms/iOS/AppDelegate.cs | 22 +- .../xplat-maui}/Platforms/iOS/Info.plist | 64 +- .../xplat-maui}/Platforms/iOS/Program.cs | 28 +- .../Platforms/iOS/Resources/LaunchScreen.xib | 86 +- .../Properties/launchSettings.json | 14 +- .../xplat-maui}/README.md | 0 .../Resources/Fonts/OpenSans-Regular.ttf | Bin .../xplat-maui}/Resources/appicon.svg | 6 +- .../xplat-maui}/Resources/appiconfg.svg | 14 +- .../xplat-maui}/XPlat.csproj | 118 +- .../xplat-maui}/app-signedin.png | Bin .../xplat-maui}/app-signedout.png | Bin {xplat-maui => 3-desktop/xplat-maui}/app.png | Bin 4-migration/.gitignore | 337 + .../App_Start/BundleConfig.cs | 30 + .../App_Start/FilterConfig.cs | 13 + .../App_Start/RouteConfig.cs | 23 + .../App_Start/Startup.Auth.cs | 34 + .../Content/Site.css | 24 + .../Content/bootstrap-theme.css | 587 + .../Content/bootstrap-theme.css.map | 1 + .../Content/bootstrap-theme.min.css | 6 + .../Content/bootstrap-theme.min.css.map | 1 + .../Content/bootstrap.css | 6834 ++++++++ .../Content/bootstrap.css.map | 1 + .../Content/bootstrap.min.css | 6 + .../Content/bootstrap.min.css.map | 1 + .../Controllers/AccountController.cs | 43 + .../Controllers/HomeController.cs | 33 + .../1-1-Setup-SAML-Playground/Global.asax | 1 + .../1-1-Setup-SAML-Playground/Global.asax.cs | 21 + .../Properties/AssemblyInfo.cs | 35 + .../1-1-Setup-SAML-Playground/README.md | 92 + .../ReadmeFiles/extensionAttClaim.png | Bin 0 -> 4065 bytes .../ReadmeFiles/groupClaim.png | Bin 0 -> 8032 bytes .../Scripts/bootstrap.js | 2580 +++ .../Scripts/bootstrap.min.js | 6 + .../Scripts/jquery-3.4.1.intellisense.js | 2670 ++++ .../Scripts/jquery-3.4.1.js | 10598 +++++++++++++ .../Scripts/jquery-3.4.1.min.js | 2 + .../Scripts/jquery-3.4.1.min.map | 1 + .../Scripts/jquery-3.4.1.slim.js | 8495 ++++++++++ .../Scripts/jquery-3.4.1.slim.min.js | 2 + .../Scripts/jquery-3.4.1.slim.min.map | 1 + .../Scripts/jquery.validate-vsdoc.js | 1288 ++ .../Scripts/jquery.validate.js | 1601 ++ .../Scripts/jquery.validate.min.js | 4 + .../Scripts/jquery.validate.unobtrusive.js | 432 + .../jquery.validate.unobtrusive.min.js | 5 + .../Scripts/modernizr-2.8.3.js | 1406 ++ .../1-1-Setup-SAML-Playground/Startup.cs | 15 + .../Views/Account/SignOutCallback.cshtml | 5 + .../Views/Home/About.cshtml | 7 + .../Views/Home/Contact.cshtml | 17 + .../Views/Home/Index.cshtml | 28 + .../Views/Shared/Error.cshtml | 9 + .../Views/Shared/_Layout.cshtml | 44 + .../Views/Shared/_LoginPartial.cshtml | 26 + .../Views/Web.config | 43 + .../Views/_ViewStart.cshtml | 3 + .../Web.Debug.config | 30 + .../Web.Release.config | 31 + .../1-1-Setup-SAML-Playground/Web.config | 83 + .../WebApp_SAML.csproj | 265 + .../1-1-Setup-SAML-Playground/WebApp_SAML.sln | 25 + .../1-1-Setup-SAML-Playground/favicon.ico | Bin 0 -> 32038 bytes .../fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20127 bytes .../fonts/glyphicons-halflings-regular.svg | 288 + .../fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 45404 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23424 bytes .../fonts/glyphicons-halflings-regular.woff2 | Bin 0 -> 18028 bytes .../1-1-Setup-SAML-Playground/packages.config | 31 + .../1-2-Setup-AzureADConnect/README.md | 54 + .../1-3-Directory-Extensions/README.md | 64 + 4-migration/1-ADFS-Host/README.md | 16 + .../2-1-SAML-WebApp/App_Start/BundleConfig.cs | 30 + .../2-1-SAML-WebApp/App_Start/FilterConfig.cs | 13 + .../2-1-SAML-WebApp/App_Start/RouteConfig.cs | 23 + .../2-1-SAML-WebApp/App_Start/Startup.Auth.cs | 44 + .../2-1-SAML-WebApp/Content/Site.css | 24 + .../Content/bootstrap-theme.css | 587 + .../Content/bootstrap-theme.css.map | 1 + .../Content/bootstrap-theme.min.css | 6 + .../Content/bootstrap-theme.min.css.map | 1 + .../2-1-SAML-WebApp/Content/bootstrap.css | 6834 ++++++++ .../2-1-SAML-WebApp/Content/bootstrap.css.map | 1 + .../2-1-SAML-WebApp/Content/bootstrap.min.css | 6 + .../Content/bootstrap.min.css.map | 1 + .../Controllers/AccountController.cs | 43 + .../Controllers/HomeController.cs | 33 + .../2-1-SAML-WebApp/Global.asax | 1 + .../2-1-SAML-WebApp/Global.asax.cs | 21 + .../Properties/AssemblyInfo.cs | 35 + .../2-AAD-Migration/2-1-SAML-WebApp/README.md | 101 + .../2-1-SAML-WebApp/Scripts/bootstrap.js | 2580 +++ .../2-1-SAML-WebApp/Scripts/bootstrap.min.js | 6 + .../Scripts/jquery-3.4.1.intellisense.js | 2670 ++++ .../2-1-SAML-WebApp/Scripts/jquery-3.4.1.js | 10598 +++++++++++++ .../Scripts/jquery-3.4.1.min.js | 2 + .../Scripts/jquery-3.4.1.min.map | 1 + .../Scripts/jquery-3.4.1.slim.js | 8495 ++++++++++ .../Scripts/jquery-3.4.1.slim.min.js | 2 + .../Scripts/jquery-3.4.1.slim.min.map | 1 + .../Scripts/jquery.validate-vsdoc.js | 1288 ++ .../Scripts/jquery.validate.js | 1601 ++ .../Scripts/jquery.validate.min.js | 4 + .../Scripts/jquery.validate.unobtrusive.js | 432 + .../jquery.validate.unobtrusive.min.js | 5 + .../Scripts/modernizr-2.8.3.js | 1406 ++ .../2-1-SAML-WebApp/Startup.cs | 15 + .../Views/Account/SignOutCallback.cshtml | 5 + .../2-1-SAML-WebApp/Views/Home/About.cshtml | 7 + .../2-1-SAML-WebApp/Views/Home/Contact.cshtml | 17 + .../2-1-SAML-WebApp/Views/Home/Index.cshtml | 28 + .../2-1-SAML-WebApp/Views/Shared/Error.cshtml | 9 + .../Views/Shared/_Layout.cshtml | 44 + .../Views/Shared/_LoginPartial.cshtml | 26 + .../2-1-SAML-WebApp/Views/Web.config | 43 + .../2-1-SAML-WebApp/Views/_ViewStart.cshtml | 3 + .../2-1-SAML-WebApp/Web.Debug.config | 30 + .../2-1-SAML-WebApp/Web.Release.config | 31 + .../2-1-SAML-WebApp/Web.config | 97 + .../2-1-SAML-WebApp/WebApp_SAML.csproj | 281 + .../2-1-SAML-WebApp/WebApp_SAML.sln | 25 + .../2-1-SAML-WebApp/favicon.ico | Bin 0 -> 32038 bytes .../fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20127 bytes .../fonts/glyphicons-halflings-regular.svg | 288 + .../fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 45404 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23424 bytes .../fonts/glyphicons-halflings-regular.woff2 | Bin 0 -> 18028 bytes .../2-1-SAML-WebApp/packages.config | 34 + .../2-2-Security-Groups/README.md | 65 + .../ReadmeFiles/groupClaim.png | Bin 0 -> 8032 bytes .../App_Start/BundleConfig.cs | 30 + .../App_Start/FilterConfig.cs | 13 + .../App_Start/RouteConfig.cs | 23 + .../App_Start/Startup.Auth.cs | 55 + .../2-3-From-SAML-to-OIDC/Content/Site.css | 24 + .../Content/bootstrap-theme.css | 587 + .../Content/bootstrap-theme.css.map | 1 + .../Content/bootstrap-theme.min.css | 6 + .../Content/bootstrap-theme.min.css.map | 1 + .../Content/bootstrap.css | 6834 ++++++++ .../Content/bootstrap.css.map | 1 + .../Content/bootstrap.min.css | 6 + .../Content/bootstrap.min.css.map | 1 + .../Controllers/AccountController.cs | 44 + .../Controllers/HomeController.cs | 33 + .../2-3-From-SAML-to-OIDC/Global.asax | 1 + .../2-3-From-SAML-to-OIDC/Global.asax.cs | 21 + .../Properties/AssemblyInfo.cs | 35 + .../2-3-From-SAML-to-OIDC/README.md | 103 + .../Scripts/bootstrap.js | 2580 +++ .../Scripts/bootstrap.min.js | 6 + .../Scripts/jquery-3.4.1.intellisense.js | 2670 ++++ .../Scripts/jquery-3.4.1.js | 10598 +++++++++++++ .../Scripts/jquery-3.4.1.min.js | 2 + .../Scripts/jquery-3.4.1.min.map | 1 + .../Scripts/jquery-3.4.1.slim.js | 8495 ++++++++++ .../Scripts/jquery-3.4.1.slim.min.js | 2 + .../Scripts/jquery-3.4.1.slim.min.map | 1 + .../Scripts/jquery.validate-vsdoc.js | 1288 ++ .../Scripts/jquery.validate.js | 1601 ++ .../Scripts/jquery.validate.min.js | 4 + .../Scripts/jquery.validate.unobtrusive.js | 432 + .../jquery.validate.unobtrusive.min.js | 5 + .../Scripts/modernizr-2.8.3.js | 1406 ++ .../2-3-From-SAML-to-OIDC/Startup.cs | 15 + .../Views/Account/SignOutCallback.cshtml | 5 + .../Views/Home/About.cshtml | 7 + .../Views/Home/Contact.cshtml | 17 + .../Views/Home/Index.cshtml | 28 + .../Views/Shared/Error.cshtml | 9 + .../Views/Shared/_Layout.cshtml | 44 + .../Views/Shared/_LoginPartial.cshtml | 19 + .../2-3-From-SAML-to-OIDC/Views/Web.config | 43 + .../Views/_ViewStart.cshtml | 3 + .../2-3-From-SAML-to-OIDC/Web.Debug.config | 30 + .../2-3-From-SAML-to-OIDC/Web.Release.config | 31 + .../2-3-From-SAML-to-OIDC/Web.config | 75 + .../WebApp_SAML_to_OIDC.csproj | 270 + .../WebApp_SAML_to_OIDC.sln | 25 + .../2-3-From-SAML-to-OIDC/favicon.ico | Bin 0 -> 32038 bytes .../fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20127 bytes .../fonts/glyphicons-halflings-regular.svg | 288 + .../fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 45404 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23424 bytes .../fonts/glyphicons-halflings-regular.woff2 | Bin 0 -> 18028 bytes .../2-3-From-SAML-to-OIDC/packages.config | 30 + 4-migration/2-AAD-Migration/README.md | 16 + 4-migration/CODE_OF_CONDUCT.md | 9 + 4-migration/LICENSE | 21 + 4-migration/README.md | 87 + 4-migration/SECURITY.md | 41 + 5-advanced/CHANGELOG.md | 13 + 5-advanced/CONTRIBUTING.md | 76 + 5-advanced/LICENSE.md | 21 + 5-advanced/README.md | 93 + .../AppCreationScripts/AppCreationScripts.md | 148 + .../AppCreationScripts/Cleanup.ps1 | 116 + .../AppCreationScripts/Configure.ps1 | 455 + .../AppCreationScripts/apps.json | 178 + .../AppCreationScripts/sample.json | 128 + .../BackgroundWorker/AuthenticationConfig.cs | 71 + .../BackgroundWorker/BackgroundWorker.csproj | 33 + .../BackgroundWorkerTokenCacheAdapter.cs | 70 + .../BackgroundWorker/ColorConsoleLogger.cs | 126 + .../BackgroundWorker/MsalAccount.cs | 23 + .../BackgroundWorker/Program.cs | 159 + .../BackgroundWorker/appsettings.json | 10 + .../IntegratedCache.sln | 37 + .../README.md | 395 + .../ReadmeFiles/diagram.png | Bin 0 -> 80904 bytes .../SPA/package-lock.json | 13166 ++++++++++++++++ .../SPA/package.json | 41 + .../SPA/public/favicon.svg | 23 + .../SPA/public/index.html | 42 + .../SPA/public/manifest.json | 8 + .../SPA/public/redirect.html | 0 .../SPA/public/robots.txt | 3 + .../SPA/src/App.jsx | 39 + .../SPA/src/authConfig.js | 73 + .../SPA/src/components/DataDisplay.jsx | 67 + .../SPA/src/components/NavigationBar.jsx | 102 + .../SPA/src/components/PageLayout.jsx | 28 + .../SPA/src/fetch.js | 32 + .../SPA/src/index.js | 41 + .../SPA/src/pages/Home.jsx | 56 + .../SPA/src/styles/App.css | 47 + .../SPA/src/styles/index.css | 13 + .../SPA/src/utils/claimUtils.js | 197 + .../WebAPI/Controllers/ProfileController.cs | 53 + .../WebAPI/Program.cs | 23 + .../WebAPI/Properties/launchSettings.json | 29 + .../MicrosoftGraphServiceExtensions.cs | 39 + .../WebAPI/Startup.cs | 146 + .../TokenAcquisitionCredentialProvider.cs | 34 + .../WebAPI/WebAPI.csproj | 30 + .../WebAPI/appsettings.Development.json | 9 + .../WebAPI/appsettings.json | 28 + .../WebAPI/wwwroot/index.html | 11 + .../AppCreationScripts/AppCreationScripts.md | 148 + .../AppCreationScripts/Cleanup.ps1 | 83 + .../AppCreationScripts/Configure.ps1 | 248 + .../AppCreationScripts/apps.json | 72 + .../AppCreationScripts/sample.json | 95 + .../BackgroundWorker/AuthenticationConfig.cs | 71 + .../BackgroundWorker/BackgroundWorker.csproj | 35 + .../BackgroundWorker/MsalAccount.cs | 25 + .../BackgroundWorker/Program.cs | 161 + .../BackgroundWorker/appsettings.json | 10 + .../IntegratedCache.sln | 37 + .../README.md | 266 + .../ReadmeFiles/diagram.png | Bin 0 -> 72287 bytes .../WebApp/Constants.cs | 8 + .../WebApp/Controllers/HomeController.cs | 55 + .../WebApp/Models/ErrorViewModel.cs | 11 + .../WebApp/Program.cs | 20 + .../WebApp/Properties/launchSettings.json | 27 + .../Services/GraphServiceClientFactory.cs | 37 + .../WebApp/Startup.cs | 156 + .../WebApp/Views/Home/Index.cshtml | 38 + .../WebApp/Views/Home/Privacy.cshtml | 6 + .../WebApp/Views/Shared/Error.cshtml | 25 + .../WebApp/Views/Shared/_Layout.cshtml | 46 + .../WebApp/Views/Shared/_LoginPartial.cshtml | 14 + .../Shared/_ValidationScriptsPartial.cshtml | 2 + .../WebApp/Views/_ViewImports.cshtml | 3 + .../WebApp/Views/_ViewStart.cshtml | 3 + .../WebApp/WebApp.csproj | 32 + .../WebApp/WebApp.sln | 25 + .../WebApp/appsettings.Development.json | 9 + .../WebApp/appsettings.json | 29 + .../WebApp/wwwroot/css/site.css | 71 + .../WebApp/wwwroot/favicon.ico | Bin 0 -> 32038 bytes .../WebApp/wwwroot/js/site.js | 4 + .../WebApp/wwwroot/lib/bootstrap/LICENSE | 22 + .../lib/bootstrap/dist/css/bootstrap-grid.css | 3719 +++++ .../bootstrap/dist/css/bootstrap-grid.css.map | 1 + .../bootstrap/dist/css/bootstrap-grid.min.css | 7 + .../dist/css/bootstrap-grid.min.css.map | 1 + .../bootstrap/dist/css/bootstrap-reboot.css | 331 + .../dist/css/bootstrap-reboot.css.map | 1 + .../dist/css/bootstrap-reboot.min.css | 8 + .../dist/css/bootstrap-reboot.min.css.map | 1 + .../lib/bootstrap/dist/css/bootstrap.css | 10038 ++++++++++++ .../lib/bootstrap/dist/css/bootstrap.css.map | 1 + .../lib/bootstrap/dist/css/bootstrap.min.css | 7 + .../bootstrap/dist/css/bootstrap.min.css.map | 1 + .../lib/bootstrap/dist/js/bootstrap.bundle.js | 7013 ++++++++ .../bootstrap/dist/js/bootstrap.bundle.js.map | 1 + .../bootstrap/dist/js/bootstrap.bundle.min.js | 7 + .../dist/js/bootstrap.bundle.min.js.map | 1 + .../lib/bootstrap/dist/js/bootstrap.js | 4435 ++++++ .../lib/bootstrap/dist/js/bootstrap.js.map | 1 + .../lib/bootstrap/dist/js/bootstrap.min.js | 7 + .../bootstrap/dist/js/bootstrap.min.js.map | 1 + .../jquery-validation-unobtrusive/LICENSE.txt | 12 + .../jquery.validate.unobtrusive.js | 432 + .../jquery.validate.unobtrusive.min.js | 5 + .../wwwroot/lib/jquery-validation/LICENSE.md | 22 + .../dist/additional-methods.js | 1158 ++ .../dist/additional-methods.min.js | 4 + .../jquery-validation/dist/jquery.validate.js | 1601 ++ .../dist/jquery.validate.min.js | 4 + .../WebApp/wwwroot/lib/jquery/LICENSE.txt | 36 + .../WebApp/wwwroot/lib/jquery/dist/jquery.js | 10364 ++++++++++++ .../wwwroot/lib/jquery/dist/jquery.min.js | 2 + .../wwwroot/lib/jquery/dist/jquery.min.map | 1 + README.md | 74 +- 577 files changed, 176974 insertions(+), 647 deletions(-) rename {web-api-azure-function => 1-server-side/web-api-azure-function}/.gitignore (100%) rename {web-api-azure-function => 1-server-side/web-api-azure-function}/Api.csproj (100%) rename {web-api-azure-function => 1-server-side/web-api-azure-function}/README.md (100%) rename {web-api-azure-function => 1-server-side/web-api-azure-function}/greeting.cs (100%) rename {web-api-azure-function => 1-server-side/web-api-azure-function}/host.json (100%) rename {web-api-obo-client => 1-server-side/web-api-obo-client}/Api.csproj (100%) rename {web-api-obo-client => 1-server-side/web-api-obo-client}/Program.cs (100%) rename {web-api-obo-client => 1-server-side/web-api-obo-client}/README.md (100%) rename {web-api-obo-client => 1-server-side/web-api-obo-client}/appsettings.json (100%) rename {web-api-obo-user => 1-server-side/web-api-obo-user}/Api.csproj (100%) rename {web-api-obo-user => 1-server-side/web-api-obo-user}/Program.cs (100%) rename {web-api-obo-user => 1-server-side/web-api-obo-user}/README.md (100%) rename {web-api-obo-user => 1-server-side/web-api-obo-user}/appsettings.json (100%) rename {web-api => 1-server-side/web-api}/Api.csproj (100%) rename {web-api => 1-server-side/web-api}/Program.cs (100%) rename {web-api => 1-server-side/web-api}/Properties/launchSettings.json (100%) rename {web-api => 1-server-side/web-api}/README.md (100%) rename {web-api => 1-server-side/web-api}/appsettings.json (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/Pages/Error.cshtml (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/Pages/Error.cshtml.cs (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/Pages/Index.cshtml (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/Pages/Index.cshtml.cs (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/Pages/Privacy.cshtml (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/Pages/Privacy.cshtml.cs (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/Pages/Shared/_Layout.cshtml (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/Pages/Shared/_Layout.cshtml.css (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/Pages/Shared/_LoginPartial.cshtml (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/Pages/Shared/_ValidationScriptsPartial.cshtml (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/Pages/_ViewImports.cshtml (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/Pages/_ViewStart.cshtml (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/Program.cs (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/Properties/launchSettings.json (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/README.md (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/WebApp.csproj (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/appsettings.json (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/media/app-signedin.png (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/media/app-signedout.png (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/css/site.css (100%) rename {spa-blazor-wasm/media => 1-server-side/web-app-aspnet/wwwroot}/favicon.ico (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/js/site.js (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/LICENSE (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css.map (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css.map (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css.map (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css.map (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css.map (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css.map (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css.map (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css.map (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.css (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.css.map (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.min.css (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.min.css.map (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.css (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.css.map (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.min.css (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.min.css.map (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap.css (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap.css.map (100%) rename {spa-blazor-wasm/wwwroot/css/bootstrap => 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css}/bootstrap.min.css (100%) rename {spa-blazor-wasm/wwwroot/css/bootstrap => 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css}/bootstrap.min.css.map (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.css (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.css.map (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.min.css (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.min.css.map (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js.map (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js.map (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.js (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.js.map (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js.map (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/js/bootstrap.js (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/js/bootstrap.js.map (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js.map (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/jquery-validation/LICENSE.md (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/jquery-validation/dist/additional-methods.js (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/jquery-validation/dist/additional-methods.min.js (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/jquery-validation/dist/jquery.validate.js (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/jquery-validation/dist/jquery.validate.min.js (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/jquery/LICENSE.txt (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/jquery/dist/jquery.js (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/jquery/dist/jquery.min.js (100%) rename {web-app-aspnet => 1-server-side/web-app-aspnet}/wwwroot/lib/jquery/dist/jquery.min.map (100%) rename {web-app-blazor-server => 1-server-side/web-app-blazor-server}/App.razor (100%) rename {web-app-blazor-server => 1-server-side/web-app-blazor-server}/BlazorServerWebApp.csproj (100%) rename {web-app-blazor-server => 1-server-side/web-app-blazor-server}/Pages/Index.razor (100%) rename {web-app-blazor-server => 1-server-side/web-app-blazor-server}/Pages/_Host.cshtml (100%) rename {web-app-blazor-server => 1-server-side/web-app-blazor-server}/Pages/_Layout.cshtml (100%) rename {web-app-blazor-server => 1-server-side/web-app-blazor-server}/Program.cs (100%) rename {web-app-blazor-server => 1-server-side/web-app-blazor-server}/Properties/launchSettings.json (100%) rename {web-app-blazor-server => 1-server-side/web-app-blazor-server}/README.md (100%) rename {web-app-blazor-server => 1-server-side/web-app-blazor-server}/Shared/LoginDisplay.razor (100%) rename {web-app-blazor-server => 1-server-side/web-app-blazor-server}/Shared/MainLayout.razor (100%) rename {web-app-blazor-server => 1-server-side/web-app-blazor-server}/Shared/MainLayout.razor.css (100%) rename {web-app-blazor-server => 1-server-side/web-app-blazor-server}/Shared/NavMenu.razor (100%) rename {spa-blazor-wasm => 1-server-side/web-app-blazor-server}/Shared/NavMenu.razor.css (100%) rename {web-app-blazor-server => 1-server-side/web-app-blazor-server}/_Imports.razor (100%) rename {web-app-blazor-server => 1-server-side/web-app-blazor-server}/app-signed-in.png (100%) rename {web-app-blazor-server => 1-server-side/web-app-blazor-server}/app-signed-out.png (100%) rename {web-app-blazor-server => 1-server-side/web-app-blazor-server}/appsettings.json (100%) rename {web-app-aspnet/wwwroot/lib/bootstrap/dist/css => 1-server-side/web-app-blazor-server/wwwroot/css/bootstrap}/bootstrap.min.css (100%) rename {web-app-aspnet/wwwroot/lib/bootstrap/dist/css => 1-server-side/web-app-blazor-server/wwwroot/css/bootstrap}/bootstrap.min.css.map (100%) rename {spa-blazor-wasm => 1-server-side/web-app-blazor-server}/wwwroot/css/open-iconic/FONT-LICENSE (100%) rename {spa-blazor-wasm => 1-server-side/web-app-blazor-server}/wwwroot/css/open-iconic/ICON-LICENSE (100%) rename {spa-blazor-wasm => 1-server-side/web-app-blazor-server}/wwwroot/css/open-iconic/README.md (100%) rename {spa-blazor-wasm => 1-server-side/web-app-blazor-server}/wwwroot/css/open-iconic/font/css/open-iconic-bootstrap.min.css (100%) rename {spa-blazor-wasm => 1-server-side/web-app-blazor-server}/wwwroot/css/open-iconic/font/fonts/open-iconic.eot (100%) rename {spa-blazor-wasm => 1-server-side/web-app-blazor-server}/wwwroot/css/open-iconic/font/fonts/open-iconic.otf (100%) rename {spa-blazor-wasm => 1-server-side/web-app-blazor-server}/wwwroot/css/open-iconic/font/fonts/open-iconic.svg (100%) rename {spa-blazor-wasm => 1-server-side/web-app-blazor-server}/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf (100%) rename {spa-blazor-wasm => 1-server-side/web-app-blazor-server}/wwwroot/css/open-iconic/font/fonts/open-iconic.woff (100%) rename {web-app-blazor-server => 1-server-side/web-app-blazor-server}/wwwroot/css/site.css (100%) rename {web-app-aspnet => 1-server-side/web-app-blazor-server}/wwwroot/favicon.ico (100%) rename {spa-blazor-wasm => 2-client-side/spa-blazor-wasm}/App.razor (100%) rename {spa-blazor-wasm => 2-client-side/spa-blazor-wasm}/BlazorWasm.csproj (100%) rename {spa-blazor-wasm => 2-client-side/spa-blazor-wasm}/Pages/Authentication.razor (100%) rename {spa-blazor-wasm => 2-client-side/spa-blazor-wasm}/Pages/Index.razor (100%) rename {spa-blazor-wasm => 2-client-side/spa-blazor-wasm}/Program.cs (100%) rename {spa-blazor-wasm => 2-client-side/spa-blazor-wasm}/README.md (100%) rename {spa-blazor-wasm => 2-client-side/spa-blazor-wasm}/Shared/LoginDisplay.razor (100%) rename {spa-blazor-wasm => 2-client-side/spa-blazor-wasm}/Shared/MainLayout.razor (100%) rename {spa-blazor-wasm => 2-client-side/spa-blazor-wasm}/Shared/MainLayout.razor.css (100%) rename {spa-blazor-wasm => 2-client-side/spa-blazor-wasm}/Shared/NavMenu.razor (100%) rename {web-app-blazor-server => 2-client-side/spa-blazor-wasm}/Shared/NavMenu.razor.css (100%) rename {spa-blazor-wasm => 2-client-side/spa-blazor-wasm}/Shared/RedirectToLogin.razor (100%) rename {spa-blazor-wasm => 2-client-side/spa-blazor-wasm}/_Imports.razor (100%) rename {spa-blazor-wasm => 2-client-side/spa-blazor-wasm}/media/app-signedin.png (100%) rename {spa-blazor-wasm => 2-client-side/spa-blazor-wasm}/media/app-signedout.png (100%) rename {web-app-blazor-server/wwwroot => 2-client-side/spa-blazor-wasm/media}/favicon.ico (100%) rename {spa-blazor-wasm => 2-client-side/spa-blazor-wasm}/wwwroot/appsettings.json (100%) rename {spa-blazor-wasm => 2-client-side/spa-blazor-wasm}/wwwroot/css/app.css (100%) rename {web-app-blazor-server => 2-client-side/spa-blazor-wasm}/wwwroot/css/bootstrap/bootstrap.min.css (100%) rename {web-app-blazor-server => 2-client-side/spa-blazor-wasm}/wwwroot/css/bootstrap/bootstrap.min.css.map (100%) rename {web-app-blazor-server => 2-client-side/spa-blazor-wasm}/wwwroot/css/open-iconic/FONT-LICENSE (100%) rename {web-app-blazor-server => 2-client-side/spa-blazor-wasm}/wwwroot/css/open-iconic/ICON-LICENSE (100%) rename {web-app-blazor-server => 2-client-side/spa-blazor-wasm}/wwwroot/css/open-iconic/README.md (100%) rename {web-app-blazor-server => 2-client-side/spa-blazor-wasm}/wwwroot/css/open-iconic/font/css/open-iconic-bootstrap.min.css (100%) rename {web-app-blazor-server => 2-client-side/spa-blazor-wasm}/wwwroot/css/open-iconic/font/fonts/open-iconic.eot (100%) rename {web-app-blazor-server => 2-client-side/spa-blazor-wasm}/wwwroot/css/open-iconic/font/fonts/open-iconic.otf (100%) rename {web-app-blazor-server => 2-client-side/spa-blazor-wasm}/wwwroot/css/open-iconic/font/fonts/open-iconic.svg (100%) rename {web-app-blazor-server => 2-client-side/spa-blazor-wasm}/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf (100%) rename {web-app-blazor-server => 2-client-side/spa-blazor-wasm}/wwwroot/css/open-iconic/font/fonts/open-iconic.woff (100%) rename {spa-blazor-wasm => 2-client-side/spa-blazor-wasm}/wwwroot/icon-192.png (100%) rename {spa-blazor-wasm => 2-client-side/spa-blazor-wasm}/wwwroot/icon-512.png (100%) rename {spa-blazor-wasm => 2-client-side/spa-blazor-wasm}/wwwroot/index.html (100%) rename {spa-blazor-wasm => 2-client-side/spa-blazor-wasm}/wwwroot/manifest.json (100%) rename {spa-blazor-wasm => 2-client-side/spa-blazor-wasm}/wwwroot/service-worker.js (100%) rename {spa-blazor-wasm => 2-client-side/spa-blazor-wasm}/wwwroot/service-worker.published.js (100%) rename {console-cli => 3-desktop/console-cli}/Program.cs (100%) rename {console-cli => 3-desktop/console-cli}/README.md (100%) rename {console-cli => 3-desktop/console-cli}/cli.csproj (100%) rename {console-daemon => 3-desktop/console-daemon}/Cli.csproj (100%) rename {console-daemon => 3-desktop/console-daemon}/Program.cs (100%) rename {console-daemon => 3-desktop/console-daemon}/README.md (100%) create mode 100644 3-desktop/console-device-code-flow/AppCreationScripts/AppCreationScripts.md create mode 100644 3-desktop/console-device-code-flow/AppCreationScripts/Cleanup.ps1 create mode 100644 3-desktop/console-device-code-flow/AppCreationScripts/Configure.ps1 create mode 100644 3-desktop/console-device-code-flow/AppCreationScripts/sample.json create mode 100644 3-desktop/console-device-code-flow/Console-DeviceCodeFlow-v2.sln create mode 100644 3-desktop/console-device-code-flow/Console-DeviceCodeFlow-v2/Console-DeviceCodeFlow-v2.csproj create mode 100644 3-desktop/console-device-code-flow/Console-DeviceCodeFlow-v2/Program.cs create mode 100644 3-desktop/console-device-code-flow/Console-DeviceCodeFlow-v2/appsettings.json create mode 100644 3-desktop/console-device-code-flow/Readme.md create mode 100644 3-desktop/console-device-code-flow/ReadmeFiles/topology.png create mode 100644 3-desktop/console-html-browser/AppCreationScripts/AppCreationScripts.md create mode 100644 3-desktop/console-html-browser/AppCreationScripts/Cleanup.ps1 create mode 100644 3-desktop/console-html-browser/AppCreationScripts/Configure.ps1 create mode 100644 3-desktop/console-html-browser/AppCreationScripts/sample.json create mode 100644 3-desktop/console-html-browser/Console-Interactive-CustomWebUI/Console-Interactive-CustomWebUI.csproj create mode 100644 3-desktop/console-html-browser/Console-Interactive-CustomWebUI/Program.cs create mode 100644 3-desktop/console-html-browser/Console-Interactive-CustomWebUI/appsettings.json create mode 100644 3-desktop/console-html-browser/Console-Interactive.sln create mode 100644 3-desktop/console-html-browser/README.md create mode 100644 3-desktop/console-html-browser/ReadmeFiles/failureMessage.png create mode 100644 3-desktop/console-html-browser/ReadmeFiles/successMessage.png create mode 100644 3-desktop/console-html-browser/ReadmeFiles/topology.png create mode 100644 3-desktop/console-interactive-multitarget-graph/AppCreationScripts/AppCreationScripts.md create mode 100644 3-desktop/console-interactive-multitarget-graph/AppCreationScripts/Cleanup.ps1 create mode 100644 3-desktop/console-interactive-multitarget-graph/AppCreationScripts/Configure.ps1 create mode 100644 3-desktop/console-interactive-multitarget-graph/AppCreationScripts/sample.json create mode 100644 3-desktop/console-interactive-multitarget-graph/Console-TokenCache.sln create mode 100644 3-desktop/console-interactive-multitarget-graph/Console-TokenCache/CacheSettings.cs create mode 100644 3-desktop/console-interactive-multitarget-graph/Console-TokenCache/Console-TokenCache.csproj create mode 100644 3-desktop/console-interactive-multitarget-graph/Console-TokenCache/Program.cs create mode 100644 3-desktop/console-interactive-multitarget-graph/Console-TokenCache/appsettings.json create mode 100644 3-desktop/console-interactive-multitarget-graph/README-national-clouds.md create mode 100644 3-desktop/console-interactive-multitarget-graph/README.md create mode 100644 3-desktop/console-web-browser/AppCreationScripts/AppCreationScripts.md create mode 100644 3-desktop/console-web-browser/AppCreationScripts/Cleanup.ps1 create mode 100644 3-desktop/console-web-browser/AppCreationScripts/Configure.ps1 create mode 100644 3-desktop/console-web-browser/AppCreationScripts/sample.json create mode 100644 3-desktop/console-web-browser/Console-Interactive-Core.sln create mode 100644 3-desktop/console-web-browser/Console-Interactive-CustomWebUI/Console-Interactive-CustomWebUI.csproj create mode 100644 3-desktop/console-web-browser/Console-Interactive-CustomWebUI/CustomWebBrowser/CustomBrowserWebUi.cs create mode 100644 3-desktop/console-web-browser/Console-Interactive-CustomWebUI/CustomWebBrowser/SingleMessageTcpListener.cs create mode 100644 3-desktop/console-web-browser/Console-Interactive-CustomWebUI/Program.cs create mode 100644 3-desktop/console-web-browser/Console-Interactive-CustomWebUI/appsettings.json create mode 100644 3-desktop/console-web-browser/README.md create mode 100644 3-desktop/console-web-browser/ReadmeFiles/failureMessage.png create mode 100644 3-desktop/console-web-browser/ReadmeFiles/successMessage.png create mode 100644 3-desktop/console-web-browser/ReadmeFiles/topology.png rename {desktop-winforms => 3-desktop/desktop-winforms}/.gitignore (100%) rename {desktop-winforms => 3-desktop/desktop-winforms}/MainWindow.Designer.cs (100%) rename {desktop-winforms => 3-desktop/desktop-winforms}/MainWindow.cs (100%) rename {desktop-winforms => 3-desktop/desktop-winforms}/MainWindow.resx (100%) rename {desktop-winforms => 3-desktop/desktop-winforms}/MsalExample.csproj (100%) rename {desktop-winforms => 3-desktop/desktop-winforms}/Program.cs (100%) rename {desktop-winforms => 3-desktop/desktop-winforms}/README.md (100%) rename {desktop-winforms => 3-desktop/desktop-winforms}/app-launch.png (100%) rename {desktop-winforms => 3-desktop/desktop-winforms}/app.png (100%) rename {desktop-winui => 3-desktop/desktop-winui}/App.xaml (100%) rename {desktop-winui => 3-desktop/desktop-winui}/App.xaml.cs (100%) rename {desktop-winui => 3-desktop/desktop-winui}/Assets/LockScreenLogo.scale-200.png (100%) rename {desktop-winui => 3-desktop/desktop-winui}/Assets/SplashScreen.scale-200.png (100%) rename {desktop-winui => 3-desktop/desktop-winui}/Assets/Square150x150Logo.scale-200.png (100%) rename {desktop-winui => 3-desktop/desktop-winui}/Assets/Square44x44Logo.scale-200.png (100%) rename {desktop-winui => 3-desktop/desktop-winui}/Assets/Square44x44Logo.targetsize-24_altform-unplated.png (100%) rename {desktop-winui => 3-desktop/desktop-winui}/Assets/StoreLogo.png (100%) rename {desktop-winui => 3-desktop/desktop-winui}/Assets/Wide310x150Logo.scale-200.png (100%) rename {desktop-winui => 3-desktop/desktop-winui}/MainWindow.xaml (100%) rename {desktop-winui => 3-desktop/desktop-winui}/MainWindow.xaml.cs (100%) rename {desktop-winui => 3-desktop/desktop-winui}/Package.appxmanifest (100%) rename {desktop-winui => 3-desktop/desktop-winui}/Properties/launchSettings.json (100%) rename {desktop-winui => 3-desktop/desktop-winui}/README.md (100%) rename {desktop-winui => 3-desktop/desktop-winui}/WinUIApp.csproj (100%) rename {desktop-winui => 3-desktop/desktop-winui}/app-launch.png (100%) rename {desktop-winui => 3-desktop/desktop-winui}/app.manifest (100%) rename {desktop-winui => 3-desktop/desktop-winui}/app.png (100%) rename {desktop-wpf => 3-desktop/desktop-wpf}/App.xaml (100%) rename {desktop-wpf => 3-desktop/desktop-wpf}/App.xaml.cs (100%) rename {desktop-wpf => 3-desktop/desktop-wpf}/AssemblyInfo.cs (100%) rename {desktop-wpf => 3-desktop/desktop-wpf}/MainWindow.xaml (100%) rename {desktop-wpf => 3-desktop/desktop-wpf}/MainWindow.xaml.cs (100%) rename {desktop-wpf => 3-desktop/desktop-wpf}/MsalExample.csproj (100%) rename {desktop-wpf => 3-desktop/desktop-wpf}/README.md (100%) rename {desktop-wpf => 3-desktop/desktop-wpf}/app-launch.png (100%) rename {desktop-wpf => 3-desktop/desktop-wpf}/app.png (100%) rename {xplat-maui => 3-desktop/xplat-maui}/App.xaml (97%) rename {xplat-maui => 3-desktop/xplat-maui}/App.xaml.cs (93%) rename {xplat-maui => 3-desktop/xplat-maui}/MainPage.xaml (97%) rename {xplat-maui => 3-desktop/xplat-maui}/MainPage.xaml.cs (97%) rename {xplat-maui => 3-desktop/xplat-maui}/MauiProgram.cs (95%) rename {xplat-maui => 3-desktop/xplat-maui}/Platforms/Android/AndroidManifest.xml (98%) rename {xplat-maui => 3-desktop/xplat-maui}/Platforms/Android/MainActivity.cs (97%) rename {xplat-maui => 3-desktop/xplat-maui}/Platforms/Android/MainApplication.cs (95%) rename {xplat-maui => 3-desktop/xplat-maui}/Platforms/Android/Resources/values/colors.xml (97%) rename {xplat-maui => 3-desktop/xplat-maui}/Platforms/MacCatalyst/AppDelegate.cs (95%) rename {xplat-maui => 3-desktop/xplat-maui}/Platforms/MacCatalyst/Info.plist (96%) rename {xplat-maui => 3-desktop/xplat-maui}/Platforms/MacCatalyst/Program.cs (95%) rename {xplat-maui => 3-desktop/xplat-maui}/Platforms/Windows/App.xaml (97%) rename {xplat-maui => 3-desktop/xplat-maui}/Platforms/Windows/App.xaml.cs (96%) rename {xplat-maui => 3-desktop/xplat-maui}/Platforms/Windows/Package.appxmanifest (97%) rename {xplat-maui => 3-desktop/xplat-maui}/Platforms/Windows/app.manifest (97%) rename {xplat-maui => 3-desktop/xplat-maui}/Platforms/iOS/AppDelegate.cs (95%) rename {xplat-maui => 3-desktop/xplat-maui}/Platforms/iOS/Info.plist (96%) rename {xplat-maui => 3-desktop/xplat-maui}/Platforms/iOS/Program.cs (95%) rename {xplat-maui => 3-desktop/xplat-maui}/Platforms/iOS/Resources/LaunchScreen.xib (98%) rename {xplat-maui => 3-desktop/xplat-maui}/Properties/launchSettings.json (94%) rename {xplat-maui => 3-desktop/xplat-maui}/README.md (100%) rename {xplat-maui => 3-desktop/xplat-maui}/Resources/Fonts/OpenSans-Regular.ttf (100%) rename {xplat-maui => 3-desktop/xplat-maui}/Resources/appicon.svg (98%) rename {xplat-maui => 3-desktop/xplat-maui}/Resources/appiconfg.svg (99%) rename {xplat-maui => 3-desktop/xplat-maui}/XPlat.csproj (97%) rename {xplat-maui => 3-desktop/xplat-maui}/app-signedin.png (100%) rename {xplat-maui => 3-desktop/xplat-maui}/app-signedout.png (100%) rename {xplat-maui => 3-desktop/xplat-maui}/app.png (100%) create mode 100644 4-migration/.gitignore create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/App_Start/BundleConfig.cs create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/App_Start/FilterConfig.cs create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/App_Start/RouteConfig.cs create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/App_Start/Startup.Auth.cs create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Content/Site.css create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Content/bootstrap-theme.css create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Content/bootstrap-theme.css.map create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Content/bootstrap-theme.min.css create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Content/bootstrap-theme.min.css.map create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Content/bootstrap.css create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Content/bootstrap.css.map create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Content/bootstrap.min.css create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Content/bootstrap.min.css.map create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Controllers/AccountController.cs create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Controllers/HomeController.cs create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Global.asax create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Global.asax.cs create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Properties/AssemblyInfo.cs create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/README.md create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/ReadmeFiles/extensionAttClaim.png create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/ReadmeFiles/groupClaim.png create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Scripts/bootstrap.js create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Scripts/bootstrap.min.js create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Scripts/jquery-3.4.1.intellisense.js create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Scripts/jquery-3.4.1.js create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Scripts/jquery-3.4.1.min.js create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Scripts/jquery-3.4.1.min.map create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Scripts/jquery-3.4.1.slim.js create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Scripts/jquery-3.4.1.slim.min.js create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Scripts/jquery-3.4.1.slim.min.map create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Scripts/jquery.validate-vsdoc.js create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Scripts/jquery.validate.js create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Scripts/jquery.validate.min.js create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Scripts/jquery.validate.unobtrusive.js create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Scripts/jquery.validate.unobtrusive.min.js create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Scripts/modernizr-2.8.3.js create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Startup.cs create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Views/Account/SignOutCallback.cshtml create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Views/Home/About.cshtml create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Views/Home/Contact.cshtml create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Views/Home/Index.cshtml create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Views/Shared/Error.cshtml create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Views/Shared/_Layout.cshtml create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Views/Shared/_LoginPartial.cshtml create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Views/Web.config create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Views/_ViewStart.cshtml create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Web.Debug.config create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Web.Release.config create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/Web.config create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/WebApp_SAML.csproj create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/WebApp_SAML.sln create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/favicon.ico create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/fonts/glyphicons-halflings-regular.eot create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/fonts/glyphicons-halflings-regular.svg create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/fonts/glyphicons-halflings-regular.ttf create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/fonts/glyphicons-halflings-regular.woff create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/fonts/glyphicons-halflings-regular.woff2 create mode 100644 4-migration/1-ADFS-Host/1-1-Setup-SAML-Playground/packages.config create mode 100644 4-migration/1-ADFS-Host/1-2-Setup-AzureADConnect/README.md create mode 100644 4-migration/1-ADFS-Host/1-3-Directory-Extensions/README.md create mode 100644 4-migration/1-ADFS-Host/README.md create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/App_Start/BundleConfig.cs create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/App_Start/FilterConfig.cs create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/App_Start/RouteConfig.cs create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/App_Start/Startup.Auth.cs create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Content/Site.css create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Content/bootstrap-theme.css create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Content/bootstrap-theme.css.map create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Content/bootstrap-theme.min.css create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Content/bootstrap-theme.min.css.map create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Content/bootstrap.css create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Content/bootstrap.css.map create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Content/bootstrap.min.css create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Content/bootstrap.min.css.map create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Controllers/AccountController.cs create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Controllers/HomeController.cs create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Global.asax create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Global.asax.cs create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Properties/AssemblyInfo.cs create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/README.md create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Scripts/bootstrap.js create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Scripts/bootstrap.min.js create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Scripts/jquery-3.4.1.intellisense.js create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Scripts/jquery-3.4.1.js create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Scripts/jquery-3.4.1.min.js create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Scripts/jquery-3.4.1.min.map create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Scripts/jquery-3.4.1.slim.js create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Scripts/jquery-3.4.1.slim.min.js create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Scripts/jquery-3.4.1.slim.min.map create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Scripts/jquery.validate-vsdoc.js create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Scripts/jquery.validate.js create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Scripts/jquery.validate.min.js create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Scripts/jquery.validate.unobtrusive.js create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Scripts/jquery.validate.unobtrusive.min.js create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Scripts/modernizr-2.8.3.js create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Startup.cs create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Views/Account/SignOutCallback.cshtml create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Views/Home/About.cshtml create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Views/Home/Contact.cshtml create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Views/Home/Index.cshtml create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Views/Shared/Error.cshtml create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Views/Shared/_Layout.cshtml create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Views/Shared/_LoginPartial.cshtml create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Views/Web.config create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Views/_ViewStart.cshtml create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Web.Debug.config create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Web.Release.config create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/Web.config create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/WebApp_SAML.csproj create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/WebApp_SAML.sln create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/favicon.ico create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/fonts/glyphicons-halflings-regular.eot create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/fonts/glyphicons-halflings-regular.svg create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/fonts/glyphicons-halflings-regular.ttf create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/fonts/glyphicons-halflings-regular.woff create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/fonts/glyphicons-halflings-regular.woff2 create mode 100644 4-migration/2-AAD-Migration/2-1-SAML-WebApp/packages.config create mode 100644 4-migration/2-AAD-Migration/2-2-Security-Groups/README.md create mode 100644 4-migration/2-AAD-Migration/2-2-Security-Groups/ReadmeFiles/groupClaim.png create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/App_Start/BundleConfig.cs create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/App_Start/FilterConfig.cs create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/App_Start/RouteConfig.cs create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/App_Start/Startup.Auth.cs create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Content/Site.css create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Content/bootstrap-theme.css create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Content/bootstrap-theme.css.map create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Content/bootstrap-theme.min.css create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Content/bootstrap-theme.min.css.map create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Content/bootstrap.css create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Content/bootstrap.css.map create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Content/bootstrap.min.css create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Content/bootstrap.min.css.map create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Controllers/AccountController.cs create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Controllers/HomeController.cs create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Global.asax create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Global.asax.cs create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Properties/AssemblyInfo.cs create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/README.md create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Scripts/bootstrap.js create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Scripts/bootstrap.min.js create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Scripts/jquery-3.4.1.intellisense.js create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Scripts/jquery-3.4.1.js create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Scripts/jquery-3.4.1.min.js create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Scripts/jquery-3.4.1.min.map create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Scripts/jquery-3.4.1.slim.js create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Scripts/jquery-3.4.1.slim.min.js create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Scripts/jquery-3.4.1.slim.min.map create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Scripts/jquery.validate-vsdoc.js create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Scripts/jquery.validate.js create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Scripts/jquery.validate.min.js create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Scripts/jquery.validate.unobtrusive.js create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Scripts/jquery.validate.unobtrusive.min.js create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Scripts/modernizr-2.8.3.js create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Startup.cs create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Views/Account/SignOutCallback.cshtml create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Views/Home/About.cshtml create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Views/Home/Contact.cshtml create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Views/Home/Index.cshtml create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Views/Shared/Error.cshtml create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Views/Shared/_Layout.cshtml create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Views/Shared/_LoginPartial.cshtml create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Views/Web.config create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Views/_ViewStart.cshtml create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Web.Debug.config create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Web.Release.config create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/Web.config create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/WebApp_SAML_to_OIDC.csproj create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/WebApp_SAML_to_OIDC.sln create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/favicon.ico create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/fonts/glyphicons-halflings-regular.eot create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/fonts/glyphicons-halflings-regular.svg create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/fonts/glyphicons-halflings-regular.ttf create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/fonts/glyphicons-halflings-regular.woff create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/fonts/glyphicons-halflings-regular.woff2 create mode 100644 4-migration/2-AAD-Migration/2-3-From-SAML-to-OIDC/packages.config create mode 100644 4-migration/2-AAD-Migration/README.md create mode 100644 4-migration/CODE_OF_CONDUCT.md create mode 100644 4-migration/LICENSE create mode 100644 4-migration/README.md create mode 100644 4-migration/SECURITY.md create mode 100644 5-advanced/CHANGELOG.md create mode 100644 5-advanced/CONTRIBUTING.md create mode 100644 5-advanced/LICENSE.md create mode 100644 5-advanced/README.md create mode 100644 5-advanced/background-console-worker-app-webapi/AppCreationScripts/AppCreationScripts.md create mode 100644 5-advanced/background-console-worker-app-webapi/AppCreationScripts/Cleanup.ps1 create mode 100644 5-advanced/background-console-worker-app-webapi/AppCreationScripts/Configure.ps1 create mode 100644 5-advanced/background-console-worker-app-webapi/AppCreationScripts/apps.json create mode 100644 5-advanced/background-console-worker-app-webapi/AppCreationScripts/sample.json create mode 100644 5-advanced/background-console-worker-app-webapi/BackgroundWorker/AuthenticationConfig.cs create mode 100644 5-advanced/background-console-worker-app-webapi/BackgroundWorker/BackgroundWorker.csproj create mode 100644 5-advanced/background-console-worker-app-webapi/BackgroundWorker/BackgroundWorkerTokenCacheAdapter.cs create mode 100644 5-advanced/background-console-worker-app-webapi/BackgroundWorker/ColorConsoleLogger.cs create mode 100644 5-advanced/background-console-worker-app-webapi/BackgroundWorker/MsalAccount.cs create mode 100644 5-advanced/background-console-worker-app-webapi/BackgroundWorker/Program.cs create mode 100644 5-advanced/background-console-worker-app-webapi/BackgroundWorker/appsettings.json create mode 100644 5-advanced/background-console-worker-app-webapi/IntegratedCache.sln create mode 100644 5-advanced/background-console-worker-app-webapi/README.md create mode 100644 5-advanced/background-console-worker-app-webapi/ReadmeFiles/diagram.png create mode 100644 5-advanced/background-console-worker-app-webapi/SPA/package-lock.json create mode 100644 5-advanced/background-console-worker-app-webapi/SPA/package.json create mode 100644 5-advanced/background-console-worker-app-webapi/SPA/public/favicon.svg create mode 100644 5-advanced/background-console-worker-app-webapi/SPA/public/index.html create mode 100644 5-advanced/background-console-worker-app-webapi/SPA/public/manifest.json create mode 100644 5-advanced/background-console-worker-app-webapi/SPA/public/redirect.html create mode 100644 5-advanced/background-console-worker-app-webapi/SPA/public/robots.txt create mode 100644 5-advanced/background-console-worker-app-webapi/SPA/src/App.jsx create mode 100644 5-advanced/background-console-worker-app-webapi/SPA/src/authConfig.js create mode 100644 5-advanced/background-console-worker-app-webapi/SPA/src/components/DataDisplay.jsx create mode 100644 5-advanced/background-console-worker-app-webapi/SPA/src/components/NavigationBar.jsx create mode 100644 5-advanced/background-console-worker-app-webapi/SPA/src/components/PageLayout.jsx create mode 100644 5-advanced/background-console-worker-app-webapi/SPA/src/fetch.js create mode 100644 5-advanced/background-console-worker-app-webapi/SPA/src/index.js create mode 100644 5-advanced/background-console-worker-app-webapi/SPA/src/pages/Home.jsx create mode 100644 5-advanced/background-console-worker-app-webapi/SPA/src/styles/App.css create mode 100644 5-advanced/background-console-worker-app-webapi/SPA/src/styles/index.css create mode 100644 5-advanced/background-console-worker-app-webapi/SPA/src/utils/claimUtils.js create mode 100644 5-advanced/background-console-worker-app-webapi/WebAPI/Controllers/ProfileController.cs create mode 100644 5-advanced/background-console-worker-app-webapi/WebAPI/Program.cs create mode 100644 5-advanced/background-console-worker-app-webapi/WebAPI/Properties/launchSettings.json create mode 100644 5-advanced/background-console-worker-app-webapi/WebAPI/Services/MicrosoftGraphServiceExtensions.cs create mode 100644 5-advanced/background-console-worker-app-webapi/WebAPI/Startup.cs create mode 100644 5-advanced/background-console-worker-app-webapi/WebAPI/TokenAcquisitionCredentialProvider.cs create mode 100644 5-advanced/background-console-worker-app-webapi/WebAPI/WebAPI.csproj create mode 100644 5-advanced/background-console-worker-app-webapi/WebAPI/appsettings.Development.json create mode 100644 5-advanced/background-console-worker-app-webapi/WebAPI/appsettings.json create mode 100644 5-advanced/background-console-worker-app-webapi/WebAPI/wwwroot/index.html create mode 100644 5-advanced/background-console-worker-app-webapp/AppCreationScripts/AppCreationScripts.md create mode 100644 5-advanced/background-console-worker-app-webapp/AppCreationScripts/Cleanup.ps1 create mode 100644 5-advanced/background-console-worker-app-webapp/AppCreationScripts/Configure.ps1 create mode 100644 5-advanced/background-console-worker-app-webapp/AppCreationScripts/apps.json create mode 100644 5-advanced/background-console-worker-app-webapp/AppCreationScripts/sample.json create mode 100644 5-advanced/background-console-worker-app-webapp/BackgroundWorker/AuthenticationConfig.cs create mode 100644 5-advanced/background-console-worker-app-webapp/BackgroundWorker/BackgroundWorker.csproj create mode 100644 5-advanced/background-console-worker-app-webapp/BackgroundWorker/MsalAccount.cs create mode 100644 5-advanced/background-console-worker-app-webapp/BackgroundWorker/Program.cs create mode 100644 5-advanced/background-console-worker-app-webapp/BackgroundWorker/appsettings.json create mode 100644 5-advanced/background-console-worker-app-webapp/IntegratedCache.sln create mode 100644 5-advanced/background-console-worker-app-webapp/README.md create mode 100644 5-advanced/background-console-worker-app-webapp/ReadmeFiles/diagram.png create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/Constants.cs create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/Controllers/HomeController.cs create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/Models/ErrorViewModel.cs create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/Program.cs create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/Properties/launchSettings.json create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/Services/GraphServiceClientFactory.cs create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/Startup.cs create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/Views/Home/Index.cshtml create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/Views/Home/Privacy.cshtml create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/Views/Shared/Error.cshtml create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/Views/Shared/_Layout.cshtml create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/Views/Shared/_LoginPartial.cshtml create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/Views/Shared/_ValidationScriptsPartial.cshtml create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/Views/_ViewImports.cshtml create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/Views/_ViewStart.cshtml create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/WebApp.csproj create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/WebApp.sln create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/appsettings.Development.json create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/appsettings.json create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/css/site.css create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/favicon.ico create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/js/site.js create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/bootstrap/LICENSE create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css.map create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css.map create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css.map create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css.map create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/bootstrap/dist/css/bootstrap.css create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/bootstrap/dist/css/bootstrap.css.map create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css.map create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js.map create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js.map create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/bootstrap/dist/js/bootstrap.js create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/bootstrap/dist/js/bootstrap.js.map create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js.map create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/jquery-validation/LICENSE.md create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/jquery-validation/dist/additional-methods.js create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/jquery-validation/dist/additional-methods.min.js create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/jquery-validation/dist/jquery.validate.js create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/jquery-validation/dist/jquery.validate.min.js create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/jquery/LICENSE.txt create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/jquery/dist/jquery.js create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/jquery/dist/jquery.min.js create mode 100644 5-advanced/background-console-worker-app-webapp/WebApp/wwwroot/lib/jquery/dist/jquery.min.map diff --git a/web-api-azure-function/.gitignore b/1-server-side/web-api-azure-function/.gitignore similarity index 100% rename from web-api-azure-function/.gitignore rename to 1-server-side/web-api-azure-function/.gitignore diff --git a/web-api-azure-function/Api.csproj b/1-server-side/web-api-azure-function/Api.csproj similarity index 100% rename from web-api-azure-function/Api.csproj rename to 1-server-side/web-api-azure-function/Api.csproj diff --git a/web-api-azure-function/README.md b/1-server-side/web-api-azure-function/README.md similarity index 100% rename from web-api-azure-function/README.md rename to 1-server-side/web-api-azure-function/README.md diff --git a/web-api-azure-function/greeting.cs b/1-server-side/web-api-azure-function/greeting.cs similarity index 100% rename from web-api-azure-function/greeting.cs rename to 1-server-side/web-api-azure-function/greeting.cs diff --git a/web-api-azure-function/host.json b/1-server-side/web-api-azure-function/host.json similarity index 100% rename from web-api-azure-function/host.json rename to 1-server-side/web-api-azure-function/host.json diff --git a/web-api-obo-client/Api.csproj b/1-server-side/web-api-obo-client/Api.csproj similarity index 100% rename from web-api-obo-client/Api.csproj rename to 1-server-side/web-api-obo-client/Api.csproj diff --git a/web-api-obo-client/Program.cs b/1-server-side/web-api-obo-client/Program.cs similarity index 100% rename from web-api-obo-client/Program.cs rename to 1-server-side/web-api-obo-client/Program.cs diff --git a/web-api-obo-client/README.md b/1-server-side/web-api-obo-client/README.md similarity index 100% rename from web-api-obo-client/README.md rename to 1-server-side/web-api-obo-client/README.md diff --git a/web-api-obo-client/appsettings.json b/1-server-side/web-api-obo-client/appsettings.json similarity index 100% rename from web-api-obo-client/appsettings.json rename to 1-server-side/web-api-obo-client/appsettings.json diff --git a/web-api-obo-user/Api.csproj b/1-server-side/web-api-obo-user/Api.csproj similarity index 100% rename from web-api-obo-user/Api.csproj rename to 1-server-side/web-api-obo-user/Api.csproj diff --git a/web-api-obo-user/Program.cs b/1-server-side/web-api-obo-user/Program.cs similarity index 100% rename from web-api-obo-user/Program.cs rename to 1-server-side/web-api-obo-user/Program.cs diff --git a/web-api-obo-user/README.md b/1-server-side/web-api-obo-user/README.md similarity index 100% rename from web-api-obo-user/README.md rename to 1-server-side/web-api-obo-user/README.md diff --git a/web-api-obo-user/appsettings.json b/1-server-side/web-api-obo-user/appsettings.json similarity index 100% rename from web-api-obo-user/appsettings.json rename to 1-server-side/web-api-obo-user/appsettings.json diff --git a/web-api/Api.csproj b/1-server-side/web-api/Api.csproj similarity index 100% rename from web-api/Api.csproj rename to 1-server-side/web-api/Api.csproj diff --git a/web-api/Program.cs b/1-server-side/web-api/Program.cs similarity index 100% rename from web-api/Program.cs rename to 1-server-side/web-api/Program.cs diff --git a/web-api/Properties/launchSettings.json b/1-server-side/web-api/Properties/launchSettings.json similarity index 100% rename from web-api/Properties/launchSettings.json rename to 1-server-side/web-api/Properties/launchSettings.json diff --git a/web-api/README.md b/1-server-side/web-api/README.md similarity index 100% rename from web-api/README.md rename to 1-server-side/web-api/README.md diff --git a/web-api/appsettings.json b/1-server-side/web-api/appsettings.json similarity index 100% rename from web-api/appsettings.json rename to 1-server-side/web-api/appsettings.json diff --git a/web-app-aspnet/Pages/Error.cshtml b/1-server-side/web-app-aspnet/Pages/Error.cshtml similarity index 100% rename from web-app-aspnet/Pages/Error.cshtml rename to 1-server-side/web-app-aspnet/Pages/Error.cshtml diff --git a/web-app-aspnet/Pages/Error.cshtml.cs b/1-server-side/web-app-aspnet/Pages/Error.cshtml.cs similarity index 100% rename from web-app-aspnet/Pages/Error.cshtml.cs rename to 1-server-side/web-app-aspnet/Pages/Error.cshtml.cs diff --git a/web-app-aspnet/Pages/Index.cshtml b/1-server-side/web-app-aspnet/Pages/Index.cshtml similarity index 100% rename from web-app-aspnet/Pages/Index.cshtml rename to 1-server-side/web-app-aspnet/Pages/Index.cshtml diff --git a/web-app-aspnet/Pages/Index.cshtml.cs b/1-server-side/web-app-aspnet/Pages/Index.cshtml.cs similarity index 100% rename from web-app-aspnet/Pages/Index.cshtml.cs rename to 1-server-side/web-app-aspnet/Pages/Index.cshtml.cs diff --git a/web-app-aspnet/Pages/Privacy.cshtml b/1-server-side/web-app-aspnet/Pages/Privacy.cshtml similarity index 100% rename from web-app-aspnet/Pages/Privacy.cshtml rename to 1-server-side/web-app-aspnet/Pages/Privacy.cshtml diff --git a/web-app-aspnet/Pages/Privacy.cshtml.cs b/1-server-side/web-app-aspnet/Pages/Privacy.cshtml.cs similarity index 100% rename from web-app-aspnet/Pages/Privacy.cshtml.cs rename to 1-server-side/web-app-aspnet/Pages/Privacy.cshtml.cs diff --git a/web-app-aspnet/Pages/Shared/_Layout.cshtml b/1-server-side/web-app-aspnet/Pages/Shared/_Layout.cshtml similarity index 100% rename from web-app-aspnet/Pages/Shared/_Layout.cshtml rename to 1-server-side/web-app-aspnet/Pages/Shared/_Layout.cshtml diff --git a/web-app-aspnet/Pages/Shared/_Layout.cshtml.css b/1-server-side/web-app-aspnet/Pages/Shared/_Layout.cshtml.css similarity index 100% rename from web-app-aspnet/Pages/Shared/_Layout.cshtml.css rename to 1-server-side/web-app-aspnet/Pages/Shared/_Layout.cshtml.css diff --git a/web-app-aspnet/Pages/Shared/_LoginPartial.cshtml b/1-server-side/web-app-aspnet/Pages/Shared/_LoginPartial.cshtml similarity index 100% rename from web-app-aspnet/Pages/Shared/_LoginPartial.cshtml rename to 1-server-side/web-app-aspnet/Pages/Shared/_LoginPartial.cshtml diff --git a/web-app-aspnet/Pages/Shared/_ValidationScriptsPartial.cshtml b/1-server-side/web-app-aspnet/Pages/Shared/_ValidationScriptsPartial.cshtml similarity index 100% rename from web-app-aspnet/Pages/Shared/_ValidationScriptsPartial.cshtml rename to 1-server-side/web-app-aspnet/Pages/Shared/_ValidationScriptsPartial.cshtml diff --git a/web-app-aspnet/Pages/_ViewImports.cshtml b/1-server-side/web-app-aspnet/Pages/_ViewImports.cshtml similarity index 100% rename from web-app-aspnet/Pages/_ViewImports.cshtml rename to 1-server-side/web-app-aspnet/Pages/_ViewImports.cshtml diff --git a/web-app-aspnet/Pages/_ViewStart.cshtml b/1-server-side/web-app-aspnet/Pages/_ViewStart.cshtml similarity index 100% rename from web-app-aspnet/Pages/_ViewStart.cshtml rename to 1-server-side/web-app-aspnet/Pages/_ViewStart.cshtml diff --git a/web-app-aspnet/Program.cs b/1-server-side/web-app-aspnet/Program.cs similarity index 100% rename from web-app-aspnet/Program.cs rename to 1-server-side/web-app-aspnet/Program.cs diff --git a/web-app-aspnet/Properties/launchSettings.json b/1-server-side/web-app-aspnet/Properties/launchSettings.json similarity index 100% rename from web-app-aspnet/Properties/launchSettings.json rename to 1-server-side/web-app-aspnet/Properties/launchSettings.json diff --git a/web-app-aspnet/README.md b/1-server-side/web-app-aspnet/README.md similarity index 100% rename from web-app-aspnet/README.md rename to 1-server-side/web-app-aspnet/README.md diff --git a/web-app-aspnet/WebApp.csproj b/1-server-side/web-app-aspnet/WebApp.csproj similarity index 100% rename from web-app-aspnet/WebApp.csproj rename to 1-server-side/web-app-aspnet/WebApp.csproj diff --git a/web-app-aspnet/appsettings.json b/1-server-side/web-app-aspnet/appsettings.json similarity index 100% rename from web-app-aspnet/appsettings.json rename to 1-server-side/web-app-aspnet/appsettings.json diff --git a/web-app-aspnet/media/app-signedin.png b/1-server-side/web-app-aspnet/media/app-signedin.png similarity index 100% rename from web-app-aspnet/media/app-signedin.png rename to 1-server-side/web-app-aspnet/media/app-signedin.png diff --git a/web-app-aspnet/media/app-signedout.png b/1-server-side/web-app-aspnet/media/app-signedout.png similarity index 100% rename from web-app-aspnet/media/app-signedout.png rename to 1-server-side/web-app-aspnet/media/app-signedout.png diff --git a/web-app-aspnet/wwwroot/css/site.css b/1-server-side/web-app-aspnet/wwwroot/css/site.css similarity index 100% rename from web-app-aspnet/wwwroot/css/site.css rename to 1-server-side/web-app-aspnet/wwwroot/css/site.css diff --git a/spa-blazor-wasm/media/favicon.ico b/1-server-side/web-app-aspnet/wwwroot/favicon.ico similarity index 100% rename from spa-blazor-wasm/media/favicon.ico rename to 1-server-side/web-app-aspnet/wwwroot/favicon.ico diff --git a/web-app-aspnet/wwwroot/js/site.js b/1-server-side/web-app-aspnet/wwwroot/js/site.js similarity index 100% rename from web-app-aspnet/wwwroot/js/site.js rename to 1-server-side/web-app-aspnet/wwwroot/js/site.js diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/LICENSE b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/LICENSE similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/LICENSE rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/LICENSE diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css.map b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css.map similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css.map rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css.map diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css.map b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css.map similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css.map rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css.map diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css.map b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css.map similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css.map rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css.map diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css.map b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css.map similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css.map rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.min.css.map diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css.map b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css.map similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css.map rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css.map diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css.map b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css.map similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css.map rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css.map diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css.map b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css.map similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css.map rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css.map diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css.map b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css.map similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css.map rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css.map diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.css b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.css similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.css rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.css diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.css.map b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.css.map similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.css.map rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.css.map diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.min.css b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.min.css similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.min.css rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.min.css diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.min.css.map b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.min.css.map similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.min.css.map rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.min.css.map diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.css b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.css similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.css rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.css diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.css.map b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.css.map similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.css.map rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.css.map diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.min.css b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.min.css similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.min.css rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.min.css diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.min.css.map b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.min.css.map similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.min.css.map rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.min.css.map diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.css b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.css similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.css rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.css diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.css.map b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.css.map similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.css.map rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.css.map diff --git a/spa-blazor-wasm/wwwroot/css/bootstrap/bootstrap.min.css b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css similarity index 100% rename from spa-blazor-wasm/wwwroot/css/bootstrap/bootstrap.min.css rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css diff --git a/spa-blazor-wasm/wwwroot/css/bootstrap/bootstrap.min.css.map b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css.map similarity index 100% rename from spa-blazor-wasm/wwwroot/css/bootstrap/bootstrap.min.css.map rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css.map diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.css b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.css similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.css rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.css diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.css.map b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.css.map similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.css.map rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.css.map diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.min.css b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.min.css similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.min.css rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.min.css diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.min.css.map b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.min.css.map similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.min.css.map rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.min.css.map diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js.map b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js.map similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js.map rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js.map diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js.map b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js.map similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js.map rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js.map diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.js b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.js similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.js rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.js diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.js.map b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.js.map similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.js.map rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.js.map diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js.map b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js.map similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js.map rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.esm.min.js.map diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.js b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.js similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.js rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.js diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.js.map b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.js.map similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.js.map rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.js.map diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js.map b/1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js.map similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js.map rename to 1-server-side/web-app-aspnet/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js.map diff --git a/web-app-aspnet/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt b/1-server-side/web-app-aspnet/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt similarity index 100% rename from web-app-aspnet/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt rename to 1-server-side/web-app-aspnet/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt diff --git a/web-app-aspnet/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js b/1-server-side/web-app-aspnet/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js similarity index 100% rename from web-app-aspnet/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js rename to 1-server-side/web-app-aspnet/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js diff --git a/web-app-aspnet/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js b/1-server-side/web-app-aspnet/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js similarity index 100% rename from web-app-aspnet/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js rename to 1-server-side/web-app-aspnet/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js diff --git a/web-app-aspnet/wwwroot/lib/jquery-validation/LICENSE.md b/1-server-side/web-app-aspnet/wwwroot/lib/jquery-validation/LICENSE.md similarity index 100% rename from web-app-aspnet/wwwroot/lib/jquery-validation/LICENSE.md rename to 1-server-side/web-app-aspnet/wwwroot/lib/jquery-validation/LICENSE.md diff --git a/web-app-aspnet/wwwroot/lib/jquery-validation/dist/additional-methods.js b/1-server-side/web-app-aspnet/wwwroot/lib/jquery-validation/dist/additional-methods.js similarity index 100% rename from web-app-aspnet/wwwroot/lib/jquery-validation/dist/additional-methods.js rename to 1-server-side/web-app-aspnet/wwwroot/lib/jquery-validation/dist/additional-methods.js diff --git a/web-app-aspnet/wwwroot/lib/jquery-validation/dist/additional-methods.min.js b/1-server-side/web-app-aspnet/wwwroot/lib/jquery-validation/dist/additional-methods.min.js similarity index 100% rename from web-app-aspnet/wwwroot/lib/jquery-validation/dist/additional-methods.min.js rename to 1-server-side/web-app-aspnet/wwwroot/lib/jquery-validation/dist/additional-methods.min.js diff --git a/web-app-aspnet/wwwroot/lib/jquery-validation/dist/jquery.validate.js b/1-server-side/web-app-aspnet/wwwroot/lib/jquery-validation/dist/jquery.validate.js similarity index 100% rename from web-app-aspnet/wwwroot/lib/jquery-validation/dist/jquery.validate.js rename to 1-server-side/web-app-aspnet/wwwroot/lib/jquery-validation/dist/jquery.validate.js diff --git a/web-app-aspnet/wwwroot/lib/jquery-validation/dist/jquery.validate.min.js b/1-server-side/web-app-aspnet/wwwroot/lib/jquery-validation/dist/jquery.validate.min.js similarity index 100% rename from web-app-aspnet/wwwroot/lib/jquery-validation/dist/jquery.validate.min.js rename to 1-server-side/web-app-aspnet/wwwroot/lib/jquery-validation/dist/jquery.validate.min.js diff --git a/web-app-aspnet/wwwroot/lib/jquery/LICENSE.txt b/1-server-side/web-app-aspnet/wwwroot/lib/jquery/LICENSE.txt similarity index 100% rename from web-app-aspnet/wwwroot/lib/jquery/LICENSE.txt rename to 1-server-side/web-app-aspnet/wwwroot/lib/jquery/LICENSE.txt diff --git a/web-app-aspnet/wwwroot/lib/jquery/dist/jquery.js b/1-server-side/web-app-aspnet/wwwroot/lib/jquery/dist/jquery.js similarity index 100% rename from web-app-aspnet/wwwroot/lib/jquery/dist/jquery.js rename to 1-server-side/web-app-aspnet/wwwroot/lib/jquery/dist/jquery.js diff --git a/web-app-aspnet/wwwroot/lib/jquery/dist/jquery.min.js b/1-server-side/web-app-aspnet/wwwroot/lib/jquery/dist/jquery.min.js similarity index 100% rename from web-app-aspnet/wwwroot/lib/jquery/dist/jquery.min.js rename to 1-server-side/web-app-aspnet/wwwroot/lib/jquery/dist/jquery.min.js diff --git a/web-app-aspnet/wwwroot/lib/jquery/dist/jquery.min.map b/1-server-side/web-app-aspnet/wwwroot/lib/jquery/dist/jquery.min.map similarity index 100% rename from web-app-aspnet/wwwroot/lib/jquery/dist/jquery.min.map rename to 1-server-side/web-app-aspnet/wwwroot/lib/jquery/dist/jquery.min.map diff --git a/web-app-blazor-server/App.razor b/1-server-side/web-app-blazor-server/App.razor similarity index 100% rename from web-app-blazor-server/App.razor rename to 1-server-side/web-app-blazor-server/App.razor diff --git a/web-app-blazor-server/BlazorServerWebApp.csproj b/1-server-side/web-app-blazor-server/BlazorServerWebApp.csproj similarity index 100% rename from web-app-blazor-server/BlazorServerWebApp.csproj rename to 1-server-side/web-app-blazor-server/BlazorServerWebApp.csproj diff --git a/web-app-blazor-server/Pages/Index.razor b/1-server-side/web-app-blazor-server/Pages/Index.razor similarity index 100% rename from web-app-blazor-server/Pages/Index.razor rename to 1-server-side/web-app-blazor-server/Pages/Index.razor diff --git a/web-app-blazor-server/Pages/_Host.cshtml b/1-server-side/web-app-blazor-server/Pages/_Host.cshtml similarity index 100% rename from web-app-blazor-server/Pages/_Host.cshtml rename to 1-server-side/web-app-blazor-server/Pages/_Host.cshtml diff --git a/web-app-blazor-server/Pages/_Layout.cshtml b/1-server-side/web-app-blazor-server/Pages/_Layout.cshtml similarity index 100% rename from web-app-blazor-server/Pages/_Layout.cshtml rename to 1-server-side/web-app-blazor-server/Pages/_Layout.cshtml diff --git a/web-app-blazor-server/Program.cs b/1-server-side/web-app-blazor-server/Program.cs similarity index 100% rename from web-app-blazor-server/Program.cs rename to 1-server-side/web-app-blazor-server/Program.cs diff --git a/web-app-blazor-server/Properties/launchSettings.json b/1-server-side/web-app-blazor-server/Properties/launchSettings.json similarity index 100% rename from web-app-blazor-server/Properties/launchSettings.json rename to 1-server-side/web-app-blazor-server/Properties/launchSettings.json diff --git a/web-app-blazor-server/README.md b/1-server-side/web-app-blazor-server/README.md similarity index 100% rename from web-app-blazor-server/README.md rename to 1-server-side/web-app-blazor-server/README.md diff --git a/web-app-blazor-server/Shared/LoginDisplay.razor b/1-server-side/web-app-blazor-server/Shared/LoginDisplay.razor similarity index 100% rename from web-app-blazor-server/Shared/LoginDisplay.razor rename to 1-server-side/web-app-blazor-server/Shared/LoginDisplay.razor diff --git a/web-app-blazor-server/Shared/MainLayout.razor b/1-server-side/web-app-blazor-server/Shared/MainLayout.razor similarity index 100% rename from web-app-blazor-server/Shared/MainLayout.razor rename to 1-server-side/web-app-blazor-server/Shared/MainLayout.razor diff --git a/web-app-blazor-server/Shared/MainLayout.razor.css b/1-server-side/web-app-blazor-server/Shared/MainLayout.razor.css similarity index 100% rename from web-app-blazor-server/Shared/MainLayout.razor.css rename to 1-server-side/web-app-blazor-server/Shared/MainLayout.razor.css diff --git a/web-app-blazor-server/Shared/NavMenu.razor b/1-server-side/web-app-blazor-server/Shared/NavMenu.razor similarity index 100% rename from web-app-blazor-server/Shared/NavMenu.razor rename to 1-server-side/web-app-blazor-server/Shared/NavMenu.razor diff --git a/spa-blazor-wasm/Shared/NavMenu.razor.css b/1-server-side/web-app-blazor-server/Shared/NavMenu.razor.css similarity index 100% rename from spa-blazor-wasm/Shared/NavMenu.razor.css rename to 1-server-side/web-app-blazor-server/Shared/NavMenu.razor.css diff --git a/web-app-blazor-server/_Imports.razor b/1-server-side/web-app-blazor-server/_Imports.razor similarity index 100% rename from web-app-blazor-server/_Imports.razor rename to 1-server-side/web-app-blazor-server/_Imports.razor diff --git a/web-app-blazor-server/app-signed-in.png b/1-server-side/web-app-blazor-server/app-signed-in.png similarity index 100% rename from web-app-blazor-server/app-signed-in.png rename to 1-server-side/web-app-blazor-server/app-signed-in.png diff --git a/web-app-blazor-server/app-signed-out.png b/1-server-side/web-app-blazor-server/app-signed-out.png similarity index 100% rename from web-app-blazor-server/app-signed-out.png rename to 1-server-side/web-app-blazor-server/app-signed-out.png diff --git a/web-app-blazor-server/appsettings.json b/1-server-side/web-app-blazor-server/appsettings.json similarity index 100% rename from web-app-blazor-server/appsettings.json rename to 1-server-side/web-app-blazor-server/appsettings.json diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css b/1-server-side/web-app-blazor-server/wwwroot/css/bootstrap/bootstrap.min.css similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css rename to 1-server-side/web-app-blazor-server/wwwroot/css/bootstrap/bootstrap.min.css diff --git a/web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css.map b/1-server-side/web-app-blazor-server/wwwroot/css/bootstrap/bootstrap.min.css.map similarity index 100% rename from web-app-aspnet/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css.map rename to 1-server-side/web-app-blazor-server/wwwroot/css/bootstrap/bootstrap.min.css.map diff --git a/spa-blazor-wasm/wwwroot/css/open-iconic/FONT-LICENSE b/1-server-side/web-app-blazor-server/wwwroot/css/open-iconic/FONT-LICENSE similarity index 100% rename from spa-blazor-wasm/wwwroot/css/open-iconic/FONT-LICENSE rename to 1-server-side/web-app-blazor-server/wwwroot/css/open-iconic/FONT-LICENSE diff --git a/spa-blazor-wasm/wwwroot/css/open-iconic/ICON-LICENSE b/1-server-side/web-app-blazor-server/wwwroot/css/open-iconic/ICON-LICENSE similarity index 100% rename from spa-blazor-wasm/wwwroot/css/open-iconic/ICON-LICENSE rename to 1-server-side/web-app-blazor-server/wwwroot/css/open-iconic/ICON-LICENSE diff --git a/spa-blazor-wasm/wwwroot/css/open-iconic/README.md b/1-server-side/web-app-blazor-server/wwwroot/css/open-iconic/README.md similarity index 100% rename from spa-blazor-wasm/wwwroot/css/open-iconic/README.md rename to 1-server-side/web-app-blazor-server/wwwroot/css/open-iconic/README.md diff --git a/spa-blazor-wasm/wwwroot/css/open-iconic/font/css/open-iconic-bootstrap.min.css b/1-server-side/web-app-blazor-server/wwwroot/css/open-iconic/font/css/open-iconic-bootstrap.min.css similarity index 100% rename from spa-blazor-wasm/wwwroot/css/open-iconic/font/css/open-iconic-bootstrap.min.css rename to 1-server-side/web-app-blazor-server/wwwroot/css/open-iconic/font/css/open-iconic-bootstrap.min.css diff --git a/spa-blazor-wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.eot b/1-server-side/web-app-blazor-server/wwwroot/css/open-iconic/font/fonts/open-iconic.eot similarity index 100% rename from spa-blazor-wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.eot rename to 1-server-side/web-app-blazor-server/wwwroot/css/open-iconic/font/fonts/open-iconic.eot diff --git a/spa-blazor-wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.otf b/1-server-side/web-app-blazor-server/wwwroot/css/open-iconic/font/fonts/open-iconic.otf similarity index 100% rename from spa-blazor-wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.otf rename to 1-server-side/web-app-blazor-server/wwwroot/css/open-iconic/font/fonts/open-iconic.otf diff --git a/spa-blazor-wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.svg b/1-server-side/web-app-blazor-server/wwwroot/css/open-iconic/font/fonts/open-iconic.svg similarity index 100% rename from spa-blazor-wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.svg rename to 1-server-side/web-app-blazor-server/wwwroot/css/open-iconic/font/fonts/open-iconic.svg diff --git a/spa-blazor-wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf b/1-server-side/web-app-blazor-server/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf similarity index 100% rename from spa-blazor-wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf rename to 1-server-side/web-app-blazor-server/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf diff --git a/spa-blazor-wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.woff b/1-server-side/web-app-blazor-server/wwwroot/css/open-iconic/font/fonts/open-iconic.woff similarity index 100% rename from spa-blazor-wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.woff rename to 1-server-side/web-app-blazor-server/wwwroot/css/open-iconic/font/fonts/open-iconic.woff diff --git a/web-app-blazor-server/wwwroot/css/site.css b/1-server-side/web-app-blazor-server/wwwroot/css/site.css similarity index 100% rename from web-app-blazor-server/wwwroot/css/site.css rename to 1-server-side/web-app-blazor-server/wwwroot/css/site.css diff --git a/web-app-aspnet/wwwroot/favicon.ico b/1-server-side/web-app-blazor-server/wwwroot/favicon.ico similarity index 100% rename from web-app-aspnet/wwwroot/favicon.ico rename to 1-server-side/web-app-blazor-server/wwwroot/favicon.ico diff --git a/spa-blazor-wasm/App.razor b/2-client-side/spa-blazor-wasm/App.razor similarity index 100% rename from spa-blazor-wasm/App.razor rename to 2-client-side/spa-blazor-wasm/App.razor diff --git a/spa-blazor-wasm/BlazorWasm.csproj b/2-client-side/spa-blazor-wasm/BlazorWasm.csproj similarity index 100% rename from spa-blazor-wasm/BlazorWasm.csproj rename to 2-client-side/spa-blazor-wasm/BlazorWasm.csproj diff --git a/spa-blazor-wasm/Pages/Authentication.razor b/2-client-side/spa-blazor-wasm/Pages/Authentication.razor similarity index 100% rename from spa-blazor-wasm/Pages/Authentication.razor rename to 2-client-side/spa-blazor-wasm/Pages/Authentication.razor diff --git a/spa-blazor-wasm/Pages/Index.razor b/2-client-side/spa-blazor-wasm/Pages/Index.razor similarity index 100% rename from spa-blazor-wasm/Pages/Index.razor rename to 2-client-side/spa-blazor-wasm/Pages/Index.razor diff --git a/spa-blazor-wasm/Program.cs b/2-client-side/spa-blazor-wasm/Program.cs similarity index 100% rename from spa-blazor-wasm/Program.cs rename to 2-client-side/spa-blazor-wasm/Program.cs diff --git a/spa-blazor-wasm/README.md b/2-client-side/spa-blazor-wasm/README.md similarity index 100% rename from spa-blazor-wasm/README.md rename to 2-client-side/spa-blazor-wasm/README.md diff --git a/spa-blazor-wasm/Shared/LoginDisplay.razor b/2-client-side/spa-blazor-wasm/Shared/LoginDisplay.razor similarity index 100% rename from spa-blazor-wasm/Shared/LoginDisplay.razor rename to 2-client-side/spa-blazor-wasm/Shared/LoginDisplay.razor diff --git a/spa-blazor-wasm/Shared/MainLayout.razor b/2-client-side/spa-blazor-wasm/Shared/MainLayout.razor similarity index 100% rename from spa-blazor-wasm/Shared/MainLayout.razor rename to 2-client-side/spa-blazor-wasm/Shared/MainLayout.razor diff --git a/spa-blazor-wasm/Shared/MainLayout.razor.css b/2-client-side/spa-blazor-wasm/Shared/MainLayout.razor.css similarity index 100% rename from spa-blazor-wasm/Shared/MainLayout.razor.css rename to 2-client-side/spa-blazor-wasm/Shared/MainLayout.razor.css diff --git a/spa-blazor-wasm/Shared/NavMenu.razor b/2-client-side/spa-blazor-wasm/Shared/NavMenu.razor similarity index 100% rename from spa-blazor-wasm/Shared/NavMenu.razor rename to 2-client-side/spa-blazor-wasm/Shared/NavMenu.razor diff --git a/web-app-blazor-server/Shared/NavMenu.razor.css b/2-client-side/spa-blazor-wasm/Shared/NavMenu.razor.css similarity index 100% rename from web-app-blazor-server/Shared/NavMenu.razor.css rename to 2-client-side/spa-blazor-wasm/Shared/NavMenu.razor.css diff --git a/spa-blazor-wasm/Shared/RedirectToLogin.razor b/2-client-side/spa-blazor-wasm/Shared/RedirectToLogin.razor similarity index 100% rename from spa-blazor-wasm/Shared/RedirectToLogin.razor rename to 2-client-side/spa-blazor-wasm/Shared/RedirectToLogin.razor diff --git a/spa-blazor-wasm/_Imports.razor b/2-client-side/spa-blazor-wasm/_Imports.razor similarity index 100% rename from spa-blazor-wasm/_Imports.razor rename to 2-client-side/spa-blazor-wasm/_Imports.razor diff --git a/spa-blazor-wasm/media/app-signedin.png b/2-client-side/spa-blazor-wasm/media/app-signedin.png similarity index 100% rename from spa-blazor-wasm/media/app-signedin.png rename to 2-client-side/spa-blazor-wasm/media/app-signedin.png diff --git a/spa-blazor-wasm/media/app-signedout.png b/2-client-side/spa-blazor-wasm/media/app-signedout.png similarity index 100% rename from spa-blazor-wasm/media/app-signedout.png rename to 2-client-side/spa-blazor-wasm/media/app-signedout.png diff --git a/web-app-blazor-server/wwwroot/favicon.ico b/2-client-side/spa-blazor-wasm/media/favicon.ico similarity index 100% rename from web-app-blazor-server/wwwroot/favicon.ico rename to 2-client-side/spa-blazor-wasm/media/favicon.ico diff --git a/spa-blazor-wasm/wwwroot/appsettings.json b/2-client-side/spa-blazor-wasm/wwwroot/appsettings.json similarity index 100% rename from spa-blazor-wasm/wwwroot/appsettings.json rename to 2-client-side/spa-blazor-wasm/wwwroot/appsettings.json diff --git a/spa-blazor-wasm/wwwroot/css/app.css b/2-client-side/spa-blazor-wasm/wwwroot/css/app.css similarity index 100% rename from spa-blazor-wasm/wwwroot/css/app.css rename to 2-client-side/spa-blazor-wasm/wwwroot/css/app.css diff --git a/web-app-blazor-server/wwwroot/css/bootstrap/bootstrap.min.css b/2-client-side/spa-blazor-wasm/wwwroot/css/bootstrap/bootstrap.min.css similarity index 100% rename from web-app-blazor-server/wwwroot/css/bootstrap/bootstrap.min.css rename to 2-client-side/spa-blazor-wasm/wwwroot/css/bootstrap/bootstrap.min.css diff --git a/web-app-blazor-server/wwwroot/css/bootstrap/bootstrap.min.css.map b/2-client-side/spa-blazor-wasm/wwwroot/css/bootstrap/bootstrap.min.css.map similarity index 100% rename from web-app-blazor-server/wwwroot/css/bootstrap/bootstrap.min.css.map rename to 2-client-side/spa-blazor-wasm/wwwroot/css/bootstrap/bootstrap.min.css.map diff --git a/web-app-blazor-server/wwwroot/css/open-iconic/FONT-LICENSE b/2-client-side/spa-blazor-wasm/wwwroot/css/open-iconic/FONT-LICENSE similarity index 100% rename from web-app-blazor-server/wwwroot/css/open-iconic/FONT-LICENSE rename to 2-client-side/spa-blazor-wasm/wwwroot/css/open-iconic/FONT-LICENSE diff --git a/web-app-blazor-server/wwwroot/css/open-iconic/ICON-LICENSE b/2-client-side/spa-blazor-wasm/wwwroot/css/open-iconic/ICON-LICENSE similarity index 100% rename from web-app-blazor-server/wwwroot/css/open-iconic/ICON-LICENSE rename to 2-client-side/spa-blazor-wasm/wwwroot/css/open-iconic/ICON-LICENSE diff --git a/web-app-blazor-server/wwwroot/css/open-iconic/README.md b/2-client-side/spa-blazor-wasm/wwwroot/css/open-iconic/README.md similarity index 100% rename from web-app-blazor-server/wwwroot/css/open-iconic/README.md rename to 2-client-side/spa-blazor-wasm/wwwroot/css/open-iconic/README.md diff --git a/web-app-blazor-server/wwwroot/css/open-iconic/font/css/open-iconic-bootstrap.min.css b/2-client-side/spa-blazor-wasm/wwwroot/css/open-iconic/font/css/open-iconic-bootstrap.min.css similarity index 100% rename from web-app-blazor-server/wwwroot/css/open-iconic/font/css/open-iconic-bootstrap.min.css rename to 2-client-side/spa-blazor-wasm/wwwroot/css/open-iconic/font/css/open-iconic-bootstrap.min.css diff --git a/web-app-blazor-server/wwwroot/css/open-iconic/font/fonts/open-iconic.eot b/2-client-side/spa-blazor-wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.eot similarity index 100% rename from web-app-blazor-server/wwwroot/css/open-iconic/font/fonts/open-iconic.eot rename to 2-client-side/spa-blazor-wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.eot diff --git a/web-app-blazor-server/wwwroot/css/open-iconic/font/fonts/open-iconic.otf b/2-client-side/spa-blazor-wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.otf similarity index 100% rename from web-app-blazor-server/wwwroot/css/open-iconic/font/fonts/open-iconic.otf rename to 2-client-side/spa-blazor-wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.otf diff --git a/web-app-blazor-server/wwwroot/css/open-iconic/font/fonts/open-iconic.svg b/2-client-side/spa-blazor-wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.svg similarity index 100% rename from web-app-blazor-server/wwwroot/css/open-iconic/font/fonts/open-iconic.svg rename to 2-client-side/spa-blazor-wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.svg diff --git a/web-app-blazor-server/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf b/2-client-side/spa-blazor-wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf similarity index 100% rename from web-app-blazor-server/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf rename to 2-client-side/spa-blazor-wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf diff --git a/web-app-blazor-server/wwwroot/css/open-iconic/font/fonts/open-iconic.woff b/2-client-side/spa-blazor-wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.woff similarity index 100% rename from web-app-blazor-server/wwwroot/css/open-iconic/font/fonts/open-iconic.woff rename to 2-client-side/spa-blazor-wasm/wwwroot/css/open-iconic/font/fonts/open-iconic.woff diff --git a/spa-blazor-wasm/wwwroot/icon-192.png b/2-client-side/spa-blazor-wasm/wwwroot/icon-192.png similarity index 100% rename from spa-blazor-wasm/wwwroot/icon-192.png rename to 2-client-side/spa-blazor-wasm/wwwroot/icon-192.png diff --git a/spa-blazor-wasm/wwwroot/icon-512.png b/2-client-side/spa-blazor-wasm/wwwroot/icon-512.png similarity index 100% rename from spa-blazor-wasm/wwwroot/icon-512.png rename to 2-client-side/spa-blazor-wasm/wwwroot/icon-512.png diff --git a/spa-blazor-wasm/wwwroot/index.html b/2-client-side/spa-blazor-wasm/wwwroot/index.html similarity index 100% rename from spa-blazor-wasm/wwwroot/index.html rename to 2-client-side/spa-blazor-wasm/wwwroot/index.html diff --git a/spa-blazor-wasm/wwwroot/manifest.json b/2-client-side/spa-blazor-wasm/wwwroot/manifest.json similarity index 100% rename from spa-blazor-wasm/wwwroot/manifest.json rename to 2-client-side/spa-blazor-wasm/wwwroot/manifest.json diff --git a/spa-blazor-wasm/wwwroot/service-worker.js b/2-client-side/spa-blazor-wasm/wwwroot/service-worker.js similarity index 100% rename from spa-blazor-wasm/wwwroot/service-worker.js rename to 2-client-side/spa-blazor-wasm/wwwroot/service-worker.js diff --git a/spa-blazor-wasm/wwwroot/service-worker.published.js b/2-client-side/spa-blazor-wasm/wwwroot/service-worker.published.js similarity index 100% rename from spa-blazor-wasm/wwwroot/service-worker.published.js rename to 2-client-side/spa-blazor-wasm/wwwroot/service-worker.published.js diff --git a/console-cli/Program.cs b/3-desktop/console-cli/Program.cs similarity index 100% rename from console-cli/Program.cs rename to 3-desktop/console-cli/Program.cs diff --git a/console-cli/README.md b/3-desktop/console-cli/README.md similarity index 100% rename from console-cli/README.md rename to 3-desktop/console-cli/README.md diff --git a/console-cli/cli.csproj b/3-desktop/console-cli/cli.csproj similarity index 100% rename from console-cli/cli.csproj rename to 3-desktop/console-cli/cli.csproj diff --git a/console-daemon/Cli.csproj b/3-desktop/console-daemon/Cli.csproj similarity index 100% rename from console-daemon/Cli.csproj rename to 3-desktop/console-daemon/Cli.csproj diff --git a/console-daemon/Program.cs b/3-desktop/console-daemon/Program.cs similarity index 100% rename from console-daemon/Program.cs rename to 3-desktop/console-daemon/Program.cs diff --git a/console-daemon/README.md b/3-desktop/console-daemon/README.md similarity index 100% rename from console-daemon/README.md rename to 3-desktop/console-daemon/README.md diff --git a/3-desktop/console-device-code-flow/AppCreationScripts/AppCreationScripts.md b/3-desktop/console-device-code-flow/AppCreationScripts/AppCreationScripts.md new file mode 100644 index 0000000..ae8be6a --- /dev/null +++ b/3-desktop/console-device-code-flow/AppCreationScripts/AppCreationScripts.md @@ -0,0 +1,166 @@ +# Registering the sample apps with Microsoft identity platform and updating the configuration files using PowerShell scripts + +## Overview + +### Quick summary + +1. On Windows run PowerShell 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 Microsoft Entra application and configure the code of the sample application accordingly. (Other ways of running the scripts are described below) + ```PowerShell + cd .\AppCreationScripts\ + .\Configure.ps1 + ``` +1. Open the Visual Studio solution and click start + +### More details + +The following paragraphs: + +- [Present the scripts](#presentation-of-the-scripts) and explain their [usage patterns](#usage-pattern-for-tests-and-devops-scenarios) for test and DevOps scenarios. +- Explain the [pre-requisites](#pre-requisites) +- Explain [four ways of running the scripts](#four-ways-to-run-the-script): + - [Interactively](#option-1-interactive) to create the app in your home tenant + - [Passing credentials](#option-2-non-interactive) to create the app in your home tenant + - [Interactively in a specific tenant](#option-3-interactive-but-create-apps-in-a-specified-tenant) + - [Passing credentials in a specific tenant](#option-4-non-interactive-and-create-apps-in-a-specified-tenant) + - [Passing environment name, for Sovereign clouds](#running-the-script-on-azure-sovereign-clouds) + +## Goal of the scripts + +### Presentation of the scripts + +This sample comes with two PowerShell scripts, which automate the creation of the Microsoft Entra applications, and the configuration of the code for this sample. Once you run them, you will only need to build the solution and you are good to test. + +These scripts are: + +- `Configure.ps1` which: + - creates Microsoft Entra applications and their related objects (permissions, dependencies, secrets), + - changes the configuration files in the C# and JavaScript projects. + - creates a summary file named `createdApps.html` in the folder from which you ran the script, and containing, for each Microsoft Entra application it created: + - the identifier of the application + - the AppId of the application + - the url of its registration in the [Microsoft Entra admin center](https://entra.microsoft.com). + +- `Cleanup.ps1` which cleans-up the Microsoft Entra objects created by `Configure.ps1`. Note that this script does not revert the changes done in the configuration files, though. You will need to undo the change from source control (from Visual Studio, or from the command line using, for instance, git reset). + +### Usage pattern for tests and DevOps scenarios + +The `Configure.ps1` will stop if it tries to create a Microsoft Entra application which already exists in the tenant. For this, if you are using the script to try/test the sample, or in DevOps scenarios, you might want to run `Cleanup.ps1` just before `Configure.ps1`. This is what is shown in the steps below. + +## How to use the app creation scripts? + +### Pre-requisites + +1. Open PowerShell (On Windows, press `Windows-R` and type `PowerShell` in the search window) +2. Navigate to the root directory of the project. +3. Until you change it, the default [Execution Policy](https:/go.microsoft.com/fwlink/?LinkID=135170) for scripts is usually `Restricted`. In order to run the PowerShell script you need to set the Execution Policy to `RemoteSigned`. You can set this just for the current PowerShell process by running the command: + ```PowerShell + Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process + ``` +### (Optionally) install AzureAD 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: + +4. If you have never done it already, in the PowerShell window, install the AzureAD PowerShell modules. For this: + + 1. Open PowerShell as admin (On Windows, Search Powershell in the search bar, right click on it and select Run as administrator). + 2. Type: + ```PowerShell + Install-Module AzureAD + ``` + + or if you cannot be administrator on your machine, run: + ```PowerShell + Install-Module AzureAD -Scope CurrentUser + ``` + +### Run the script and start running + +5. Go to the `AppCreationScripts` sub-folder. From the folder where you cloned the repo, + ```PowerShell + cd AppCreationScripts + ``` +6. Run the scripts. See below for the [four options](#four-ways-to-run-the-script) to do that. +7. Open the Visual Studio solution, and in the solution's context menu, choose **Set Startup Projects**. +8. select **Start** for the projects + +You're done. this just works! + +### Four 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. + +Here are the details on how to do this. + +#### Option 1 (interactive) + +- Just run ``. .\Configure.ps1``, and you will be prompted to sign-in (email address, password, and if needed MFA). +- The script will be run as the signed-in user and will use the tenant in which the user is defined. + +Note that the script will choose the tenant in which to create the applications, based on the user. Also to run the `Cleanup.ps1` script, you will need to re-sign-in. + +#### Option 2 (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) + + if you want to create the apps in a particular tenant, you can use the following option: +- open the [Microsoft Entra admin center](https://entra.microsoft.com) +- Select the Microsoft Entra ID you are interested in (in the combo-box below your name on the top right of the browser window) +- Find the "Active Directory" object in this tenant +- Go to **Properties** and copy the content of the **Directory Id** property +- Then use the full syntax to run the scripts: + +```PowerShell +$tenantId = "yourTenantIdGuid" +. .\Cleanup.ps1 -TenantId $tenantId +. .\Configure.ps1 -TenantId $tenantId +``` + +#### 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`. + +The acceptable values for this parameter are: + +- AzureCloud +- AzureChinaCloud +- AzureUSGovernment +- AzureGermanyCloud + +Example: + + ```PowerShell + . .\Cleanup.ps1 -AzureEnvironmentName "AzureGermanyCloud" + . .\Configure.ps1 -AzureEnvironmentName "AzureGermanyCloud" + ``` diff --git a/3-desktop/console-device-code-flow/AppCreationScripts/Cleanup.ps1 b/3-desktop/console-device-code-flow/AppCreationScripts/Cleanup.ps1 new file mode 100644 index 0000000..a38d715 --- /dev/null +++ b/3-desktop/console-device-code-flow/AppCreationScripts/Cleanup.ps1 @@ -0,0 +1,80 @@ +[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)')] + [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" + } + + <# + .Description + This function removes the Azure AD applications for the sample. These applications were created by the Configure.ps1 script + #> + + # $tenantId is the Active Directory Tenant. This is a GUID which represents the "Directory ID" of the AzureAD tenant + # into which you want to create the apps. Look it up in the Azure portal in the "Properties" of the Azure AD. + + # 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 + } + 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 + } + $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 "Removing 'client' (Console-DeviceCodeFlow-MultiTarget-v2) if needed" + Get-AzureADApplication -Filter "DisplayName eq 'Console-DeviceCodeFlow-MultiTarget-v2'" | ForEach-Object {Remove-AzureADApplication -ObjectId $_.ObjectId } + $apps = Get-AzureADApplication -Filter "DisplayName eq 'Console-DeviceCodeFlow-MultiTarget-v2'" + if ($apps) + { + Remove-AzureADApplication -ObjectId $apps.ObjectId + } + + foreach ($app in $apps) + { + Remove-AzureADApplication -ObjectId $app.ObjectId + Write-Host "Removed Console-DeviceCodeFlow-MultiTarget-v2.." + } + # also remove service principals of this app + Get-AzureADServicePrincipal -filter "DisplayName eq 'Console-DeviceCodeFlow-MultiTarget-v2'" | ForEach-Object {Remove-AzureADServicePrincipal -ObjectId $_.Id -Confirm:$false} + +} + +Cleanup -Credential $Credential -tenantId $TenantId \ No newline at end of file diff --git a/3-desktop/console-device-code-flow/AppCreationScripts/Configure.ps1 b/3-desktop/console-device-code-flow/AppCreationScripts/Configure.ps1 new file mode 100644 index 0000000..91968f8 --- /dev/null +++ b/3-desktop/console-device-code-flow/AppCreationScripts/Configure.ps1 @@ -0,0 +1,225 @@ +[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)')] + [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 + + There are four ways to run this script. For more information, read the AppCreationScripts.md file in the same folder as this script. +#> + +# Adds the requiredAccesses (expressed as a pipe separated string) to the requiredAccess structure +# The exposed permissions are in the $exposedPermissions collection, and the type of permission (Scope | Role) is +# described in $permissionType +Function AddResourcePermission($requiredAccess, ` + $exposedPermissions, [string]$requiredAccesses, [string]$permissionType) +{ + foreach($permission in $requiredAccesses.Trim().Split("|")) + { + 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) + } + } + } +} + +# +# Example: GetRequiredPermissions "Microsoft Graph" "Graph.Read|User.Read" +# See also: http://stackoverflow.com/questions/42164581/how-to-configure-a-new-azure-ad-application-through-powershell +Function GetRequiredPermissions([string] $applicationDisplayName, [string] $requiredDelegatedPermissions, [string]$requiredApplicationPermissions, $servicePrincipal) +{ + # If we are passed the service principal we use it directly, otherwise we find it from the display name (which might not be unique) + if ($servicePrincipal) + { + $sp = $servicePrincipal + } + else + { + $sp = Get-AzureADServicePrincipal -Filter "DisplayName eq '$applicationDisplayName'" + } + $appid = $sp.AppId + $requiredAccess = New-Object Microsoft.Open.AzureAD.Model.RequiredResourceAccess + $requiredAccess.ResourceAppId = $appid + $requiredAccess.ResourceAccess = New-Object System.Collections.Generic.List[Microsoft.Open.AzureAD.Model.ResourceAccess] + + # $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" + } + + # $sp.AppRoles | Select Id,AdminConsentDisplayName,Value: To see the list of all the Application permissions for the application + if ($requiredApplicationPermissions) + { + AddResourcePermission $requiredAccess -exposedPermissions $sp.AppRoles -requiredAccesses $requiredApplicationPermissions -permissionType "Role" + } + return $requiredAccess +} + + +Function UpdateLine([string] $line, [string] $value) +{ + $index = $line.IndexOf('=') + $delimiter = ';' + if ($index -eq -1) + { + $index = $line.IndexOf(':') + $delimiter = ',' + } + if ($index -ige 0) + { + $line = $line.Substring(0, $index+1) + " "+'"'+$value+'"'+$delimiter + } + return $line +} + +Function UpdateTextFile([string] $configFilePath, [System.Collections.HashTable] $dictionary) +{ + $lines = Get-Content $configFilePath + $index = 0 + while($index -lt $lines.Length) + { + $line = $lines[$index] + foreach($key in $dictionary.Keys) + { + if ($line.Contains($key)) + { + $lines[$index] = UpdateLine $line $dictionary[$key] + } + } + $index++ + } + + Set-Content -Path $configFilePath -Value $lines -Force +} + +Set-Content -Value "
| Application | AppId | Url in the Azure portal |
|---|---|---|
| client | $currentAppId | Console-DeviceCodeFlow-MultiTarget-v2 |
YRCq!eVi$#qOJQ{eLbFq_imAdJ)}{BJnt392 zq@p3nRB1r-oTy9Imhd63QJbFUV}6p}6R&)DCqY(p $aN)8beLnhTS3_GI tO7H(*Zep|pdcbmP1}U8+`+=- znRZ$bvc(h`Ihzm+bgDscK0eW6O6@7uH<@KAXN#VG2<|xBj3B&5(GqR`LP8eh;px6z zj6k7^IBdgJx$bpJ)(lfty8?`NW3eV=6mWkVU#dj%zFiNGlZo)Q6 gQ5 %czWAoOEQ?Z1^`4r567kXPBblkMnLcWwWa#bXS zGofuju kas?76c<5nR)Li}$3Lk+P$F1KAabdwt>YSR@>`0yv93PfB;=L*3Dt=; zRW`yqwj^MX4Q_t-{i` IaOHAn4p#!Q8x8QUI?wbA*?mrP+1=4TK_B9LUqr4(7HdaQ1NeA+*v=z(Q z2{?5LG{P?{U)eZ$-lI3Nu|Oj*)lDaUq6>c~z5J-53#AHxW)pNeyna`;To;to$gD*4 zH^`(tc{#Xl0Gwo0m#!BCQ%?e+T7wcPGD&cTUcKuyy-A%9FG$|7?ZQq!GG%gw?5WAh zsR&D7vTEe{G?&g`l2Log)XLrWlG}c^|9ZqF{x=+&A8fFsmZ}PbiQ0Wq-1;&Fb#`)I zb{3-kjI79>2yy4~zhix7K5UzP2b!(X CgQU2sD@WuO=5!!kb!!j1YzApMWX%5F#BS_Si*GE$=VzdY=eCPVamJbo$Gwd^%B{ zg~$FYm+pg(s5dPe0TL`L7p7&pM`RF&It<0RhhV6n4cVyZ+?=sBFNE_5zxBo1FrkeC z-h}6{tNMDS&|4`zmqROMqoo|#M!~g6p{4Ci6+Ycf_U$>8AEa@N^M2MGf*@pj>-vk9 z==6N{jlYuRw>CaI+@gPSF)4|cpAP9Jfj+e$4)lT5Zvv{j!TRwF-Q+EWTN&-&4JTxN zh1!)qi0PPtc#bIY-&{84QE>M@BU6Srwk0(1v`!3SqZQ Qll_8`hCw%3+cyyHx3=hjM_u|1+HBw_L}9!B==-*g3S3bpolP3AoqjU0beHxiq_K$C8lS)S3t-E29Xw$V#Z3Ci(Gi5UnwxLdo>*m!7S>* zl0zGrM9tiQn%^h(?I_rETI-6ni?)l2WhwR!cZ>~EtQh#sMNVuvVe5Tzf<^39^CluG zuGY9%c#y0 wT)!!a Cpjd}7Dv?dc3vc $ zjVOzj`voE1G#ix=lVo^u{(R*kHYwbqWHHJR%_FR$ YZob!FfgLTNKmU^Pbz^@ zAO2fT%)l7+1))%+3#Xzngn*0RW2S3gVye+e%_LW-dT19pO-w^4e8CN0fY{R+C0(<< zMps9PIP=*FJa0L_ZGdII4j$aH)BUBsc>8vyFP=6t4L}sS^d7NWQ`Ytv! `rRv3D_8AvMx*dNoGW5K$@ z%l$4O*4L7~>!#E2P5f!;&yfD4&6!EZ^-(bH$oUEQ^|AV_CCaZ+$Q)c-Q28Mi6j2Zf zEu}ERyIa0_5x_&tvmX0t`8~D{nqKKc)xN$hxs)zcW|{PG&L2@CCumof=DNc3 ~8n-K&;vmCcVzB7@?k!L)((00x6x% u+UV8^hd)hYD0BgWAlSc?77v^(ig!R yAe)dS|2Civ%X{dam z`MpOyKdi0Y*f<|v%HxZOM8Yb1o&{?^^@H2Uf sf- z0K5X9`!^LxOhOr_aRO2{^LDArTai0Sx5va@s2y0&_1mYc{51#LuI=v!;*NVaQ^OBW zNaPa#lu^|5meAY4Xe~X*5c-z)+!VnIzpFENS8k~7)*uQ>cTahO5vC1rlH)DH;9#MF z64ZK9O?;w+$gz-;F(Wq{J0B*PzRT}g`3C=MZi+r8ZHMG;vt9=k$@Uz!GmSs+nv~`v z%R3@#$%!}^O4N32e3p`~8Jb#+F#Xv>=J5Tq%SLFnN{sSqgXk?$9(6QTtv?W{A@+9^ zp(z6f`TM|aX0bxz@eS{}-n| x!K%CJ?bL@@OIcsDMe{eL} zYJ@(55($}GxKoUn_val{OClFpgUpchp*`bg-_dr+GL9WEO}FaQc%aBKtqDo0PLiS_ zmPVI6NmEsQanA&nhLp@8*}AZ@`@M!7>f9Ff%VOVz!_w^msR29Ak2YZK*5vFij>~vo zOjI_aS17FVr)8u*Bg9TBXdUYw)w-*$4P=4=sI FIr6dX-v_n#{$Mm~Xo7dkPWgf^e2;$V}pQ%sks z%t~PtK3|=2H;cw
Lu)h|cVs>kRsXyy&)fL;5KzzgqxZ~QHgL#r0j;o`KX4mTwGRc4ue ziGi=LShqoZ&(p9H^Y2j0x(7nmyw*fI^MG$aS#m@(gMo6>pylhNu}l)ls$XDV(x5YP z0Pxpegx2% T=wabE2qGOClXk}&A#jeHf4cr0Xpj20Oc_zt zYBABJZbq&L#z~tGTdz=@Biw+FcoEe*tuy!jZlkmbgu4XX-?1_w$d_k5AVBRt+efq&8I%#yNw1FI>2doT@v#m*uLgtsIAcilU+T1{T2z$1eB zxQa|2U?=4&-}S*AtL@jLu*&C97+6iCVuKRHAn7X#ag9h^57f8%lr`|8)RjapkjkT7 z^-evywzxaozlH_F{B~?O&?EO&DP3LgRrtx)&AB8|!3Ow#xRm_J=AU%>7x){8BtGf< z+D!dz{LHm38~)(c0Q03ENHC*)4P_Bpd87W-w9QHLn-PZ*2?>cNjMZ;ZR}qIM>FSOh z*{d*S;GYEpqaOZxpo-}yPHnDnzEx{}Qfad3Uzo79r>gjt-S4g%x4D+!U`$=At(z__ z>MX3>o#2!0$4P?}oZdueY|Hqn5H!0Kew3MCm|pEvqRg_TV&TKOE*VxK6fU3t8yWI`KODqKpF|c1e2WQSW`}-# zGYTHaw1b%xHbNSSZ5-Dk{OevsZYG!?sW0r=g+JUe9K85%u8KWE1ey16Mky%qJ-%)) zprOKK kMp;t#?|i&ZWG-{ErV$n5sha>_=vfn+qi=-4_ #bDd|JMvb{V01?$ql+Cm(2FLtN$1agG7tJ2wl9Yld<+4QjPNq3|=Z6;9FS~aC( z9R2|jg^LHP|DP7qaM9&iz8RfSto(9AxGpOGI2wU|FO`&-G=It0->1?RL{Dzg{w}IWT~RBy{$6 z;BW5 W-u&-|Vd`wR_s?#HNPK&q-V(wfxYd?C4QkNqF}NRy-D zvX1@RPK0I4?liF;LxTVPkFSSUAr|ZZ(~@F|!v5vs|Igh1uR-5SZ>vRWmb1c@irFQs z(eAnL63K;^6Rsv-|Jg?P$3dhzfgy;uhn!}gdex4RAk3JexCb}Wu;3FHx4`xe(g;g= zunueOu5n&iN+G#JfaHsxk)PPeO)Lrp{y#p2;|4*`a2T8wGezO~C^;xm59AK1K1h2l zO1vad(vPZ# (E}FhbK2-_)Ug z6?n@gf}X^Rbm=4)BrZJ_y_b>3Oo8T#k;YXD>HW@j+0)zek09&^#)hf`n)e||1opNU z<}Li^hdy+awmeU~SmKx*)}QME+~I@zbW+*fNpV^|a;WjI{?Srj9?-)ke5x23hk}W8 z5bNBjW?^6%tdBbI`$0_gF?tkC{kLqAj^u~-C R)0J2zzQ$|5sIi>B{2G+ A<8P6Xw<%>Eaw2^>>ZWc}>gEjF6i((}Q80+qt-6Yqh(2p7ZbSTS9%UR&Xq zB2s &w{X?q|=ALHPhdI_y23}eJY$3T~4lm2|0R8 z2QQw=4?m31!blBX1>gfn#1l_^iQWN7< !>9Z4Z8NR zO0Oi+xM_S)&}A3~F_eP({It4%fJ!5%1TB`vMnDA&JbKCwcU_qqt*q7DRnywLI6i*_ z uIzVLCL;!&juXWk~co2{c+sy t_J^SH7$7wjQHW3 z@+4V62WYfxlGnA{s>a^?y{O0gk6L*_KY)0u6edqB-}7CwhPlfncs (>r1XeL$!d^3Qo>EytXvQfpj(A8`UHBRn&iP#CR;=@T `YOPl*umEJFM!Qu!o53@C!P(f~ddxctd_R}!cnmWHO5{wYGf+KB z`3s?a7LXb~Z`>3AVBdeHX@MOU9r@#BvSqmY`TS$*Z2#KRrysjfF)76~DaFOS!T>Wp zU2DBGkD1YXntgo-KHO3TgZMLrbh_p#9eum%Dz{zUyX3pJ5rb?C<)-PjDwT5C0$iC$ z;0-*gWH+BhshkYLFZ4ZQ2cng{g=
C5f9+#Vz*;0swBGVyP ziGEJqSTM{{!Vn-r32u7Q5ZBbOQT^nqr|lA8 Z7bE7;yjqNWE}~E}GFBuV4ff zJmd735BHZNfh@pM`HgwQpsgY?-Rr12*-(sH2Y|5lev7&1a04AGIW+GsdFRx)bH#UK z#A1YHalUw^tG;vL@@ZD@Oxw2x6EIcv=nF{Ixw!94%Ki4_UE4M>_vf4sq5GFPHBz~c z_$4X_H>qX}H+Okt#$Gz`?K>+dA_DkL{gu@FQbQ`f&pGNMYy|wDgUP9ZHCu6Ek`dUL zj|< vmXv3#%W9T z+lSF)KQ&pB-G;L$+JY~IW{J^0MD@BJESE84ePBd#;!Z>lR$9a|n%t9W9$ulZ-_b@$ zW$*zYi1g7WptI7m8XacBued!r=4Si+8oq>zEb|;ojrAxxh;C>$Fx76~$uffLDqWVJ zhgn69FBJTD5C0r(VHm&dN~k4AUMmAR%IOf$Ov!FGG9cmn`sfM )VIzU&Z>u!IcJKQ$Y4&@C?Bw2qJ0f{8c5A|Ws78|*5xGWr9_|1U ztkQEJir7Q%wkLFZ_RH^o@nZbun5}2|VA#FEq70rKCiGaoHDWMsVl;p7J2YTPwph5k zy@GSyg08BZH8so^(`D%N-(^{!TLTXx{Y*7j*Md3GLV(wJ(RtiFep*Wmkq&|R^Zomt z_c(S> SAJ CmXZyMVk(=ZFc{06F z#CJerNa`oNg>rqn(9jP !~I!?MX#xQq2yQTG$p825U48BzvDIh0_Le%aI=SKr3t!%mO#TW-t7 z3lUpsXL- J}mR?^M?=WEP!xTz}o=ni_dTtn%E z&*Iahu|#RO2;f*$H@@%gMRSqgJ{#fi1B!aFg54NxHA=S6j1}sI{I_!O9~h@QSbr6R zbC&Lt7cQNAKWsZ0!H~Ab_HhZPPM4SMVGgRI7aj8|&;rs`;p2xw0M@y@u07gUneFh* zx6xD>>8?n*zr1Bc&-SV8#P57jepxp%a<)t4MEhFAYim9C9*{5LMBAuuiKoAp9Pnp1 zL(rJMo@un}YUyz$1)yiS=kI0ch`Xw=WMS({gw(7qm%Zjy0ow0ZR7S;2Wm?O8zU<-@ z+(O;5J;6L>sufB!)l+jwPlRMIaM-=*ChEKhM{nKa!%p4rp@{w9kR#Hb#(SNRb&0&? zw!(9#&%Jf`ceZR$jF2U8q>XeEi_)*F=*(1M6qfFbvQppkh C zBv%>%FQ5 zPg&*a5zFTG4v`}XT68(}H !|7bFg9w~DRHcpZ5D_R4!33c6F z#c(ji lt%=eG7Qg)!w6^E8?}*hHIu#VGy1{Xr!Xk?M%WB}rA14Woj?6 z1BJUEbg!F)r>mqbHxU_1(^nLz64rlSa@b>hq}r@)U`ZhCJ9KmAw5ytl4c)ZLWWKT! zZLM>*wA~ mmOlJ} z5E`Egj5t7hZF3;`)uXv5{zr|wSlOHE-g_?-X}9pfF!*d_iTcBdy-AZ7iYgSCW)9wV zK 1GeUa^)|jl!bzXo`ib zBGguI*f7R*qZAKfrE^$`>c)hsAlguRakju)U9~TAqu)DLKVoG+ZgX-CidF *7mafzi#LSe4sCeX+-c@~v z+VmDH8j=$oEZt%L5%NkWX2jDaI2FjA4+&~jq10};${}A6|xz0 z_U|S(aKNm!>MJQsLmlr?bQ4#Vvx#dARTe%B8E z_NG*v3 zWwfc&IAl8?fSJh5rw&XZWKWEb7v`fO#{XsZ`!8>D_9^M#=`5(>V}N|Cvt~9K8_GP$ zePix10bjga9E@hCDN@(2d%F6 dswz1jpN>sNl#e?~#}#y1ZLNJ40M+s)9(VmdWd zP+i@19R_&FHP8$=tCzk~;j*|^co>^kPL19_ZQ=8BJ0 I6F1nnq3T8LnT1gQ4Y8J9jzR`je`eK=u=_*sj;ew4b-_njMB zIRi^UNIYwGD7zP2J{c&v8U}AX+QbS@f9cbp7pwQarqbX`Z5X0d^Bg|f;|z=MaOEg2 zdUHXi1afu6$F5nSaltd)Z*GU2@3ku8pDe~vsfI+o;k~e)DMj} pKg!F$bBm3w-Fe9V(EH@oA^z4m_JB7sx`1t4id1RStgxV%W z?~s?7p@C_zX;eO)NAQ7FhY;c|d$NB0BY1CJ<+c7a>u8zwtbxRDX?a)8AR(@l+0*BB zyN}J|s`aCz?G`F+7Ai>=j;H&3`}Pxm3VH#zE=WR~901{D17TpmYWg2q_>%iqsSi{t zaI;T6@oK4sx`eN*4R=39P9S`bQ$Wo^iRhW+Si>oIc}#WW2fME<9R-e;fK=o!G${o1 za_fWkrNuAI3JHnr b%)?aW^iAG_F3)8Uz!RU3D zo8E*z tQ(nK zbOw5b7cwJ?GlmAgLM1_HVxmQo`72{qo|vwFvtSz=c0f7@YYqRc*O 7n)}lbK+=tTN3u4 zDehBeo*5@!@#90Ju?E{e*eZzyp@SYvUW&^CIwUpe=-yiwwcs(jp^P<;P(!qe$&I{k ztxqc|ZD`iWA3+6x <`Q3T-?12dKh%%kV?Q!*O=0?1aND6R z^v4E&YBPw`grmub$Y}#0iL`N-BzwTF+^Kk^{R96 Cw6>}MGbIbb7~eh$tl4!Ri*#)V6%aWcgj$YC5P{Vjuj2a=$A zwCs07p;c7@?!f7tPW@o!fV!jny*Fu})_f^}{W*%-wp%}CWoRpxQZq6yG&O6x*qBhv zEaW|g_|^^_NTU_C$+C{TY}ObCitN~~&a_}R6#sSs*n^8cKDxwVIJvguY0r68%>qp= zGAvx8EF9;&n(m(64IaP_g8>I7YuB2UxxljVx>?I~0NC4D;45#gL^f^>4npiX+fuZC zLKzG|rXBZMh=zsKHP>YtHwky2c-l2LmGX 0W^3UsVw*)5@#KpA@^mQ?QXHP5}q zPb(3rpLKKS@5fV4e__m5w5~o{rg#_^Uj;b;cv(x+d4&D!T;DW$YCOGpF264uOFgv^ z{|urP3~dIDY8sS!cIK+>`?^|H$!hR9^vE-n@R*@A-?;ROsCUx{#xLSw6pA#VSlvWT z3;={7 J! zSH6zuBOIURK1%wVVYnmHt5(vim3TGXOXQAUvbMYG{VeK+ZLAi*`pvWw$5D_%q{Z>_ ztP}Uhl0Jz4woY65;yG6Rx~oRHpqAAAYMj+Hv*1s{hqoSI_a4}5SYf@_e~qK|b#1vS zc4N3cz`^6;N40Rm^yE?@NHmafgoE>VTU7_TkaN3{ 3SV9989(okz7S#wE$el=D5lkxPTq1wXI?A))X?1DkR zvU % z!-Pj+ln9-`KXOZ;=uSKlW8VMGCbG)+Ut+5!rIShx0E8!sYtCJ2$64 wv-}J%^Uc6|2!u0&~>`{-^1} zj=MUNToJvna$kGJ7#5rR;DVdt;;u$rs>xY?KK#hK2;3L)j7J<#&-^~K@@-MCJ%c@h zjYc*LJ&j{vm*$g~-Er5W>o~9Rp!bpe)62>e6K71|t+s3Pw~?}1oyFD>olDkTo+9n* zV!-Y0{GD;xL3`RlhVHCOZC+>oLWFH0B9iU}w*_{%PK@9hCfIXJ!-vGku27^@IxK@# zidkP4DZU=r y-Z%c(z6Y+DC6{AK8I!w1wO20 q2nBLE7B1GY}@)n;)8NTb}TStihaF2ztf31j$nH>0(9;(VT4q3d6_FLGQ z5Yf(cDhWd4`XE04h^7YRJW%@M;?wpgknrZPpj|c4mqplPWEYzn^bBDvcIsQu96Y|G z$HHToK4j01WG!=92m#a>su#WeplBrS8qKj~!s^jjtVdq_hWRL$*|F6vu)83J4A{=F zbSc$kp}p52JMr?|nE_mzb9#`35H%g z0`ylqBrZ#rQtHb5iRaZ>UYju%)Ss0C76>&4GcuD2)5Hl|IJ|I^b@KQ(l1HrkQYYkw zWgu>^Z8)(aKc{O6e8s2Mx4eXbj;2$cF`P!7YRB*0>TZn(JYa7a{O!?Mi)qn;L_R4{ zSKtD`r7fjo-$oC0K7P{FTp Mc{eQcj$yj>eF_ zu*tSl$KfWHbkHhD!6Kh=@72-B3&JQd#$cmdB;YD(+>S8u)`Y?|ume5?VoTy2CB{ ztDGE89}XlB&-V0RKpU+5HkL>#BnbI)-*Lu{LU0iYQ21=l>EkW0f(` %_JTeNOhB 4LX z?)UPgoUFrg2?BGO&&MUFo*eJ=3i1he9$((w#5*Z7T&c K=NHj;N>vLkTCU>5weh~;FOW- sBxJij@R!Y5Zj`u~C@DdL&T~aV@>gKU5e4aaT(%c?^@wFM{c`5^vdsgvsT-@r# zJo Y5%JDY)a^d(W>r_JfJ&|13>u=Y ze;oc1Mg2L;66-ceY<;lG?=r+SgFJZaQv`wR%=~MJjTg$$TxaG4A!`7u&A@mAjqHfm z4=pS1l@+{QrI@o^Z7ctssn~WXk*K+j3!^7`l)k|Q>@G|8kyJ8}M%vmdmHXPt%8RTg zhQ%rFqT4zx`hxXgp^&= bOGsW2ggnRC|kuZ5^SNp)zbZO;s6?!6X1m0m1zjiaEa!OJ~X z5uJ-LD+STcwxgMtB;cc^em;pbb-UzdCBs=#*?#(ajZy`9pm-e3WKrmST78pWN|lhl z`PJ-G@|~N*M7F)LOWWqdXcePjRvrpn`AE(p-om~F{VCQi%iFLWq`R{1>LT>qpCq%W z)mU1Z5qu7#Ve`|QsZy*F)rHEAo<%KZ3lt5&z4TaU0G-!NYu%O#@3_2*(XdUkgDR6= zz iS*)jZE)Ay3#tY9+#ISoXAY2+q zn42nhS54V{cS1wqpSug@W50knnJ#QLniUE>K8f3zhC}k8oXM+tUKRuLR%^XAYdrvP z;W7(#jmr{_LQ(}O?&E#2jFHN5E@MLXwT5*lLdv }# z>p)xiHVfZVV<-E^!?GOc@;c<|r0LAQ`sqP^Wg$n!$KKA85Y81r{&Xf+s(KP#FkqZB zzSNuMB#IF4=djuX>XX84*8KhwPu1}SCU;(GAmH>wr!`eIwX3Nlv D6G}8Zb z&3aB&>)DS^9Ao#YqSl!x!+ZxLyEqpOGOYe5Yufi8K-ePTu@~BQhb@k2z!Cx6Q)9t} zzy?R3NY98L^~!eqHZ@ZYL_c<3coTCfXc?%g#cI#bdIjB_e5l6i8pb(9&sb9iO71jL zIpDMSqGJaMmy0P|W#G$<>+K-LVOq2v){+*bb`^UZ@QGLn2ReO$fb56BG3NO1&kq$9 zz>W0hO2a6MjP$!Hx@D&Tq1~?Lc5q|m1*+TE;_HW6>CiQ-ciaJ!bH48n^FDo6|CV7G ze O4aNwN7&3{n&phCkX7E5TLA z# TEdmoQ#NW6-&n~GbUu!YT ztx2Bnas9+BA#TadDEXM?IjA72Or=B!uf}C4F-hL`ud ZyER;DOwH zY*4BD)>!@m)fVhXCGSazp<;6h-HIy!r{O{y332Z5JSp*#@w=%R6HpOi3rN-r-m9ZJ zqCXJJ$9OkJW*ABG%i-Zm;3HuQgLckATbT33N|^v3=wlT?{sr?7>r0 j zKr0;Hu@-x23;0(CRMDm`AMKxXv>TrbT1>MAZm^t)7zG&zddtoytAvis(uz^d_e>4K z^(uUbLr-^T9_xIr-5t96mW_E@;Y->0bmKp V-102KcI_ztRp zr8xBgUGP{3kItyc%~mG0eRb@~lwqnYlDrqpv9lHA>b;XpFW%BN{aa5x)0c2h8n2=~ z4bIG83Q^YnQ0GM?z7Kd+$(Z8P4{hnb4cTXe`uVM3-f0W@R#{Fxe0_NLyl+&|@^Yc5 zN?yK{323CNJ d=B*KU@On7_~`R4W7l9E(^o1F!w5j3|}Vg-a$KP10Ua> zxOr)fu4g?&1keD5w78*aOVc49j2J1R0rWS;ch&ZM-`j3~_7i?J3_PE^&+SaBfgMh$ z`rodjww}@MkjXKLBxzu$8U+fJ? zV#}M0njlxi2#- 9vof(xghLl~h%@4Y$VWa6%4nBu3cq&x(X=SZ{2ysf15d($~-B7oP9O zC>e4BK+7D|H|56$K$ppj8{QM+72O*s#=O6q?9D<`^SS`%g(51;j&~{IBVoZ=k;l~Hzx|)2kQJo{Kp#`QZ-pcMva!4KF=})Z|)Vco?wT17pt4hHd_-H-VgUMh;R-FSC zpVExr-0#YL+Qm c^y^v<~p!>UNF*nq7vgpOBMZP zNhZY^ZGR(&ti66*AeL7>8g_I`Y^y$rTcB-AoD5GKskqi*-KLM?^syl9-WpD(68I(c zM`Q6O_ACJ^r(&=qcBNb$JD4x|$5^6R?}t*+S5-X-tlEQz7ydW>-`i7np!We2bn_mo zO`z*j3q4+D#;%*P=M{4Pj=fLJ9~e<){er6&EZUZ2-h7~s-UF;322BAxo*tg}?{cIu zq;j|xf)DaOt{sMxV(x3MM0mm>)1#o2UPNCt8F#2HSTGfM8gsOZoUuKBZ64fHm&)Do zc<3CwI}S)rS+W4O)_HgHA4{G!K`$#W5zcrgME2VPWR4xKmPIb49+or+Z_x_^|9m(R zp __-J(}f{im#c zKb|jFiEPqp($3T)QtxkFY*B3R6TG^_dCuBA^dLM2AnXXLScpm^+mn8=Ud{g97yfZM zB_P`Rn+2wbfZEApjC4BGO8qidqb-oc7`oESj7d=rU5cv0WG-v<&|U_1 TArbk#Jc{u@vcA9|M4S(8AJ|9um*jWbq9e?sc0$`~!o6u$Av2`a zQ ?4?=oeC Bz;Xx)w`lyyYW=2UqtYO8MVOc2_PBg`h zK6^RkkB`TCx%wG*{rk~SD}$x^jvRs`Pujuj_oi>>!>(QuL?0F;5vWJ;K0X>cH~4GH z;DUlw4ePcF$T2|x^%E}R&@Ih;(<7&;Y7e=*e0#3=nrXVhPSB&J%vA@O{CPP&GSa2= zoHR3Iw1KuE*AvZ<`o`OxT?tHB+dGK~$mhP2l!aLddOnYCYft5QUMgTr(Yt7#=;$a} ze=Yk|7E^bNrIxX?P)W}s^|+WkSxCFWcF_JJApU>r(B-CF(qG_%VLv$C@ad)?9A^mp zb%48F5w$TjYzWyd8m{?b)aZ1nR&Z0DIi2I+7?F8F(&l>zjgFpI0}Sxevp?y8g;{$( zUVlNs)_EZ{RG_{O^)^H@aR~! e6{dO>}z><7GhP|N22hf_oA-rAuZK?4(R IulG~(*t;?5>=#1R%y`R&zJ+UwK}S)5BakltR>J2j zJ$SD-eeR+$`>be|w)ye4Bqf*CULbwNnZDdb)Bn&9flQTR$d9_~l|e)*U|U{&v^pRhsK8k70^=Vn#i70x}&}lTY|NOODU%lk9h< zrfQo@2eQK1_silE915y$S|DYQOPLog*Zh;j`@l~OR-yM?T- D3RU?9U=5y1f+M6-jg@p z_kTZo?=SCj98bRGNHUpgU27(jnRWh7jr-!C^ng4e(`_Qejx*rI3Hse~t*vhLj>|<` z@>&5w%fW}TQthJU(E}vu0;VSoHz86#AS5d1U|L({Br-8=rq4nM!dRQ*ovsk0k!KdK zd42~ZLuXY#-X%C@?YY0-;+4NZ >X Nv+of-LX4m&qQSo*Q4jB%l1cu~*R{ryvkf9zFe*DWHumO+G!kdd-N$ z|7NR1)qqLy`bu6@r& a3bw?Hww{<34ZkDt|>`S662CW I^gX67@UG7@Y0K4S%@t&4I)|{+CFpd1^lyr#nw JJ6cMX~vhHK~0Sk-Ag8)5AB@!<*`0ZGDichlWpfc}*p(p$%4*Ti#Y) zYNF#0hY#|J9aR(xYS6elDD6jcY+ZbJmYUV^-@9wEMNm1W8CC6jy78FIg0&Unmu&ZG z7E?*ShY1_cf_}YIWIB2;7n3C*of*^U3r6t>0oh!&VGk2MpdzN2_BoW~K{RI%M3shi zlj)Ye#{njAht6^A%#vYCT@*F$wO)6$4vyMzNI%n-TSF;Lp2_=#g9>%}^RVq11sV%- zINK?X Cjm)rm9Hl+Az~4>ALR^6zoZy-_Df4|b4@5Ka@jgbAou4Y zfD|FWgE~uq@bzzx(>luybv?3P8P*=l_{-8SHp^jk--@h^4v9A;rFFja#TSicJJa(C z4sF|lVgI`V5H=qHwW4I#t-{_?6$UUGyL_VRhf|$BW1%%L7Z3^NorF^{?g2^BxvG-$ zT<+r^%%JA|s@}*qg5f>(6emUr1EQp=3&UjY%(~|$!=)-*WkW~D;x&+;d}5au5UOnP z74c>EtkN}}+TtT!pSJqa*{X*2svj5F=?j}j%8e=d2Zbyqfuvq?)uYGhTLTm=$(Dr- z#7232IcBf0m+drWj8W1np;vnJZGq#3=7AtLXcgY{%Q1%Of^`4Ak!L(UQt960r&%Vc ztwyKz*eX6r`)#fbKg@ho&KH!Ye4Krr(G?r`RC?*F3{~LG5$r;8RpN8L@;>;bB+z_y zDj&^32$8ywUJwSVpw<@pX$9KSUbxXoiBPc1)!#7FLzDz8TR1NxcY}tumNd$xZN**R zxfnLs#+%Fk;gFR2SPI>G(qsis{lr^K^#p<)GJYrVgH!xa|3l0Sr@G0ujkB3>4{`<{ zeRgIob4P94iLJc_`f{^5D(+2{7@+2{ jCJ%><*Ds07N? z?u@IV^!_`i$BV$m2@d_so3spPb7io5LcWns^P;al9KOiY_I=zRF^E^sGn|rXx*WH7 zA!B|T89sfmu}fH|zbxK-g&G{zu-(9$w?B0U0b8V4;qs^x8FiOs*mP#`p&|pGloQ_w zZqR=I5&=8+#<$#pMM1D10FU)JBGyWof+)|KMm*$w+Gf-D(z2!HHagJQ8UsqDbE)7) zpJy7@Y>e97s8iE#n$F@}_RY1MNX;X)w7;zayF+vin+!}7ZT#Ib-D6QYP6+-Z2=~1A z=9FxI-vr05xJ+e2cJ+a=N@TPEmy%?7R(zQXE%XB %z2?~Nc#G42&%D_tGJ zgO`E&a*xM~;RDC<45GD35uuVZ{6-@!H7J$RSgP;j9be{s{?L{P(?^7O-M7e07|LYz zw!sPh*&110-mj2ll$@Hly7DOIunjNa>3-WiUv0r)G|H}4xEWVhT6|V!VUtQc-HL@i z*>+`^U5jI;+I-tZmqVit-jzSIK3Bd6uo?pkG|8^mW?uQb422k3(V=#Gs{$6Z&PR;w zj+Qm=Vd+rG=Dfj^^x)+qXvg`RiWVcCb0y7NZAX(OZ@&5^CN3}5mG^prwTzK;x@W7< zHc+m*g@b&+*XGYZoVvy`{7TejgV{P8{DBv28E*;0^OJPXul @J_E zaSb2RmCP{d8-!q~mnTm>VHL!2Z4!4^KBOqFYn5cot?@btNB@8s13xji=mXT;VAP @&>{6QdJjk8;6eG>#|-DyFV)9bk1PD zeJOv=q*65I`1S0#w@4*@WOEQ0AX)!Vz4rw!D 5Eh!B@imxJl?-B;m z`Mpekl)FV86ZdtEM LBb!C>n5Sa3m2c~tJXytPfi3%Y zld&b?t)W$g*i}vPW;@br|0z6Fye~hr*{V!zYE3py-HH89m7fc(|CsJcxj7lnk1hW8 zP-+S&MGqP~erLQyzoZVVkvjckWeHKO=gw5Pdl95p&o25#b6b0Ah#~?s>qq>$j{S_0 zeP$E5CZF21^AKLRe8f4MI2FiOS=4=NL+8CD9X;8iNaB@sbER_jfk@eT%w>;x^0&F> zUN$gdIU8Uhz#8cvv65@OJIQDp`<@QtZ|cq*fj%u46*Xr=8m!j4>&pl=cZ T~wI_3bH6)da*@OD_V)8$;^85 zp;Du8Jy9flo|;UGxy8!yysev?ZK >tEMSc$Ik6D2}b_UdS6z@eedR-?@1x3<3#TN7K zx+}_tY@>_I+i~+gXNFSJmr8$zdZqCbw-j#M}k6!U*RR;5JOdDXd=|HBAb zT~>^7d-2$zN_&=1rX|l}onM1Mjp@SileQx#dU@ON`)U2Amg5IJ!W%u7>rNSr@QMVt z>(!Iz4`1xd2*=3TM2W^6N4HenxvoW0EO^(nk&>A@yXzJ$RjSK7O+*X1tqrTDtFL$1 z8%^wPIW+!2Z)2 dB4Wi*dInJ4KP6^z^sLF1;*8hi6N^4z{TtZ5kI3R zv|X+%M~8~-B@Dk_O50UvH@`vZ$j?M*%M-%2fBabt!g!@-Z}JuV%2RPP@}og=-}PJY zli#%+FI(PO Chy5n@1x9>NoW58J;W=_Rs7`dBjoGNr;I@-W zpGgDECF|L1z$&eU&a#Ibhd%B`!E98@c3*LV5A5q+DD~QQD-trD=V4K+TMaLgB`=I& zV^8pJwYc{j$^Ae}mlaX8#ux_rw-+-we{m@+NHvE)op8cKLi<+QEO(DNo2~4p1)7Ti zkz7%-{FFZ_d?+cNf8+cZ5kP#Tl~;r#aaG7|CJ>q;s`*?!Y3I5x&%{Txs!F)g9D%Jn zThqz$;?alUqdv>VRr#E!62_c6DYw0i>cHGreNKbT4f?SxBXho+u1=*(G;f)>enQ3f zA5*`m0=n>SnLczID@1~!^LgyC`wc0x>d|jWwsgHpu{D284~+IBtOo%4-Q;%;`qzUV zs_umXI!3MYwhto6F~db)|0(#?53{it%aQNMJrVMy{YYDT`F@X|bzJP+Q+jJq4YyU& zj_fcgaZvI&)`vYiy0i*hPGrk9JjtS=RapKb8d2f0CDf$NQKk>|UOQ!1x1QP*j!Zni z7_M_SbOUqEv~Z5z!Pzd24fpnirLGuSANAPbi{~kgc;(TmqNw44;6U`r2Rf3N)#|RY zL0V%gCR$+aqmtY@X2T`n-kM#Zt(RXU}Z2uvGvYKO}8ah3@c^FGL2F`vnwa9ldhu zOt17uH*a(k37zLbzl?g;Zb0#i&;{ApwaLSe{T19m 7;H7!XkY)J3U=Y;)(*b98baAI=71=W|~SN&3DCzX{5=h_R#OA(OFg`Of=l*POBjU zZS`vvoby>VSBv`|2?Kk#Kh$n6$TrzC*iPf qIUZ~ zn$cXx1^Iia*Qb0kSZkkVi7I$N{^+@qfM80J0KPdc^0Gh|utk@{Kx|nO)Q4%$^mt>% zZW(MHkxciha8~P>Nu;P(GZ0;+(p*5N&IxQn{#nAi#-aKaCQGOM-m9Jsms)+YLVV%6 zOZZf(g<-CW?I6i=gFbcf?m!=0pKJtD1z&Y7B&uE}(<%*e9`5f1%4@dhi8W~Cg!Rh8 z1a@AYw}sf*veQrz1@f@lS?sWp6$QxK=h4aaKJw+#?8AQOba*MOw|L{Z#1(6)mTtml z4_va3 jVwDecaHY`s?B_Rq1~{VtMx(IUH&DPR<=!o^$6m)W53^ggWu1Fi5y#}yAv zn~S}yk;W%F{&KsJt@eXO*i$jZouW`Y;pV1AHBvD}kGYjdONPN-B#XF;xlT)~mGxs2 z8lO-da9&{4Fv6iU*%3(61NwxgmiFZV@iP{trz{7#$p8`t>r|Rw*)!|jA3$CdwJ3Jz z^1(MEy7*jv>iyU ^$|6N4m9L*xK6HQKO`JA}nzXrW_5U+IK16TKW*^+)cO~{m zR&4-0M>}CvxFk@0R`&)oDe*d~u#rA1(Q9F_JN;Rfm#K!dG`(AR@%ful+L*iDn0W#t zFAIG`HLx{IR?KTOQ9_Vy0{?BI=(J`v>^RPg4y1`EwPIzH66E7uy8UezxtbKq+3dSF zQ3`zBq*m`P%y3F1Jpd=u 6wlwY4r9Zrn#zB%v>mUxh< z4Y4|qWNcGXi99me({k|H-v_}|P=`sIu-2tNLo+9BjVE^lT|Kn3JhKUp-l;)oBl `ZraVKZ-+CR1YzVv-L{M`@vq4(=U6!;?;-B=h}a*R zno5?BLdp-JlGop8$)o9-93dw{*}E6$(vb3zIb&Dxa+AVvgt0?0E`3*ntFQ(&W~iWi zk6J8LM;o!5Tp@LHf;_7N5(*iupZV>Ca3sAk1Ob $ zyqN121xq~{sEI5oKg`&TDF|w+i4R?E8kUTuAD&3Sdj4LOsWTr+*p_PMbv5YWQP-l^ zCE;4NmcGCd;8k!qXTF^9X4OQ)5{W?U3>9_07j1hg*gx9-B+V&hGb-QIXwN#7KNxY@ zTHBb^SM8Xlf7+)#jqS1S2e!ZX5+(+(E!mk~rt#W*hnH!WV=HRtNn8%bNHRoI5no#z zf@s4)PjL4f4AO#*VT+~sb#cU%xRbx|_-`;{b4DI1zs|H$H`Y%GH3P|2x(a8%P-{Xg z50sv|vnF1iX&NBJ ETty?w5gv)3UI?sTydrp ^^9F1(QBp z(e0!&FfwFf=H))ZK7g?rSts8w%*A%IlvI@6I&lKOz4gBaj-VD6&dU9MaYfD_Wn|Ut zm_N^(cZV4-^$9kFh(h4gD~|4`T-*VE+4V&WCNl>m+xtBB)#QSgo5HTvy7iD`VMvk? z3x%*TXR%bgt`A%F#eLK+#*S_nAM|*2aq Ds())pPlJ?EoQd-o=)q*E|B`Enrs9a zYB4tiSfpzHY3?e=8`eWDP`{Ltnmta$FHdT;ysQ}H{?y)pF0}7-VWgRH_^cH EICo)@#>oiS7q0?LDSX4#h=$s@^bOgZbu&=I`qD@%D2BBAudeNBC1 zJI^TvUxugMP%oiNJcvr$>Bpr5JQW9%43wjzF49?XN7iT{pt0l((#!#GE?*m-o2nmT zNA z?`d)<3dloiE^S+a{~L4(&618G$Q?( z9tsiD7T_m=8g5KRo-{^`@buqyk}7Ltx!!F+*JGs;TMuPUZ=Gx%Taxbvecm80$R*mU z|BSU_o)RR(M0Ia^H}WJ(UiP^_NmQvK_vWExS=k@K&9>?t)*zny9b{3MJ2}!@qYGZ{ z=zsEV3+_-}Teg4yCu8tlo^~BH_J?Pv6OBHgMB^_0>Jzc}eNouqO;=ivx2CKt*ucBo zjytbxD+`nAvPVi{RZCRZ&`YJ|B%NPguVEXm-X^|4Fd&4hyrH%QF<%5#ZXIV@a1mme z7Pxu|n+|O@)flh4^3_p@qxGMP P3v%bdD)EG zTWkWg>EA~_hFf~wESC+jO?m&$W&5C@v%GU$Gn-k+H9Z+oXOWs{#6#ZZ#E5FtZgg21 zGWN{dK%Pqok2IWgVN8u|TuM0QT(psgNG(pC%BUaFYq$ZP3Hy8M?H&$_LgOExv@XS) zUj6(Zam82(6+B|Vz~Ff-e~zO98Jci7tpP|J5J+jk6hCge8~HiI^lf&}>*n4-a_UM3 z+IA~Y^I6v+8&e)b(7Us|{Qz%Ci{tBQeZErbqm~E4E6(#wH_T($TQ`ix-juvhMUOr# z61Bl%R%4HewasGL^o%JR)c&{(qI2`sy$*F)b9xx^oZckm&sE{!t%r``=H{ wo{|y^HNR%Z1XE>@|Yj zsy0e8VkNZyR8l}uch@%>WhD)Jb4|7g`w9Pq``$)(=O(#{l$8R;QCn5KE5Y(T+_xnn z8)p%_Yez!AkOrLrG&|lR6_<_cOJQ}1TxxFWQgbI0m(319E&q|SE7fR%6P`tq0xL>1 zk7@hgx=#L-(&zx$yTWt3oY|NUSo|GHB29vDMw`Mu)d;|8xeQ^>XMxE~!+Vf%k{crL zDPr}65cU&(8j_Koybj3Xg!`CXjIoR9tuqg6XaLuA3K1nYGzO0?ca0bve+S%H6Un ~g$&p?~TlaoK9
#fKGDQY8WPwf6G54$dl3T0lT%c)C{+{W-%U>_Lcge z%nu92^b?m)3 Z^d#hGvFPlp}qb{!#UG_tGlqlk yu=^5By-F?=oFYW;vKJx%?Wt8472A=t3iGx$MKX^3_^VPSX7|hdZ6ro1i(9-U7 zy+idVMA=6Va3y3l>`DYTw_2u)
cexX@GSjLAL2 zXXv_5b|-Ef&dQQYeOMpdXv*V97HTMF944NCOh#zI&s+xrK61|*&3 l|4p!UTs{hBuRoQ{qZ_aq&XjGOb=;17>6cC&K(&QDi45@&cfIq8 zBpIK-2WGtepiW-mf>R;wxvSNAll@u&&HDVy(3lBa0jV+1lfM@432)d}h+}CtYpvSN z^eX7*Yi_Tq`NaqSo%PZ%mTv#*qRAXFNQQ_vN1VjRa;YoXUFPuJN6h!*mJ4|}nDq6m zh9(%kT+lwrlG5dM)EFieJFz-s2h>PirZS~c^N{V2Kx281*lqWV59;bY$-`6@-6q(* zlX?>Gmusg$o^5wyOqLM4{jcJ!& &=puzPbVlmnO!xu{qTh5uLqU#c3Czz{`o6 zW>?{{kui%Hvfb!Xx0N^>79b&h=I2Ic`XHC?ipiT?sPzdo@^XX8R&a41xARE5z%Dt? z>^w=-EB%=RM|`{OoS7kAP+<-=gt>B=waK&R%Ym&uqX?@hhNK!2r@a;G{Uc|O)p66$ zTRC*&5| 3eGv}HTP>5Eg0 za #df5> zO^mpoj~21frxqHrMHVVg66G=x^ gznLbp?R09M!nM<=eZk?L!UN;k!~hj-74TzVoE(nU4E~ZexgftZ&tD ztuTD+o@6hPyG?ZuysvlXP@ArQYjeXShnTbpY#o{Z-(j;Sp{5diTCIHclQvO%-QVzj zDn<*jW(e{syn*;oOV!u?xm9e2H`OASl280^9kw!0p+{-SwKrd&8BI%_1lENn+ZR7a z@t+p=l{|2IL7>EWHu^4p@ PGM`-bA>rj$n=J7iJN)Xqk`S-Yqt+NzZ3PT(Qt*830H)Oa?7RBdS| z<2zL-zdh&7q9cFlF&2l<0Ai7Z4dVXJx&|yF+bTB#|AJ5pHtjqYIUmS@uhqufuOj}r z^R3e~?sefJ9aom5+CrTgh>k0B(uMI)usWyBQEr$WkwBTz`YVT`EPsNZGceCTg*G^} zn1e5<13D=GOQuWw_1vcHwHL;VlL-bcHdWo3OxXR;!GbqorP(nY_vwYlBi%D72hfTK zP<<)u{YClA6G?t_0$`IVW|8OOeAD-${5q3;9a^9F!t>Rz+@12;u8lg*0g~QLKEGYd zN%d>s)cOTd%0WcyC 2<2sZ!tW)Lzu6!Nz(#GK_C6 z5}Y{+W#Hg*_9kw%`^GPEg}uTXt_SA&^mX^{GV v&iWDdN1@%vCHZG|wiwSp*li z>UUVxOZx}aa>9oUlI5kCnYcQoio32HdccDVsDytH%kPk=dQZ(MQw}b$`)tb#*3ojw zhs!~AK`^Dw {JwHtd{ zG|dCX%YN0rzj*IK5$AA`_b!c7=dEgq@HuU@a=5s}D*kxhYe#{7{F!@yo_7jkf--j5 z1I@3L>9p7do#MWdP2pRwC93ICII4@K%m?S))FA7KV%WbnbvV8FtrKGP1!5E&Cw!)| z`0B>%l_c!2Q6f2ODf7pkxw0<3#97`L4;}Z8u~XBL@ajgT8kEITx_FVe%g6&BkGH_ndFF~gErxBs`ebp){ z@vr 2W_Pnzz*VTdeQCMP*O8BN&7=LTat~6y- z5TjwM2CwhS665p ne_{1#h~Ut133 d z^(H^VC_H!bHWTFQnXhYuY wy?b;Id3l*FA~y#!{B75aX-)ItecUytEiK1MM{xni`wLv19`ISMUEsQw};|q z683mJZUX9$$2Zi&2;~|4$s|5Kv%@BQks>$9!6>J|IQo22;l4hukM&qmGs%}kKHi(Z ztHkPvHA~#ui?fRlzFX8ISkKLl);?8QDu1z5-)QCeJ{?E?>&XmfxKLPG6I i2!KD6$iLVZedX8z-Qv)C7nj2_`>RKJ}>BN?uX z4ZAfoj5}G1`7;y~O{zL=^XPjV Jc`sPX;!iFc0P)uTrTe{gy-hoQi1U9Iw#H0@t!tKWhe7sj&|6R!LL zmdf=LfdJcRN}N9;!L4j+Kb%IRp&6x4$f@0@yGvqHeSAE9RSkhao>xs^uQ70Vra?#o zF^3nt#7CJvhl^WF=Fo}N~JCW0rSh?)x$JJzE9*W?g=U3!0dO|NmO7R}@4)+xe+ za%BI~G>EPqd6#h+x!3HNnRR~BNRSqwR`G3;F1<{qBPdw(Nf76_(2DT)uz*^ Dw(bHEj;zS_>QUqBcr{&tHL)v<_svkNzG+{YU9YP=5c7 zg~_9YmyqYwH5p&?c~6{3_wC~iQ}g?%TKckBM1|XJ351f6W86(jk6-BB<#yCGZuh55 z$yb$m7JH4*o`rG!qoKuY jw}7V{6Pj=jyFK8YC0_Ha7R<|k=(?jUl71hO{>6=Teos>v+=U= zDWYZf=x`^~rNKd0W(GqHOfNCjB;IjBe{^9;r+nMrbf=d+KfdEoe_ifhi(tCA*`TAc z;+pfTTI{<0*&PR4dgg?0O1NX|sSwZl^na*dFlr^C0>CKlEz6kvhjn%`t*4FrZnq~* zB&A|j4voBy9(L*!LrpmY4v$^Y(%K^7$(wMJvusa1`WMaxS%zOV1^0t8G?y Bp_wI-!-7V1s`qEA<;$~^XFTcbZIy-R`6D{ZjnI>>NEb =&T8r>0Th>*nTdmF+Dw<8z{NSvZ(9IG$Bdh5XKEq@t`Z12nPI)Qw%( z(>L{Y&>5-{e(DSMV+B$FH)$?kT8l{IWHRsp#XS3#ZlXuEPn&?)v23-L6d&s~id%hF zcYI}(ib#&mjE$!sM_S^A+ce)OLYgQ-iL3)U&7z9m`lvs0)g~Ky@yE_7(!$Yv?$;&B z7Tvo5$;QJ{M_s_C&eEyxUY}l~-|F0nqk}!NbS7O21=tb>mfl@WOeMY9Kyc4D8E5_4 zO}Z0O^n%sT_X>(^q)FxuvrHN^Lb*MxvsI4>AzlHzN zs=u$xnE3D GSm=3zh+EouwC}%CHsjnHz)Sd!N zn7KugIY&MTgPD`js+o@L!Oy^GZ7bS8;UD=s8QVODcguU&AcsT8ayb+}pJJa1G&Mx4 zzyX)XJ+|R`yAN}(e1Gl~dd)NHQoT{wqZ(svWx${s!UPzV%Lp&mq~Ach@ghdl>c@1( zLVwnjqB8e4Ves$Qxs7wEA9aVSJl_M{jE=0chFdJ0HfdE);K$A@)>$yL DI5_j7RZ`c_*JErbmf0w&4zT%Qx%o<`f;<@|F#U9% z-1ceEgWU0aR;G5Qv?2$SuTV^HIo?Ib_|~fZq8JSSa@9(TjUh3hpuNJpHPE5e(WNhd z#`*rVE(Z3o9(8ZEH#4p4XQx(()=Aa#*>fw~)m|+4`o=EIY@A&*`Ysaa!@3rx?W;vw z+_5E-u@0oZKAR{tw}KqCQB-lpb{lPO8YR^L^Z;Cu=?-aQ=GT6kvD4PIqXPKFW%SG4 zs?h@uX>3^lY8wa7eU*7u99W6ZvEae16Pl6yUq1wFxhs#Wlq8zTriMxz7m+(+E+{Lf zJHqT{XJ$yghNeUTbFBM}s-}$r&tiwL9sw42L5E2YD7~N(q_h13n4?Um8(Sb+96%0< z@RKwYUHa*_Te6>?B)nKXhV0QVZM#xA-x8jeyw$qT)Yy=1TlRTX*rVzP|M~iBW3(Bu zNL;OYwJXIiOp5}i3!dAKd?bOpW8C~FAAgSC|0K`Stk6<@swVYKc52q~=y20JLUqiR z0VilI3j=BK!(VEFJeko9CcEu#7rARD;xB6R2+&1d1pofw%@5>;<;vUX=2Th}CBGX9 zOCBg+5`s;;MOjJYI2rfWG|q=K`ipUL&SS8ZBv%NnKMVIZ8smMU?5-)rm&|_I{BkZA zny%f9^mPcbbl42bZaT>gNllX9s2>{nA)e(lvYV%Re&(to-42+{ewQOjG)bYB4#`xf zoLv6MupSaVc+4|Q3_O7tk@$VBL6fm^J1Zco&`laP-&0pj=hj+z-Ex7#5ZT0=IKth+ z39RT?oL{p{4^<~?DOpLWuC366@qd6AXua#TixYc;zB%pC@3M!kQFjzRLynO>B{{b! z{G4#}Zglm}9|6e2PK$`|wO7Q{3>32YlFErY;d?;2c^tlP!+IC@b{;#{+5PZ?k~|~* z>42TYlO1f1DxWu6cy(-F)7opLodL}co`eC-=%AJT@Lmr5`IO+|XPW#P)H4@P-IOPQ z54w8 A(A&q3NS&X2$<7X8C_`Z^`~QL3g>N z{kkhLDG{IAC%T>mjo{V;5KMF}xYcAFY(;wrr!}o(;qCGVJ$brLqf`X@wD^g78JeMK z))H>@4?TFf 9pzmKSfP7x=E3O^ z!ytSOjnvY4fV{t0xo`~YO~mo1wxWq)M-fc&Rt4-B^R L)xBIZRkKxxls4&|>HUW4+f)3hIND5W=lljQ+iqG+-h1q*Z^ zVG?8oKDzzzQ_&muOdG{!XEOK?MOq#6X{k&@ZqiscMF%`B9qZ&0AWU#|x!`Cx^o$=9 znpS;QFWph5D{R$0D9RKb@TE=0Kn84({7dpT*gg^iq<8E7#X)dN4IyOeb 7_p+L@_c@WV94a(cK(HC}(R!}eBh_vBPwOJ@tZ2Q(L{VvZo9&&ysX|TJ zlY*(qjJ3g0da0#;eZ_x0yZ&D8Q@|9_XwFwOXnEEZBjqVU=Xx$)0MnNu)1R-M1B(Vt znUVNl+0zI{L1vr&&qdfwhaHY~MC;4H0ce{qR16_{G4U_~EYQeI_+*c2b$R6%nH5(& zXQJ2C;Ms*8a>|m5tR4$SSrl4SUt}(OFJ^!?G>}dS=%YXn+s|`?H-bK+3qO!kY7}uf zCHEeqY5@NPHZ|um8~UFLc;|dfR@1o0M>$$w#=cWI^~6zO&1o;>^}~y(zibXX)s}JX z_)mQQ8gz_H*UDe; b5jlFjQVcKs+3PA7}jr*v%~jZ{k^P<4L&-; z&PsQCRGikIWC!72&`4b#w8o|+d~>;jUybuWPIW~rXofJldI6mimhaTiE-sJI10HeuEq7c9L*=KibM#{wq0x|T8DctCBOI6=q9SLlJ< z_Lo^q`m-mJ0zci3(ca)R?fBYvw4ySoF5 *X`krjg7L+$vr(im`&fKGtkbAX5P?;KWWpc=fR#j|K6OZy`Ep*3rk2W{#hk5 zRc2cL*#PyDZ6^+VLdg+J@}H(C_3gmmu%lVA6CvZ^{>@<$CTzyKDLX-x=lK6j06bq_ z`!nbXk`)KCH8eKPIn-0r$A*HFV8bh2VVckL%ZR)F6Nk0nzO}$}*Za&jE}Pyr?8XpZ zjHo(-|7wFyDV}V5!N=ZXb}*$G7erXxUpya_`ZuFNSQg?o4h}*Y!Z*eIk6naU_O?zo z5KKp89skv^v}teX-rW~Dn&=!|9=nfke6K!vdwa{ucJWre`A_Vkumicx3kwT-^T2ue z`LaCLcOvfll oQ%rK&!k&zj1 zu~{iFe-tuORt`ryL;f`y#3E|nRS@$!S;v8N+B!JU`4<=)3};Kxr+mWBl4I PuVp(KJJX4Z=RQ$kwF8S0snQM#3`M!yZZQn@zYPGM&d_^utYKQ zS %gTrCGy?08~c3#t;+Y;W-jj+?1nk(CNfX zI1cSd5g|%VJIZ~@${MRE2JKtJJ^skxEg1XoIhS|+n-iYx-CZaYIu7FRjZl8hu0D|P zgh}B!RWPu{^R=)rg*!DzXC43d 9 za#6if@&K-0YAg$xV|=meBaz$%QsdJy2@!kKb7|B-)vwV}w9)48Pa;wBQQ%IiYBOQ= zss#te$*C#njyyK1qvuh$8={V1qm%fphqo76v%-CT+@KlfL?aaB }gP_#i%?n};vgf%f#oIdy6?8zPRfX?LhkMn960c1P@}NgrVx3~sBn$1{iAy9Vb3 zzeizxYF@+%evWQoXx2{~!-fLcbIroUguzOO?l9%dipAG5S!U{#4 _or@> zJhE^pv~8m)FAM+7oY d_aj zf1WdM^?DG|g+@~FU~PW?%af-}pt*7=%lhG!nIY~qzIIGGg|>R+rPO|yJ>tQHjTXO? z;|%WP|7D)@7CpuhM^9%T8~%hQq@{_vrjVd{Jsl}BuCA`XezOuv-z*Ym#f|*)PMRN| z(B7!t-Z!2#czr!R9gR4irBG;ScEo4&Y=rJL7J3+?KZ-WIdj1s4!u+3(M1}vgq%eIa z%^oY^Q#S4?VfJ^rj4Dywcx|4CIrwk8qmG403z>fcqK)6xBK@eY$iYkKD_4o$K;Aw7 zXTkFnq@Ita7iXM?5gD6l0nqxNi;4Q|!KBds@PJ@#nak)My>wfV2P0TM_@A%idN+;F zVcIbHoiRROs7;qc`->m-PvO6Is#q2(#OuFu9| ByzEUJK7pN}%pjG4&(D)@!OgP&T%mT@`}?#4 z>fW|?0d (_sy^0c=bJ!_cqQj-3q*rPv(-fsAReDN{#2K7)WFYLW!{4@^QjQD}F Myt-V4jA_vS2Z@5O@&Et; literal 0 HcmV?d00001 diff --git a/3-desktop/console-html-browser/AppCreationScripts/AppCreationScripts.md b/3-desktop/console-html-browser/AppCreationScripts/AppCreationScripts.md new file mode 100644 index 0000000..ae8be6a --- /dev/null +++ b/3-desktop/console-html-browser/AppCreationScripts/AppCreationScripts.md @@ -0,0 +1,166 @@ +# Registering the sample apps with Microsoft identity platform and updating the configuration files using PowerShell scripts + +## Overview + +### Quick summary + +1. On Windows run PowerShell 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 Microsoft Entra application and configure the code of the sample application accordingly. (Other ways of running the scripts are described below) + ```PowerShell + cd .\AppCreationScripts\ + .\Configure.ps1 + ``` +1. Open the Visual Studio solution and click start + +### More details + +The following paragraphs: + +- [Present the scripts](#presentation-of-the-scripts) and explain their [usage patterns](#usage-pattern-for-tests-and-devops-scenarios) for test and DevOps scenarios. +- Explain the [pre-requisites](#pre-requisites) +- Explain [four ways of running the scripts](#four-ways-to-run-the-script): + - [Interactively](#option-1-interactive) to create the app in your home tenant + - [Passing credentials](#option-2-non-interactive) to create the app in your home tenant + - [Interactively in a specific tenant](#option-3-interactive-but-create-apps-in-a-specified-tenant) + - [Passing credentials in a specific tenant](#option-4-non-interactive-and-create-apps-in-a-specified-tenant) + - [Passing environment name, for Sovereign clouds](#running-the-script-on-azure-sovereign-clouds) + +## Goal of the scripts + +### Presentation of the scripts + +This sample comes with two PowerShell scripts, which automate the creation of the Microsoft Entra applications, and the configuration of the code for this sample. Once you run them, you will only need to build the solution and you are good to test. + +These scripts are: + +- `Configure.ps1` which: + - creates Microsoft Entra applications and their related objects (permissions, dependencies, secrets), + - changes the configuration files in the C# and JavaScript projects. + - creates a summary file named `createdApps.html` in the folder from which you ran the script, and containing, for each Microsoft Entra application it created: + - the identifier of the application + - the AppId of the application + - the url of its registration in the [Microsoft Entra admin center](https://entra.microsoft.com). + +- `Cleanup.ps1` which cleans-up the Microsoft Entra objects created by `Configure.ps1`. Note that this script does not revert the changes done in the configuration files, though. You will need to undo the change from source control (from Visual Studio, or from the command line using, for instance, git reset). + +### Usage pattern for tests and DevOps scenarios + +The `Configure.ps1` will stop if it tries to create a Microsoft Entra application which already exists in the tenant. For this, if you are using the script to try/test the sample, or in DevOps scenarios, you might want to run `Cleanup.ps1` just before `Configure.ps1`. This is what is shown in the steps below. + +## How to use the app creation scripts? + +### Pre-requisites + +1. Open PowerShell (On Windows, press `Windows-R` and type `PowerShell` in the search window) +2. Navigate to the root directory of the project. +3. Until you change it, the default [Execution Policy](https:/go.microsoft.com/fwlink/?LinkID=135170) for scripts is usually `Restricted`. In order to run the PowerShell script you need to set the Execution Policy to `RemoteSigned`. You can set this just for the current PowerShell process by running the command: + ```PowerShell + Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process + ``` +### (Optionally) install AzureAD 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: + +4. If you have never done it already, in the PowerShell window, install the AzureAD PowerShell modules. For this: + + 1. Open PowerShell as admin (On Windows, Search Powershell in the search bar, right click on it and select Run as administrator). + 2. Type: + ```PowerShell + Install-Module AzureAD + ``` + + or if you cannot be administrator on your machine, run: + ```PowerShell + Install-Module AzureAD -Scope CurrentUser + ``` + +### Run the script and start running + +5. Go to the `AppCreationScripts` sub-folder. From the folder where you cloned the repo, + ```PowerShell + cd AppCreationScripts + ``` +6. Run the scripts. See below for the [four options](#four-ways-to-run-the-script) to do that. +7. Open the Visual Studio solution, and in the solution's context menu, choose **Set Startup Projects**. +8. select **Start** for the projects + +You're done. this just works! + +### Four 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. + +Here are the details on how to do this. + +#### Option 1 (interactive) + +- Just run ``. .\Configure.ps1``, and you will be prompted to sign-in (email address, password, and if needed MFA). +- The script will be run as the signed-in user and will use the tenant in which the user is defined. + +Note that the script will choose the tenant in which to create the applications, based on the user. Also to run the `Cleanup.ps1` script, you will need to re-sign-in. + +#### Option 2 (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) + + if you want to create the apps in a particular tenant, you can use the following option: +- open the [Microsoft Entra admin center](https://entra.microsoft.com) +- Select the Microsoft Entra ID you are interested in (in the combo-box below your name on the top right of the browser window) +- Find the "Active Directory" object in this tenant +- Go to **Properties** and copy the content of the **Directory Id** property +- Then use the full syntax to run the scripts: + +```PowerShell +$tenantId = "yourTenantIdGuid" +. .\Cleanup.ps1 -TenantId $tenantId +. .\Configure.ps1 -TenantId $tenantId +``` + +#### 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`. + +The acceptable values for this parameter are: + +- AzureCloud +- AzureChinaCloud +- AzureUSGovernment +- AzureGermanyCloud + +Example: + + ```PowerShell + . .\Cleanup.ps1 -AzureEnvironmentName "AzureGermanyCloud" + . .\Configure.ps1 -AzureEnvironmentName "AzureGermanyCloud" + ``` diff --git a/3-desktop/console-html-browser/AppCreationScripts/Cleanup.ps1 b/3-desktop/console-html-browser/AppCreationScripts/Cleanup.ps1 new file mode 100644 index 0000000..f482b34 --- /dev/null +++ b/3-desktop/console-html-browser/AppCreationScripts/Cleanup.ps1 @@ -0,0 +1,77 @@ +[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)')] + [string] $azureEnvironmentName +) + +if ($null -eq (Get-Module -ListAvailable -Name "AzureAD")) { + Install-Module "AzureAD" -Scope CurrentUser +} +Import-Module AzureAD +$ErrorActionPreference = "Stop" + +Function Cleanup +{ + if (!$azureEnvironmentName) + { + $azureEnvironmentName = "AzureCloud" + } + + <# + .Description + This function removes the Azure AD applications for the sample. These applications were created by the Configure.ps1 script + #> + + # $tenantId is the Active Directory Tenant. This is a GUID which represents the "Directory ID" of the AzureAD tenant + # into which you want to create the apps. Look it up in the Azure portal in the "Properties" of the Azure AD. + + # 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 + } + 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 + } + $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 "Removing 'client' (Console-Interactive-MultiTarget-v2) if needed" + Get-AzureADApplication -Filter "DisplayName eq 'Console-Interactive-MultiTarget-v2'" | ForEach-Object {Remove-AzureADApplication -ObjectId $_.ObjectId } + $apps = Get-AzureADApplication -Filter "DisplayName eq 'Console-Interactive-MultiTarget-v2'" + if ($apps) + { + Remove-AzureADApplication -ObjectId $apps.ObjectId + } + + foreach ($app in $apps) + { + Remove-AzureADApplication -ObjectId $app.ObjectId + Write-Host "Removed Console-Interactive-MultiTarget-v2.." + } + # also remove service principals of this app + Get-AzureADServicePrincipal -filter "DisplayName eq 'Console-Interactive-MultiTarget-v2'" | ForEach-Object {Remove-AzureADServicePrincipal -ObjectId $_.Id -Confirm:$false} + +} + +Cleanup -Credential $Credential -tenantId $TenantId \ No newline at end of file diff --git a/3-desktop/console-html-browser/AppCreationScripts/Configure.ps1 b/3-desktop/console-html-browser/AppCreationScripts/Configure.ps1 new file mode 100644 index 0000000..3e1bf0c --- /dev/null +++ b/3-desktop/console-html-browser/AppCreationScripts/Configure.ps1 @@ -0,0 +1,224 @@ +[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)')] + [string] $azureEnvironmentName +) + +<# + This script creates the Azure AD applications needed for this sample and updates the configuration files + for the visual Studio projects from the data in the Azure AD applications. + + 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 + + There are four ways to run this script. For more information, read the AppCreationScripts.md file in the same folder as this script. +#> + +# Adds the requiredAccesses (expressed as a pipe separated string) to the requiredAccess structure +# The exposed permissions are in the $exposedPermissions collection, and the type of permission (Scope | Role) is +# described in $permissionType +Function AddResourcePermission($requiredAccess, ` + $exposedPermissions, [string]$requiredAccesses, [string]$permissionType) +{ + foreach($permission in $requiredAccesses.Trim().Split("|")) + { + 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) + } + } + } +} + +# +# Example: GetRequiredPermissions "Microsoft Graph" "Graph.Read|User.Read" +# See also: http://stackoverflow.com/questions/42164581/how-to-configure-a-new-azure-ad-application-through-powershell +Function GetRequiredPermissions([string] $applicationDisplayName, [string] $requiredDelegatedPermissions, [string]$requiredApplicationPermissions, $servicePrincipal) +{ + # If we are passed the service principal we use it directly, otherwise we find it from the display name (which might not be unique) + if ($servicePrincipal) + { + $sp = $servicePrincipal + } + else + { + $sp = Get-AzureADServicePrincipal -Filter "DisplayName eq '$applicationDisplayName'" + } + $appid = $sp.AppId + $requiredAccess = New-Object Microsoft.Open.AzureAD.Model.RequiredResourceAccess + $requiredAccess.ResourceAppId = $appid + $requiredAccess.ResourceAccess = New-Object System.Collections.Generic.List[Microsoft.Open.AzureAD.Model.ResourceAccess] + + # $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" + } + + # $sp.AppRoles | Select Id,AdminConsentDisplayName,Value: To see the list of all the Application permissions for the application + if ($requiredApplicationPermissions) + { + AddResourcePermission $requiredAccess -exposedPermissions $sp.AppRoles -requiredAccesses $requiredApplicationPermissions -permissionType "Role" + } + return $requiredAccess +} + + +Function UpdateLine([string] $line, [string] $value) +{ + $index = $line.IndexOf('=') + $delimiter = ';' + if ($index -eq -1) + { + $index = $line.IndexOf(':') + $delimiter = ',' + } + if ($index -ige 0) + { + $line = $line.Substring(0, $index+1) + " "+'"'+$value+'"'+$delimiter + } + return $line +} + +Function UpdateTextFile([string] $configFilePath, [System.Collections.HashTable] $dictionary) +{ + $lines = Get-Content $configFilePath + $index = 0 + while($index -lt $lines.Length) + { + $line = $lines[$index] + foreach($key in $dictionary.Keys) + { + if ($line.Contains($key)) + { + $lines[$index] = UpdateLine $line $dictionary[$key] + } + } + $index++ + } + + Set-Content -Path $configFilePath -Value $lines -Force +} + +Set-Content -Value " " -Path createdApps.html +Add-Content -Value "
" -Path createdApps.html +} + +# Pre-requisites +if ((Get-Module -ListAvailable -Name "AzureAD") -eq $null) { + Install-Module "AzureAD" -Scope CurrentUser +} + +Import-Module AzureAD + +# Run interactively (will ask you for the tenant ID) +ConfigureApplications -Credential $Credential -tenantId $TenantId \ No newline at end of file diff --git a/3-desktop/console-html-browser/AppCreationScripts/sample.json b/3-desktop/console-html-browser/AppCreationScripts/sample.json new file mode 100644 index 0000000..8b7636d --- /dev/null +++ b/3-desktop/console-html-browser/AppCreationScripts/sample.json @@ -0,0 +1,52 @@ +{ + "Sample": { + "Title": "Using the Microsoft identity platform to call Microsoft Graph API with custom web ui.", + "Level": 300, + "Client": ".NET Desktop (Console)", + "Service": "Microsoft Graph", + "RepositoryUrl": "ms-identity-dotnet-desktop-tutorial", + "Endpoint": "AAD v2.0" + }, + + /* + This section describes the Azure AD Applications to configure, and their dependencies + */ + "AADApps": [ + { + "Id": "client", + "Name": "Console-Interactive-MultiTarget-v2", + "Kind": "Desktop", + "ReplyUrls": "https://login.microsoftonline.com/common/oauth2/nativeclient, http://localhost", + "RequiredResourcesAccess": [ + { + "Resource": "Microsoft Graph", + "DelegatedPermissions": [ "User.Read" ] + } + ] + } + ], + + /* + This section describes how to update the code in configuration files from the apps coordinates, once the apps + are created in Azure AD. + Each section describes a configuration file, for one of the apps, it's type (XML, JSon, plain text), its location + with respect to the root of the sample, and the mappping (which string in the config file is mapped to which value + */ + "CodeConfiguration": [ + { + "App": "client", + "SettingKind": "JSon", + "SettingFile": "\\..\\Console-Interactive-CustomWebUI\\appsettings.json", + "Mappings": [ + { + "key": "ClientId", + "value": ".AppId" + }, + { + "key": "TenantId", + "value": "$tenantId" + } + ] + } + ] +} diff --git a/3-desktop/console-html-browser/Console-Interactive-CustomWebUI/Console-Interactive-CustomWebUI.csproj b/3-desktop/console-html-browser/Console-Interactive-CustomWebUI/Console-Interactive-CustomWebUI.csproj new file mode 100644 index 0000000..57fc6d2 --- /dev/null +++ b/3-desktop/console-html-browser/Console-Interactive-CustomWebUI/Console-Interactive-CustomWebUI.csproj @@ -0,0 +1,25 @@ +ο»Ώ" -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" + + if (!$azureEnvironmentName) + { + $azureEnvironmentName = "AzureCloud" + } + + # $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 + } + 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 + } + + + + $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 (Console-Interactive-MultiTarget-v2)" + # create the application + $clientAadApplication = New-AzureADApplication -DisplayName "Console-Interactive-MultiTarget-v2" ` + -ReplyUrls "https://login.microsoftonline.com/common/oauth2/nativeclient", "http://localhost" ` + -AvailableToOtherTenants $True ` + -PublicClient $True + + # 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 + Write-Host "'$($user.UserPrincipalName)' added as an application owner to app '$($clientServicePrincipal.DisplayName)'" + } + + + Write-Host "Done creating the client application (Console-Interactive-MultiTarget-v2)" + + # 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 " Application AppId Url in the Azure portal " -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" ` + + $requiredResourcesAccess.Add($requiredPermissions) + + + Set-AzureADApplication -ObjectId $clientAadApplication.ObjectId -RequiredResourceAccess $requiredResourcesAccess + Write-Host "Granted permissions." + + # Update config file for 'client' + $configFile = $pwd.Path + "\..\Console-Interactive-CustomWebUI\appsettings.json" + Write-Host "Updating the sample code ($configFile)" + $dictionary = @{ "ClientId" = $clientAadApplication.AppId;"TenantId" = $tenantId }; + UpdateTextFile -configFilePath $configFile -dictionary $dictionary + + Add-Content -Value " client $currentAppId Console-Interactive-MultiTarget-v2 + + diff --git a/3-desktop/console-html-browser/Console-Interactive-CustomWebUI/Program.cs b/3-desktop/console-html-browser/Console-Interactive-CustomWebUI/Program.cs new file mode 100644 index 0000000..e605666 --- /dev/null +++ b/3-desktop/console-html-browser/Console-Interactive-CustomWebUI/Program.cs @@ -0,0 +1,161 @@ +ο»Ώusing Microsoft.Extensions.Configuration; +using Microsoft.Graph; +using Microsoft.Identity.Client; +using System; +using System.Linq; +using System.Net.Http.Headers; +using System.Threading.Tasks; + +namespace Console_Interactive_CustomWebUI +{ + class Program + { + private static PublicClientApplicationOptions appConfiguration = null; + private static IConfiguration configuration; + private static string graphURL; + + // The MSAL Public client app + private static IPublicClientApplication application; + + // Object with the custom HTML + private static SystemWebViewOptions _customWebView = GetCustomHTML(); + + static async Task Main(string[] args) + { + // Using appsettings.json as our configuration settings + var builder = new ConfigurationBuilder() + .SetBasePath(System.IO.Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json"); + + configuration = builder.Build(); + + appConfiguration = configuration + .Get+ + +Exe +netcoreapp3.1; net472 +Console_Interactive_CustomWebUI ++ + ++ + + + + + + + + ++ +PreserveNewest +(); + + // We intend to obtain a token for Graph for the following scopes (permissions) + string[] scopes = new[] { "user.read" }; + + graphURL = configuration.GetValue ("GraphApiUrl"); + + // Sign-in user using MSAL and obtain an access token for MS Graph + GraphServiceClient graphClient = await SignInAndInitializeGraphServiceClient(appConfiguration, scopes); + + // Call the /me endpoint of MS Graph + await CallMSGraph(graphClient); + + Console.ReadKey(); + } + + /// + /// Sign in user using MSAL and obtain a token for MS Graph + /// + ///+ private async static Task SignInAndInitializeGraphServiceClient(PublicClientApplicationOptions configuration, string[] scopes) + { + GraphServiceClient graphClient = new GraphServiceClient(graphURL, + new DelegateAuthenticationProvider(async (requestMessage) => + { + requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", await SignInUserAndGetTokenUsingMSAL(configuration, scopes)); + })); + + return await Task.FromResult(graphClient); + } + + /// + /// Signs in the user using the device code flow and obtains an Access token for MS Graph + /// + /// + /// + ///+ private static async Task SignInUserAndGetTokenUsingMSAL(PublicClientApplicationOptions configuration, string[] scopes) + { + // build the AAd authority Url + string authority = string.Concat(configuration.Instance, configuration.TenantId); + + // Initialize the MSAL library by building a public client application + application = PublicClientApplicationBuilder.Create(configuration.ClientId) + .WithAuthority(authority) + .WithRedirectUri(configuration.RedirectUri) + .Build(); + + + AuthenticationResult result; + + try + { + var accounts = await application.GetAccountsAsync(); + + // Try to acquire an access token from the cache, if UI interaction is required, MsalUiRequiredException will be thrown. + result = await application.AcquireTokenSilent(scopes, accounts.FirstOrDefault()).ExecuteAsync(); + } + catch (MsalUiRequiredException) + { + // Acquiring an access token interactively using the custom html. + result = await application.AcquireTokenInteractive(scopes) + .WithSystemWebViewOptions(_customWebView) // Using the custom html + .ExecuteAsync(); + } + + return result.AccessToken; + } + + /// + /// Call MS Graph and print results + /// + /// + ///+ private static async Task CallMSGraph(GraphServiceClient graphClient) + { + var me = await graphClient.Me.Request().GetAsync(); + + // Printing the results + Console.Write(Environment.NewLine); + Console.WriteLine("-------- Data from call to MS Graph --------"); + Console.Write(Environment.NewLine); + Console.WriteLine($"Id: {me.Id}"); + Console.WriteLine($"Display Name: {me.DisplayName}"); + Console.WriteLine($"Email: {me.Mail}"); + } + + /// + /// Returns a custom HTML for the authorization success or failure, and redirect url. + /// For more available options, please inspect the SystemWebViewOptions class. + /// + ///+ private static SystemWebViewOptions GetCustomHTML() + { + return new SystemWebViewOptions + { + HtmlMessageSuccess = @" + Authentication Complete + ++ +Custom Web UI
++ + + + ", + + HtmlMessageError = @" +Authentication complete
+You can return to the application. Feel free to close this browser tab.+Authentication Failed + ++ +Custom Web UI
++ + + + " + }; + } + } +} diff --git a/3-desktop/console-html-browser/Console-Interactive-CustomWebUI/appsettings.json b/3-desktop/console-html-browser/Console-Interactive-CustomWebUI/appsettings.json new file mode 100644 index 0000000..070f49e --- /dev/null +++ b/3-desktop/console-html-browser/Console-Interactive-CustomWebUI/appsettings.json @@ -0,0 +1,7 @@ +{ + "Instance": "https://login.microsoftonline.com/", + "ClientId": "[Enter the Client Id (Application ID obtained from the Azure portal), e.g. ba74781c2-53c2-442a-97c2-3d60re42f403]", + "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]", + "RedirectUri": "http://localhost", + "GraphApiUrl": "https://graph.microsoft.com/beta/" +} diff --git a/3-desktop/console-html-browser/Console-Interactive.sln b/3-desktop/console-html-browser/Console-Interactive.sln new file mode 100644 index 0000000..bf66cc9 --- /dev/null +++ b/3-desktop/console-html-browser/Console-Interactive.sln @@ -0,0 +1,25 @@ +ο»Ώ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29709.97 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Console-Interactive-CustomWebUI", "Console-Interactive-CustomWebUI\Console-Interactive-CustomWebUI.csproj", "{509D5688-3BD1-4650-8A43-3CEF5B64198E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {509D5688-3BD1-4650-8A43-3CEF5B64198E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {509D5688-3BD1-4650-8A43-3CEF5B64198E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {509D5688-3BD1-4650-8A43-3CEF5B64198E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {509D5688-3BD1-4650-8A43-3CEF5B64198E}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {42EE218E-9522-4DBA-9DFE-2EC0FB0CD3D5} + EndGlobalSection +EndGlobal diff --git a/3-desktop/console-html-browser/README.md b/3-desktop/console-html-browser/README.md new file mode 100644 index 0000000..9b1b631 --- /dev/null +++ b/3-desktop/console-html-browser/README.md @@ -0,0 +1,255 @@ +--- +services: active-directory +platforms: dotnet +author: TiagoBrenck +level: 200 +client: .NET Desktop (Console) +service: Microsoft Graph +endpoint: Microsoft identity platform +page_type: sample +languages: + - csharp +products: + - azure + - microsoft-entra-id + - dotnet + - office-ms-graph +description: "This sample demonstrates a .NET Desktop (Console) application calling Microsoft Graph using custom web UI HTML" +--- + +# Using the Microsoft identity platform to call Microsoft Graph API with custom web UI HTML. + + + +## About this sample + +### Overview + +This sample demonstrates how to use a custom web UI HTML on MSAL.NET. + +1. The .NET Desktop (Console) application uses the Microsoft Authentication Library (MSAL) to obtain a JWT access token from Microsoft Entra ID. +1. Once the authorization request is finished (successfully or not), the customized HTML will be shown and the browser will return the response to MSAL. + +### Scenario + +The console application: + +- gets an access token from Microsoft Entra ID interactively using a custom web UI HTML +- and then calls the Microsoft Graph `/me` endpoint to get the user information, which it then displays in the console. + + + +## How to run this sample + +To run this sample, you'll need: + +- [Visual Studio 2019](https://aka.ms/vsdownload) +- An Internet connection +- a Microsoft Entra tenant. For more information on how to get a Microsoft Entra tenant, see [How to get a Microsoft Entra tenant](https://azure.microsoft.com/documentation/articles/active-directory-howto-tenant/) +- A user account in your Microsoft Entra tenant. This sample will not work with a Microsoft account (formerly Windows Live account). Therefore, if you signed in to the [Microsoft Entra admin center](https://entra.microsoft.com) with a Microsoft account and have never created a user account in your directory before, you need to do that now. + +### Step 1: Clone or download this repository + +From your shell or command line: + +```Shell +git clone https://github.com/Azure-Samples/ms-identity-dotnet-desktop-tutorial.git +``` + +or download and extract the repository .zip file. + +> Given that the name of the sample is quiet long, and so are the names of the referenced NuGet packages, you might want to clone it in a folder close to the root of your hard drive, to avoid file size limitations on Windows. + +### Step 2: Register the sample application with your Microsoft Entra tenant + +There is one project in this sample. To register it, you can: + +- either follow the steps [Step 2: Register the sample with your Microsoft Entra tenant](#step-2-register-the-sample-with-your-azure-active-directory-tenant) and [Step 3: Configure the sample to use your Microsoft Entra tenant](#choose-the-azure-ad-tenant-where-you-want-to-create-your-applications) +- or use PowerShell scripts that: + - **automatically** creates the Microsoft Entra applications and related objects (passwords, permissions, dependencies) for you. Note that this works for Visual Studio only. + - modify the Visual Studio projects' configuration files. + + ++ +Follow the steps below to manually walk through the steps to register and configure the applications. + +#### Choose the Microsoft Entra tenant where you want to create your applications + +As a first step you'll need to: + +1. Sign in to the [Microsoft Entra admin center](https://entra.microsoft.com) using either a work or school account or a personal Microsoft account. +1. If your account is present in more than one Microsoft Entra tenant, select your profile at the top right corner in the menu on top of the page, and then **switch directory**. + Change your portal session to the desired Microsoft Entra tenant. + +#### Register the client app (Console-Interactive-MultiTarget-v2) + +1. Navigate to the Microsoft identity platform for developers [App registrations](https://go.microsoft.com/fwlink/?linkid=2083908) page. +1. Click **New registration** on top. +1. In the **Register an application page** that appears, enter your application's registration information: + - In the **Name** section, enter a meaningful application name that will be displayed to users of the app, for example `Console-Interactive-MultiTarget-v2`. + - Change **Supported account types** to **Accounts in any organizational directory and personal Microsoft accounts (e.g. Skype, Xbox, Outlook.com)**. +1. Click on the **Register** button in bottom to create the application. +1. In the app's registration screen, find the **Application (client) ID** value and record it for use later. You'll need it to configure the configuration file(s) later in your code. +1. In the app's registration screen, click on the **Authentication** blade in the left. + - If you don't have a platform added yet, click on **Add a platform** and select the **Public client (mobile & desktop)** option. + - In the **Redirect URIs** section, enter the following redirect URIs. + - `http://localhost` + - In the **Redirect URIs** | **Suggested Redirect URIs for public clients (mobile, desktop)** section, select **https://login.microsoftonline.com/common/oauth2/nativeclient** + +1. Click the **Save** button on top to save the changes. +1. In the app's registration screen, click on the **API permissions** blade in the left to open the page where we add access to the Apis that your application needs. + - Click the **Add a permission** button and then, + - Ensure that the **Microsoft APIs** tab is selected. + - In the *Commonly used Microsoft APIs* section, click on **Microsoft Graph** + - In the **Delegated permissions** section, select the **User.Read** in the list. Use the search box if necessary. + - Click on the **Add permissions** button at the bottom. + +##### Configure the client app (Console-Interactive-MultiTarget-v2) to use your app registration + +Open the project in your IDE (like Visual Studio) to configure the code. +>In the steps below, "ClientID" is the same as "Application ID" or "AppId". + +1. Open the `Console-Interactive-MultiTarget\appsettings.json` file +1. Find the app key `ClientId` and replace the existing value with the application ID (clientId) of the `Console-Interactive-MultiTarget-v2` application copied from the Microsoft Entra admin center. +1. Find the app key `TenantId` and replace the existing value with your Microsoft Entra tenant ID. + +### Step 4: Run the sample + +Clean the solution, rebuild the solution, and run it. + +Start the application, sign-in and check the result in the console. + +> [Consider taking a moment to share your experience with us.](https://forms.office.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbR73pcsbpbxNJuZCMKN0lURpUREhEVDBOTFBMUVRPUElBUE5WMjdPQ1RaMiQlQCN0PWcu) + +## About the code + +MSAL has the class [SystemWebViewOptions.cs](https://docs.microsoft.com/dotnet/api/microsoft.identity.client.systemwebviewoptions?view=azure-dotnet) which allows you to set properties to customize the UI after the authentication request. + +In this sample, we customized the HTML for successful and failure authorization requests, but more options are available. Please refer to the [SystemWebViewOptions.cs documentation](https://docs.microsoft.com/dotnet/api/microsoft.identity.client.systemwebviewoptions?view=azure-dotnet) for more options. + +1- Customizing the success or failure HTML message: + +```csharp +private static SystemWebViewOptions GetCustomHTML() +{ + return new SystemWebViewOptions + { + HtmlMessageSuccess = @" +Expand this section if you want to use this automation:
+ +1. On Windows, run PowerShell 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 Microsoft Entra application and configure the code of the sample application accordingly. +1. In PowerShell run: + + ```PowerShell + cd .\AppCreationScripts\ + .\Configure.ps1 + ``` + + > Other ways of running the scripts are described in [App Creation Scripts](./AppCreationScripts/AppCreationScripts.md) + > The scripts also provide a guide to automated application registration, configuration and removal which can help in your CI/CD scenarios. + +1. Open the Visual Studio solution and click start to run the code. + +Authentication Complete + ++ +Custom Web UI
++ + + + ", + + HtmlMessageError = @" +Authentication complete
+You can return to the application. Feel free to close this browser tab.+Authentication Failed + ++ +Custom Web UI
++ + + + " + }; +} +``` + +2- Using `.WithSystemWebViewOptions()` on the `AcquireTokenInteractive` request, passing the customized SystemWebViewOptions object so MSAL can use it to display the response. + +```csharp +var app = PublicClientApplicationBuilder.Create(appConfiguration.ClientId) + .WithAuthority(_authority) + .WithRedirectUri(appConfiguration.RedirectUri) + .Build(); + +string[] scopes = new[] { "user.read" }; +AuthenticationResult result; + +try +{ + var accounts = await app.GetAccountsAsync(); + result = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault()) + .ExecuteAsync(); +} +catch (MsalUiRequiredException) +{ + result = await app.AcquireTokenInteractive(scopes) + .WithSystemWebViewOptions(_customWebView) // Using the custom html + .ExecuteAsync(); +} +``` + +3- Once the authorization response gets back, the opened tab will display the custom successful or failure message. + +Success custom message: + + +Failure custom message: + + +## Community Help and Support + +Use [Stack Overflow](http://stackoverflow.com/questions/tagged/msal) to get support from the community. +Ask your questions on Stack Overflow first and browse existing issues to see if someone has asked your question before. +Make sure that your questions or comments are tagged with [`azure-active-directory` `msal` `dotnet`]. + +If you find a bug in the sample, please raise the issue on [GitHub Issues](../../../../issues). + +To provide a recommendation, visit the following [User Voice page](https://feedback.azure.com/forums/169401-azure-active-directory). + +## Contributing + +If you'd like to contribute to this sample, see [CONTRIBUTING.MD](/CONTRIBUTING.md). + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information, see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + +## More information + +For more information, see MSAL.NET's conceptual documentation: + +- [MSAL.NET's conceptual documentation](https://aka.ms/msal-net) +- [Microsoft identity platform (Microsoft Entra ID for developers)](https://docs.microsoft.com/azure/active-directory/develop/) +- [Quickstart: Register an application with the Microsoft identity platform](https://docs.microsoft.com/azure/active-directory/develop/quickstart-register-app) +- [Quickstart: Configure a client application to access web APIs](https://docs.microsoft.com/azure/active-directory/develop/quickstart-configure-app-access-web-apis) + +- [Understanding Microsoft Entra application consent experiences](https://docs.microsoft.com/azure/active-directory/develop/application-consent-experience) +- [Understand user and admin consent](https://docs.microsoft.com/azure/active-directory/develop/howto-convert-app-to-be-multi-tenant#understand-user-and-admin-consent) +- [Application and service principal objects in Microsoft Entra ID](https://docs.microsoft.com/azure/active-directory/develop/app-objects-and-service-principals) + +For more information about how OAuth 2.0 protocols work in this scenario and other scenarios, see [Authentication Scenarios for Microsoft Entra ID](http://go.microsoft.com/fwlink/?LinkId=394414). diff --git a/3-desktop/console-html-browser/ReadmeFiles/failureMessage.png b/3-desktop/console-html-browser/ReadmeFiles/failureMessage.png new file mode 100644 index 0000000000000000000000000000000000000000..8d682a4c237ec1cdeb55b45f364a3448140fd512 GIT binary patch literal 50277 zcmd@6byOQ+*FKE4g(AhFxEC)F+^u+9inX}ATd)wcxNET%_fp)0ySrO}BEj7P1o`Om zyzlq-`RknX{l2v(D{Cf``<{EYUHjU5CR{~H9_tO+n-?!$V14>1^Yz6GB-$4*Uh1Kt zJReybt?GULdg=02Ug|~p7{%W64zi`BqU4JgRk0ZN#;>3E(VaeOyS#XT@A~iaa@B&` zAuthentication failed
+Error details: error {0} error_description: {1}+
+You can return to the application. Feel free to close this browser tab.+4UcCM=QSc2}Cp3sg#$o-aDO+Jm%M9ilf@GNW zLlZZM`Y gfQyC7S}qe*v4tL z!tnv~()DYy#O#%W(_{2TM`I-MB@G66#_#^N(OYN3P*zfqdlKULe#@xP{FBWmtk2HW zQaj5DT$|m_fz#`0(+h|`nM?aMoN@a<@jGp6Gnyy8=X*%FK;2iq7h@7Y)l8=Q9AcE% z#AZ+NmEZ^G`S9}%Lgpld` g5Z2datck2#?w^!Sg(l{{KWR$jAI^38R&% zEtKy3OGi3~ ($LW<#03L3sy%JsK #E-7%-aV%({u`4P2La-nDND<&CDDZXJ11N-|vM+Ol|2r c~cl<0$ z|I`QtL8T32HZXRhX#$-9;I7Z>>W0L9wQKlE!phjj8jJO8&3Jatx*KMjY {BvX~ D<49k?PrYr9Kk}A-xXq4i9fcyH=$+}hlw3ry2M@=i)0}rSh z3^x5S!IE2txkiSUac6vUDQfp z=V4bK34LST=Zu~xlDIvDuj$Y>mbPw8_@hc* =ba;Z(^eoH#;j6GNNr|d%OYwE4QG!b6{J0J;1 zusMaDjBr%XeO*-dEqNm(@ijBmb-K==+_EU0v2ifwU)aphWU`Z!Wi`7UaT kgfj!0$j_4bFI<1eRWMwTcRkeiAG#ykFsk7t7|NXq3G@!hb9 z+Be-Ek>|!f_b4}u2hP4^N7jx_kd4hzUR%q~&XK1C W~BGd{dN@&Km>k$@u>OvjwG4ALAk);C_lg9fix4eWeC?s*` zsh%TP58r24O7m7`yubePaBE4tj~1uNyNLTLiX*{<=&dt_Umg}5$KSUYbNaiZbpv7E zw-od!TNH$wNh2>Zd#Am}?OWrIL4}l(*V2A{g~Rp1%el5KZn*}fOEE~!n&tv?i)=r{ z&sRlgq0j~Yr<}}*i&f#n#OC+r3k`F>+ENk6GN_FwIfZEBJrdvNU$L`QDJe;1Pk-Z( zyiR{Xgrc6__cL3F8ZF>P{KG$wm#21IXLwU)i5jWxex-5`y0?yn!f}J+FCr@2n~2;@ zB8*pfyZ5T*Xs>oOzx2Io4W<-(c>r@mb+IE_lqQ?Af)g&^p-)r@s~TRD`SMi_^i5z& zKSh}@XtQjpYes&iDvEkEJ_k{D36Y(7BAF_d%0#D!=5m9dYWgd!V^-*23F}pT9AAt5 zRr8MB5@ MdWq$%`AzyTbR*@ 9t4*mtpH)=Y;9`(CZ%fU_3f0(+l)esO(>jbvg7 z0VDtu7vVKCZ62Q`At^q5t&xqAe`C;`mf-2iqC@!^xj;7lMai%eELgLqZV^z?2P?7= z8Vxw+gpD=^q+8qskDtdA!Q@=^-h6#Z420Q&ayJYMZtSxkCMk*~JF}*Y+~B!!8XmX@ z7KPcCiBXzXB)J~x7Ud#gUAzZ9{X3DFJ*D0*Omvpe;^2iwvp2_VvjZS=mq1j+=aG z#X$8YQ>8PameWW8q_|GdAv)_aD*&|W{qc5o0KJsY<4tt_yirtQvq6N)Wurib`m%WS zw&DH5Zl0p`Y(36#!%axRjaK`8)6u(NI^ao0p|kik6}Nq1WaQ^z`7_o$QFB5vqTok@ zbCvWgi;P^)Zr2v73Cni?jN9G;0`5N+EzVDwEF4C|#}xDng73%++gFhdbDv{wo9;ir zva!S<`jSIKWAksa`ORJV1FPGckCkGgCYH{MJYaW0u2*v z%)-q+cLZ*^p871&9O2gQm__#L0NFBr7m+ b2{xZy*P53(;ji>_pdc9 zd- 4B=B%mw5X|T#1wooL4RbTP4WDhE1t?xEpY3@Ku}}g; zNi5Sf8v6grmrg&l!CC5AWetMyZ4KEVp_iPlX$0%_+B+|aNCQ2Vqws1wJKi4b-d%tX zDCXXCZT5Y`!9JzM$k~m*5iA905cq^Y!=M}Ne?a?LP1m6$l#Y9C&d4VZj4v~~yKyI3 z&`oQct4xMprdzoe _&rpmvav7t~p* zf1AQTdit=?8LQJDY^N3au)!lYD7>XDZXDI~*T7km&YhF0E^2(B|N6nC-#5PN=^5C- zdE0tkHXDBxFmyag|Fk5x5S1fbML?+TyvEetk)gj;P9S!? )wFc|)u@U@hA8?0WBGZ$VJVq95put@4{nh}IC&?XO1*{xjp!H%?l%hV>$0P=C> zDR-QJN6JJg;xt`cDV{M5jToyTV4`@)l6vC*b?u>mYf~it `dIx1vMW`krZ>&FDCT&r}8~E zP9A$zZB|*l#0;a=MmhP%0e(uW>)n-xgD`}g R@p3eqiV{_z`L&tBo3&X@zUTA@@E-`7wChh|&2xsW zG}0Ro@S^ne*DJQvl7oKdN951R;~l34(x;jQ%8#(GkvvQ=2b$VPbkD+j6vwv|vPX+# zhifeqLVjd{Jys2Fm;o^tvU@l1lnA6pGP43PhdM-JRT;%2=D~-fPxs%B_xH%{9fJ%< zT^lcmot69Lsn_Wm4>}*vP(;8uVkq6!9(T8PBZKv0O4pGns3soa<3hXoNQ~c)WDi0~ z$=%TnYhJ!LZpc?2f$7}MuUS!!#A0a`VfLNH{;_EuctR5};P?mdz5f$UYoIZRq6J@! z&gEjiOPAndvbPUhg#0xVuU5VRvwDr9 Z7$1|~1!rX5wH~A+ zU!)t}hyz->mf8O eBiKqARI~R#48k@>F8qirQarnJM3? zh}JYMi5pzaYCVjgX%Qd0)3HCiyy0p-QU8e3BepQ185M$ca@q#(Zn6o*(>%}EeGebK zgm4fhQ$;XUb8W+AujRlG4kJh8{!01@oY#wNTjg5)2SY$_%8o6}9nGlDT`0G%_HT~i z-h9ha*3oRlN6eN(12E8|!@}J6jG>m^g+>@NH2^w}{TCw6wbQnJRr2D3`Y3{m;OM{? z9*?AWQ1Q&U2zERppFW|%xqMl!9PD2fktTb#%7b3ILUqoyqkP^jz15fZ+#0$}QW@ra zh{%PJd`?8=P;%cKGbl0rE;Smo80=EDz~rno`Dg=nl%y;vTOE(sjy8j0)))|Ebz=|3 zdB$*1SzryHWSwu*Qkha6{CZP=LEXFn mX-@Br8uf?9P7=MAKm0u%S&{TKHu90oBBrhwAqrUOuA;UrI#5a zE~d3h14UyEtdoM|fUaER7KkW0hw{l0A)C&4x@UJq^$#fokar~6!EOqjWc1i*i`4k? z)16$2UafplLfiS P)Ebj8)45}0ARYe@q5@!IPT >SO 71G7mkmF2nIg#r073dA}Alr zq^MNtD#zOl3iBe p4Qkg&sK1TlO`Va5;fbq?ePA8+DCCvojL|H5@o zWsQkKmK42UNGS-wV`-q4(3m`#6zbph _bXsIXrRp>THT5Q!4zH$mT0Y6z2b zePds)fly^=iIAS8k9A1Gy-qG2Yh89T;O7(A_x&HJYiz;R1PI X$+u^c-mOvq4QO$k(H*VE(5PX3Di0P+^Q!?A1mavo(4Vq97&UJwEwY3 zy#ExW>%&1zd&kK5pR>`b46URKrl?O*l3(&C1<@m;B=tVOe@v`-BNFQq7|2?*Nld9b zZ1^B4EZWa+tSa|r!xau{%)4#niL0?;icxp$y3CSAwt|NBz9}+=bvioP?Y!T*XCY(( za)r64iK3>EPjUf2ej1fq-R4dgy#8r8j_(*Fv1S;QJ{TV272(m}Q$Rzv!*coPFKV5u zIRAD8>WW`yo)(|NzCnoPQ#(^z^v;V^86kigFOY-tuAFoj@Ky{(1e2B8UE)sIJG~lr zl^8CvV&R0-ZqCAM6UN4BFlXZPlf+c}?DO~3RGFy3vF`0^opdNKfpjjJs+K*9(Osbp zpkz2sjB!$BUPerT;z#s-HNip_oY?^ 523>_oF3RUS74#|CQ#(=e)KyD*0HdhettLN)h*-t9e6?@&9G}fd# gE{e6VtUTC{ z!TEvZBojRk2lSRV_e^M{@TZACt)eYUHwG!N*OjfZ5D1V!YnJ72t{{lgse2Ty(TzqY z|5OnjM9Q1$r9mtvvDOb0XbR1nX&ZDD%yMjY zO{p6_%~0S vUd>}kI)8Zfk>#TQqRuNp2w_UhppT>(ac#?m zJD8>z8mXY}oJAAXHyQ9t|5=@1{u}vK%DLsb$(iPP7;8w7<)qE2tlmh5sjCu-lH6__ z_IbxpFZ_`jaFl}jD)e-0CAxHl_wdwp#c4mr%^3&a`!z@*6udRA|3c^Sg%x=q5z>#z z^BC&E4(#;ej$Sw0j%&^D8R8|G7+6TY(ATtLo0ES)iJoIoLV(Xp%l 6x5N%mu8ab=t!DqYc76-cjS z=(gMip1d%0T)BmC5%9kW&{pn7 Nl5h}V+OnCD^PAMy{fM9Z=sv4{;k35cJ}f0TcNdiYpl1AOmD7bLDis=kLx zJaANsW&NG99bfM%3f;Q3*qSlW8+dSZ^yEdA`O8w20#0{vs=80V&v|L{NIMOQCx2=p zEgj2vB| vUP0Y0t--n zLtO#2eZEr`dB0K)VupV_QzgUyDL@G$hB_|mbzDKUanu-6O)JLfjXMY9z`bl}JHAjO zcFG&j0VWd ;PZy{eupbU}csF zZ(149S{Qq?%hs>AKpLw@TBVsh<$RTAG@!4-@LpW2EZW5+2ixueU(ZVE7B|FmOsdjU zxW7Am2?=s}EULG#5_h43b-f;eGUY+W<_G2(!vzIz)eNl7udT;uA>HbZQ|3OwVlsQV z2&VDc{S}(MeI7T!+O-si`Ome!jb8=kjPl0< H0kiEh*rxmyPL7wN;lBW0dDyMv( zwOSL _YD9R@DT)Grddcn^m8`!sWJ+h}NSpfj+FDJbHmXgP%ELI6 z-=A`lbnV!|3M@~*)`-V`$Cv|K;W9!*`t$6MznaviyTm)w#n-Vi-G1uD+TmW&RcD;S z3yJf`$(hYFoj6}@p4iwXGD-?{9eXWs2{_-mgv=fo`RGPPDu}E4evOBF?5fsMa3ixf z-KUZ(5_Sko36@A;U;E)%EnfBSS9MfCW-d6B?gjY5Zkz+}4kq8#=i#Ts?fQSdliHUM z*pA%|xSFX*T$}O6r|2%I^MbW~mtb|L(Sg$72-&TOKrS1{mTXCb;}Q+?W={=sVShb> z^x%XXh8dmAQNxjxljlVOCH>79PQWw=Pi^4C0B=x?2QE8mZ(cAWmqkoZyvxMwr=f+m zfggGMW05e^jUb?Hm@=-yb!|h+FDkBQ(u!{bkI!#;4f(plnF?z!nEP>}8>(`=ioxzG zmKx
r| zzgINz`M$8=r21TY%IJ}go dE;E+@0W0|?#sa*UiZ6*w4N$;YW`T5N>$2LhB znIO?=(TNn?=NNSBE&xJvm6IO^pzRfAh0Kp)ot8Trer=*AegGRI^tqhabe`9R+Z$^W z9d|rvwb(yXcBod?iDI%`PtuNZ<)hUa%I$&&8gba`r3??nbN+Ex({-!}*`1-2&3oD` zgkVY!izu3Y{qk%TLry>@fdR2oSLpCXp@;x9$?O4_9VL2uj6^xHnE)jIV{&7ix3;OM zhD^^1@nFSw2doV{@Q+LL`yMALYS{F#B*~C^%7 pJ3xKkJc)ci z&%+yW2C=>MTK-UbcO_$B(9}t@0|6S;>QV`w5d=k%j9 }_M)^n5RnGcG}YvaSlP(Q zyoqy-6|saY-qpZo9*XEcJXFZh!t275CRbg{+PLcgxsPy?m1VWDMoOdRay1TmGIo >G|h5C%Fj zsVMbXclF@(I8#ESI|D8DX1e@}+Y&X_+Ap{4Qs1&
V3Y|jM2R}Ok?UaXvg6QW35`txt*je0EssYA z^rIc!4CQ_$u+n5{?-9!hZMkI!GkEFd^d4 &tl*6?N6@{RW3=91l;PxUu5^x+If++?2G#XktyBCe z=!ID?G5L&69wlZZELQ*yb8evZ$_gxEGV5DM(UYyV%ru|pAR=_^BVFcnF*;Ub_`2)$ zF)t-d?jgim&%=iw;9zZp@|$rzyDANrDc`3QTC?u1uPM?gWY8xMYojcC8l7XtZtOh7 zM2@G~xhUA@fMuH5#@JK-_H&8Gq`BSCpLzYnJsNb46m-8}%-C9Q-y6#Mj8cIA<$8zk zH!qvJ8gHC_MX$$)D;TC4&{4ndF0dfa_aY4n<=enIkflaiB=49{10LHg^uhk o2LwNVYE9mk|A#> zR_ws(!!nI#qwUjw>s=ggC?IBdKF0FY;$$hJcdYYQLhw-zx2Nvazb2AsXX_KC#(6Y= zFLr(RWuX`@U=M|uKodaR*410^9D&IlwTsx>a@Wt@_`(;|)5f3EoaoT!<`xK}(07Fb ztmr@2Sggy7y8!LO#46qCq+qR{BR||bFA0A0$&QjBIYHl)Il#u)A8XGwKLnSQ3Cg>z zo!D&H%~}qu!zc=!3si$BA_@3A5^Td2|04#aE#13cPw2K(nyucN=_2`vt5ywwhKji< z;hi)o^tT1d@En5vbx}cx7F!hrjvVNO`Y3 FL>PU(orxi$J{DS6jUG_03wa>JQ>>&t8_>YGthvpM5 zGH_Pxw9d|R;c|}X8v{JmF?jA6=cgO&0C;W zI`Z1{VDHsJ{cQB{JHKAs#Yx`YL*Gom0Wov^t=r7_&q$0&%?*=5Up?Uhw?hH=*$#L{ zQa4W~aP6eT$d%HjcX)u;baAx~; XWnYsYWoK5y(Tn{-zGT0bf7 zM~S{UmS9bDSANAG>FFC7X)C~c$NK&`_n`idRz^EEd{5eoj^sz Rc)f z*Mo%e-(VN!Q+t+Hc=khU1r_UER7WmFBWo#sk$0Lzf2G7L=n6!m%5~L0X8HD2i+>AH zaBL5ZG#pZPvV89Z+%p7Pw^tOGp$9-T{$*9=Tnm{GeRYx!5G3~d>dCH&4gTrn-HL|4 z_zlK <1_ys6nSo|LMe#C)5Y(yHmA!llhY2@K28@V^m6JLBkekA|ap8Sm*sJfLC z){jWLr*fg>_7K!@g(y)00lrw*d&7`8^Y=J7#`nLP&ATV2Yn>Q&PT%XLvs$R6g<$yk zkRMh?bAkI>jz4`%GDofTbYhme#7K@LT-5{yYW=8aSVI-bIXGY<;-xsN9MvJz#D8w= zNEwc{61v$zLr)3~;4wEEHc%P !R3yRIGdB) zw@TA#`ULYJxyby^^Nyd%t$y3yS)S5QNsKwNT|caTc4V*_0_V|oz;o$+_6>rYx_)9i zNTid`xrexLyhyBXsp8Z*V-UTPOo_oSNod4Qe>>fl1$AGp^C$;i?s%xFp-!QrLv{82 z+4zJFlsO3E7L!D z-yOR %@deSAQDr!Rmec7 z*6uM&p(B5+nDtO~%dJxF=LfoRYJlkq_;GiWVQP~lkIU+IbDJ%XF~9h{k!9BjXIz9T z#p`5ye3QH4iQ6POrL$p>`f|Y2tO&`s>tL2+3RjpGoz~3fnI=$vZkm0t*t{5*knfM7 z1U_8do$UUX9(#`IpVEa~PzVVLcjwB|{(;2i|KU2HyBh!hrziIRd U+=YsqQEMs>6_?VF>&lxIvrMHUHQvC2-Kd_JR0kY z*-L$Eo<>ijZsyVs$*s`p&&OeN@kpnjwjf-rJmyWWICdQLjpqFO(e+)CGgEK&*yk{z z7ZC^4<=&=fVUDf9cK5q~a}8N>GR1kk9AmT${V;wUdp1Pn8%@4&Q3R?i&WUV#!k;cw z rGv(5W5q<#^=w7?Cm~pS_gSYDsqU0v>pB6^aGV) zV%}F?bQfCQlc9_H-ml*jtc$Ku9Y;~W*97X{JWB754BPkh6NcS@|J)&NB+)8vNO%$) zrFYP81sS_Nf3tM)_}pz&wP$o7`5D9n1c-i#SPDv^BLAL$+Z=6OT-I~^wSy25#)a)1 z85_5bd}Th+TEUv|q!+Vbd69?^_v-f@`FtFKa2^G#1?F1bIf*@r>*2IV!Cnuaopbnu zn672BEF Ai(s{rvU%$CtGKU29m zqSk3ej=y_!Q&cz nv hFou&wbYO%`RmTWuR##PQQk+ z3_a70@SUBzakGHH{B}y*4TTdJA3OD^-dCy?^W(pgK~Iw0Lw)RN0|B%}@pB&%4i3_D z4~cD-M>}BQYdaQoF){6}e<&9w6DPb*d7?wTK1dF$HvnfRTO`J4EMMU7(SmwR^vTh> zUsjKw@@|yMRemUcRlDTeG!$8a8{?!Ley|)Zwv2JM1a=s^cfiMA8gL=YQ6;&9ve9pf zYP2Mt966}9VUD-^P^}nxkP-+Vm=G3<%`Ro)1Ay4kUg3s&J! zkFLGw5e