Declarative Use of Custom SecurityTokenParameters


It’s not the first time I’ve stated this, but one of the reasons I love WCF is that it’s so wonderfully extensible. You can even implement your own custom security token, as this article explains. The only problem with this article is that it uses imperative code to create a custom Binding, and it doesn’t explain how you can implement a custom security token mechanism in a declarative way (i.e. using app.config).


The offending part is the custom SecurityTokenParameters, which you can’t specify declaratively, but have to attach to a SecurityBindingElement in some way.


So if you still want to be able to specify the use of your custom security token in app.config, how can you implement that?


A simple solution I’ve found involves creating a custom BindingElement that contains all the custom security token implementation, including the custom SecurityTokenParameters. This BindingElement additionally acts as a Decorator for whatever SecurityBindingElement you really want to use:


public class CreditCardSecurityBindingElement : BindingElement
{
    private readonly SymmetricSecurityBindingElement innerBindingElement_;
 
    public CreditCardSecurityBindingElement()
    {
        this.innerBindingElement_ = new SymmetricSecurityBindingElement();
        this.innerBindingElement_.EndpointSupportingTokenParameters.SignedEncrypted.Add(new CreditCardTokenParameters());
 
        //..
    }
 
    //..
}

To fully implement your custom BindingElement, remember to override all its virtual methods to delegate the functionality to the inner SecurityBindingElement, like this:


public override T GetProperty<T>(BindingContext context)
{
    return this.innerBindingElement_.GetProperty<T>(context);
}

To be able to use your custom BindingElement (CreditCardSecurityBindingElement) declaratively as part of a custom binding in app.config, you need to implement a BindingElementExtensionElement that creates it. Once you have done that, you should be good to go.

Comments (5)

  1. Lee says:

    not entirely on topic but close enough 🙂 i’m trying to implement the CustomToken over tcp. The original used the SymmetricSecurityBindingElement and the transport http, this works fine, but when i change URI’s and and the transport, it gives an error saying:

    Binding ‘CustomBinding’ doesn’t support creating any channel types. This often indicates that the BindingElements in a CustomBinding have been stacked incorrectly or in the wrong order. A Transport is required at the bottom of the stack. The recommended order for BindingElements is: TransactionFlow, ReliableSession, Security, CompositeDuplex, OneWay, StreamSecurity, MessageEncoding, Transport.

    do you have any incite into this issue or a way to get a specific error?

    thank you

  2. Oleg Zimin says:

    I’m trying to realize Declarative binding on your suit.

    I have the following error occurs:

    —————————————-

    The security capabilities of binding ‘System.ServiceModel.Channels.CustomBinding’ do not match those of the generated runtime object. Most likely this means the binding contains a StreamSecurityBindingElement, but lacks a TransportBindingElement that supports Stream Security (such as TCP or Named Pipes). Either remove the unused StreamSecurityBindingElement or use a transport that supports this element.

    ——————————————–

    Could you provide the source code of your example.

    Thank you very much.

  3. ploeh says:

    Hi Oleg

    As you probably have already noticed, I also replied privately to the email you sent, but for the benefit of other readers, I’ll repeat my answer here:

    Normally, I’m only happy to share my sample code, but in rare cases, the code I post is taken directly from customer or production code. In those rare cases, it would be illegal for me to share the code; unfortunately, the code in this particular post is such a case.

    However, I can share an anonymized customBinding element of one of my .config files:

    <binding name="…">

              <creditCardSecurity />

              <binaryMessageEncoding />

              <httpTransport />

    </binding>

  4. rally25rs says:

    Thanks for this writeup, it was a huge help! I still don’t have it fully working, but for implementation, I beleive you can skip the custom BindingElement and just do the work in the BindingElementExtensionElement, like this:

    public sealed class CentralAuthTokenBindingExtension : BindingElementExtensionElement

    {

    public CentralAuthTokenBindingExtension()

    : base()

    {

    }

    public override Type BindingElementType

    {

    get { return typeof(SymmetricSecurityBindingElement); }

    }

    protected override System.ServiceModel.Channels.BindingElement CreateBindingElement()

    {

    X509SecurityTokenParameters protectionParams = new X509SecurityTokenParameters();

    protectionParams.InclusionMode = SecurityTokenInclusionMode.Never;

    SymmetricSecurityBindingElement innerBindingElement = new SymmetricSecurityBindingElement();

    innerBindingElement.EndpointSupportingTokenParameters.SignedEncrypted.Add(new CentralAuthTokenParameters());

    //innerBindingElement.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt;

    innerBindingElement.ProtectionTokenParameters = protectionParams;

    return innerBindingElement;

    }