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

Adding SNI support to ClientCertificateCredential #14636

Merged
merged 2 commits into from
Aug 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions sdk/identity/Azure.Identity/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# Release History
## 1.3.0-preview.1 (Unreleased)

### New Features
- Restoring Application Authentication APIs from 1.2.0-preview.6
- Added `IncludeX5CClaimHeader` to `ClientCertificateCredentialOptions` to enable subject name / issuer authentication with the `ClientCertificateCredential`.

### Fixes and improvements
- Fixed issue with non GUID Client Ids (Issue [#14585](https://github.com/Azure/azure-sdk-for-net/issues/14585))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public partial class ClientCertificateCredentialOptions : Azure.Identity.TokenCr
public ClientCertificateCredentialOptions() { }
public bool AllowUnencryptedCache { get { throw null; } set { } }
public bool EnablePersistentCache { get { throw null; } set { } }
public bool IncludeX5CCliamHeader { get { throw null; } set { } }
}
public partial class ClientSecretCredential : Azure.Core.TokenCredential
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ internal ClientCertificateCredential(string tenantId, string clientId, IX509Cert

_pipeline = pipeline ?? CredentialPipeline.GetInstance(options);

_client = client ?? new MsalConfidentialClient(_pipeline, tenantId, clientId, certificateProvider, options as ITokenCacheOptions);
_client = client ?? new MsalConfidentialClient(_pipeline, tenantId, clientId, certificateProvider, (options as ClientCertificateCredentialOptions)?.IncludeX5CCliamHeader ?? false, options as ITokenCacheOptions);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,10 @@ public class ClientCertificateCredentialOptions : TokenCredentialOptions, IToken
/// If set to true the credential will fall back to storing tokens in an unencrypted file if no OS level user encryption is available.
/// </summary>
public bool AllowUnencryptedCache { get; set; }

/// <summary>
/// Will include x5c header to enable subject name / issuer based authentication for the <see cref="ClientCertificateCredential"/>.
/// </summary>
public bool IncludeX5CCliamHeader { get; set; }
}
}
7 changes: 5 additions & 2 deletions sdk/identity/Azure.Identity/src/MsalConfidentialClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ namespace Azure.Identity
internal class MsalConfidentialClient : MsalClientBase<IConfidentialClientApplication>
{
private readonly string _clientSecret;
private readonly bool _includeX5CClaimHeader;
private readonly ClientCertificateCredential.IX509Certificate2Provider _certificateProvider;

/// <summary>
Expand All @@ -29,9 +30,10 @@ public MsalConfidentialClient(CredentialPipeline pipeline, string tenantId, stri
_clientSecret = clientSecret;
}

public MsalConfidentialClient(CredentialPipeline pipeline, string tenantId, string clientId, ClientCertificateCredential.IX509Certificate2Provider certificateProvider, ITokenCacheOptions cacheOptions)
public MsalConfidentialClient(CredentialPipeline pipeline, string tenantId, string clientId, ClientCertificateCredential.IX509Certificate2Provider certificateProvider, bool includeX5CClaimHeader, ITokenCacheOptions cacheOptions)
: base(pipeline, tenantId, clientId, cacheOptions)
{
_includeX5CClaimHeader = includeX5CClaimHeader;
_certificateProvider = certificateProvider;
}

Expand All @@ -56,7 +58,8 @@ protected override async ValueTask<IConfidentialClientApplication> CreateClientA
public virtual async ValueTask<AuthenticationResult> AcquireTokenForClientAsync(string[] scopes, bool async, CancellationToken cancellationToken)
{
IConfidentialClientApplication client = await GetClientAsync(async, cancellationToken).ConfigureAwait(false);
return await client.AcquireTokenForClient(scopes).ExecuteAsync(async, cancellationToken).ConfigureAwait(false);

return await client.AcquireTokenForClient(scopes).WithSendX5C(_includeX5CClaimHeader).ExecuteAsync(async, cancellationToken).ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,25 @@ public async Task FromX509Certificate2()
}
}

[Test]
public async Task IncludeX5CCliamHeader()
{
var tenantId = TestEnvironment.ServicePrincipalTenantId;
var clientId = TestEnvironment.ServicePrincipalClientId;
var certPath = TestEnvironment.ServicePrincipalSniCertificatePath;

var options = Recording.InstrumentClientOptions(new ClientCertificateCredentialOptions { IncludeX5CCliamHeader = true });

var credential = new ClientCertificateCredential(tenantId, clientId, certPath, options);

var tokenRequestContext = new TokenRequestContext(new[] { AzureAuthorityHosts.GetDefaultScope(AzureAuthorityHosts.AzurePublicCloud) });

// ensure we can initially acquire a token
AccessToken token = await credential.GetTokenAsync(tokenRequestContext);

Assert.IsNotNull(token.Token);
}

[Test]
public void IncorrectCertificate()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ public IdentityTestEnvironment() : base("identity")
public string ServicePrincipalClientSecret => GetOptionalVariable("IDENTITY_SP_CLIENT_SECRET") ?? "SANITIZED";
public string ServicePrincipalCertificatePfxPath => GetOptionalVariable("IDENTITY_SP_CERT_PFX") ?? Path.Combine(TestContext.CurrentContext.TestDirectory, "Data", "cert.pfx");
public string ServicePrincipalCertificatePemPath => GetOptionalVariable("IDENTITY_SP_CERT_PEM") ?? Path.Combine(TestContext.CurrentContext.TestDirectory, "Data", "cert.pem");

public string ServicePrincipalSniCertificatePath => GetOptionalVariable("IDENTITY_SP_SNI_CERT") ?? Path.Combine(TestContext.CurrentContext.TestDirectory, "Data", "cert.pfx");
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading