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

Add support for AuthenticationSchemes.IntegratedWindowsAuthentication #4353

Merged
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
4 changes: 2 additions & 2 deletions src/System.Private.ServiceModel/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -862,10 +862,10 @@
<value>Cannot resolve the host name of URI "{0}" using DNS.</value>
</data>
<data name="HttpRequiresSingleAuthScheme" xml:space="preserve">
<value>The '{0}' authentication scheme has been specified on the HTTP factory. However, the factory only supports specification of exactly one authentication scheme. Valid authentication schemes are Digest, Negotiate, NTLM, Basic, or Anonymous.</value>
<value>The '{0}' authentication scheme has been specified on the HTTP factory. However, the factory only supports specification of exactly one authentication scheme. Valid authentication schemes are Digest, Negotiate, NTLM, Basic, IntegratedWindowsAuthentication, or Anonymous.</value>
</data>
<data name="HttpAuthSchemeCannotBeNone" xml:space="preserve">
<value>The value specified for the AuthenticationScheme property on the HttpTransportBindingElement ('{0}') is not allowed when building a ChannelFactory. If you used a standard binding, ensure the ClientCredentialType is not set to HttpClientCredentialType.InheritedFromHost, a value which is invalid on a client. If you set the value to '{0}' directly on the HttpTransportBindingElement, please set it to Digest, Negotiate, NTLM, Basic, or Anonymous.</value>
<value>The value specified for the AuthenticationScheme property on the HttpTransportBindingElement ('{0}') is not allowed when building a ChannelFactory. If you used a standard binding, ensure the ClientCredentialType is not set to HttpClientCredentialType.InheritedFromHost, a value which is invalid on a client. If you set the value to '{0}' directly on the HttpTransportBindingElement, please set it to Digest, Negotiate, NTLM, Basic, IntegratedWindowsAuthentication, or Anonymous.</value>
</data>
<data name="HttpAuthorizationFailed" xml:space="preserve">
<value>The HTTP request is unauthorized with client authentication scheme '{0}'. The authentication header received from the server was '{1}'.</value>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ internal HttpChannelFactory(HttpTransportBindingElement bindingElement, BindingC
_httpCookieContainerManager = new HttpCookieContainerManager();
}

if (!bindingElement.AuthenticationScheme.IsSingleton())
if (!bindingElement.AuthenticationScheme.IsSingleton() && bindingElement.AuthenticationScheme != AuthenticationSchemes.IntegratedWindowsAuthentication)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("value", SR.Format(SR.HttpRequiresSingleAuthScheme,
bindingElement.AuthenticationScheme));
Expand Down Expand Up @@ -328,8 +328,20 @@ internal async Task<HttpClient> GetHttpClientAsync(EndpointAddress to, Uri via,
else
{
CredentialCache credentials = new CredentialCache();
credentials.Add(GetCredentialCacheUriPrefix(via),
AuthenticationSchemesHelper.ToString(AuthenticationScheme), credential);
Uri credentialCacheUriPrefix = GetCredentialCacheUriPrefix(via);
if (AuthenticationScheme == AuthenticationSchemes.IntegratedWindowsAuthentication)
{
credentials.Add(credentialCacheUriPrefix, AuthenticationSchemesHelper.ToString(AuthenticationSchemes.Negotiate),
credential);
credentials.Add(credentialCacheUriPrefix, AuthenticationSchemesHelper.ToString(AuthenticationSchemes.Ntlm),
credential);
}
else
{
credentials.Add(credentialCacheUriPrefix, AuthenticationSchemesHelper.ToString(AuthenticationScheme),
credential);
}

clientHandler.Credentials = credentials;
}
}
Expand Down Expand Up @@ -413,7 +425,7 @@ internal ICredentials GetCredentials()
}
break;
case AuthenticationSchemes.Ntlm:
goto case AuthenticationSchemes.Negotiate;
case AuthenticationSchemes.IntegratedWindowsAuthentication:
case AuthenticationSchemes.Negotiate:
if (credentials.Windows.ClientCredential.UserName != string.Empty)
{
Expand Down Expand Up @@ -451,6 +463,7 @@ private SecurityTokenProviderContainer CreateAndOpenTokenProvider(TimeSpan timeo
break;
case AuthenticationSchemes.Negotiate:
case AuthenticationSchemes.Ntlm:
case AuthenticationSchemes.IntegratedWindowsAuthentication:
tokenProvider = TransportSecurityHelpers.GetSspiTokenProvider(SecurityTokenManager, target, via, Scheme, authenticationScheme, channelParameters);
break;
case AuthenticationSchemes.Digest:
Expand Down Expand Up @@ -617,10 +630,11 @@ protected virtual string OnGetConnectionGroupPrefix(SecurityTokenContainer clien

internal static bool IsWindowsAuth(AuthenticationSchemes authScheme)
{
Contract.Assert(authScheme.IsSingleton(), "authenticationScheme used in an Http(s)ChannelFactory must be a singleton value.");
Fx.Assert(authScheme.IsSingleton() || authScheme == AuthenticationSchemes.IntegratedWindowsAuthentication, "authenticationScheme used in an Http(s)ChannelFactory must be a singleton value.");

return authScheme == AuthenticationSchemes.Negotiate ||
authScheme == AuthenticationSchemes.Ntlm;
authScheme == AuthenticationSchemes.Ntlm ||
authScheme == AuthenticationSchemes.IntegratedWindowsAuthentication;
}

private string GetConnectionGroupName(NetworkCredential credential, AuthenticationLevel authenticationLevel,
Expand Down Expand Up @@ -1336,7 +1350,7 @@ public WebProxyFactory(Uri address, bool bypassOnLocal, AuthenticationSchemes au
_address = address;
_bypassOnLocal = bypassOnLocal;

if (!authenticationScheme.IsSingleton())
if (!authenticationScheme.IsSingleton() && authenticationScheme != AuthenticationSchemes.IntegratedWindowsAuthentication)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(nameof(authenticationScheme), SR.Format(SR.HttpRequiresSingleAuthScheme,
authenticationScheme));
Expand Down Expand Up @@ -1376,8 +1390,18 @@ public async Task<IWebProxy> CreateWebProxyAsync(AuthenticationLevel requestAuth
}

CredentialCache credentials = new CredentialCache();
credentials.Add(_address, AuthenticationSchemesHelper.ToString(AuthenticationScheme),
credential);
if (AuthenticationScheme == AuthenticationSchemes.IntegratedWindowsAuthentication)
{
credentials.Add(_address, AuthenticationSchemesHelper.ToString(AuthenticationSchemes.Negotiate),
credential);
credentials.Add(_address, AuthenticationSchemesHelper.ToString(AuthenticationSchemes.Ntlm),
credential);
}
else
{
credentials.Add(_address, AuthenticationSchemesHelper.ToString(AuthenticationScheme),
credential);
}
result.Credentials = credentials;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ private static async Task<NetworkCredential> GetCredentialCoreAsync(Authenticati
break;

case AuthenticationSchemes.Ntlm:
case AuthenticationSchemes.IntegratedWindowsAuthentication: // IWA could use NTLM
result = await TransportSecurityHelpers.GetSspiCredentialAsync(credentialProvider,
impersonationLevelWrapper, authenticationLevelWrapper, timeout);
if (authenticationLevelWrapper.Value == AuthenticationLevel.MutualAuthRequired)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingC
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("value", SR.Format(SR.HttpAuthSchemeCannotBeNone,
AuthenticationScheme));
}
else if (!AuthenticationScheme.IsSingleton())
else if (!AuthenticationScheme.IsSingleton() && AuthenticationScheme != AuthenticationSchemes.IntegratedWindowsAuthentication)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("value", SR.Format(SR.HttpRequiresSingleAuthScheme,
AuthenticationScheme));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ internal static HttpClientCredentialType MapToClientCredentialType(Authenticatio
result = HttpClientCredentialType.Ntlm;
break;
case AuthenticationSchemes.Negotiate:
case AuthenticationSchemes.IntegratedWindowsAuthentication:
result = HttpClientCredentialType.Windows;
break;
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ private bool IsDigestAuthenticationScheme(SecurityTokenRequirement requirement)
{
AuthenticationSchemes authScheme = (AuthenticationSchemes)requirement.Properties[ServiceModelSecurityTokenRequirement.HttpAuthenticationSchemeProperty];

if (!authScheme.IsSingleton())
if (!authScheme.IsSingleton() && authScheme != AuthenticationSchemes.IntegratedWindowsAuthentication)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("authScheme", string.Format(SR.HttpRequiresSingleAuthScheme, authScheme));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,15 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

//

using System;
using System.Collections.Generic;
using System.Net;
using System.ServiceModel;
using System.ServiceModel.Channels;
using Infrastructure.Common;

using Xunit;

public static class Http_ClientCredentialTypeTests
public class Http_ClientCredentialTypeTests : ConditionalWcfTest
{
[WcfFact]
[OuterLoop]
Expand Down Expand Up @@ -139,4 +136,29 @@ public static void HttpExpect100Continue_DigestAuthentication_True()
ScenarioTestHelpers.CloseCommunicationObjects((ICommunicationObject)serviceProxy, factory);
}
}

[WcfFact]
[Condition(nameof(Windows_Authentication_Available), nameof(Is_Windows))]
[OuterLoop]
public static void WindowsAuthentication_RoundTrips_Echo()
{
BasicHttpBinding basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly);
basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;

ScenarioTestHelpers.RunBasicEchoTest(basicHttpBinding, Endpoints.Http_WindowsAuth_Address, "BasicHttpBinding with Windows authentication", null);
}

[WcfFact]
[Condition(nameof(Windows_Authentication_Available), nameof(Is_Windows))]
[OuterLoop]
public static void IntegratedWindowsAuthentication_Negotiate_RoundTrips_Echo()
{
BasicHttpBinding basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly);
basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
var binding = new CustomBinding(basicHttpBinding);
var htbe = binding.Elements.Find<HttpTransportBindingElement>();
htbe.AuthenticationScheme = System.Net.AuthenticationSchemes.IntegratedWindowsAuthentication;

ScenarioTestHelpers.RunBasicEchoTest(binding, Endpoints.Http_WindowsAuth_Address, "BasicHttpBinding with IntegratedWindowsAuthentication authentication and Negotiate endpoint", null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -238,13 +238,16 @@ public static void NtlmAuthentication_RoundTrips_Echo()
}

[WcfFact]
[Condition(nameof(Windows_Authentication_Available), nameof(Is_Windows))]
[Condition(nameof(NTLM_Available), nameof(Root_Certificate_Installed))]
[OuterLoop]
public static void WindowsAuthentication_RoundTrips_Echo()
public static void IntegratedWindowsAuthentication_Ntlm_RoundTrips_Echo()
{
BasicHttpBinding basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly);
BasicHttpBinding basicHttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
basicHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
var binding = new CustomBinding(basicHttpBinding);
var htbe = binding.Elements.Find<HttpsTransportBindingElement>();
htbe.AuthenticationScheme = System.Net.AuthenticationSchemes.IntegratedWindowsAuthentication;

ScenarioTestHelpers.RunBasicEchoTest(basicHttpBinding, Endpoints.Http_WindowsAuth_Address, "BasicHttpBinding with Windows authentication", null);
ScenarioTestHelpers.RunBasicEchoTest(binding, Endpoints.Https_NtlmAuth_Address, "BasicHttpBinding with IntegratedWindowsAuthentication authentication and Ntlm endpoint", null);
}
}