diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0e254957df7..c7fdb9274a8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,7 +13,7 @@ The best way to get started with a contribution is to start a dialog with us. So - Clone the repo - . - Identify the module(s) that you want add the custom cmdlets to. E.g. [Groups](https://github.com/microsoftgraph/msgraph-sdk-powershell/tree/dev/src/Groups/Groups). - Navigate to the module’s custom folder. E.g. [Groups/custom](https://github.com/microsoftgraph/msgraph-sdk-powershell/tree/dev/src/Groups/Groups/custom). In here, you will find a readme.md that has basic instructions on how to add custom cmdlets. A full guide can be found [here](https://github.com/Azure/autorest/blob/master/docs/powershell/customization.md#creating-a-new-cmdlet). -- In the custom directory, add your custom cmdlet naming the file as `{Verb}Mg{Subject}_{Variant}.(cs|ps)`. This file will contain the implementation of your custom cmdlet. You can refer to [NewMgGroupMember_Create.cs](https://github.com/microsoftgraph/msgraph-sdk-powershell/blob/dev/src/Groups/Groups/custom/NewMgGroupMember_Create.cs) as an example. +- In the custom directory, add your custom cmdlet naming the file as `{Verb}Mg{Subject}_{Variant}.(cs|ps)`. This file will contain the implementation of your custom cmdlet. You can refer to [NewMgGroupMember_Create.cs](https://github.com/microsoftgraph/msgraph-sdk-powershell/blob/dev/src/Groups/v1.0/custom/NewMgGroupMember_Create.cs) as an example. - Once done, bump up the module version number in the module’s root [readme.md](https://github.com/microsoftgraph/msgraph-sdk-powershell/blob/dev/src/Groups/Groups/readme.md#versioning) then run `.\msgraph-sdk-powershell\tools\GenerateModules.ps1 -Build` to create, build and export the cmdlets to `..\exports` folder. ## Modifying Existing Cmdlets diff --git a/docs/AT-Pop.md b/docs/AT-Pop.md new file mode 100644 index 00000000000..7793dd6c9e8 --- /dev/null +++ b/docs/AT-Pop.md @@ -0,0 +1,79 @@ +# Microsoft Graph PowerShell SDK: Access Token Proof of Possession (AT PoP) Capability + +## Overview + +This README provides comprehensive details on the Access Token Proof of Possession (AT PoP) functionality introduced in the Microsoft Graph PowerShell SDK. This feature enhances security by binding tokens to specific HTTP methods and URIs, ensuring they are used only for their intended purposes. + +## Table of Contents + +- [Key Features](#key-features) +- [Installation](#installation) +- [Configuration](#configuration) +- [Usage Examples](#usage-examples) +- [References](#references) + +## Key Features + +- **Access Token Proof of Possession (AT PoP)**: This feature binds tokens to specific HTTP methods and URIs, preventing misuse of tokens by ensuring they are used only for the intended HTTP requests. +- **Updated Dependencies**: Compatibility improvements with recent library changes. +- **Enhanced Token Acquisition Options**: Users can now specify the HTTP method and URI during token acquisition to further secure token usage. + +### Token acquisition behaviors + +| Condition | Unbound (default) | Bound (PoP) | +|-----------|-----------|-----------| +| First sign-in | New token, interactive| New token, interactive | +| Existing token, same URI | No new token, silent | No new token, silent | +| Existing token, different URI | No new token, silent | New token, silent | +| Existing expired token, below max token refreshes | New token, silent | New token, silent | +| Existing expired token, exceeded max refreshes | New token, interactive | New token, interactive | + +## Installation + +To install the Microsoft Graph PowerShell SDK with the latest updates, use the following command: + +```powershell +Install-Module -Name Microsoft.Graph -AllowClobber -Force +``` + +Ensure you are using the latest version to access the AT PoP functionality. + +## Configuration + +### Enabling Access Token Proof of Possession + +To enable AT PoP, configure the Microsoft Graph SDK options as follows: + +```powershell +Set-MgGraphOption -EnableATPoP $true + +Connect-MgGraph +``` + +This configuration ensures that the acquired token is only valid for the specified HTTP method and URI. + +## Usage Examples + +### Example 1: + +```powershell +Set-MgGraphOption -EnableATPoP $true + +Connect-MgGraph + +Invoke-MgGraphRequest -Method GET https://graph.microsoft.com/v1.0/me -Debug +``` + +### Example 2: + +```powershell +Set-MgGraphOption -EnableATPoP $true + +Connect-MgGraph + +Invoke-MgGraphRequest -Uri "https://graph.microsoft.com/v1.0/me/sendMail" -Method POST -Debug +``` + +## References + +This README provides a detailed guide on the new AT PoP functionality, offering users the ability to secure their token usage effectively. If you have any questions or need further assistance, please refer to the official [Microsoft Graph PowerShell SDK documentation](https://docs.microsoft.com/en-us/powershell/microsoftgraph/). diff --git a/docs/authentication.md b/docs/authentication.md index 6cfbfda695f..4d587898495 100644 --- a/docs/authentication.md +++ b/docs/authentication.md @@ -112,6 +112,26 @@ When using `-AccessToken`, we won't have access to the refresh token and the cli Before using the provided `-AccessToken` to get Microsoft Graph resources, customers should ensure that the access token has the necessary scopes/ permissions needed to access/modify a resource. +### Access Token Proof of Possession (AT PoP) + +AT PoP is a security mechanism that binds an access token to a cryptographic key that only the token requestor has. This prevents unauthorized use of the token by malicious actors. AT PoP enhances data protection, reduces token replay attacks, and enables fine-grained authorization policies. + +Note: AT PoP requires Web Account Manager (WAM) to function. + +Microsoft Graph PowerShell module supports AT PoP in the following scenario: + +- To enable AT PoP on supported devices + +```PowerShell +Set-MgGraphOption -EnableATPoP $true +``` + +- To disable AT PoP on supported devices + +```PowerShell +Set-MgGraphOption -EnableATPoP $false +``` + ## Web Account Manager (WAM) WAM is a Windows 10+ component that acts as an authentication broker allowing the users of an app benefit from integration with accounts known to Windows, such as the account already signed into an active Windows session. diff --git a/openApiDocs/beta/DeviceManagement.Actions.yml b/openApiDocs/beta/DeviceManagement.Actions.yml index 574d51f91e8..559f0285739 100644 --- a/openApiDocs/beta/DeviceManagement.Actions.yml +++ b/openApiDocs/beta/DeviceManagement.Actions.yml @@ -47608,4 +47608,4 @@ components: tokenUrl: https://login.microsoftonline.com/common/oauth2/v2.0/token scopes: { } security: - - azureaadv2: [ ] + - azureaadv2: [ ] \ No newline at end of file diff --git a/src/Applications/beta/examples/Get-MgBetaServicePrincipalSynchronizationTemplate.md b/src/Applications/beta/examples/Get-MgBetaServicePrincipalSynchronizationTemplate.md index 3f1ed3342cb..e69de29bb2d 100644 --- a/src/Applications/beta/examples/Get-MgBetaServicePrincipalSynchronizationTemplate.md +++ b/src/Applications/beta/examples/Get-MgBetaServicePrincipalSynchronizationTemplate.md @@ -1,11 +0,0 @@ -### Example - -```powershell - -Import-Module Microsoft.Graph.Beta.Applications - -Get-MgBetaServicePrincipalSynchronizationTemplate -ServicePrincipalId $servicePrincipalId - -``` -This example will### example - diff --git a/src/Authentication/Authentication.Core/Common/GraphSession.cs b/src/Authentication/Authentication.Core/Common/GraphSession.cs index 6b893d4d1c4..f0941608403 100644 --- a/src/Authentication/Authentication.Core/Common/GraphSession.cs +++ b/src/Authentication/Authentication.Core/Common/GraphSession.cs @@ -56,6 +56,11 @@ public class GraphSession : IGraphSession /// public IGraphOption GraphOption { get; set; } + /// + /// Temporarily stores the user's Graph request details such as Method and Uri. Essential as part of the Proof of Possession efforts. + /// + public IGraphRequestPopContext GraphRequestPopContext { get; set; } + /// /// Represents a collection of Microsoft Graph PowerShell meta-info. /// diff --git a/src/Authentication/Authentication.Core/Interfaces/IGraphOptions.cs b/src/Authentication/Authentication.Core/Interfaces/IGraphOptions.cs index 3dd2483694f..de7f68f15d8 100644 --- a/src/Authentication/Authentication.Core/Interfaces/IGraphOptions.cs +++ b/src/Authentication/Authentication.Core/Interfaces/IGraphOptions.cs @@ -2,14 +2,11 @@ // Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. // ------------------------------------------------------------------------------ -using System; -using System.Security; -using System.Security.Cryptography.X509Certificates; - namespace Microsoft.Graph.PowerShell.Authentication { public interface IGraphOption { bool EnableWAMForMSGraph { get; set; } + bool EnableATPoPForMSGraph { get; set; } } } \ No newline at end of file diff --git a/src/Authentication/Authentication.Core/Interfaces/IGraphRequestPopContext.cs b/src/Authentication/Authentication.Core/Interfaces/IGraphRequestPopContext.cs new file mode 100644 index 00000000000..61551edb318 --- /dev/null +++ b/src/Authentication/Authentication.Core/Interfaces/IGraphRequestPopContext.cs @@ -0,0 +1,21 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. +// ------------------------------------------------------------------------------ + +using Azure.Core; +using Azure.Core.Pipeline; +using Azure.Identity; +using System; +using System.Net.Http; + +namespace Microsoft.Graph.PowerShell.Authentication +{ + public interface IGraphRequestPopContext + { + Uri Uri { get; set; } + HttpMethod HttpMethod { get; set; } + AccessToken AccessToken { get; set; } + HttpPipeline PopPipeline { get; set; } + InteractiveBrowserCredential PopInteractiveBrowserCredential { get; set; } + } +} \ No newline at end of file diff --git a/src/Authentication/Authentication.Core/Interfaces/IGraphSession.cs b/src/Authentication/Authentication.Core/Interfaces/IGraphSession.cs index c7f8ba48c3d..fc0fd19cbb5 100644 --- a/src/Authentication/Authentication.Core/Interfaces/IGraphSession.cs +++ b/src/Authentication/Authentication.Core/Interfaces/IGraphSession.cs @@ -12,5 +12,6 @@ public interface IGraphSession IDataStore DataStore { get; set; } IRequestContext RequestContext { get; set; } IGraphOption GraphOption { get; set; } + IGraphRequestPopContext GraphRequestPopContext { get; set; } } } \ No newline at end of file diff --git a/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj b/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj index fd2f232daa2..6457abe3f67 100644 --- a/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj +++ b/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj @@ -1,19 +1,22 @@ - + 9.0 netstandard2.0;net6.0;net472 Microsoft.Graph.PowerShell.Authentication.Core - 2.18.0 + 2.12.0 true true - - - + + + + + + diff --git a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs index 3d004336109..1389bbb821c 100644 --- a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs +++ b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs @@ -3,6 +3,7 @@ // ------------------------------------------------------------------------------ using Azure.Core; using Azure.Core.Diagnostics; +using Azure.Core.Pipeline; using Azure.Identity; using Azure.Identity.Broker; using Microsoft.Graph.Authentication; @@ -14,6 +15,8 @@ using System.Globalization; using System.IO; using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; @@ -113,23 +116,44 @@ private static async Task GetInteractiveBrowserCre { if (authContext is null) throw new AuthenticationException(ErrorConstants.Message.MissingAuthContext); - var interactiveOptions = IsWamSupported() ? new InteractiveBrowserCredentialBrokerOptions(WindowHandleUtlities.GetConsoleOrTerminalWindow()) : new InteractiveBrowserCredentialOptions(); + var interactiveOptions = IsWamSupported() ? + new InteractiveBrowserCredentialBrokerOptions(WindowHandleUtlities.GetConsoleOrTerminalWindow()) : + new InteractiveBrowserCredentialOptions(); interactiveOptions.ClientId = authContext.ClientId; interactiveOptions.TenantId = authContext.TenantId ?? "common"; interactiveOptions.AuthorityHost = new Uri(GetAuthorityUrl(authContext)); interactiveOptions.TokenCachePersistenceOptions = GetTokenCachePersistenceOptions(authContext); + var interactiveBrowserCredential = new InteractiveBrowserCredential(interactiveOptions); + var popTokenRequestContext = new PopTokenRequestContext(); + if (GraphSession.Instance.GraphOption.EnableATPoPForMSGraph) + { + popTokenRequestContext = await CreatePopTokenRequestContext(authContext); + GraphSession.Instance.GraphRequestPopContext.PopInteractiveBrowserCredential = interactiveBrowserCredential; + } + if (!File.Exists(Constants.AuthRecordPath)) { AuthenticationRecord authRecord; - var interactiveBrowserCredential = new InteractiveBrowserCredential(interactiveOptions); if (IsWamSupported()) { - authRecord = await Task.Run(() => + // Adding a scenario to account for Access Token Proof of Possession + if (GraphSession.Instance.GraphOption.EnableATPoPForMSGraph) { - // Run the thread in MTA. - return interactiveBrowserCredential.Authenticate(new TokenRequestContext(authContext.Scopes), cancellationToken); - }); + authRecord = await Task.Run(() => + { + // Run the thread in MTA. + return interactiveBrowserCredential.AuthenticateAsync(popTokenRequestContext, cancellationToken); + }); + } + else + { + authRecord = await Task.Run(() => + { + // Run the thread in MTA. + return interactiveBrowserCredential.Authenticate(new TokenRequestContext(authContext.Scopes), cancellationToken); + }); + } } else { @@ -446,5 +470,34 @@ public static Task DeleteAuthRecordAsync() File.Delete(Constants.AuthRecordPath); return Task.CompletedTask; } + + private static async Task CreatePopTokenRequestContext(IAuthContext authContext) + { + // Creating a httpclient that would handle all pop calls + Uri popResourceUri = GraphSession.Instance.GraphRequestPopContext.Uri ?? new Uri("https://graph.microsoft.com/beta/organization"); + HttpClient popHttpClient = new(new HttpClientHandler()); + + // Find the nonce in the WWW-Authenticate header in the response. + var popMethod = GraphSession.Instance.GraphRequestPopContext.HttpMethod ?? HttpMethod.Get; + var popResponse = await popHttpClient.SendAsync(new HttpRequestMessage(popMethod, popResourceUri)); + + // Refresh token logic --- start + var popPipelineOptions = new HttpPipelineOptions(new PopClientOptions() + { + + }); + + GraphSession.Instance.GraphRequestPopContext.PopPipeline = HttpPipelineBuilder.Build(popPipelineOptions, new HttpPipelineTransportOptions()); + var popRequest = GraphSession.Instance.GraphRequestPopContext.PopPipeline.CreateRequest(); + popRequest.Method = RequestMethod.Parse(popMethod.Method.ToUpper()); + popRequest.Uri.Reset(popResourceUri); + + // Refresh token logic --- end + var popContext = new PopTokenRequestContext(authContext.Scopes, isProofOfPossessionEnabled: true, proofOfPossessionNonce: WwwAuthenticateParameters.CreateFromAuthenticationHeaders(popResponse.Headers, "Pop").Nonce, request: popRequest); + return popContext; + } + } + internal class PopClientOptions : ClientOptions + { } } \ No newline at end of file diff --git a/src/Authentication/Authentication/Cmdlets/InvokeMgGraphRequest.cs b/src/Authentication/Authentication/Cmdlets/InvokeMgGraphRequest.cs index 4e16b462486..b1360636f43 100644 --- a/src/Authentication/Authentication/Cmdlets/InvokeMgGraphRequest.cs +++ b/src/Authentication/Authentication/Cmdlets/InvokeMgGraphRequest.cs @@ -1026,6 +1026,8 @@ private async Task ProcessRecordAsync() try { PrepareSession(); + GraphSession.Instance.GraphRequestPopContext.Uri = Uri; + GraphSession.Instance.GraphRequestPopContext.HttpMethod = GetHttpMethod(Method); var client = HttpHelpers.GetGraphHttpClient(); ValidateRequestUri(); using (var httpRequestMessage = GetRequest(client, Uri)) diff --git a/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs b/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs index ad4f0f76a11..fc4da16a8ed 100644 --- a/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs +++ b/src/Authentication/Authentication/Cmdlets/SetMgGraphOption.cs @@ -13,6 +13,9 @@ public class SetMgGraphOption : PSCmdlet { [Parameter] public bool EnableLoginByWAM { get; set; } + + [Parameter] + public bool EnableATPoP { get; set; } protected override void BeginProcessing() { @@ -27,6 +30,11 @@ protected override void ProcessRecord() GraphSession.Instance.GraphOption.EnableWAMForMSGraph = EnableLoginByWAM; WriteDebug($"Signin by Web Account Manager (WAM) is {(EnableLoginByWAM ? "enabled" : "disabled")}."); } + if (this.IsParameterBound(nameof(EnableATPoP))) + { + GraphSession.Instance.GraphOption.EnableATPoPForMSGraph = EnableATPoP; + WriteDebug($"Access Token Proof of Posession (AT-PoP) is {(EnableATPoP ? "enabled" : "disabled")}."); + } File.WriteAllText(Constants.GraphOptionsFilePath, JsonConvert.SerializeObject(GraphSession.Instance.GraphOption, Formatting.Indented)); } diff --git a/src/Authentication/Authentication/Common/GraphSessionInitializer.cs b/src/Authentication/Authentication/Common/GraphSessionInitializer.cs index 4d3d527da14..ec165e5a942 100644 --- a/src/Authentication/Authentication/Common/GraphSessionInitializer.cs +++ b/src/Authentication/Authentication/Common/GraphSessionInitializer.cs @@ -47,7 +47,8 @@ internal static GraphSession CreateInstance(IDataStore dataStore = null) { DataStore = dataStore ?? new DiskDataStore(), RequestContext = new RequestContext(), - GraphOption = graphOptions ?? new GraphOption() + GraphOption = graphOptions ?? new GraphOption(), + GraphRequestPopContext = new GraphRequestPopContext() }; } /// diff --git a/src/Authentication/Authentication/Handlers/AuthenticationHandler.cs b/src/Authentication/Authentication/Handlers/AuthenticationHandler.cs index e57d74186b3..362a262abfc 100644 --- a/src/Authentication/Authentication/Handlers/AuthenticationHandler.cs +++ b/src/Authentication/Authentication/Handlers/AuthenticationHandler.cs @@ -3,11 +3,15 @@ // ------------------------------------------------------------------------------ +using Azure.Core; using Microsoft.Graph.Authentication; +using Microsoft.Graph.PowerShell.Authentication.Core.Utilities; using Microsoft.Graph.PowerShell.Authentication.Extensions; +using Microsoft.Identity.Client; using System; using System.Collections.Generic; using System.Linq; +using System.Management.Automation; using System.Net; using System.Net.Http; using System.Net.Http.Headers; @@ -21,7 +25,10 @@ internal class AuthenticationHandler : DelegatingHandler { private const string ClaimsKey = "claims"; private const string BearerAuthenticationScheme = "Bearer"; + private const string PopAuthenticationScheme = "Pop"; private int MaxRetry { get; set; } = 1; + private PopTokenRequestContext popTokenRequestContext; + private Request popRequest = GraphSession.Instance.GraphRequestPopContext.PopPipeline.CreateRequest(); public AzureIdentityAccessTokenProvider AuthenticationProvider { get; set; } @@ -45,6 +52,12 @@ protected override async Task SendAsync(HttpRequestMessage HttpResponseMessage response = await base.SendAsync(httpRequestMessage, cancellationToken).ConfigureAwait(false); + // Continuous nonce extraction on each request + if (GraphSession.Instance.GraphOption.EnableATPoPForMSGraph) + { + popTokenRequestContext = new PopTokenRequestContext(GraphSession.Instance.AuthContext.Scopes, isProofOfPossessionEnabled: true, proofOfPossessionNonce: WwwAuthenticateParameters.CreateFromAuthenticationHeaders(response.Headers, PopAuthenticationScheme).Nonce, request: popRequest); + } + // Check if response is a 401 & is not a streamed body (is buffered) if (response.StatusCode == HttpStatusCode.Unauthorized && httpRequestMessage.IsBuffered()) { @@ -63,9 +76,24 @@ private async Task AuthenticateRequestAsync(HttpRequestMessage httpRequestMessag { if (AuthenticationProvider != null) { - var accessToken = await AuthenticationProvider.GetAuthorizationTokenAsync(httpRequestMessage.RequestUri, additionalAuthenticationContext, cancellationToken: cancellationToken).ConfigureAwait(false); - if (!string.IsNullOrEmpty(accessToken)) - httpRequestMessage.Headers.Authorization = new AuthenticationHeaderValue(BearerAuthenticationScheme, accessToken); + if (GraphSession.Instance.GraphOption.EnableATPoPForMSGraph) + { + popRequest.Method = RequestMethod.Parse(httpRequestMessage.Method.Method.ToUpper()); + popRequest.Uri.Reset(httpRequestMessage.RequestUri); + foreach (var header in httpRequestMessage.Headers) + { + popRequest.Headers.Add(header.Key, header.Value.First()); + } + + var accessToken = await GraphSession.Instance.GraphRequestPopContext.PopInteractiveBrowserCredential.GetTokenAsync(popTokenRequestContext, cancellationToken).ConfigureAwait(false); + httpRequestMessage.Headers.Authorization = new AuthenticationHeaderValue(PopAuthenticationScheme, accessToken.Token); + } + else + { + var accessToken = await AuthenticationProvider.GetAuthorizationTokenAsync(httpRequestMessage.RequestUri, additionalAuthenticationContext, cancellationToken: cancellationToken).ConfigureAwait(false); + if (!string.IsNullOrEmpty(accessToken)) + httpRequestMessage.Headers.Authorization = new AuthenticationHeaderValue(BearerAuthenticationScheme, accessToken); + } } } diff --git a/src/Authentication/Authentication/Helpers/HttpHelpers.cs b/src/Authentication/Authentication/Helpers/HttpHelpers.cs index cfd9252f5f5..96fd8884ff9 100644 --- a/src/Authentication/Authentication/Helpers/HttpHelpers.cs +++ b/src/Authentication/Authentication/Helpers/HttpHelpers.cs @@ -54,7 +54,7 @@ private static HttpClient GetGraphHttpClient(AzureIdentityAccessTokenProvider au new NationalCloudHandler(), new ODataQueryOptionsHandler(), new HttpVersionHandler(), - new CompressionHandler(), + //new CompressionHandler(), new RetryHandler(new RetryHandlerOption{ Delay = requestContext.RetryDelay, MaxRetry = requestContext.MaxRetry, diff --git a/src/Authentication/Authentication/Microsoft.Graph.Authentication.nuspec b/src/Authentication/Authentication/Microsoft.Graph.Authentication.nuspec index 6c2e698b026..c8cf6124e3e 100644 --- a/src/Authentication/Authentication/Microsoft.Graph.Authentication.nuspec +++ b/src/Authentication/Authentication/Microsoft.Graph.Authentication.nuspec @@ -50,12 +50,14 @@ + + diff --git a/src/Authentication/Authentication/Models/GraphOption.cs b/src/Authentication/Authentication/Models/GraphOption.cs index d8c48d7f70a..e8c83e6ef01 100644 --- a/src/Authentication/Authentication/Models/GraphOption.cs +++ b/src/Authentication/Authentication/Models/GraphOption.cs @@ -9,6 +9,7 @@ namespace Microsoft.Graph.PowerShell.Authentication internal class GraphOption : IGraphOption { public bool EnableWAMForMSGraph { get; set; } + public bool EnableATPoPForMSGraph { get; set; } } } \ No newline at end of file diff --git a/src/Authentication/Authentication/Models/GraphRequestPopContext.cs b/src/Authentication/Authentication/Models/GraphRequestPopContext.cs new file mode 100644 index 00000000000..4be69f16e7e --- /dev/null +++ b/src/Authentication/Authentication/Models/GraphRequestPopContext.cs @@ -0,0 +1,23 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. +// ------------------------------------------------------------------------------ + +using Azure.Core; +using Azure.Core.Pipeline; +using Azure.Identity; +using System; +using System.IO; +using System.Net.Http; + +namespace Microsoft.Graph.PowerShell.Authentication +{ + internal class GraphRequestPopContext : IGraphRequestPopContext + { + public Uri Uri { get; set; } + public HttpMethod HttpMethod { get; set; } + public AccessToken AccessToken { get; set; } + public HttpPipeline PopPipeline { get; set; } + public InteractiveBrowserCredential PopInteractiveBrowserCredential { get; set; } + } + +} \ No newline at end of file diff --git a/src/Authentication/Authentication/test/Connect-MgGraph.Tests.ps1 b/src/Authentication/Authentication/test/Connect-MgGraph.Tests.ps1 index 6f88feddf0e..d14f9495f6d 100644 --- a/src/Authentication/Authentication/test/Connect-MgGraph.Tests.ps1 +++ b/src/Authentication/Authentication/test/Connect-MgGraph.Tests.ps1 @@ -73,7 +73,7 @@ Describe 'Connect-MgGraph In Delegated Mode' { Describe 'Connect-MgGraph In Environment Variable Mode' { It 'Should throw exception when supported environment variables are not specified' { - { Connect-MgGraph -EnvironmentVariable -ErrorAction Stop } | Should -Throw -ExpectedMessage "*EnvironmentCredential authentication unavailable. Environment variables are not fully configured*" + { Connect-MgGraph -EnvironmentVariable -ErrorAction Stop } | Should -Throw -ExpectedMessage "*EnvironmentCredential authentication unavailable*" } It 'Should attempt to use configured environment variables' { { @@ -81,7 +81,7 @@ Describe 'Connect-MgGraph In Environment Variable Mode' { $Env:AZURE_CLIENT_SECRET = "Not_Valid" $Env:AZURE_TENANT_ID = "common" Connect-MgGraph -EnvironmentVariable -ErrorAction Stop - } | Should -Throw -ExpectedMessage "*ClientSecretCredential authentication failed: AADSTS700016: Application with identifier 'Not_Valid' was not found in the directory 'Microsoft'.*" + } | Should -Throw -ExpectedMessage "*ClientSecretCredential authentication failed*" } } @@ -99,7 +99,7 @@ Describe 'Connect-MgGraph In App Mode' { Describe 'Connect-MgGraph Dependency Resolution' { It 'Should load Mg module side by side with Az module.' { { Connect-AzAccount -ApplicationId $RandomClientId -CertificateThumbprint "Invalid" -Tenant "Invalid" -ErrorAction Stop } | Should -Throw -ExpectedMessage "*Could not find tenant id*" - { Connect-MgGraph -TenantId "thisdomaindoesnotexist.com" -ErrorAction Stop -UseDeviceAuthentication } | Should -Throw -ExpectedMessage "*AADSTS90002*" + { Connect-MgGraph -TenantId "thisdomaindoesnotexist.com" -ErrorAction Stop -UseDeviceAuthentication } | Should -Throw -ExpectedMessage "*DeviceCodeCredential authentication failed*" } } diff --git a/src/Authentication/Authentication/test/Get-MgGraphOption.Tests.ps1 b/src/Authentication/Authentication/test/Get-MgGraphOption.Tests.ps1 index 786105807c7..2708d2f7f41 100644 --- a/src/Authentication/Authentication/test/Get-MgGraphOption.Tests.ps1 +++ b/src/Authentication/Authentication/test/Get-MgGraphOption.Tests.ps1 @@ -13,7 +13,7 @@ Describe "Get-MgGraphOption Command" { $GetMgGraphOptionCommand = Get-Command Set-MgGraphOption $GetMgGraphOptionCommand | Should -Not -BeNullOrEmpty $GetMgGraphOptionCommand.ParameterSets | Should -HaveCount 1 - $GetMgGraphOptionCommand.ParameterSets.Parameters | Should -HaveCount 13 # PS common parameters. + $GetMgGraphOptionCommand.ParameterSets.Parameters | Should -HaveCount 14 # PS common parameters. } It 'Executes successfully' { diff --git a/src/Authentication/Authentication/test/Set-MgGraphOption.Tests.ps1 b/src/Authentication/Authentication/test/Set-MgGraphOption.Tests.ps1 index 6a2cb60693a..775cdcaa629 100644 --- a/src/Authentication/Authentication/test/Set-MgGraphOption.Tests.ps1 +++ b/src/Authentication/Authentication/test/Set-MgGraphOption.Tests.ps1 @@ -9,14 +9,14 @@ Describe "Set-MgGraphOption" { Import-Module $ModulePath -Force -ErrorAction SilentlyContinue } Context "When executing the command" { - it 'Should have one ParameterSets' { + it 'Should have two ParameterSets' { $SetMgGraphOptionCommand = Get-Command Set-MgGraphOption $SetMgGraphOptionCommand | Should -Not -BeNullOrEmpty $SetMgGraphOptionCommand.ParameterSets | Should -HaveCount 1 - $SetMgGraphOptionCommand.ParameterSets.Parameters | Should -HaveCount 13 # PS common parameters. + $SetMgGraphOptionCommand.ParameterSets.Parameters | Should -HaveCount 14 # PS common parameters. } - It 'Executes successfully whren toggling WAM on' { + It 'Executes successfully when toggling WAM on' { { Set-MgGraphOption -EnableLoginByWAM $true -Debug | Out-Null } | Should -Not -Be $null { Set-MgGraphOption -EnableLoginByWAM $true -ErrorAction SilentlyContinue } | Should -Not -Throw } @@ -25,5 +25,15 @@ Describe "Set-MgGraphOption" { { Set-MgGraphOption -EnableLoginByWAM $false -Debug | Out-Null } | Should -Not -Be $null { Set-MgGraphOption -EnableLoginByWAM $false -ErrorAction SilentlyContinue } | Should -Not -Throw } + + It 'Executes successfully when toggling AT PoP on' { + { Set-MgGraphOption -EnableATPoP $true -Debug | Out-Null } | Should -Not -Be $null + { Set-MgGraphOption -EnableATPoP $true -ErrorAction SilentlyContinue } | Should -Not -Throw + } + + It 'Executes successfully when toggling AT PoP off' { + { Set-MgGraphOption -EnableATPoP $false -Debug | Out-Null } | Should -Not -Be $null + { Set-MgGraphOption -EnableATPoP $false -ErrorAction SilentlyContinue } | Should -Not -Throw + } } } \ No newline at end of file diff --git a/src/Authentication/docs/Connect-MgGraph.md b/src/Authentication/docs/Connect-MgGraph.md index 9ef5d0af7ce..5e793b1f142 100644 --- a/src/Authentication/docs/Connect-MgGraph.md +++ b/src/Authentication/docs/Connect-MgGraph.md @@ -16,38 +16,40 @@ Microsoft Graph PowerShell supports two types of authentication: delegated and a ``` Connect-MgGraph [[-Scopes] ] [[-ClientId] ] [-TenantId ] [-ContextScope ] [-Environment ] [-UseDeviceCode] [-ClientTimeout ] [-NoWelcome] - [] + [-ProgressAction ] [] ``` ### AppCertificateParameterSet ``` Connect-MgGraph [-ClientId] [[-CertificateSubjectName] ] [[-CertificateThumbprint] ] - [-Certificate ] [-TenantId ] [-ContextScope ] [-Environment ] - [-ClientTimeout ] [-NoWelcome] [] + [-SendCertificateChain ] [-Certificate ] [-TenantId ] + [-ContextScope ] [-Environment ] [-ClientTimeout ] [-NoWelcome] + [-ProgressAction ] [] ``` ### IdentityParameterSet ``` Connect-MgGraph [[-ClientId] ] [-ContextScope ] [-Environment ] - [-ClientTimeout ] [-Identity] [-NoWelcome] [] + [-ClientTimeout ] [-Identity] [-NoWelcome] [-ProgressAction ] [] ``` ### AppSecretCredentialParameterSet ``` Connect-MgGraph [-ClientSecretCredential ] [-TenantId ] [-ContextScope ] - [-Environment ] [-ClientTimeout ] [-NoWelcome] [] + [-Environment ] [-ClientTimeout ] [-NoWelcome] [-ProgressAction ] + [] ``` ### AccessTokenParameterSet ``` Connect-MgGraph [-AccessToken] [-Environment ] [-ClientTimeout ] [-NoWelcome] - [] + [-ProgressAction ] [] ``` ### EnvironmentVariableParameterSet ``` Connect-MgGraph [-ContextScope ] [-Environment ] [-ClientTimeout ] - [-EnvironmentVariable] [-NoWelcome] [] + [-EnvironmentVariable] [-NoWelcome] [-ProgressAction ] [] ``` ## DESCRIPTION @@ -351,6 +353,21 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -ProgressAction +{{ Fill ProgressAction Description }} + +```yaml +Type: ActionPreference +Parameter Sets: (All) +Aliases: proga + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -Scopes An array of delegated permissions to consent to. @@ -366,6 +383,21 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -SendCertificateChain +Include x5c header in client claims when acquiring a token to enable subject name / issuer based authentication using given certificate. + +```yaml +Type: Boolean +Parameter Sets: AppCertificateParameterSet +Aliases: + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ### -TenantId The id of the tenant to connect to. You can also use this parameter to specify your sign-in audience. diff --git a/src/Authentication/docs/Get-MgGraphOption.md b/src/Authentication/docs/Get-MgGraphOption.md index f4ef0a7c258..7678d11d798 100644 --- a/src/Authentication/docs/Get-MgGraphOption.md +++ b/src/Authentication/docs/Get-MgGraphOption.md @@ -1,7 +1,7 @@ --- external help file: Microsoft.Graph.Authentication.dll-Help.xml Module Name: Microsoft.Graph.Authentication -online version: https://learn.microsoft.com/en-us/powershell/module/microsoft.graph.authentication/get-mgenvironment +online version: https://learn.microsoft.com/en-us/powershell/module/microsoft.graph.authentication/get-mggraphoption schema: 2.0.0 --- diff --git a/src/Authentication/docs/Set-MgGraphOption.md b/src/Authentication/docs/Set-MgGraphOption.md index 85ee3e9fca6..99ef8e95a29 100644 --- a/src/Authentication/docs/Set-MgGraphOption.md +++ b/src/Authentication/docs/Set-MgGraphOption.md @@ -1,7 +1,7 @@ --- external help file: Microsoft.Graph.Authentication.dll-Help.xml Module Name: Microsoft.Graph.Authentication -online version: https://learn.microsoft.com/en-us/powershell/module/microsoft.graph.authentication/set-mgenvironment +online version: https://learn.microsoft.com/en-us/powershell/module/microsoft.graph.authentication/set-mggraphoption schema: 2.0.0 --- @@ -15,6 +15,9 @@ Sets global configurations that apply to the SDK. For example, toggle Web Accoun ``` Set-MgGraphOption [-EnableLoginByWAM ] [] ``` +``` +Set-MgGraphOption [-EnableATPoP ] [] +``` ## DESCRIPTION Sets global configurations that apply to the SDK. For example, toggle Web Account Manager (WAM) support. @@ -28,11 +31,21 @@ PS C:\> Set-MgGraphOption -EnableLoginByWAM $True Sets web account manager support +### Example 2: Set access token proof of possession support +```powershell +PS C:\> Set-MgGraphOption -EnableATPoP $True +``` + + Sets access token proof of possession support + ## PARAMETERS ### -EnableLoginByWAM {{ Fill EnableLoginByWAM Description }} +### -EnableATPoP +{{ Fill EnableATPoP Description }} + ```yaml Type: Boolean Parameter Sets: (All) diff --git a/src/Authentication/examples/Set-MgGraphOption.md b/src/Authentication/examples/Set-MgGraphOption.md index 055431b5920..afc23d97cb1 100644 --- a/src/Authentication/examples/Set-MgGraphOption.md +++ b/src/Authentication/examples/Set-MgGraphOption.md @@ -2,4 +2,10 @@ ```powershell PS C:\> Set-MgGraphOption -EnableLoginByWAM $True ``` - Sets web account manager support \ No newline at end of file + Sets web account manager support + +### Example 2: Set access token proof of possession support +```powershell +PS C:\> Set-MgGraphOption -EnableATPoP $True +``` + Sets access token proof of possession support \ No newline at end of file