# Monday, November 17, 2008
Cibrax (Pablo M Cibrano) - has supplied an example WCF Provider sample, including a generic Request Interceptor suitable for OAuth enabling your own RESTful WCF services.

The code is available in these two new projects (as part of the DevDefined.OAuth library).
The implementation has been covered on his blog here in a couple of posts:
Thanks for the contribution Cibrax - much appreciated!

Take a look at the devdefined-tools site for more details on this library, and for those who are curious this code is all released under the MIT license.

.Net | OAuth | WCF
posted @ Monday, November 17, 2008 9:16:14 AM (New Zealand Daylight Time, UTC+13:00)    Comments [0] | |
# 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] | |
# Monday, September 08, 2008
You may recall a few months back I released an OAuth library for .Net (which can be found here on google code) - at the time of writing that library the only other OAuth "solution" for .Net developers was a C# file containing some simple helper functions, that didn't even produce valid results in many cases, and the rather basic implementation as part of the restful chess/myspace example.

Well the guys at Madgex in the UK have now released their own OAuth.Net library.. for more details you can:
As for differences between the two implementations... from a 50K foot glance.
  • There's a dependency on the Windsor container when using the Madgex library (if you want to use it's out the box implementation / configuration examples etc.)
  • The Madgex library includes a http module for making a provider implementation easier when building web apps.
  • The madgex library appears to take a harder dependency on HttpRequest then the DevDefined library (but that's just a hunch, saw it in a few interface definitions, rather then some wrapper equivalent).
  • The madgex library looks a little more polished (i.e. xml docs) and has a configuration section.
  • The Madgex library features some niceities like Sliding window validation support (i.e. they only allow messages to be supplied where the timestamp falls within a certain time window of the server, and keep the list of previous nonces only for the period of that window - flushing nonces that are not longer required via a background thread - saving on the volume of nonces to record i.e. for replay attacks).  Of course it's an in-memory solution, so not suited to farms, but still cool.
  • Slightly less fluent consumer implementation, I prefer my libraries consumer implementation, but of course that's just me :P
  • Both libraries are under the MIT license.
All said and done it's a very sound effort, great work guys! And it's awesome to have some choice emerging in this space.




posted @ Monday, September 08, 2008 10:11:11 PM (New Zealand Standard Time, UTC+12:00)    Comments [2] | |
# Wednesday, August 27, 2008
It's been a back and forth discussion on the OAuth list for a while now - and with some people (zealots? ;o) having ideas they weren't even willing to contribute to the OAuth group until the IPR was sorted I'm glad to finally see it's been completed, this should hopefully help to improve the longevity and adoption of the standard by some who have been fence sitting.

So what's happened?

Well all all parties involved in building the original spec have signed an agreement of non-assertion, so now OAuth can be safely implemented anywhere without concern about lawsuits related to the IP in the spec.

OAuth is a pretty elementary standard in it's version 1 state - so in some ways it was inevitable that this would happen (or at least I thought so) - there wasn't much to gain by any of the contributors blocking the progress of it becoming an open standard - but it's involved a lot of work to get it there by all accounts, so full credit goes to all involved!

For a detailed writeup check out the post from Eran Hammer-Lahav or the post on Read/write web.

Conspicuous by it's absence is Microsoft, but for no other reason than they did not contribute to the OAuth standard - and so didn't have to sign - but of course LiveId does tackle delegated authentication - so in some ways they have a competing platform for handling delegation, presumably because OAuth doesn't provide a rich enough set of features at this stage to handle some of the more complex scenarios around scalability, signing message bodies etc. - though I'm just hazarding a guess, LiveId was presented at the OAuth summit earlier this year.

.Net | LiveId | OAuth
posted @ Wednesday, August 27, 2008 1:24:58 PM (New Zealand Standard Time, UTC+12:00)    Comments [0] | |
# Wednesday, June 11, 2008

OAuth for Beginners

For those unfamiliar with OAuth, here's a very short run-down... I'm skipping over some of the details but I think this should give you a taste for what it's all about - for a more well rounded introduction, check out this article on the OAuth.Net website.

The participants

Consumer - "weitu.googlepages.com" - that application that wants to see protected information the provider has for a user.
Provider - "google.com" - the keeper of a users protected information.
User - a user who stores protected information with the provider (say contacts in gmail)

The goal

To allow the user to give a consumer access to their data on the provider without the user having to disclose their credentials (username & password) and to allow for fine-grained control over access granted to an individual consumer - i.e. putting power in the hands of the user to revoke access when they want to, and having it only affect one consumer.

A consumer needs to be known to a provider before they can request a token.

How it works

(For this example we'll use google, for more info on the google implementation see this thread)

The provider publishes 3 Urls for their service and documents them on their site somewhere:
The consumer is known to google by it's consumer key (which in the case of a google api is normally a host address, like www.test.com) and this relationship is established in a proprietary manor (i.e. it's not covered by the OAuth spec).

Getting a Request Token

The start the ball rolling the consumer makes a request to the Request Token Url, they get back some form-encoded parameters in the body of the response which contains the token information.

As an example, here's an http request to get a new request token:

GET /accounts/OAuthGetRequestToken?
  scope=http%3A%2F%2Fwww.google.com%2Fm8%2Ffeeds
  &oauth_nonce=759437c3-3edf-4098-ac14-58d4f162b0e6
  &oauth_consumer_key=weitu.googlepages.com
  &oauth_signature_method=RSA-SHA1
  &oauth_timestamp=1213129078
  &oauth_version=1.0
  &oauth_token=
  &oauth_signature=peUZigwq1BLs%2Bb721vcct2vzA3Odk1j...

HTTP/1.1

Host: www.google.com
Connection: Keep-Alive

And here's the response:

HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Date: Tue, 10 Jun 2008 20:18:01 GMT
Expires: Tue, 10 Jun 2008 20:18:01 GMT
Cache-Control: private, max-age=0
Content-Length: 51
Server: GFE/1.3

oauth_token=CMiJx-LdFxD56bOXAQ&oauth_token_secret=

Notice the oauth_signature and other oauth_ etc. parameters - as part of the OAuth core specification it requires that requests be "signed" so that a provider can ensure they haven't been tampered with - this is one of the aspects my library will take care of for you (signing and verifying requests).

User Authorization

At that point the consumer now needs to send the user off to the providers site - this involves using the second of the 3 urls, the User Authorize Url... we just append the scope (required by google, identifies the service you wish to access - not part of OAuth spec itself) and the request token (CMiJx-LdFxD56bOXAQ)

Note that the User Authorize Url isn't signed like the other requests... this is because this step may be manual i.e. a user typing or copying a link into their browser or some hand held device.

GET /accounts/accounts/OAuthAuthorizeToken?
  scope=http://www.google.com/m8/feeds
  &oauth_token=CMiJx-LdFxD56bOXAQ

HTTP/1.1

In this case, google takes us to a universal login page:

google_login.jpg

Once authenticated it then takes us to a page where we can authorize the consumer to have access:

google_authorize.JPG

By granting access at this point the consumer can then use the last of the 3 Urls, the Access Token Url, to exchange their request token for an access token. Upon granting access a few things should happen:
  • An access token should be created.
  • The access token should be related to the request token.
  • The currently logged in user should be associated with the access token.
The last point is important - because you're passing tokens around, rather than account names, you need to have the provider implementation record the association between the access token and the user granting access - and it should be easy for your API implementation to fetch the associated user when a protected resource is accessed.

Exchanging Tokens

Once the user has authorized the consumers access request, the consumer can then exchange their request token for an access token - generally a request token can only be used once - so if the request failed for some reason they would need to start the authorization process again from scratch.

here's the http request for exchanging tokens:

GET /accounts/OAuthGetAccessToken?
  scope=http%3A%2F%2Fwww.google.com%2Fm8%2Ffeeds
  &oauth_token=CMiJx-LdFxD56bOXAQ
  &oauth_nonce=19fe6f62-8b2c-4a40-b055-210d279ba770
  &oauth_consumer_key=weitu.googlepages.com
  &oauth_signature_method=RSA-SHA1
  &oauth_timestamp=1213129477
  &oauth_version=1.0
  &oauth_signature=hagokrS1W%2BcBXdRwTIlOd84PSO56OT...

 HTTP/1.1 Host: www.google.com

And the corresponding response from the google server:
 
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Date: Tue, 10 Jun 2008 20:24:39 GMT
Expires: Tue, 10 Jun 2008 20:24:39 GMT
Cache-Control: private, max-age=0
Content-Length: 57
Server: GFE/1.3

oauth_token=CNO384n8BRD6pZTT_P____8B&oauth_token_secret=

Accessing a Protected Resource

Now that the consumer has an access token they can then make requests for protected resources - they just need to use the access token, here's an example of doing just that:

GET /m8/feeds/contacts/default/base?
  scope=http%3A%2F%2Fwww.google.com%2Fm8%2Ffeeds
  &oauth_token=CNO384n8BRD6pZTT_P____8B
  &oauth_nonce=3ae44855-9d27-4b80-8b4f-2f68d1531657
  &oauth_consumer_key=weitu.googlepages.com
  &oauth_signature_method=RSA-SHA1
  &oauth_timestamp=1213129479
  &oauth_version=1.0
  &oauth_signature=kTFRbcD1IKzjPADfgF%2B3...

HTTP/1.1 Host: www.google.com

Obviously once the request has been validated (i.e. valid signature, valid token, valid timestamp range, nonce is unique etc.) the provider implementation needs to fetch the user associated with the access token, so it can then return the correct data back to the consumer - normally you would want to automatically associate the token's user with the current request / controller / channel so that OAuth is basically transparent (i.e. it's just like getting a request from a user who's authenticated normally).

Risks & Issues

One obvious risk is that of phishing... if the consumer sends you to a site that looks like googles authentication page, but isn't google then you're in trouble.  Of course this kind of phishing is more a general problem, then something isolated to OAuth.

Another potential risk are that some signature methods are risky/flawed to the consumer due to implementation i.e. if you have a flickr uploader winforms application, and you use RSA-SHA1, the uploader will need to ship with the x509 certificate (including the private key) in their application ... this basically invalidates the strength of that certificate, because anyone could extract and use the private key themselves (so it's as bad as a plain text signature) - on the flip side for a website RSA-SHA1 is very strong because the private key is kept private.



posted @ Wednesday, June 11, 2008 9:26:02 AM (New Zealand Standard Time, UTC+12:00)    Comments [6] | |

DevDefined.OAuth

I have a first release of my OAuth implementation up on google code, you can read a little more about it here and the code can be found here.  It's released under the MIT license, basically do what you like with it.

The library includes both consumer and a provider implementations - test coverage is pretty poor, as it was originally put together as part of my REST presentation to the local Ellerslie .Net user group a few weeks ago, but as I work through the code and rewrite various sections in my spare time it should become a little more robust.

If you're serious about using this code then I would suggest reviewing the OAuth core spec 1.0 and the OAuth problem reporting extensions.

The OAuth wiki and google group are also great places to learn more about OAuth.

I have not added the MonoRail examples back to the code yet - but will shortly - and will probably provide a WCF implementation as well.

I've also posted a short intro to OAuth - OAuth for beginners - for those who are interested.
posted @ Wednesday, June 11, 2008 7:37:58 AM (New Zealand Standard Time, UTC+12:00)    Comments [1] | |
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