# Monday, September 22, 2008
I've had some requests from different ASP.Net developers writing applications for the OpenSocial platform lately wanting to use DevDefined.OAuth to validate signed requests with a public certificate - so I've put together a little example to help get people started.

What are we trying to do?


So first of let's review how the process works and what we're trying to achieve.

OAuthOpenSocialRequestFlow.PNG

Basically as a developer for the OpenSocial platform you will be writing gadgets - these gadgets are generally defined in an XML document providing information about your application and a chunk of html content which will be rendered into an IFrame to kick the application off (including javascript functions etc. to fetch remote content) - to work around spoofing issues and to avoid cross-scripting issues your gadget can use pre-canned functions in the open-social java-script library to make requests to your own services, which to the developer appear to be a direct request to their site.

Under the hood the the requests are instead made to the opensocial host platform, which acts as a proxy passing the request onto your application - at this point the platform employes OAuth (though without any 3-pronged delegate authority being established) to sign the request using a x509 Certificate (i.e. the RSA-SHA1 signature method) at which point it calls your application with the signed request and passed on response back to the calling gadget.

The main goals in signing the request (in so far as I can tell) are to ensure it hasn't been tampered with, spoofed and provide a Nonce and timestamp so you can void replay attacks - something that using SSL alone would not prevent.

Because a lot of the mechanics of OAuth itself is being circumnavigated, it's much simpler to verify the signature is valid.

Gadget XML


Right - onto the code - Let's take a look at the Gadget XML first:

<?xml version="1.0" encoding="UTF-8" ?>

<Module>

  <ModulePrefs title="OAuth TestBed" description="Testbed to test the OAuth library"

    title_url="http://www.devdefined.com/" author="Alex Henderson" author_email="bittercoder@gmail.com" author_affiliation="friendster"

    author_location="Auckland, New Zealand" thumbnail="" icon="">

    <Icon></Icon>

    <Locale lang="en" />

    <Require feature="opensocial-0.7" />

    <Require feature="dynamic-height"/>

    <Require feature="views"/>

  </ModulePrefs>

  <Content type="html">

    <![CDATA[

    <script>

      function makeRequest(server_url,fn){

          var params = {};

          params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.GET;

          params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.TEXT;

          params[gadgets.io.RequestParameters.AUTHORIZATION] = gadgets.io.AuthorizationType.SIGNED;

          gadgets.io.makeRequest(server_url, fn, params);

      }

 

      function renderPage(){

        var url = 'http://demo.devdefined.com/Friendster/SocialService.aspx';

        makeRequest(url, pageload_Callback);

      }

 

      function pageload_Callback(data) {

        var response;

        if(data.text){response = data.text;}else if(data.body){response = data.body;}else{response = data;}

        if(response.indexOf){

          document.getElementById('container').innerHTML = response;

        }

      }

 

      gadgets.util.registerOnLoadHandler(function() {       

          renderPage(); 

      });

    </script>

    <div id="container">

    </div>

  ]]>

  </Content>

</Module>


Basically the XML for the gadget is a chunk of metadata and finally some actual content for the gadget itself - notice that it regsters a handler to run on load of the gadget, and that it's then making a request to the url http://demo.devdefined.com/Friendster/SocialService.aspx and render the response in the inner HTML of the container div DOM element.

The key to this being an OAuth signed request is the 5th line of the makeRequest function:

    params[gadgets.io.RequestParameters.AUTHORIZATION] = gadgets.io.AuthorizationType.SIGNED;


So far so good - uploading your application is pretty easy - but is generally platform specific - if you wanted to try this out on Friendster then just head to http://www.friendster.com/developer/ click on the OpenSocial tab and follow the instructions - the approach is to save your gadget definition as an XML file somewhere, then publish that XML document on the web and then create an application in your open social host of choice and direct th it to the XML files location.  It takes all of a minute to do.


ASP.Net Application (Provider)


Now for the application itself - first off you need to locate and download the provided public key (certificate) for the social platform host and either store it on the filesystem or in the case of this demo we'll just store it as a string, like so:


public class OpenSocialCertificates

{

    private const string _friendsterCertificate =

@"-----BEGIN CERTIFICATE-----

MIIB2TCCAYOgAwIBAgIBADANBgkqhkiG9w0BAQUFADAvMQswCQYDVQQGEwJVUzEL

MAkGA1UECBMCQ0ExEzARBgNVBAoTCkZyaWVuZHN0ZXIwHhcNMDgwODEzMTgwMzQ5

WhcNMTQwMjAzMTgwMzQ5WjAvMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEzAR

BgNVBAoTCkZyaWVuZHN0ZXIwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAyVjnX2Hr

SLTyAuh2f2/OSRWkLFo3+q+l0Czb48v24Me6CsoexkPgwLOjXmPn/Pt8WtwlisQP

tZ9RX30iymg0owIDAQABo4GJMIGGMB0GA1UdDgQWBBQlDiW+HfExpSnvWqM5a1JD

C+IMyTBXBgNVHSMEUDBOgBQlDiW+HfExpSnvWqM5a1JDC+IMyaEzpDEwLzELMAkG

A1UEBhMCVVMxCzAJBgNVBAgTAkNBMRMwEQYDVQQKEwpGcmllbmRzdGVyggEAMAwG

A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADQQCXFtEZswNcPcOTT78oeTuslgmu

0shaZB0PAjA3I89OJZBI7SknIwDxj56kNZpEo6Rhf3uilpj44gkJFecSYnG2

-----END CERTIFICATE-----";

 

    public static X509Certificate2 FriendsterCertificate

    {

      get { return new X509Certificate2(Encoding.ASCII.GetBytes(_friendsterCertificate)); }

    }

}


It's worth noting that the certificates can be changed at any time - but fair warning will be given (according to the document) - and that the location (url) of the certificate is actually included as a parameter in the requests the host makes to your application (xoauth_signature_publickey) - so it's fairly trivial to implement a caching scheme to automatically pull down and update the certificate if it has changed.


Now that we have the certificate we just need to validate the request, in this cause I'm just going to check it's been signed - I've left validating timestamps and nonces out of the example, as these tend to be propritary to the app your building, but both are easy to implement.


public partial class SocialService : Page

{

    protected void Page_Load(object sender, EventArgs e)

    {

        ValidateWithDevDefinedOAuth();

 

        // now handle the request...

    }

 

    private void ValidateWithDevDefinedOAuth()

    {

        try

        {

            OAuthContext context = new OAuthContextBuilder().FromHttpRequest(Request);

            var signer = new OAuthContextSigner();

            var signingContext = new SigningContext {Algorithm = OpenSocialCertificates.FriendsterCertificate.PublicKey.Key};

 

            if (!signer.ValidateSignature(context, signingContext))

            {

                throw new OAuthException(context, OAuthProblems.SignatureInvalid, "check certificate is still valid");

            }

        }

        catch (OAuthException authEx)

        {

            Response.Clear();

            Response.Write(authEx.Report.ToString());

            Response.End();

        }

    }

}


The process is basically using the OAuthContextBuilder class to construct a context (which is used to calculate a signature base) from the current pages request.  It then constructs a signer (used for signing requests and checking their signatures i.e. validation) and a signing context, which is used to provide additional information to the signer, such as the public key of the friendster certificate.


We then invoke ValidateSignature to ensure the signature is valid - if not we throw an exception.


Finally if an OAuthException is thrown we catch it and render it's report to response stream and close it - this provides diagnostic information as per the OAuth problem reporting extension.


Hope this has been useful to some people out there - BTW I'm no OpenSocial expert, so please direct general OpenSocial questions to the apropriate google groups, I can only help with OAuth library questions.


Problems with Friendster Requests


As a side note - for anyone who's tried writing an OpenSocial application using DevDefined.OAuth to validate request signatures they may have found it didn't work! This was a result of Friendster appending an ampersand (&) to the end of the query string on the Url, which was causing the signature base to be incorrect (I'm not sure if this is an issue for other OpenSocial implementations) - The code now checks for this and removes it if discovered - and signature validation works as expected.

posted @ Monday, September 22, 2008 10:33:18 AM (New Zealand Standard Time, UTC+12:00)    Comments [0] | |
Search
FeedCount

Tags...
.Net (83) .Net Reactor (4) .net user groups (9) 2008SummerRoadTrip (1) ActiveRecord (1) architecture (1) architecture chat (95) ArchitectureCamp2007 (2) asp.net (1) Astoria (1) Auckland (1) base4 (9) batching (1) binsor (1) blog (4) boo (1) books (1) C# 3.0 (9) cambodia (9) CAML.Net (1) castle (40) china (8) codecamp (3) codeplex (3) dapper.net (1) DevDefined Ltd. (4) DirectShow.Net (1) DLR (1) DSL (4) EAUG (1) Enterprise Architect (5) Enterprise Architecture (1) Enterprise Library (1) F# (1) feedburner (2) first post (1) Friendster (1) generics (1) googlegears (1) hacks (3) hardware (3) hongkong (2) Horn (1) hyper-v (1) ideas (1) IoC (21) IronPython (13) IronRuby (2) jobs (1) Languages (2) laos (8) LINQ (7) LiveId (1) LLU (1) Local Government (1) MDA (1) MDD (1) microsoft (1) Model Driven Development (1) mono (1) monorail (2) Movies (1) Music (1) nDepend (1) news (1) NHibernate (3) NUnit (2) nvelocity (1) OAuth (6) office (1) OpenSocial (1) orcon (1) photos (1) php (1) PostSharp (1) powerpoint (1) presentations (1) ReSharper (1) REST (2) rhino commons (3) rhinomocks (5) Ruby (1) SaaS (1) scm (1) Screen Architect (0) SharePoint (5) silverlight (1) Splicer (4) SQL2008 (1) supcom (1) survey (1) svn (1) Syzmk (4) thailand (6) Tools (2) Tortoise SVN (1) trac (2) Travel (36) Unity (2) vietnam (7) vista (2) visual nhibernate (1) vmware (1) volta (3) VS2008 (1) WCF (3) wiki (2) wikipedia (1) Windows Server 2008 (1) windsor (6) WinForms (1) wix (2) WPF (2) xmlrpc (1) yahoo pipes (1)
Who am I?
Alex Henderson
Alex Henderson
Auckland, New Zealand
Managing Director at Dev|Defined Limited

"Self Confessed Coding Junky for 15 years"
View Alex Henderson's profile on LinkedIn
 
Mobile: +64-21-402-969
Email: bittercoder 'at' gmail 'dot' com
MSN: bittercoder_nz@hotmail
Skype: alex.devdefined
Navigation