Monday, May 28, 2012

Windows Command Line Hash Check

Knowing that, "Linux has been doing this for years" I decided to add make a command line method for checking the MD5 and SHA hashes of downloaded files. I used PowerShell to create a function and added it to my profile so that I can call it whenever I want. First, the code for the function:


function Check-Hash {
param
(
 $file,
 [switch]$SHA1 = $false,
 [switch]$SHA256 = $false,
 [switch]$MD5 = $false
)

function computeHash {
$stream = New-Object System.IO.FileStream($file, [System.IO.FileMode]::Open)
$stringBuilder = New-Object System.Text.StringBuilder
$hash = $algo.ComputeHash($stream) | % { [void] $stringBuilder.Append($_.ToString("x2")) }
$stringBuilder.ToString()
$stream.Dispose()
}

if ($SHA1) {
  $algo = New-Object System.Security.Cryptography.SHA1Managed
  Write-Host "SHA1: " -NoNewline ; computeHash
 }
if  ($SHA256) {
  $algo = New-Object System.Security.Cryptography.SHA256Managed
  Write-Host "SHA256: " -NoNewline ; computeHash
 }
if ($MD5) {
  $algo = New-Object System.Security.Cryptography.MD5CryptoServiceProvider
  Write-Host "MD5: " -NoNewline ; computeHash
 }

}
You can save this as Check-Hash.ps1, which matches the function name. Next, you can add the path to the .ps1 file to your profile, so that when you start up PowerShell, you'll have this function by default. The link to edit your profile can be found here:

http://msdn.microsoft.com/en-us/library/windows/desktop/bb613488(v=vs.85).aspx

Once added, you can check the hash of a file you downloaded, using any combination of the algorithms. The syntax is, "Check-Hash -filename -SHA1 -SHA256 -MD5". Here is an example of a download and it's matching hash:


Tuesday, May 1, 2012

SharePoint and Reverse Proxies

Recently, I designed a SharePoint 2010 solution that involved an extranet scenario where the intranet portal would be accessed both from inside and outside of the LAN. The portal had to meet the following requirements:


  1. Be securely accessible from outside of the corporate network.
  2. Users should only type one URL and not have to specify port or protocol.
  3. When inside the corporate network, users should not be using SSL (HTTPS).
  4. User experience on the extranet should match the intranet.
I chose Forefront UAG 2010 SP1 to meet the extranet needs. It can provide the security they required as well as would assist with reverse proxying, which would allow the users to not have to deal with specifying different URLs, ports, or protocols.

The Setup

From a high level, the setup put the UAG server on the edge network and split DNS was used so that the URL would route straight to the SharePoint server from inside the network and to the UAG server when outside of the network. 


With this setup, SharePoint pages were served up through UAG and if a user didn't specify HTTPS, the UAG server would redirect all the links to SSL... or so we thought.

The Issue

During testing, it was noticed that on the My Sites page, users' pictures were not displaying in the out-of-the box Silverlight Organizational Chart web part and were instead replaced with a "green shirt" icon different from the one displayed when a user has no picture uploaded. This was only occurring when accessing the site through UAG and only with the org chart web part. Profile pictures showed up in other places.


I opened up Fiddler to check out what was going on, and discovered that the link for the picture in the Siliverlight app was coming through as HTTP in the JSON code, and was not being converted to HTTPS by UAG.


The Explanation

UAG does not inspect the packets coming across it for SSL redirects; they are only done in the headers. The image URL for this web part was inside of the JSON code, which UAG does not alter. Pictures showed up fine in other places because they are loaded into the page with GET requests, which UAG does alter. I needed to find a way to force SharePoint to send SSL URLs to users accessing through UAG, but not accessing it from the corporate network. I also had to make sure that the users didn't have to type a different URL, port, or protocol.

The issue lied with both SharePoint and the UAG server. Since UAG was acting as a reverse proxy, what would happen was:

  1. User types, "my.vmlab.loc" into the browser.
  2. UAG redirects to "https://my.vmlab.loc" and forces user to log in.
  3. Once logged in, the UAG server initiates a new connection to the SharePoint farm on behalf of the user with non-SSL. That is, "http://my.vmlab.loc."
  4. SharePoint sees this request coming in over port 80 with a host header of, "my.vmlab.loc" and directs it to the IIS site hosting My Sites.
  5. SharePoint sends the requests back to the UAG server as, "http://my.vmlab.loc", which then sends it back to the user as "https://my.vmlab.loc."
The kink in this process is that SharePoint always believes all requests are coming from, "http://my.vmlab.loc." This is correct in that both internal network users and UAG are not expecting to communicate over SSL. The problem is URLs generated from scripts that are not redirected by UAG are getting sent back to the client with the wrong protocol.

The Fix

The trick to keeping all the requirements of the portal and serving up the pages correctly lies with both UAG and SharePoint. What is needed is a way to tell SharePoint that UAG requests are "different" and need special treatment. On the SharePoint end, this can be accomplished using Alternate Access Mappings (AAM). This will tell SharePoint that if it receives a request from a certin URL, in this case what UAG sends it, to send out a different URL. When SharePoint generates URLs inside of scripts, it will send out something different from the originating URL it received. I needed to rework the process above to achieve the following:

  1. User types, "my.vmlab.loc" into the browser.
  2. UAG redirects to "https://my.vmlab.loc" and forces user to log in.
  3. Once logged in, the UAG server initiates a new connection to the SharePoint farm on behalf of the user with non-SSL. This time, UAG will send down a "dummy" host header so that SharePoint knows that the request is coming from UAG. In this example, I went with, "ext.my.vmlab.loc."
  4. SharePoint sees this request coming in over port 80 with a host header of, "ext.my.vmlab.loc" and directs it to the IIS site hosting My Sites because of the AAM.
  5. SharePoint sends the requests back to the UAG server as, "http://ext.my.vmlab.loc", which then sends it back to the user as "https://my.vmlab.loc."
The key point here is that with the AAM in place, when SharePoint gets a request with the host header of, "ext.my.vmlab.loc" it will generate scripts using the public URL we specify. 

Here is a picture of how the AAM was setup initially:


To change this, we need to extend the My Sites web application with a zone that uses the dummy host header. An example of what I chose is below:


You can double check IIS to see the result of your change:



From here, you need to change the AAM so they match something similar to this:


Note that SharePoint now knows to send out, "https://my.vmlab.loc" when it gets requests with, "ext.my.vmlab.loc" as its host header. This setup will not break functionality from within the network, as the AAM for "http://my.vmlab.loc" still maps to non-ssl and does no altering.

Next, we have to head over to the UAG server and change it so that it alters the host header on the way in and out for SharePoint. Here is a picture of how it was setup before the changes:


And here is the spot you'll need to change to make sure this magic happens:


Once these changes are applied, the pictures in the web part will load correctly:


Bonus: Confirmation

As a bonus, you can see what's going on underneath. Here is a picture of the JSON packet from Fiddler, which now displays the correct URL:


You can also see that with a regular picture GET, the machine is using, "my.vmlab.loc" as the host header and getting back SSL URLs:



Lastly, I took a capture with WireShark on the UAG server to show how it sees things. As you can see in the picture below it is changing the host header to the dummy one: