needDrain = false;
}
- string challengeData = challenge.ChallengeData;
+ if (NetEventSource.IsEnabled)
+ {
+ NetEventSource.Info(connection, $"Authentication: {challenge.AuthenticationType}, Uri: {authUri.AbsoluteUri.ToString()}");
+ }
- // Need to use FQDN normalized host so that CNAME's are traversed.
- // Use DNS to do the forward lookup to an A (host) record.
- // But skip DNS lookup on IP literals. Otherwise, we would end up
- // doing an unintended reverse DNS lookup.
- string spn;
- UriHostNameType hnt = authUri.HostNameType;
- if (hnt == UriHostNameType.IPv6 || hnt == UriHostNameType.IPv4)
+ // Calculate SPN (Service Principal Name) using the host name of the request.
+ // Use the request's 'Host' header if available. Otherwise, use the request uri.
+ string hostName;
+ if (request.HasHeaders && request.Headers.Host != null)
{
- spn = authUri.IdnHost;
+ // Use the host name without any normalization.
+ hostName = request.Headers.Host;
+ if (NetEventSource.IsEnabled)
+ {
+ NetEventSource.Info(connection, $"Authentication: {challenge.AuthenticationType}, Host: {hostName}");
+ }
}
else
{
- IPHostEntry result = await Dns.GetHostEntryAsync(authUri.IdnHost).ConfigureAwait(false);
- spn = result.HostName;
+ // Need to use FQDN normalized host so that CNAME's are traversed.
+ // Use DNS to do the forward lookup to an A (host) record.
+ // But skip DNS lookup on IP literals. Otherwise, we would end up
+ // doing an unintended reverse DNS lookup.
+ UriHostNameType hnt = authUri.HostNameType;
+ if (hnt == UriHostNameType.IPv6 || hnt == UriHostNameType.IPv4)
+ {
+ hostName = authUri.IdnHost;
+ }
+ else
+ {
+ IPHostEntry result = await Dns.GetHostEntryAsync(authUri.IdnHost).ConfigureAwait(false);
+ hostName = result.HostName;
+ }
}
- spn = "HTTP/" + spn;
+ string spn = "HTTP/" + hostName;
if (NetEventSource.IsEnabled)
{
- NetEventSource.Info(connection, $"Authentication: {challenge.AuthenticationType}, Host: {authUri.IdnHost}, SPN: {spn}");
+ NetEventSource.Info(connection, $"Authentication: {challenge.AuthenticationType}, SPN: {spn}");
}
ChannelBinding channelBinding = connection.TransportContext?.GetChannelBinding(ChannelBindingKind.Endpoint);
NTAuthentication authContext = new NTAuthentication(isServer:false, challenge.SchemeName, challenge.Credential, spn, ContextFlagsPal.Connection, channelBinding);
+ string challengeData = challenge.ChallengeData;
try
{
while (true)
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
+using System.Linq;
+using System.Net.Sockets;
using System.Net.Test.Common;
using System.Text;
using System.Threading.Tasks;
private static bool IsNtlmInstalled => Capability.IsNtlmInstalled();
private static bool IsWindowsServerAvailable => !string.IsNullOrEmpty(Configuration.Http.WindowsServerHttpHost);
private static bool IsDomainJoinedServerAvailable => !string.IsNullOrEmpty(Configuration.Http.DomainJoinedHttpHost);
+ private static NetworkCredential DomainCredential = new NetworkCredential(
+ Configuration.Security.ActiveDirectoryUserName,
+ Configuration.Security.ActiveDirectoryUserPassword,
+ Configuration.Security.ActiveDirectoryName);
[ConditionalFact(nameof(IsDomainJoinedServerAvailable))]
public async Task Credentials_DomainJoinedServerUsesKerberos_Success()
using (HttpClientHandler handler = CreateHttpClientHandler())
using (HttpClient client = CreateHttpClient(handler))
{
- handler.Credentials = new NetworkCredential(
- Configuration.Security.ActiveDirectoryUserName,
- Configuration.Security.ActiveDirectoryUserPassword,
- Configuration.Security.ActiveDirectoryName);
+ handler.Credentials = DomainCredential;
- var request = new HttpRequestMessage();
- var server = $"http://{Configuration.Http.DomainJoinedHttpHost}/test/auth/kerberos/showidentity.ashx";
- request.RequestUri = new Uri(server);
+ string server = $"http://{Configuration.Http.DomainJoinedHttpHost}/test/auth/kerberos/showidentity.ashx";
+ using (HttpResponseMessage response = await client.GetAsync(server))
+ {
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ string body = await response.Content.ReadAsStringAsync();
+ _output.WriteLine(body);
+ }
+ }
+ }
- // Force HTTP/1.1 since both CurlHandler and SocketsHttpHandler have problems with
- // HTTP/2.0 and Windows authentication (due to HTTP/2.0 -> HTTP/1.1 downgrade handling).
- // Issue #35195 (for SocketsHttpHandler).
- request.Version = new Version(1,1);
+ [ConditionalFact(nameof(IsDomainJoinedServerAvailable))]
+ public async Task Credentials_DomainJoinedServerUsesKerberos_UseIpAddressAndHostHeader_Success()
+ {
+ if (IsCurlHandler || IsWinHttpHandler)
+ {
+ throw new SkipTestException("Skipping test on platform handlers (CurlHandler, WinHttpHandler)");
+ }
+
+ using (HttpClientHandler handler = CreateHttpClientHandler())
+ using (HttpClient client = CreateHttpClient(handler))
+ {
+ handler.Credentials = DomainCredential;
+
+ IPAddress[] addresses = Dns.GetHostAddresses(Configuration.Http.DomainJoinedHttpHost);
+ IPAddress hostIP = addresses.Where(a => a.AddressFamily == AddressFamily.InterNetwork).Select(a => a).First();
+
+ var request = new HttpRequestMessage();
+ request.RequestUri = new Uri($"http://{hostIP}/test/auth/kerberos/showidentity.ashx");
+ request.Headers.Host = Configuration.Http.DomainJoinedHttpHost;
+ _output.WriteLine(request.RequestUri.AbsoluteUri.ToString());
+ _output.WriteLine($"Host: {request.Headers.Host}");
using (HttpResponseMessage response = await client.SendAsync(request))
{
Configuration.Security.WindowsServerUserName,
Configuration.Security.WindowsServerUserPassword);
- var request = new HttpRequestMessage();
- request.RequestUri = new Uri(server);
-
- // Force HTTP/1.1 since both CurlHandler and SocketsHttpHandler have problems with
- // HTTP/2.0 and Windows authentication (due to HTTP/2.0 -> HTTP/1.1 downgrade handling).
- // Issue #35195 (for SocketsHttpHandler).
- request.Version = new Version(1,1);
-
- using (HttpResponseMessage response = await client.SendAsync(request))
+ using (HttpResponseMessage response = await client.GetAsync(server))
{
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
string body = await response.Content.ReadAsStringAsync();