Welcome to WindowsClient.net | Sign in | Join

Zuker On Foundations

The realm of .NET (WPF, WCF and all around)

WCF Security - UserName Over TCP Transport

In our project we build services in the intranet zone, therefore windows authentication is really the most simple and sufficient authentication mode for us.

Lately though, we have encountered continuing troubles with Kerberos Delegation,
Most of the times it was due to domain settings (delegation trust / spns and such), unfortunately, in the other times we discovered it's actually hardware issues - We needed to update the user's network adapter drivers.

We decided No More, let's look into different approach that will replace it.

I headed to work and found a great sample in the SDK called 'Trusted Facade'.

Service Side:

We create a custom binding that uses a tcp transport with windows stream security but the authentication mode is set to UserNameOverTransport.
This essentially means the binding will be over TCP, accepting calls from windows account users but the authentication will be done for the username being passed on the transport, allowing a client to call with a constant windows identity but passing the actual caller's username onto the transport.

<customBinding>
  
<binding name="TcpUserNameBinding">
      <security authenticationMode="UserNameOverTransport" />
      <
windowsStreamSecurity />
      <tcpTransport maxReceivedMessageSize="2147483646" />
   </
binding>
</
customBinding>

We create the service behavior and setting the service credentials.

Since this is no longer windows integrated, we could use the aspnet membership provider but since the client passes a windows account's username and not an aspnet user I will set it to custom.
The PasswordValidator doesn't do much, simply throws an exception if the username is null or empty, in some cases I check for an expected password that only valid clients will know of, anyway, you can implement any logic that suits you.

<behavior name="CustomUserNamePasswordValidatorBehavior">
   <serviceCredentials>
      <
userNameAuthentication
         userNamePasswordValidationMode="Custom"
         customUserNamePasswordValidatorType="Zuker.Solutions.ServiceModel.Security.SecuredUserNamePasswordValidator, Zuker.Solutions.ServiceModel" />
   </
serviceCredentials>
</
behavior>

We set the endpoint - bind it to our binding and behavior, then of course - hosting it up.

Client Side

We set the configuration pretty much a like, create the custom binding and bind it to our endpoint.

<customBinding>
  
<binding name="TcpUserNameBinding">
      <security authenticationMode="UserNameOverTransport" />
      <
windowsStreamSecurity />
      <tcpTransport maxReceivedMessageSize="2147483646" />
   </
binding>
</
customBinding>

Before calling the service, we need to set the username and password if needed, e.g. -

ChannelFactory<ISomeContract> channel = null;
channel.Credentials.UserName.UserName =
"MyUser";
channel.Credentials.UserName.Password =
"abc123";

Then we can create our channel and call the services, That's it!

Service Side - Extracting the UserName from the ClaimSet:

foreach (ClaimSet claimSet in ServiceSecurityContext.Current.AuthorizationContext.ClaimSets)
{
   foreach (Claim claim in claimSet)
   {
      if (claim.ClaimType == ClaimTypes.Name && claim.Right == Rights.Identity)
      {
         return (string)claim.Resource;
      }
   }
}

Notes on top of my mind:

  • This was suitable in my case where I searched for a fast and easy approach for replacing the normal windows integrated security.
    If you need to pass along more information or manage some sort of identity management, you can use authorization policies to make changes to the claim set, perhaps taking it further and use a custom token (SAML is a good standard) with a trusted issuer and implement a sort of WS-Trust mechanism
  • You can extract the caller's username from the ClaimSet, one thing you do lose here over windows integrated is the ability for using windows account impersonation so the actual context of the code to run under the caller's windows identity - you would have to know the user's password and perform an actual impersonation in this case
  • When using this mechanism, if the services call other services and the "others" want the initial caller's identity then they should support the same security model or you would need to impersonate the caller's identity on the first service.
  • Might think of implementing some sort of a intermediate service which will manage all calls and bridge over security differences in this case
Posted: Mar 04 2008, 07:50 AM by zuker | with 4 comment(s)
Filed under: ,

Comments

KJQ said:

This looks like exactly what i have been trying to do except the only difference is I have a wsHttp endpoint calling a tcp service and want to pass the credentials over to that.

Is there a source code sample for this?

Thanks.

KJQ

# May 21, 2008 12:32 PM

zuker said:

Hi KJQ,

There is a sample in the SDK which is called 'Trusted Facade' (usually at C:\Program Files\Microsoft SDKs\Windows\v6.0\Samples\WCFSamples\TechnologySamples\Scenario\TrustedFacade\CS)

The sample illustrates this concept.

As I understand from you,

Th client's endpoint is configured using a wsHttpBinding and the service is configured to use tcp protocol?

In this case you will experience problems and the communication will not work.

The bindings between the client and server must match.

# May 21, 2008 1:00 PM

KJQ said:

Almost...what i have is the following:

1) Public client makes call to a service (ServiceA) using public endpoint (wsHttp) and AspNet.  Client and server config matches.

2) From within the service (ServiceA) I want to call another service (ServiceB) that exposes an endpoint for internal use only (TCP or Pipes).

The issue I have been having is cascading the credentials from the AspNet (ServiceA) invocation to ServiceB.  At the point when I am in ServiceA I have the Principal.  Now what I want to do is call another service from that service and cascade those credentials over.  I don't need to necessarily secure the inner-service (ServiceB) just carry the Principal over.

In summary, I want to make service-to-service calls similar to how I make public-to-service calls.

Thanks.

# June 1, 2008 9:58 AM

zuker said:

Hi KJQ,

If I understand you correctly, you are talking about security delegation / cascading matters.

The flow as I understand is as follows:

Client --> Service A --> Service B

What is the security configuration for both Service A and Service B?

When you say Service A is an AspNet service, do you mean it is mapped to the aspnet roles store? (configured with Username authentication and aspnet roles authorization)

What is Service B configured with? If it is the native form of Tcp Binding, it is configured to accept windows tokens.

If that is the case, you have 2 services configured with different authentication.

This is a problem, because Service A will not have a Windows principal if it configured so, when calling Service B from the context of Service A, there wouldn't occur delegation in this case.

You could perform impersonation in Service A, but you would have to match a windows account for each username detail, plus you would have to know its password.

You should determine the following -

1) - Could the security configuration be matched between the services?

  - Perhaps add another authentication mode to Service B which would support Username as well.

  - Use Claims-Based security.

2) - Perhaps implementing a STS, trusting it in all services, some sort of WS-Trust

3) - Impersonate an appropriate windows account when calling Service B.

4) - Determine the best technical way to perform the security token delegation between services.

# June 8, 2008 3:20 AM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

Page view counter