Monday, March 16, 2009

OpenSocial using OAuth and ShinDig

OpenSocial is a standard to allow social websites to communicate with other social websites.
For example developers can create widgets/gadgets that can be placed on their google home page
(http://www.google.com/ig) that get contacts/friends from twitter.com.

Shindig is a java application that acts as a container for hosting these gadgets.
OAuth is the authentication standard for authenticating a user across different sites.
For extensive coverage of OAuth see, http://oauth.net/ .

In this document , I will discuss how to setup a developer's environment so that he/she can
run a sample OpenSocial gadget using OAuth.

We will need a Consumer website (site where gadget is hosted), and a OAuth Provider site (where gadget gets its data from).
We will be using Shindig as our Container Site/ OAuth Consumer for hosting this sample OpenSocial gadget.
In OAuth parlance Shindig is the Consumer site.
We will use oauth code project from google code as our OAuth Provider site, http://oauth.googlecode.com

In this example Shindig (Container Site/OAuth Consumer) will be run on port 8080.
OAuth.googlecode will be run on port 9090.

Overview of Steps

1. Download, compile/package, configure and run (via Jetty WebServer )oauth provider example site on port 9090
from http://oauth.googlecode.com
2. Download, compile, configure , and run in Eclipse IDE the Shindig (Consumer/Container site) using Jetty Webserver on
port 8080 via Maven Jetty Plugin.
3. Apply recommended edits/patches to Shindig
4. Startup OAuth Provider Site via command line.
5. Startup Shindig site via Eclipse using External Tools configuration for Jetty.


Prerequisite Software:
1. Download and Install a SVN client (i.e Tortoise SVN) , http://tortoisesvn.tigris.org/
2. Download and Install Java (JDK/JRE) 1.5 or later and set the JAVA_HOME environment variable. See, http://java.sun.com
3. Download and Install Maven (a build tool like ant but with a ton of features) , http://maven.apache.org/download.html
2. Download and Install Eclipse IDE , choose Java EE Developers Version from , http://www.eclipse.org/downloads/
3. Install the Maven2 Plugin in Eclipse
Steps:
A. Help -> Software Updates -> Find and Install
B. Search for new features to Install
C. Create a new remote update site for Maven 2 plugin
Name: Maven2 - Sonatype
Url: http://m2eclipse.sonatype.org/update/
D. Select the site and click finish
E. There are optional dependencies on mylyn and subclipse. Get them here if you don't have them.
link: http://m2eclipse.sonatype.org/update/
Otherwise, just install the Maven Integration plugin.


Detail Steps for setting up OAuth provider example site
1. Using your svn client (Tortoise SVN), download the oauth code from http://oauth.googlecode.com/svn/code/java
2. Open a command window, and navigate to download location.
3. at command line: mvn
(This will run the default build step for the oauth project, and will compile the code )


Detail Steps for setting up Shindig
Note:
Setting up Shindig in Eclipse was time consuming for me , for some reason the Maven plugin
in Eclipse didn't auto detect all the dependencies, and I had to right click on the Shindig and
select Maven - > Add dependecy -> and add each dependency listed in the pom.xml file.

Most of the steps here are from: http://incubator.apache.org/shindig/#tab-building

Setup new workspace and project

Creating a new workspace eliminates the performance cost from existing projects and makes it easier to manage the
code.
  1. File -> Switch Workspace -> Other...
  2. Select directory to store workspace
    • Do not select a parent directory of the shindig source (e.g. ~/src/shindig) as Eclipse won't allow
    • you to
      create the Java project.
    • Something like ~/eclipse/workspaces/shindig would work fine


  3. File -> New -> Java Project
    1. Name the project. The instructions below will assume "SHINDIG".
    2. Select 'Create project from existing source' and navigate to .../src/shindig/java
    3. Click Finish
    4. If you see a dialog for "Open Associated Perspective", click Ok. Don't worry about the errors after
      loading as they will be fixed in the next step.


  4. Right-click the project, select Maven : Enable Dependency Management
  5. Right-click the project, select Maven : Update Project Configuration
  6. Optionally, if you would like to be able to browse or step into the code of your dependent jars when
    debugging, you need the source jars.
  7. Right-click the project, select Maven : Download Sources and
    Eclipse will automatically know about these sources when debugging.
  8. You can browse them under Maven
    Dependencies
    in your project.
  9. If you'll be using AllTests to run tests or generate code coverage stats, adjust the project's output folders.
    1. Project -> Properties -> Java Build Path -> Source
    2. Locate and open SHINDIG/gadgets/src/test/java
    3. Select Output Folder: (Default Output Folder) and click Edit...
    4. Select Specific Output Folder
    5. Enter target/test-classes and click OK.
    6. Repeat for SHINDIG/social-api/src/test/java


Debug using Eclipse

Overview of Debugging
You will need to setup an External Tools Configuration in Eclipse to enable the Jetty WebServer.
You will also need to setup a Debugging Configuration in Eclipse.
Another reference site is: http://cwiki.apache.org/WICKET/maven-jetty-plugin.html

Setting Up External Tools Configuration

Select In Eclipse Run -> External Tools -> External Tools Configuration
Select the New Launch Configuration, name it "Maven-Jetty"
In the Main tab, fill in Location box with your Maven execution location. (i.e D:\Maven\bin\mvn.bat)
In the Main tab, fill in the Working Directory of your Shindig project. ( i.e ${workspace_loc:/SHINDIG} )
In the Main tab, fill in the Arguments box with : jetty:run-war -f pom.xml
Select the Enironment tab, click New Variable enter Name : JAVA_HOME, value: (location of your JAVA_HOME, i.e c:\SUN\sdk\jdk)
click New again, enter Name: MAVEN_OPTS,
value: -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=8080,server=y,suspend=y

Setup Debug Configuration
Select Run - Debug -> Remote Java Application. Click New Launch Configuration icon, name this: " Debug Maven Jetty".
Fill in the dialog by selecting your project: SHINDIG.
In the connection properties, set Host to: localhost, Port: 8080.



Patches to Shindig Trunk that you should apply yourself:
Patch #1
Class: OAuthRequest.java, method: fetchRequestToken
Near Line: 327
Edits:
HttpRequest request = new HttpRequest(
Uri.parse(accessor.consumer.serviceProvider.requestTokenURL));
request.setMethod(accessorInfo.getHttpMethod().toString());
//Bug - Need to Set authtype as well, otherwise AuthType always
//defaults to NONE via the HttpRequest constructor.
request.setAuthType(realRequest.getAuthType());

Patch #2
Class: OAuthRequest.java, method: createHttpRequest
Near Line: 485
private HttpRequest createHttpRequest(HttpRequest base,
List<Map.Entry<String, String>> oauthParams) throws OAuthRequestException {

OAuthParamLocation paramLocation = accessorInfo.getParamLocation();

// paramLocation could be overriden by a run-time parameter to fetchRequest

//bug alert: no need afaik to create a new HttpRequest instance,
//since we pass it the base HttpRequest instance in as a parameter
//The use case of having an authType other than NONE is a real use case
//If we leave this line in then the authType always gets overriden to NONE
//via this constructor new HttpRequest(base)
//HttpRequest result = new HttpRequest(base);
HttpRequest result = base;
// If someone specifies that OAuth parameters go in the body, but then sends a request for
// data using GET, we've got a choice. We can throw some type of error, since a GET request
// can't have a body, or we can stick the parameters somewhere else, like, say, the header.
// We opt to put them in the header, since that stands some chance of working with some
// OAuth service providers.
if (paramLocation == OAuthParamLocation.POST_BODY &&
!result.getMethod().equals("POST")) {
paramLocation = OAuthParamLocation.AUTH_HEADER;
}

switch (paramLocation) {
case AUTH_HEADER:
result.addHeader("Authorization", getAuthorizationHeader(oauthParams));
break;

case POST_BODY:
String contentType = result.getHeader("Content-Type");
if (!OAuth.isFormEncoded(contentType)) {
throw responseParams.oauthRequestException(OAuthError.INVALID_REQUEST,
"OAuth param location can only be post_body if post body if of " +
"type x-www-form-urlencoded");
}
String oauthData = OAuthUtil.formEncode(oauthParams);
if (result.getPostBodyLength() == 0) {
result.setPostBody(CharsetUtil.getUtf8Bytes(oauthData));
} else {
result.setPostBody((result.getPostBodyAsString() + '&' + oauthData).getBytes());
}
break;

case URI_QUERY:
result.setUri(Uri.parse(OAuthUtil.addParameters(result.getUri().toString(), oauthParams)));
break;
}

return result;
}

Startup OAuth Provider Site via command line

1. Open a command window, and change directory to download location of oauth
2. at command line: cd example/oauth-provider
( This is the main directory for the sample oauth-provider website )
3. at command line: mvn -Djetty.port=9090 jetty:run-war
(this will run the oauth-provider website using the jetty webserver on port 9090)

Startup Shindig site via Eclipse using External Tools configuration for Jetty

Prerequisite: Create consumer key file using OpenSSL from the command line. Download at: http://www.openssl.org/related/binaries.html
1. Open Command Line and run:
openssl req -newkey rsa:1024 -days 365 -nodes -x509 -keyout testkey.pem -out testkey.pem -subj '/CN=mytestkey'
2. From Command Line run:
openssl pkcs8 -in testkey.pem -out oauthkey.pem -topk8 -nocrypt -outform PEM
3. copy oauthkey.pem to : Shindig\java\server\src\main\webapp\WEB-INF
4. Edit Shindig\java\common\conf\shindig.properties and edit shindig.signing.key-name and shindig.signing.key-file
# OAuth confiugration, including the key file for signing requests
# The URL base to use for full OAuth support (three-legged)
shindig.oauth.state-key=
shindig.oauth.base-url=/oauth/
shindig.oauth.authorize-action=/WEB-INF/authorize.jsp
shindig.signing.key-name=mytestkey
shindig.signing.key-file=/WEB-INF/testkey.pem

Steps:
1. Assuming you have the Shindig project open in Eclipse,
select Run - > External Tool Configuration -> select "Maven-Jetty" ( created in the "Setting Up External Tools Configuration" above)
2. Next if you want to debug and set breakpoints,
select Run -> Debug Configurations -> select " Debug Maven Jetty" configuration.
( created in the "Setup Debug Configuration" step above.

This is a intial draft, so let me know if additional comments or steps should be added.
Have fun with OpenSocial and Shindig!