From 7b1989066336416ae62b31165686360d820eb915 Mon Sep 17 00:00:00 2001 From: Timothy Wamalwa Date: Tue, 30 Apr 2024 00:03:33 +0300 Subject: [PATCH 01/24] Added safe rollout feature --- config/ModuleMetadata.json | 12 ++++++------ .../Authentication/Cmdlets/ConnectMgGraph.cs | 15 ++++++++++++++- src/Authentication/Authentication/Constants.cs | 4 ++++ 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/config/ModuleMetadata.json b/config/ModuleMetadata.json index a5136fbceb1..c6cc198b1eb 100644 --- a/config/ModuleMetadata.json +++ b/config/ModuleMetadata.json @@ -26,16 +26,16 @@ ], "versions": { "authentication": { - "prerelease": "", - "version": "2.18.0" + "prerelease": "preview1", + "version": "2.22.0" }, "beta": { - "prerelease": "", - "version": "2.18.0" + "prerelease": "preview1", + "version": "2.22.0" }, "v1.0": { - "prerelease": "", - "version": "2.18.0" + "prerelease": "preview1", + "version": "2.22.0" } } } diff --git a/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs b/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs index 3fd26ccb594..7926f90070e 100644 --- a/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs +++ b/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs @@ -56,6 +56,14 @@ public class ConnectMgGraph : PSCmdlet, IModuleAssemblyInitializer, IModuleAssem [Alias("SecretCredential", "Credential")] public PSCredential ClientSecretCredential { get; set; } + /* + Torus migration changes for client based rollout + */ + + [Parameter(Mandatory = false, ParameterSetName = Constants.SafeRolloutParameterSet, HelpMessage = HelpMessages.SafeRollout)] + [Alias("ValidateRollout")] + public bool SafeRollOut { get; set; } + [Parameter(ParameterSetName = Constants.AccessTokenParameterSet, Position = 1, Mandatory = true, HelpMessage = HelpMessages.AccessToken)] public SecureString AccessToken { get; set; } @@ -127,6 +135,7 @@ protected override void BeginProcessing() { environment = GraphEnvironment.BuiltInEnvironments[GraphEnvironmentConstants.EnvironmentName.Global]; } + } protected override void ProcessRecord() { @@ -167,7 +176,11 @@ private async Task ProcessRecordAsync() IAuthContext authContext = new AuthContext { TenantId = TenantId, PSHostVersion = this.Host.Version, Environment = environment?.Name }; if (MyInvocation.BoundParameters.ContainsKey(nameof(ClientTimeout))) GraphSession.Instance.RequestContext.ClientTimeout = TimeSpan.FromSeconds(ClientTimeout); - + if(SafeRollOut) + { + environment.AzureADEndpoint = $"{environment.AzureADEndpoint}?safe_rollout=apply%3a0238caeb-f6ca-4efc-afd0-a72e1273a8bc"; + } + WriteDebug($"Connecting to {environment.Name} environment. Azure AD endpoint: {environment.AzureADEndpoint} Graph endpoint: {environment.GraphEndpoint}"); GraphSession.Instance.Environment = environment; GraphSession.Instance.GraphHttpClient = null; if (GraphSession.Instance.InMemoryTokenCache is null) diff --git a/src/Authentication/Authentication/Constants.cs b/src/Authentication/Authentication/Constants.cs index 47924df7842..7f9e9fd35bc 100644 --- a/src/Authentication/Authentication/Constants.cs +++ b/src/Authentication/Authentication/Constants.cs @@ -18,6 +18,7 @@ public static class Constants internal const string AppSecretCredentialParameterSet = nameof(AppSecretCredentialParameterSet); internal const string AccessTokenParameterSet = nameof(AccessTokenParameterSet); internal const string IdentityParameterSet = nameof(IdentityParameterSet); + internal const string SafeRolloutParameterSet = nameof(SafeRolloutParameterSet); internal const string EnvironmentVariableParameterSet = nameof(EnvironmentVariableParameterSet); internal static readonly string ContextSettingsPath = Path.Combine(Core.Constants.GraphDirectoryPath, "mg.context.json"); internal const int MAX_RETRY_DELAY_IN_SECONDS = 180; @@ -48,6 +49,9 @@ public static class HelpMessages public const string Identity = "Login using a Managed Identity."; public const string EnvironmentVariable = "Allows for authentication using environment variables configured on the host machine. See https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/identity/Azure.Identity#environment-variables."; public const string ManagedIdentityClientId = "The client id to authenticate for a user assigned managed identity. For more information on user assigned managed identities see: https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview#how-a-user-assigned-managed-identity-works-with-an-azure-vmId. To use the SystemAssigned identity, leave this field blank."; + + //Help message for safe rollout during torus migration + public const string SafeRollout = "Use this parameter to enable safe rollout of the app owners to use the app in destination tenant based on their deployment strategy. This will allow you to test the app without affecting the existing functionality. Once the migration has been finalized, you can remove this parameter."; } } } From 1f703d18445b0a74433d608df0f5b732a444ee6f Mon Sep 17 00:00:00 2001 From: Timothy Wamalwa Date: Tue, 30 Apr 2024 00:27:46 +0300 Subject: [PATCH 02/24] Updated file --- src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs b/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs index 7926f90070e..e4338ef7767 100644 --- a/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs +++ b/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs @@ -180,8 +180,8 @@ private async Task ProcessRecordAsync() { environment.AzureADEndpoint = $"{environment.AzureADEndpoint}?safe_rollout=apply%3a0238caeb-f6ca-4efc-afd0-a72e1273a8bc"; } - WriteDebug($"Connecting to {environment.Name} environment. Azure AD endpoint: {environment.AzureADEndpoint} Graph endpoint: {environment.GraphEndpoint}"); GraphSession.Instance.Environment = environment; + WriteDebug($"Environment: {GraphSession.Instance.Environment.Name} Azure AD endpoint: {GraphSession.Instance.Environment.AzureADEndpoint} Graph endpoint: {GraphSession.Instance.Environment.GraphEndpoint}"); GraphSession.Instance.GraphHttpClient = null; if (GraphSession.Instance.InMemoryTokenCache is null) GraphSession.Instance.InMemoryTokenCache = new InMemoryTokenCache(); From c760cfa2034e2034f7e9e1db7441ef68cbff7fc7 Mon Sep 17 00:00:00 2001 From: Timothy Wamalwa Date: Tue, 30 Apr 2024 13:01:18 +0300 Subject: [PATCH 03/24] Update Auth helper and ConnectMgGraph classes --- .../Utilities/AuthenticationHelpers.cs | 38 ++++++++++--------- .../Authentication/Cmdlets/ConnectMgGraph.cs | 15 ++++---- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs index 3d004336109..d8ba725e2a4 100644 --- a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs +++ b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs @@ -30,16 +30,15 @@ public static class AuthenticationHelpers /// /// The to get a token credential for. /// A based on provided . - public static async Task GetTokenCredentialAsync(IAuthContext authContext, CancellationToken cancellationToken = default) + public static async Task GetTokenCredentialAsync(IAuthContext authContext, bool safeRollOut, CancellationToken cancellationToken = default) { if (authContext is null) throw new AuthenticationException(ErrorConstants.Message.MissingAuthContext); - switch (authContext.AuthType) { case AuthenticationType.Delegated: if (authContext.TokenCredentialType == TokenCredentialType.InteractiveBrowser) - return await GetInteractiveBrowserCredentialAsync(authContext, cancellationToken).ConfigureAwait(false); + return await GetInteractiveBrowserCredentialAsync(authContext, safeRollOut, cancellationToken).ConfigureAwait(false); return await GetDeviceCodeCredentialAsync(authContext, cancellationToken).ConfigureAwait(false); case AuthenticationType.AppOnly: return authContext.TokenCredentialType == TokenCredentialType.ClientCertificate @@ -63,7 +62,7 @@ private static async Task GetEnvironmentCredentialAsync(IAuthCo var tokenCredentialOptions = new TokenCredentialOptions { - AuthorityHost = new Uri(GetAuthorityUrl(authContext)) + AuthorityHost = new Uri(GetAuthorityUrl(authContext, false)) }; if (IsAuthFlowNotSupported()) @@ -93,7 +92,7 @@ private static async Task GetClientSecretCredentialAsync(IAuthC var clientSecretCredentialOptions = new ClientSecretCredentialOptions { - AuthorityHost = new Uri(GetAuthorityUrl(authContext)), + AuthorityHost = new Uri(GetAuthorityUrl(authContext, false)), TokenCachePersistenceOptions = GetTokenCachePersistenceOptions(authContext) }; var clientSecretCredential = new ClientSecretCredential(authContext.TenantId, authContext.ClientId, authContext.ClientSecret.ConvertToString(), clientSecretCredentialOptions); @@ -109,16 +108,16 @@ private static async Task GetManagedIdentityCredentialAsync(IAu return await Task.FromResult(new ManagedIdentityCredential(userAccountId)).ConfigureAwait(false); } - private static async Task GetInteractiveBrowserCredentialAsync(IAuthContext authContext, CancellationToken cancellationToken = default) + private static async Task GetInteractiveBrowserCredentialAsync(IAuthContext authContext,bool safeRollOut, CancellationToken cancellationToken = default) { if (authContext is null) throw new AuthenticationException(ErrorConstants.Message.MissingAuthContext); 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.TenantId = authContext.TenantId ?? "common"; + interactiveOptions.AuthorityHost = new Uri(GetAuthorityUrl(authContext, safeRollOut)); + Console.WriteLine($"Got authority host {interactiveOptions.AuthorityHost}"); interactiveOptions.TokenCachePersistenceOptions = GetTokenCachePersistenceOptions(authContext); - if (!File.Exists(Constants.AuthRecordPath)) { AuthenticationRecord authRecord; @@ -156,7 +155,7 @@ private static async Task GetDeviceCodeCredentialAsync(IAu { ClientId = authContext.ClientId, TenantId = authContext.TenantId, - AuthorityHost = new Uri(GetAuthorityUrl(authContext)), + AuthorityHost = new Uri(GetAuthorityUrl(authContext, false)), TokenCachePersistenceOptions = GetTokenCachePersistenceOptions(authContext), DeviceCodeCallback = (code, cancellation) => { @@ -183,7 +182,7 @@ private static async Task GetClientCertificateCrede var clientCredentialOptions = new ClientCertificateCredentialOptions { - AuthorityHost = new Uri(GetAuthorityUrl(authContext)), + AuthorityHost = new Uri(GetAuthorityUrl(authContext, false)), TokenCachePersistenceOptions = GetTokenCachePersistenceOptions(authContext), SendCertificateChain = authContext.SendCertificateChain }; @@ -211,7 +210,7 @@ public static async Task GetAuthenticationProv return new AzureIdentityAccessTokenProvider(credential: tokenCrdential, scopes: GetScopes(authContext)); } - public static async Task AuthenticateAsync(IAuthContext authContext, CancellationToken cancellationToken) + public static async Task AuthenticateAsync(IAuthContext authContext, bool safeRollOut, CancellationToken cancellationToken) { if (authContext is null) throw new AuthenticationException(ErrorConstants.Message.MissingAuthContext); @@ -227,7 +226,7 @@ public static async Task AuthenticateAsync(IAuthContext authContex (args, message) => GraphSession.Instance.OutputWriter.WriteDebug($"{message}"), level: EventLevel.Informational)) { - signInAuthContext = await SignInAsync(authContext, cancellationToken).ConfigureAwait(false); + signInAuthContext = await SignInAsync(authContext, safeRollOut,cancellationToken).ConfigureAwait(false); retrySignIn = false; }; } @@ -272,11 +271,11 @@ public static async Task AuthenticateAsync(IAuthContext authContex return signInAuthContext; } - private static async Task SignInAsync(IAuthContext authContext, CancellationToken cancellationToken = default) + private static async Task SignInAsync(IAuthContext authContext, bool safeRollOut, CancellationToken cancellationToken = default) { if (authContext is null) throw new AuthenticationException(ErrorConstants.Message.MissingAuthContext); - var tokenCredential = await GetTokenCredentialAsync(authContext, cancellationToken).ConfigureAwait(false); + var tokenCredential = await GetTokenCredentialAsync(authContext, safeRollOut, cancellationToken).ConfigureAwait(false); var token = await tokenCredential.GetTokenAsync(new TokenRequestContext(GetScopes(authContext)), cancellationToken).ConfigureAwait(false); JwtHelpers.DecodeJWT(token.Token, account: null, ref authContext); return authContext; @@ -304,14 +303,19 @@ private static string[] GetScopes(IAuthContext authContext) /// /// The to get an authority URL for. /// - private static string GetAuthorityUrl(IAuthContext authContext) + private static string GetAuthorityUrl(IAuthContext authContext, bool safeRollOut) { if (authContext is null) throw new AuthenticationException(ErrorConstants.Message.MissingAuthContext); string audience = authContext.TenantId ?? Constants.DefaultTenant; + if(safeRollOut) + return GraphSession.Instance.Environment != null + ? $"{GraphSession.Instance.Environment.AzureADEndpoint}?safe_rollout=apply%3a0238caeb-f6ca-4efc-afd0-a72e1273a8bc" + : $"{Constants.DefaultAzureADEndpoint}?safe_rollout=apply%3a0238caeb-f6ca-4efc-afd0-a72e1273a8bc"; + return GraphSession.Instance.Environment != null ? $"{GraphSession.Instance.Environment.AzureADEndpoint}/{audience}" - : $"{Constants.DefaultAzureADEndpoint}/{audience}"; + : $"{Constants.DefaultAzureADEndpoint}/{audience}"; } /// diff --git a/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs b/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs index e4338ef7767..1d8791af2ab 100644 --- a/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs +++ b/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs @@ -59,8 +59,8 @@ public class ConnectMgGraph : PSCmdlet, IModuleAssemblyInitializer, IModuleAssem /* Torus migration changes for client based rollout */ - - [Parameter(Mandatory = false, ParameterSetName = Constants.SafeRolloutParameterSet, HelpMessage = HelpMessages.SafeRollout)] + [Parameter(ParameterSetName = Constants.UserParameterSet, Mandatory = false, HelpMessage = HelpMessages.SafeRollout)] + //[Parameter(Mandatory = false, ParameterSetName = Constants.SafeRolloutParameterSet, HelpMessage = HelpMessages.SafeRollout)] [Alias("ValidateRollout")] public bool SafeRollOut { get; set; } @@ -176,12 +176,10 @@ private async Task ProcessRecordAsync() IAuthContext authContext = new AuthContext { TenantId = TenantId, PSHostVersion = this.Host.Version, Environment = environment?.Name }; if (MyInvocation.BoundParameters.ContainsKey(nameof(ClientTimeout))) GraphSession.Instance.RequestContext.ClientTimeout = TimeSpan.FromSeconds(ClientTimeout); - if(SafeRollOut) - { - environment.AzureADEndpoint = $"{environment.AzureADEndpoint}?safe_rollout=apply%3a0238caeb-f6ca-4efc-afd0-a72e1273a8bc"; - } + + bool.TryParse(SafeRollOut.ToString().ToLower(), out bool safeRollOut); + WriteDebug($"SafeRollOut Initiated: {safeRollOut} "); GraphSession.Instance.Environment = environment; - WriteDebug($"Environment: {GraphSession.Instance.Environment.Name} Azure AD endpoint: {GraphSession.Instance.Environment.AzureADEndpoint} Graph endpoint: {GraphSession.Instance.Environment.GraphEndpoint}"); GraphSession.Instance.GraphHttpClient = null; if (GraphSession.Instance.InMemoryTokenCache is null) GraphSession.Instance.InMemoryTokenCache = new InMemoryTokenCache(); @@ -260,7 +258,8 @@ private async Task ProcessRecordAsync() try { - GraphSession.Instance.AuthContext = await AuthenticationHelpers.AuthenticateAsync(authContext, _cancellationTokenSource.Token).ConfigureAwait(false); + GraphSession.Instance.AuthContext = await AuthenticationHelpers.AuthenticateAsync(authContext, safeRollOut, _cancellationTokenSource.Token).ConfigureAwait(false); + } catch (Exception) { From c87473980347988c61c55a39935ad9dad93f822b Mon Sep 17 00:00:00 2001 From: Timothy Wamalwa Date: Tue, 30 Apr 2024 14:16:28 +0300 Subject: [PATCH 04/24] Removed unnecessary debug --- src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs b/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs index 1d8791af2ab..db8b37365ec 100644 --- a/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs +++ b/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs @@ -178,7 +178,6 @@ private async Task ProcessRecordAsync() GraphSession.Instance.RequestContext.ClientTimeout = TimeSpan.FromSeconds(ClientTimeout); bool.TryParse(SafeRollOut.ToString().ToLower(), out bool safeRollOut); - WriteDebug($"SafeRollOut Initiated: {safeRollOut} "); GraphSession.Instance.Environment = environment; GraphSession.Instance.GraphHttpClient = null; if (GraphSession.Instance.InMemoryTokenCache is null) From 6e077257626f51f053281a8b5406bb7f5a62102a Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Thu, 16 May 2024 18:26:00 +0300 Subject: [PATCH 05/24] Add Safe rollout parameter to access token paramter set --- src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs b/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs index db8b37365ec..6d473d0bc96 100644 --- a/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs +++ b/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs @@ -59,8 +59,7 @@ public class ConnectMgGraph : PSCmdlet, IModuleAssemblyInitializer, IModuleAssem /* Torus migration changes for client based rollout */ - [Parameter(ParameterSetName = Constants.UserParameterSet, Mandatory = false, HelpMessage = HelpMessages.SafeRollout)] - //[Parameter(Mandatory = false, ParameterSetName = Constants.SafeRolloutParameterSet, HelpMessage = HelpMessages.SafeRollout)] + [Parameter(ParameterSetName = Constants.AccessTokenParameterSet, Mandatory = false, HelpMessage = HelpMessages.SafeRollout)] [Alias("ValidateRollout")] public bool SafeRollOut { get; set; } From 54ad2966a50a471fda61136067a9b4c3efaec892 Mon Sep 17 00:00:00 2001 From: Timothy Wamalwa Date: Fri, 17 May 2024 07:09:50 +0300 Subject: [PATCH 06/24] Added Safe rollout feature on user provided --- .../Authentication/Cmdlets/ConnectMgGraph.cs | 23 +++++++++++++++---- .../GraphEnvironmentConstants.cs | 17 +++++++++++++- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs b/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs index db8b37365ec..78c1565cb3e 100644 --- a/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs +++ b/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs @@ -60,7 +60,7 @@ public class ConnectMgGraph : PSCmdlet, IModuleAssemblyInitializer, IModuleAssem Torus migration changes for client based rollout */ [Parameter(ParameterSetName = Constants.UserParameterSet, Mandatory = false, HelpMessage = HelpMessages.SafeRollout)] - //[Parameter(Mandatory = false, ParameterSetName = Constants.SafeRolloutParameterSet, HelpMessage = HelpMessages.SafeRollout)] + [Parameter(Mandatory = false, ParameterSetName = Constants.AccessTokenParameterSet, HelpMessage = HelpMessages.SafeRollout)] [Alias("ValidateRollout")] public bool SafeRollOut { get; set; } @@ -133,7 +133,15 @@ protected override void BeginProcessing() } else { - environment = GraphEnvironment.BuiltInEnvironments[GraphEnvironmentConstants.EnvironmentName.Global]; + bool.TryParse(SafeRollOut.ToString().ToLower(), out bool safeRollOut); + if(safeRollOut && AccessToken != null){ + //Use Torus environment + environment = GraphEnvironment.BuiltInEnvironments[GraphEnvironmentConstants.EnvironmentName.Torus]; + } + else{ + environment = GraphEnvironment.BuiltInEnvironments[GraphEnvironmentConstants.EnvironmentName.Global]; + } + } } @@ -176,7 +184,6 @@ private async Task ProcessRecordAsync() IAuthContext authContext = new AuthContext { TenantId = TenantId, PSHostVersion = this.Host.Version, Environment = environment?.Name }; if (MyInvocation.BoundParameters.ContainsKey(nameof(ClientTimeout))) GraphSession.Instance.RequestContext.ClientTimeout = TimeSpan.FromSeconds(ClientTimeout); - bool.TryParse(SafeRollOut.ToString().ToLower(), out bool safeRollOut); GraphSession.Instance.Environment = environment; GraphSession.Instance.GraphHttpClient = null; @@ -257,7 +264,7 @@ private async Task ProcessRecordAsync() try { - GraphSession.Instance.AuthContext = await AuthenticationHelpers.AuthenticateAsync(authContext, safeRollOut, _cancellationTokenSource.Token).ConfigureAwait(false); + GraphSession.Instance.AuthContext = await AuthenticationHelpers.AuthenticateAsync(authContext, safeRollOut,_cancellationTokenSource.Token).ConfigureAwait(false); } catch (Exception) @@ -281,6 +288,14 @@ private static string GetWelcomeMessage(string clientId, string authType) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine($"Welcome to Microsoft Graph!{System.Environment.NewLine}"); + //Show message that this is a torus test if environment is torus and the access token is user defined + if (GraphEnvironment.BuiltInEnvironments[GraphEnvironmentConstants.EnvironmentName.Torus].Name == GraphSession.Instance.Environment.Name) + { + stringBuilder.AppendLine($"You are connected to the Torus environment. This is a test environment and should not be used for production scenarios.{System.Environment.NewLine}"); + //Show the azure endpoint for torus environment + stringBuilder.AppendLine($"Azure Endpoint: {GraphEnvironment.BuiltInEnvironments[GraphEnvironmentConstants.EnvironmentName.Torus].AzureADEndpoint}{System.Environment.NewLine}"); + } + //Show torus migration message if safe rollout is enabled stringBuilder.AppendLine($"Connected via {authType.ToLower()} access using {clientId}"); stringBuilder.AppendLine($"Readme: {Constants.SdkReadmeLink}"); stringBuilder.AppendLine($"SDK Docs: {Constants.SdkDocsLink}"); diff --git a/src/Authentication/Authentication/GraphEnvironmentConstants.cs b/src/Authentication/Authentication/GraphEnvironmentConstants.cs index b13710d234f..8e942fc114c 100644 --- a/src/Authentication/Authentication/GraphEnvironmentConstants.cs +++ b/src/Authentication/Authentication/GraphEnvironmentConstants.cs @@ -14,6 +14,10 @@ internal static class GraphEnvironmentConstants /// public static class EnvironmentName { + /// + /// Environment used for tours tests. + /// + public const string Torus = "Torus"; /// /// The graph national cloud. /// @@ -103,7 +107,18 @@ public static class EnvironmentType AzureADEndpoint = "https://login.chinacloudapi.cn", GraphEndpoint = "https://microsoftgraph.chinacloudapi.cn" } - } + }, + + // Environment used for torus tests. + { + EnvironmentName.Torus, new GraphEnvironment + { + Name = EnvironmentName.Torus, + Type = EnvironmentType.BuiltIn, + AzureADEndpoint = "https://login.microsoftonline.com?safe_rollout=apply%3a0238caeb-f6ca-4efc-afd0-a72e1273a8bc", + GraphEndpoint = "https://graph.microsoft.com" + } + }, }; } } From de0efd7de5798a42ede2c09779d1009dcbeb3f46 Mon Sep 17 00:00:00 2001 From: Timothy Wamalwa Date: Fri, 17 May 2024 09:15:49 +0300 Subject: [PATCH 07/24] updated endpoint --- tools/OpenApiInfoGenerator/OpenApiInfoGenerator/Program.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/OpenApiInfoGenerator/OpenApiInfoGenerator/Program.cs b/tools/OpenApiInfoGenerator/OpenApiInfoGenerator/Program.cs index 36e9f6c0949..ee506991426 100644 --- a/tools/OpenApiInfoGenerator/OpenApiInfoGenerator/Program.cs +++ b/tools/OpenApiInfoGenerator/OpenApiInfoGenerator/Program.cs @@ -6,8 +6,8 @@ internal class Program { public static string openApiInfoFile = "openApiInfo.json"; public static string openApiFileError = "openAPIErrors.csv"; - private const string openApiInfoMetadataUrl_v1 = "https://raw.githubusercontent.com/microsoftgraph/msgraph-sdk-powershell/metadata-changes-detection/docs/OpenApiInfo/v1.0/openApiInfo.json"; - private const string openApiInfoMetadataUrl_beta = "https://raw.githubusercontent.com/microsoftgraph/msgraph-sdk-powershell/metadata-changes-detection/docs/OpenApiInfo/beta/openApiInfo.json"; + private const string openApiInfoMetadataUrl_v1 = "https://raw.githubusercontent.com/microsoftgraph/msgraph-sdk-powershell/dev/docs/OpenApiInfo/v1.0/openApiInfo.json"; + private const string openApiInfoMetadataUrl_beta = "https://raw.githubusercontent.com/microsoftgraph/msgraph-sdk-powershell/dev/docs/OpenApiInfo/beta/openApiInfo.json"; private static IList openApiInfo_v1 = new OriginalMetadata(openApiInfoMetadataUrl_v1).GetOpenApiInfo(); private static IList openApiInfo_beta = new OriginalMetadata(openApiInfoMetadataUrl_beta).GetOpenApiInfo(); private static IDictionary> openApiVersions = new Dictionary>(); From eae203e3330a991ae0def7b2285db38c35f23b06 Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Mon, 20 May 2024 16:34:49 +0300 Subject: [PATCH 08/24] Add safe rollout parameter sets to support different auth flows --- src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs b/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs index e3fa941eba6..9f956af9da9 100644 --- a/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs +++ b/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs @@ -60,6 +60,10 @@ public class ConnectMgGraph : PSCmdlet, IModuleAssemblyInitializer, IModuleAssem Torus migration changes for client based rollout */ [Parameter(ParameterSetName = Constants.AccessTokenParameterSet, Mandatory = false, HelpMessage = HelpMessages.SafeRollout)] + [Parameter(Mandatory = false, ParameterSetName = Constants.AppCertificateParameterSet, HelpMessage = HelpMessages.Certificate)] + [Parameter(Mandatory = false, ParameterSetName = Constants.AppSecretCredentialParameterSet, HelpMessage = HelpMessages.ClientSecretCredential)] + [Parameter(ParameterSetName = Constants.UserParameterSet, Mandatory = false, HelpMessage = HelpMessages.SafeRollout)] + [Parameter(ParameterSetName = Constants.EnvironmentVariableParameterSet, Mandatory = false, HelpMessage = HelpMessages.Environment)] [Alias("ValidateRollout")] public bool SafeRollOut { get; set; } From 1105de373d34b10ba4d45fff5ebe917e6ae9a885 Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Mon, 20 May 2024 16:53:13 +0300 Subject: [PATCH 09/24] Update login authority during safe rollout --- .../Authentication.Core/Utilities/AuthenticationHelpers.cs | 2 +- src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs index d8ba725e2a4..10d2acf9dd0 100644 --- a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs +++ b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs @@ -310,7 +310,7 @@ private static string GetAuthorityUrl(IAuthContext authContext, bool safeRollOut string audience = authContext.TenantId ?? Constants.DefaultTenant; if(safeRollOut) return GraphSession.Instance.Environment != null - ? $"{GraphSession.Instance.Environment.AzureADEndpoint}?safe_rollout=apply%3a0238caeb-f6ca-4efc-afd0-a72e1273a8bc" + ? $"{GraphSession.Instance.Environment.AzureADEndpoint}" : $"{Constants.DefaultAzureADEndpoint}?safe_rollout=apply%3a0238caeb-f6ca-4efc-afd0-a72e1273a8bc"; return GraphSession.Instance.Environment != null diff --git a/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs b/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs index 9f956af9da9..ab8bac696eb 100644 --- a/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs +++ b/src/Authentication/Authentication/Cmdlets/ConnectMgGraph.cs @@ -137,7 +137,7 @@ protected override void BeginProcessing() else { bool.TryParse(SafeRollOut.ToString().ToLower(), out bool safeRollOut); - if(safeRollOut && AccessToken != null){ + if (safeRollOut) { //Use Torus environment environment = GraphEnvironment.BuiltInEnvironments[GraphEnvironmentConstants.EnvironmentName.Torus]; } From 9119652e99ec4e89e5d44d2b94c0395f7810456d Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Mon, 3 Jun 2024 18:34:55 +0300 Subject: [PATCH 10/24] Change safe rollout authority host to valid authority --- .../Authentication.Core/Utilities/AuthenticationHelpers.cs | 5 ----- .../Authentication/GraphEnvironmentConstants.cs | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs index 10d2acf9dd0..ded4994a9db 100644 --- a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs +++ b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs @@ -308,11 +308,6 @@ private static string GetAuthorityUrl(IAuthContext authContext, bool safeRollOut if (authContext is null) throw new AuthenticationException(ErrorConstants.Message.MissingAuthContext); string audience = authContext.TenantId ?? Constants.DefaultTenant; - if(safeRollOut) - return GraphSession.Instance.Environment != null - ? $"{GraphSession.Instance.Environment.AzureADEndpoint}" - : $"{Constants.DefaultAzureADEndpoint}?safe_rollout=apply%3a0238caeb-f6ca-4efc-afd0-a72e1273a8bc"; - return GraphSession.Instance.Environment != null ? $"{GraphSession.Instance.Environment.AzureADEndpoint}/{audience}" : $"{Constants.DefaultAzureADEndpoint}/{audience}"; diff --git a/src/Authentication/Authentication/GraphEnvironmentConstants.cs b/src/Authentication/Authentication/GraphEnvironmentConstants.cs index 8e942fc114c..7f674caf4a0 100644 --- a/src/Authentication/Authentication/GraphEnvironmentConstants.cs +++ b/src/Authentication/Authentication/GraphEnvironmentConstants.cs @@ -115,7 +115,7 @@ public static class EnvironmentType { Name = EnvironmentName.Torus, Type = EnvironmentType.BuiltIn, - AzureADEndpoint = "https://login.microsoftonline.com?safe_rollout=apply%3a0238caeb-f6ca-4efc-afd0-a72e1273a8bc", + AzureADEndpoint = "https://login.microsoftonline.com", GraphEndpoint = "https://graph.microsoft.com" } }, From 06e6064a04bedbc680a420dc8c87dc30ec34b8bb Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Tue, 4 Jun 2024 22:24:27 +0300 Subject: [PATCH 11/24] Add azure .NET sdk as submodule --- .gitmodules | 4 ++++ azure-sdk-for-net | 1 + 2 files changed, 5 insertions(+) create mode 160000 azure-sdk-for-net diff --git a/.gitmodules b/.gitmodules index 8cdc33c02ec..78f43921495 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,3 +2,7 @@ path = autorest.powershell url = https://github.com/microsoftgraph/autorest.powershell branch = powershell_v2 +[submodule "azure-sdk-for-net"] + path = azure-sdk-for-net + url = https://github.com/Ndiritu/azure-sdk-for-net.git + branch = feat/token-credential-query-parameters diff --git a/azure-sdk-for-net b/azure-sdk-for-net new file mode 160000 index 00000000000..5400419ed98 --- /dev/null +++ b/azure-sdk-for-net @@ -0,0 +1 @@ +Subproject commit 5400419ed982e64f9d9e44911d55689a65649cec From 357a24bd3f84d6ab55cbd9a587cb47821c9e72cd Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Tue, 4 Jun 2024 22:43:56 +0300 Subject: [PATCH 12/24] Bump version --- config/ModuleMetadata.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/ModuleMetadata.json b/config/ModuleMetadata.json index c6cc198b1eb..81e50c37af7 100644 --- a/config/ModuleMetadata.json +++ b/config/ModuleMetadata.json @@ -26,15 +26,15 @@ ], "versions": { "authentication": { - "prerelease": "preview1", + "prerelease": "preview2", "version": "2.22.0" }, "beta": { - "prerelease": "preview1", + "prerelease": "preview2", "version": "2.22.0" }, "v1.0": { - "prerelease": "preview1", + "prerelease": "preview2", "version": "2.22.0" } } From d94e8f1c59e4d0718a75664864a0c0575e9d5822 Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Tue, 4 Jun 2024 23:29:41 +0300 Subject: [PATCH 13/24] Fix Azure.Identity submodule reference in Authentication module --- azure-sdk-for-net | 2 +- .../Microsoft.Graph.Authentication.Core.csproj | 5 +++-- .../Microsoft.Graph.Authentication.Test.csproj | 3 ++- src/Authentication/Authentication.sln | 6 ++++++ .../Authentication/Microsoft.Graph.Authentication.csproj | 3 ++- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/azure-sdk-for-net b/azure-sdk-for-net index 5400419ed98..df53011334b 160000 --- a/azure-sdk-for-net +++ b/azure-sdk-for-net @@ -1 +1 @@ -Subproject commit 5400419ed982e64f9d9e44911d55689a65649cec +Subproject commit df53011334b2e9c2ab61df1b4661278ce609caa3 diff --git a/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj b/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj index c385a4f63ae..d11ec0a78f5 100644 --- a/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj +++ b/src/Authentication/Authentication.Core/Microsoft.Graph.Authentication.Core.csproj @@ -4,14 +4,15 @@ 9.0 netstandard2.0;net6.0;net472 Microsoft.Graph.PowerShell.Authentication.Core - 2.18.0 + 2.22.0 + preview2 true true - + diff --git a/src/Authentication/Authentication.Test/Microsoft.Graph.Authentication.Test.csproj b/src/Authentication/Authentication.Test/Microsoft.Graph.Authentication.Test.csproj index 8a3d6c004f8..63b93836d74 100644 --- a/src/Authentication/Authentication.Test/Microsoft.Graph.Authentication.Test.csproj +++ b/src/Authentication/Authentication.Test/Microsoft.Graph.Authentication.Test.csproj @@ -2,7 +2,8 @@ net6.0;net472 false - 2.8.0 + 2.22.0 + preview2 diff --git a/src/Authentication/Authentication.sln b/src/Authentication/Authentication.sln index 1e4002e7a0b..3eb3306ea2b 100644 --- a/src/Authentication/Authentication.sln +++ b/src/Authentication/Authentication.sln @@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Graph.Authenticat EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenApiInfoGenerator", "..\..\tools\OpenApiInfoGenerator\OpenApiInfoGenerator\OpenApiInfoGenerator.csproj", "{6437E29A-E398-48EE-B7BE-27A8C922F13E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Identity", "..\..\azure-sdk-for-net\sdk\identity\Azure.Identity\src\Azure.Identity.csproj", "{BDAFCAD5-1DAB-4C57-A7D4-140E396CCC83}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -33,6 +35,10 @@ Global {6437E29A-E398-48EE-B7BE-27A8C922F13E}.Debug|Any CPU.Build.0 = Debug|Any CPU {6437E29A-E398-48EE-B7BE-27A8C922F13E}.Release|Any CPU.ActiveCfg = Release|Any CPU {6437E29A-E398-48EE-B7BE-27A8C922F13E}.Release|Any CPU.Build.0 = Release|Any CPU + {BDAFCAD5-1DAB-4C57-A7D4-140E396CCC83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BDAFCAD5-1DAB-4C57-A7D4-140E396CCC83}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BDAFCAD5-1DAB-4C57-A7D4-140E396CCC83}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BDAFCAD5-1DAB-4C57-A7D4-140E396CCC83}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Authentication/Authentication/Microsoft.Graph.Authentication.csproj b/src/Authentication/Authentication/Microsoft.Graph.Authentication.csproj index 383f9e88005..fab65eee1a7 100644 --- a/src/Authentication/Authentication/Microsoft.Graph.Authentication.csproj +++ b/src/Authentication/Authentication/Microsoft.Graph.Authentication.csproj @@ -10,7 +10,8 @@ Microsoft.Graph.Authentication.nuspec © Microsoft Corporation. All rights reserved. - 2.6.1 + 2.22.0 + preview2 true From ecb761880c0b9f898edd6654158644f33efa2dbb Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Wed, 5 Jun 2024 00:06:13 +0300 Subject: [PATCH 14/24] Change submodule branch --- .gitmodules | 2 +- azure-sdk-for-net | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 78f43921495..7e13bf3d635 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,4 +5,4 @@ [submodule "azure-sdk-for-net"] path = azure-sdk-for-net url = https://github.com/Ndiritu/azure-sdk-for-net.git - branch = feat/token-credential-query-parameters + branch = feat/extra-query-params diff --git a/azure-sdk-for-net b/azure-sdk-for-net index df53011334b..f4dc3d86dce 160000 --- a/azure-sdk-for-net +++ b/azure-sdk-for-net @@ -1 +1 @@ -Subproject commit df53011334b2e9c2ab61df1b4661278ce609caa3 +Subproject commit f4dc3d86dce735e43f3b0b1b2ea476d42eed8422 From 6158bb6d353d328358356e1d6dd14fd2772050c0 Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Wed, 5 Jun 2024 00:43:11 +0300 Subject: [PATCH 15/24] Update submodule --- azure-sdk-for-net | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-sdk-for-net b/azure-sdk-for-net index f4dc3d86dce..8f5e6c13783 160000 --- a/azure-sdk-for-net +++ b/azure-sdk-for-net @@ -1 +1 @@ -Subproject commit f4dc3d86dce735e43f3b0b1b2ea476d42eed8422 +Subproject commit 8f5e6c13783e5e64af98afd29d929ab72161f56d From e2cef83c091e62cdf5d42cff36fe61efe1ff7e68 Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Wed, 5 Jun 2024 00:46:37 +0300 Subject: [PATCH 16/24] Add safe rollout as extra query parameter --- .../Utilities/AuthenticationHelpers.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs index ded4994a9db..a8aa28565b6 100644 --- a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs +++ b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs @@ -11,6 +11,7 @@ using Microsoft.Identity.Client.Extensions.Msal; using System; using System.Diagnostics.Tracing; +using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; @@ -118,6 +119,13 @@ private static async Task GetInteractiveBrowserCre interactiveOptions.AuthorityHost = new Uri(GetAuthorityUrl(authContext, safeRollOut)); Console.WriteLine($"Got authority host {interactiveOptions.AuthorityHost}"); interactiveOptions.TokenCachePersistenceOptions = GetTokenCachePersistenceOptions(authContext); + if (safeRollOut) + { + interactiveOptions.ExtraQueryParameters = new Dictionary + { + { "safe_rollout", "apply%3a0238caeb-f6ca-4efc-afd0-a72e1273a8bc" } + }; + } if (!File.Exists(Constants.AuthRecordPath)) { AuthenticationRecord authRecord; From e77a074397f3d382ffe78e5f7c0c80f6d3f0623c Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Wed, 5 Jun 2024 11:44:50 +0300 Subject: [PATCH 17/24] Add safe rollout as extra query parameter --- .../Utilities/AuthenticationHelpers.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs index a8aa28565b6..fd7cc91b42d 100644 --- a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs +++ b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs @@ -40,7 +40,7 @@ public static async Task GetTokenCredentialAsync(IAuthContext a case AuthenticationType.Delegated: if (authContext.TokenCredentialType == TokenCredentialType.InteractiveBrowser) return await GetInteractiveBrowserCredentialAsync(authContext, safeRollOut, cancellationToken).ConfigureAwait(false); - return await GetDeviceCodeCredentialAsync(authContext, cancellationToken).ConfigureAwait(false); + return await GetDeviceCodeCredentialAsync(authContext, safeRollOut, cancellationToken).ConfigureAwait(false); case AuthenticationType.AppOnly: return authContext.TokenCredentialType == TokenCredentialType.ClientCertificate ? await GetClientCertificateCredentialAsync(authContext).ConfigureAwait(false) @@ -154,7 +154,7 @@ private static async Task GetInteractiveBrowserCre return new InteractiveBrowserCredential(interactiveOptions); } - private static async Task GetDeviceCodeCredentialAsync(IAuthContext authContext, CancellationToken cancellationToken = default) + private static async Task GetDeviceCodeCredentialAsync(IAuthContext authContext, bool safeRollOut, CancellationToken cancellationToken = default) { if (authContext is null) throw new AuthenticationException(ErrorConstants.Message.MissingAuthContext); @@ -171,6 +171,13 @@ private static async Task GetDeviceCodeCredentialAsync(IAu return Task.CompletedTask; } }; + if (safeRollOut) + { + deviceCodeOptions.ExtraQueryParameters = new Dictionary + { + { "safe_rollout", "apply%3a0238caeb-f6ca-4efc-afd0-a72e1273a8bc" } + }; + } if (!File.Exists(Constants.AuthRecordPath)) { var deviceCodeCredential = new DeviceCodeCredential(deviceCodeOptions); From 58ab29ba4dda578c018a2e18d202f361210b7f46 Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Wed, 5 Jun 2024 12:52:04 +0300 Subject: [PATCH 18/24] Update submodule --- azure-sdk-for-net | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-sdk-for-net b/azure-sdk-for-net index 8f5e6c13783..6c3fe39a370 160000 --- a/azure-sdk-for-net +++ b/azure-sdk-for-net @@ -1 +1 @@ -Subproject commit 8f5e6c13783e5e64af98afd29d929ab72161f56d +Subproject commit 6c3fe39a370c99c0d3c7dfd9ea624f3d81e0cccd From 269c76ee7da16c9f24a150db6f025867e0f8529a Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Wed, 5 Jun 2024 12:52:18 +0300 Subject: [PATCH 19/24] Update safe rollout query param string --- .../Authentication.Core/Utilities/AuthenticationHelpers.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs index fd7cc91b42d..58fc62672d8 100644 --- a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs +++ b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs @@ -123,7 +123,7 @@ private static async Task GetInteractiveBrowserCre { interactiveOptions.ExtraQueryParameters = new Dictionary { - { "safe_rollout", "apply%3a0238caeb-f6ca-4efc-afd0-a72e1273a8bc" } + { "safe_rollout", "apply:0238caeb-f6ca-4efc-afd0-a72e1273a8bc" } }; } if (!File.Exists(Constants.AuthRecordPath)) @@ -175,7 +175,7 @@ private static async Task GetDeviceCodeCredentialAsync(IAu { deviceCodeOptions.ExtraQueryParameters = new Dictionary { - { "safe_rollout", "apply%3a0238caeb-f6ca-4efc-afd0-a72e1273a8bc" } + { "safe_rollout", "apply:0238caeb-f6ca-4efc-afd0-a72e1273a8bc" } }; } if (!File.Exists(Constants.AuthRecordPath)) From f13219f25568835d1a47682d559cd977bccf2ab4 Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Tue, 18 Jun 2024 16:13:49 +0300 Subject: [PATCH 20/24] Add sub-claim to auth context --- .../Authentication.Core/Interfaces/IAuthContext.cs | 1 + src/Authentication/Authentication.Core/Models/JwtPayload.cs | 3 +++ src/Authentication/Authentication.Core/Utilities/JwtHelpers.cs | 1 + 3 files changed, 5 insertions(+) diff --git a/src/Authentication/Authentication.Core/Interfaces/IAuthContext.cs b/src/Authentication/Authentication.Core/Interfaces/IAuthContext.cs index d7060de2a46..bfaaf206e0f 100644 --- a/src/Authentication/Authentication.Core/Interfaces/IAuthContext.cs +++ b/src/Authentication/Authentication.Core/Interfaces/IAuthContext.cs @@ -52,5 +52,6 @@ public interface IAuthContext ContextScope ContextScope { get; set; } Version PSHostVersion { get; set; } SecureString ClientSecret { get; set; } + string SubClaim { get; set; } } } \ No newline at end of file diff --git a/src/Authentication/Authentication.Core/Models/JwtPayload.cs b/src/Authentication/Authentication.Core/Models/JwtPayload.cs index a439981875d..f9c3de588b4 100644 --- a/src/Authentication/Authentication.Core/Models/JwtPayload.cs +++ b/src/Authentication/Authentication.Core/Models/JwtPayload.cs @@ -50,5 +50,8 @@ internal partial class JwtPayload [JsonPropertyName("upn")] public string Upn { get; set; } + + [JsonPropertyName("sub")] + public string Sub { get; set; } } } diff --git a/src/Authentication/Authentication.Core/Utilities/JwtHelpers.cs b/src/Authentication/Authentication.Core/Utilities/JwtHelpers.cs index 826cd1227d8..c4ec78ec3e0 100644 --- a/src/Authentication/Authentication.Core/Utilities/JwtHelpers.cs +++ b/src/Authentication/Authentication.Core/Utilities/JwtHelpers.cs @@ -42,6 +42,7 @@ internal static void DecodeJWT(string jwToken, IAccount account, ref IAuthContex authContext.TenantId = jwtPayload?.Tid ?? account?.HomeAccountId?.TenantId; authContext.AppName = jwtPayload?.AppDisplayname; authContext.Account = jwtPayload?.Upn ?? account?.Username; + authContext.SubClaim = jwtPayload?.Sub; } /// From 990695587cd30419ebf5529460a82e466b1fe1d6 Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Mon, 24 Jun 2024 13:14:16 +0300 Subject: [PATCH 21/24] Enable safe rollout on app only auth --- .../Utilities/AuthenticationHelpers.cs | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs index 58fc62672d8..6e919c686a1 100644 --- a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs +++ b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs @@ -43,8 +43,8 @@ public static async Task GetTokenCredentialAsync(IAuthContext a return await GetDeviceCodeCredentialAsync(authContext, safeRollOut, cancellationToken).ConfigureAwait(false); case AuthenticationType.AppOnly: return authContext.TokenCredentialType == TokenCredentialType.ClientCertificate - ? await GetClientCertificateCredentialAsync(authContext).ConfigureAwait(false) - : await GetClientSecretCredentialAsync(authContext).ConfigureAwait(false); + ? await GetClientCertificateCredentialAsync(authContext, safeRollOut).ConfigureAwait(false) + : await GetClientSecretCredentialAsync(authContext, safeRollOut).ConfigureAwait(false); case AuthenticationType.ManagedIdentity: return await GetManagedIdentityCredentialAsync(authContext).ConfigureAwait(false); case AuthenticationType.EnvironmentVariable: @@ -86,7 +86,7 @@ private static bool IsWamSupported() return GraphSession.Instance.GraphOption.EnableWAMForMSGraph && SharedUtilities.IsWindowsPlatform(); } - private static async Task GetClientSecretCredentialAsync(IAuthContext authContext) + private static async Task GetClientSecretCredentialAsync(IAuthContext authContext, bool safeRollout) { if (authContext is null) throw new AuthenticationException(ErrorConstants.Message.MissingAuthContext); @@ -96,6 +96,13 @@ private static async Task GetClientSecretCredentialAsync(IAuthC AuthorityHost = new Uri(GetAuthorityUrl(authContext, false)), TokenCachePersistenceOptions = GetTokenCachePersistenceOptions(authContext) }; + if (safeRollout) + { + clientSecretCredentialOptions.ExtraQueryParameters = new Dictionary + { + { "safe_rollout", "apply:0238caeb-f6ca-4efc-afd0-a72e1273a8bc" } + }; + } var clientSecretCredential = new ClientSecretCredential(authContext.TenantId, authContext.ClientId, authContext.ClientSecret.ConvertToString(), clientSecretCredentialOptions); return await Task.FromResult(clientSecretCredential).ConfigureAwait(false); } @@ -190,7 +197,7 @@ private static async Task GetDeviceCodeCredentialAsync(IAu return new DeviceCodeCredential(deviceCodeOptions); } - private static async Task GetClientCertificateCredentialAsync(IAuthContext authContext) + private static async Task GetClientCertificateCredentialAsync(IAuthContext authContext, bool safeRollOut) { if (authContext is null) throw new AuthenticationException(ErrorConstants.Message.MissingAuthContext); @@ -201,6 +208,13 @@ private static async Task GetClientCertificateCrede TokenCachePersistenceOptions = GetTokenCachePersistenceOptions(authContext), SendCertificateChain = authContext.SendCertificateChain }; + if (safeRollOut) + { + clientCredentialOptions.ExtraQueryParameters = new Dictionary + { + { "safe_rollout", "apply:0238caeb-f6ca-4efc-afd0-a72e1273a8bc" } + }; + } var clientCertificateCredential = new ClientCertificateCredential(authContext.TenantId, authContext.ClientId, GetCertificate(authContext), clientCredentialOptions); return await Task.FromResult(clientCertificateCredential).ConfigureAwait(false); } From c8eeffab3ada323b5b15f22e27309fa53038dfa7 Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Mon, 24 Jun 2024 13:14:54 +0300 Subject: [PATCH 22/24] Add sub-claim to auth context --- src/Authentication/Authentication/Models/AuthContext.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Authentication/Authentication/Models/AuthContext.cs b/src/Authentication/Authentication/Models/AuthContext.cs index 6538667da03..cc83e426325 100644 --- a/src/Authentication/Authentication/Models/AuthContext.cs +++ b/src/Authentication/Authentication/Models/AuthContext.cs @@ -28,6 +28,7 @@ public class AuthContext : IAuthContext public string ManagedIdentityId { get; set; } public SecureString ClientSecret { get; set; } public string Environment { get; set; } = GraphEnvironmentConstants.EnvironmentName.Global; + public string SubClaim { get; set; } public AuthContext() { From a5588c55999ed3034d0152018f70565a03ae2b19 Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Mon, 24 Jun 2024 16:09:10 +0300 Subject: [PATCH 23/24] Bump azure sdk submodule --- azure-sdk-for-net | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-sdk-for-net b/azure-sdk-for-net index 6c3fe39a370..bf7d0ff8590 160000 --- a/azure-sdk-for-net +++ b/azure-sdk-for-net @@ -1 +1 @@ -Subproject commit 6c3fe39a370c99c0d3c7dfd9ea624f3d81e0cccd +Subproject commit bf7d0ff85902cbf1b47c411e3a338b19338eec39 From f06f12abeb855cbf7abb767db856423a6de72bb3 Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Mon, 24 Jun 2024 16:28:33 +0300 Subject: [PATCH 24/24] Add safe rollout for environment credential login --- .../Utilities/AuthenticationHelpers.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs index 6e919c686a1..b0a1353ce89 100644 --- a/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs +++ b/src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs @@ -48,7 +48,7 @@ public static async Task GetTokenCredentialAsync(IAuthContext a case AuthenticationType.ManagedIdentity: return await GetManagedIdentityCredentialAsync(authContext).ConfigureAwait(false); case AuthenticationType.EnvironmentVariable: - return await GetEnvironmentCredentialAsync(authContext).ConfigureAwait(false); + return await GetEnvironmentCredentialAsync(authContext, safeRollOut).ConfigureAwait(false); case AuthenticationType.UserProvidedAccessToken: return new UserProvidedTokenCredential(); default: @@ -56,7 +56,7 @@ public static async Task GetTokenCredentialAsync(IAuthContext a } } - private static async Task GetEnvironmentCredentialAsync(IAuthContext authContext) + private static async Task GetEnvironmentCredentialAsync(IAuthContext authContext, bool safeRollout) { if (authContext is null) throw new AuthenticationException(ErrorConstants.Message.MissingAuthContext); @@ -66,6 +66,14 @@ private static async Task GetEnvironmentCredentialAsync(IAuthCo AuthorityHost = new Uri(GetAuthorityUrl(authContext, false)) }; + if (safeRollout) + { + tokenCredentialOptions.ExtraQueryParameters = new Dictionary + { + { "safe_rollout", "apply:0238caeb-f6ca-4efc-afd0-a72e1273a8bc" } + }; + } + if (IsAuthFlowNotSupported()) { throw new Exception(string.Format(CultureInfo.InvariantCulture, ErrorConstants.Message.AuthNotSupported, "Username and password"));