Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
32 changes: 25 additions & 7 deletions src/client/Microsoft.Identity.Client/Http/HttpManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ public async Task<HttpResponse> SendRequestAsync(
Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> validateServerCert,
CancellationToken cancellationToken,
IRetryPolicy retryPolicy,
int retryCount = 0)
int retryCount = 0,
bool allowAutoRedirect = true)
{
Exception timeoutException = null;
HttpResponse response = null;
Expand All @@ -89,7 +90,8 @@ public async Task<HttpResponse> SendRequestAsync(
method,
bindingCertificate,
validateServerCert, logger,
cancellationToken).ConfigureAwait(false);
cancellationToken,
allowAutoRedirect).ConfigureAwait(false);
}

if (response.StatusCode == HttpStatusCode.OK)
Expand Down Expand Up @@ -128,7 +130,8 @@ public async Task<HttpResponse> SendRequestAsync(
validateServerCert,
cancellationToken,
retryPolicy,
retryCount) // Pass the updated retry count
retryCount, // Pass the updated retry count
allowAutoRedirect)
.ConfigureAwait(false);
}

Expand Down Expand Up @@ -176,13 +179,23 @@ public async Task<HttpResponse> SendRequestAsync(
return response;
}

private HttpClient GetHttpClient(X509Certificate2 x509Certificate2, Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> validateServerCert)
private HttpClient GetHttpClient(
X509Certificate2 x509Certificate2,
Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> validateServerCert,
bool allowAutoRedirect)
{
if (x509Certificate2 != null && validateServerCert != null)
{
throw new NotImplementedException("Mtls certificate cannot be used with service fabric. A custom http client is used for service fabric managed identity to validate the server certificate.");
}

if (x509Certificate2 is null &&
validateServerCert is null &&
_httpClientFactory is IHttpClientFactoryWithRedirectControl redirectControlFactory)
Comment thread
logdog16 marked this conversation as resolved.
Resolved
Comment thread
logdog16 marked this conversation as resolved.
Resolved
{
return redirectControlFactory.GetHttpClient(allowAutoRedirect);
}
Comment thread
logdog16 marked this conversation as resolved.
Resolved

if (validateServerCert != null)
{
// If the factory is an IMsalSFHttpClientFactory, use it to get an HttpClient with the custom handler
Expand Down Expand Up @@ -239,7 +252,8 @@ private async Task<HttpResponse> ExecuteAsync(
X509Certificate2 bindingCertificate,
Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> validateServerCert,
ILoggerAdapter logger,
CancellationToken cancellationToken = default)
CancellationToken cancellationToken,
bool allowAutoRedirect)
{
using (HttpRequestMessage requestMessage = CreateRequestMessage(endpoint, headers))
{
Expand All @@ -252,7 +266,10 @@ private async Task<HttpResponse> ExecuteAsync(

Stopwatch sw = Stopwatch.StartNew();

HttpClient client = GetHttpClient(bindingCertificate, validateServerCert);
HttpClient client = GetHttpClient(
bindingCertificate,
validateServerCert,
allowAutoRedirect);

try
{
Expand Down Expand Up @@ -300,7 +317,8 @@ protected static async Task<HttpContent> CloneHttpContentAsync(HttpContent httpC
{
Headers = response.Headers,
Body = body,
StatusCode = response.StatusCode
StatusCode = response.StatusCode,
RequestUri = response.RequestMessage?.RequestUri
};
}

Expand Down
3 changes: 3 additions & 0 deletions src/client/Microsoft.Identity.Client/Http/HttpResponse.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http.Headers;
Expand Down Expand Up @@ -34,5 +35,7 @@ public IDictionary<string, string> HeadersAsDictionary
public string UserAgent { get; set; }

public string Body { get; set; }

public Uri RequestUri { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Net.Http;

namespace Microsoft.Identity.Client.Http
{
internal interface IHttpClientFactoryWithRedirectControl
{
HttpClient GetHttpClient(bool allowAutoRedirect);
}
}
4 changes: 3 additions & 1 deletion src/client/Microsoft.Identity.Client/Http/IHttpManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ internal interface IHttpManager
/// <param name="cancellationToken"></param>
/// <param name="retryPolicy">Retry policy to be used for the request.</param>
/// <param name="retryCount">Number of retries to be attempted in case of retriable status codes.</param>
/// <param name="allowAutoRedirect">Whether the HTTP client can automatically follow redirects.</param>
/// <returns></returns>
Task<HttpResponse> SendRequestAsync(
Uri endpoint,
Expand All @@ -43,6 +44,7 @@ Task<HttpResponse> SendRequestAsync(
Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> validateServerCertificate,
CancellationToken cancellationToken,
IRetryPolicy retryPolicy,
int retryCount = 0);
int retryCount = 0,
bool allowAutoRedirect = true);
}
}
11 changes: 10 additions & 1 deletion src/client/Microsoft.Identity.Client/MsalErrorMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,16 @@ public static string iOSBrokerKeySaveFailed(string keyChainResult)
public const string RopcDoesNotSupportMsaAccounts = "ROPC does not support MSA accounts. See https://aka.ms/msal-net-ropc for details. ";

public const string WsTrustEndpointNotFoundInMetadataDocument =
"WS-Trust endpoint not found in metadata document. ";
"A secure HTTPS WS-Trust endpoint was not found in the metadata document. ";

public const string WsTrustMetadataEndpointRequiresHttps =
"The WS-Trust metadata endpoint must use HTTPS. ";

public const string WsTrustMetadataEndpointInvalidUri =
"The WS-Trust metadata endpoint must be a well-formed absolute URI. ";

public const string WsTrustNonHttpsRedirectNotSupported =
"A non-HTTPS redirect is not supported for WS-Trust requests. ";

public const string GetUserNameFailed = "Failed to get user name. ";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,24 @@ namespace Microsoft.Identity.Client.PlatformsCommon.Shared
/// .NET should use the IHttpClientFactory, but MSAL cannot take a dependency on it.
/// .NET should use SocketHandler, but UseDefaultCredentials doesn't work with it
/// </remarks>
internal class SimpleHttpClientFactory : IMsalMtlsHttpClientFactory, IMsalSFHttpClientFactory
internal class SimpleHttpClientFactory :
IMsalMtlsHttpClientFactory,
IMsalSFHttpClientFactory,
IHttpClientFactoryWithRedirectControl
{
//Please see (https://aka.ms/msal-httpclient-info) for important information regarding the HttpClient.
private static readonly ConcurrentDictionary<string, HttpClient> s_httpClientPool = new ConcurrentDictionary<string, HttpClient>();
private static readonly object s_cacheLock = new object();

private static HttpClient CreateHttpClient()
private static HttpClient CreateHttpClient(bool allowAutoRedirect)
{
CheckAndManageCache();

var httpClient = new HttpClient(new HttpClientHandler()
{
/* important for IWA */
UseDefaultCredentials = true
UseDefaultCredentials = true,
AllowAutoRedirect = allowAutoRedirect
});
HttpClientConfig.ConfigureRequestHeadersAndSize(httpClient);

Expand Down Expand Up @@ -63,7 +67,20 @@ private static HttpClient CreateMtlsHttpClient(X509Certificate2 bindingCertifica

public HttpClient GetHttpClient()
{
return s_httpClientPool.GetOrAdd("non_mtls", CreateHttpClient());
return GetHttpClient(allowAutoRedirect: true);
}

HttpClient IHttpClientFactoryWithRedirectControl.GetHttpClient(bool allowAutoRedirect)
{
return GetHttpClient(allowAutoRedirect);
}

private static HttpClient GetHttpClient(bool allowAutoRedirect)
{
string key = allowAutoRedirect ? "non_mtls" : "non_mtls_no_redirect";
return s_httpClientPool.GetOrAdd(
key,
_ => CreateHttpClient(allowAutoRedirect));
}

public HttpClient GetHttpClient(X509Certificate2 x509Certificate2)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,11 @@ private void SetPolicyEndpointAddresses(XContainer mexDocument)
XElement endpointAddress = endpointReference.Elements(XmlNamespace.Wsa10 + "Address").FirstOrDefault();
if (endpointAddress != null && Uri.IsWellFormedUriString(endpointAddress.Value, UriKind.Absolute))
{
_bindings[portBindingNameSegments[1]].Url = new Uri(endpointAddress.Value);
var endpointUri = new Uri(endpointAddress.Value);
if (string.Equals(endpointUri.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase))
{
_bindings[portBindingNameSegments[1]].Url = endpointUri;
}
}
}
}
Expand Down
Loading
Loading