Freitag Apr 10, 2009

Using OpenID for JForum

Today I want to post the solution I developed to use OpenID in JForum.

There are different Solutions for OpenID Authentication Modules. As I am running JForum on Glassfish Server I decided to use set OpenIDAuthModul based on JSR-196 . This module is easy to install see my blog OpenID for JEE Appplications Part II.

So now when you have installed the OpenID Module and configured on Glassfish there are only a few steps to complete.

1.) Add sun-web.xml

To use JSR-196 athtentication in you JForum you need to add a sun-web.xml which points to your OpenID Provider.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sun-web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 9.0 Servlet 2.5//EN" "http://www.sun.com/software/appserver/dtds/sun-web-app_2_5-0.dtd">

<sun-web-app error-url="" httpservlet-security-provider="OpenID2">
<context-root>/shareyourwork/jforum</context-root>
<security-role-mapping>
<role-name>user</role-name>
<principal-name>user</principal-name>
<group-name>Author</group-name>
</security-role-mapping>
<class-loader delegate="true" />
<jsp-config>
<property name="keepgenerated" value="true">
<description>Keep a copy of the generated servlet class javacode.</description>
</property>
</jsp-config>
</sun-web-app>  

Notice the Security Role Mapping I am using here! I map the JForums role "user" to my default Group "Auhtor" which I configured in my OpenID Autmodule as explained in Part II of my OpenID Blog.

2. Change web.xml

Next I changed the web XML to force a Login when Users access my JForum (this is wy we need not more Registration in JForum)

<security-constraint>
<web-resource-collection>
<web-resource-name>Restricted Area</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>user</role-name>
</auth-constraint>
</security-constraint>
<security-role>
<role-name>user</role-name>
</security-role>

3. Implement a SSO Module for JForum

Next we need a so called SSO Moduel for JForum. This is a JForum specific way to allow individual authentification mechanism. Read more about JForums sso here.

This is the class I implemented:

package org.imixs.login;

import java.util.Collection;

import javax.servlet.http.Cookie;

import net.jforum.ControllerUtils;
import net.jforum.JForumExecutionContext;
import net.jforum.context.RequestContext;
import net.jforum.entities.UserSession;
import net.jforum.sso.SSO;
import net.jforum.util.preferences.ConfigKeys;
import net.jforum.util.preferences.SystemGlobals;

import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.jee.ejb.EntityServiceRemote;

/**
* Simple SSO Implemetation for JForum
*
* @author Ralph Soika
* @version 0.0.1
*/
public class SSOLogin implements SSO {

String userName;
String userID;
String email;

public final String COOKIE_NAME = "jforumUserId";

public String authenticateUser(RequestContext request) {
String sUser = request.getRemoteUser();
userName = sUser;
if (sUser != null) {
// here you can complete user spcific informations if necessary
try {
/*
* Code was taken from
* http://www.jforum.net/doc/ImplementSSO
*/
ControllerUtils.addCookie("JforumSSO", userName); // refresh
}

} catch (NamingException e) {
System.out.println("------ SSO LOGIN - Error ");
e.printStackTrace();
}

}

return userName;
}

/**
* Code was taken from
*
* http://www.jforum.net/doc/ImplementSSO
*
*/
public boolean isSessionValid(UserSession userSession,
RequestContext request) {
String remoteUser = null;
Cookie SSOCookie = ControllerUtils.getCookie("JforumSSO");
if (SSOCookie != null)
remoteUser = SSOCookie.getValue(); // jforum username

// user has since logged out
if (remoteUser == null
&& userSession.getUserId() != SystemGlobals
.getIntValue(ConfigKeys.ANONYMOUS_USER_ID)) {
return false;

// user has since logged in
} else if (remoteUser != null
&& userSession.getUserId() == SystemGlobals
.getIntValue(ConfigKeys.ANONYMOUS_USER_ID)) {
return false;

// user has changed user
} else if (remoteUser != null
&& !remoteUser.equals(userSession.getUsername())) {
return false;
}
return true; // myapp user and forum user the same
// return true;
}

}
 

This code did not do much as I use the OpenID URL as the UserName used by JForum.

I an internal project we added some individual code in into the method authenticateUser() to get the Username and Email from a different application. But this is not necessary if you allow users to complete there profile in JForum. The Profile will be generated automatically.

4.) Customize SystemGlobals.properties.

  FinallyI customized the SystemGlobals.properties (located in  WEB-INF/config/).

....
authentication.type = sso
login.authenticator = net.jforum.sso.DefaultLoginAuthenticator
sso.implementation = org.imixs.login.SSOLogin
....

Conclusion

So this was an easy way for me to allow users to work with there OpenID (like yahoo.com accounts) in my JFourm. If you have any suggestions you can post your comments here.