Monday, August 24, 2009

How to check signature in MySpace iframe application (.net version)

It was a kind of headache for me after I decided to add checking signature to our MySpace application. I couldn't make it work using existing tools like the MySpaceToolkit. But eventually I was able to do it myself. I cannot say it was painless. There were several examples in php like this one, that could bring even more questions than answers. But they meant to be working and my code started working too though having eaten a plenty of my time. Here is the complete code:

private static string GenerateIFrameSignature(HttpRequest req, string secretKey)
{
    const string c_unreservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";

    // We cannot use the HttpUtility.UrlEncode method because it produces lowercase output as OAuth requires uppercase.
    // The code of the delegate was extracted out of MySpaceToolkit library.
    Func UrlEncode = (value) =>
    {
        StringBuilder result = new StringBuilder();

        foreach (char symbol in value)
        {
            if (c_unreservedChars.IndexOf(symbol) != -1)
            {
                result.Append(symbol);
            }
            else
            {
                result.Append('%' + String.Format("{0:X2}", (int)symbol));
            }
        }

        return result.ToString();
    };

    var sortedKeysWOSig = req.QueryString.AllKeys.Where(k => k != "oauth_signature").OrderBy(k => k);
    var query = new StringBuilder();

    foreach (string key in sortedKeysWOSig)
    {
        if (query.Length > 0) query.Append('&');

        query.Append(UrlEncode(key))
        .Append('=')
        .Append(UrlEncode(req.QueryString[key]));
    }

    StringBuilder @base = new StringBuilder();
        @base.Append("GET&")
        .Append(UrlEncode(req.Url.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.Unescaped)))
        .Append('&')
        .Append(UrlEncode(query.ToString()));


    using (KeyedHashAlgorithm alg = HMACSHA1.Create())
    {
        //according to http://oauth.googlecode.com/svn/spec/core/1.0/oauth-core-1_0.html#rfc.section.9.2 we should concat [Consumer Secret] + & + [Token Secrect]. The latter one is not provided by MySpace. So we imply empty string in this place.
        alg.Key = Encoding.ASCII.GetBytes(secretKey + "&");

        byte[] dataBuffer = Encoding.ASCII.GetBytes(@base.ToString());
        byte[] hashBytes = alg.ComputeHash(dataBuffer);

        return Convert.ToBase64String(hashBytes);
    }
}

There is no reason to use the UrlEncode as delegate except placing it in a single method for readability of this post.

After comparing signature out of 'oauth_signature' query string parameter and the one the method above returns you can also verify auth timestamp to be up to date:

private const string _oauthTimestampKey = "oauth_timestamp";
private static readonly TimeSpan _staledInterval = TimeSpan.FromMinutes(10);
private static readonly DateTime _stDate = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

...

long authTime;
if (!Int64.TryParse(request.QueryString[_oauthTimestampKey], NumberStyles.Any, CultureInfo.InvariantCulture, out authTime))
{
    #region Logging
    if (_log.IsDebugEnabled) _log.DebugFormat("Couldn't parse oauth_timestamp value {0}", authTime);
    #endregion
    return false;
}

var now = DateTime.UtcNow;
DateTime time = _stDate.AddSeconds(authTime);
if (now - time > _staledInterval)
{
    #region Logging
    if (_log.IsDebugEnabled) _log.DebugFormat("Auth time was too late. Expected greater than {0}. Actual was {1}", now - _staledInterval, time);
    #endregion
    return false;
}

Wednesday, June 10, 2009

How to run a shell command in the background on windows

If you are dealing wih unix os you can run command in background merely adding & in shell:

sleep 2 &

Recently I did need this functionality as I was debugging a web application crashes on our live servers. Being in terminal session I run the adplus script to catch crashes for a specified process:

adplus -crash -p <pid>

The script attaches debugger to a process making the debugger monitor exceptions. It could take a long while till we catch anything. I needed to leave my terminal session unattended or forcibly close it to proceed my regular routines. An unattended or disconnected session can be logged out according to a policy set by administrator, but the running script stuck to my session.

Fortunately, windows users have the magic 'at' command that schedules commands at a specified time. So we can run our debugging script in the background just by passing it the scheduler:

at <time> cscript "<fullpath-to>\adplus.vbs" -quiet -crash -p <pid>

We need the -quiet option to skip initial dialog box the script shows when attaching a process. We use absolute path to the adplus because the current directory for the executing command is the systemroot folder. Our command will be executed under System user. It's enough for debugging. But be careful when you rely on this, e.g. when you connect to sql server using integrated security.

I set the time parameter a minute ahead and the task is appointed on today.

Friday, March 27, 2009

DevSmtp server released

Have you ever debugged sending emails from your application? I have many times. Users of your website pay for goods and then they should be sent a notification. The conditions to test receiving mails can be uneasy. User account email should be valid and you are allowed to connect to smtp server or have your local smtp that might be considered by the remote one as unreliable and your mail will be rejected or cut off by a spam filter.

As a developer I always wanted a reliable tool for checking the both things: to ensure the email is sent and see how the email looks like for user.

Besides Windows Vista doesn't have an smtp server. So I decided to implement it on my own. It wasn't a real world project and I didn't have tight schedule, so I chose to refresh my C++ skills that had been more academical than practical and to write a server using I/O Completion Ports.

I use github to host the project. There you can either download the project source code and compile it in VS 2008 or get a precompiled binary.
  1. In order to run in console mode put devsmtp.exe in an appropriate location and execute: devsmtp -c
  2. to register as windows service, execute: devsmtp -i (to uninstall, use devsmtp -u)
Now start testing you programs. If you want to verify a message is sent, run DebugView utility and you will see smtp communication protocol messages between your application and the server. After the message is on the server, it will be stored in a folder under devsmtp.exe location named with from email.

So you can double click on the eml file and see it in embedded viewer.

Attention. The server doesn't send mails to recipients. It serves for the debugging purpose only.

Have fun!

Tuesday, January 27, 2009

How to fix Windows SDK Configuration Tool

There are many posts out there pointing out that Windows SDK Configuration Tool contains a bug. When I first met the issue I googled hither and thither but did find a solution for Visual Studio 2005. The workarounds did not work for me and were too clumsy to use them on a regular basis.

Eventually I decided to dig into its code - fortunately WindowsSdkVer.exe is a .net assembly. Therefore, bingo, we can use .net reflector to infer its sorce code. It wasn't too difficult. To that end, the reflector contains an option to export an entire assembly as the visual studio project:

 Export an assembly

The exported WindowsSdkVer project contained a dependency, the library VCIntegrate.dll, that can be found in the same folder as WindowsSdkVer.exe itself lies. I added the library to the project references and could build and run it.

Running the project on my Vista x64 I quickly found my issue. It was in the Utility.cs file, the GetInstalledProduct method:

foreach (string str in key.GetSubKeyNames())
{
    RegistryKey key2 = key.OpenSubKey(str);
    Product newProduct = new Product();
    try
    {
        newProduct.SdkVersion = str;
        if (!string.IsNullOrEmpty(productVersionKey))
        {
            newProduct.Version = new Version(key2.GetValue(productVersionKey).ToString());
            newProduct.Version = new Version(key2.GetValue(productVersionKey).ToString().Replace("v", "").Replace("A", ""));
        }
        else
        {

The problem is that the Version class can't parse version given as the value of v6.0A being in my windows registry under the following key: HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432NODE\Microsoft\Microsoft SDKs\Windows\v6.0A\ProductVersion.

Stripping leading and ending characters helped somehow. But the code seemed to contain various issues. The next one I met was in VersionSelector.cs, the GetInstalledVisualStudioVersions method:

foreach (Product product in products)
foreach (Product product in new List<Product>(products))
{
    float num;
    if (float.TryParse(product.SdkVersion, out num))
    {
        if (num < 8f)
        {
            products.Remove(product);
        }
    }
    else
    {
        products.Remove(product);
    }
}
return products;

Guess what a problem may raise up here? Who did write this?  You can't delete from a collection during looking it through by enumerator.

And at last for those having a non-english windows you have to add a line into the Program.cs file:


[STAThread]
private static void Main(string[] args)
{
    Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
 
    Mutex mutex = null;

It is required to parse numbers correctly.

You should place the compiled execution over the existing one to ensure that all its functionallity works properly. That because the program relies on files lying around.

If you somehow trust me, you can download the patched utility directly.