Zulfiqar's weblog

Architecture, security & random .Net

Archive for the ‘WCF’ Category

Silverlight Claim-Based-Security

Posted by zamd on February 8, 2011

This would hopefully be a multi-part series showing some tricks to enable claims-based-security in Silverlight 4.0. Silverlight 5.0 would have a much better story around claim-based-security as mentioned here.

In this first post, I’ll give you a high level overview of the solution. The main idea is to use the ‘WCF Routing Service’ in the DMZ to route both token issuance requests & business requests to the actual backend services.

1. Routing Service looks for a token issuing request and forwards it to the STS where the actual authentication is performed. After the successful authentication, STS issues a SAML token which goes back to Silverlight client via the routing service. Routing Service also terminates the SSL and backend is called using straight HTTP. This model offers strong security on the internet while keeping the internal deployment simpler & efficient. This model also resembles with the standard SSL offloading setup where a hardware load-balancer is used to terminate the SSL.

1: Token Issuance Path

image

2. Once the Silverlight client got a SAML token, it can attach it to all subsequent message sent to business service(s). Routing Services forwards al the business messages (messages which doesn’t match the token issuance filter) to the actual backend services again doing the protocol transitioning from HTTPS to HTTP. Please note, here you can use the rich filtering mechanism provided by the Routing services to decide which messages should to which services. I used a very simple MatchAll filter which forwards all the non-token-issuance messages to the business service.

2: Web Service Call Containing a SAML Token

image

To implement the 1st part of solution I have used the WSTrustClient class & the associated bindings from the identity training kit.

var vm = this.DataContext as MainPageViewModel;

var stsBinding = new WSTrustBindingUsernameMixed();

var stsCreds = new UsernameCredentials(vm.UserId, vm.Password);
var client = new WSTrustClient(
    stsBinding,
    new EndpointAddress(vm.SelectedEndpoint),
    stsCreds);

var rst = new RequestSecurityToken(WSTrust13Constants.KeyTypes.Bearer);
rst.AppliesTo = new EndpointAddress(vm.AppliesTo);

client.IssueCompleted += new System.EventHandler<IssueCompletedEventArgs>(client_IssueCompleted);
client.IssueAsync(rst);

For the 2nd part I have implemented a message inspector along with an extension method which makes it super easy to attach the SAML with outgoing messages.

var vm = this.DataContext as MainPageViewModel;
var client = new ServiceReference1.Service1Client();

client.AttachToken(vm.SecurityToken.RawToken);

client.GetDataCompleted += new EventHandler<ServiceReference1.GetDataCompletedEventArgs>(client_GetDataCompleted);
client.GetDataAsync(32);

Posted in Security, WCF, WIF | 11 Comments »

WCF Reliable Messaging Retransmission Algorithm

Posted by zamd on October 13, 2010

When configuring WS-Reliable messaging, you would notice that even though number of retries (MaxRetryCount) is configurable but the interval in which retries are attempted is NOT configurable.  This is because WCF uses an exponential back-off congestion control algorithm to calculate the retry timeout.  This algorithm is internal to WCF and is NOT configurable.

The initial retry time is calculated based on the “session initiation time” (Time difference between the CreateSequence and CreateSequenceResponse). The algorithm doubles the retransmission delay with every attempt until MaxRetryCount reached.

If you try to send large messages inside a reliable session you might see additional retransmission fairly quickly. As the RM implementation calculates its initial retransmission timeout based on the “session initiation time” which remains quite small value (< 50ms ) in most cases. Now if the second message is a large one – the retry timeout expires and message is retransmitted.  This behaviour is by design as Reliable messaging is not intended to be used for large messages – this is why it doesn’t support streaming. If your goal is to send large messages and survive broken connections, then you should look at ReliableSessions along with the ChunckingChannel.

Posted in WCF | Leave a Comment »

Using WIF for securing REST Service

Posted by zamd on July 31, 2010

OAuth WRAP and SWT (Simple Web Token) have emerged as a standard way for employing claim-based-security to the REST services.  Conceptually this model is very similar to the one used in SOAP world. A client goes to an issuer, authenticates itself using some token and gets back a different token (containing claims) in SWT format. 

WIF provides a rich API and object model to claim-enable your .Net applications but currently it doesn’t natively support OAuth or SWT. In this post, I’ll show how you can extend WIF to bring claim-based-security to REST services.  My goal is to implement this functionality in such a way that all the WIF goodness around claims-transformation (ClaimsAuthenticationManager), claim-based-authorization (ClaimsAuthorizationManager) etc can be used exactly the same way in the REST world.

I have achieved this by introducing an OAuth WRAP channel which sits in the WCF channel stack and perform an almost identical job to its SOAP counterpart WS-Security channel.  I have implemented the OAuth WRAP channel using the interceptor API from the REST Starter Kit.

image WebServiceHost2 host = new WebServiceHost2(typeof(TestService), new Uri(http://localhost:9090));

host.Interceptors.Add(new OAuthWrapSecurityChannel());

host.Open();

The OAuth channel takes care of extracting the token from the incoming message, running it through the validation pipeline (based on WIF SecurityTokenHandler framework), calling ClaimsAuthenticationManager, setting the WCF authorization context so that ClaimsAuthorizationManager can be called, and finally presenting the claims to the service method in the standard WIF way: Thread.CurrentPrincipal :)

Now with OAuth channel plugged in, if I call the service with a token issues by the Windows AppFabric ACS:

clip_image002

I get following output on the service side.

clip_image001

And from the service code, you would notice that standard WIF API is used to access incoming claims.

[WebGet]

string Hello()

{

    Console.WriteLine("Hello called…");

    Console.WriteLine("——————");

    var cp = Thread.CurrentPrincipal as IClaimsPrincipal;

    if (cp != null)

    {

        foreach (var id in cp.Identities)

        {

            Console.WriteLine("Authentication Type: " + id.AuthenticationType);

            Console.WriteLine("Is Authenticated: " + id.IsAuthenticated);

            Console.WriteLine("Name: " + id.Name);

            Console.WriteLine();

            Console.WriteLine("Claims…");

            foreach (var c in id.Claims)

            {

                Console.WriteLine(c.ClaimType + ": " + c.Value);

            }

        }

    }

    return "Hello, World";

}

 

WIF would be configured using exactly same configuration settings required for a SOAP service.

  1. <configuration>
  2.   <configSections>
  3.     <section name="microsoft.identityModel" type="Microsoft.IdentityModel.Configuration.MicrosoftIdentityModelSection, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  4.   </configSections>
  5.  
  6.   <system.serviceModel>
  7.     <behaviors>
  8.       <serviceBehaviors>
  9.         <behavior>
  10.           <federatedServiceHostConfiguration />
  11.           <serviceDebug includeExceptionDetailInFaults="true" />
  12.         </behavior>
  13.       </serviceBehaviors>
  14.     </behaviors>
  15.     <extensions>
  16.       <behaviorExtensions>
  17.         <add name="federatedServiceHostConfiguration" type="Microsoft.IdentityModel.Configuration.ConfigureServiceHostBehaviorExtensionElement, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  18.       </behaviorExtensions>
  19.     </extensions>
  20.   </system.serviceModel>
  21.   <!–WIF configuration–>
  22.   <microsoft.identityModel>
  23.     <service>
  24.       <securityTokenHandlers>
  25.         <add type="Microsoft.IdentityModel.OAuth.SWTSecurityTokenHandler, Microsoft.IdentityModel.OAuth, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  26.       </securityTokenHandlers>
  27.       <issuerNameRegistry type="SampleService.MySimpleRegistry, SampleService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  28.       <claimsAuthorizationManager type="SampleService.MySimpleClaimsAuthorizationManager, SampleService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  29.       <audienceUris>
  30.         <add value="http://localhost/" />
  31.       </audienceUris>
  32.       <issuerTokenResolver type="SampleService.WrapIssuerTokenResolver, SampleService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
  33.     </service>
  34.   </microsoft.identityModel>
  35.   <startup>
  36.     <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
  37.   </startup>
  38. </configuration>

 

In summary, these extensions implement OAuth WRAP protocol head for Windows Identity Foundation and re-uses all the neat WIF APIs for deriving the service behaviour. In the next post, I’ll discuss how to create a local OAuth WRAP issuer using the SecurityTokenService WIF API.

Feel free to download the source and experiment.

Posted in WCF, WIF, Windows Azure AppFabric | 6 Comments »

PasswordDigest authentication in WCF

Posted by zamd on July 12, 2010

WS-Security UsernameToken Profile describes how a client can authenticate to a web service using a "username" and a password. Two variations of the password are defined as part of the specification which includes "PasswordText" and "PasswordDigest". Neither WCF nor WIF out of box support "PasswordDigest" however there are some interop scenarios which might require "PasswordDigest". For example, WSE 3.0 supports "PasswordDigest" and if you have to interop your WSE 3.0 clients with WCF services you might need PasswordDigest functionality. In this post I’ll show you a basic implementation of PasswordDigest closely integrated with WCF API. Please note, this could be much easier to implement using the SecurityTokenHandler based API shipped with WIF.

I have created a new assembly and added all the security extensions in this new assembly named Microsoft.ServiceModel.SecurityExtensions.dll.

Microsoft.ServiceModel.SecurityExtensions.dll extends WCF to support Password Digest authentication while retaining WCF’s public programming model. You need to reference this assembly in all your web service projects where you want to enable PasswordDigest authentication. The security extensions are very closely aligned to the standard WCF model of userName/Password validation so you should be able to leverage all of your existing knowledge. 

Please note this is a trivial implementation primarily focused on WCF integration rather than spec implementation. This example doesn’t contain any countermeasure code against replay attacks. You can add such functionality by maintaining a cache of used nonces on the server side and then checking against the replay.

To use these extensions in your web service(s), you need to do following:

  • Specify the type attribute of serviceCredentials to Microsoft.ServiceModel.SecurityExtensions.ServiceCredentialsEx for the extensions to kick in.
  • Specify your custom validator using the standard WCF syntax. Your custom validator MUST inherit from Microsoft.ServiceModel.SecurityExtensions.UserNamePasswordDigestValidator

<behaviors>

  <serviceBehaviors>

    <behavior>

      <serviceCredentials type="Microsoft.ServiceModel.SecurityExtensions.ServiceCredentialsEx, Microsoft.ServiceModel.SecurityExtensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">

        <userNameAuthentication userNamePasswordValidationMode="Custom"

                                customUserNamePasswordValidatorType="PasswordDigest.MyValidator, PasswordDigest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>

      </serviceCredentials>

    </behavior>

  </serviceBehaviors>

</behaviors>

  • Finally implement your custom validator by inheriting from Microsoft.ServiceModel.SecurityExtensions.UserNamePasswordDigestValidator. This class integrates with various extensions and implements the logic of PasswordDigest validation.

I have attached the source code and sample project with this post.

Posted in Extensibility, Security, WCF | 3 Comments »

X509 based proof keys with wsFederationHttpBinding

Posted by zamd on May 14, 2010

When requesting a SAML token from an STS you can also request a proof token, which you can use to proof your ownership (by signing the primary signature with the proof token) of the token to the relying party when sending a SOAP message to it. In Identity terms, this is known as Holder-Of-Key subject confirmation method.

When using Holder-Of-Key confirmation method, there are three options for proof token:

  1. Symmetric key (based proof tokens)
  2. Asymmetric key
  3. Bearer key

See this post from Vittorio on the details of proof token.

Asymmetric key based proof tokens can come in following two forms:

  1. Requestor can generate an ephemeral RSA key pair and submit the public key to the IP/STS as part of the RST request. Requestor then signs the RST request with its private key to demonstrate the knowledge of the private key.
  2. Requestor can use an existing X509 public key cert as the proof token and use the corresponding private key cert to create the supporting signature.

wsFederationHttpBinding out of box (as in .NET 4.0) only supports an ephemeral RSA key pair while certain interop scenarios require X509 based asymmetric proof keys. For example, Apache Rampart 1.4 doesn’t seem to like ephemeral RSA key pair and forces you to use X509 based asymmetric proof keys. Unfortunately today this scenario is not possible out of box with wsFederationHttBinding. WSTrustChannelFactory API in WIF however supports both RSA key pair & X509 certs and you can choose your desired key type when requesting a token but WIF is not supported on XP.

So If you are on Windows XP or can’t use WIF for some other reason, you would have to extend wsFederationHttpBinding to enable X509 based proof keys. Probably a custom endpoint behaviour and inside it you would have to tweak IssuedSecurityTokenProvider to force it to use X509 key. See this post on how to work with IssuedSecurityTokenProvider directly. In the next post, I will talk more about extending wsFederationHttpBinding to support X509 based proof keys.

Posted in Security, WCF | 1 Comment »

Custom ServiceHostFactory for a XAMLX based Service

Posted by zamd on April 23, 2010

For IIS/WAS hosted services backed by a physical .SVC file (WCF 3.0/3.5) you can specify a custom ServiceHostFactory in the .svc file as part of service specification. There is no such declaration for XAMLX files and instead you can use config-based activation feature to achieve the same result.

If my WCF service is deployed as Service1.xamlx and I want to customize the WorkflowServiceHost before it’s opened and used, I can easily do this using following two steps:

  1. Create a custom ServiceHostFactory by sub classing the default one

namespace DeclarativeServiceLibrary1

{

    public class MyServiceHostFactory : WorkflowServiceHostFactory

    {

        protected override WorkflowServiceHost CreateWorkflowServiceHost(Activity activity, Uri[] baseAddresses)

        {

            return base.CreateWorkflowServiceHost(activity, baseAddresses);

        }

        protected override WorkflowServiceHost CreateWorkflowServiceHost(WorkflowService service, Uri[] baseAddresses)

        {

            var host =  base.CreateWorkflowServiceHost(service, baseAddresses);

            // add your customizations here…

            return host;

        }

    }

}

2.  Configure your custom ServiceHostFactory for your XAMLX file

  <system.serviceModel>

  

    <serviceHostingEnvironment multipleSiteBindingsEnabled=true >

      <serviceActivations>

        <add relativeAddress=~/Service1.xamlx

             service=Service1.xamlx

             factory=DeclarativeServiceLibrary1.MyServiceHostFactory/>

      </serviceActivations>

    </serviceHostingEnvironment>

  </system.serviceModel>

Posted in WCF | 6 Comments »

Adding Dynamic methods to a WCF Service

Posted by zamd on February 5, 2010

Someone asked me if it’s possible to add a Ping method to every service contract without repeatedly defining it in each service contract?  The answer is yes & and it’s fairly simply too.

Here I have a LoginService, which require that implicit Ping method (DateTime Ping(){})like all other service.

 

[ServiceContract]

class LoginService

{

    [OperationContract]

    public bool Login(string userName, string password)

    {

        return true;

    }

}

This is how you would configure your host for these implicit methods.

class Program

{

    static void Main(string[] args)

    {

        var sh = new ServiceHost(typeof(LoginService), new Uri(http://localhost:9001&#8243;));

 

        GeneratePingMethod(sh);

        sh.Open();

 

        Console.ReadLine();

        sh.Close();

    }

}

 

Please note “GeneratePingMethod” adds the Ping method to every endpoint.  I’m simply creating the operation using the WCF description API and adding it into the description tree. PingImplementationBehavior plugs in a custom OperationInvoker which calls the actual Ping implementation.

 

private static void GeneratePingMethod(ServiceHost sh)

{

    foreach (var endpoint in sh.Description.Endpoints)

    {

        var cd = endpoint.Contract;

        var od = new OperationDescription(“Ping”, cd);

        var inputMsg = new MessageDescription(cd.Namespace + cd.Name + “/Ping”, MessageDirection.Input);

        var outputMsg = new MessageDescription(cd.Namespace + cd.Name + “/PingResponse”, MessageDirection.Output);

        var retVal = new MessagePartDescription(“PingResult”, cd.Namespace); ;

        retVal.Type = typeof(DateTime);

 

        outputMsg.Body.ReturnValue = retVal;

 

 

        od.Messages.Add(inputMsg);

        od.Messages.Add(outputMsg);

 

        od.Behaviors.Add(new DataContractSerializerOperationBehavior(od));

        od.Behaviors.Add(new PingImplementationBehavior());

 

        cd.Operations.Add(od);

    }

}

 

class PingImplementationBehavior : IOperationBehavior

{

    public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)

    { }

 

    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)

    { }

 

    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)

    {

        dispatchOperation.Invoker = new PingInvoker();

    }

 

    public void Validate(OperationDescription operationDescription)

    { }

}

Again a fairly simple invoker which is tightly coupled to the signature of Ping method.

class PingInvoker : IOperationInvoker

{

    public object[] AllocateInputs()

    {

        return new object[0];

    }

 

    public object Invoke(object instance, object[] inputs, out object[] outputs)

    {

        outputs = new object[0];

        return Ping();

    }

 

    public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)

    {

        throw new NotImplementedException();

    }

 

    public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)

    {

        throw new NotImplementedException();

    }

 

    public bool IsSynchronous

    {

        get { return true; }

    }

 

    public static DateTime Ping()

    {

        return DateTime.Now;

    }

}

Posted in WCF | 8 Comments »

Using Request Headers for Metadata Address

Posted by zamd on January 14, 2010

WCF by default adds the listen address of the endpoints in the WSDL so in a scenario where the private address of the server is different from the public address you get incorrect endpoint address in WSDL.

For example if a service is listening on http://localhost:7721/ and you access its metadata using a virtual IP http://102.212.0.117/?wsdl, you get following:

 

Now this behavior might not work in certain scenarios and you want the metadata generation to dynamically pick the address from the request headers, similar to ASMX web services.

UseRequestHeadersForMetadataAddressBehavior enables exactly this. This opt-in behavior sets the address of endpoints dynamically, based on the request header.  

Like all other WCF behaviors, this behavior can be enabled either in the code or config.

sh.Description.Behaviors.Add(new UseRequestHeadersForMetadataAddressBehavior());

<system.serviceModel>

  <behaviors>

    <serviceBehaviors>

      <behavior>

        <useRequestHeadersForMetadataAddress/>

      </behavior>

    </serviceBehaviors>

  </behaviors>

</system.serviceModel>

As part of this behavior, you can also specify default ports for different schemes (http,https etc..). These default ports come into action in following scenarios:

  • When metadata is accessed over http, all http based URIs are substitued with the Hostname and host port from the Host header
  • All https based URIs picks the default port registered against https scheme
  • Similarly when metadata is accessed over https, all https URIs pick up the host and port from the host header and http based URIs used the default port registered against http scheme

This behavior is added in .NET 4.0 and there is a QFE available for 3.5 SP1: http://support.microsoft.com/kb/971842

Posted in WCF | 4 Comments »

WCF Behavior Ordering

Posted by zamd on June 2, 2009

WCF behaviours are applied based on a particular evaluation order. Exact details are available here 

The ServiceHost applies behaviors in the following order:

1.     Contract

2.     Operation

3.     Endpoint

  1. Service

Please note within any collection of behaviors, ordering is NOT guaranteed. Because of that sometimes when you configure some aspects of runtime in your custom behavior (for example, TransactionRequired property of the operation) – they get overwritten by default WCF behavior. For example, following will not work and TransactionRequired will always be set to false (default value).

class TestBv : Attribute, IOperationBehavior

{

    public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) { }

    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation){}

 

    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)

    {

        dispatchOperation.TransactionRequired = true;

    }

 

    public void Validate(OperationDescription operationDescription){}

}

Why? Because here WCF is executing default OperationBehavior after the execution of your custom behavior. Please note, missing OperationBehaviorAttribute doesn’t mean that behavior won’t be applied at all rather it mean a default OperationBehavior will be applied.

So how to fix this?

Use explicit ordering: Remove the bahavior from the collection and apply it at a particular time yourself. Here is the modified behavior which will work correctly.

class TestBv : Attribute, IOperationBehavior

{

    IOperationBehavior orignal;

 

    public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) { }

    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation){}

 

    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)

    {

        orignal.ApplyDispatchBehavior(operationDescription, dispatchOperation);

        dispatchOperation.TransactionRequired = true;

    }

 

    public void Validate(OperationDescription operationDescription)

    {

        this.orignal = operationDescription.Behaviors.Find<OperationBehaviorAttribute>();

        if (orignal != null)

             operationDescription.Behaviors.Remove(orignal);

    }

}

HTH…

Posted in WCF | Leave a Comment »

Pass-through SAML tokens & Secure Conversation (Part1)

Posted by zamd on May 8, 2009

Part 2

Let’s say you have implemented federated security and now you have bunch of services all of them requires a token from a trusted STS to provide any service. Now some of these services are logically part of same security realm but are still distinct entities.  To optimize performance, you probably want to do some short circuiting so that when a user presents a token (issued by trusted STS) to one of these services – then this frontend service should simply be able to forward this incoming token to backend services within its logical security boundary (akin to trusted delegation). Here is a diagrammatic view.

On the surface, this sounds like a simple scenario which can be implemented as:

·         Reach into incoming service security context

·         Extract the incoming token

·         Pass it on to backend service

The trouble here is: wsFederationHttpBinding wisely uses secure conversation, to avoid token acquisition overhead for each call. Due to this optimization, we never get to see the actual bootstrap token (token used to establish secure conversation session) inside our service methods.

 In the next post, I will show you how to extend WCF security framework to enable this scenario?

At a very high level, we need to hook into secure conversation handshake, extract the incoming SAML token and save it somewhere for future use.

 

Posted in Federation/STS, WCF | Leave a Comment »

 
Follow

Get every new post delivered to your Inbox.