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.

Saturday, November 08, 2008

Maven cheat sheet

Download and install maven: http://maven.apache.org/download.html.

Running Maven
http://maven.apache.org/guides/getting-started/maven-in-five-minutes.html
http://maven.apache.org/guides/getting-started/index.html
Generally the local repository is provided in USER_HOME/.m2/repository.

Configuration
http://maven.apache.org/guides/mini/guide-configuring-maven.html
Three levels:

Build your own private/internal repository:
This article introduces how to create a repository using Artifactory: http://www.theserverside.com/tt/articles/article.tss?l=SettingUpMavenRepository. In addition, the author also compares some mainstream maven remote repository managers including Standard maven proxy, Dead simple Maven Proxy, Proximity and Artifactory.
In my case, I also use Artifactory and deploy it to tomcat. It has a nice web-based interface. Artifactory uses database(derby I think) to store various repository data so a user can not know the repository content by directly looking at the directory.

Deploy your artifacts to remote repository by using maven-deploy plugin:
http://maven.apache.org/plugins/maven-deploy-plugin/usage.html
(1) If the artifacts are built by using Maven, you should use deploy:deploy Mojo.
In your pom.xml, element <distributionManagement/> should be inserted to tell Maven how to deploy current package. If your repository is secured, you may also want to configure your settings.xml file to define corresponding <server/> entries which provides authentication information.
Command: mvn deploy.
(2) If the artifacts are NOT built by using Maven, you should use deploy:deploy-file Mojo.
Sample command:
mvn deploy:deploy-file -Dpackaging=jar -Durl=file:/grids/c2/www/htdocs/maven2 
-Dfile=./junit.jar -DgroupId=gridshib -DartifactId=junit -Dversion=GTLAB

FAQ:
(1) What does maven standard directory layout look like?
http://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html
(1) How to specify parent artifact in pom.xml?
Read http://maven.apache.org/guides/introduction/introduction-to-the-pom.html.
(2) If a dependent package can not be download from central Maven repository, three methods can be used to deal with it:

"
  1. Install the dependency locally using the install plugin. The method is the simplest recommended method. For example:
    mvn install:install-file -Dfile=non-maven-proj.jar -DgroupId=some.group -DartifactId=non-maven-proj -Dversion=1

    Notice that an address is still required, only this time you use the command line and the install plugin will create a POM for you with the given address.

  2. Create your own repository and deploy it there. This is a favorite method for companies with an intranet and need to be able to keep everyone in synch. There is a Maven goal called deploy:deploy-file which is similar to the install:install-file goal (read the plugin's goal page for more information).
  3. Set the dependency scope to system and define a systemPath. This is not recommended, however, but leads us to explaining the following elements:
"
(2) How to add new repository?
Put following code snippet into pom.xml or settings.xml.
<repository>
  <id>your-new-repository-id</id>
  <name>New Maven Repository </name>
  <layout>default</layout>
  <url>Address of the new repository</url>
  <snapshots>
    <enabled>enable-it?</enabled>
  </snapshots>
  <releases>
    <enabled>enable-it?</enabled>
  </releases>
</repository>
(3) How to disable default central maven repository?
Put following snippet into your pom.xml.
<repository>
  <id>central</id>
  <name>Maven Repository Switchboard</name>
  <layout>default</layout>
  <url>http://repo1.maven.org/maven2</url>
  <snapshots>
    <enabled>false</enabled>
  </snapshots>
  <releases>
    <enabled>false</enabled>
  </releases>
</repository>
(4) How can I package source code without run test?
Feed parameter -Dmaven.test.skip=true into the command line.
Note this property is defined by maven plugin surefire.
(5) Why does "mvn clean" delete my source code?
In your pom.xml, if content of element <directory> nested in element <build> is "./", "mvn clean" will delete all content in current directory including the src directory.
There are two more elements which can be used to specify locations of compiled classes.
outputDirectory:  The directory where compiled application classes are placed.
testOutputDirectory:  The directory where compiled test classes are placed.
(6) How to add resources into built package?
http://maven.apache.org/guides/getting-started/index.html#How_do_I_add_resources_to_my_JAR.
http://maven.apache.org/guides/getting-started/index.html#How_do_I_filter_resource_files