My diary of software development

Archive for the ‘WPF Development’ Category

Finally! An 4.0 XBAP can call a Windows Authenticated WCF Service! Part 2

In the first part to this subject, I wrote about the problem I ran into, the hotfix from Microsoft, the hotfix’s failure, and finally Microsoft’s promise to fix the bug in .Net 4.0. Now that 4.0 is in RC mode and proved itself to fix this problem, I’m going to take a look at the source code to see just how it did fix this problem. But before I look at the 4.0 source code, I’m going to look at the 3.5 pre-hotfix source code and then the 3.5 post hotfix source code to get a feel for what Microsoft was doing which caused my problem. By the way, I’m using RedGate’s Reflector product to look at the source code.   

.Net 3.5 Service Pack 1, Pre-Hotfix

Here is the exception stack thrown when my problem first surfaced in the 3.5 pre-hotfix era:

Pre-Hotfix Exception

 The exception came from HttpChannelFactor.GetConnectionGroupName():   

 

[SecurityTreatAsSafe, SecurityCritical]
private string GetConnectionGroupName(HttpWebRequest httpWebRequest, NetworkCredential credential, AuthenticationLevel authenticationLevel, TokenImpersonationLevel impersonationLevel, SecurityTokenContainer clientCertificateToken)
{
    if (this.credentialHashCache == null)
    {
        lock (base.ThisLock)
        {
            if (this.credentialHashCache == null)
            {
                this.credentialHashCache = new MruCache<string, string>(5);
            }
        }
    }
    string inputString = TransferModeHelper.IsRequestStreamed(this.TransferMode) ? "streamed" : string.Empty;
    if (AuthenticationSchemesHelper.IsWindowsAuth(this.AuthenticationScheme))
    {
        httpWebRequest.UnsafeAuthenticatedConnectionSharing = true;
        inputString = this.AppendWindowsAuthenticationInfo(inputString, credential, authenticationLevel, impersonationLevel);
    }
    inputString = this.OnGetConnectionGroupPrefix(httpWebRequest, clientCertificateToken) + inputString;
    string str3 = null;
    if (!string.IsNullOrEmpty(inputString))
    {
        lock (this.credentialHashCache)
        {
            if (!this.credentialHashCache.TryGetValue(inputString, out str3))
            {
                byte[] bytes = new UTF8Encoding().GetBytes(inputString);
                str3 = Convert.ToBase64String(this.HashAlgorithm.ComputeHash(bytes));
                this.credentialHashCache.Add(inputString, str3);
            }
        }
    }
    return str3;
}

The GetConnectionGroupName() function is attempting to set the UnsafeAuthenticatedConnectionSharing property and according to the MSDN reference for the property, an application must have unrestricted web permission to set it. However I used the Intranet Zone permission set for my XBAP which did not have the web permission security privlege and so this is why the above exception was thrown. I did not dig into the actual source code when this problem arose last summer, I simply opened a ticket with Microsoft because I figured that I should be able to call a WCF service secured with Windows Integrated security from an XBAP. After a few days, I received feedback from Microsoft that they had released a hotfix.   

.Net 3.5 Service Pack 1, Post-Hotfix

Here is how Microsoft fixed the above problem in the hotfix. The below code is the same HttpChannelFactory.GetConnectionGroupName() function shown above except that it has the hotfix changes in it:    


[SecurityCritical, SecurityTreatAsSafe]
private string GetConnectionGroupName(HttpWebRequest httpWebRequest, NetworkCredential credential, AuthenticationLevel authenticationLevel, TokenImpersonationLevel impersonationLevel, SecurityTokenContainer clientCertificateToken)
{
    if (this.credentialHashCache == null)
    {
        lock (base.ThisLock)
        {
            if (this.credentialHashCache == null)
            {
                this.credentialHashCache = new MruCache<string, string>(5);
            }
        }
    }
    string inputString = TransferModeHelper.IsRequestStreamed(this.TransferMode) ? "streamed" : string.Empty;
    if (AuthenticationSchemesHelper.IsWindowsAuth(this.AuthenticationScheme))
    {
        if (!httpWebRequestWebPermissionDenied)
        {
            try
            {
                httpWebRequest.UnsafeAuthenticatedConnectionSharing = true;
            }
            catch (SecurityException)
            {
                httpWebRequestWebPermissionDenied = true;
            }
        }
        inputString = this.AppendWindowsAuthenticationInfo(inputString, credential, authenticationLevel, impersonationLevel);
    }
    inputString = this.OnGetConnectionGroupPrefix(httpWebRequest, clientCertificateToken) + inputString;
    string str3 = null;
    if (!string.IsNullOrEmpty(inputString))
    {
        lock (this.credentialHashCache)
        {
            if (!this.credentialHashCache.TryGetValue(inputString, out str3))
            {
                byte[] bytes = new UTF8Encoding().GetBytes(inputString);
                str3 = Convert.ToBase64String(this.HashAlgorithm.ComputeHash(bytes));
                this.credentialHashCache.Add(inputString, str3);
            }
        }
    }
    return str3;
}

The httpWebRequestWebPermissionDenied flag is checked to guard against setting the UnsafeAuthenticatedConnectionSharing property. So if this flag is set, the code will not try to set the connection sharing property. However, where is the httpWebRequestWebPermissionDenied flag set? It is set to true if an exception is thrown in the above code on line 25 and it is initialized to false in the constructor but the only other place it is set is in the OnOpen() function:    


protected override void OnOpen(TimeSpan timeout)
{
    if (this.IsSecurityTokenManagerRequired())
    {
        this.InitializeSecurityTokenManager();
    }
    if (this.AllowCookies)
    {
        this.cookieContainer = new CookieContainer();
    }
    if (!httpWebRequestWebPermissionDenied && (HttpWebRequest.DefaultMaximumErrorResponseLength != -1))
    {
        int num;
        if (this.MaxBufferSize >= 0x7ffffbff)
        {
            num = -1;
        }
        else
        {
            num = this.MaxBufferSize / 0x400;
            if ((num * 0x400) < this.MaxBufferSize)
            {
                num++;
            }
        }
        if ((num == -1) || (num > HttpWebRequest.DefaultMaximumErrorResponseLength))
        {
            try
            {
                HttpWebRequest.DefaultMaximumErrorResponseLength = num;
            }
            catch (SecurityException exception)
            {
                httpWebRequestWebPermissionDenied = true;
                if (DiagnosticUtility.ShouldTraceWarning)
                {
                    DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Warning);
                }
            }
        }
    }
}

 

This function uses pretty much the same logic to set the httpWebRequestWebPermissionDenied flag. If a SecurityException is thrown, then the flag is set to true. That seems like a quick and dirty way to set the permission flag’s value and I guess it works but it seems to me that it should be set during class initialization by reading the XBAP’s associated manifest file to see if that permission is in the XBAP’s permission set. I looked at the .Net 4.0 code to see if the flag was initialized in some way but found that it uses the same logic to figure out if the XBAP doesn’t have web permission. Strange, I thought there’d be a more elegant way.    

However ugly the above hotfix is, it did get the code past that point and on down the callstack. But farther down in the callstack another exception was thrown:    

Post-Hotfix Exception

This next exception was thrown because SecurityUtils.AppendWindowsAuthenticationInfo() called WindowsIdentity.GetCurrent():    


[SecurityCritical]
internal static string AppendWindowsAuthenticationInfo(string inputString, NetworkCredential credential, AuthenticationLevel authenticationLevel, TokenImpersonationLevel impersonationLevel)
{
    if (IsDefaultNetworkCredential(credential))
    {
        using (WindowsIdentity identity = WindowsIdentity.GetCurrent())
        {
            SecurityIdentifier user = identity.User;
            return (inputString + "\0" + user.Value + "\0" + AuthenticationLevelHelper.ToString(authenticationLevel) + "\0" + TokenImpersonationLevelHelper.ToString(impersonationLevel));
        }
    }
    return (inputString + "\0" + NetworkCredentialHelper.UnsafeGetDomain(credential) + "\0" + NetworkCredentialHelper.UnsafeGetUsername(credential) + "\0" + NetworkCredentialHelper.UnsafeGetPassword(credential) + "\0" + AuthenticationLevelHelper.ToString(authenticationLevel) + "\0" + TokenImpersonationLevelHelper.ToString(impersonationLevel));
}

However, in order to call WindowsIdentity.GetCurrent, the app must have SecurityPermissionFlag.ControlPrincipal as the WindowsIdentity.GetCurrent() method demands it:    


[SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)]
public static WindowsIdentity GetCurrent()
{
    return GetCurrentInternal(TokenAccessLevels.MaximumAllowed, false);
}

Since my clickonce XBAP did not have this security, this Demand caused another exception.    

.Net 4.0

The .Net 4.0 code was the same as the hotfix code for dealing with the UnsafeAuthenticatedConnectionSharing property problem. However it handled the WindowsIdentity.GetCurrent() somewhat differently. Here is the SecurityUtils.AppendWindowsAuthenticationInfo() function in .Net 4.0:  

</pre>
 

[SecurityCritical]
internal static string AppendWindowsAuthenticationInfo(string inputString, NetworkCredential credential, AuthenticationLevel authenticationLevel, TokenImpersonationLevel impersonationLevel)
{
    if (IsDefaultNetworkCredential(credential))
    {
        string str = UnsafeGetCurrentUserSidAsString();
        return (inputString + "\0" + str + "\0" + AuthenticationLevelHelper.ToString(authenticationLevel) + "\0" + TokenImpersonationLevelHelper.ToString(impersonationLevel));
    }
    return (inputString + "\0" + NetworkCredentialHelper.UnsafeGetDomain(credential) + "\0" + NetworkCredentialHelper.UnsafeGetUsername(credential) + "\0" + NetworkCredentialHelper.UnsafeGetPassword(credential) + "\0" + AuthenticationLevelHelper.ToString(authenticationLevel) + "\0" + TokenImpersonationLevelHelper.ToString(impersonationLevel));
}

 

The logic for this version of SecurityUtils.AppendWindowsAuthenticationInfo() is about the same as the logic in .Net 3.5 except for the call to the new member UnsafeGetCurrentUserSidAsString() on line 11. The code to this new member function is shown below:

[SecurityCritical, SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.ControlPrincipal)]
private static string UnsafeGetCurrentUserSidAsString()
{
    using (WindowsIdentity identity = WindowsIdentity.GetCurrent())
    {
        return identity.User.Value;
    }
}

On line 1 of the above code there is an Assert for the ControlPrincipal flag, the same flag which WindowsIdentity.GetCurrent() demands. This Assert will satisfy the stack walk caused by the Demand and no exception will be thrown. So that is how Microsoft fixed this bug in .Net 4.0. 

 

Advertisements

Finally! An 4.0 XBAP can call a Windows Authenticated WCF Service! Part 1

The Problem

Last year, I was on a project where I designed a solution with an XBAP and an IIS hosted WCF data service. The problem came out because the WCF service was secured with Windows integrated authentication and the XBAP, being a partial trust application, did not have the appropriate privileges needed to call the necessary CLR methods needed to package and issue a call to the secured WCF service. 

The first hint of the problem came out when I got a security exception from calling the WCF service from inside the XBAP. The security exception was because the WCF service proxy was trying to set the HttpWebRequest.UnsafeAuthenticatedConnectionSharing property. However, unrestricted web permission is required to set that property and the XBAP, which was running with the Intranet zone privleleges, did not have that permission. Here is the stack trace of the exception:

I opened a ticket with Microsoft concerning this problem and after a few days, received hotfix 959546 which was supposed to address this problem:

This hotfix did address the problem and allowed the code to proceed past the point of setting the HttpWebRequest.UnsafeAuthenticatedConnectionSharing property but a new exception was thrown higher in the callstack:

It took quite a bit of time after I first opened the ticket, worked throught he hotfix, and before Microsoft was able to clearly address this issue and by this time in my ticket lifecycle, I was working with an escalation engineer. After reporting the above problem to him, I received the below email email in which he indicating that this bug was to be fixed in .Net 4.0:

So at this point, I’m left with a problem: I can’t use the WCF service proxy to call a secured WCF service so what should I do? Should I re-implement the WCF data service as a 2.0 web service? ~~SHIVER!!~~. Grasping at straws, I decided to try using a 2.0 web service proxy to call my secured WCF data service and see what would happen. What happened was that it worked! So I released this project as an XBAP, a secure WCF data service, and a 2.0 web service proxy inside the XBAP to call the secure data service.

And that brings us to today. As you can see from the dates in the email chain above, this all happened last summer and today the .Net framework release 4.0 is in RC mode so I decided to see if this problem was fixed in 4.0. To try out this fix, I setup two quick hyper-v VMs:

  1. Win7 + Visual Studio 2010 RC
  2. 2008 R2 + IIS 7.5

To model the environment of last year’s project, I wrote a quick WCF service and an XBAP to call the service. I ran the XBAP and sure enough, everything worked just fine in 4.0, the XBAP was able to call the WCF service which was being hosted on IIS 7.5 using Windows Integrated Authentication. Just for kicks, I regressed the build’s target framework back to .Net 3.5 and ran it again just to see what would happen. What happened was I got the same exception I did last summer, so that proved to me there were no shenanigans going and that nogthing had crept in to my problem domain (you never know after a year long wait) as the outcome of my proofs were what I expected.

After going through this test with 4.0, I became curious about how exactly Microsoft fixed this problem. To satisfy this curiosity, I’ve decided to write a second part of this post and take a look at the version 3.5 CLR code using Reflector to see what exactly the code looks like that was causing this problem. And then I’ll take look at the 4.0 CLR code to see how the problem was fixed.

 

 

Binding updates to a WPF View from outside of its ViewModel – part 1

Application Overview

I’ve been working on an MVVM WPF app that has a view of metrics collected by some background threads.  A screen shot is shown below:

As I mentioned, I’m using the MVVM pattern for this app so I have a view, a view model, and a model layer. The model layer consists of a ThreadMetrics class which contains the metrics you see for one row of the screen shot above. The view model (ingeniously named the ThreadMetricsViewModel) contains an instance of a ThreadMetrics class as well as the necessary get accessors for the view’s binding targets. The class layout and interactions are shown below:

MVVM Class Interactions

Where this app starts to differ from the other MVVM apps I’ve written is that the updates to the view model’s data do not come from the UI user or a command handler inside the view model. Instead they start with a background thread which updates counts inside the ThreadMetrics instance within the ThreadMetricsViewModel. From there, the view binding will pick them up from Get accessors within the ThreadMetricsViewModel.

Since in this application, data is changed outside of the view model and needs to be reflected on the view, my problem became how to trigger the ThreadMetricsViewModel’s property changed events everytime the values in its associated ThreadMetrics instance were changed. There was also a problem with how often these values changed which caused the view to become unresponsive to user manipulations and I’ll cover that too. 

Triggering view model property changes from the background thread

For the first problem of triggering the property changed events, I’m using the Mediator v2 solution which allows the ThreadMetrics instance to advise the ThreadMetricsViewModel of changes to its metric counts by the background thread. Each time the ThreadMetricsViewModel handles an update notification for one of these counts, it will issue a property changed event which causes the view binding to pick up that value and update it on the view. The image below shows the interaction which solved this problem:

Triggering The ViewModel's PropertyChange Events

Triggering The ViewModel's PropertyChange Events

Keeping the view from becoming unresponsive

The next problem was that the PropertyChange events were happening so fast due to the the high rate of activity by the background threads that the UI became unresponsive. I solved this problem by only sending the PropertyChange events periodically (but often enough to keep the view continuously updated.) The image below shows the UpdateUI method which does this:
The UpdateUI Method

Summary

So that is how I handled updating the view in my MVVM app from changes made outside of the view model, but I need to say that I still don’t get a ‘good’ gut feeling from this implementation.  The ThreadMetricsViewModel doesn’t really serve any purpose other than being a go-between or a proxy to the ThreadMetrics instance which holds the actual values and the background thread class is where the actual logic takes place. It seems that there should be more logic in the ThreadMetricsViewModel, that maybe the ThreadMetrics class should go away and the background thread should reach into the ThreadMetricsViewModel instance to change values there. Or maybe that the ThreadMetrics and the background thread classes both should go away and all the thread and view model logic should occur inside the ThreadMetricsViewModel.

Causing a rift in the WPF coding space-time continuum

At the beginning of developing this app, I feared I may have caused a rift in the space-time continuum of WPF coding best practices because  I did indeed have all of the thread/view model logic and data inside the ThreadMetricsViewModel instances. However this didn’t seem right either because I knew I was mixing backend service operations with view layer operations. It seemed that mixing everything like this into only two layers: the view and view model was violating some basic law of WPF  coding best practices. I began to fear I had created an enormous rift in space and time so I refactored the logic into my current ThreadMetricsViewModel, ThreadMetrics, and background thread classes. Unfortunately it may already be too late and I’m writing this blog from another space-time realm of WPF development and do not know it.

My next post will talk about how I handled updating the aggregate metrics from all my ThreadMetrics instances. That is, the total number of Create and other operations.

A New Way To Hide Disabled WPF TreeView Items

I had a project with a strange requirement which dealt with hiding disabled items on a WPF tree view. The easiest way to for me to explain this requirement is to show it to you visually rather than try to explain it in words. First, take a look at the the image below, it is of a tree view with both enabled and disabled items:

Before

Tree View Showing Enabled and Disabled Items

The strange requirement which I was having difficulty with was to hide those inactive items but still leave their active descendants visible. Notice that item 1 is disabled but it’s direct descendant item 1.1 is not.  So to corectly implement this requirement, I would need to hide the parent item 1 but leave its child item 1.1 still visible. And not only leave its child still visible but leave its child’s horizontal positioning intact as well.

Below is an image of this requirement in action. All inactive items are hidden but their active children are not. If an active item was horizontally aligned X number of device units to the right when its inactive parent was visible, then it needed to stay horizontally alligned X number of device units to the right when its inactive parent was hidden.

After

Tree View Showing Only Active Items

I was writing this project using the MVVM pattern and so in my first attempt at this requirement, I simply used some data triggers in my XAML to hide items which were marked inactive in my view model. Walla! I was done and could move onto more pressing issues in the project. But I soon realized that was not going to happen because although I was able to easily hide inactive tree view items, their children were hidden also.  The default TreeView action when hiding an item was to hide that item’s children also regardless of if the children are active or not.

In order to solve this problem and implement my requriement correctly, I knew I’d have to probably look at the TreeView’s control template and modify it. Which I was dreading. I am not a XAML expert and wanted no part with doing something like this. As a matter of fact, I was quite confused by all of those ‘templates’ in WPF I kept hearing about and trying to read about. There is a control template, a data template, an items panel template, and others. I was thinking to myself, just how many templates are there any way? Do we actually need them? Come on Microsoft, make something easy for me for once.

So after I got over my rant, which took weeks, I took the time to sit down and tell myself “I am going to do this. It will be my project for the day and I can do this.” I felt the ‘force’ close by (well actually Josh Smith’s blog but close enough) and so I felt confident.

Isn’t it strange that after you do something which had been challenging you and forcing you to struggle to surmount it, that it really doesn’t seem so difficult after you do it? I hate that feeling, it makes me feel like I didn’t do anything. Nevertheless, I am going to present the very few and simple steps that I did to accomplish this daring and heroic feat :

1 – I pulled the TreeView control template with the Show Me The Template tool and copied it into my build directory to a new file named TreeViewForStrangeRequirement.xaml.

2 – I then placed a TreeView in my window’s XAML and referenced this new template:

XAML1

3- I had a checkbox on my window which the user could check to show only the active tree view items or the user could uncheck it to show all active and inactive tree view items.

4- I modified the control template at line 139 and added a MultiDataTrigger which triggered on this checkbox and on my view model’s IsActive property for each data item. The image below shows this section of the TreeView’s control template which I modified: 

 
 
 
 
 

Template

Section of the TreeView Control Template which I modified