Tomtom
Tomtom

Reputation: 9394

Authentication in CoreWCF-Server

I'm currently migrating a .net framework 4.8 Application which hosts several REST-APIs and WCF-Interfaces to ASP.NET Core (.NET 8). To migrate the WCF-Interfaces I'm using CoreWCF.

I can't change the client-code, because there are many dependencies on the client-code.

An example of a working client-code to make a REST-Request to the migrated server looks like:

 using (HttpClientHandler handler = new HttpClientHandler())
 {
     handler.UseDefaultCredentials = true;
     using (HttpClient client = new HttpClient(handler))
     {
         var response = client.GetAsync($"https://localhost:44375/api/interfaces").Result;      
     }
 }

The server is hosted in IIS-Express for development and should be running on an IIS-Server when deployed. But that's not the problem now.

The client-code to initialize the WCF-connection is:

 private static void EnsureWCFServiceBindings()
  {
      if (transportBinding == null)
      {
          XmlDictionaryReaderQuotas readerQuotas = new XmlDictionaryReaderQuotas();
          readerQuotas.MaxDepth = 2147483647;
          readerQuotas.MaxStringContentLength = 2147483647;
          readerQuotas.MaxArrayLength = 2147483647;
          readerQuotas.MaxBytesPerRead = 2147483647;
          readerQuotas.MaxNameTableCharCount = 2147483647;

          HttpTransportSecurity httpTransportSecurity = new HttpTransportSecurity();
          httpTransportSecurity.ClientCredentialType = HttpClientCredentialType.Ntlm;
          httpTransportSecurity.ProxyCredentialType = HttpProxyCredentialType.Ntlm;
          httpTransportSecurity.Realm = "mydomain.com";

          BasicHttpMessageSecurity basicHttpMessageSecurity = new BasicHttpMessageSecurity();
          basicHttpMessageSecurity.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
          basicHttpMessageSecurity.AlgorithmSuite = SecurityAlgorithmSuite.Default;


          BasicHttpsSecurity basicHttpsSecurity = new BasicHttpsSecurity
          {
              Mode = BasicHttpsSecurityMode.Transport, 
              Transport = httpTransportSecurity, 
              Message = basicHttpMessageSecurity
          };

          BasicHttpsBinding basicHttpsBinding = new BasicHttpsBinding
          {
              CloseTimeout = TimeSpan.FromMinutes(5), 
              OpenTimeout = TimeSpan.FromMinutes(5), 
              ReceiveTimeout = TimeSpan.FromMinutes(10),
              SendTimeout = TimeSpan.FromMinutes(5),
              AllowCookies = false, 
              BypassProxyOnLocal = false,
              HostNameComparisonMode = HostNameComparisonMode.StrongWildcard,
              MaxBufferSize = 2147483647, 
              MaxBufferPoolSize = 0,
              MaxReceivedMessageSize = 2147483647,
              MessageEncoding = WSMessageEncoding.Text, 
              TextEncoding = Encoding.UTF8, 
              TransferMode = TransferMode.Buffered, 
              ReaderQuotas = readerQuotas,
              Security = basicHttpsSecurity
          };
          transportBinding = basicHttpsBinding;
      }

      if (clientBuildClient == null)
      {          
          clientBuildClient = new EndpointAddress(string.Format("{0}{1}", "https://localhost:44375/", "BuildClient.svc"));
      }
  }

And the call to the server is done with the following code:

MyCommunicationClient myClient = new MyCommunicationClient (WCFBindings.TransportBinding, WCFBindings.EndPointBuildClient));
ResultObject response = myClient.CallService(serviceRequestParameter);

When I try this WCF-Call to the migrated service I get a HttpStatusCode 401.

The current configuration of the migrated server looks like the following in the Program.cs:

builder.Services.AddHttpContextAccessor();
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
    .AddNegotiate();

builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = options.DefaultPolicy;
    options.AddPolicy("RequireWindowsAuth", policy =>
    {
        policy.RequireAuthenticatedUser();
        policy.AddAuthenticationSchemes(NegotiateDefaults.AuthenticationScheme);
    });
});

builder.WebHost.UseIISIntegration();
// some more code here
app.UseServiceModel(serviceBuilder =>
{



 serviceBuilder.AddService<BuildClient>((serviceOptions) => { })
        .AddServiceEndpoint<BuildClient, IBuildClient>(new BasicHttpBinding
        {
            Security = new BasicHttpSecurity
            {
                Mode = BasicHttpSecurityMode.Transport,
                Transport = new HttpTransportSecurity
                {
                    ClientCredentialType = HttpClientCredentialType.Windows,
                    AlwaysUseAuthorizationPolicySupport = true,
                    Realm = "mydomain.com"
                }
            }
        }, "/BuildClient.svc");

});

    var serviceMetadataBehavior = app.Services.GetRequiredService<ServiceMetadataBehavior>();
    serviceMetadataBehavior.HttpGetEnabled = true;
    serviceMetadataBehavior.HttpsGetEnabled = true;
    
    IHttpContextAccessor httpContextAccessor = app.Services.GetRequiredService<IHttpContextAccessor>();
    IdentityProvider.Configure(httpContextAccessor);

    
app.UseAuthentication();
app.UseAuthorization();

The configuration for the IIS-Express is:

{

    "iisSettings": {
        "windowsAuthentication": true,
        "anonymousAuthentication": false,
        "iisExpress": {
            "applicationUrl": "http://localhost:50228",
            "sslPort": 44375
        }
    },
    "profiles": {
        "IIS Express": {
            "commandName": "IISExpress",
            "launchBrowser": true,
            "launchUrl": "swagger",
            "environmentVariables": {
                "ASPNETCORE_ENVIRONMENT": "Development"
            }
        }
    },
    "BuildService": {
        "commandName": "Project",
        "dotnetRunMessages": true,
        "launchBrowser": true,
        "applicationUrl": "http://localhost:50228;https://localhost:44375",
        "environmentVariables": {
            "ASPNETCORE_ENVIRONMENT": "Development"
        }
    }
}

With this setup I get the already mentioned 401 Http-Code. When I change the AddAuthentication to look like the following:

builder.Services.AddAuthentication("Ntlm")
    .AddScheme<NtlmAuthenticationOptions, NtlmAuthenticationHandler>("Ntlm", options =>
    {
        options.Domain = "mydomain.com";
    }).AddNegotiate();

where the NtlmAuthenticationHandler contains the following:

protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
  var user = Context.User;
  var user2 = IdentityProvider.Current;
}

When I look at the user or user2-variable while autentication I can see in the REST-Request that I'm authenticated and my user-id is provided. Within the WCF-Request there is no user-id provided and the request is not authenticated.

I've also tried some other combinations of setup for HttpClientCredentialType but with no success.

Does anyone have an idea how to configure the migrated server to properly authenticated the calling user within a WCF-call?

If you need more informations about the server or the client I can provide them.

Upvotes: 0

Views: 39

Answers (0)

Related Questions