From 35819eca4f7a6409fa2ebb241c1385c1b617dad2 Mon Sep 17 00:00:00 2001 From: Jason Johnston Date: Mon, 27 Jan 2020 10:22:48 -0500 Subject: [PATCH 1/7] Removing old project --- .gitignore | 4 +- AppCreationScripts/Cleanup.ps1 | 63 ------ AppCreationScripts/Configure.ps1 | 213 ------------------ ConsoleApplication/ApplicationConfig.cs | 96 -------- .../DeltaQueryConsoleApplication.csproj | 150 ------------ ConsoleApplication/Helpers/Constants.cs | 43 ---- .../Helpers/GraphClientFactory.cs | 61 ----- .../Helpers/MsalAuthenticationProvider.cs | 86 ------- ConsoleApplication/Helpers/PageIterator.cs | 90 -------- ConsoleApplication/Program.cs | 168 -------------- ConsoleApplication/app.config | 6 - ConsoleApplication/appsettings.json.example | 34 --- ConsoleApplication/packages.config | 20 -- DeltaQuerySample.sln | 31 --- NuGet.config | 13 -- 15 files changed, 2 insertions(+), 1076 deletions(-) delete mode 100644 AppCreationScripts/Cleanup.ps1 delete mode 100644 AppCreationScripts/Configure.ps1 delete mode 100644 ConsoleApplication/ApplicationConfig.cs delete mode 100644 ConsoleApplication/DeltaQueryConsoleApplication.csproj delete mode 100644 ConsoleApplication/Helpers/Constants.cs delete mode 100644 ConsoleApplication/Helpers/GraphClientFactory.cs delete mode 100644 ConsoleApplication/Helpers/MsalAuthenticationProvider.cs delete mode 100644 ConsoleApplication/Helpers/PageIterator.cs delete mode 100644 ConsoleApplication/Program.cs delete mode 100644 ConsoleApplication/app.config delete mode 100644 ConsoleApplication/appsettings.json.example delete mode 100644 ConsoleApplication/packages.config delete mode 100644 DeltaQuerySample.sln delete mode 100644 NuGet.config diff --git a/.gitignore b/.gitignore index dc721ad..b8e2743 100644 --- a/.gitignore +++ b/.gitignore @@ -215,5 +215,5 @@ pip-log.txt #Mr Developer .mr.developer.cfg -#Appsettings.json file -ConsoleApplication/appsettings.json \ No newline at end of file +# VS Code +.vscode/ \ No newline at end of file diff --git a/AppCreationScripts/Cleanup.ps1 b/AppCreationScripts/Cleanup.ps1 deleted file mode 100644 index 91e5dd2..0000000 --- a/AppCreationScripts/Cleanup.ps1 +++ /dev/null @@ -1,63 +0,0 @@ -[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 -) - -if ((Get-Module -ListAvailable -Name "AzureAD") -eq $null) { - Install-Module "AzureAD" -Scope CurrentUser -} -Import-Module AzureAD -$ErrorActionPreference = 'Stop' - -Function Cleanup -{ -<# -.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 - } - else - { - if (!$TenantId) - { - $creds = Connect-AzureAD -Credential $Credential - } - else - { - $creds = Connect-AzureAD -TenantId $tenantId -Credential $Credential - } - } - - if (!$tenantId) - { - $tenantId = $creds.Tenant.Id - } - $tenant = Get-AzureADTenantDetail - $tenantName = ($tenant.VerifiedDomains | Where { $_._Default -eq $True }).Name - - # Removes the applications - Write-Host "Cleaning-up applications from tenant '$tenantName'" - - Write-Host "Removing 'client' (ConsoleApp-DeltaQuery-DotNet) if needed" - $app=Get-AzureADApplication -Filter "DisplayName eq 'ConsoleApp-DeltaQuery-DotNet'" - - if ($app) - { - Remove-AzureADApplication -ObjectId $app.ObjectId - Write-Host "Removed." - } - -} - -Cleanup -Credential $Credential -tenantId $TenantId diff --git a/AppCreationScripts/Configure.ps1 b/AppCreationScripts/Configure.ps1 deleted file mode 100644 index 1809919..0000000 --- a/AppCreationScripts/Configure.ps1 +++ /dev/null @@ -1,213 +0,0 @@ -[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 -) - -<# - 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) - } - } - } -} - -# -# Exemple: 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 - -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 -#> - - # $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 - } - else - { - if (!$TenantId) - { - $creds = Connect-AzureAD -Credential $Credential - } - else - { - $creds = Connect-AzureAD -TenantId $tenantId -Credential $Credential - } - } - - if (!$tenantId) - { - $tenantId = $creds.Tenant.Id - } - - $tenant = Get-AzureADTenantDetail - $tenantName = ($tenant.VerifiedDomains | Where { $_._Default -eq $True }).Name - - # Get the user running the script - $user = Get-AzureADUser -ObjectId $creds.Account.Id - - # Create the client AAD application - Write-Host "Creating the AAD application (ConsoleApp-DeltaQuery-DotNet)" - $clientAadApplication = New-AzureADApplication -DisplayName "ConsoleApp-DeltaQuery-DotNet" ` - -ReplyUrls "urn:ietf:wg:oauth:2.0:oob" ` - -AvailableToOtherTenants $True ` - -PublicClient $True - - $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 (ConsoleApp-DeltaQuery-DotNet)" - - # URL of the AAD application in the Azure portal - # Future? $clientPortalUrl = "https://portal.azure.com/#@"+$tenantName+"/blade/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/Overview/appId/"+$clientAadApplication.AppId+"/objectId/"+$clientAadApplication.ObjectId+"/isMSAApp/" - $clientPortalUrl = "https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/CallAnAPI/appId/"+$clientAadApplication.AppId+"/objectId/"+$clientAadApplication.ObjectId+"/isMSAApp/" - Add-Content -Value "" -Path createdApps.html - - $requiredResourcesAccess = New-Object System.Collections.Generic.List[Microsoft.Open.AzureAD.Model.RequiredResourceAccess] - - # Add Required Resources Access (from 'client' to 'Microsoft Graph') - Write-Host "Getting access from 'client' to 'Microsoft Graph'" - $requiredPermissions = GetRequiredPermissions -applicationDisplayName "Microsoft Graph" ` - -requiredDelegatedPermissions "Mail.Read" ` - - $requiredResourcesAccess.Add($requiredPermissions) - - - Set-AzureADApplication -ObjectId $clientAadApplication.ObjectId -RequiredResourceAccess $requiredResourcesAccess - Write-Host "Granted permissions." - - # Update config file for 'client' - $configFile = $pwd.Path + "\..\ConsoleApplication\appsettings.json" - Write-Host "Updating the sample code ($configFile)" - $dictionary = @{ "ClientId" = $clientAadApplication.AppId }; - UpdateTextFile -configFilePath $configFile -dictionary $dictionary - Write-Host "" - Write-Host "IMPORTANT: Please follow the instructions below to complete a few manual step(s) in the Azure portal": - Write-Host "- For 'client'" - Write-Host " - Navigate to '$clientPortalUrl'" - Write-Host " - Navigate to the API permissions page and click on 'Grant admin consent for {tenant}'" - - Add-Content -Value "
ApplicationAppIdUrl in the Azure portal
client$currentAppIdConsoleApp-DeltaQuery-DotNet
" -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/ConsoleApplication/ApplicationConfig.cs b/ConsoleApplication/ApplicationConfig.cs deleted file mode 100644 index 99c0237..0000000 --- a/ConsoleApplication/ApplicationConfig.cs +++ /dev/null @@ -1,96 +0,0 @@ -/* - The MIT License (MIT) - -Copyright (c) 2019 Microsoft Corporation - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - */ - -using Microsoft.Extensions.Configuration; -using System; -using System.Globalization; -using System.IO; - -namespace DeltaQueryApplication -{ - /// - /// Description of the configuration of an AzureAD public client application (desktop/mobile application). This should - /// match the application registration done in the Azure portal - /// - public class AppConfiguration - { - /// - /// instance of Azure AD, for example public Azure or a Sovereign cloud (Azure China, Germany, US government, etc ...) - /// - public string Instance { get; set; } = "https://login.microsoftonline.com/{0}"; - - /// - /// The Tenant is: - /// - either the tenant ID of the Azure AD tenant in which this application is registered (a guid) - /// or a domain name associated with the tenant - /// - or 'organizations' (for a multi-tenant application) - /// - public string TenantId { get; set; } - - /// - /// Guid used by the application to uniquely identify itself to Azure AD - /// - public string ClientId { get; set; } - - /// - /// URL of the authority - /// - public string Authority - { - get - { - return String.Format(CultureInfo.InvariantCulture, Instance, TenantId); - } - } - - /// - /// Base URL for the Microsoft Graph endpoint (depends on the Azure Cloud) - /// - public string MicrosoftGraphBaseEndpoint { get; set; } - - - - /// - /// Period at which to check for updates/changes in seconds - /// - public int PullIntervalSec { get; set; } - - /// - /// Reads the configuration from a json file - /// - /// Path to the configuration json file - /// AuthenticationConfig read from the json file - public static AppConfiguration ReadFromJsonFile(string path) - { - IConfigurationRoot Configuration; - - var builder = new ConfigurationBuilder() - .SetBasePath(Directory.GetCurrentDirectory()) - .AddJsonFile(path); - - Configuration = builder.Build(); - return Configuration.Get(); - } - } -} diff --git a/ConsoleApplication/DeltaQueryConsoleApplication.csproj b/ConsoleApplication/DeltaQueryConsoleApplication.csproj deleted file mode 100644 index 45d41b0..0000000 --- a/ConsoleApplication/DeltaQueryConsoleApplication.csproj +++ /dev/null @@ -1,150 +0,0 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {FE14AE0B-4328-4633-ABFA-C87000175BD2} - {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Exe - DifferentialQueryConsoleApplication - dq - 4.4.0.14 - v4.6.1 - 512 - 1.0.0.0 - - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - - true - bin\x64\Debug\ - DEBUG;TRACE - full - x64 - prompt - MinimumRecommendedRules.ruleset - false - - - bin\x64\Release\ - TRACE - true - pdbonly - x64 - prompt - MinimumRecommendedRules.ruleset - false - - - true - - - - - - - - - - - - Designer - - - Always - - - - - - ..\packages\Microsoft.Extensions.Configuration.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll - - - ..\packages\Microsoft.Extensions.Configuration.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll - - - ..\packages\Microsoft.Extensions.Configuration.Binder.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Binder.dll - - - ..\packages\Microsoft.Extensions.Configuration.FileExtensions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.FileExtensions.dll - - - ..\packages\Microsoft.Extensions.Configuration.Json.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Json.dll - - - ..\packages\Microsoft.Extensions.FileProviders.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Abstractions.dll - - - ..\packages\Microsoft.Extensions.FileProviders.Physical.2.2.0\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Physical.dll - - - ..\packages\Microsoft.Extensions.FileSystemGlobbing.2.2.0\lib\netstandard2.0\Microsoft.Extensions.FileSystemGlobbing.dll - - - ..\packages\Microsoft.Extensions.Primitives.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll - - - ..\packages\Microsoft.Graph.1.12.0\lib\net45\Microsoft.Graph.dll - - - ..\packages\Microsoft.Graph.Core.1.12.0\lib\net45\Microsoft.Graph.Core.dll - - - ..\packages\Microsoft.Identity.Client.2.7.0\lib\net45\Microsoft.Identity.Client.dll - - - ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll - - - - ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll - - - - - - - - - ..\packages\System.Memory.4.5.1\lib\netstandard2.0\System.Memory.dll - - - - - ..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll - - - ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.1\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll - - - - - - - - - - - \ No newline at end of file diff --git a/ConsoleApplication/Helpers/Constants.cs b/ConsoleApplication/Helpers/Constants.cs deleted file mode 100644 index 50ce3b5..0000000 --- a/ConsoleApplication/Helpers/Constants.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* - The MIT License (MIT) - -Copyright (c) 2019 Microsoft Corporation - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - */ - -namespace DeltaQueryApplication -{ - /// - /// This class contains the constant fields used in this sample. - /// - internal static class Constants - { - - /// - /// Feed annotation that represents a URI to be called immediately for more changes. - /// - public const string DeltaLinkFeedAnnotation = "@odata.deltaLink"; - - /// - /// String url for the default scope in MS Graph - /// - public const string DefaultScope = "https://graph.microsoft.com/.default"; - } -} \ No newline at end of file diff --git a/ConsoleApplication/Helpers/GraphClientFactory.cs b/ConsoleApplication/Helpers/GraphClientFactory.cs deleted file mode 100644 index 02a92b1..0000000 --- a/ConsoleApplication/Helpers/GraphClientFactory.cs +++ /dev/null @@ -1,61 +0,0 @@ -/* - The MIT License (MIT) - -Copyright (c) 2019 Microsoft Corporation - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - */ - -using Microsoft.Graph; -using Microsoft.Identity.Client; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace DeltaQueryApplication -{ - public static class GraphClientFactory - { - /// - /// Helper to generate an instance of a usable Graphclient class - /// Client id for the application needing to make graph calls - /// Url to provide authority for the tenant - /// Scopes to be used by the application - /// - public static GraphServiceClient GetGraphServiceClient(string clientId, string authority, string[] scopes) - { - var authenticationProvider = CreateAuthorizationProvider(clientId, authority, scopes); - return new GraphServiceClient(authenticationProvider); - } - - /// - /// Helper to generate an instance of a IAuthenticationProvider - /// Client id for the application needing to make graph calls - /// Url to provide authority for the tenant - /// Scopes to be used by the application - /// - private static IAuthenticationProvider CreateAuthorizationProvider(string clientId, string authority, string[] scopes) - { - var clientApplication = new PublicClientApplication(clientId, authority); - return new MsalAuthenticationProvider(clientApplication, scopes.ToArray()); - } - } -} diff --git a/ConsoleApplication/Helpers/MsalAuthenticationProvider.cs b/ConsoleApplication/Helpers/MsalAuthenticationProvider.cs deleted file mode 100644 index f659dbc..0000000 --- a/ConsoleApplication/Helpers/MsalAuthenticationProvider.cs +++ /dev/null @@ -1,86 +0,0 @@ -/* - The MIT License (MIT) - -Copyright (c) 2019 Microsoft Corporation - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - */ - -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; -using Microsoft.Identity.Client; -using Microsoft.Graph; -using System.Collections.Generic; -using System.Linq; - -namespace DeltaQueryApplication -{ - // This class encapsulates the details of getting a token from MSAL and exposes it via the - // IAuthenticationProvider interface so that GraphServiceClient or AuthHandler can use it. - // A significantly enhanced version of this class will in the future be available from - // the GraphSDK team. It will supports all the types of Client Application as defined by MSAL. - public class MsalAuthenticationProvider : IAuthenticationProvider - { - private PublicClientApplication _clientApplication; - private IEnumerable _scopes; - - /// - /// Constructor for the MsalAuthenticationProvider - /// Client application to be used by the class - /// Scopes to be used by the class - /// - public MsalAuthenticationProvider(PublicClientApplication clientApplication, IEnumerable scopes) { - _clientApplication = clientApplication; - _scopes = scopes; - } - - /// - /// Update HttpRequestMessage with credentials - /// Http request to update with credentials - /// - public async Task AuthenticateRequestAsync(HttpRequestMessage request) - { - var token = await GetTokenAsync(); - request.Headers.Authorization = new AuthenticationHeaderValue("bearer", token); - } - - /// - /// Acquire Token - /// - public async Task GetTokenAsync() - { - AuthenticationResult authResult = null; - var accounts = await _clientApplication.GetAccountsAsync(); - IAccount account = accounts.FirstOrDefault(); // Supposing here there is only one user to the app - - try - { - // Benefit from the token cache, and automatic token refresh - authResult = await _clientApplication.AcquireTokenSilentAsync(_scopes, account); - } - catch (MsalUiRequiredException) - { - authResult = await _clientApplication.AcquireTokenAsync(_scopes); - } - return authResult.AccessToken; - - } - } -} \ No newline at end of file diff --git a/ConsoleApplication/Helpers/PageIterator.cs b/ConsoleApplication/Helpers/PageIterator.cs deleted file mode 100644 index ca399b9..0000000 --- a/ConsoleApplication/Helpers/PageIterator.cs +++ /dev/null @@ -1,90 +0,0 @@ -/* - The MIT License (MIT) - -Copyright (c) 2019 Microsoft Corporation - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - */ - -namespace DeltaQueryApplication -{ - using System.Threading.Tasks; - using System; - using Microsoft.Graph; - - /// - /// Iterator for walking entities and pages of entities. - /// - /// This class will be incorporated as a generic capability in the SDK as soon as - /// we have a standard interface for collections. Currently CollectionPage classes do not share - /// any base class or interface so it is difficult to write generic class to support the paging behavior. - /// - public class PageIterator - { - private IMailFolderDeltaCollectionPage mailfolders; - private readonly Action callback; - - /// - /// String token used for making request to Graph API to check - /// for changes in the collection - /// - public string DeltaLink { get; private set; } - - /// - /// Constructor for the PageIterator - /// Instance of that holds - /// the collection mail folders to be processed. - /// Call back to process each item in collection. - /// - public PageIterator(IMailFolderDeltaCollectionPage mailFolders, Action callback) - { - this.mailfolders = mailFolders; - this.callback = callback; - } - - /// - /// Iterate through the mailfolders collection and process each item with the provided callback. - /// - public async Task Iterate() - { - var more = true; - while (more) - { - foreach (var item in this.mailfolders) - { - callback(item); - } - - if (mailfolders.NextPageRequest != null) - { - this.mailfolders = await mailfolders.NextPageRequest.GetAsync(); - } - else - { - more = false; - } - - if (this.mailfolders.AdditionalData.ContainsKey(Constants.DeltaLinkFeedAnnotation)) - { - DeltaLink = this.mailfolders.AdditionalData[Constants.DeltaLinkFeedAnnotation] as string; - } - } - } - } -} diff --git a/ConsoleApplication/Program.cs b/ConsoleApplication/Program.cs deleted file mode 100644 index 886af4f..0000000 --- a/ConsoleApplication/Program.cs +++ /dev/null @@ -1,168 +0,0 @@ -/* - The MIT License (MIT) - -Copyright (c) 2019 Microsoft Corporation - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - */ - -namespace DeltaQueryApplication -{ - using System.Configuration; - using System.Threading.Tasks; - using System; - using System.IO; - using System.Collections.Generic; - using System.Diagnostics; - using Microsoft.Graph; - using Microsoft.Identity.Client; - - /// - /// Delta Query sample console application - /// - public class Program - { - - private static GraphServiceClient _graphServiceClient; - - /// - /// Application entry point - /// - private static void Main() - { - AppConfiguration appConfiguration = AppConfiguration.ReadFromJsonFile("appsettings.json"); - - _graphServiceClient = - GraphClientFactory.GetGraphServiceClient( - appConfiguration.ClientId, - appConfiguration.Authority, - new string[] { Constants.DefaultScope }); - - // Start watching mail folders - try - { - Task.Run(() => WatchMailFolders(appConfiguration.PullIntervalSec)).Wait(); - } - catch (MsalServiceException mse) - { - ProcessMsalException(mse); - } - catch (MsalException me) - { - // For memory, we need to revisit this - // There will be an Http timeout exception in MSAL 3.0 - Console.WriteLine(me.Message); - Console.WriteLine("Error occured (MsalException) with Graph call"); - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - } - Console.ReadLine(); - } - - /// - /// Method for watching for changes in MailFolders - /// - /// - /// - public static async Task WatchMailFolders(int pullIntervalSec) - { - // Retreive first page of mailfolders - IMailFolderDeltaCollectionPage deltaCollection; - deltaCollection = await _graphServiceClient.Me.MailFolders.Delta().Request().GetAsync(); - - while (true) - { - // Iterate over pages of mailfolders and record DeltaLink in last page - var changedMailFolders = new List(); - var iterator = new PageIterator(deltaCollection, (m)=> changedMailFolders.Add(m)); - await iterator.Iterate(); - - if (changedMailFolders.Count == 0) - { - Console.WriteLine("No changes"); - } - else - { - foreach (MailFolder mailfolder in changedMailFolders) - { - string mailfolderName = mailfolder.DisplayName; - bool isDeleted = mailfolder.AdditionalData != null ? mailfolder.AdditionalData.ContainsKey("@removed") : false; - if (isDeleted) - { - Console.WriteLine($"Object {mailfolderName} deleted"); // Interactively deleting MailFolders actually only moves them to DeletedItems so they show as "updated". - } - else - { - Console.WriteLine($"Object {mailfolderName} created/updated"); - } - } - } - - // Delta query should return DeltaLink for us to make another query in the future. - if (iterator.DeltaLink != null) - { - Console.WriteLine( - "Processed change(s) successfully. Will check back in {0} sec.", - pullIntervalSec); - await Task.Delay(pullIntervalSec * 1000); - - // Request Mailfolders changed since last call - deltaCollection.InitializeNextPageRequest(_graphServiceClient, iterator.DeltaLink); - deltaCollection = await deltaCollection.NextPageRequest.GetAsync(); - } - } - } - - /// - /// Method for handling exceptions thrown by the MSAL library. - /// - /// Intance of an excpetion of the type > - /// - private static void ProcessMsalException(MsalServiceException mse) - { - switch (mse.ErrorCode) - { - case MsalServiceException.InvalidAuthority: - // What happens: When the library attempts to discover the authority and get the endpoints it - // needs to acquire a token, it got an un-authorize HTTP code or an unexpected response - // Remediation: - // Check that the authority configured for the application, or passed on some overrides - // of token acquisition tokens supporting authority override is correct - case "unauthorized_client": - // For instance: AADSTS700016: Application with identifier '{clientId}' was not found in the directory '{domain}'. - // This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. - // You may have sent your authentication request to the wrong tenant - // Cause: The clientId in the app.config is wrong - // Remediation: check the clientId and the app registration - Console.WriteLine("The application is not configured correctly with Azure AD"); - break; - case MsalServiceException.RequestTimeout: - case MsalServiceException.ServiceNotAvailable: - Console.WriteLine("Acquiring a security token to call Graph failed. Please try later"); - break; - default: - Console.WriteLine(mse.Message); - Console.WriteLine("Error occured with Graph call"); - break; - } - } - } -} diff --git a/ConsoleApplication/app.config b/ConsoleApplication/app.config deleted file mode 100644 index 4a96db7..0000000 --- a/ConsoleApplication/app.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/ConsoleApplication/appsettings.json.example b/ConsoleApplication/appsettings.json.example deleted file mode 100644 index 70714d9..0000000 --- a/ConsoleApplication/appsettings.json.example +++ /dev/null @@ -1,34 +0,0 @@ -{ - // Azure Cloud instance among: - // - https://login.microsoftonline.com/{0} for the AzurePublic - // (see https://aka.ms/aaddevv2). This is the default value - // - https://login.microsoftonline.us/{0} for AzureUsGovernment - // (see https://docs.microsoft.com/azure/azure-government/documentation-government-developer-guide) - // - https://login.partner.microsoftonline.cn/{0} for AzureChina - // (see https://docs.microsoft.com/azure/china/china-get-started-developer-guide) - // - https://login.microsoftonline.de/{0} for AzureGermany - // (See https://docs.microsoft.com/azure/germany/germany-developer-guide) - "Instance": "https://login.microsoftonline.com/{0}", - - - // Azure AD Audience among: - // - tenant ID or domain (only in your organization) - // - "organizations" (multi-tenant): Any work and school accounts - // - "common" (any work and school account or Microsoft personal account) - // - "consumers" (Microsoft personal account only) - // Note that this sample uses username/password which does not allow common or consumer - "TenantId": "common", - - - // ClientId (ApplicationId) as copied from the application registration (which depends on the cloud instance) - // See docs referenced in the AzureCloudInstance section above - "ClientId": "YOUR_CLIENT_ID_HERE", - - // Web API. Here Microsoft Graph. The endpoint is different depending on the cloud instance - // (See docs referenced in the "Instance" section above. - "MicrosoftGraphBaseEndpoint": "https://graph.microsoft.com", - - //Period to refresh the delta query to check for changes/updates in seconds - "PullIntervalSec" : 60, - -} \ No newline at end of file diff --git a/ConsoleApplication/packages.config b/ConsoleApplication/packages.config deleted file mode 100644 index 7c11783..0000000 --- a/ConsoleApplication/packages.config +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/DeltaQuerySample.sln b/DeltaQuerySample.sln deleted file mode 100644 index 86c9401..0000000 --- a/DeltaQuerySample.sln +++ /dev/null @@ -1,31 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28010.2003 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeltaQueryConsoleApplication", "ConsoleApplication\DeltaQueryConsoleApplication.csproj", "{FE14AE0B-4328-4633-ABFA-C87000175BD2}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {FE14AE0B-4328-4633-ABFA-C87000175BD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FE14AE0B-4328-4633-ABFA-C87000175BD2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FE14AE0B-4328-4633-ABFA-C87000175BD2}.Debug|x64.ActiveCfg = Debug|x64 - {FE14AE0B-4328-4633-ABFA-C87000175BD2}.Debug|x64.Build.0 = Debug|x64 - {FE14AE0B-4328-4633-ABFA-C87000175BD2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FE14AE0B-4328-4633-ABFA-C87000175BD2}.Release|Any CPU.Build.0 = Release|Any CPU - {FE14AE0B-4328-4633-ABFA-C87000175BD2}.Release|x64.ActiveCfg = Release|x64 - {FE14AE0B-4328-4633-ABFA-C87000175BD2}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {19CAD7FA-EBFB-47E7-94ED-ECEE3661264B} - EndGlobalSection -EndGlobal diff --git a/NuGet.config b/NuGet.config deleted file mode 100644 index 8b5ff49..0000000 --- a/NuGet.config +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file From e3dddc6e5e230f7a3e7bcf394c45737bdd6d3c00 Mon Sep 17 00:00:00 2001 From: Jason Johnston Date: Mon, 27 Jan 2020 11:23:21 -0500 Subject: [PATCH 2/7] Simplified app registration script --- AppCreationScripts/AppCreationScripts.md | 146 ----------------------- AppCreationScripts/sample.json | 54 --------- README.md | 124 ++++++++----------- RegisterApp.ps1 | 68 +++++++++++ images/aad-application-id.png | Bin 0 -> 9589 bytes images/aad-default-client-type.png | Bin 0 -> 7725 bytes images/aad-portal-app-registrations.png | Bin 0 -> 68909 bytes images/aad-redirect-uris.png | Bin 0 -> 18700 bytes images/aad-register-an-app.png | Bin 0 -> 35516 bytes 9 files changed, 116 insertions(+), 276 deletions(-) delete mode 100644 AppCreationScripts/AppCreationScripts.md delete mode 100644 AppCreationScripts/sample.json create mode 100644 RegisterApp.ps1 create mode 100644 images/aad-application-id.png create mode 100644 images/aad-default-client-type.png create mode 100644 images/aad-portal-app-registrations.png create mode 100644 images/aad-redirect-uris.png create mode 100644 images/aad-register-an-app.png diff --git a/AppCreationScripts/AppCreationScripts.md b/AppCreationScripts/AppCreationScripts.md deleted file mode 100644 index 68a7817..0000000 --- a/AppCreationScripts/AppCreationScripts.md +++ /dev/null @@ -1,146 +0,0 @@ -# Registering the Azure Active Directory applications and updating the configuration files for this sample 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 Azure AD application and configure the code of the sample application accordinly. (Other ways of running the scripts are described below) - ```PowerShell - .\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) - -## Goal of the scripts - -### Presentation of the scripts - -This sample comes with two PowerShell scripts, which automate the creation of the Azure Active Directory applications, and the configuration of the code for this sample. Once you run them, you will only need to build the solution and you are good to test. - -These scripts are: - -- `Configure.ps1` which: - - creates Azure AD applications and their related objects (permissions, dependencies, secrets), - - 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 Azure AD application it created: - - the identifier of the application - - the AppId of the application - - the url of its registration in the [Azure portal](https://portal.azure.com). - -- `Cleanup.ps1` which cleans-up the Azure AD objects created by `Configure.ps1`. Note that this script does not revert the changes done in the configuration files, though. You will need to undo the change from source control (from Visual Studio, or from the command line using, for instance, git reset). - -### Usage pattern for tests and DevOps scenarios - -The `Configure.ps1` will stop if it tries to create an Azure AD application which already exists in the tenant. For this, if you are using the script to try/test the sample, or in DevOps scenarios, you might want to run `Cleanup.ps1` just before `Configure.ps1`. This is what is shown in the steps below. - -## How to use the app creation scripts ? - -### Pre-requisites - -1. Open PowerShell (On Windows, press `Windows-R` and type `PowerShell` in the search window) -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 indentity 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 [Azure portal](https://portal.azure.com) -- Select the Azure Active directory you are interested in (in the combo-box below your name on the top right of the browser window) -- Find the "Active Directory" object in this tenant -- Go to **Properties** and copy the content of the **Directory Id** property -- Then use the full syntax to run the scripts: - -```PowerShell -$tenantId = "yourTenantIdGuid" -. .\Cleanup.ps1 -TenantId $tenantId -. .\Configure.ps1 -TenantId $tenantId -``` - -#### 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 -``` diff --git a/AppCreationScripts/sample.json b/AppCreationScripts/sample.json deleted file mode 100644 index fba0b47..0000000 --- a/AppCreationScripts/sample.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "Sample": { - "Title": "Invoking an API protected by Azure AD with Integrated Windows Authentication, on a Windows domain jointed or AAD joined machine", - "Level": 200, - "Client": ".NET console app", - "Service": "Microsoft Graph", - "RepositoryUrl": "consoleApp-deltaQuery-dotNet-sample", - "Endpoint": "AAD v2.0" - }, - - /* - This section describes the Azure AD Applications to configure, and their dependencies - */ - "AADApps": [ - { - "Id": "client", - "Name": "ConsoleApp-DeltaQuery-DotNet", - "Kind": "Desktop", - "UsesROPCOrIWA": true, - "Audience": "AzureADMultipleOrgs", - "RequiredResourcesAccess": [ - { - "Resource": "Microsoft Graph", - "DelegatedPermissions": [ "Mail.Read" ] - } - ], - "ManualSteps": [ - { - "Comment" : "Navigate to the API permissions page and click on 'Grant admin consent for {tenant}'" - } - ] - } - ], - - /* - 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": "\\..\\ConsoleApplication\\appsettings.json", - "Mappings": [ - { - "key": "ClientId", - "value": ".AppId" - } - ] - } - ] -} diff --git a/README.md b/README.md index 87dceb6..7d6686c 100644 --- a/README.md +++ b/README.md @@ -5,122 +5,94 @@ products: languages: - csharp extensions: - contentType: samples + contentType: samples technologies: - Microsoft Graph createdDate: 5/25/2017 5:03:53 PM --- -# ConsoleApp-MicrosoftGraphAPI-DeltaQuery-DotNet +# Microsoft Graph delta query sample -This console application demonstrates how to make Delta Query calls to the Graph API, allowing applications to request only changed data from Microsoft Graph tenants. - -The sample uses demonstates how graph calls can be made with the Graph SDK and how the reponses can be handled. - -The specific example used in this sample involves monitoring changes(addition and removal) of MailFolders in an individual's email account. +This console application demonstrates how to make [delta queries](https://docs.microsoft.com/graph/delta-query-overview) to Microsoft Graph, allowing applications to request only changed entities within a target resource. This sample monitors changes of messages in the user's inbox. ## How To Run This Sample To run this sample you will need: -- Visual Studio 2017 -- An Internet connection -- An Azure Active Directory (Azure AD) tenant. For more information on how to get an Azure AD tenant, please see [How to get an Azure AD tenant](https://azure.microsoft.com/en-us/documentation/articles/active-directory-howto-tenant/) -### Step 1: Clone or download this repository +- The [.NET Core 3.1 SDK](https://dotnet.microsoft.com/download) +- A user in a Microsoft 365 tenant with an Exchange Online mailbox. -From your shell or command line: +### Step 1: Register the sample application in Azure Active Directory -`git clone https://github.com/microsoftgraph/ConsoleApp-DeltaQuery-DotNet` +Before running the sample, you will need to create an app registration in Azure Active Directory to obtain an application ID. You can do this with the PowerShell script in this sample, or you can register it manually in the Azure Active Directory portal. -### Step 2: Register the sample application with your Azure Active Directory tenant +#### Option 1: Register with PowerShell -There is one project in this sample. To register it, you can: +The [RegisterApp.ps1](RegisterApp.ps1) script uses the [Azure AD PowerShell for Graph module](https://docs.microsoft.com/powershell/azure/active-directory/install-adv2?view=azureadps-2.0) to create the app registration. -- either follow the steps [Step 2: Register the sample with your Azure Active Directory tenant](#step-2-register-the-sample-with-your-azure-active-directory-tenant) and [Step 3: Configure the sample to use your Azure AD tenant](#choose-the-azure-ad-tenant-where-you-want-to-create-your-applications) -- or use PowerShell scripts that: - - **automatically** creates the Azure AD applications and related objects (passwords, permissions, dependencies) for you - - modify the Visual Studio projects' configuration files. +1. Open Windows PowerShell in the root directory of this sample. -If you want to use this automation: +1. If you do not have the Azure AD PowerShell module installed, run the following command to install it: -1. On Windows run PowerShell and navigate to the root of the cloned directory -1. In PowerShell run: + ```PowerShell + Install-Module AzureAD + ``` - ```PowerShell - Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process -Force - ``` +1. Run the following command to set the execution policy for the current PowerShell window to allow the script to run. -1. Run the script to create your Azure AD application and configure the code of the sample application accordinly. + ```PowerShell + Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process + ``` - ```PowerShell - .\AppCreationScripts\Configure.ps1 - ``` +1. Run the script with the following command. - > Other ways of running the scripts are described in [App Creation Scripts](./AppCreationScripts/AppCreationScripts.md) + ```PowerShell + ./RegisterApp.ps1 + ``` -1. Open the Visual Studio solution and click start +1. In the pop-up window, sign in using a Microsoft 365 user that has permission to register an application in Azure Active Directory. -If you don't want to use this automation, follow the steps below +1. The application ID is printed to the console. -#### Choose the Azure AD tenant where you want to create your applications + ```PowerShell + App creation successful. Your app ID is: b730d25e-c81c-4046-a49c-ac56c07e930a + ``` -As a first step you'll need to: +#### Option 2: Register with the Azure Active Directory admin center -1. Sign in to the [Azure portal](https://portal.azure.com) using either a work or school account or a personal Microsoft account. -1. If your account gives you access to more than one tenant, select your account in the top right corner, and set your portal session to the desired Azure AD tenant - (using **Switch Directory**). -1. In the left-hand navigation pane, select the **Azure Active Directory** service, and then select **App registrations (Preview)**. +1. Open a browser and navigate to the [Azure Active Directory admin center](https://aad.portal.azure.com) and login using a Microsoft 365 user that has permission to register an application in Azure Active Directory. -#### Register the client app (ConsoleApp-DeltaQuery-DotNet) +1. Select **Azure Active Directory** in the left-hand navigation, then select **App registrations** under **Manage**. -1. In **App registrations (Preview)** page, select **Register an Application**. -1. When the **Register an application page** 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 `ConsoleApp-DeltaQuery-DotNet`. - - In the **Supported account types** section, select **Accounts in any organizational directory and personal Microsoft accounts (e.g. Skype, Xbox, Outlook.com)**. - - Select **Register** to create the application. -1. On the app **Overview** page, find the **Application (client) ID** value and record it for later. You'll need it to configure the Visual Studio configuration file for this project. -1. In the list of pages for the app, select **Authentication** - - In the *Suggested Redirect URIs for public clients(mobile,desktop)*, check the second box so that the app can work with the MSAL libs used in the application. (The box should contain the option *urn:ietf:wg:oauth:2.0:oob*). -1. In the list of pages for the app, select **API permissions** - - 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, ensure that the right permissions are checked: **Mail.Read**. Use the search box if necessary. - - Select the **Add permissions** button + ![A screenshot of the App registrations ](./images/aad-portal-app-registrations.png) -### Step 3: Configure the sample to use your Azure AD tenant +1. Select **New registration**. On the **Register an application** page, set the values as follows. -In the steps below, "ClientID" is the same as "Application ID" or "AppId". + - Set **Name** to `Delta Query Console Sample`. + - Set **Supported account types** to **Accounts in any organizational directory and personal Microsoft accounts**. + - Leave **Redirect URI** empty. -Open the solution in Visual Studio to configure the projects + ![A screenshot of the Register an application page](./images/aad-register-an-app.png) -#### Configure the client project +1. Select **Register**. On the **Delta Query Console Sample** page, copy the value of the **Application (client) ID** and save it, you will need it in the next step. -1. In the *ConsoleApplication* folder, rename the `appsettings.json.example` file to `appsettings.json` -1. Open and edit the `appsettings.json` file to make the following change - 1. Find the line where `ClientId` is set as `YOUR_CLIENT_ID_HERE` and replace the existing value with the application ID (clientId) of the `ConsoleApp-DeltaQuery-DotNet` application copied from the Azure portal. + ![A screenshot of the application ID of the new app registration](./images/aad-application-id.png) -Clean the solution, rebuild the solution, and start it in the debugger. +1. Select the **Add a Redirect URI** link. On the **Redirect URIs** page, locate the **Suggested Redirect URIs for public clients (mobile, desktop)** section. Select the `https://login.microsoftonline.com/common/oauth2/nativeclient` URI. -## Contributing + ![A screenshot of the Redirect URIs page](./images/aad-redirect-uris.png) -If you'd like to contribute to this sample, see [CONTRIBUTING.MD](/CONTRIBUTING.md). +1. Locate the **Default client type** section and change the **Treat application as a public client** toggle to **Yes**, then choose **Save**. -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. + ![A screenshot of the Default client type section](./images/aad-default-client-type.png) -## Questions and comments +### Step 2: Configure the sample -We'd love to get your feedback about the Microsoft Graph Webhooks sample using WebJobs SDK. You can send your questions and suggestions to us in the [Issues](https://github.com/microsoftgraph/ConsoleApp-DeltaQuery-DotNet/issues) section of this repository. +### Step 3: Run the sample -Questions about Microsoft Graph in general should be posted to [Stack Overflow](https://stackoverflow.com/questions/tagged/MicrosoftGraph). Make sure that your questions or comments are tagged with *[MicrosoftGraph]*. - -If you have a feature suggestion, please post your idea on our [User Voice](https://officespdev.uservoice.com/) page, and vote for your suggestions there. +## Contributing -## Additional resources +If you'd like to contribute to this sample, see [CONTRIBUTING.MD](/CONTRIBUTING.md). -- [AAD DQ sample](https://github.com/Azure-Samples/active-directory-dotnet-graphapi-diffquery) -- [Working with Delta Query in Microsoft Graph](https://developer.microsoft.com/en-us/graph/docs/concepts/delta_query_overview) -- [Microsoft Graph developer site](https://developer.microsoft.com/en-us/graph/) -- [Call Microsoft Graph in an ASP.NET MVC app](https://developer.microsoft.com/en-us/graph/docs/platform/aspnetmvc) -- [MSAL.NET](https://aka.ms/msal-net) +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. -Copyright (c) 2019 Microsoft Corporation. All rights reserved. +Copyright (c) 2020 Microsoft Corporation. All rights reserved. diff --git a/RegisterApp.ps1 b/RegisterApp.ps1 new file mode 100644 index 0000000..83b425b --- /dev/null +++ b/RegisterApp.ps1 @@ -0,0 +1,68 @@ +[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 +) + +<# + This script creates the Azure AD application needed for this sample. + + 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 +#> + +# If user passed credentials, use those +# Otherwise, prompt the user to sign in +if ($Credential) +{ + $session = Connect-AzureAD -Credential $Credential +} +else +{ + $session = Connect-AzureAD +} + +# Get the user's object from Azure AD, we need the object ID +$user = Get-AzureADUser -ObjectId $session.Account.Id + +Write-Host "Creating app registration..." -NoNewline + +# Create the application +# Reply url: This is the standard reply URL used by MSAL with the device code flow +# Available to other tenants: Set to true here for simplification (don't need to specify tenant ID) +# Public client: Necessary to enable the device code flow +$app = New-AzureADApplication -DisplayName "Delta Query Console Sample" ` + -ReplyUrls "https://login.microsoftonline.com/common/oauth2/nativeclient" ` + -AvailableToOtherTenants $true ` + -PublicClient $true + +Write-Host "DONE" -ForeGroundColor Green + +Write-Host "Creating service principal..." -NoNewline + +# Create the app's service principal +$servicePrincipal = New-AzureADServicePrincipal -AppId $app.AppId -Tags {WindowsAzureActiveDirectoryIntegratedApp} + +Write-Host "DONE" -ForeGroundColor Green + +# If the user was not added as an owner, add them now +$owner = Get-AzureADApplicationOwner -ObjectId $app.ObjectId +if ($null -eq $owner) +{ + Write-Host "Adding $($user.DisplayName) (object ID $($user.ObjectId)) as owner..." -NoNewline + + # Add the user as the owner of the application + # This conforms with the behavior in the Azure portal + Add-AzureADApplicationOwner -ObjectId $app.ObjectId -RefObjectId $user.ObjectId + + Write-Host "DONE" -ForeGroundColor Green +} + +Write-Host "" +Write-Host "App creation successful. Your app ID is: " -NoNewline +Write-Host $($app.AppId) -ForegroundColor Cyan + +Disconnect-AzureAD \ No newline at end of file diff --git a/images/aad-application-id.png b/images/aad-application-id.png new file mode 100644 index 0000000000000000000000000000000000000000..b4536c75216d7e5b11312f52fd99d69b7f1be800 GIT binary patch literal 9589 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 literal 0 HcmV?d00001 diff --git a/images/aad-default-client-type.png b/images/aad-default-client-type.png new file mode 100644 index 0000000000000000000000000000000000000000..6e63e2962bf7ebe88e7d28b234c7d737bc69901e GIT binary patch literal 7725 zcmch6bx_n@xIc)3LFkJ#h=_+9?1=jZS59~c-I6ciK^5)v93 z8Wt879v&VM5fK#?6&)QN8ylODkdT;|h(I8cl9G~>lT%VskVxdWZ{Jc=Q`6JaGcqzz zD3ot_Q)oy%!oNB;09P7TQyJfwnVFfDm6el|lbf5HmzS5HpI=y5SX5M0Qc_Y{T3S|C z_Wk?!^73*l7F$_aSzTRSQ&Ur0TU%FGS6^S>(9qD>*x1z66wovo_+A3DA8ntS=$aWA82I(;*U-?=@bK`+$jIpE=-AlU z`1tt5#Kh#}h`gHGH^Tt^(Vf*LS8Gh%iZ|8hq?r3P?cw%jDWbd3f zvAi_7GCMmvH#avwKfkcBu(-HLAP|T|;?mO6>fHL@zkipPmseI+R##Wo*4Eb7*Eg?d zX?yPQeE#r)xO4P(>ul}hVs~SIYinzJdwXYRXLomZe}Dhr;NWoYX!rPZ_v~Wt=zRbD z;`rd?=;-L=goG{lUy#1fru8Es zVXjh^mxZ_)t*1w!42ShPX|KgmQT6aE@|Li0s6Bsumxl^#O;<@zXCpWS4E}^Hw;E$! zN!*(6a8=8fd=zRDgf>Q8wfwMAyAsz=UI>>$_-aQTvyFc>ge}PX7O%eHjs zO>21=Ic{oSfR6#k&Tw)${|;$yp`evS^I!qs~}X>(mI%ENmYD44+# zNT3-^$0e9skmHd}&%P0@ubXCh=pe;KPfu9s+Iqu`4qE}24fH{VT70sP)v#^S!)P5j zMDgG%ob#AesHT3vm%`K2lbd^cb^$v?y$@A)%{Vc~UMBP;e-ITK9vvDI-T&RGuID<; zo6VUX1ialu8ppNKr2TT9NO=2THC2Ury4G|Yy%cM9s#Z{cs);NcaMWWw{!6TmuNJZY zYCT&!`Oe_$u3Z#U#N3HU0e6Y@zc57LR@Zn0UPn>N=6-2gEv2 z3i)Sb_{Bdx-8@D#NbN(vUVIi$H39Y1lL^rfV{a)10U?SaO(OOC-|s7^zSFlD@52QZ zuF+B!u&or=TM}M`JdoPY(kj~f=5{!UY&uy_E+^!(yYaXa@G4iNT9$p?L7Z;TDxqY~ zzezPUdAYeRVOt|mKS#yFYkdeEokp+1+C))1$j_x-e=EEX>vtA6@k!9eBKu_Zhvswp z&_6La1?$W&Yb+@DQ8JDSyQS`$VxOXF*q?{dLysy!hkJadEi$vOjxohoK`@eA==HZc zS)hrK(^ergn(j1_5(R|VZxZZYD$krug=Yw5fDsAfsh*xXUKbjAge4vRNx-mb3zsn| z?(Z|7udQBp?$E_IdHzqBkN_IG0S>7~9cwK(4@3`1E5Qh(o6B{_-;38i2jrl4)}EI| z)Bx(DVgM~==Q4dMmiE^FADkb5Jz#9FWpF^GbD9uYopledm13PAq_G=Th)(a~+K!=*amj;vGJEhnma_GcVmE+#_ z;AE9kqFdeG(cg|qyPzveSs+#wmgYb9WRi`J{9IN?xWXjszf9K(z+}7}rfX>|*!!Bc z1TbEwiHb@GW7${A6m(LhQa3J7d}Pj9mNIH`xzr^O+umK`W%SrSI$!2vd){li^P%3R zi^F+&_6PMJ3W$DES1B%t_v&4b%-2a)A@i`bD5x{9WWrslE?wpyk3V8azvL>;{kXwi z9`po~bP3KaAj*i+I@=XJ(7=7e-4Rw$B2Wc#j*%(l|)5e0p5({c7o1UOq#0*2imH^)>G9khe5{ml0}RbH@+RB5^cq0=59>1r=ea}7 zi_?s)NMAs|$xhGLe8&Fpuw=JcxD=mrj*d>Ssj%H+znuC}ve*GDYi<)2s2El}lW*hc zXz8(UUMLo2{XHBUxiPpzgeI|gFA4rhNnuMTyhRk5o4&Sac7G}&sPS#ZEJIKm={#D* ztuo1_jMjTU|44x~z|71hTPKb>Qz8$gf30I}UGPL@p7hP`^EF#N7z6QpvGEAW!XN>KkyxxWwwK9Rz`Y75Hha++&=Y zi!RiKY!b|*p~#sQHMCu;J{@gJwF8tHtEp$(i^fAW$8VE;BzMt{~JKk27;f*S25@#5m z(1%!##3KYFO?LqC7fXd*ft1?bX+K{#;|+1bBqJ?@Tw35itYVat8pqsSb!MC3vEmRJvvSD zbQku(+W*%eQ)Ipag5hqFNS)&4f^`L!JR^F6a$&CLV7}#_VmJNbqJYA*DTm{h#e0jk zXO(4nyMWppNZ_H?N4Lt&Ase`a;hv?w+UXD1%6>;sx0Unc-=++ojIeR=Qo79MSj~v( zbJl|R5|PNr)9*#&kJyika+sNx#9o+Jj#n&ST)w^7(8hG~`m7XSg54d2=Mm{CMFYW2 zkB(3B7%m)%qK`fpRc|y5)0~hc?9H{RE=fK9asYemA)D73LyCcGt2=(4-bu*2`&`<6B`GEvZm}>HhAx(*1gE5W7HA zP15_R`bR}TrNRV6FQkebRM7gP5bX4T6O_Z?=Ga*QbY8p4jP$@?0d=51Llw?7!j*8H zs^;LcD$)+4t{WDTR59TXyF`57>GB9w!BbdpBK0AH+merU*Z^Iqeh~EfkLNP?`6O~y zUwmgz{XFP5B}M5?w9(Mh&*!8(d)5Btj>*MS(eK*&h`0MrAqV5U-wdOYGi?3MQE78Tgv`>q|qAUz|506Fv!w$zDP?Co|Jc2E6#kR z)oGSQn`unOg?N9pyd}zvJ*o{I8qg6-ns;ra zc%iPF<3%WZ1r(%Lqv#xXDq39Q_nuBmtSz1A)#iX#`HM?DUni9>JpV$xxE=B;9ty|E z*3lX1cMZOeh9S5lm0Yr7kb6Zk~t@XmoJ|xOtNDCs@XjraK;L zcEXh~OtyE!Qsj-!USvPAAx9u^_}(-RM6c7@Q`Sy&h{An3o^DFb}*!;AZ9RxBQ@gm?hHrXr$ql6vFYX z-MihtTUL-_J|%4$no*o&XCWnGz1dF#0r^Ddr=d%ohM_cZ(k&63T!58ZZAP zIdi)RC>ea&7Q8~JO71$7;NB{594Rp>NyZ@iDn!{j?P6)?p8?V`o|M4iMmxdF8 z@u!~gntD%)R0>t93=|&TFU@fxdOeF-)NMCJk{;tF9G?&yH^+50NSv^S!-lvgU-WR} z&r*2o+fXlTxVxJ%D}2GM_YVwt5^Hz4<~+8s*|WaPF9Y3$!}#$L13Y#t+Hyu-OA0qMyqKc%dN_ZX98u402v*6rZ*62DqIpfu?eKJ)2 zw7K=n*i=Wj^L?|q`E1WXGG_X=KrggU1LMTDCbxbhk9VZM7FV3sXPh<`rVIb-G@09> zMs3wnvbo#VVBhS-^?<4FA4UWUjJd9BUzqT!C=e3pJFaKdTkaN8Z3V&J_32Bc!8R zPGgnRmVZkQzWiAhgy2`z1Mv;E8QE3bM@K@`n&-R0d=!X~krJkN@!KzKM>bSD1dN&v zPy$D-;pq!VQOnR6)d^V`b z_|}Q~vtmi!QiH3L=ma)eNWI{$3dXej@K5;g!&mnf&?C7n6>w``Dzc>SjmqRK(CzzGDS)rHFoMF; zJf$O5UV?wPe8!OfaiA-N;LR}Wm?me3B?FlWCna(y&t;!0gTmJujX&rIgCe@sxl{TJ z(-yjv+fOYY`hNXKJ0ucdT@cd(Gc;&&#FlG3-C>v4YzxP?gvlzxA@I$V?6KjPA`;M8 zq>r1BuG;dXJl&8IT@ut(OaTf(+D7bu^n36P81Y5p52>91O2ru-Ew(#JGEm`LDS+)L z33a0vUvY_3YDf0YiT4}E2@a3}6WZ>H&ys}KXJWe-5jbPzkAdpO$x^#oK=ZAh2;VZ} z5uSc2E-rTMQVq`Z5IVP2lG7l$e#Nft=$AMrM67+29qe(SD%xB#ubjf; z(@%6#vjOdl86wl04Uyv*dplNVIHuEs4nj?p0<1CqaXq-bWwT`rQhn{T{-a(y07&B? zdx^(6$srOrQhDXzytIu6_h2|Oyej;Gb%yt|33rl=mS)F}iNW=JaCNdw$1Um7xy;*7 zmY#3%adH6js>sAFNNS!UUP65X^>e}0>t2F*_}A*(_xcHic&|B1auC)!@IZ}uiHWk$ zq?LuTRv<};al*F<&%gzGCqTGQcAUqCfzgJKJZ!8nN&4=}j_Mol?ZiQedUwY7K(~OnpLfpNJ*3s;j3C-kJwW0>l`&@&fO)dEBFQI+W5}$V9h)91UrU-RS z)A^UXx}E3gS|jNh-;D@0Nj5z^TD^RBj?u3!YJ8m5F_?nMyMU z4h*SQdN&E$wLuy6d_;l}6kPW!9;9oJw@oe-=pj~vXL=N-tizB6ks68bg3!jEM#ID) zQ?>76ZqIJGiQ}x=bz_W@MpgoV;kotG;0@h=_`vgeHXPGRCdkw6^x9RCSiRxypZ1f= zEV{Yt1$jH2jsN-!dLub*;k*3Rkok!=G|<_1*#jN5Vi}Aa_KXPS) zyLTZE#K5o{ld636<^hdwt3T|h7GVL7Co)u+5P+(6lBF<>%6l!X8CXedZynTxy@y-2%z`B1{yQ9gL;DPu?m*gCN4o_@>#b?Bg~7YRZJB2p-E5BR(w(t0m1GVMf-vF`3Zpa=`+Z;=%*Cnlqi9P@q5yk& zH%Nq`|(t(?ls$Z1zZ^SCK|`aZxic1tmB`!e8KG|V1_HQ$OjP%8$~ZZl>c)h zM{F33aDh~@jN9@Ksk+x$PPW#~t1ezvjzR94Y;y}fuzGR-dI>G4f~=jD{&9f_owOJP z90=|!!+@CoDhtOF)>>MrubS-s0DrCg=ROxz> zXp<8udtYhrTCwEW{tfN8G#mdmSoN0R^tS0bO64vsS(jy{5Z6iIP0sVV?La6&^`+kQp_oKh5Yq$a>q9LVT_z!QU@)|)mdtcz-KLLggeHXakrlzA+(ep{0z7 zZSGg_OO997|E4DzQYEC5mI4^+A$a-`yw$fARKP?10?tJMhf;6DHfg6CEpwGqR_HBP zMZ$ne9>9DY(~87l)6C_xp57cIWh!xIz2Ih;gpm|sOiN2DOx2%?!9Eo_fgcb7O3a1H zwv5+0XQ@-?vM*qo7c}vXU)|mv9)}? z{^~4*Bt5?Z)T102+?KlVIgbDBbJnHwt7qLuE&qog1xcu1pYq(iB->W!l4=(DIq>g~ On6iSpeCcar|Nj84l(57A literal 0 HcmV?d00001 diff --git a/images/aad-portal-app-registrations.png b/images/aad-portal-app-registrations.png new file mode 100644 index 0000000000000000000000000000000000000000..52b8ca4ee17a19e0da2619e73c17d956561c1bb9 GIT binary patch literal 68909 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 literal 0 HcmV?d00001 diff --git a/images/aad-redirect-uris.png b/images/aad-redirect-uris.png new file mode 100644 index 0000000000000000000000000000000000000000..40d1f208b3f09fd47606480d21931fc35205ad36 GIT binary patch literal 18700 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 literal 0 HcmV?d00001 diff --git a/images/aad-register-an-app.png b/images/aad-register-an-app.png new file mode 100644 index 0000000000000000000000000000000000000000..964d540cc6b54b467a427c9e31bb963a3199b696 GIT binary patch literal 35516 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 z693^(­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 au!@?w@G90s9{mISxvFQZTY1?b;{O4+cZ4Va literal 0 HcmV?d00001 From 5610f343deb6edcc452f88cf208c68ef69bf1ce7 Mon Sep 17 00:00:00 2001 From: Jason Johnston Date: Mon, 27 Jan 2020 11:34:08 -0500 Subject: [PATCH 3/7] Minor correction to app registration script --- RegisterApp.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RegisterApp.ps1 b/RegisterApp.ps1 index 83b425b..34cae7f 100644 --- a/RegisterApp.ps1 +++ b/RegisterApp.ps1 @@ -44,7 +44,7 @@ Write-Host "DONE" -ForeGroundColor Green Write-Host "Creating service principal..." -NoNewline # Create the app's service principal -$servicePrincipal = New-AzureADServicePrincipal -AppId $app.AppId -Tags {WindowsAzureActiveDirectoryIntegratedApp} +New-AzureADServicePrincipal -AppId $app.AppId -Tags {WindowsAzureActiveDirectoryIntegratedApp} | Out-Null Write-Host "DONE" -ForeGroundColor Green From 7a9bc692cd31aa85c6261bdcc38150f64f4a6fa8 Mon Sep 17 00:00:00 2001 From: Jason Johnston Date: Mon, 27 Jan 2020 14:07:11 -0500 Subject: [PATCH 4/7] Created new .NET Core console app --- .gitignore | 3 --- .vscode/launch.json | 26 ++++++++++++++++++++++ .vscode/tasks.json | 42 ++++++++++++++++++++++++++++++++++++ DeltaQuery/DeltaQuery.csproj | 14 ++++++++++++ DeltaQuery/Program.cs | 12 +++++++++++ 5 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json create mode 100644 DeltaQuery/DeltaQuery.csproj create mode 100644 DeltaQuery/Program.cs diff --git a/.gitignore b/.gitignore index b8e2743..ea8c6fa 100644 --- a/.gitignore +++ b/.gitignore @@ -214,6 +214,3 @@ pip-log.txt #Mr Developer .mr.developer.cfg - -# VS Code -.vscode/ \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..f5bba35 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,26 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + "program": "${workspaceFolder}/DeltaQuery/bin/Debug/netcoreapp3.1/DeltaQuery.dll", + "args": [], + "cwd": "${workspaceFolder}", + "stopAtEntry": false, + "console": "internalConsole" + }, + { + "name": "PowerShell: Launch Current File", + "type": "PowerShell", + "request": "launch", + "script": "${file}", + "cwd": "${file}" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..7453deb --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,42 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/DeltaQuery/DeltaQuery.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/DeltaQuery/DeltaQuery.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "${workspaceFolder}/DeltaQuery/DeltaQuery.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/DeltaQuery/DeltaQuery.csproj b/DeltaQuery/DeltaQuery.csproj new file mode 100644 index 0000000..8297ad9 --- /dev/null +++ b/DeltaQuery/DeltaQuery.csproj @@ -0,0 +1,14 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + diff --git a/DeltaQuery/Program.cs b/DeltaQuery/Program.cs new file mode 100644 index 0000000..dddc47b --- /dev/null +++ b/DeltaQuery/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace DeltaQuery +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Hello World!"); + } + } +} From bb07e78b306965f3394ed0b45d70863e6f330bfa Mon Sep 17 00:00:00 2001 From: Jason Johnston Date: Mon, 27 Jan 2020 18:01:10 -0500 Subject: [PATCH 5/7] Re-implemented functionality from original sample --- .vscode/launch.json | 9 +- .../Authentication/DeviceCodeAuthProvider.cs | 73 ++++++++++++++ DeltaQuery/DeltaQuery.csproj | 7 +- DeltaQuery/Program.cs | 95 ++++++++++++++++++- README.md | 38 +++++++- 5 files changed, 206 insertions(+), 16 deletions(-) create mode 100644 DeltaQuery/Authentication/DeviceCodeAuthProvider.cs diff --git a/.vscode/launch.json b/.vscode/launch.json index f5bba35..a4ca96f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -13,14 +13,7 @@ "args": [], "cwd": "${workspaceFolder}", "stopAtEntry": false, - "console": "internalConsole" - }, - { - "name": "PowerShell: Launch Current File", - "type": "PowerShell", - "request": "launch", - "script": "${file}", - "cwd": "${file}" + "console": "externalTerminal" } ] } \ No newline at end of file diff --git a/DeltaQuery/Authentication/DeviceCodeAuthProvider.cs b/DeltaQuery/Authentication/DeviceCodeAuthProvider.cs new file mode 100644 index 0000000..bf9c1bd --- /dev/null +++ b/DeltaQuery/Authentication/DeviceCodeAuthProvider.cs @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +using Microsoft.Graph; +using Microsoft.Identity.Client; +using System; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; + +namespace DeltaQuery.Authentication +{ + public class DeviceCodeAuthProvider : IAuthenticationProvider + { + private IPublicClientApplication _msalClient; + private string[] _scopes; + private IAccount _userAccount; + + public DeviceCodeAuthProvider(string appId, string[] scopes) + { + _scopes = scopes; + + _msalClient = PublicClientApplicationBuilder + .Create(appId) + .WithAuthority(AadAuthorityAudience.AzureAdAndPersonalMicrosoftAccount, true) + .Build(); + } + + public async Task GetAccessToken() + { + // If there is no saved user account, the user must sign-in + if (_userAccount == null) + { + try + { + // Invoke device code flow so user can sign-in with a browser + var result = await _msalClient.AcquireTokenWithDeviceCode(_scopes, callback => { + Console.WriteLine(callback.Message); + return Task.FromResult(0); + }).ExecuteAsync(); + + _userAccount = result.Account; + return result.AccessToken; + } + catch (Exception exception) + { + Console.WriteLine($"Error getting access token: {exception.Message}"); + return null; + } + } + else + { + // If there is an account, call AcquireTokenSilent + // By doing this, MSAL will refresh the token automatically if + // it is expired. Otherwise it returns the cached token. + + var result = await _msalClient + .AcquireTokenSilent(_scopes, _userAccount) + .ExecuteAsync(); + + return result.AccessToken; + } + } + + // This is the required method to implement IAuthenticationProvider + // The Graph SDK will call this method each time it makes a Graph + // call. + public async Task AuthenticateRequestAsync(HttpRequestMessage requestMessage) + { + requestMessage.Headers.Authorization = + new AuthenticationHeaderValue("bearer", await GetAccessToken()); + } + } +} \ No newline at end of file diff --git a/DeltaQuery/DeltaQuery.csproj b/DeltaQuery/DeltaQuery.csproj index 8297ad9..c5dd94b 100644 --- a/DeltaQuery/DeltaQuery.csproj +++ b/DeltaQuery/DeltaQuery.csproj @@ -1,14 +1,13 @@ + - Exe netcoreapp3.1 + 8f7bbee5-dcc4-411f-a100-5a7c1ccef5b6 - - - + \ No newline at end of file diff --git a/DeltaQuery/Program.cs b/DeltaQuery/Program.cs index dddc47b..dc93434 100644 --- a/DeltaQuery/Program.cs +++ b/DeltaQuery/Program.cs @@ -1,12 +1,101 @@ -using System; +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. +using DeltaQuery.Authentication; +using Microsoft.Extensions.Configuration; +using Microsoft.Graph; +using System; +using System.Threading.Tasks; namespace DeltaQuery { class Program { - static void Main(string[] args) + // The Microsoft Graph permission scopes used by the app + static string[] _scopes = { "User.Read", "Mail.Read" }; + + // The number of seconds to wait between delta queries + static int _pollIntervalInSecs = 30; + static GraphServiceClient _graphClient; + + static async Task Main(string[] args) + { + var appConfig = LoadAppSettings(); + + var authProvider = new DeviceCodeAuthProvider( + appConfig["AzureAppId"], _scopes); + + _graphClient = new GraphServiceClient(authProvider); + + await WatchMailFolders(_pollIntervalInSecs); + } + + static async Task WatchMailFolders(int pollInterval) + { + // Get first page of mail folders + IMailFolderDeltaCollectionPage deltaCollection; + deltaCollection = await _graphClient.Me.MailFolders + .Delta() + .Request() + .GetAsync(); + + // TODO: Keep an in-memory dictionary of folder names and ids, use this to give more info + // Example: "Folder test renamed to test2" or "Folder test2 deleted" or "Folder foo moved to deleted items" + while(true) + { + if (deltaCollection.CurrentPage.Count <= 0) + { + Console.WriteLine("No changes..."); + } + else + { + bool morePagesAvailable = false; + do + { + morePagesAvailable = deltaCollection.NextPageRequest != null; + foreach(var mailFolder in deltaCollection.CurrentPage) + { + bool isDeleted = mailFolder.AdditionalData != null ? + mailFolder.AdditionalData.ContainsKey("@removed") : + false; + + Console.WriteLine($"Folder {mailFolder.DisplayName} {(isDeleted ? "deleted" : "created/updated")}"); + } + + if (morePagesAvailable) + { + deltaCollection = await deltaCollection.NextPageRequest.GetAsync(); + } + } + while (morePagesAvailable); + } + + var deltaLink = deltaCollection.AdditionalData["@odata.deltaLink"]; + if (!string.IsNullOrEmpty(deltaLink.ToString())) + { + Console.WriteLine($"Processed current delta. Will check back in {pollInterval} seconds."); + await Task.Delay(pollInterval * 1000); + + deltaCollection.InitializeNextPageRequest(_graphClient, deltaLink.ToString()); + deltaCollection = await deltaCollection.NextPageRequest.GetAsync(); + } + } + } + + static IConfigurationRoot LoadAppSettings() { - Console.WriteLine("Hello World!"); + // Load the values stored in the secret + // manager + var appConfig = new ConfigurationBuilder() + .AddUserSecrets() + .Build(); + + // Check for required settings + if (string.IsNullOrEmpty(appConfig["AzureAppId"])) + { + return null; + } + + return appConfig; } } } diff --git a/README.md b/README.md index 7d6686c..c2d6062 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ extensions: --- # Microsoft Graph delta query sample -This console application demonstrates how to make [delta queries](https://docs.microsoft.com/graph/delta-query-overview) to Microsoft Graph, allowing applications to request only changed entities within a target resource. This sample monitors changes of messages in the user's inbox. +This console application demonstrates how to make [delta queries](https://docs.microsoft.com/graph/delta-query-overview) to Microsoft Graph, allowing applications to request only changed entities within a target resource. This sample monitors changes to the mail folders in a user's mailbox. ## How To Run This Sample @@ -87,8 +87,44 @@ The [RegisterApp.ps1](RegisterApp.ps1) script uses the [Azure AD PowerShell for ### Step 2: Configure the sample +1. Open your command-line interface (CLI) in the directory that contains **DeltaQuery.csproj**. + +1. Run the following command. + + ```Shell + dotnet user-secrets init + ``` + +1. Run the following command to store your application ID (obtained in the previous step) to the secret manager Be sure to replace `YOUR_APP_ID` with your application ID. + + ```Shell + dotnet user-secrets set AzureAppId YOUR_APP_ID + ``` + ### Step 3: Run the sample +#### Option 1: Using Visual Studio Code + +1. Open the root folder of this sample using Visual Studio Code. + +1. On the **Debug** menu, choose **Start Debugging**. + +#### Option 2: From the command line + +1. Open your command-line interface (CLI) in the directory that contains **DeltaQuery.csproj**. + +1. Run the following command to build the sample. + + ```Shell + dotnet build + ``` + +1. Run the following command to run the sample. + + ```Shell + dotnet run + ``` + ## Contributing If you'd like to contribute to this sample, see [CONTRIBUTING.MD](/CONTRIBUTING.md). From b7df1ab66d0529b584a97b308e3762ad662e911d Mon Sep 17 00:00:00 2001 From: Jason Johnston Date: Tue, 28 Jan 2020 14:50:08 -0500 Subject: [PATCH 6/7] Enhanced sample to give more info on changes Now keeps an in-memory list of mailfolders. When processing a delta, it checks if the folder already exists in the local list, then uses that to compare what's changed. --- DeltaQuery/Program.cs | 87 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 10 deletions(-) diff --git a/DeltaQuery/Program.cs b/DeltaQuery/Program.cs index dc93434..4e5921b 100644 --- a/DeltaQuery/Program.cs +++ b/DeltaQuery/Program.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Graph; using System; +using System.Collections.Generic; using System.Threading.Tasks; namespace DeltaQuery @@ -11,11 +12,16 @@ namespace DeltaQuery class Program { // The Microsoft Graph permission scopes used by the app - static string[] _scopes = { "User.Read", "Mail.Read" }; + private static string[] _scopes = { "User.Read", "Mail.Read" }; // The number of seconds to wait between delta queries - static int _pollIntervalInSecs = 30; - static GraphServiceClient _graphClient; + private static int _pollIntervalInSecs = 30; + + // Graph client + private static GraphServiceClient _graphClient; + + // In-memory "database" of mail folders + private static List _localMailFolders = new List(); static async Task Main(string[] args) { @@ -38,8 +44,6 @@ static async Task WatchMailFolders(int pollInterval) .Request() .GetAsync(); - // TODO: Keep an in-memory dictionary of folder names and ids, use this to give more info - // Example: "Folder test renamed to test2" or "Folder test2 deleted" or "Folder foo moved to deleted items" while(true) { if (deltaCollection.CurrentPage.Count <= 0) @@ -51,24 +55,24 @@ static async Task WatchMailFolders(int pollInterval) bool morePagesAvailable = false; do { + // If there is a NextPageRequest, there are more pages morePagesAvailable = deltaCollection.NextPageRequest != null; foreach(var mailFolder in deltaCollection.CurrentPage) { - bool isDeleted = mailFolder.AdditionalData != null ? - mailFolder.AdditionalData.ContainsKey("@removed") : - false; - - Console.WriteLine($"Folder {mailFolder.DisplayName} {(isDeleted ? "deleted" : "created/updated")}"); + await ProcessChanges(mailFolder); } if (morePagesAvailable) { + // Get the next page of results deltaCollection = await deltaCollection.NextPageRequest.GetAsync(); } } while (morePagesAvailable); } + // Once we've iterated through all of the pages, there should + // be a delta link, which is used to request all changes since our last query var deltaLink = deltaCollection.AdditionalData["@odata.deltaLink"]; if (!string.IsNullOrEmpty(deltaLink.ToString())) { @@ -81,6 +85,69 @@ static async Task WatchMailFolders(int pollInterval) } } + static async Task ProcessChanges(MailFolder mailFolder) + { + // Check if the local list of folders already contains this one + var localFolder = _localMailFolders.Find(f => f.Id == mailFolder.Id); + + bool isDeleted = mailFolder.AdditionalData != null ? + mailFolder.AdditionalData.ContainsKey("@removed") : + false; + + if (localFolder != null) + { + // In this case it's a delete or an update of a folder + // we already know about + if (isDeleted) + { + // Remove the entry from the local list + Console.WriteLine($"Folder {localFolder.DisplayName} deleted"); + _localMailFolders.Remove(localFolder); + } + else + { + Console.WriteLine($"Folder {localFolder.DisplayName} updated:"); + + // Was it renamed? + if (string.Compare(localFolder.DisplayName, mailFolder.DisplayName) != 0) + { + Console.WriteLine($" - Renamed to {mailFolder.DisplayName}"); + } + + // Was it moved? + if (string.Compare(localFolder.ParentFolderId, mailFolder.ParentFolderId) != 0) + { + // Get the parent folder + var parent = await _graphClient.Me + .MailFolders[mailFolder.ParentFolderId] + .Request() + .GetAsync(); + + Console.WriteLine($" - Moved to {parent.DisplayName} folder"); + } + + // Remove old entry and add new one + _localMailFolders.Remove(localFolder); + _localMailFolders.Add(mailFolder); + } + } + else + { + // No local match + if (isDeleted) + { + // Folder deleted, but we never knew about it anyway + Console.WriteLine($"Unknown folder with ID {mailFolder.Id} deleted"); + } + else + { + // New folder, add to local list + Console.WriteLine($"Folder {mailFolder.DisplayName} added"); + _localMailFolders.Add(mailFolder); + } + } + } + static IConfigurationRoot LoadAppSettings() { // Load the values stored in the secret From a30ac155b66b03170f5b332b94d91dacfc31b13c Mon Sep 17 00:00:00 2001 From: Jason Johnston Date: Tue, 28 Jan 2020 14:54:32 -0500 Subject: [PATCH 7/7] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c2d6062..b28fd1a 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,8 @@ The [RegisterApp.ps1](RegisterApp.ps1) script uses the [Azure AD PowerShell for ### Step 3: Run the sample +When the sample runs, it will prompt you to browse to a login URL and enter a device code. Once signed in, the app will check for changes to the mail folders in the user's mailbox every 30 seconds. + #### Option 1: Using Visual Studio Code 1. Open the root folder of this sample using Visual Studio Code.