Search

Locations of visitors to this page

Categories

On this page

WCF Behavior Ordering
Pass-through SAML tokens & Secure Conversation (Part1)
Forms Auth & Federated Security (part 2)

Archive

Blogroll

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

RSS 2.0 | Atom 1.0 | CDF

Send mail to the author(s) E-mail

Total Posts: 50
This Year: 6
This Month: 1
This Week: 1
Comments: 69

Sign In

 Tuesday, June 02, 2009
Tuesday, June 02, 2009 1:39:43 PM (GMT Standard Time, UTC+00:00) ( WCF )

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...

Comments [0] | | # 
 Friday, May 08, 2009
Friday, May 08, 2009 10:36:33 PM (GMT Standard Time, UTC+00:00) ( )
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.

 

Comments [0] | | # 
 Saturday, April 25, 2009
Saturday, April 25, 2009 1:23:14 PM (GMT Standard Time, UTC+00:00) ( Federation/STS | WCF Security )

Here I talked about an approach that you can use to integrate your legacyJ  forms auth applications with STS and bring them into the world of federated security.   

One major hurdle in implementing this approach is to flow Forms Auth cookie to the STS so that it can authenticate the caller and can issue a token. With wsFederationHttpBinding, you don’t directly talk to the STS rather federation binding talks to the STS as part of your service call.  After wsFederationHttpBinding successfully acquired a token, only then your service is called and token is sent as part of the call. This is good because it hides all the token acquisition/forwarding complexity from you and offers you a simple programming model.

Now in our case, we need to intercept the messages sent by FedBinding to the STS so that we can send our Forms Auth cookie along with the message.

At this point a very brief diagrammatic overview of WCF message security framework will help:

On the client side TokenProvider is responsible for providing tokens to message security layer. There is TokenProvider for each type of type (Usernname, IssuedToken etc).

IssuedSecurityTokenProvider is used when a SAML token is required by the message security layer and this is the guy we need to intercept.

Let’s start by creating a custom ClientCredentials:

public class ClientCredentialsWrapper : ClientCredentials

{

    public ClientCredentialsWrapper()

    {}

    public ClientCredentialsWrapper(ClientCredentials other):base(other)

    {}

    public override SecurityTokenManager CreateSecurityTokenManager()

    {

        return new ClientSecurityTokenManagerWrapper(this);

    }

    protected override ClientCredentials CloneCore()

    {

        return new ClientCredentialsWrapper(this);

    }

}

Next our custom SecurityTokenManager:

class ClientSecurityTokenManagerWrapper : ClientCredentialsSecurityTokenManager

{

    public ClientSecurityTokenManagerWrapper(ClientCredentials parent)

        : base(parent)

    { }

    public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)

    {

        var provider = base.CreateSecurityTokenProvider(tokenRequirement);

        var issuedProvider = provider as IssuedSecurityTokenProvider;

        if (issuedProvider != null)

            issuedProvider.IssuerChannelBehaviors.Add(new MessageInspectorInstallerBehavior());

        return provider;

    }

}

Here I have added endpoint behaviour in the ChannelFactory used by IssuedSecurityTokenProvider to talk to STS.

 

 class MessageInspectorInstallerBehavior : IEndpointBehavior

{

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)

    { }

 

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)

    {

        clientRuntime.MessageInspectors.Add(new CookieFlowMessageInspector());

    }

 

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)

    { }

 

    public void Validate(ServiceEndpoint endpoint)

    { }

}

Here I’m simply installing a MessageInspector which looks like this:

class CookieFlowMessageInspector : IClientMessageInspector

{

    public void AfterReceiveReply(ref Message reply, object correlationState)

    { }

 

    public object BeforeSendRequest(ref Message request, IClientChannel channel)

    {

        object prop = null;

        HttpRequestMessageProperty rmp = null;

        if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, out prop))

            rmp = prop as HttpRequestMessageProperty;

        else

            rmp = new HttpRequestMessageProperty();

 

        rmp.Headers[HttpRequestHeader.Cookie] = FormAuthUtility.GetCookieHeaderFromRequest();

        request.Properties[HttpRequestMessageProperty.Name] = rmp;

        return null;

    }

}

Client code will stay the same and you just have to call just one extension method to hook everything together.

 var proxy = new STSCookieServiceReference.EchoServiceClient();

var certPath = HttpContext.Current.Server.MapPath("~/localhost.cer");

proxy.ClientCredentials.ServiceCertificate.DefaultCertificate = new X509Certificate2(certPath);

 

proxy.EnableIssuedTokenProviderCookieFlow(); 

proxy.Echo("Welcome.");

And this is how extension method is implemented.

public static void EnableIssuedTokenProviderCookieFlow<TChannel>(this ClientBase<TChannel> source) where TChannel : class

{   

    var orignal = source.Endpoint.Behaviors.Remove<ClientCredentials>();

    source.Endpoint.Behaviors.Add(new ClientCredentialsWrapper(orignal));

}

I have attached complete solution with this post. Feel free to download and have a look.

 

 

Download: FormsAuthFedSecurity.zip

Comments [0] | | #