Nielsens Weblog : WS-Epicentre
Updated: 09-09-2009; 17:47:15.

 

Home

Subscribe to "Nielsens Weblog" in Radio UserLand.

Click to see the XML version of this web page.

Click here to send an email to the editor of this weblog.

 
 

9. september 2009

The next issue of Microsoft Archiecture Journal will contain an article published by 2 of my colleagues. The article links to a new site called Soa in 10 days.

Check it out, I'll be writing a 3 part series on how to build a publish/subscribe architecture in WCF.

Be sure to subscribe to the site for updates, full source code for the pub/sub thing and lots more on security matters is up.

 


5:47:10 PM    comment []

31. december 2008

I wish you guys a happy new year, the best of luck in 2009.

what's up in 2009 ?

  • WCF, WF, Geneva Framework and SQL2008.
  • Azure Services Platform.
  • Traveling ... London, Frankfurt, Hanoi ?
  • Vacation in Italy and Switzerland.
  • on October the 25th .. Luzern Marathon
  • YAESB on Codeplex, stay tuned

bring it on,

@llan


5:39:36 PM    comment []

9. april 2008

Just back from Vietnam yesterday, jetlag... darn tired. Next week I am taking some time off, going to London on a small vacation...so what's up in London ?

Essential Windows Workflow Foundation

what else is there to do in London ?

:-D


7:32:02 PM    comment []

23. januar 2008

The project we're working on currently is using ServiceAuthorizationManager for authorizing incoming request.

 

The current implementation is expecting the RequestMessage.Headers.Action field to contain the incoming soap action. Here is the catch, if you have a method that is decorated with IsOneWay=true, then guess what the RequestContext is null!...

 

This makes sense as one way calls is not the usual request/response pattern, but it sure did break our implementation :).

 

So a quick fix would be to look at the IncomingMessageHeaders instead like this:

 

  for (int i = 0; i < operationContext.IncomingMessageHeaders.Count; ++i)

  {

      MessageHeaderInfo h = operationContext.IncomingMessageHeaders[i];

      if (h.Name == "Action")

      {

          XmlReader xr = operationContext.IncomingMessageHeaders.GetReaderAtHeader(i);

          action = xr.ReadElementContentAsString();

 

 

BTW. Happy new year!, we spend the holidays in New York. We stayed at the Hilton Millenium on 54th floor. Amazing view, we had the governor suite (I think it was called that way). On my right side we could see the Brooklyn bridge, strait out the window we could see the Empire State Building (upper Manhattan) and on our left side we had the Statue of Liberty and of course Ground Zero.

 

Okay I don't get it, what fun is it standing on Times Square from 13.00 to 23.59 waiting for a ball drop ?!? J. Well glad I was watching this from my room instead J. We're definitely going to visit New York again.

 

Start spreading the news I'm leaving today … .


2:39:41 PM    comment []

22. september 2007

 

Say you are doing a banking SmartClient application, people finally got tired of phissing and "fat" clients is the answer here.

Now my SmartClient uses WCF (duh) as the communication infrastructure between the end user and the bank. The end user is presented with the usual login box + some extra security id RSA key she must enter.

The credentials is then stored in memory and each time I call out to my WCF proxy I pass in those credentials + the extra rsa custom token. I am holding on to the username token in memory using SecureString of course.

So here is my concern, say I am holding on to my session aware channelfactory for many reasons, performance amongst other things. Obviously I have to set the Username and Password on the channel, fine but the UserNamePasswordClientCredential class uses string to hold my identity!! WTF. Great eh, out goes the SecureString idea.

We're not talking about securing the token when it crosses the wire, that part is secured, but I am talking about the fact that my password and username is visible to prying eyes in memory, the second I set my credentials on the channelfactory.

Might not be a big deal, but why not use SecureString on the UserNamePasswordClientCredential in the first place!.

I might be missing the obvious reason as why UserNamePasswordClientCredential is designed like this, comments are welcome here.

Btw: a possible implementation of the cached identity could be written like this (given the fact that UserNamePasswordClientCredential uses System.String ;-)).

public sealed class CacheClientCredentials

{

        private static SecureString usr = new SecureString();

        private static SecureString  pwd= new SecureString();

 

        public static string UserName

        {

            get  { return SecureStringToString(usr); }

            set

            {

                char[] chars = value.ToCharArray();

                foreach (char c in chars)

                    usr.AppendChar(c);

                usr.MakeReadOnly();

            }

        }

 

        public static string Password

        {

            get { return SecureStringToString(pwd);  }

            set

            {

                    char[] chars = value.ToCharArray();

                    foreach (char c in chars)

                        pwd.AppendChar(c);

                    pwd.MakeReadOnly();

            }

        }

 

        private  static string SecureStringToString(SecureString value)

        {

            IntPtr bstr = Marshal.SecureStringToBSTR(value);

            try

            {

                return Marshal.PtrToStringBSTR(bstr);

            }

            finally

            {

                Marshal.FreeBSTR(bstr);

            }

        }

    }

The average, healthy, well-adjusted adult gets up at seven-thirty in the morning feeling just plain terrible.
    -- Jean Kerr


10:41:57 AM    comment []

19. september 2007

Sigh, it's the client proxy that throws the exception.

We have setup the usual universal error handler implementing the IErrorHandler interface, all good I figured.

The ProvideFault implementation is strait forward, if any exception occurs, wrap it up in a FaultException and return that to the client. I believed that this was it, no faulted channels on my shift and client was happy.

The problem we ran into was the implementation of the ProvideFault. The symptoms was that, when ever a SecurityAccessDeniedException was thrown, the client would catch that exception and show a localized message to the enduser, except the client never got the SecurityAccessDeniedException, it got an untyped FaultException!.

The reason why is actually obvious, if the exception thrown by the service is already an exception derived from the CommunicationException aka a FaultException, the ProvideFault should of course not wrap that fault up into yet another FaultException, it should simply just return from the ProvideFault and let the faultexception travel.

So the implementation must have the following check:

public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)

{

       if (error is FaultException)

           return;

this way the faultexception is propagated to the client proxy and then the client proxy will turn the FaultException into the SecurityAccessDeniedException and then re throw it.


My theory is that all of Scottish cuisine is based on a dare.
-- Mike Myers


4:43:54 PM    comment []

15. september 2007

Back from Vietnam. I survived the first 6 days without any stomach trouble, but then oh boy... for another 5 consecutive days I was in deep shit sort of speak. Long live Coca Cola!.

 

Okay we ran into the TimeStampHasCreationTimeInFuture, cool. Now it's not possible to extend the default bindings with the maxClockSkew setting, so you have to resort to custom bindings.

 

We are using basicHttpBinding for maximum interoperability, so creating a similar custom binding given this default binding here:

 

<basicHttpBinding>

        <binding name="basic">

          <security mode="TransportWithMessageCredential">

            <message clientCredentialType="UserName"/>

          </security>

        </binding>

      </basicHttpBinding>

 

is strait forward converting this into a custom binding like this:

 

       <customBinding>

        <binding name="basic">

          <security authenticationMode="UserNameOverTransport">

            <localClientSettings maxClockSkew="00:10:00"/>

            <localServiceSettings maxClockSkew="00:10:00"/>

          </security>

          <textMessageEncoding messageVersion="Soap11"/>

          <httpsTransport/>

        </binding>

      </customBinding>

 

First you apply the security element which enables you to set the maxClockSkew values.

 

MaxClockSkew has a default value of 5 minutes and using svcutil to generate the client config, it stays that way ;-), correct svcutil does not pick up the server side values so you would have to set them manually afterwards.

 

Next we setup the mandatory encoding element and the soap version, in our case we use text encoding and soap 1.1 for maximum interoperability with external clients.

 

We finish our custom binding with specifying the mandatory transport element, which in our case is HTTPS securing a username token.

 

Off topic:

Say you're not concerned about interoperability but instead are picking a battles with the paranoid it-guys responsible for the all the firewalls in the company. These guys tends to lock down every port but port 80, 443. <rant>They even close port 1433 behind firewalls forcing us to write "rpc" services! don't get me started. ;-)</rant>

 

In situations like that I would recommend using a custom binding also but with a binary encoding instead.

 

For example given the above bindings you could build your custom binding exactly the same way but with a binary message encoding instead.

 

       <customBinding>

        <binding name="basic">

          <security authenticationMode="UserNameOverTransport">

            <localClientSettings maxClockSkew="00:10:00"/>

            <localServiceSettings maxClockSkew="00:10:00"/>

          </security>

          <binaryMessageEncoding />

          <httpsTransport/>

        </binding>

      </customBinding>

 

Performance is optimal with the binary encoder and you keep the it-guys happy.

 

"As long as you're going to be thinking anyway, THINK BIG."


- Donald Trump

 


9:38:38 PM    comment []

13. juli 2007

 

Say you have a service which requires a UsernameToken, the client would be responsible for passing in this token. Where do you get this token from, well usually the user is prompted for her credentials. There is the standard UI dialogbox for this kind of thing here.

               

So let's try and complicate things a bit by NOT just passing in the username and password on the proxy.ClientCredentials.UserName.UserName, oh no, not this time.

Now the WCF team have provided us with this little (rarely used imo) interface called IInteractiveChannelInitializer

 

This interface helps us implement the "lets bother the user with a tedious login box" but BEFORE a channel is opened, this is the key thing to remember here and the sole motivation for this interface.

 

The documentation on this interface is rather weak and I completely missed out on the fact that I had to implement a ClientCredentialsSecurityTokenManager also, so I got some hard to understand exceptions on my first implemention.

 

Okay the basic song goes like this, create a class that derives from ClientCredentials and override the ApplyClientBehavior by adding your own class which implements the IInteractiveChannelInitializer interface… and yes override the CreateSecurityTokenManager with your own SecurityTokenManager (I messed that part up initially).

 

So a sparse implementation of the ClientCredentials would turn out this way :

 

public class ClientCredentialsEx : ClientCredentials

{

    public ClientCredentialsEx(): base() {}

    public ClientCredentialsEx(ClientCredentialsEx other): base(other){}

    public override SecurityTokenManager CreateSecurityTokenManager()

    {

        return new MyClientCredentialsSecurityTokenManager(this);

    }

 

public override void ApplyClientBehavior(ServiceEndpoint serviceEndpoint, ClientRuntime behavior)

    {

            behavior.InteractiveChannelInitializers.Add(new ShowCredentialsUI());

            base.ApplyClientBehavior(serviceEndpoint, behavior);   

    }

    protected override ClientCredentials CloneCore()

    {

        return new ClientCredentialsEx(this);

    }

}

 

 

And then your implementation of the IInteractiveChannelInitializer

Would look something like this, note I didn't go all the way with the standard CreUIPromptForCredentials dialogbox, google it.

 

public class ShowCredentialsUI : IInteractiveChannelInitializer

{

    public IAsyncResult BeginDisplayInitializationUI(IClientChannel channel,

AsyncCallback callback, object state)

    {

        //call the CredUIPromptForCredentials and get back a user and password.

        ChannelParameterCollection col = channel.GetProperty<ChannelParameterCollection>();

col.Add(new System.Net.NetworkCredential(username, password));       

return new AsyncResult();

    }

 

    public void EndDisplayInitializationUI(IAsyncResult result)

    {

        AsyncResult ar = (AsyncResult)result;

        ar.isCompleted = true;

    }

}


 

 

Now a very sparse implemention of the IAsyncResult, I blogged about this long time ago.

 

public class AsyncResult : IAsyncResult

{

    public bool isCompleted = false;

 

    public object AsyncState

    {

        get { throw new Exception("The method or operation is not implemented."); }

    }

 

    public System.Threading.WaitHandle AsyncWaitHandle

    {

        get { throw new Exception("The method or operation is not implemented."); }

    }

 

    public bool CompletedSynchronously{get{return true;}}

 

    public bool IsCompleted { get { return isCompleted; }

    }

}

 

 

Now for the implementation of the custom ClientCredentialsSecurityTokenManager.

The crux of this is you would dig out the NetworkCredential from the ChannelParameterCollection which was set by the BeginDisplayInitializationUI.

 

class MyClientCredentialsSecurityTokenManager : ClientCredentialsSecurityTokenManager

{

    public MyClientCredentialsSecurityTokenManager(ClientCredentials parent): base(parent){}

   

    public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)

    {

        if (tokenRequirement.KeyUsage == SecurityKeyUsage.Signature)

        {

            NetworkCredential token = null;

            ChannelParameterCollection obj = (ChannelParameterCollection)tokenRequirement.Properties[ServiceModelSecurityTokenRequirement.ChannelParametersCollectionProperty];

            token = obj[0] as NetworkCredential;

            if (tokenRequirement.TokenType == SecurityTokenTypes.UserName)

            {

                return new MyUsernameSecurityTokenProvider(token);

            }

        }

        return base.CreateSecurityTokenProvider(tokenRequirement);

    }

 

My custom SecurityTokenProvider which just creates the UserNameSecurityToken for the channel to use.

 

    class MyUsernameSecurityTokenProvider : SecurityTokenProvider

    {

        NetworkCredential cre = null;

        public MyUsernameSecurityTokenProvider(NetworkCredential credentials)

        {

            this.cre = credentials;

        }

        protected override SecurityToken GetTokenCore(TimeSpan timeout)

        {

            UserNameSecurityToken token = new UserNameSecurityToken(cre.UserName,cre.Password);

            return token;

        }

    }

 

Now that was easy, all we need todo now is to hook up our new behavior on the proxy. This can be done in many ways, I choose to override the ClientBase which then would add our new "lets bother the user with a tedious login box". This is a matter of replacing the standard ClientCredentials class on the proxy behaviour, with our own IEndpointBehavior implemented by our custom ClientCredentialsEx class like this:

 

public partial class PartnerSubscriptionProxy : ClientBase<IPartnerSubscriptionService>, IPartnerSubscriptionService

{

        public PartnerSubscriptionProxy(string address)

        {

            Endpoint.Address = new EndpointAddress(address);

            Endpoint.Behaviors.Remove< ClientCredentials >();

            Endpoint.Behaviors.Add(new ClientCredentialsEx());

        }

......

 

Right so all you have to do now is just invoke the proxy and call out to a method, this will invoke our ui box before the channel is opened giving the user a chance to think real hard about her credentials (which btw. always can be found on that yellow slip on your desk).

"Some cause happiness wherever they go; others, whenever they go."
 --Oscar Wilde


8:45:57 PM    comment []

2. april 2007

I think Microsoft did a great job with WCF, totally in love with this framework.

 

For years I have been using an xsd editor when designing my asmx messages, this is no different when choosing WCF as your favorite communication framework.

 

My frustration is when you design your xsd's and set the max occurs to unbounded on any simple type or complex type, the code generated by the svcutil sucks big time.

 

Take for instance this xsd:

 

<?xml version="1.0" encoding="utf-16"?>

<xs:schema xmlns:b="http://schemas.microsoft.com/BizTalk/2003" xmlns="http://datacontract/2007/03/OrderMessage" elementFormDefault="qualified" targetNamespace="http://datacontract/2007/03/OrderMessage" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="OrderMessage" nillable="true" type="OrderMessage" />

  <xs:complexType name="OrderMessage">

    <xs:sequence>

      <xs:element minOccurs="1" maxOccurs="unbounded" name="Items" nillable="true" type="LineItems" />

    </xs:sequence>

  </xs:complexType>

  <xs:element name="LineItems" nillable="true" type="LineItems" />

  <xs:complexType name="LineItems">

    <xs:sequence minOccurs="1" maxOccurs="1">

      <xs:element name="total" type="xs:decimal" />

      <xs:element name="description" type="xs:string" />

    </xs:sequence>

  </xs:complexType>

  <xs:element name="OrderMessageReply" type="OrderMessageReply" />

  <xs:complexType name="OrderMessageReply">

    <xs:sequence>

      <xs:element name="Confirmed" type="xs:boolean" />

    </xs:sequence>

  </xs:complexType>

</xs:schema>

 

When generating code using svcutil.exe /dconly schema1.xsd it produces this code here:

 

Garbage omitted here for clarity J

 

public class OrderMessage : List<LineItems>

{

}

   

public partial class LineItems : object, IExtensibleDataObject

{

 

WTF, this is clearly not what I wanted, give me this structure here !!:

          

public class OrderMessage : object, IExtensibleDataObject

{

      public List<LineItems> LineItems;

}

 

What can you about this ?.

 

Apparently there is this ArrayOfxxxx convention, a convention first seen in the wsdl 1.1 specification, later abandond by the WS-BP and then gladly introduced again in the svcutil.exe, oh joy, what a great interoperability message the world here got from the WCF team J.

 

You can overcome this by introducing in your xsd's a complex type called ArrayOfLineItems and then create an element of type LineItems and then you would set the max occurs to unbounded. In your OrderMessage you would then create an element of type ArrayOfLineItems.

 

Great eh!!, this sure will put an extra burden on how you would organize your xsd's in the future.

 

This is not just about your custom complex types, oh no this goes for all the simple types also!!, so putting max occurs > 1 on a simple string type would mean you would have to create an ArrayOfstring.

 

That simply sucks, agree.

 

Your only option is to go with xsd.exe. That equally messed up code generator which has no support for System.Collections.Generic.List and friends, no support for Guids, Uri and the like.

 

Say you can live with xsd.exe!!!, you would then use the [XmlSerializerFormat]

which you can use on the interface, operation and on a class also.

 

[XmlSerializerFormat]

[ServiceContract(Namespace = "http://testservice/2007/03/service")]

public interface IService

{

       [OperationContract]

       OrderMessageReply CreateOrder(OrderMessage message);

}

 

This will instruct the serializer to use the xmlserializer instead of the datacontractserializer when performing marshalling of your messages.

 

I just hate this, I take a 10% performance loss when using the XmlSerializer and the fact that I am still stuck with xsd.exe is just bad karma.

 

What are the BTS team doing about this. BTS R2 will have support for WCF, are you telling me these guys will gladly accept this crap code from svcutil ???, I think not, so I take some comfort in believing that this will be corrected this year and the person who introduced this tedious nameing convention in svcutil.exe is promoted to VB 6.0 program manager in Sibiria.

 

"The most difficult thing in the world is to know how to do a thing and to

watch someone else do it wrong, without comment."

   --Theodore H. White

 


10:41:54 PM    comment []

17. marts 2007

Yesterday I blogged about WCF routing. The one thing that might have seemed counterintuitive was that the function ProcessMessage created a channel based on the router service contract and then used the operation ProcessMessage  to send messages to the final endpoint.

Could you not have used one of the built in channel shapes ?. Yes by all means J, that would be the IDuplexSessionChannel. This shape is used for sending and receiving messages using a duplex session aware communication pattern. With a sessionful channel, messages that are sent in a session are delivered in order. WCF does not allow any credentials to be sent in clear text and as we have configured our backend to authenticationMode="UserNameOverTransport" the IDuplexSessionChannel will perform some bootstrapping calls to exchange a secure symmetric security token, which obey the WS-Trust and WS-SecureConversation specification (RST,RSTR,SCT).

The code is pretty strait forward and it looks a bit more generic than the previous code. From a performance point of view I have found this code to perform slightly better, but there is more code and I have not included any checks in regards to OneWay calls.

public Message ProcessMessage(Message message)

        {

            Message replyMsg = null;

            switch (message.Headers.To.AbsoluteUri)

            {

                case "urn:MyServer":

                    ClientCredentials credentials = new ClientCredentials();

                    credentials.UserName.UserName =

         ServiceSecurityContext.Current.PrimaryIdentity.Name;

 

                    Binding b = CreateCustomBinding();

 

BindingParameterCollection bpc = new BindingParameterCollection();

                    bpc.Add(credentials);

 

IChannelFactory<IDuplexSessionChannel> fac = b.BuildChannelFactory<IDuplexSessionChannel>(bpc);

                    fac.Open();

 

                    IDuplexSessionChannel channel = fac.CreateChannel(epa);

                    channel.Open();

                    //save message id for correlation

                    object msgID = message.Headers.MessageId;

 

Message strippedMsg = Message.CreateMessage(MessageVersion.Default,

message.Headers.Action, message.GetReaderAtBodyContents());

                    //add message id.

                    strippedMsg.Headers.MessageId = (System.Xml.UniqueId)msgID;

                    channel.Send(strippedMsg);

                    Message msg = channel.Receive();

                    replyMsg = Message.CreateMessage(MessageVersion.Default,

msg.Headers.Action, msg.GetReaderAtBodyContents());

                    //stuff the messageid back in the reply message

                    replyMsg.Headers.MessageId = (System.Xml.UniqueId)msgID;

                    channel.Close();

                    fac.Close();

                    break;

            }

            return replyMsg;

        }

"The beginning of knowledge is the discovery of something we do not understand."
- Frank Herbert

 


6:14:57 PM    comment []

16. marts 2007

 

I have a scenario where I would like to be able to shield a large number of clients against redeployment and relocation of a large number of services.

I also have the requirement that services must do authentication and authorization based on the identity and role.

 

A solution to this would be to put a router which does the authentication and route messages to the correct service on the backend. The service can then do its own authorization based on role(s) the identity belongs to.

 

The assumption here is that clients supports the WS-* specifications (ws-security, ws-secureconvertion), in other words the client would have .NET 3.0 installed and can support the wsHttpBinding.

 

The router will be put in a DMZ, each service at the backend trusts the router and that the router did the authentication for them.

 

The authentication is done with the MemberShipProvider, which means the router is configured to use the MemberShipProvider :

<serviceCredentials>

    <userNameAuthentication userNamePasswordValidationMode="MembershipProvider" membershipProviderName="SqlMembershipProvider"/>

 

The binding for the router uses message authentication and is configured as such:

 

<bindings>

      <wsHttpBinding>

        <binding name="secure">

          <security mode="Message">

            <message clientCredentialType="UserName"/>

          </security>

        </binding>

      </wsHttpBinding>

    </bindings>

 

The client must present a user/password which is valid in the context of the MemberShipProvider, so we are not using the Windows account to authenticate the client here, although its possible and perfectly valid, but the idea of maintaining > 100.000 users is not in our scope here, ask Amazon.

 

Each backend service is configured with this custom binding here:

 

<customBinding>

    <binding name="aBackendService">

       <security authenticationMode="UserNameOverTransport"/>

       <windowsStreamSecurity/>

       <tcpTransport/>

    </binding>

</customBinding>

 

This means the router must create this custom binding when contacting the backend services. Creating this kind of custom binding is easy:

 

public static Binding CreateCustomBinding()

{

BindingElementCollection bindingElements = new BindingElementCollection();

bindingElements.Add(SecurityBindingElement.CreateUserNameOverTransportBindingElement());

WindowsStreamSecurityBindingElement wbe = new WindowsStreamSecurityBindingElement();

wbe.ProtectionLevel =   System.Net.Security.ProtectionLevel.EncryptAndSign;

bindingElements.Add(wbe);

bindingElements.Add(new TcpTransportBindingElement());

CustomBinding backendServiceBinding = new  CustomBinding(bindingElements);

 return backendServiceBinding;

}

 

Now the authenticationMode="UserNameOverTransport" takes care of flowing the identity of the caller and the <tcpTransport/> and <windowsStreamSecurity/>

handles the authentication of the router and does message protection, here EncryptAndSign is the default.

 

Each backend service does the authorization with a custom ServiceAuthorizationManager and is configured like this:

          <!-- Configure role based authorization to use the Role Provider -->

          <serviceAuthorization principalPermissionMode="UseAspNetRoles" roleProviderName="SqlRoleProvider" serviceAuthorizationManagerType="ServiceAuthMgr.MyServiceAuthorizationManager, ServiceAuthMgr">


  

The default authentication mode on the backend service is Windows, so this means the identity will be mapped to a Windows account. This will not work here as our router have already authenticated the identity using the MemberShipProvider, so we need to "disable" this default behaviour by configuring our own UserNamePasswordValidator which in our case does nothing!

<serviceCredentials>

    <userNameAuthentication userNamePasswordValidationMode="Custom"

customUserNamePasswordValidatorType="aService.MyUserNamePasswordValidator, aServiceHost"/>

 

 

okay we are all set now and we start by defining the routers service contract

 

[ServiceContract()]

public interface IRouter

{

   [OperationContract(Action="*",ReplyAction="*")]

   Message ProcessMessage(Message message);

}

This operation contract has the notation of what is called an unmatched message handler. The basic idea is that each EndpointDispatcher signals the ChannelDispatcher that it can handle any messages. This is indicated by applying a behaviour with the AddressFilterMode set to Any as show here.

 

[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any,  ValidateMustUnderstand = false)]

public class RouterImpl : IRouter

{

By default the EndpointDispatcher will try to invoke methods that corresponds to the Actions on a service contract, which when exported to wsdl is seen as the SOAPAction.

Each EndpointDispatcher maintains a collection of actions that can be invoked and in our case we indicate that we can handle any action and any ReplyAction, so the ChannelDispatcher will go ahead and send us the message.

Lets look at the ProcessMessage implementation, which is the core piece of code that makes the routing works.

public Message ProcessMessage(Message message)

{

            Message replyMsg = null;

            switch (message.Headers.To.AbsoluteUri)

            {

                case "urn:MyServer":

                    #endregion

                    //lookup urn:MyServer in cache/database and get the epa.

                    //epa = new EndpointAddress(new Uri("http://......"))

  ´        ChannelFactory<IRouter> dest = new ChannelFactory<IRouter>(custBinding, epa);

dest.Credentials.UserName.UserName = ServiceSecurityContext.Current.PrimaryIdentity.Name;

Message strippedMsg = Message.CreateMessage(MessageVersion.Default, message.Headers.Action, message.GetReaderAtBodyContents());

                    IRouter router = dest.CreateChannel(epa);

                    Message msg = router.ProcessMessage(strippedMsg);

replyMsg = Message.CreateMessage(MessageVersion.Default, msg.Headers.Action, msg.GetReaderAtBodyContents());

                      dest.Close();

                   

                    break;

          

              

            }

            return replyMsg;

        }

}

The first thing that might seem strange is I create a ChannelFactory of IRouter which takes the custom binding and the endpoint of the located backend service.

Then I pass in the Identity of the client which can be found in the ServiceSecurityContext.Current.PrimaryIdentity.Name. I then take the body of the message and creates a new message, then create the channel and sends the message using my own ProcessMessage operation!, then I strip the headers off the reply message and creates a new message with the body and return that message to the caller.

Okay what I do here is I contact the backend service using the correct EndpointAddress (which was found using the logical uri of the client) and when using the ProcessMessage to send the incoming message, the ChannelDispacther on the backend service will see if the EndpointDispatcher can handle the message given the SOAPAction that can be found in the messages. The backend service will perform its work, just as if it was invoked directly by the client using the direct operation contract.

The reason why I strip off the headers on the request/reply message is due to the fact that we are not using the same binding and I can not simply piggyback the message on the a new call to the backend service. This will produce duplicate and wrong headers according the WS-*, so cutting off the headers will produce a correct message according the our backend service binding. The reply message will be correct also when it returns to the client, WCF will add what ever headers there must be, according to the WS-*.

Now to the client side:

A client will prior to all this have either been handed a service contract or would have generated a proxy to the backend service. If we have generated a proxy given the backend mex, the client side configuration would look like this:


 

<endpoint address="urn:MyServer"

                      behaviorConfiguration="ClientBehavior"

                      binding="wsHttpBinding"

                      bindingConfiguration="WSHttpBinding_IaService"

                      contract="WebUIClient.localhost.IaService"

                      name="WSHttpBinding_IaService" >

       

<bindings>

            <wsHttpBinding>

                <binding name="WSHttpBinding_IaService">

                    <security mode="Message">

                        <message clientCredentialType="UserName" />

                    </security>

                </binding>

            </wsHttpBinding>

        </bindings>

 

Notice the address which points to a logical address!. This is the logical Uri that is passed in from the client and this is the uri that the router will eventually use to fetch the real EndpointAddress (from some storage) of the backend service. This uri is configured by hand.

Okay so when the client contacts our backend service is creates an EndPointAddress that points to our router location:

 

Uri via = new Uri("http://localhost:8080/Router");

 

Then the client creates the logical endpoint like this:

 

EndpointAddress endptadr = new EndpointAddress(new Uri("urn:MyServer"));

 

It then creates a channel, passing in the logical endpoint and the Via uri is then set to our router.

 

So go contact this logical endpoint Via the routers endpoint, is what is says here.

 

ChannelFactory<IaService> factory = new ChannelFactory<IaService>("WSHttpBinding_IaService");

 

We pass in our credentials according to the binding.

 

factory.Credentials.UserName.UserName = "Alice";

factory.Credentials.UserName.Password = "abc!123";

 

we then create the channel

 

IaService client = factory.CreateChannel(endptadr, via);

 

and invoke an operation.

           

OrderMessage msg = new OrderMessage();

OrderMessageReply res = client.CreateOrder(msg);

 

The backend service will receive this request via the router but with the initial Identity, which the backend can perform authorization on. In my case I am building up some other claims by implementing the IAuthorizationPolicy and then have the ServiceAuthorizationManager perform the GO no GO based on the built claims and roles.

Source code available upon request.

"If I had more time, I would have written a shorter letter."

-- Pascal.


12:22:38 PM    comment []

15. marts 2007

Well it's been a busy year 2006, you can say that. Last year was a great year, I was doing web service intermediate stuff in Brussels, security with the usual gang in London, well deserved vacation in Orlando, Fl wow and before you know it 2006 flipped and 2007 started with a bang.
Year 2007 is only 3 month old now and I brushed up my WCF in London before going to Hanoi on a business trip. Hanoi was amazing and I am looking forward to visiting Hanoi again in May. The Project that I am working on in Vietnam is of course "none of your business" :), but my job is to teach WCF to a very very skilled team in Hanoi (guys you are the best, hang in there).

"Let's face it, .NET is meant to rule the world. :)  With that out of the way let's get onto business."

 


3:31:31 PM    comment []

7. juni 2006

Last week I was in London enjoying Dominick Baier's .NET 2.0 Security course. It was really an eye-opener.

Dominick is a very passionate, paranoid Developmentor instructor, so if you ever get the chance ....

Btw pickup a hardcopy around November.

Security is not just something you apply at the end of a project, you need to design and plan for security. You need to get into that mindset at the very beginning of every software project.

Security was never of great concerns on all the projects i have been involved with...it was just something you brute forced into your software at the very last minute, guarantied to break your design.

I am currently working on a project now that does just about everything wrong when it comes to security, currently it's out of my hands (blame it on politics, ignorance and deadlines). It's frustrating to watch this, but I guess reality bites the project soon, so bring your rain coat and fire hose ;-).

If you need to model and analyze threats, Microsoft actually made a descent job with this tool here.

Currently reading "Secrets and Lies".

"If you know the enemy and know yourself, you need not fear the result of a hundred battles."

-- Sun Tzu The Art of War


8:37:11 AM    comment []

26. marts 2006

Yes, If you have the time and space it's possible in theory.


2:16:19 PM    comment []

23. marts 2006

Apparently in .NET 2.0 the impersonation token is propagated across threads, this was not the case in 1.1.

In .NET 2.0 you can perform the following code in a simple console app:

class GoWithTheFlow
{
 public static void IdentityMatters(object state)
 {
  Console.WriteLine("Thread Identity " +WindowsIdentity.GetCurrent().Name);
 }
  
 static void Main()
 {
  Console.WriteLine("User before impersonation : " + WindowsIdentity.GetCurrent().Name);
  ImpersonateUser x = new ImpersonateUser();
  x.Impersonate();
  Console.WriteLine("In Main, my identity : " + WindowsIdentity.GetCurrent().Name);
  ThreadPool.QueueUserWorkItem(new WaitCallback(IdentityMatters), 42);
  Thread.Sleep(1000);
  Console.WriteLine("back In Main, my identity: " +WindowsIdentity.GetCurrent().Name);
  x.Undo();
  Console.WriteLine("After undo In Main, my identity: " +WindowsIdentity.GetCurrent().Name);
  Console.Read();
 }
}

Assuming the ImpersonateUser will do the usual LogonUser thing, in my case with the account Kill Bill on server NEO. The output is show here:

User before impersonation : NEO\Allan
In Main, my identity : NEO\Kill Bill
Thread Identity : NEO\Kill Bill <--good stuff
back In Main, my identity: NEO\Kill Bill
After undo In Main, my identity: NEO\Allan

As you can see the impersonation token it actually propagated across the thread. In .NET 1.1 the output would be

User before impersonation : NEO\Allan
In Main, my identity : NEO\Kill Bill
Thread Identity : NEO\Allan <--bad thing
back In Main, my identity: NEO\Kill Bill
After undo In Main, my identity: NEO\Allan

This is of course great news, but here is my observation in regards to trying to achieve the same thing in a webservice. To quickly test this, create an asmx endpoint with the following code in it:

[WebService(Namespace = "http://identityflow.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Service : System.Web.Services.WebService
{
    public Service (){}
    static AutoResetEvent are;
    static bool complete = false;
    [WebMethod]
    public string IdentityMatters()
    {
        this.Context.Trace.Write("Current Identity before thread : " + WindowsIdentity.GetCurrent().Name);
        are = new AutoResetEvent(false);
       ThreadPool.QueueUserWorkItem(new WaitCallback(YourIdentityPlease), this);
        if (!complete)
            are.WaitOne();
        this.Context.Trace.Write("back in business, Identity:  " + WindowsIdentity.GetCurrent().Name);
        return "done";
    }
    public static void YourIdentityPlease(object state)
    {
        Service s = (Service)state;
        s.Context.Trace.Write("thread Identity: " + WindowsIdentity.GetCurrent().Name);
        complete = true;
        are.Set();
    }
}

In your web.config turn on the <identity impersonate="true"/>

Under IIS, turn off the 'Anonymous access' and check the 'Integrated Windows authentication'.

when you activate the endpoint, the output in tracelog shows this :

: Current Identity before thread : NEO\Allan
: thread Identity : NEO\ASPNET <-- did not expect this
: back in business, Identity:  NEO\Allan

Hmm ... the impersonation token is NOT propagated !!!

"Never send a human to do a machine's job"
 -- Agent Smith.

[update]

thanks for sharing this.

apparently this behaviour is for legacy reasons. You need to modify the aspnet.config file located in your runtime directory \WINDOWS\Microsoft.NET\Framework\v2.0.50727

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <runtime>
        <legacyUnhandledExceptionPolicy enabled="false" />
        <legacyImpersonationPolicy enabled="true"/>
        <alwaysFlowImpersonationPolicy enabled="true"/>
        <SymbolReadingPolicy enabled="1" />
    </runtime>
</configuration>

some documentation on this can be found here

sticking this information in the config file doesn't help, inetinfo's job is to locate the endpoint and then load the correct isapi, and as usual it's aspnet_isapi.dll and that isapi extention needs this information before the AppDomain is created in the aspnet_wp.exe.

"The greatest mistake a man can make is to be afraid of making one."
  --Elbert Hubbard


11:47:40 AM    comment []

8. december 2005

Have you ever found your self wandering sleepless around in this directory here :

"C:Program FilesCommon FilesMicrosoft SharedHelp 8" and stumbled over this assembly here:
Microsoft.WizardFramework.dll

Yeah right that's the .Net 2.0 Wizard framework, its not documented yet, so Reflector.exe is your best option here (as usual).

Here is how I got a descent Wizard to work:
Create an 'inherited Form' that derives from the WizardForm like this:

 public partial class WizardFrm : Microsoft.WizardFramework.WizardForm
 {
 .....
 
Create some wizard pages, this is best done by creating an 'Inherited User Control' which derives from WizardPage like this:

public partial class Page1 : Microsoft.WizardFramework.WizardPage
{
        public Page1(WizardForm wizard):base(wizard)
        {
            InitializeComponent();
        }
.....

Now in the WizardFrm's ctor add your WizardPages like this:

public WizardFrm()
{
      InitializeComponent();
      p1 = new Page1(this);
      this.AddPage(p1);
      p2 = new Page2(this);
      this.AddPage(p2);
      p3 = new Page3(this);
      this.AddPage(p3);
}
´
private void WizardFrm_Load(object sender, EventArgs e)
{
      EnableButton(ButtonType.Next, true);
}


Invoke your wizard from in your app like this :

WizardFrm frm = new WizardFrm();
frm.Start();

Now when you design the individual WizardPages set the 'infoPanel.Dock' to Fill, this will let you add your controls to the wizard page. Set the WizardPage.StepTitle to a description that this WizardPage represents.

I was not able to find any Events like OnNext, OnPrev etc. This makes it hard to validate a WizardPage there by defeating the whole purpose of a Wizard...I am sure that deep down in the WizardForm or in the 'NavigationButtonBar' its possible to catch these events ...I didn't proceed that far for now.

I wonder why this WizardFramework isn't documented, I sure do hope they make it official ...I have been missing that Wizard since the good old MFC days.

contact me if you need the sourcecode.

"One of the secrets of life is to make stepping stones out of stumbling blocks"
-- Jack Penn


 


2:25:32 PM    comment []

19. november 2005

If you experience a Win32Exception during the WinFX Runtime Components installation, make sure your eventlog isn't full :), I was bouncing the walls for a good 15 minutes there.

To see what the installer tries to-do, run the "xws_reg.exe -ir" commandline tool, this will spit out a warning, that your eventlog is full, followed by the exception ... Now if only the warning was shown during the installation!!

 


9:21:48 AM    comment []

22. oktober 2005

I have been extremely busy on a client site recently.  One of the challenges was a class design that supported asynchronous operations.

I soon found out that utilizing the asynchronous functionality built into delegates produced poor performance. This is due to the overhead of the remoting infrastructure that delegates so beautifully supports, so ThreadPool.QueueUserWorkItem was favored here.

I needed some boilerplate code for the basic of this Async Pattern so implementing the IAsyncResult interface is the key to creating a successfully class design supporting asynchronous operations.

My basic implementation goes like this:

public class AsyncResult : IAsyncResult
{
         private object state;
         internal bool complete = false;
         internal AutoResetEvent are;
         internal AsyncCallback callback;
         internal AsyncResult(AsyncCallback callback, object state)
         {
                this.callback = callback;
                this.state = state;
                this.are = new AutoResetEvent(false);
         }     
         public virtual object AsyncState
         {
              get { return state; }
              set { state=value;}
         }
         public bool IsCompleted { get {return complete; }}
         public WaitHandle AsyncWaitHandle {get {return are; }}
         public bool CompletedSynchronously {get {return false; }}
}

pretty strait forward, now lets see how we can utilize this implementation in class design with asynchronous support.

public class FibonacciEx
{
         private static void Fibonacci(object data)
         {
                AsyncResult m = (AsyncResult)data;
                int n = (i nt)m.AsyncState;
                int previous = -1;
                int result = 1;
                for (int i = 0; i <= n; ++i)
                {
                     int sum = result + previous;
                     previous = result;
                     result = sum;
                }
                 m.AsyncState = result;
                 m.complete = true;
                 m.are.Set();
           }
  

           public IAsyncResult BeginFib(AsyncCallback callback, object state)
           {
                   AsyncResult ar = new AsyncResult(callback, state);
                   ThreadPool.QueueUserWorkItem(new WaitCallback(Fibonacci), ar);
                   return ar;
            }

           public int EndFib(IAsyncResult ar)
           {
                    AsyncResult reqState = (AsyncResult)ar;
                   //are we done
                   if (!reqState.IsCompleted)
                         reqState.AsyncWaitHandle.WaitOne();
                   //invoke our callback function
                  if(reqState.callback!=null)
                     reqState.callback(reqState);
                  //in this class design we return the result also.
                  return (int)reqState.AsyncState;
           }
  
}

 and the usage of this simpel class could be like this:

class AsyncSample
{
 /// <summary>
 /// The main entry point for the application.
 /// </summary>
 [STAThread]
 static void Main(string[] args)
 {
           int seq1=0;
           int seq2=0;
           float goldenRatio = 0;
           FibonacciEx fib = new FibonacciEx();

          AsyncCallback ac = new AsyncCallback(FibResult);
          IAsyncResult res = fib.BeginFib(ac, 9);
          //
          //do some other important stuff
          //
  
          seq1 = fib.EndFib(res);
  
          ac = new AsyncCallback(FibResult);
          res = fib.BeginFib(ac, 10);
          //
          //do some other important stuff
          //
          seq2 = fib.EndFib(res);

         //calculate the golden ratio, the phi, the magic number.
         goldenRatio = (float)seq2/seq1;

         Console.WriteLine("Magic number: " + goldenRatio.ToString());
         Console.ReadLine();
 }
  
       public static void FibResult(IAsyncResult ar)
       {
            Console.WriteLine(ar.AsyncState.ToString());
       }
}

use the AsyncResult boilerplate for your furture class design if you must support the Async Pattern.


1:44:26 PM    comment []

20. oktober 2005

100% sure thing, there is a bug in the Graphics.DrawImage function.
Complete disrespect for the ImageAttributes I say :).

I am trying to print a Tiff that supports multi-page documents. This is done by using the
Image.SelectActiveFrame function and Graphics.DrawImage.


SelectActiveFrame selects the current page(or other stuff) into the image and passed on to the DrawImage function.
The DrawImage function should then print what ever image was selected by the SelectActiveFrame..but it doesn't, it simply ignores the imageattributes on the selected image and spits out the very first frame.

the code shown here always prints the first page in the multi-page document,
but it should actually print all pages in the Tiff file.

private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{

    bm.SelectActiveFrame(FrameDimension.Page, curPage);  //select current page..
    e.Graphics.DrawImage((Image)bm,0,0); // this always draws the first frame !!!
......

}


this code shown here works, but it is tremendously slow, totally useless if you ask me...

private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
    ...
    bm.SelectActiveFrame(FrameDimension.Page, curPage); 
    Bitmap tmpBmp = new Bitmap(bm.Width,  bm.Height,System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
    using(Graphics g = Graphics.FromImage(tmpBmp)) 
    {
       g.DrawImage((Image)bm,0,0);//render image.. dog slow zzzzzzzzzzzz.
    }
    e.Graphics.DrawImage((Image)tmpBmp,0,0);
    ...
}

so what I came up with and it turns out to be extremly fast, is to save the frame that was selected by
the SelectActiveFrame into a MemoryStream, call FromStream and then draw it:

private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
 ....
 Image img = Image.FromStream(ms); //ms is a memstream pointing to a tiff picture.
 img.SelectActiveFrame(FrameDimension.Page, curPage);
 using(MemoryStream stm = new MemoryStream())
 {     
  img.Save(stm, imgCodecInfo, encParams); //save to memory stream with Lempel-Ziv-Welch etc.
  Bitmap bmp = (Bitmap)Image.FromStream(stm);
  e.Graphics.DrawImage((Image)bmp,0,0);
  bmp.Dispose();
 }
 img.Dispose();}
....
}

Apparently creating a new image with Image.FromStream makes the DrawImage happy.

"A true friend stabs you in the front."
- Oscar Wilde


1:58:23 PM    comment []

28. august 2005

Guess who got floor tickets to the U2 concert at the MGM Grand, Saturday the 5th of November in Las Vegas.
yup, my wife and I are taking a quick trip, we'll be flying from Copenhagen to the "City of blinding lights" on Friday
the 4th of November staying at the Hilton, jumping up and down on Saturday and then back home on Sunday.

"Unos dos tres catorce"


2:43:41 PM    comment []

15. maj 2005

I think BTS 2004 is a confusing, frustrating, tedious, wonderful, huge, exciting and never ending story.
...so where do you put your business logic in BTS, some might say use the Business Rule Framework, others say call an external .NET assembly and put your business logic in there, others would see it put now where but in an orchestration, others again would place some logic in custom functoids and some might argue strongly that there business logic should reside in a custom pipeline, hell why not in a custom adapter while we are at it.


It can be pretty confusing making these decisions on where to put your business logic and validation in BTS...its not like when we eat sleep and s... the DNA (Doesn't Mean Anything) model back in the late 90', that was pretty strait forward compared to Biztalk.


I think the Biztalk model unfortunately invites you to put your business logic all over the place and then sometimes forces you to put it in a certain place...take for instance the scenario where you receive a schema from a third party, they want to make sure you obey certain rules, so they have made a schema with a pattern value for you. Now unfortunate for you, if you base your messages on this schema because the pattern is lost when you compile your BTS solution....for some reason the BTS team thought it was not necessary to crank up some code that utilized the Regex class when dealing with schemas that had the pattern value in it....so you must go an create a custom pipeline and do the schema validation there instead, while this might as well could have been built into say the Microsoft.XLANGs.BaseTypes.SchemaBase class.


btw I think it is tremendously traumatic that the Business Rules Composer doesn't include the namespace in the Document type when adding a schema :(, you are looking at some frustrating debugging hours if you are not aware of this....

Rorschach abstraction; no two people think they mean quite the same thing


10:11:26 PM    comment []

© Copyright 2009 Allan Nielsen.



Click here to visit the Radio UserLand website.
 


September 2009
Sun Mon Tue Wed Thu Fri Sat
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30      
Dec   Oct