About the author

Brian Keating is a developer addicted to Microsoft Technologies.

Month List

RecentComments

Comment RSS

Supporting WSE plain text password with WCF BasicHttpBinding

clock November 17, 2011 02:12 by author Brian Keating |

 

Hi all,

Ok, so I did a bit of googling to see if this had been done by someone else, turns out I failed to find a suitable solution, just many frustrated people.

So this post is an attempt to make those people a little happier.

The solutions is as follows(, It’s a bit rough around the edges at the moment as I have just got it working and have not yet cleaned up the code).

  • Firstly, I created a binding to manage the header
public class MyBehavior : BehaviorExtensionElement, IEndpointBehavior
    {      
 
        public MyBehavior(string userName, string password)
        {
            this.UserName = userName;
            this.Password = password;
        }
 
        #region IEndpointBehavior Members
 
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }
 
        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            clientRuntime.MessageInspectors.Add(new MyMessageInspector(this.UserName, this.Password));
        }
 
        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) 
        {
        }
        
        public void Validate(ServiceEndpoint endpoint) 
        { 
            
        }
 
        #endregion
        
 
        public override Type BehaviorType
        {
            get 
            { 
                return typeof(MyBehavior); 
            } 
        }
        
        protected override object CreateBehavior() 
        { 
            return new MyBehavior(this.UserName, this.Password); 
        }
 
        public string UserName { get; set; }
        public string Password { get; set; }
    }

Ok so now we can see this behavior adds a MessageInspector to every message. lets take a look at what the message inspector does.

 

  • MessageInspector
class MyMessageInspector : IClientMessageInspector
{
    public MyMessageInspector(string username, string password)
    {
        _username = username;
        _password = password;
    }

    public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
    {
            
    }

    public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
    {
        var header = new WseHeader(_username, _password);            
                
        request.Headers.Add(header); 
            
        return null;
    }


    private string _username;
    private string _password;
}

So here in my message inspector I add a new header.

In fact it’s this header that was making life hard for most people.

  • WseHeader
class WseHeader : MessageHeader
    {        
        public WseHeader(string userName, string password)
        {
            this.UserName = userName;
            this.Password = password;
        }
              
        public string UserName
        {
            get;
            private set;
        }
 
        private string Password
        {
            get;
            set;
        }
 
        protected override void OnWriteStartHeader(System.Xml.XmlDictionaryWriter writer, MessageVersion messageVersion)
        {
            base.OnWriteStartHeader(writer, messageVersion);
            writer.WriteAttributeString("s:mustUnderstand", "0");
            writer.WriteAttributeString("xmlns:wsse", WsseNamespaceToken);
            writer.WriteAttributeString("xmlns:s", "http://schemas.xmlsoap.org/soap/envelope/");
        }
 
        
 
        protected override void OnWriteHeaderContents(System.Xml.XmlDictionaryWriter writer, MessageVersion messageVersion)
        {
            writer.WriteRaw(Properties.Resources.WseHeaderText.Replace("{USERNAME}", 
                this.UserName).Replace("{PASSWORD}", this.Password));
            
        }
 
        public override string Name
        {
            get { return "wsse:Security"; }
        }
 
        public override string Namespace
        {
            get { return ""; }
        }
 
        public override bool MustUnderstand
        {
            get
            {
                return false;
            }
        }
 
 
        private const string WsseNamespaceToken = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
        
    }

This class will create a header like this

<wsse:Security s:mustUnderstand="0" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <wsse:UsernameToken wsu:Id="SecurityToken-3f7f983f-66ce-480d-bce6-170632d33f92" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
        <wsse:Username>bek@anchor</wsse:Username>
        <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">dotnetrocks</wsse:Password>
    </wsse:UsernameToken>
    </wsse:Security>
 

  • Please note I’m getting the body of the header from a project resource, here it is WseHeaderText
<wsse:UsernameToken wsu:Id="SecurityToken-3f7f983f-66ce-480d-bce6-170632d33f92" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <wsse:Username>{USERNAME}</wsse:Username>
    <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">{PASSWORD}</wsse:Password>
</wsse:UsernameToken>
 

I just replace the username and password in code in the MessageHeader. I could probably do all this neater with the API but it’s good enough for my investigation tonight, I usually just add the WSE header directly into my configuration file and not bother with the behavior.

e.g.

<client>
          <endpoint address="http://anchor:8083/gdm/TemplateActionsService/TemplateActionsService" binding="basicHttpBinding" bindingConfiguration="TemplateActionsServiceSoapBinding" contract="TemplateActionsProxy.TemplateActionsServiceType" name="TemplateActionsServicePort">
            <!-- this will work without behaviour by explicitly adding the header
            <headers>
              <wsse:Security s:mustUnderstand="0" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
                <wsse:UsernameToken wsu:Id="SecurityToken-3f7f983f-66ce-480d-bce6-170632d33f92" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
                  <wsse:Username>bek@anchor</wsse:Username>
                  <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">dotnetrocks</wsse:Password>
                </wsse:UsernameToken>
              </wsse:Security>
            </headers>-->
          </endpoint>
        </client>

So I hope this helps somebody else. Ninja




HowTo: Consume WCF From WF4

clock December 15, 2010 20:07 by author Brian Keating |

Hi all.

I've discovered this is not as simple as it would appear to be.
Infact it's worse; in "order" to do this you will need to jump through a few hoops...; in a particular order!

 

1. Add an activity library project
2. Add a reference to this new project from your WF4 app (any app with workflows.. silverlight/mvc etc)
    ENSURE: this is done before step 3 or visual studio 2010 will give you a circular reference error!
3. In the activity library add the service reference to your webservice
4. Modify your webconfig file to contain the abc information for the connection (servicemodel stuff)
5. Now use the activities (from the toolbox)

I gather from crawling through google that the above sequence is already well defined as a workaround for the vs2010 bug.

 

 




WCF 4.0 File-less Activation (.svc less)

clock August 12, 2010 07:34 by author Brian Keating |


http://url/abc.svc  .svc at the end of url makes it user unfriendly. It also makes it Low REST service as it donot follow the REST URI principle.

Till date developers have to overcome this limitation by implementing URLReWrite module in IIS.
Writing custom code to implement this is error prone and needs maintenance over a period. WCF 4.0 has introduced
a feature to access WCF services using attribute called as relativeAddress.
Following .config setting depicts how a Calculat

orService can be accessed using relative URL.

<system.serviceModel>

    <serviceHostingEnvironment>

      <serviceActivations>

        <add relativeAddress="/Payment" service=“CalculatorService.svc"/>

      </serviceActivations>

    </serviceHostingEnvironment>

  </system.serviceModel>

 

**UPDATE

I've just tried to do this in an application I was working on, don't know where I got my origional information from but this Fileless activation was not what was advertised at the time, it requires a .svc extension on the url without the need for for a .svc physical file.

I've accomplished my restful approach with routing.

 




Sql Server Compact Edition

clock January 27, 2010 07:09 by author Brian Keating |

I've been playing with a workflow service hosted here http://www.briankeating.net/PSService/PSService.svc
Feel free to give it a bash) Endpoint is using basic http binding.

Tonight I whipped a Sql Server Compact Database out of another little app I have lying around so I could sit it behind the webservice persist data.

But

To my horror it doesn't work..

I get the following exception " sql compact is not intended for asp.net development"

 I can imagine why I guess.. bit what a pity.. it's not allowed..




Converting your VS2008 projects to support xaml designer in Expression blend 3

clock December 4, 2009 07:58 by author Brian Keating |

If you've created a new WPF project in VS2008 and then you try to design your UX in Expressino Blend 3 you'll find that you get xaml view only.

What is required is to add

<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>

 to the project file.