Enabling OAuth in Shindig
In order to fully enable oauth support in shindig, production-worthy mechanisms to store client secrets and authorization tokens must be implemented. The sample shindig version is able to provide OAuth authentication for gadget data requests, but requires significant work to add secrets and will loose tokens each time the server is restarted. It's also unsuitable for use if more than one shindig instance is set up for the same domain.
Configuring the current version
To enable preliminary testing, oauth support can be enabled by editing the config/oauth.json file. This file lists the consumer secrets that a gadget uses to communicate with a given service. For example, assume the gadget at
http://one.author.com/niftyGadget.xml has the following service declared in its xml file:
Then an entry like the following is needed in the config/oauth.json file:
Where the data
("consumer_key", "consumer_secret", and "key_type") was negotiated previously between the gadget author and some-server.com. The container's only role in this is to receive that data as part of adding niftyGadget to the application directory and store it, either in this file or in the production quality store.
After adding this configuration (and redeploying and restarting the server) niftyGadget should be able to make OAuth data requests to some-server.com.
Enabling OAuth for production use
To enable production quality support for OAuth, an implementation of the interface OAuthStore is needed. This store needs to be able to:
- Store oauth authentication data
(key, secret, key_type)indexed by
(gadget, server)pairs. Shindig only needs read access to this store. Adding secrets here is a responsability of the container's application directory handling.
- Write/read/delete OAuth tokens, indexed by
(owner, viewer, gadget, server), where
(owner, viewer)are the usual opensocial users.
This second part of the store needs to be available to all shindig instances, but it need not be readable by any other part of the container infrastructure and it can be auto-expiring (as long as it respects the oauth token's validity times).
The store can (and should) implement caching, of course making sure all shindig instances are notified of stores and deletes (maybe simply
by having them all use the same cache )
Once this store is written, it needs to be registered in a new Guice module. The new Guice module can reuse some parts of OAuthModule.
The OAuthCrypterProvider is used to provide encryption for some client-side state. The Shindig implementation is suitable for production use, provided that you share a shindig.oauth.state-key file across all of your servers. The contents of that file should be a long (20 or 30 characters) secret string. If your organization has standard procedures for managing secret keys in production servers, you should replace OAuthCrypterProvider to hook into a custom implementation of BlobCrypter.
The OAuthRequest class is suitable for production use. If you need to add additional parameters to OAuth signed requests beyond the standard opensocial parameters, you will want to write your own provider, or possibly your own implementation of RequestPipeline.
The BasicOAuthStore class is not suitable for production use. You need to tie into a persistent storage system.
Enabling server-side OAuth for the REST api
To enable the REST api, support for server side OAuth is required. This is not three-legged core OAuth, but the two-legged "Consumer extension". The basic idea behind this is:
- The gadget author's servers need to request/send data to the container. They send an OAuth-signed REST call that says: "I'm gadgetABC, requesting access with viewerID 5678".
- Shindig validates the OAuth call.
- Shindig checks authorization. How to do this is a policy decision on the container's part. At the least, it should include checking that user 5678 has installed the ABC gadget, but more checks could be made.
- The request then goes on to the rest of shindig and the data is returned.
The gadget needs to have a consumer key and secret to use for point 1). This key and secret must be generated by the container and provided to the author at gadget registration time.
The pieces that require Java implementation are 2) and 3). In order to do this, a java class implementing
OAuthLookupService needs to be written. This java class needs access to whatever store is used for the gadget's key and secret, in order to validate the call, as well as implement whatever logic it needs to process the authorization policy.
A very simple implementation, with hardcoded keys and secrets to a pair of fictitious gadgets is in
SampleContainerOAuthLookupService. This class is obviously not production ready, but it shows the required functions and shows the adecuate calls to the OAuth library needed to validate the call.