Category: WCF

11/29/08

Permalink 03:38:49 pm, Categories: Architecture, WCF

In the making of TimeTracker, we got to this point where one has to authenticate against the web server. Easy, you put a service behind https, with a method that takes a username and password, and returns something that says if yes or no the authentication negotiation has been successful.

In a normal process, back on the client, you would then create a Principal and put it on the AppDomain so that it's shared amongst all threads. However, you have those two choices: either you wait until the authentication to create your Principal, meaning that no principal is available between application start and authentication negotiation, or you simply replace the Principal object with a new "authenticated" one, with correct roles. Neither of those solutions were satisfying to me. For the first case, I believe that a correctly built application should always have a well-known principal object to put on the current thread, that principal being anonymous until authentication. For the second case, well, I dislike the idea of replacing altogether the object with a new, promoted one. I mean, the principal represents the user that started and runs the application. At time t, that user is anonymous, and at time t+1, it's now authenticated. It's not a new user, it's just the same user with new roles after successful authentication.

So I decided to create the class SecurePrincipal with the method Promote on it. That method takes an array of roles and add those roles to the current principal. I also created a service, called CredentialsService, that puts a new, anonymous principal in the AppDomain when it starts. The service is also responsible for negotiating authentication with a username and password taken from the user. To that end, and since the service is unable to ask for credentials to the client, it declares an ExtensionPort where modules can be plugged. When asked to EnsureUserIsAuthenticated, the services loops through the extenders plugged into its extension port, and asks them to NegociateAuthentication, passing the current (anonymous) SecurePrincipal object. Note that the extenders could have taken it from the current thread, since a module always runs in the application's AppDomain. The extender is responsible to get a username and password, usually by popping a window at the user, and to negotiate authentication, usually by calling a service that runs on the server. The first extender that successfully negotiates authentication wins, and the service stops looping. Latter, if EnsureUserIsAuthenticated is called again, the service simply returns (no window will be popped up, since to Extender will be called).

As you know, a Principal as an associated Identity object. For the same reasons, I created a SecureIdentity, and put a Promote method on it. The Identity holds the username and the authentication method and determines if the user is authenticated. To that end, I copied the behavior of GenericIdentity, which checks if the username is empty; if not then the user is considered authenticated. The Promote method takes a username and authentication method so that the user can go from anonymous (unauthenticated) to authenticated.

Since talking to a server generally means to exchange authentication tokens to prove one's identity on each call, and since one of the easiest ways to do that is to include the user's password on each request following authentication, I decided to add the Password property to SecureIdentity. That password, of course, is a SecureString, managed by the Window's kernel. Logically, Promote also takes that password for user's promotion. One can then get the current user's password from System.Threading.Thread.CurrentPrincipal.Identity, given that the authentication has successfully been negotiated.

With WCF and Message Credentials security (the preferred way to communicate over the Internet, according to Juval Lowy), you have to pass username and password with every request. Since Foundation uses an Object Container to abstract services, I don't want the consumer of a WCF service whose proxy is put into the Object Container to have to know that this service implementation is in fact a WCF proxy that asks for a username and password; therefore, my next step will be to create a reusable facade whose responsibility will be to intercept the consumer's call and put the username and password just before WCF marshals the call on the wire, using the Secure Principal and Identity of the current thread. Everything will be transparent to the user, Montreal Canadians will win the cup, and everybody will be happy ;-)

10/14/08

Permalink 04:18:20 pm, Categories: Architecture, WCF

Lately I came across an interesting problem in WCF.  It’s about generic contract types.

Before diving into this and presenting the solution, let me expose a little architectural problem as an introduction: The interface IEntityAdapter<TEntity>, in Omniscient.Foundation.Data is used in the business layer to save and load entities.  It’s generally used in conjunction with IEntityController<TEntity> that helps manage the entity status, but can also be used directly.  In a client-server implementation scenario, the adapter could stay on the server, while the consumer is on the client.  Suppose we’re using WCF to communicate.  Do we expose IEntityAdapter as a service contract, or do we hide it behind a façade, or another layer?  What’s important here is separation of concerns.  Should that interface be concerned by communication matters?  Strictly speaking, the answer would be no.  But when you consider it, an interface is already a contract; it’s a run-time contract, it helps us achieve dependency injection, inversion of control and unit testing.  It defines the communication between two objects.  So, why not extend it to be a WCF contract?  Contract for contract, it’s pretty much the same concern!

The fact is that this interface is bridging the database.  It’s a data layer interface, and its role is to define the interaction with the database.  One lesson learned over time is that it’s dangerous to couple presentation layers with data stuff.  You jump over the business layer, short-circuiting things like validation and business triggers.  The result is that you end up putting business logic into the UI.  Now, what’s a WCF service if not a presentation layer?  It’s not inside a workflow, it’s at the beginning of a workflow; inputs from the “user” trigger business actions and therefore, it’s no different then every presentation layer.  It even has its own user interface, the WSDL.  Isn’t it logic then to try and separate WCF front-end from the back-end and IEntityAdapter?

When you’re building a framework you’re constantly facing this kind of question: how far should the framework go in order to protect the user (in the case of a framework, the user is always a programmer) against their own dumbness?  Should I force the user into creating a façade over IEntityAdapter by omitting to decore it with WCF attributes?  In my opinion, the answer is no.  The developer is an intelligent creature; let them use your framework the way they want.  Most frameworks out there are good at that: forcing you into a single, often complicated way of using it.  Then, instead of helping you code better and faster, it’s often leading you into obscure and complicated paths where you can’t jump the fence.  Is there a possibility that people would want to use IEntityAdapter as a service contract?  Yes.  Therefore, I decided to implement this behaviour into IEntityAdapter<TEntity>.

So!  There begins the problem.  At first, I decorated the interface with the required Contract Operation attributes, but it wasn't working (that's because of a configuration problem - more on that latter). Then I got interested into the fact that IEntityAdapter is a generic interface. You'll see that in this case it's not a problem, but I thought it was because I knew that the WSDL is unable to deal with generics (nor is it able to publish overloaded methods, by the way). Simply put, there's no way in WSDL to pass a type from the client to the server, to "feed" generic type parameters.

Here we must understand what I'm talking about: there's a difference between generics that are "instanciated" (whose real type is known at compile-time), and those that are still "open". It's the second type that cause us problems.

Let's present this with an example: Suppose I have the contract IContract, as below:


[ServiceContract()]
public interface IContract<T>
{
   [OperationContract()]
   T Echo(T item);
}

This contract can be easily published by WSDL, since the service itself (the class that implements the service contract) is not generic; by implementing the interface, it must specify the actual type of the generic type parameter, and in turn, the whole non-generic type is used in the endpoint contract. For example, if I have:


public class Service: IContract<string>
{
   string Echo(string item)
   {
      return item;
   }
}

then the endpoint's contract must be declared as follow: contract="IContract`1[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]". The reason why we use the assembly-qualified name of the type string is because that's the way it works in .net; generic type instances must be assembly-qualified in order to be valid (which makes total sense when you think about it).

That's working because WSDL has something to work with; the type of the contract is no longer IContract<T>, it's now IContract<string>.

Now, consider that little modification:


[ServiceContract()]
public interface IContract<T>
{
   [OperationContract()]
   T Echo(T item);

   [OperationContract()]
   T2 Echo2<T2>(T2 item);
}


Bang! That's not working. Why? Because "T2" is an "open generic"; it's still available to be changed at run-time! That's exactly the kind of things the WSDL is unable to represent. It's unable, in fact, to transfer the type parameter from the client to the server. Indeed, from the client, if you want to call this operation, you have to specify a type; and this type must make it to the server. WSDL and SOAP are unable to do that. When you try to open a host with a service implementing such contract, you get this error:
Type 'T2' cannot be exported as a schema type because it is an open generic type. You can only export a generic type if all its generic parameter types are actual types.
In fact, .NET is telling you that the WSDL is unable to 1-publish type parameters and 2-transfer type parameters from the client to the server.

Will this limitation be fixed in the future? I don't know...

September 2010
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    

Here on this blog you'll find continuous thoughts and information about Omniscient's Foundation framework.

Search

The requested Blog doesn't exist any more!

XML Feeds

powered by b2evolution free blog software