Skip to content

Commit 80faef7

Browse files
ashok672bgavrilMSgladjohnpmaytak
authored
SsoPolicy support for PCA. (#4659)
* SsoPolicy initial * Remove SSOPolicy project * Update LibsAndSamples.sln * Delete files not needed * Introduce WithSSoPolicy in broker project and rename RuntimeBroker to MsalCppRuntime * Revert "Introduce WithSSoPolicy in broker project and rename RuntimeBroker to MsalCppRuntime" This reverts commit 5e9f794. * Update ApplicationConfiguration.cs * Update InternalsVisibleTo.cs * Hook up the E2E for adding SsoPolicy headers in OAuth2 implementation * Update NuGet.Config * Inject headers in RequestBase * Update src/client/Microsoft.Identity.Client/Platforms/Features/RuntimeBroker/RuntimeBroker.cs Co-authored-by: Gladwin Johnson <[email protected]> * Update src/client/Microsoft.Identity.Client/MsalErrorMessage.cs Co-authored-by: Bogdan Gavril <[email protected]> * Fix for review comments * Fix for review comments * Update src/client/Microsoft.Identity.Client/MsalErrorMessage.cs Co-authored-by: Bogdan Gavril <[email protected]> * Update src/client/Microsoft.Identity.Client/AppConfig/ApplicationConfiguration.cs Co-authored-by: Peter <[email protected]> * Update src/client/Microsoft.Identity.Client/Platforms/Features/WinFormsLegacyWebUi/WindowsFormsWebAuthenticationDialogBase.cs Co-authored-by: Peter <[email protected]> * Update src/client/Microsoft.Identity.Client/Internal/Broker/NullBroker.cs Co-authored-by: Peter <[email protected]> * Fix for review comments * Update RuntimeBroker.cs * Fix mobile build breaks --------- Co-authored-by: Bogdan Gavril <[email protected]> Co-authored-by: Gladwin Johnson <[email protected]> Co-authored-by: Peter <[email protected]>
1 parent e065471 commit 80faef7

File tree

14 files changed

+128
-11
lines changed

14 files changed

+128
-11
lines changed

Directory.Packages.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<PropertyGroup>
33
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
44
<!-- Version of the Microsoft.Identity.Client.NativeInterop package. -->
5-
<MSALRuntimeNativeInteropVersion>0.13.14</MSALRuntimeNativeInteropVersion>
5+
<MSALRuntimeNativeInteropVersion>0.16.0</MSALRuntimeNativeInteropVersion>
66
<!-- Version of MSAL if not defined by the CI-->
77
<MsalInternalVersion>4.51.0</MsalInternalVersion>
88
</PropertyGroup>

src/client/Microsoft.Identity.Client.Broker/BrokerExtension.cs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,20 +47,35 @@ public static PublicClientApplicationBuilder WithBrokerPreview(this PublicClient
4747
/// parameters, and to create a public client application instance</returns>
4848
public static PublicClientApplicationBuilder WithBroker(this PublicClientApplicationBuilder builder, BrokerOptions brokerOptions)
4949
{
50-
AddRuntimeSupportForWam(builder);
50+
AddRuntimeSupport(builder);
5151
builder.Config.BrokerOptions = brokerOptions;
5252
builder.Config.IsBrokerEnabled = brokerOptions.IsBrokerEnabledOnCurrentOs();
5353
return builder;
5454
}
5555

56-
private static void AddRuntimeSupportForWam(PublicClientApplicationBuilder builder)
56+
/// <summary>
57+
/// Use this API to enable SsoPolicy enforcement.
58+
/// Should only be utilized by Microsoft 1st party applications.
59+
/// This is applicable only when broker is not enabled and embedded webview is the preferred choice.
60+
/// By default, the broker supports SsoPolicy, and system webview SsoPolicy is also supported at the OS level.
61+
/// <param name="builder"></param>
62+
/// <returns>A <see cref="PublicClientApplicationBuilder"/> from which to set more
63+
/// parameters, and to create a public client application instance</returns>
64+
public static PublicClientApplicationBuilder WithSsoPolicy(this PublicClientApplicationBuilder builder)
65+
{
66+
AddRuntimeSupport(builder);
67+
builder.Config.IsWebviewSsoPolicyEnabled = true;
68+
return builder;
69+
}
70+
71+
private static void AddRuntimeSupport(PublicClientApplicationBuilder builder)
5772
{
5873
if (DesktopOsHelper.IsWin10OrServerEquivalent())
5974
{
60-
builder.Config.BrokerCreatorFunc =
75+
builder.Config.BrokerCreatorFunc =
6176
(uiParent, appConfig, logger) =>
6277
{
63-
logger.Info("[RuntimeBroker] WAM supported OS.");
78+
logger.Info("[Runtime] WAM supported OS.");
6479
return new RuntimeBroker(uiParent, appConfig, logger);
6580
};
6681
}
@@ -69,7 +84,7 @@ private static void AddRuntimeSupportForWam(PublicClientApplicationBuilder build
6984
builder.Config.BrokerCreatorFunc =
7085
(uiParent, appConfig, logger) =>
7186
{
72-
logger.Info("[RuntimeBroker] Not a Windows 10 or Server equivalent machine. WAM is not available.");
87+
logger.Info("[RuntimeBroker] Not a Windows 10 or Server equivalent machine. Runtime broker or SsoPolicy support is not available.");
7388
return new NullBroker(logger);
7489
};
7590
}

src/client/Microsoft.Identity.Client/AppConfig/ApplicationConfiguration.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ public string ClientVersion
6666

6767
public bool IsBrokerEnabled { get; internal set; }
6868

69+
/// <summary>
70+
/// Applicable to only public client applications to enforce SSO policy with embedded webview.
71+
/// </summary>
72+
public bool IsWebviewSsoPolicyEnabled { get; internal set; }
73+
6974
// Legacy options for UWP. .NET broker options are in BrokerOptions
7075
public WindowsBrokerOptions UwpBrokerOptions { get; set; }
7176

@@ -121,6 +126,9 @@ public string ClientVersion
121126
public ManagedIdentityId ManagedIdentityId { get; internal set; }
122127

123128
public bool IsManagedIdentity { get; }
129+
public bool IsConfidentialClient { get; }
130+
public bool IsPublicClient => !IsConfidentialClient && !IsManagedIdentity;
131+
124132

125133
public Func<AppTokenProviderParameters, Task<AppTokenProviderResult>> AppTokenProvider;
126134

@@ -201,8 +209,7 @@ public X509Certificate2 ClientCredentialCertificate
201209
public ITokenCacheInternal UserTokenCacheInternalForTest { get; set; }
202210
public ITokenCacheInternal AppTokenCacheInternalForTest { get; set; }
203211

204-
public IDeviceAuthManager DeviceAuthManagerForTest { get; set; }
205-
public bool IsConfidentialClient { get; }
212+
public IDeviceAuthManager DeviceAuthManagerForTest { get; set; }
206213
public bool IsInstanceDiscoveryEnabled { get; internal set; } = true;
207214
#endregion
208215

src/client/Microsoft.Identity.Client/Internal/Broker/IBroker.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Task<MsalTokenResponse> AcquireTokenByUsernamePasswordAsync(
3131
AuthenticationRequestParameters authenticationRequestParameters,
3232
AcquireTokenByUsernamePasswordParameters acquireTokenByUsernamePasswordParameters);
3333

34+
IReadOnlyDictionary<string, string> GetSsoPolicyHeaders();
3435
/// <summary>
3536
/// If device auth is required but the broker is not enabled, AAD will
3637
/// signal this by returning an URL pointing to the broker app that needs to be installed.

src/client/Microsoft.Identity.Client/Internal/Broker/NullBroker.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using Microsoft.Identity.Client.Utils;
1313
using System;
1414
using System.Collections.Generic;
15+
using System.Linq;
1516
using System.Threading.Tasks;
1617

1718
namespace Microsoft.Identity.Client.Internal.Broker
@@ -80,5 +81,10 @@ public Task<MsalTokenResponse> AcquireTokenByUsernamePasswordAsync(Authenticatio
8081
_logger.Info("NullBroker - returning null on ROPC request.");
8182
return Task.FromResult<MsalTokenResponse>(null);
8283
}
84+
85+
public IReadOnlyDictionary<string, string> GetSsoPolicyHeaders()
86+
{
87+
return CollectionHelpers.GetEmptyDictionary<string, string>();
88+
}
8389
}
8490
}

src/client/Microsoft.Identity.Client/Internal/Requests/RequestBase.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
using Microsoft.IdentityModel.Abstractions;
2222
using Microsoft.Identity.Client.TelemetryCore.TelemetryClient;
2323
using Microsoft.Identity.Client.TelemetryCore.OpenTelemetry;
24+
using Microsoft.Identity.Client.Internal.Broker;
2425

2526
namespace Microsoft.Identity.Client.Internal.Requests
2627
{
@@ -422,13 +423,32 @@ protected Task<MsalTokenResponse> SendTokenRequestAsync(
422423
tokenClient.AddHeaderToClient(CcsHeader.Value.Key, CcsHeader.Value.Value);
423424
}
424425

426+
InjectPcaSsoPolicyHeader(tokenClient);
427+
425428
return tokenClient.SendTokenRequestAsync(
426429
additionalBodyParameters,
427430
scopes,
428431
tokenEndpoint,
429432
cancellationToken);
430433
}
431434

435+
private void InjectPcaSsoPolicyHeader(TokenClient tokenClient)
436+
{
437+
if (ServiceBundle.Config.IsPublicClient && ServiceBundle.Config.IsWebviewSsoPolicyEnabled)
438+
{
439+
IBroker broker = ServiceBundle.Config.BrokerCreatorFunc(
440+
null,
441+
ServiceBundle.Config,
442+
AuthenticationRequestParameters.RequestContext.Logger);
443+
444+
var ssoPolicyHeaders = broker.GetSsoPolicyHeaders();
445+
foreach (KeyValuePair<string, string> kvp in ssoPolicyHeaders)
446+
{
447+
tokenClient.AddHeaderToClient(kvp.Key, kvp.Value);
448+
}
449+
}
450+
}
451+
432452
//The AAD backup authentication system header is used by the AAD backup authentication system service
433453
//to help route requests to resources in Azure during requests to speed up authentication.
434454
//It consists of either the ObjectId.TenantId or the upn of the account signing in.
@@ -570,6 +590,6 @@ private static RegionDetails CreateRegionDetails(ApiEvent apiEvent)
570590
apiEvent.RegionOutcome,
571591
apiEvent.RegionUsed,
572592
apiEvent.RegionDiscoveryFailureReason);
573-
}
593+
}
574594
}
575595
}

src/client/Microsoft.Identity.Client/OAuth2/OAuth2Client.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
using Microsoft.Identity.Client.Instance.Oidc;
1616
using Microsoft.Identity.Client.Internal;
1717
using Microsoft.Identity.Client.Utils;
18+
using Microsoft.Identity.Client.Internal.Broker;
19+
1820
#if SUPPORTS_SYSTEM_TEXT_JSON
1921
using System.Text.Json;
2022
#else

src/client/Microsoft.Identity.Client/Platforms/Android/Broker/AndroidAccountManagerBroker.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,5 +459,10 @@ public Task<MsalTokenResponse> AcquireTokenByUsernamePasswordAsync(Authenticatio
459459
{
460460
return Task.FromResult<MsalTokenResponse>(null); // nop
461461
}
462+
463+
public IReadOnlyDictionary<string, string> GetSsoPolicyHeaders()
464+
{
465+
return CollectionHelpers.GetEmptyDictionary<string, string>();
466+
}
462467
}
463468
}

src/client/Microsoft.Identity.Client/Platforms/Android/Broker/AndroidContentProviderBroker.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,5 +400,10 @@ public Task<MsalTokenResponse> AcquireTokenByUsernamePasswordAsync(Authenticatio
400400
{
401401
return Task.FromResult<MsalTokenResponse>(null); // nop
402402
}
403+
404+
public IReadOnlyDictionary<string, string> GetSsoPolicyHeaders()
405+
{
406+
return CollectionHelpers.GetEmptyDictionary<string, string>();
407+
}
403408
}
404409
}

src/client/Microsoft.Identity.Client/Platforms/Features/RuntimeBroker/RuntimeBroker.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,32 @@ public async Task<IReadOnlyList<IAccount>> GetAccountsAsync(
552552
}
553553
}
554554
}
555+
public IReadOnlyDictionary<string, string> GetSsoPolicyHeaders()
556+
{
557+
using LogEventWrapper logEventWrapper = new LogEventWrapper(this);
558+
Debug.Assert(s_lazyCore.Value != null, "Should not call this API if MSAL runtime init failed");
559+
560+
NativeInterop.SsoPolicy ssoPolicy = new SsoPolicy();
561+
_logger.Info(() => $"[RuntimeBroker] Broker returned SsoPolicyType {ssoPolicy.SsoPolicyType} and errorCode {ssoPolicy.ErrorCode}.");
562+
563+
var ssoPolicyHeaders = new Dictionary<string, string>();
564+
if (ssoPolicy.SsoPolicyType == SsoPolicyType.PermissionRequired)
565+
{
566+
ssoPolicyHeaders.Add("x-ms-SsoFlags", "SsoRestr");
567+
}
568+
else if (ssoPolicy.SsoPolicyType == SsoPolicyType.Error)
569+
{
570+
ssoPolicyHeaders.Add("x-ms-SsoFlags", "SsoPolicyError");
571+
string subStatusValue = "SsoRestrError:" + ssoPolicy.ErrorCode.ToString();
572+
ssoPolicyHeaders.Add("x-ms-SsoFlagsSubstatus", Base64UrlHelpers.Encode(subStatusValue));
573+
}
574+
else if (ssoPolicy.SsoPolicyType == SsoPolicyType.Unknown)
575+
{
576+
ssoPolicyHeaders.Add("x-ms-SsoFlags", "SsoRestrUndefined");
577+
}
578+
579+
return ssoPolicyHeaders;
580+
}
555581

556582
public void HandleInstallUrl(string appLink)
557583
{

0 commit comments

Comments
 (0)