Thursday, November 05, 2009

A bug in Shindig code (for revision 832845)

Recently, I tried to deploy cyberaide filetransfer gadget (http://lily01.rit.edu/cyberaideFiletransfer.xml) and jobman gadget (http://lily01.rit.edu/cyberaideJobman.xml). They did NOT work in shindig server built from revision 832845. Those two gadgets use ‘tab’ feature which is not implemented well in shindig code.

Problem description
See source code of tab feature at http://svn.apache.org/repos/asf/incubator/shindig/trunk/features/src/main/javascript/features/tabs/tabs.js?p=832845.
In this file, function ‘html_sanitize’ is used. It is a function from caja javascript library.
Shindig website does not provide much useful information about integration of caja. http://incubator.apache.org/shindig/developers/java/build.html#Running_with_Caja
I found a useful wiki page in caja project: http://code.google.com/p/google-caja/wiki/GettingStarted.
Basically the user needs to add following text to ModulePrefs element of the gadget xml file
    <Require feature="caja"/>
After I changed the gadget xml file, it still didn’t work. It seems that after caja library sanitizes the rendered html/javascript code, some useful code is removed.

My solution
To make it simple, I disabled caja. I just removed invocations of functions belonging to caja library. Concretely, I removed invocations of function ‘html_sanitize’ in file ‘tab.js

Also, feature ‘minimessage’ also uses caja functions to sanitize html/javascript. If your gadgets use that feature, corresponding changes must be made as well.

Monday, November 02, 2009

X connection to localhost:xx.x broken (explicit kill or server shutdown)

When I run tomcat server, I got this weird problem. It seems that tomcat tries to access GUI, which is contrary to my thought that tomcat is a background daemon.

A simple google search brought me lots of posts about this problem: http://www.google.com/search?hl=en&client=firefox-a&rls=org.mozilla%3Aen-US%3Aofficial&hs=ugP&q=tomcat+connection+to+localhost%3A+broken+%28explicit+kill+or+server+shutdown%29&aq=f&oq=&aqi=

According to suggestion from this post http://bugs.mysql.com/bug.php?id=24226, I just unset environment variable *DISPLAY* in *startup.sh*.
In bash, use *unset DISPLAY*

Enable and disable Shindig caching

Shindig implements a complex caching hierarchy including referred external resources, locale messages, gadget specification files, etc.
During development phase, the developers want to disable caching to make modifications take effect immediately.

  • Build-Time Solution
    It is according to this post https://studio.atlassian.com/browse/AG-145.
    Download source code tree and build the war file using command “mvn –Pdebug package
  • Run-time solution
    HttpCache: caches http request sent out from shindig server. During gadget rendering, this is controlled by “nocache” parameter. So when you render a gadget, add parameter ‘nocache’ with value 1.
    I don’t know how to do it at server side.

Saturday, October 31, 2009

Thursday, September 24, 2009

Trial of Apache Sling

Introduction

Sling is based on Felix which is an implementation of OGSi. It includes Felix webconsole (http://felix.apache.org/site/apache-felix-web-console.html) bundle to make it easy to inspect OSGi framework. Also Sling integrates Jackrabbit and wraps it as an OSGi bundle. To update Java Content Repository, the client app can send regular HTTP POST requests. In other words, it exposes Java Content Repository in a REST way.
It can be run either independently or in a servlet container (e.g. Apache Tomcat).

Resources

Sling: http://sling.apache.org/site/index.html
Useful Sling help: http://felix.apache.org/site/apache-felix-framework-usage-documentation.html
Install and upgrade bundles in Felix web console: http://sling.apache.org/site/installing-and-upgrading-bundles.html
Address of Felix Management Web Console: http://ip_address:port/system/console/


When I clicked “Configuration” link on the top, Null Pointer Exception was thrown out.
It turns out that this is problem of Felix webconsole. See
http://issues.apache.org/jira/browse/FELIX-1135
http://issues.apache.org/jira/browse/FELIX-1028

This post contains some useful information http://groups.google.com/group/sakai-kernel/web/building-3akai-sling.

Solution

Download sling (standalone distribution) and unzip the tarball:
http://mirror.cc.columbia.edu/pub/software/apache/sling/org.apache.sling.launchpad.app-5-incubator-bin.tar.gz
Download new version of felix webconsole:
https://issues.apache.org/jira/secure/attachment/12407768/org.apache.felix.webconsole-1.2.9-SNAPSHOT.jar
Assume the new version of webconsole is downloaded to dir <DIR>

Execute following commands in the directory where sling tarball is unzipped.

jar xf org.apache.sling.launchpad.app-5-incubator.jar 
cd resources/bundles/5/ 
rm org.apache.felix.webconsole-1.2.8.jar 
cp <dir>/org.apache.felix.webconsole-1.2.9-SNAPSHOT.jar ./ 
jar cMf org.apache.sling.launchpad.app-5-incubator.jar resources META-INF org

Run the server:

java -jar org.apache.felix.webconsole-1.2.8.jar -p 4040

Note: you CANNOT use arbitrary new version of felix webconsole without updating other components of felix package. The reason is that different versions of felix console requires different versions of felix core/OSGi.

Misc.

If you are using both JCR Installer and Felix web console to update a bundle, you will get into trouble.
JCR installer:
    http://sling.apache.org/site/jcr-installer-jcrjcrinstall-and-osgiinstaller.html
    JCR installer tries to install OSGi bundles/modules found in Java Content Repository.
Bug
   “JCR Install prevents update of bundle through other channels like the web console”
    http://issues.apache.org/jira/browse/SLING-1106

Wednesday, September 23, 2009

Java Conent Repository - Jackrabbit

Resources

Wiki: http://en.wikipedia.org/wiki/Content_repository_API_for_Java
JSR 170: http://jcp.org/en/jsr/detail?id=170
JSR 170 API: http://www.day.com/maven/jsr170/javadocs/jcr-1.0/index.html
JSR 283 (JCR 2.0): http://jcp.org/en/jsr/detail?id=283 (in progress)
Jackrabbit: http://jackrabbit.apache.org/
List of Jackrabbit components: http://jackrabbit.apache.org/jackrabbit-components.html

Introduction

Jackrabbit implements JSR 170 and JSR 283.

Installation problem

When I tried to install Jackrabbit on gridfarm machine which uses NFS V3, I got problem described in this bug report (http://issues.apache.org/jira/browse/JCR-1605). Basically it says Jackrabbit needs some features that are not implemented in NFS prior to V4.

Friday, August 28, 2009

Dynamic-height in Shindig

Gadget specification provides a feature called dynamic-height to dynamically adjust height of a gadget.
If gadget server and gadget container are in the same domain, this can be done using javascript.
However, if gadget server and gadget container are in different domains, this can not be achieved by directly using Javascript and DOM because of same-origin policy imposed by modern browsers.
This email http://markmail.org/message/53r5dwhr56lby733#query:dynamic%20height%20shindig+page:1+mid:53r5dwhr56lby733+state:results includes some information about how to make it work.
I am going to give more details here.

Gadget container

  1. Download
        http://svn.apache.org/repos/asf/incubator/shindig/trunk/javascript/container/cookies.js
        http://svn.apache.org/repos/asf/incubator/shindig/trunk/javascript/container/gadgets.js
        http://svn.apache.org/repos/asf/incubator/shindig/trunk/javascript/container/util.js
        http://your_shindig_deploy/gadgets/js/rpc.js?c=1&debug=1 (//this file actually includes rpc framework and all possible communication mechanism, e.g. ifpc, wpm...)
    And put them into your gadget container server.
  2. Include following code in your container web page to make them point to those javascript files you downloaded in step 1).
    <script type="text/javascript" src="rpc.js"></script>
    <script type="text/javascript" src="cookies.js"></script>
    <script type="text/javascript" src="util.js"></script>
    <script type="text/javascript" src="gadgets.js"></script>
  3. Download
        rpc_relay.html : http://svn.apache.org/repos/asf/incubator/shindig/trunk/javascript/container/rpc_relay.html
    or
        rpc_relay_uncompressed.html: http://svn.apache.org/repos/asf/incubator/shindig/trunk/javascript/container/rpc_relay.uncompressed.html

Gadget server/renderer

  1. Check out Shindig source code. See http://incubator.apache.org/shindig/source-repository.html
  2. Change source code of file ifpc.transport.js
    Original:
    // The RPC mechanism supports two formats for IFPC (legacy and current). var src = null; if (rpc.l) {
    New
    // The RPC mechanism supports two formats for IFPC (legacy and current).
    var src = null;
    if (false) {
    This disables use of legacy data format which is buggy.
  3. Change configuration in file config/container.js
        Original: "parentRelayUrl" : "/gadgets/files/container/rpc_relay.html"
        New:       "parentRelayUrl" : "rpc_relay file address on your gadget container" //it is download in this step
    Also you may want to use ifpc instead of browser-specific communication mechanisms.
        Original: "useLegacyProtocol" : false    //gadget tries browser-specific communication mechanisms first. If they fail, fall back to ifpc.
        New:      "useLegacyProtocol" : true           //use ifpc directly.
    Note: the current wire format will be used instead of legacy format because we have disabled legacy format.
    This option is not used in the way described by comment in the source code. The shindig developers want users to use this option to control whether legacy format is used. I use it to configure whether ifpc is used. If ifpc is used, only current wire format is utilized.
    This can also be set after you deploy shindig. The configuration file is located at WEB-INF/classes/containers/default/.
  4. Rebuild shindig.
  5. Copy generated .war file in directory server/target to your servlet container.

Resources

Detailed discussion: http://docs.google.com/View?id=dmxthpg_125ckh55fff
Cross-Domain Communication with IFrames: http://softwareas.com/cross-domain-communication-with-iframes

Friday, August 21, 2009

Google GData API usage

Recently, I am using Google GData APIs to access Google Picasa and Google Calendar Services.
There is a Java library which is hosted at http://code.google.com/p/gdata-java-client/. Currently, the code is maintained using ant. We use maven2 to build our project, so we manually uploaded those jars to our maven repository and added necessary pom files. Dependencies of gdata java library are described at http://code.google.com/p/gdata-java-client/wiki/Dependencies.
Google Picasa doc: http://code.google.com/apis/picasaweb/docs/2.0/developers_guide.html
Google Calendar doc: http://code.google.com/apis/calendar/docs/2.0/developers_guide.html

During using of Google Calendar APIs, one thing I want to do is publish a new event to a specific non-primary calendar. According to http://code.google.com/apis/calendar/docs/2.0/developers_guide_protocol.html#CreatingSingle, POST requests should be sent to http://www.google.com/calendar/feeds/default/private/full. However that results in putting new event to primary calendar. The document does not tell us how to put a new event to non-primary calendar.

Solution (How to publish a new event to a non-primary calendar)

Steps:
  1. Get a list of all calendars owned by the user
    Send GET request to http://www.google.com/calendar/feeds/default/owncalendars/full
  2. In the response feed, each calendar has an entry.
    Each entry should has a link element like this:
        <link rel="alternate"
                 type="application/atom+xml"
                 href="http://www.google.com/calendar/feeds/pnk4d66rpmiho1pl0m4t6dnki0%40group.calendar.google.com/private/full"/>
    Value of attribute href is the URL to which the POST request should be sent to create a new event in the corresponding calendar.
  3. Send POST request to the URL specified by attribute "href" found in step 2)
    Example of POST data is shown http://code.google.com/apis/calendar/docs/2.0/developers_guide_protocol.html#CreatingSingle


Monday, August 10, 2009

MySQL Connection Timeout Error in Hibernate

Problem

I am using Hibernate and MySQL in myour project. After our application is started, it just works well. However, if the application is not used for some time (like one day), it throws connection exception when it is used again. Trace of the exception:
com.mysql.jdbc.CommunicationsException: 
The last packet successfully received from the server was seconds ago.
The last packet sent successfully to the server was 407270 seconds ago, which  is longer than the server configured value of 'wait_timeout'. 
You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.

I googled this problem, and it seems that many other persons also suffer this problem. I found some really nice blog posts about how to solve this problem.

According to the error message, I set the option autoReconnect (http://dev.mysql.com/doc/refman/5.0/en/connector-j-reference-configuration-properties.html) to true. But it still does not work. I searched in google and it shows this option works in some platforms while it doesn't work in other platforms.

Solution

Basically, the solution is 1) use a connection manager 2) tweak parameters of the connection manager.

C3P0 is a free JDBC connection manager.
Some C3p0 configuration parameters are mapped to Hibernate config. Those mapped configuration parameters are listed at http://www.mchange.com/projects/c3p0/index.html#hibernate-specific.

"Please note that configuration parameters that ARE mapped into hibernate's config file MUST be set within hibernate's configuration, or else they will be overridden by hibernate-specified defaults.
[The hibernate-mapped c3p0 parameters are minPoolSize, maxPoolSize, maxIdleTime, maxStatements, acquireIncrement, testConnectionOnCheckout, and idleConnectionTestPeriod. These map to the fllowing hibernate parameters: hibernate.c3p0.min_size, hibernate.c3p0.max_size, hibernate.c3p0.timeout, hibernate.c3p0.max_statements, hibernate.c3p0.acquire_increment, hibernate.c3p0.validate, and hibernate.c3p0.idle_test_period. DataSources configured in Tomcat should always use c3p0-native parameter names. But pools constructed under the covers by Hibernate must be configured in hibernate's config file with hibernate-defined parameter names where applicable.] "

For those C3p0 parameters that are NOT mapped, they should be specified in file WEB-INF/classes/c3p0.properties.
Note: C3P0 configuration parameter <c3p0.testConnectionsOnCheckout> is mapped to <hibernate.c3p0.validate> only in hibernate 2.x!
Also the configuration parameter c3p0.testConnectionsOnCheckout is really expensive. Users can use c3p0.maxIdleTime (it is mapped to hibernate.c3p0.timeout in hibernate) instead.

My hibernate.cfg.xml includes following configuration:
        <property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
        <property name="c3p0.min_size">5</property>
        <property name="c3p0.max_size">30</property>
        <property name="c3p0.timeout">600</property>
        <property name="c3p0.max_statements">0</property>
        <property name="c3p0.acquire_increment">5</property>
        <property name="c3p0.idle_test_period">60</property>

The idle test operation can be optimized by specifying option preferrredTestQuery.
I am using MySQL as underlying RDB and putting c3p0.preferredTestQuery = SELECT 1 into c3p0.properties works fine (this is stolen from post comment http://www.databasesandlife.com/automatic-reconnect-from-hibernate-to-mysql/#comment-3156).

Resources

A really good article about how to reconnect from Hibernate to MySQL: http://www.databasesandlife.com/automatic-reconnect-from-hibernate-to-mysql/
C3P0 (Connection manager): http://www.mchange.com/projects/c3p0/index.html
How to configure C3P0 in Hibernate: https://www.hibernate.org/214.html
A forum thread about C3P0 configuration in Hibernate: https://forum.hibernate.org/viewtopic.php?t=934779&highlight=c3p0

Monday, June 15, 2009

Key generation using OpenSSL

Generate RSA public/private key pair

Generate private key:
openssl genrsa -out private_key.pem 1024
Convert private key to PKCS8 format:
openssl pkcs8 -topk8 -in privkey.pem -nocrypt
Generate public key:
openssl rsa -pubout -in private_key.pem -out public_key.pem
Read Base64 Encoded private key
openssl rsa -text -in private_key.pem

Generate Self-Signed certificate

openssl req \
  -x509 -nodes -days 365 \
  -newkey rsa:1024 -keyout private_key.pem -out cert.pem

Thursday, June 04, 2009

2-legged OAuth System Tutorial

Use Cases:

(1) A user wants to grant data access priviledges to a third-party application.
  Here three parties are involved:
  User
    the end user
  Third-Party application
    It wants to manipulate user's data on behalf of the user.
  Service Provider
    a remote application that provides the real service.

  The procedure of granting priviledges:
  (I) complete steps described in section
      (Provider side) > (For regular users)
  (II) complete steps described in section
      (Consumer side) > (For regular users)
  Note: the public key uploaded in step (I) and private key uploaded in
  step (II) must match.

(2) A user wants to develop a third-party application for our service.
  (I) Register the application by completing steps described in section
      (Provider side) > (For thrid-party application developers)
  Now, the application can use the service.

  (II) To make use of built-in third-party application, complete steps
    described in section
      (Consumer side) > (For application manager)

(3) A user wants to use a deployed and configured third-party application.
  (I) Go to http://yourhost:yourport/oauthConsumer-0.1
  (II) Login with existing account and you will be directed to page 'account.jsp'
  (III) All supported third-party applications are listed under section
  (Available service providers). Click a link to use the corresponding
  application.

 

Consumer side

For regular users

Steps
  (1) Go to http://yourhost:yourport/oauthConsumer-0.1
  (2) Register a new account or log in with existing account
  (3) Go to account.jsp (you should be automatically directed to this page)
  (4) If it is the first time for the user to request an OAuth protected
      service via client application, the user should do some configurations.
      Click the link "Private Key Binding And Service Provider Setting"
  (5) On this page, user can do some configurations
    (5.1) UserId binding
      This setting binds local user Id to user Id used by remote service.
      For example, if a user wants to access remote Yahoo flickr service
      through a third-party app, the local user Id is the user id used by the
      third-party app and it is bound to the user Id used by Yahoo Flickr.
    (5.2) Private key setting
      Possession of private key makes the third-party app be able to access
      remote service on behalf of the user.

For application manager

Actually, only administrators should have the priviledge to manage third-party
application registry. But currently user management system is simple and all
users have the same priviledges.
Steps
  (1) Go to http://yourhost:yourport/oauthConsumer-0.1
  (2) Register a new account or log in with existing account
  (3) Go to account.jsp (you should be automatically directed to this page)
  (4) Click the link "Attributes of available service providers"
  (5) Now, the user can register a new third-party app, remove an existing
      registration and modify existing registration information.

Provider side

Currently, only one service is offered - echo service.

For regular users

Steps
  (1) Go to http://yourhost:yourport/oauthServer-0.1
  (2) Register a new account or log in with existing account
  (3) Go to account.jsp (you should be automatically directed to this page)
  (4) Click the link "Certificate Setting"
  (5) On this page, user can do some configurations
    (5.1) Third-party app priviledge setting
      Users can specify which third-party applications are allowed to access
      their data.
    (5.2) Certificate upload
      Upload your X.509 certificate (of PEM format).

For thrid-party application developers

Steps
  (1) Go to http://yourhost:yourport/oauthServer-0.1
  (2) Register a new account or log in with existing account
  (3) Go to account.jsp (you should be automatically directed to this page)
  (4) Click the link "Developer Account"
  (5) Type information of the third-party application that is to be registered.
      A consumer key/secret pair is generated as well.

Use of Public/Private key pair

There are two types of private/public key pair:
(1)
    One is used to guarantee integrity of messages transmissioned between
  third-party application and service provider.
    So for service provider, the public key is published. If a third-party
  application wants to access the service, it should use the published public
  key to sign outbound messages.
(2)
    The other is owned and deployed by end user. The goal is to provide a way so
  that third-party application can use backend service on behalf of user
  without user involvement.
    So this pair is owned by end user. To deploy the key pair:
  (*) upload the public key to service provider
  (*) upload the private key to third-party application
    Then the third-party application uses the private key to sign part of the
  message (The whole message is signed using pub/priv key pair described in
  bullet 1).

OAuth message

    ___________________________________________________________
   |                                                           |
   |     _________________________________________________     |
   |    |   ___________________________________________   |    |
   |    |  |  ______________       _________________   |  |    |
   |   P|  | |              |     |                 |  |  |    |
   |   a|  | | Payload 2    |     |  Signature (2)  |  |  |    |
   |   y|  | |______________|     |_________________|  |  |    |
   |   l|  |___________________________________________|  |    |
   |   o|                                                 |    |
   |   a|   ___________________________________________   |    |
   |   d|  |                                           |  |    |
   |    |  |                Other parts                |  |    |
   |   1|  |___________________________________________|  |    |
   |    |_________________________________________________|    |
   |     _________________________________________________     |
   |    |                                                 |    |   
   |    |       Signature (1)                             |    |
   |    |_________________________________________________|    |
   |                                                           |
   |___________________________________________________________|

In above figure, <Signature (1)> is calculated using key described in bullet 1. <Signature (2)> is calculated using key described in bullet 2.

Tuesday, June 02, 2009

H2 Exception "Database may be already in use: Locked by another process"

I wrote two Java web servlet apps (oauth consumer app, and oauth server app) both of which rely on H2 as database engine. I want H2 to be run in embedded mode instead of server mode. According to the official document, following statement should be added to web.xml

<listener>
    <listener-class>org.h2.server.web.DbStarter</listener-class>
</listener>

This class has methods that listen to the servlet context event (context initialization, context destroyed).

When I deploy just one of the two web apps to tomcat, it works fine. When I deploy both of them, following exception is thrown

Exception in thread "main" org.h2.jdbc.JdbcSQLException: Database may be already in use: Locked by another process. Possible solutions: close all other connecti on(s); use the server mode [90020-63]

I am 100% sure that those two apps use different databases. To make myself 200% sure that my code does not create or use additional databases unintentionaly, I rechecked my code many many times. But my code looks just fine. So I doubted it may be because of the H2 database engine.
Then I used command 'lsof' to list opened files by tomcat java process. Surprisingly, a database named 'test' is created under my home directory.
I reread the document http://www.h2database.com/html/tutorial.html#web_applications, and I got what I missed before.

For details on how to access the database, see the file DbStarter.java. By default the DbStarter listener opens an embedded connection using the database URL 'jdbc:h2:~/test', user name 'sa', and password 'sa'.

Code of class DbStarter can be accessed at http://code.google.com/p/h2database/source/browse/trunk/h2/src/main/org/h2/server/web/DbStarter.java.
I am just curious about why a default database is created by class DbStarter.

Solutions
(1) remove the listener declaration in web.xml
In other words, remove
    <listener> <listener-class>org.h2.server.web.DbStarter</listener-class> </listener>
(2) change url of created database.

  <context-param>
    <param-name>db.url</param-name>
    <param-value>jdbc:h2:your_new_db_url</param-value>
  </context-param>

Sunday, May 17, 2009

Change ROOT app in Tomcat

Recently, I tried new version of shindig - shindig-1.1-SNAPSHOT-java (http://incubator.apache.org/shindig/download/index.html). It is a reference implementation for OpenSocial 0.9 spec.

The old problem (described at http://cglreport.zhenhua.info/2009/02/shindig-server-on-tomcat.html) has not been solved.
At first I wanted to try it by deploying the war as root application in tomcat.

One easy solution is to rename the war file to ROOT.war.
I used another solution.
Steps:
Deployment:
  (1) create directory <tomcat_root>/myapps
  (2) put the war file (shindig-server-1.1-SNAPSHOT.war) to the directory created in step 1.
  (3) rename the original directory ROOT. (This step may be overlooked sometimes)
Configuration:
  (1) Add file <tomcat_root>/conf/Catalina/localhost/ROOT.xml
  (2) Content of the file is

<?xml version="1.0" encoding="UTF-8"?>
<Context
    path=""
    docBase="/globalhome/zhguo/servers/apache-tomcat-6.0.18/myapps/shindig-server-1.1-SNAPSHOT.war"
    debug="0"
    reloadable="true">
</Context>
  (3) restart tomcat

Wednesday, May 06, 2009

Implementation of 2-Legged OAuth

2-Legged OAuth

I did not change the process flow of original 3-legged OAuth to support 2-legged OAuth. I made a small change to user authorization step described at http://oauth.net/core/1.0/#auth_step2. Two additional parameters are added to support 2-legged OAuth: user_id and cgl_oauth_signagure. See http://zhenhua-guo.blogspot.com/2009/04/oauth-myproxy-integration-prototype.html for more information.

Integrity check:

  1. check trust relationship between service provider and client app.
    Currently, just check whether the clien app has been registered at service provider with correct information.
  2. check pre-assigned priviledges to client app by user (this only applies to 2-legged OAuth)
    A client app must have been granted access priviledge before it can access user data stored at service provider

Implementation

Client

Client App

Most important information about a client application includes:

  • name
  • description
  • consumer key
    See http://oauth.net/core/1.0/#anchor6
  • consumer secret
    See http://oauth.net/core/1.0/#anchor6
  • callback URL
    The address to which user is redirected after data owner accepts access request.
  • signature method
    HMAC-SHA1 or RSA-SHA1. Currently, only use RSA-SHA1.
  • private key
    Used to generate signature
  • request token URL
    See http://oauth.net/core/1.0/#auth_step1
  • authorization URL
    See http://oauth.net/core/1.0/#auth_step2
  • access token url
    See http://oauth.net/core/1.0/#auth_step3

A list of client applications is listed and users can add or remove client applications.
Snapshot:
oauthConsumer-0_1_consumers

Users can set userid that is used during invocation of remote service. Also to make it possible for client app to access user data at service provider, the user should upload private key to client app so that correct signature can be generated during OAuth process.
oauthConsumer-0_1_myproxy

Tables

Four tables in database:
oauth_consumer_users
This table stores basic user account information. Currently, username and password are the only two attributes.
oauth_consumer_settting
This table stores private key belonging to each user. The private key is used during OAuth authorization process.
oauth_consumer_spbinding
This table stores binding relationships between users and service providers. So the information in this table is used when client app invokes remote service on behalf of user. Currently the main information is the user id that is used by service provider. In other words, a mapping from local user id to remote user id is established.
oauth_consumers
This table stores information of client applications.

Service Provider

Service provider provides interfaces that can be used by third party applications to access users' data.

For application developer

Client application registration

To register a client app, developers need to follow these instructions:

  1. apply for a consumer key/secret pair.
  2. type informatoin about the clien app including
    • app name
    • app description
    • app callback URL
    • public key

In my implementation, the registration page can be accessed at <baseurl>/oauthServer-0.1/developerAcc.jsp after our system is installed.
Screenshot:
oauthServer-0_1_developerAcc

For common users

Some third-party applications may want to access users' data stored at service provider. In 3-legged OAuth, the service provider redirects the user to a web page where the access request can be accepted or denied. In 2-legged, no user intervenetion is involved, so the authorization setting must be preset.
In our system, we provide a way for common users to grant priviledge to and revoke priviledge from client (3rd party) applications. Also the user must upload a public key against which signature of requests receieved from client app can be verified.
Snapshot
oauthServer-0_1_myproxy

Tables

oauth_server_users
Basic user account information. Currently, just includes user name and password.
oauth_server_setting
stores public key extracted from myproxy server or direct upload.
oauth_server_dev
Stores information of registered client applications.
oauth_server_userappauth
Stores information of priviledge authorization set by each user.

Wednesday, April 08, 2009

Port attribute in HTTP Cookie

Recently, I have encountered a http session problem in jetty.
I start two Jetty instances on the same machine. These two jetty instances share the same base URL, but port numbers are different.
    http://example.com:8000/
    http://example.com:9000/
When I visit http://example.com:8000/, a cookie (called JSESSIONID) is set by the server automatically.
After that I visit the other URL http://example.com:9000/, the cookie set for http://example.com:8000/ is sent to the server by user agent. The the server gets confused :-(

After debugging it, I found the reason is that the server does NOT include port number in the Set-Cookie header. According to section 3.3.1 in RFC 2965, if the port attribute is missing in the Set-Cookie header, the user agent would react based on following description:

   Port    The default behavior is that a cookie MAY be returned to any
           request-port.

That means if a cookie is set for address A, the cookie also matches those addresses which share all the same URL components with A but port number.

For tomcat, I searched its email list
http://www.google.com/search?hl=en&client=firefox-a&rls=org.mozilla%3Aen-US%3Aofficial&q=cookie+port+site%3Ahttp%3A%2F%2Fmail-archives.apache.org%2Fmod_mbox%2Ftomcat-users%2F&btnG=Search
It seems that port number currently is not supported in cookie management.

Solution
(1) use different domain names which map to the same IP
(2) use different paths.
E.g.
    http://example.com:8000/webapp1
    http://example.com:9000/webapp2

Friday, April 03, 2009

OAuth + MyProxy integration prototype

Client

Client is the consumer of backend services.
Functionalities

  • A simple user management system
    Users can create new accounts, log in the system and log out the system.
  • Each user can upload her/his private key
  • For each backend service, the user can set his/her user id which is bound to the backend service.
    oauth_myproxy_consumer_uid_binding
    In above figure, the end user logins the client app as user "john". The client support accessing of three backend services. Then the user sets the binding of user id to each backend service. When the user wants to invoke backend service 1, the client app would set the user id to "mark" in the requests.

Service Provider

Functionalities of the service provider:

  • A simple user management system
  • Each user can bind a MyProxy account to his/her local account.
    The needed information of MyProxy account includes username, password, MyProxy server host and port number.
    Then the server would automatically retrieve a certificate chain from the specified MyProxy server. After parsing the certificate chain, public key of the original certificate that belongs to the user is extracted.
    Note: we don't use public key included the proxy certificate. There is just one original certificate stored in the MyProxy server while many proxy certificates can be acquired. Each time a new proxy certificate is requested, a new public/private key is created and the public key is sent to MyProxy server. Usually, this process is done by system automatically.
  • Each service could be accessed by various client applications. Users can set which client apps are allowed to access their data.

OAuth Integration

In OAuth authorization procedure, there are three main steps:

  1. Get a request token
  2. Ask user to authorize the request
  3. Exchange request token with an access token

Then the access token acquired in step (3) is used to access protected resources.
Trust relationship between client app and service provider is built out of band. Two mechanisms are supported: shared secret and RSA.
In my solution, step (2) is extended with step (1) and (3) staying the same. Two additional parameters are added: user_id and cgl_oauth_signagure. Parameter user_id is described here. The cgl_oauth_signature is calculated against user_id using the user's private key. After service provider receives the request, the corresponding public key (retrieved from MyProxy server) is used to verify the signature.

Future Work

  1. Revoke the authorized privileges
    1. Users can set an expiration time after which the access token will become invalid. Then the whole OAuth authorization process must be executed once again.
    2. Provides a way for user to revoke authorized privileges at any time they like.
  2. Trust relationship establishment.
    Developers of client apps go to specified web page of the service provider to apply for development account. Then one of the following two things happens:
    • A shared secret would be generated automatically and copied to the corresponding client app.
    • The developers of the client apps upload their certificate to backend service.

Saturday, February 28, 2009

Deploy standalone shindig on Quarry and an OAuth gadget demo

I got a virtual machine which I can log in as root. The virtual machine is pretty clean without any more packages besides CentOS.
I installed vim using yum install vim-enhanced. I also installed jdk1.5 and maven2.

Then I checked out the source code from shindig svn trunk. See instructions here http://incubator.apache.org/shindig/#tab-building.
Unfortunately, the test failed when I compiled and installed shindig. This kind of things always happens because of instability of trunk code. So I copied my previous checkout of shindig code which worked well from another machine. Then the compilation and installation succeeded.

OAuth gadget demo to retrieve google contact list

Now the sample demo is here:
http://gw11.quarry.iu.teragrid.org:9999/gadgets/files/samplecontainer/samplecontainer.html

Set field "Displaying gadget" to http://156.56.104.196:8888/oauth/gadgets/os_gadget.xml, Uncheck "use cache".
Click button "reset all". If everything works fine, you would see following in main panel:
temp

Clieck "Personalize this gadget", a popup window would appear which prompts you to login to your google account. Then you can choose grant or deny the access request. If you grant the request, the popup window would be closed automatically, and the main panel would be populated with your google contact list.

Saturday, February 21, 2009

Manipulate IFrame in Javascript

Create a iframe and set the content directly:

var frame = document.createElement('iframe');
parentElement.appendChild(frame);
frame.contentDocument.write(result);
According to Dom level 2 HTML specification, contentDocument is a property of HTMLIFrameElement.

Following code may also work. However I have not found the contentWindow property in W3C DOM specification.

var frame = document.createElement('iframe');
parentElement.appendChild(frame);
frame.contentWindow.document.write(result);

Saturday, February 14, 2009

Integration of OpenSocial containers via OAuth

For OpenSocial gadgets,  OpenSocial containers are necessary to hold users' data (friends, profile, ...). In Javascript API, class opensocial.DataRequest can be used to get users' data from the container which renders the gadget.

But to integrate users' data from third-party OpenSocial containers, some additional steps are needed. opensocial.DataRequest does not allow gadget developers to specify which OpenSocial container would be used to serve the data. Also the gadgets can not send requests directly to third-party containers because of Same-Origin policy imposed by browsers.

Method gadgets.io.makeRequest can be used to send arbitrary HTTP GET/POST requests. These requests are sent to the original container first. The original container does some processing and relays the requests to the destination address.
http://code.google.com/apis/opensocial/docs/0.8/reference/gadgets/#gadgets.io.makeRequest
http://code.google.com/apis/opensocial/articles/makerequest-0.8.html
http://code.google.com/apis/gadgets/docs/remote-content.html

Both REST and RPC protocol specifications requires that compliant containers must be OAuth service provider:
http://www.opensocial.org/Technical-Resources/opensocial-spec-v081/restful-protocol (Section 4)
http://www.opensocial.org/Technical-Resources/opensocial-spec-v081/rpc-protocol
Also I found OAuth Consumer Request 1.0 Draft 1 (hosted at googlecode, not oauth.net) which standardizes two-legged authorization process without a User involvement. It is useful in server-to-server interaction.

How to use OAuth in gadgets
http://code.google.com/apis/gadgets/docs/oauth.html (Very useful)
http://sites.google.com/site/oauthgoog/oauth-proxy/social-oauthproxy

OpenSocial container list:
http://wiki.opensocial.org/index.php?title=Main_Page#Container_Information

Extensions:
Also, I found many OAuth extension drafts which are not listed in OAuth.net. I guess these extensions are implemented in Shindig and evaluated.
http://oauth.googlecode.com/svn/spec/ext/

Saturday, February 07, 2009

Enable/Disabl Directory Listing in Tomcat

By default, directory listing (list content of a directory instead of render a web page) is forbidden in Tomcat.

To enable it globally, modified file <tomcat>/conf/web.xml.
Default setting for default servlet is:

    <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

Change the param-value for parameter listings to true.

To enable it for a specific web application, add following snippet to the web.xml of the application

    <servlet>
        <servlet-name>default_new</servlet-name>
        <servlet-class>
          org.apache.catalina.servlets.DefaultServlet
        </servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>true</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!-- The mapping for the default servlet -->
    <servlet-mapping>
        <servlet-name>default_new</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
Note: servet-name can not be default because it is name of tomcat's default servlet . So you need to use a different name. Also servlet-mapping element is necessary to make it work.

Shindig server on Tomcat

Shindig can be run with built-in jetty server without problems. But after I deployed the war to Tomcat, there are some problems. I got a blank page when I tried to render a gadget. I searched for the problem, some other guys got this problem as well.

Other posts related to this problem:
http://mail-archives.apache.org/mod_mbox/incubator-shindig-dev/200805.mbox/%3C483C780B.6080802@oracle.com%3E

Finally I figured out how to make shindig work on Tomcat.
Why does not it work?
It ignores the context path. In other words, the implementation only considers the situation that the application is deployed as root application.

Two possible Solutions
(1) make shindig war the root application
Two alternative ways:
    (*) rename it to ROOT.war and deploy it to tomcat. (The original ROOT application cannot be used)
    (*) change conf/context.xml to set shindig application as root application
(2) Modify shindig configuration files <shindig>/java/common/conf/shindig.properties and <shindig>/config/container.js to add context path in all related urls.
It seems to work well. I am not sure whether there is any potential problem.