Joe 89
Joe 89

Reputation: 910

Using NetworkCredential in WCF services

I have a WCF service which uses Windows Authentication to view Service Contract and a specfic method in a service is configured to be accessed only by a specific user UserX.

[PrincipalPermission(SecurityAction.Demand,Name="xxx\\UserA")]

In the client side, I need to access the above service method. If I am using a Web Reference -> I add the following

client = new WebRefLocal.Service1();
client.Credentials = new System.Net.NetworkCredential("UserA", "xxxxxx", "test");

But the above cannot be achieved in WCF Service Reference as Client Credentials are read-only. One best way I can achieve the above is Impersonation https://msdn.microsoft.com/en-us/library/ff649252.aspx.

My question here is

  1. Why ClientCredentials are made readonly in WCF?
  2. How Network Credential work? Will they authenticate the Windows login in client side or server side?
  3. Is there is any way I can achieve the above in WCF aswell without impersonation?

Upvotes: 2

Views: 6003

Answers (2)

Daniel Stackenland
Daniel Stackenland

Reputation: 3239

I've done something like this - hope it helps:

 var credentials = new ClientCredentials();
credentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Delegation;
credentials.Windows.ClientCredential = new System.Net.NetworkCredential("UserA", "xxxxxx", "test");

client.Endpoint.Behaviors.Remove<ClientCredentials>();
client.Endpoint.Behaviors.Add(credentials);

Used with a BasicHttpBinding with following security settings:

  <security mode="TransportCredentialOnly">
    <transport clientCredentialType="Windows" proxyCredentialType="Windows" />
  </security>

Upvotes: 2

3dd
3dd

Reputation: 2530

One method you can use is to make use of ChannelFactory when calling the WCF service.

The following code was taken from one of my MVCprojects, hence it has someModelState` validation code, I'm sure you can modify it to suit your needs.

protected R ExecuteServiceMethod<I, R>(Func<I, R> serviceCall) {
    R result = default(R);
    ChannelFactory<I> factory = CreateChannelFactory<I>();
    try {
        I manager = factory.CreateChannel();
        result = serviceCall.Invoke(manager);
    } catch (FaultException<ValidationFaultException> faultException) {
        faultException.Detail.ValidationErrors.ToList().ForEach(e => ModelState.AddModelError("", e));
    } finally {
        if (factory.State != CommunicationState.Faulted) factory.Close();
    }
    return result;
}

private ChannelFactory<I> CreateChannelFactory<I>() {
   UserAuthentication user = GetCurrentUserAuthentication();

   ChannelFactory<I> factory = new ChannelFactory<I>("Manager");

   if (IsAuthenticated) {
       factory.Credentials.UserName.UserName = user.UserName;
       factory.Credentials.UserName.Password = user.Password;
   }

   BindingElementCollection elements = factory.Endpoint.Binding.CreateBindingElements();
   factory.Endpoint.Binding = new CustomBinding(elements);
   SetDataContractSerializerBehavior(factory.Endpoint.Contract);

   return factory;
}

Upvotes: 0

Related Questions