Skip to content

Commit

Permalink
Adding authentication extension api to enable the extending of MSAL (#…
Browse files Browse the repository at this point in the history
…4859)

* Initial commit

* Updating Core logic for CDT

* Updates

* Refactoring CdtAuthScheme
Adding unit tests

* Adding cache test case

* Resolving issues

* Update

* Adding api to enable additional caching parameters

* clean up

* Clean up, Refactoring, Updating tests

* Fixing test issue

* Resolving build issue

* Test fix

* Refactoring CDT logic to make it extensible

* hooking up addin

* Adding support for arrays and objects

* Hooking up Additional cache param logic

* Clean up
fix test

* Adding integration test

* Fixing tests

* Ignoring test

* Resolving build error

* Making constraints an array

* Updating CDT format

* Moving CDT implementation to new project.

* clean up

* Moving cdt implementation to new project. Removing MSAL internal dependencies

* Setting tokenType to internal

* Resolving build issues

* Refactoring CdtAuthScheme to use wilson

* Resolving build errors

* Revert "Resolving build errors"

This reverts commit 68a8922.

* Fixing error

* Revert "Fixing error"

This reverts commit 75e9955.

* Revert "Revert "Resolving build errors""

This reverts commit 3fba7ba.

* Revert "Resolving build errors"

This reverts commit 68a8922.

* Renaming authentication extension apis

* Removing CDT

* Ignoring failing test

* Revert "Removing CDT"

This reverts commit 54fb683.

* Updating naming

* Revert "Revert "Removing CDT""

This reverts commit fba6bd9.

* Update Microsoft.Identity.Client.csproj

* Revert "Revert "Revert "Removing CDT"""

This reverts commit 2a96823.

* Revert "Revert "Revert "Revert "Removing CDT""""

This reverts commit ab14305.

* Refactoring.
Clean up.
Removing CDT

* Additional test cases

* Clean up

* Refactoring
clean up

* Enabling CdtTelemetry

* Renaming

* TestFix

* Apply suggestions from code review

Co-authored-by: Ray Luo <[email protected]>
Co-authored-by: Gladwin Johnson <[email protected]>

* Adding test

* Fixing test issue

---------

Co-authored-by: trwalke <[email protected]>
Co-authored-by: Ray Luo <[email protected]>
Co-authored-by: Gladwin Johnson <[email protected]>
  • Loading branch information
4 people authored Oct 18, 2024
1 parent 9c40835 commit 97c51de
Show file tree
Hide file tree
Showing 40 changed files with 536 additions and 128 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -334,9 +334,10 @@ public T WithB2CAuthority(string authorityUri)
return this as T;
}

internal /* for testing */ T WithAuthenticationScheme(IAuthenticationScheme scheme)
internal /* for testing */ T WithAuthenticationOperation(IAuthenticationOperation authOperation)
{
CommonParameters.AuthenticationScheme = scheme ?? throw new ArgumentNullException(nameof(scheme));
ValidateUseOfExperimentalFeature();
CommonParameters.AuthenticationOperation = authOperation ?? throw new ArgumentNullException(nameof(authOperation));
return this as T;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Identity.Client.ApiConfig;
using Microsoft.Identity.Client.ApiConfig.Executors;
using Microsoft.Identity.Client.AppConfig;
using Microsoft.Identity.Client.AuthScheme.PoP;
Expand Down Expand Up @@ -82,7 +85,7 @@ public T WithProofOfPossession(PoPAuthenticationConfiguration popAuthenticationC

CommonParameters.PopAuthenticationConfiguration = popAuthenticationConfiguration ?? throw new ArgumentNullException(nameof(popAuthenticationConfiguration));

CommonParameters.AuthenticationScheme = new PopAuthenticationScheme(CommonParameters.PopAuthenticationConfiguration, ServiceBundle);
CommonParameters.AuthenticationOperation = new PopAuthenticationOperation(CommonParameters.PopAuthenticationConfiguration, ServiceBundle);

return this as T;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public AcquireTokenByUsernamePasswordParameterBuilder WithProofOfPossession(stri
popConfig.HttpMethod = httpMethod;

CommonParameters.PopAuthenticationConfiguration = popConfig;
CommonParameters.AuthenticationScheme = new PopBrokerAuthenticationScheme();
CommonParameters.AuthenticationOperation = new PopBrokerAuthenticationOperation();

return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ public AcquireTokenInteractiveParameterBuilder WithProofOfPossession(string nonc
popConfig.HttpMethod = httpMethod;

CommonParameters.PopAuthenticationConfiguration = popConfig;
CommonParameters.AuthenticationScheme = new PopBrokerAuthenticationScheme();
CommonParameters.AuthenticationOperation = new PopBrokerAuthenticationOperation();

return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ public AcquireTokenSilentParameterBuilder WithProofOfPossession(PoPAuthenticatio

CommonParameters.PopAuthenticationConfiguration = popAuthenticationConfiguration ?? throw new ArgumentNullException(nameof(popAuthenticationConfiguration));

CommonParameters.AuthenticationScheme = new PopAuthenticationScheme(CommonParameters.PopAuthenticationConfiguration, ServiceBundle);
CommonParameters.AuthenticationOperation = new PopAuthenticationOperation(CommonParameters.PopAuthenticationConfiguration, ServiceBundle);

return this;
}
Expand Down Expand Up @@ -232,20 +232,20 @@ public AcquireTokenSilentParameterBuilder WithProofOfPossession(string nonce, Ht
popConfig.HttpMethod = httpMethod ?? throw new ArgumentNullException(nameof(httpMethod));
popConfig.Nonce = nonce;

IAuthenticationScheme authenticationScheme;
IAuthenticationOperation authenticationScheme;

//POP Auth scheme should not wrap and sign token when broker is enabled for public clients
if (ServiceBundle.Config.IsBrokerEnabled)
{
popConfig.SignHttpRequest = false;
authenticationScheme = new PopBrokerAuthenticationScheme();
authenticationScheme = new PopBrokerAuthenticationOperation();
}
else
{
authenticationScheme = new PopAuthenticationScheme(popConfig, ServiceBundle);
authenticationScheme = new PopAuthenticationOperation(popConfig, ServiceBundle);
}
CommonParameters.PopAuthenticationConfiguration = popConfig;
CommonParameters.AuthenticationScheme = authenticationScheme;
CommonParameters.AuthenticationOperation = authenticationScheme;

return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ internal class AcquireTokenCommonParameters
public IDictionary<string, string> ExtraQueryParameters { get; set; }
public string Claims { get; set; }
public AuthorityInfo AuthorityOverride { get; set; }
public IAuthenticationScheme AuthenticationScheme { get; set; } = new BearerAuthenticationScheme();
public IAuthenticationOperation AuthenticationOperation { get; set; } = new BearerAuthenticationOperation();
public IDictionary<string, string> ExtraHttpHeaders { get; set; }
public PoPAuthenticationConfiguration PopAuthenticationConfiguration { get; set; }
public Func<OnBeforeTokenRequestData, Task> OnBeforeTokenRequestHandler { get; internal set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ public static bool StoreTokenTypeInCacheKey(string tokenType)
{
if (string.Equals(
tokenType,
BearerAuthenticationScheme.BearerTokenType,
BearerAuthenticationOperation.BearerTokenType,
StringComparison.OrdinalIgnoreCase))
{
return false;
}

if (string.Equals(
tokenType,
SSHCertAuthenticationScheme.SSHCertTokenType,
SSHCertAuthenticationOperation.SSHCertTokenType,
StringComparison.OrdinalIgnoreCase))
{
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@

namespace Microsoft.Identity.Client.AuthScheme.Bearer
{
internal class BearerAuthenticationScheme : IAuthenticationScheme
internal class BearerAuthenticationOperation : IAuthenticationOperation
{
internal const string BearerTokenType = "bearer";

public TokenType TelemetryTokenType => TokenType.Bearer;
public int TelemetryTokenType => (int)TokenType.Bearer;

public string AuthorizationHeaderPrefix => "Bearer";

public string AccessTokenType => BearerTokenType;

public string KeyId => null;

public string FormatAccessToken(MsalAccessTokenCacheItem msalAccessTokenCacheItem)
public void FormatResult(AuthenticationResult authenticationResult)
{
return msalAccessTokenCacheItem.Secret;
// no-op
}

public IReadOnlyDictionary<string, string> GetTokenRequestParams()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,28 @@ namespace Microsoft.Identity.Client.AuthScheme
/// <summary>
/// Used to modify the experience depending on the type of token asked.
/// </summary>
internal interface IAuthenticationScheme
public interface IAuthenticationOperation
{
/// <summary>
/// Value to log to telemetry to indicate pop usage.
/// Value to log to telemetry
/// Values available:
///
/// Bearer token type.
/// Bearer = 1
///
/// Pop token type.
/// Pop = 2,
///
/// Ssh-cert token type.
/// SshCert = 3,
///
/// External token type.
/// External = 4,
///
/// Extension token type.
/// Extension = 5
/// </summary>
TokenType TelemetryTokenType { get; }
int TelemetryTokenType { get; }

/// <summary>
/// Prefix for the HTTP header that has the token. E.g. "Bearer" or "POP"
Expand All @@ -37,7 +53,7 @@ internal interface IAuthenticationScheme
/// <summary>
/// Creates the access token that goes into an Authorization HTTP header.
/// </summary>
string FormatAccessToken(MsalAccessTokenCacheItem msalAccessTokenCacheItem);
void FormatResult(AuthenticationResult authenticationResult);

/// <summary>
/// Expected to match the token_type parameter returned by ESTS. Used to disambiguate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@

using System;
using System.Security.Cryptography;
using Microsoft.Identity.Client.AuthScheme.PoP;
using Microsoft.Identity.Client.Utils;

namespace Microsoft.Identity.Client.AuthScheme.PoP
{

/// <summary>
/// The default implementation will store a key in memory
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ namespace Microsoft.Identity.Client.AuthScheme.PoP
/// <summary>
/// This factory ensures key rotation every 8h
/// </summary>
internal static class PoPProviderFactory
internal static class PoPCryptoProviderFactory
{
private static InMemoryCryptoProvider s_currentProvider;
private static DateTime s_providerExpiration;

public /* public for test only */ static TimeSpan KeyRotationInterval { get; }
public /* public for test only */ static TimeSpan KeyRotationInterval { get; }
= TimeSpan.FromHours(8);

private static object s_lock = new object();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

namespace Microsoft.Identity.Client.AuthScheme.PoP
{
internal class PopAuthenticationScheme : IAuthenticationScheme
internal class PopAuthenticationOperation : IAuthenticationOperation
{
private readonly PoPAuthenticationConfiguration _popAuthenticationConfiguration;
private readonly IPoPCryptoProvider _popCryptoProvider;
Expand All @@ -33,7 +33,7 @@ internal class PopAuthenticationScheme : IAuthenticationScheme
/// Currently the signing credential algorithm is hard-coded to RSA with SHA256. Extensibility should be done
/// by integrating Wilson's SigningCredentials
/// </remarks>
public PopAuthenticationScheme(PoPAuthenticationConfiguration popAuthenticationConfiguration, IServiceBundle serviceBundle)
public PopAuthenticationOperation(PoPAuthenticationConfiguration popAuthenticationConfiguration, IServiceBundle serviceBundle)
{
if (serviceBundle == null)
{
Expand All @@ -48,7 +48,7 @@ public PopAuthenticationScheme(PoPAuthenticationConfiguration popAuthenticationC
KeyId = Base64UrlHelpers.Encode(keyThumbprint);
}

public TokenType TelemetryTokenType => TokenType.Pop;
public int TelemetryTokenType => (int)TokenType.Pop;

public string AuthorizationHeaderPrefix => Constants.PoPAuthHeaderPrefix;

Expand All @@ -67,25 +67,26 @@ public IReadOnlyDictionary<string, string> GetTokenRequestParams()
};
}

public string FormatAccessToken(MsalAccessTokenCacheItem msalAccessTokenCacheItem)
public void FormatResult(AuthenticationResult authenticationResult)
{
if (!_popAuthenticationConfiguration.SignHttpRequest)
{
return msalAccessTokenCacheItem.Secret;
// token will be signed by the caller
return;
}

var header = new JObject();
header[JsonWebTokenConstants.Algorithm] = _popCryptoProvider.CryptographicAlgorithm;
header[JsonWebTokenConstants.KeyId] = KeyId;
header[JsonWebTokenConstants.Type] = Constants.PoPTokenType;

var body = CreateBody(msalAccessTokenCacheItem);
var body = CreateBody(authenticationResult.AccessToken);

string popToken = CreateJWS(JsonHelper.JsonObjectToString(body), JsonHelper.JsonObjectToString(header));
return popToken;
authenticationResult.AccessToken = popToken;
}

private JObject CreateBody(MsalAccessTokenCacheItem msalAccessTokenCacheItem)
private JObject CreateBody(string accessToken)
{
var publicKeyJwk = JToken.Parse(_popCryptoProvider.CannonicalPublicKeyJwk);
var body = new JObject
Expand All @@ -96,7 +97,7 @@ private JObject CreateBody(MsalAccessTokenCacheItem msalAccessTokenCacheItem)
[PoPClaimTypes.JWK] = publicKeyJwk
},
[PoPClaimTypes.Ts] = DateTimeHelpers.CurrDateTimeInUnixTimestamp(),
[PoPClaimTypes.At] = msalAccessTokenCacheItem.Secret,
[PoPClaimTypes.At] = accessToken,
[PoPClaimTypes.Nonce] = _popAuthenticationConfiguration.Nonce ?? CreateSimpleNonce(),
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,19 @@ namespace Microsoft.Identity.Client.AuthScheme.PoP
//Authentication Scheme used when MSAL Broker and pop are used together.
//Tokens acquired from brokers will not be saved in the local ache and MSAL will not search the local cache during silent authentication.
//This is because tokens are cached in the broker instead so MSAL will rely on the broker's cache for silent requests.
internal class PopBrokerAuthenticationScheme : IAuthenticationScheme
internal class PopBrokerAuthenticationOperation : IAuthenticationOperation
{
public TokenType TelemetryTokenType => TokenType.Pop;
public int TelemetryTokenType => (int)TokenType.Pop;

public string AuthorizationHeaderPrefix => Constants.PoPAuthHeaderPrefix;

public string KeyId => string.Empty;

public string AccessTokenType => Constants.PoPTokenType;

public string FormatAccessToken(MsalAccessTokenCacheItem msalAccessTokenCacheItem)
public void FormatResult(AuthenticationResult authenticationResult)
{
//no op
return msalAccessTokenCacheItem.Secret;
//no-op
}

public IReadOnlyDictionary<string, string> GetTokenRequestParams()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@

namespace Microsoft.Identity.Client.AuthScheme.SSHCertificates
{
internal class SSHCertAuthenticationScheme : IAuthenticationScheme
internal class SSHCertAuthenticationOperation : IAuthenticationOperation
{
internal const string SSHCertTokenType = "ssh-cert";
private readonly string _jwk;

public SSHCertAuthenticationScheme(string keyId, string jwk)
public SSHCertAuthenticationOperation(string keyId, string jwk)
{
if (string.IsNullOrEmpty(keyId))
{
Expand All @@ -29,7 +29,7 @@ public SSHCertAuthenticationScheme(string keyId, string jwk)
_jwk = jwk;
}

public TokenType TelemetryTokenType => TokenType.SshCert;
public int TelemetryTokenType => (int)TokenType.SshCert;

public string AuthorizationHeaderPrefix =>
throw new MsalClientException(
Expand All @@ -39,9 +39,9 @@ public SSHCertAuthenticationScheme(string keyId, string jwk)

public string KeyId { get; }

public string FormatAccessToken(MsalAccessTokenCacheItem msalAccessTokenCacheItem)
public void FormatResult(AuthenticationResult authenticationResult)
{
return msalAccessTokenCacheItem.Secret;
// no-op
}

public IReadOnlyDictionary<string, string> GetTokenRequestParams()
Expand Down
8 changes: 7 additions & 1 deletion src/client/Microsoft.Identity.Client/AuthScheme/TokenType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ internal enum TokenType
/// <summary>
/// External token type.
/// </summary>
External = 4
External = 4,

/// <summary>
/// Extension token type.
/// Extension = 5
/// </summary>
Extension = 5
}
}
Loading

0 comments on commit 97c51de

Please sign in to comment.