Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use clientinfo endpoint to determine home object id and home tenant i… #177

Merged
merged 6 commits into from
May 27, 2020
11 changes: 9 additions & 2 deletions src/Microsoft.Identity.Web/ClaimConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,16 @@ public static class ClaimConstants
public const string ClientInfo = "client_info";

/// <summary>
/// UniqueObjectIdentifier: "utid".
/// UniqueObjectIdentifier: "uid".
/// Home Object Id.
/// </summary>
public const string UniqueObjectIdentifier = "utid";
public const string UniqueObjectIdentifier = "uid";

/// <summary>
/// UniqueTenantIdentifier: "utid".
/// Home Tenant Id.
/// </summary>
public const string UniqueTenantIdentifier = "utid";

/// <summary>
/// Older scope claim: "http://schemas.microsoft.com/identity/claims/scope".
Expand Down
42 changes: 27 additions & 15 deletions src/Microsoft.Identity.Web/ClaimsPrincipalExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,14 @@ public static class ClaimsPrincipalExtensions
/// <returns>A string corresponding to an account identifier as defined in <see cref="Microsoft.Identity.Client.AccountId.Identifier"/>.</returns>
public static string GetMsalAccountId(this ClaimsPrincipal claimsPrincipal)
{
jennyf19 marked this conversation as resolved.
Show resolved Hide resolved
string userObjectId = claimsPrincipal.GetObjectId();
string nameIdentifierId = claimsPrincipal.GetNameIdentifierId();
string tenantId = claimsPrincipal.GetTenantId();
string userFlowId = claimsPrincipal.GetUserFlowId();

if (!string.IsNullOrWhiteSpace(nameIdentifierId) &&
!string.IsNullOrWhiteSpace(tenantId) &&
!string.IsNullOrWhiteSpace(userFlowId))
{
// B2C pattern: {oid}-{userFlow}.{tid}
return $"{nameIdentifierId}.{tenantId}";
}
else if (!string.IsNullOrWhiteSpace(userObjectId) && !string.IsNullOrWhiteSpace(tenantId))
string uniqueObjectIdentifier = claimsPrincipal.GetHomeObjectId();
string uniqueTenantIdentifier = claimsPrincipal.GetHomeTenantId();

if (!string.IsNullOrWhiteSpace(uniqueObjectIdentifier) && !string.IsNullOrWhiteSpace(uniqueTenantIdentifier))
{
// AAD pattern: {oid}.{tid}
return $"{userObjectId}.{tenantId}";
// AAD pattern: {uid}.{utid}
// B2C pattern: {uid}-{userFlow}.{utid} -> userflow is included in the uid for B2C
return $"{uniqueObjectIdentifier}.{uniqueTenantIdentifier}";
}

return null;
Expand Down Expand Up @@ -146,6 +138,26 @@ public static string GetUserFlowId(this ClaimsPrincipal claimsPrincipal)
return userFlowId;
}

/// <summary>
/// Gets the GetHomeObjectId associated with the <see cref="ClaimsPrincipal"/>.
/// </summary>
/// <param name="claimsPrincipal">the <see cref="ClaimsPrincipal"/> from which to retrieve the sub claim.</param>
/// <returns>Home Object identifier ID (sub) of the identity, or <c>null</c> if it cannot be found.</returns>
jennyf19 marked this conversation as resolved.
Show resolved Hide resolved
public static string GetHomeObjectId(this ClaimsPrincipal claimsPrincipal)
{
jennyf19 marked this conversation as resolved.
Show resolved Hide resolved
return claimsPrincipal.FindFirstValue(ClaimConstants.UniqueObjectIdentifier);
}

/// <summary>
/// Gets the GetHomeTenantId associated with the <see cref="ClaimsPrincipal"/>.
/// </summary>
/// <param name="claimsPrincipal">the <see cref="ClaimsPrincipal"/> from which to retrieve the sub claim.</param>
/// <returns>Home Tenant identifier ID (sub) of the identity, or <c>null</c> if it cannot be found.</returns>
jennyf19 marked this conversation as resolved.
Show resolved Hide resolved
public static string GetHomeTenantId(this ClaimsPrincipal claimsPrincipal)
{
jennyf19 marked this conversation as resolved.
Show resolved Hide resolved
return claimsPrincipal.FindFirstValue(ClaimConstants.UniqueTenantIdentifier);
}

/// <summary>
/// Gets the NameIdentifierId associated with the <see cref="ClaimsPrincipal"/>.
/// </summary>
Expand Down
10 changes: 2 additions & 8 deletions src/Microsoft.Identity.Web/TokenAcquisition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -302,14 +302,8 @@ public async Task RemoveAccountAsync(RedirectContext context)
}
else
{
account = await app.GetAccountAsync(context.HttpContext.User.GetMsalAccountId()).ConfigureAwait(false);

// Workaround for the guest account
if (account == null)
{
var accounts = await app.GetAccountsAsync().ConfigureAwait(false);
account = accounts.FirstOrDefault(a => a.Username == user.GetLoginHint());
}
string identifier = context.HttpContext.User.GetMsalAccountId();
account = await app.GetAccountAsync(identifier).ConfigureAwait(false);

if (account != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
Expand Down Expand Up @@ -130,6 +129,8 @@ public static AuthenticationBuilder AddSignIn(
context.Properties.Parameters.Remove(OpenIdConnectParameterNames.DomainHint);
}

context.ProtocolMessage.SetParameter("client_info", "1");

// Additional claims
if (context.Properties.Items.ContainsKey(OidcConstants.AdditionalClaims))
{
Expand All @@ -140,8 +141,6 @@ public static AuthenticationBuilder AddSignIn(

if (microsoftIdentityOptions.IsB2C)
{
context.ProtocolMessage.SetParameter("client_info", "1");

// When a new Challenge is returned using any B2C user flow different than susi, we must change
// the ProtocolMessage.IssuerAddress to the desired user flow otherwise the redirect would use the susi user flow
await b2cOidcHandlers.OnRedirectToIdentityProvider(context).ConfigureAwait(false);
Expand Down
21 changes: 9 additions & 12 deletions src/Microsoft.Identity.Web/WebAppServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -207,22 +207,19 @@ public static IServiceCollection AddWebAppCallsProtectedWebApi(
var onTokenValidatedHandler = options.Events.OnTokenValidated;
options.Events.OnTokenValidated = async context =>
{
if (!context.Principal.HasClaim(c => c.Type == ClaimConstants.Tid || c.Type == ClaimConstants.TenantId))
ClientInfo clientInfoFromServer;
if (context.Request.Form.ContainsKey(ClaimConstants.ClientInfo))
{
ClientInfo clientInfoFromServer;
if (context.Request.Form.ContainsKey(ClaimConstants.ClientInfo))
context.Request.Form.TryGetValue(ClaimConstants.ClientInfo, out Microsoft.Extensions.Primitives.StringValues value);

if (!string.IsNullOrEmpty(value))
{
context.Request.Form.TryGetValue(ClaimConstants.ClientInfo, out Microsoft.Extensions.Primitives.StringValues value);
clientInfoFromServer = ClientInfo.CreateFromJson(value);

if (!string.IsNullOrEmpty(value))
if (clientInfoFromServer != null)
{
clientInfoFromServer = ClientInfo.CreateFromJson(value);

if (clientInfoFromServer != null)
{
context.Principal.Identities.FirstOrDefault().AddClaim(new Claim(ClaimConstants.Tid, clientInfoFromServer.UniqueTenantIdentifier));
context.Principal.Identities.FirstOrDefault().AddClaim(new Claim(ClaimConstants.UniqueObjectIdentifier, clientInfoFromServer.UniqueObjectIdentifier));
}
context.Principal.Identities.FirstOrDefault().AddClaim(new Claim(ClaimConstants.UniqueTenantIdentifier, clientInfoFromServer.UniqueTenantIdentifier));
context.Principal.Identities.FirstOrDefault().AddClaim(new Claim(ClaimConstants.UniqueObjectIdentifier, clientInfoFromServer.UniqueObjectIdentifier));
}
}
}
Expand Down
14 changes: 10 additions & 4 deletions tests/Microsoft.Identity.Web.Test.Common/TestConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,21 @@ public static class TestConstants
public const string ApiAudience = "api://" + ApiClientId;
public const string ApiClientId = "1EE5A092-0DFD-42B6-88E5-C517C0141321";

public const string UserOne = "User One";
public const string UserTwo = "User Two";

public const string ClientId = "87f0ee88-8251-48b3-8825-e0c9563f5234";
public const string TenantId = "some-tenant-id";
public const string TenantId = "guest-tenant-id";
public const string TenantIdAsGuid = "da41245a5-11b3-996c-00a8-4d99re19f292";
public const string ObjectIdAsGuid = "6364bb70-9521-3fa8-989d-c2c19ff90223";
public const string Domain = "contoso.onmicrosoft.com";
public const string Uid = "my-uid";
public const string Utid = "my-utid";
public const string Uid = "my-home-object-id";
public const string Oid = "my-guest-object-id";
public const string Utid = "my-home-tenant-id";
public const string LoginHint = "login_hint";
public const string DomainHint = "domain_hint";
public const string Claims = "additional_claims";
public const string PreferredUsername = "preferred_username";

public const string AadInstance = "https://login.microsoftonline.com";
public const string AuthorityCommonTenant = AadInstance + "/common/";
Expand Down Expand Up @@ -99,4 +105,4 @@ public static class TestConstants
y1NFZmB24rMoq8C+HPOpuVLzkwBr+qcCq7ry2326auogvVMGaxhHlwSLR4Q1OhRjKs8JctCk2+5Qs1NHfawa7jWHxdAK6cLm7Rv/c0ig2Jow7wRaI5ciAcEjX7
m1t9gRT1mNeeluL4cZa6WyVXqXc6U2wfR5DY6GOMUubN5Nr1n8Czew8TPfab4OG37BuEMNmBpqoRrRgFnDzVtItOnhuFTa0=";
}
}
}
Loading