tag:blogger.com,1999:blog-68211292771470750622024-02-20T03:18:25.765-08:00Fluffy's .NET Identity Blog"I don't make films, but if I did they'd have a Samurai" - Barenaked LadiesFluffyhttp://www.blogger.com/profile/17466975530647578197noreply@blogger.comBlogger8125tag:blogger.com,1999:blog-6821129277147075062.post-44399734549382952672008-09-01T08:24:00.001-07:002008-09-01T08:57:19.479-07:00Extending LINQ to EntitiesThe other day I was trying to perform the equivalent of a SQL 'Where In' Clause using the Entity Framework.<br /><br />As of today, the Entity Framework does not support such functionality natively. However, it is possible to replicate this functionality in a straight forward way.<br /><br />Once again, I'm going to use extension methods and lambda expressions to get where I need.<br /><br />To understand the way I've achieved this, you need to understand that (what I call) LINQ methods such as Where, OrderBy, Take etc manipulate the IQueryable<T> interface (where T is an EntityObject within your ObjectContext). So in order to extend the functionality of the Entity Framework, we're going to need to extend any class that implements the IQueryable<T> <span style="font-family:lucida grande;">interface</span>.<br /><br />The extension method looks like this:<br /><br /><span style="font-family:courier new;font-size:85%;">public static IQueryable<T> In<T, TValue>(this IQueryable<T> source, Expression<Func<T, TValue>> valueSelector, IEnumerable<TValue> values)<br />{<br />if (null == valueSelector)<br />{<br />throw new ArgumentNullException("valueSelector");<br />}<br /><br />if (null == values)<br />{<br />throw new ArgumentNullException("values");<br />}<br /><br />if (!values.Any())<br />{<br />throw new ArgumentOutOfRangeException("values");<br />}<br /><br />ParameterExpression p = valueSelector.Parameters.Single();<br /><br />var equals = values.Select(value => (Expression)Expression.Equal(valueSelector.Body, Expression.Constant(value, typeof(TValue))));<br /><br />var body = equals.Aggregate<expression>((accumulate, equal) => Expression.Or(accumulate, equal));<br /><br />var containsExpression = Expression.Lambda<Func<T, bool>>(body, p);<br /><br />string command = "Where";<br /><br />Type type = typeof(T);<br /><br />var resultExpression = Expression.Call(<br />typeof(Queryable),<br />command,<br />new Type[] { type },<br />source.Expression,<br />Expression.Quote(containsExpression));<br /><br />return source.Provider.CreateQuery<T>(resultExpression);<br />}</span><br /><br />Firstly, we're providing two arguments - the first is a parameter to tell the 'In' method how to select values within the clause. The second is a list of values mimicking the In clause itself.<br /><br />We expand the Expression tree to write a standard 'Where' clause, with each predicate explictly stated, instead of<br /><br />Where [Name] In { A, B, C }<br /><br />we write<br /><br />Where [Name] = 'A' OR [Name] = 'B' OR [Name] = 'C'<br /><br />Finally, we execute the expression on the source object. The return type of IQueryable<T> enables us to 'chain' this method with any of the existing methods.<br /><br />To call this method, do something like this:<br /><br /><span style="font-family:courier new;font-size:85%;">List<string> names = new List<string>();</span><br /><span style="font-family:courier new;font-size:85%;">names.Add("Fluffy");</span><br /><span style="font-family:courier new;font-size:85%;">names.Add("Sweetness");<br />var results = objectcontext.Person.In(p => p.Name, names).ToList();</span><br /><span style="font-family:Courier New;font-size:85%;"></span><br /><span style="font-family:lucida grande;">This selects all users whose [Name] is either 'Fluffy' or 'Sweetness' from the table 'Person' within my object context. You'll notice that the code has the same feel as it might with any of the native LINQ methods.</span><br /><br />Happy Coding!<br /><br />GraemeFluffyhttp://www.blogger.com/profile/17466975530647578197noreply@blogger.com1tag:blogger.com,1999:blog-6821129277147075062.post-30430099557759780352008-08-29T08:08:00.000-07:002008-09-04T02:58:24.649-07:00Method decoration using Lambda expressionsMy latest foray into the world of .NET 3.5 got me wondering about how I might be able to 'decorate' methods from other assemblies, using a standard pattern, with the minimum of fuss.<br /><br />To illustrate, in my particular example I wanted a 'RunAs' functionality for any existing method; so the workflow goes as follows:<br /><br />1 - Cache any existing user details<br />2 - Logon a new user<br />3 - Execute some code<br />4 - Return the previous context<br /><br />I didn't want other developers writing their own code to do this, because the potential for mistakes and misunderstanding is very high.<br /><br />In the above example steps 1, 2 and 4 aren't important, I could have equally written<br /><br />1 - Do something<br />2 - Execute some code<br />3 - Do something else<br /><br />I found a neat way of doing this, involving both Lambda expressions and Extension methods (although I'm sure there's plenty of other ways to achieve the same thing).<br /><br />Firstly, we'll create an extension method (mine is of System.Object so that ALL objects can do this, but you may want to restrict yours).<br /><br /><span style="font-family:courier new;"><span style="font-size:85%;">/// <summary><br />/// Enables ANY Function to be executed as another user (prompts logon first)<br />/// </summary><br />/// <typeparam name="R">Return type</typeparam><br />/// <param name="source">Type to extend</param><br />/// <param name="f">Function to be executed</param><br />/// <returns>The response from the wrapped method</returns><br />/// <remarks>Call this method like so:<br />/// <c>var result = this.RunAs(() => this.DoSomething());</c><br />/// </remarks><br />public static R RunAs<R>(this object source, Func<R> f)<br />{<br /><span style="color:#ff6666;">DO SOMETHING PRIOR...</span><br />R result = f();<br /></span><span style="font-size:85%;"><span style="color:#ff6666;">... DO SOMETHING POST<br /></span>return result;<br />}<br /></span></span><br />To call this method, we may write something like:<br /><br /><span style="font-family:courier new;"><span style="font-size:85%;">var result = this.RunAs(() => this.DoSomething());</span><br /></span><br />Notice that the lambda expression is clever enough to figure out the return type for us. Pretty cool. Another remarkable fact is that the signature of the method you're calling doesn't even have to match the Func<R> delegate type in the extension method...<br /><br /><span style="font-size:85%;"><span style="font-family:courier new;">var result this.RunAs(() => this.<span class="blsp-spelling-error" id="SPELLING_ERROR_0">DoSomethingElse</span>( 1, 2, 3));</span> </span><br /><br />... would be equally valid! This is <span class="blsp-spelling-corrected" id="SPELLING_ERROR_1">because</span> the lambda expression actually evaluates to a Func<R> delegate, i.e. a function that takes no arguments (hence the () construct) and that returns something of type R (the return type of '<span class="blsp-spelling-error" id="SPELLING_ERROR_4">DoSomething</span>').<br /><br />An overload of the <span class="blsp-spelling-error" id="SPELLING_ERROR_5">RunAs</span> method is needed to execute an Action delegate (i.e. one with no return type)<br /><br /><span style="font-size:85%;"><span style="font-family:courier new;">public static void <span class="blsp-spelling-error" id="SPELLING_ERROR_6">RunAs</span>(this object source, Action a)<br />{<br /><span style="color:#ff6666;">DO SOMETHING PRIOR...</span><br />a();<br /><span style="color:#ff6666;">... DO SOMETHING POST</span><br />}</span><br /></span><br />Does anybody else think this is totally cool?<br /><br />Lambda expressions really are a very powerful tool for your programming locker.<br /><br />Cheers!<br /><br />GraemeFluffyhttp://www.blogger.com/profile/17466975530647578197noreply@blogger.com0tag:blogger.com,1999:blog-6821129277147075062.post-24348439623811875322008-08-18T05:40:00.001-07:002008-08-19T16:08:40.852-07:00Custom WCF Channel in Silverlight<span style="font-family:times new roman;">Here's some code I use to create a custom channel in Silverlight. I use this to mimic the IMessageInspector behaviour available in the standard WCF stack (but alas, not in Silverlight).<br /><br />Firstly you'll need a Custom BindingElement:<br /></span><br /><span style="font-family:arial;"><span style="font-size:85%;"><span style="font-family:courier new;"><strong>/// <summary><br />/// Custom binding element - builds the inner channel<br />/// </summary><br />public class ClientChannelBindingElement : BindingElement<br />{<br />#region Constructors<br />/// <summary><br />/// Default constructor<br />/// </summary><br />public ClientChannelBindingElement()<br />{<br />}<br />/// <summary><br />/// Protected constructor<br />/// </summary><br />/// <param name="other">Another binding element</param><br />protected ClientChannelBindingElement(ClientChannelBindingElement other)<br />: base(other)<br />{<br />}<br />#endregion<br />#region Public methods<br />/// <summary><br />/// Build a channel factory<br />/// </summary><br />/// <typeparam name="TChannel">Channel of interest</typeparam><br />/// <param name="context">Binding context</param><br />/// <returns>A new channel factory</returns><br />public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)<br />{<br />ClientChannelFactory<TChannel> factory = new ClientChannelFactory<TChannel>();<br />factory.InnerChannelFactory = context.BuildInnerChannelFactory<TChannel>();<br />return factory;<br />}<br />/// <summary><br />/// Copy this object<br />/// </summary><br />/// <returns>A copy of this</returns><br />public override BindingElement Clone()<br />{<br />return new ClientChannelBindingElement(this);<br />}<br />/// <summary><br />/// Gets an element property<br />/// </summary><br />/// <typeparam name="T">Channel of interest</typeparam><br />/// <param name="context">Binding context</param><br />/// <returns>Property value</returns><br />public override T GetProperty<T>(BindingContext context)<br />{<br />return context.GetInnerProperty<T>();<br />}<br />#endregion<br />} </strong><br /></span><br /><span style="font-family:times new roman;font-size:100%;">Secondly, you'll need to reference this from a binding. I've made this binding look the same as a BasicHttpBinding, so that it may be used from Silverlight: </span><br /><br /></span></span><span style="font-size:85%;"><span style="font-family:courier new;"><strong>/// <summary><br />/// Custom Silverlight binding (mimics BasicHttpBinding)<br />/// </summary><br />public class ClientChannelBinding : CustomBinding<br />{<br />#region Constructor<br />/// <summary><br />/// Default constructor<br />/// </summary><br />public ClientChannelBinding()<br />{<br />BasicHttpBinding basic = new BasicHttpBinding();<br />this.Elements.Add(new ClientChannelBindingElement());<br />this.Elements.Add(new TextMessageEncodingBindingElement(basic.MessageVersion, basic.TextEncoding));<br />this.Elements.Add(new HttpTransportBindingElement());<br />}<br />#endregion<br />#region Public methods<br />/// <summary><br />/// Builds the channel factory<br />/// </summary><br />/// <typeparam name="TChannel">Channel of interest</typeparam><br />/// <param name="parameters">Binding parameters</param><br />/// <returns>An encapsulated channel factory</returns><br />public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingParameterCollection parameters)<br />{<br />ClientChannelFactory<TChannel> factory = new ClientChannelFactory<TChannel>();<br />BasicHttpBinding binding = new BasicHttpBinding();<br />factory.InnerChannelFactory = binding.BuildChannelFactory<TChannel>();<br />return factory;<br />}<br />#endregion<br />#region Internal methods<br />/// <summary><br />/// Async Opened event handler<br />/// </summary><br />/// <typeparam name="TChannel">Channel of interest</typeparam><br />/// <param name="result">Async result</param><br />internal void OnOpened<TChannel>(IAsyncResult result)<br />{<br />if (result.CompletedSynchronously)<br />{<br />return;<br />}<br />else<br />{<br />CompleteOpen<TChannel>(result);<br />}<br />}<br />/// <summary><br />/// Async callback handler<br />/// </summary><br />/// <typeparam name="TChannel">Channel of interest</typeparam><br />/// <param name="result">Async result</param><br />internal void CompleteOpen<TChannel>(IAsyncResult result)<br />{<br />IChannelFactory<TChannel> factory = (IChannelFactory<TChannel>)result.AsyncState;<br />factory.EndOpen(result);<br />}<br />#endregion<br />} </strong></span></span><br /><strong><span style="font-family:Courier New;font-size:85%;"></span></strong><br /><span style="font-family:times new roman;">Next, you'll need a channel ...<br /></span><br /><span style="font-family:courier new;"><span style="font-size:85%;"><strong>/// <summary><br />/// Silverlight client channel class<br />/// </summary><br />public class ClientChannel : IRequestChannel<br />{<br />#region Fields<br />/// <summary><br />/// Internal channel<br />/// </summary><br />private IRequestChannel innerChannel;<br />#endregion<br />#region Constructors<br />/// <summary><br />/// Channel Constructor<br />/// </summary><br />/// <param name="innerChannel">Inner channel</param><br />public ClientChannel(IRequestChannel innerChannel)<br />{<br />this.innerChannel = innerChannel;<br />}<br />#endregion<br />#region Events<br />/// <summary><br />/// Close event handler<br />/// </summary><br />public event EventHandler Closed;<br />/// <summary><br />/// Closing event handler<br />/// </summary><br />public event EventHandler Closing;<br />/// <summary><br />/// Faulted event handler<br />/// </summary><br />public event EventHandler Faulted;<br />/// <summary><br />/// Open event handler<br />/// </summary><br />public event EventHandler Opened;<br />/// <summary><br />/// Opening event handler<br />/// </summary><br />public event EventHandler Opening;<br />#endregion<br />#region Properties<br />/// <summary><br />/// Gets the remote address of the channel<br />/// </summary><br />public EndpointAddress RemoteAddress<br />{<br />get<br />{<br />return this.innerChannel.RemoteAddress;<br />}<br />}<br />/// <summary><br />/// Gets the coomunication state object<br />/// </summary><br />public CommunicationState State<br />{<br />get<br />{<br />return this.innerChannel.State;<br />}<br />}<br />/// <summary><br />/// Gets the URI (from inner channel)<br />/// </summary><br />public Uri Via<br />{<br />get<br />{<br />return this.innerChannel.Via;<br />}<br />}<br />#endregion<br />#region Methods<br />/// <summary><br />/// Async begin request<br />/// </summary><br />/// <param name="message">Message to send</param><br />/// <param name="timeout">Timeout period</param><br />/// <param name="callback">Callback method</param><br />/// <param name="state">State information</param><br />/// <returns>Asynchronous result</returns><br />public IAsyncResult BeginRequest(Message message, TimeSpan timeout, AsyncCallback callback, object state)<br />{ </strong></span></span><br /><span style="font-family:courier new;"><span style="font-size:85%;"><strong><span style="color:#ff6666;">// In Silverlight this is the place to add the header to the outgoing request </span></strong></span></span><br /><span style="font-family:courier new;"><span style="font-size:85%;"><strong><span style="color:#ff6666;">... ADD THE HEADER HERE ...<br /></span>this.Decorate(message);<br />IAsyncResult result = this.innerChannel.BeginRequest(message, timeout, callback, state);<br />return result;<br />}<br />/// <summary><br />/// Async begin request<br />/// </summary><br />/// <param name="message">Message to send</param><br />/// <param name="callback">Callback method</param><br />/// <param name="state">State information</param><br />/// <returns>Asynchronous result</returns><br />public IAsyncResult BeginRequest(Message message, AsyncCallback callback, object state)<br />{ </strong></span></span><br /><span style="font-family:courier new;"><span style="font-size:85%;"><strong><span style="color:#ff6666;">... ADD THE HEADER HERE ...</span><br />this.Decorate(message);<br />IAsyncResult result = this.innerChannel.BeginRequest(message, callback, state);<br />return result;<br />}<br />/// <summary><br />/// End the request - parse the reply for the security header<br />/// </summary><br />/// <param name="result">Async results object</param><br />/// <returns><c>Message</c> reply</returns><br />public Message EndRequest(IAsyncResult result)<br />{</strong></span></span><br /><span style="font-family:courier new;"><span style="font-size:85%;"><strong><span style="color:#ff6666;">// In Silverlight this is the place to read the header from the incoming reply<br /></span>Message reply = this.innerChannel.EndRequest(result);</strong></span></span><span style="font-family:courier new;"><span style="font-size:85%;"><strong><br /></strong></span></span><span style="font-family:courier new;"><span style="font-size:85%;"><strong><span style="color:#ff6666;">... READ THE HEADER HERE ...</span><br />return reply;<br />}<br />/// <summary><br />/// Synchronous request<br />/// </summary><br />/// <param name="message">Outgoing message</param><br />/// <param name="timeout">Timeout period</param><br />/// <returns>Modified message</returns><br />public Message Request(Message message, TimeSpan timeout)<br />{<br />this.Decorate(message);<br />return this.innerChannel.Request(message, timeout);<br />}<br />/// <summary><br />/// Synchronous request<br />/// </summary><br />/// <param name="message">Outgoing message</param><br />/// <returns>Modified message</returns><br />public Message Request(Message message)<br />{<br />this.Decorate(message);<br />return this.innerChannel.Request(message);<br />}<br />/// <summary><br />/// Gets a channel property<br />/// </summary><br />/// <typeparam name="T">Type of property</typeparam><br />/// <returns>Property result</returns><br />public T GetProperty<T>() where T : class<br />{<br />return this.innerChannel.GetProperty<T>();<br />}<br />/// <summary><br />/// Abort this channel<br />/// </summary><br />public void Abort()<br />{<br />this.innerChannel.Abort();<br />}<br />/// <summary><br />/// Asynchronous close<br />/// </summary><br />/// <param name="timeout">Timeout period</param><br />/// <param name="callback">Callback method</param><br />/// <param name="state">State information</param><br />/// <returns>Asynchronous result</returns><br />public IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback, object state)<br />{<br />return this.innerChannel.BeginClose(timeout, callback, state);<br />}<br />/// <summary><br />/// Asynchronous close<br />/// </summary><br />/// <param name="callback">Callback method</param><br />/// <param name="state">State information</param><br />/// <returns>Asynchronous result</returns><br />public IAsyncResult BeginClose(AsyncCallback callback, object state)<br />{<br />return this.innerChannel.BeginClose(callback, state);<br />}<br />/// <summary><br />/// Asynchronous open<br />/// </summary><br />/// <param name="timeout">Timeout period</param><br />/// <param name="callback">Callback method</param><br />/// <param name="state">State information</param><br />/// <returns>Asynchronous result</returns><br />public IAsyncResult BeginOpen(TimeSpan timeout, AsyncCallback callback, object state)<br />{<br />return this.innerChannel.BeginOpen(timeout, callback, state);<br />}<br />/// <summary><br />/// Asynchronous open<br />/// </summary><br />/// <param name="callback">Callback method</param><br />/// <param name="state">State information</param><br />/// <returns>Asynchronous result</returns><br />public IAsyncResult BeginOpen(AsyncCallback callback, object state)<br />{<br />return this.innerChannel.BeginOpen(callback, state);<br />}<br />/// <summary><br />/// Synchronous close<br />/// </summary><br />/// <param name="timeout">Timeout period</param><br />public void Close(TimeSpan timeout)<br />{<br />this.innerChannel.Close(timeout);<br />}<br />/// <summary><br />/// Synchronous close<br />/// </summary><br />public void Close()<br />{<br />this.innerChannel.Close();<br />}<br />/// <summary><br />/// Asynchronous callback - close<br />/// </summary><br />/// <param name="result">Async result</param><br />public void EndClose(IAsyncResult result)<br />{<br />this.innerChannel.EndClose(result);<br />}<br />/// <summary><br />/// Asynchronous callback - open<br />/// </summary><br />/// <param name="result">Async result</param><br />public void EndOpen(IAsyncResult result)<br />{<br />this.innerChannel.EndOpen(result);<br />}<br />/// <summary><br />/// Synchronous open<br />/// </summary><br />/// <param name="timeout">Timeout period</param><br />public void Open(TimeSpan timeout)<br />{<br />this.innerChannel.Open(timeout);<br />}<br />/// <summary><br />/// Synchronous open<br />/// </summary><br />public void Open()<br />{<br />this.innerChannel.Open();<br />}<br />#endregion<br />#region Protected Methods<br />/// <summary><br />/// Decorate the message with the new headers<br />/// </summary><br />/// <param name="message">Message to decorate</param><br />protected virtual void Decorate(Message message)<br />{<br />message.Headers.Add(new SecurityHeader());<br />}<br />#endregion<br />}<em> </em></strong></span></span><br /><strong><em><span style="font-family:Courier New;font-size:85%;"></span></em></strong><br /><span style="color:#ff6666;">[Note: the SecurityHeader class is derived from the MessageHeader class]</span><br /><br /><span style="font-family:times new roman;">... and an associated channel factory:</span><br /><p><br /><strong><span style="font-family:courier new;font-size:85%;">/// <summary><br />/// Overriden custom channel factory<br />/// </summary><br />/// <typeparam name="TChannel">Type of channel to create</typeparam><br />public class ClientChannelFactory<TChannel> : ChannelFactoryBase<TChannel><br />{<br />#region Fields<br />/// <summary><br />/// Inner channel factory<br />/// </summary><br />private IChannelFactory<TChannel> innerChannelFactory;<br />#endregion<br />#region Constructor<br />/// <summary><br />/// Default constructor<br />/// </summary><br />public ClientChannelFactory()<br />{<br />}<br />#endregion<br />#region Properties<br />/// <summary><br />/// Gets or sets the inner channel factory<br />/// </summary><br />public IChannelFactory<TChannel> InnerChannelFactory<br />{<br />get<br />{<br />return this.innerChannelFactory;<br />}<br />set<br />{<br />this.innerChannelFactory = value;<br />}<br />}<br />#endregion<br />#region Protected methods<br />/// <summary><br />/// Open event handler<br />/// </summary><br />/// <param name="timeout">Timeout period</param><br />protected override void OnOpen(TimeSpan timeout)<br />{<br />this.innerChannelFactory.Open(timeout);<br />}<br />/// <summary><br />/// Create channel evebt handler<br />/// </summary><br />/// <param name="to">Destination of channel</param><br />/// <param name="via">Via this URI</param><br />/// <returns>Newly created channel</returns><br />protected override TChannel OnCreateChannel(EndpointAddress to, Uri via)<br />{<br />TChannel innerchannel = this.innerChannelFactory.CreateChannel(to, via);<br />if (innerchannel is IRequestChannel)<br />{<br />ClientChannel clientChannel = new ClientChannel((IRequestChannel)innerchannel);<br />return (TChannel)(object)clientChannel;<br />}<br />return innerchannel;<br />}<br />/// <summary><br />/// End open async callback handler<br />/// </summary><br />/// <param name="result">Async result</param><br />protected override void OnEndOpen(IAsyncResult result)<br />{<br />this.innerChannelFactory.EndOpen(result);<br />}<br />/// <summary><br />/// Begin open async handler<br />/// </summary><br />/// <param name="span">Timeout span</param><br />/// <param name="callback">Callback method</param><br />/// <param name="asyncState">Async state object</param><br />/// <returns>Async result</returns><br />protected override IAsyncResult OnBeginOpen(TimeSpan span, AsyncCallback callback, object asyncState)<br />{<br />return this.innerChannelFactory.BeginOpen(callback, asyncState);<br />}<br />#endregion<br />}<br /></span></strong><br /><br />Finally, you'll need to create the channel from your code (the client class is autogenerated when you import the service):</p><p><br /><strong><span style="font-family:courier new;"><span style="font-size:85%;">ClientChannelBinding binding = new ClientChannelBinding();<br />EndpointAddress endpoint = new EndpointAddress("http://localhost:3532/Authentication.svc"); ////TODO get this from config<br />this.client = new Authentication.AuthenticationClient(binding, endpoint);</span><br /></span></strong></p><p>Happy coding!</p><p></p><p>Graeme</p>Fluffyhttp://www.blogger.com/profile/17466975530647578197noreply@blogger.com3tag:blogger.com,1999:blog-6821129277147075062.post-57692120868936658882008-06-25T01:35:00.000-07:002008-06-25T02:02:08.065-07:00TFS Automated Build - Mailing the developerNot strictly identity related, but anything to make my life easier is all good:<br /><br />A little while ago I asked a question on the <span class="blsp-spelling-error" id="SPELLING_ERROR_0">TFS</span> forum. It was a simple request to email the person who requested the build when the build was finished, including the status of the build (success/failure).<br />The answer I received was to implement a web service, with a known interface, and subscribe this service to receive events from the build process. The web service receives a chunk of <span class="blsp-spelling-error" id="SPELLING_ERROR_1">xml</span>, which I'd need to parse to retrieve the user name. In turn I'd need to look up the email of this user (somehow!). All a bit of pain, frankly. Suffice to say, we never seemed to have the time to do this.<br /><br />Recently I have been investigating gated builds, and in particular an open source product called <a href="http://www.opengauntlet.org/"><span class="blsp-spelling-error" id="SPELLING_ERROR_2">OpenGauntlet</span></a>. I noticed that these guys are emailing developers on start and on finish of their gated builds - brilliant. A quick look through the source code showed me how:<br /><br />The <span class="blsp-spelling-error" id="SPELLING_ERROR_3">TFS</span> <span class="blsp-spelling-error" id="SPELLING_ERROR_4">API</span> is rich in functionality, but the important <span class="blsp-spelling-corrected" id="SPELLING_ERROR_5">interface</span> in this case is<br /><span style="font-family:courier new;color:#009900;"><span class="blsp-spelling-error" id="SPELLING_ERROR_6">IGroupSecurityService</span></span>. Here's how it can be used to retrieve a user's email address:<br /><br /><span style="font-family:courier new;">// First we need to get our <span class="blsp-spelling-error" id="SPELLING_ERROR_7">TFS</span> and then find it's build store<br /><span class="blsp-spelling-error" id="SPELLING_ERROR_8">TeamFoundationServer</span> server = new <span class="blsp-spelling-error" id="SPELLING_ERROR_9">TeamFoundationServer</span>( <span class="blsp-spelling-error" id="SPELLING_ERROR_10">serverUrl</span>, <span class="blsp-spelling-error" id="SPELLING_ERROR_11">CredentialCache</span>.<span class="blsp-spelling-error" id="SPELLING_ERROR_12">DefaultCredentials</span> );</span><br /><span style="font-family:courier new;"></span><br /><span style="font-family:courier new;">// Now get the correct interface<br /><span class="blsp-spelling-error" id="SPELLING_ERROR_13">IGroupSecurityService</span> <span class="blsp-spelling-error" id="SPELLING_ERROR_14">gss</span> = ( <span class="blsp-spelling-error" id="SPELLING_ERROR_15">IGroupSecurityService</span> ) server.<span class="blsp-spelling-error" id="SPELLING_ERROR_16">GetService</span>( <span class="blsp-spelling-error" id="SPELLING_ERROR_17">typeof</span>( <span class="blsp-spelling-error" id="SPELLING_ERROR_18">IGroupSecurityService</span> ) );</span><br /><span style="font-family:courier new;"></span><br /><span style="font-family:courier new;">// Retrieve the identity<br />Identity <span class="blsp-spelling-error" id="SPELLING_ERROR_19">objIdentity</span> = <span class="blsp-spelling-error" id="SPELLING_ERROR_20">gss</span>.<span class="blsp-spelling-error" id="SPELLING_ERROR_21">ReadIdentity</span>( <span class="blsp-spelling-error" id="SPELLING_ERROR_22">SearchFactor</span>.<span class="blsp-spelling-error" id="SPELLING_ERROR_23">AccountName</span>, <span class="blsp-spelling-error" id="SPELLING_ERROR_24">userName</span>, <span class="blsp-spelling-error" id="SPELLING_ERROR_25">QueryMembership</span>.None );</span><br /><span style="font-family:courier new;"></span><br /><span style="font-family:courier new;">// Get the email address</span><br /><span style="font-family:courier new;">string email = <span class="blsp-spelling-error" id="SPELLING_ERROR_26">objIdentity</span>.<span class="blsp-spelling-error" id="SPELLING_ERROR_27">MailAddres</span>;</span><br /><span style="font-family:Courier New;"></span><br /><span style="font-family:arial;">The <span class="blsp-spelling-error" id="SPELLING_ERROR_28">userName</span> is retrieved like so:</span><br /><br /><span style="font-family:courier new;"><span class="blsp-spelling-error" id="SPELLING_ERROR_29">BuildStore</span> store = ( <span class="blsp-spelling-error" id="SPELLING_ERROR_30">BuildStore</span> ) server.<span class="blsp-spelling-error" id="SPELLING_ERROR_31">GetService</span>( <span class="blsp-spelling-error" id="SPELLING_ERROR_32">typeof</span>( <span class="blsp-spelling-error" id="SPELLING_ERROR_33">BuildStore</span> ) );<br />// Get the build from our <span class="blsp-spelling-error" id="SPELLING_ERROR_34">uri</span><br /><span class="blsp-spelling-error" id="SPELLING_ERROR_35">BuildData</span> <span class="blsp-spelling-error" id="SPELLING_ERROR_36">bd</span> = store.<span class="blsp-spelling-error" id="SPELLING_ERROR_37">GetBuildDetails</span>( <span class="blsp-spelling-error" id="SPELLING_ERROR_38">buildUri</span> );</span><br /><span style="font-family:Courier New;">// user name</span><br /><span style="font-family:Courier New;">string <span class="blsp-spelling-error" id="SPELLING_ERROR_39">userName</span> = <span class="blsp-spelling-error" id="SPELLING_ERROR_40">buildData</span>.<span class="blsp-spelling-error" id="SPELLING_ERROR_41">RequestedBy</span>;</span><br /><br />Knowing this, it is a simple matter of writing a task to email the developer, passing <span style="font-family:courier new;"><span class="blsp-spelling-error" id="SPELLING_ERROR_42">serverUri</span></span>, <span style="font-family:courier new;"><span class="blsp-spelling-error" id="SPELLING_ERROR_43">buildUri</span></span> etc as optional parameters.<br /><br />Simple.Fluffyhttp://www.blogger.com/profile/17466975530647578197noreply@blogger.com0tag:blogger.com,1999:blog-6821129277147075062.post-53312102867154090992008-03-28T09:31:00.000-07:002008-03-31T01:35:23.580-07:00Federation over a Duplex channelMe again.<br /><br />This time I wanted to do something a little beyond the norm, at least as far as the available examples are concerned. I would really like to implement a publish/subscriber service, where an application subscribes to various system wide events. Seems like a job for a Duplex channel - the client subscribes to service, and also provides an endpoint as a means to receive events.<br /><br />The big catch here is that I'd love this service to execute under the same security context as the rest of my architecture, i.e. I'd like the service to be federated with my STS.<br /><br />After trawling the net, I found several useful snippets, but nothing that solved the whole problem. Specifically, I wanted to achieve all this via config, if possible.<br /><br />So here's how I did it...<br /><br /><br />The client binding looks like<br /><br /><customBinding><br /><binding name="DuplexBinding"><br /><security authenticationMode="SecureConversation"><br /><secureConversationBootstrap authenticationMode="IssuedToken"><br /><issuedTokenParameters tokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1"><br /><issuer address="http://localhost:8080/STS/Slave" binding="wsFederationHttpBinding" bindingConfiguration="UserNameFederationBinding"><br /><identity><br /><dns value="My STS" /><br /></identity><br /></issuer><br /><issuerMetadata address="http://localhost:8080/STS/Slave/mex" /><br /></issuedTokenParameters><br /></secureConversationBootstrap><br /></security><br /><compositeDuplex clientBaseAddress="http://localhost:8080/Client"/><br /><oneWay/><br /><textMessageEncoding /><br /><httpTransport /><br /></binding><br /></customBinding><br /><br />Here, the original authentication mechanism was via a Username token. Notice the order of the elements within the <security>tag - this foxed me for a good while before it clicked! Also note that the authentication mode is set to 'SecureConversation', with the bootstrap mode set to 'IssuedToken'. Initially I thought this seemed counter-intuitive, but when you consider the order in which WCF (or more correctly, WS-Security) performs its negotiation, this makes more sense.<br /><br />In the service, the binding looks like<br /><br /><customBinding><br /><binding name="DuplexBinding"><br /><security authenticationMode="SecureConversation"><br /><secureConversationBootstrap authenticationMode="IssuedToken"><br /><issuedTokenParameters tokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1"><br /><issuer address="http://localhost:8080/STS/Slave" binding="wsHttpBinding" /><br /><issuerMetadata address="http://localhost:8080/STS/Slave/mex" /><br /></issuedTokenParameters><br /></secureConversationBootstrap><br /></security><br /><compositeDuplex/><br /><oneWay/><br /><textMessageEncoding /><br /><httpTransport /><br /></binding><br /></customBinding><br /><br />The service works in exactly the same way a standard Duplex service would, i.e. it simply retains a reference to the callback channel, like so<br /><br />IRegisterCallback callback = OperationContext.Current.GetCallbackChannel<iregistercallback>();<br /><br />in order to use this when necessary.<br /><br />I hope this helps anybody else wishing to do the same, or similar, with their architecture.<br /><br />Cheers<br /><br />GraemeFluffyhttp://www.blogger.com/profile/17466975530647578197noreply@blogger.com0tag:blogger.com,1999:blog-6821129277147075062.post-29545974417339131882008-02-21T07:29:00.000-08:002008-03-10T08:51:45.221-07:00Token expiration dates<span style="font-family:arial;">Here's another (brief) problem regarding the setting of validity dates within a token, or more specifically an RSTR (Issue), as implemented in WCF.<br /><br />I was attempting to set validity date information within an RSTR. Firstly, I updated the dates within the SAML assertion itself, like so</span><br /><br /><br />DateTime validFrom = DateTime.UtcNow;<br /><br />DateTime validTo = validFrom + TimeSpan.FromDays(1);<br />SamlAssertion assertion = new SamlAssertion();<br />assertion.Conditions = new SamlConditions(validFrom, validTo);<br /><br /><span style="font-family:verdana;">Avid readers (!) will note that the WS-Trust schema defines the following elements for specifying the valid date range of the accompanying token:<br /><br /></span></code><code><span style="font-family:verdana;">wst:RequestSecurityTokenResponse/wst:Lifetime<br /></span><br /><br /><span style="font-family:verdana;">wst:RequestSecurityTokenResponse/wst:Lifetime/wsu:Created</span></code><br /><br /><p><span style="font-family:verdana;">wst:RequestSecurityTokenResponse/wst:Lifetime/wsu:Expires</p><br /><br /><br /></span><br /><span style="font-family:verdana;">where wst namespace is <a href="http://schemas.xmlsoap.org/ws/2005/02/trust"><em>http://schemas.xmlsoap.org/ws/2005/02/trust</em></a></span></code><br /><br /><span style="font-family:Verdana;">and wsu namespace is<br /><a href="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd</a></span><br /><br /><span style="font-family:verdana;">It is these dates that WCF will use to determine the lifetime of a token. The trick, when setting these dates in your RSTR, is to supply them in the correct format. If you don't you'll receive a very unhelpful error message within your client, the gist of which will be 'I don't understand your date formats, but I'm not going to tell you why'. After alot of messing, and finally resorting to code decomposition, I determined that the correct format is:<br /></span><br />time.ToUniversalTime().ToString("o");<br /><span style="font-family:verdana;">The RSTR is modified like so (within the <em>OnWriteBodyContents</em> method of the <em>RequestSecurityTokenResponse</em> class as per the WCF samples), for completeness:</span><br /><br /><span style="font-family:verdana;"></span><br /><br />// This part tells WCF what the lifetime of the token is, without having to parse the token itself<br />writer.WriteStartElement("Lifetime", TrustNS);<br />writer.WriteElementString("Created", UtilityNS, FormatDate(validFrom));<br />writer.WriteElementString("Expires", UtilityNS, FormatDate(validTo));<br />writer.WriteEndElement();<br /><br /><span style="font-family:Verdana;"></span><br /><br /><span style="font-family:verdana;">I guess that, with hindsight, it is reasonably obvious that the time should be UTC, but as they say, hindsight is a wonderful thing.<br /><br /><br />Hopefully, this will save somebody at least a small amount of time in future!<br /><br /><br />Fluffy<br /></span>Fluffyhttp://www.blogger.com/profile/17466975530647578197noreply@blogger.com0tag:blogger.com,1999:blog-6821129277147075062.post-72198301470059083342008-02-21T07:02:00.000-08:002008-03-10T08:49:23.849-07:00SAML token serialization<span style="font-family:verdana;">So, as promised, my first post is regarding simple serialization/de-serialization of a SAML token. </span><br /><br /><br /><span style="font-family:verdana;"></span><br /><br /><br /><span style="font-family:verdana;">The driver for this exercise was to implement the 'Renew' verb of the WS-Trust specification, using the framework that WCF provides. To my endless frustration, the development team over at Microsoft stopped short of implementing the entire WS-Trust spec for anything but SCTs! Instead we're left with just 'Issue'. </span><br /><br /><br /><span style="font-family:verdana;"></span><br /><br /><br /><span style="font-family:verdana;">My STS is signing tokens using self-issued X509 certificates (one for the STS and one for each client). Here's the (shortened) code for the serialization of the token:</span><br /><br /><br /><br /><br />/// <summary><br />/// Write the given token into an XmlWriter object<br />/// </summary><br />/// <param name="token"></param><br />/// <param name="writer"></param><br />public virtual void WriteToken(SamlSecurityToken token, XmlWriter writer)<br />{<br />System.ServiceModel.Security.WSSecurityTokenSerializer serializer = new System.ServiceModel.Security.WSSecurityTokenSerializer();<br />serializer.WriteToken(writer, token);<br />}<br /><br /><br /><span style="font-family:verdana;">Now, when I receive the token back from the client for renewal I need to de-serialize it in order to update its validity time span. Here's the code for this:</span><br /><br /><span style="font-family:verdana;"></span><br /><br />/// <summary><br />/// Read the token from an XmlDictionaryReader reader<br />/// </summary><br />/// <param name="reader"></param><br />/// <returns></returns><br />public virtual SamlSecurityToken ReadToken(XmlDictionaryReader reader)<br />{<br />System.ServiceModel.Security.WSSecurityTokenSerializer serializer = new System.ServiceModel.Security.WSSecurityTokenSerializer();<br />System.Collections.Generic.List<securitytoken> tokens = new System.Collections.Generic.List<securitytoken>();<br />tokens.Add(SigningToken);<br />tokens.Add(UnencryptingToken);<br />System.IdentityModel.Selectors.SecurityTokenResolver resolver =<br />System.IdentityModel.Selectors.SecurityTokenResolver.CreateDefaultSecurityTokenResolver(tokens.AsReadOnly(), false);<br />SamlAssertion assertion = new SamlAssertion();<br />assertion.ReadXml(reader, new SamlSerializer(), serializer, resolver);<br />return new SamlSecurityToken(assertion);<br />}<br /><span style="font-family:verdana;"></span><br /><span style="font-family:verdana;"></span><br /><br /><span style="font-family:verdana;">Note that here the signing token is the certificate used by the STS to sign the assertion, and the unencrypting token is the private key equivalent of the certificate used to encrypt the proof key in the RSTR. </span><br /><span style="font-family:Verdana;"></span><br /><span style="font-family:verdana;">The point here is that in order to de-serialize the token, you're going to need the private key of the certificate used to encrypt the original. I guess this isn't a problem when you're in control of client certification, but I think you can see why this might cause issues.</span>Fluffyhttp://www.blogger.com/profile/17466975530647578197noreply@blogger.com0tag:blogger.com,1999:blog-6821129277147075062.post-62702969546231689432008-02-21T06:44:00.000-08:002008-02-21T06:52:21.485-08:00Welcome!Hi guys!<br /><br />I've recently been doing a lot of work around Identity in the .NET framework, especially as it applies in 3.0 and 3.5. I've found that much of this stuff isn't covered in any great detail in the documentation. To get a problem solved I've simply had to 'suck it and see', if you'll pardon the expression. This has been frustrating, to say the least! I finally decided to blog about some of my exploits with SAML, WCF, WS-Trust, etc, in order that I might be able to help out a few people who come across the same issues!<br /><br />I'll begin posting in the very near future - I'll start with a simple SAML serialization/de-serialization problem I encountered a few months ago. I also want to share my experiences of WS-Trust and how it applies (or doesn't!) to WCF, plus one or two salutory tales of developing an STS (Security Token Service) from scratch.<br /><br />Cheers<br /><br />FluffyFluffyhttp://www.blogger.com/profile/17466975530647578197noreply@blogger.com0