Friday, October 27, 2006

Terta & Bodington "Review"

Michael Feldstein has written a couple of very good posts about the Bodington VLE following the Tetra annoucement. His posts aren't a "review" of Bodington but more of an exploration of how Bodington does access control which is often over simplified in other tools.
Here at Oxford we use WebAuth for web based Single Sign On (SSO) and when looking at tools we like to see how easily they can be WebAuth enabled. Thankfully Sakai makes it all pretty easy. Sakai has the ability to support two authentication methods at the same time so we can have a login route for both Oxford users (WebAuth) and for internal Sakai users.

Previously we have used the Apache WebAuth module but this time I decided to attempt to use the Java WebAuth Filter developed as part of the SIPE project here at Oxford. One note is that the Standford WebAuth download pages have a newer version of the Java WebAuth filter than the SIPE pages. The Java WebAuth implementation only works with Java 1.5.

The first thing is to configure Kerberos on the machine so that it points to the correct servers, on my Linux box at Oxford this means having a configuration file called /etc/krb5.conf containing:

[libdefaults]
default_realm = OX.AC.UK

[realms]
OX.AC.UK = {
kdc = kdc0.ox.ac.uk
kdc = kdc2.ox.ac.uk
kdc = kdc1.ox.ac.uk
admin_server = kdc-admin.ox.ac.uk
}

[domain_realm]
.ox.ac.uk = OX.AC.UK
ox.ac.uk = OX.AC.UK


I also needed the kerberos tools too, on Ubuntu these come as part of the krb5-user package (sudo apt-get install krb5-user). Once my machine was running with Kerboros I needed to visit the systems development team and get a kerberos principal, this involved saying hello to the nice people upstairs and then typing a password for my new principal (buckett/itss). This principal then had rights over my webauth principal (webauth/oucs-matthewb.oucs.ox.ac.uk) so that I could key a keytab for my webauth principal. I get a keytab with the commands:

buckett@oucs-matthewb:~ $ kadmin -p buckett/itss
Authenticating as principal buckett/itss with password.
Password for buckett/itss@OX.AC.UK:
kadmin: ktadd -k /home/buckett/.webauth.keytab webauth/oucs-matthewb.oucs.ox.ac.uk
Entry for principal webauth/oucs-matthewb.oucs.ox.ac.uk with kvno 4, encryption type Triple DES cbc mode with HMAC/sha1 added to keytab WRFILE:/home/buckett/.webauth.keytab.
Entry for principal webauth/oucs-matthewb.oucs.ox.ac.uk with kvno 4, encryption type DES cbc mode with CRC-32 added to keytab WRFILE:/home/buckett/.webauth.keytab.

This gives me a keytab file that allows the WebAuth filter to authenticate with the Kerberos server without having to ask me for a password every time I start it up. I also need to create a keyring file.

touch /home/buckett/.webauth.keyring

and set the permissions on both of the files to be as restrictive as possible (chmod 400 ~/.webauth.*).

The the sakai login tool needs to be changed to include the WebAuth filter.
This means dropping all the JARs from the WebAuth distribution (bcprov-jdk15-132.jar, commons-httpclient-3.0.jar, commons-logging-api-1.0.4.jar, commons-codec-1.3.jar, commons-logging-1.0.4.jar, webauth-java-1.2.jar) into the WEB-INF/lib folder.
The web.xml then needs some extra sections added (in bold).

  <description>Sakai 2 sample tools: login</description>

  <!-- Webauth Filter Start -->
  <filter>
   <filter-name>Webauth Filter</filter-name>
   <filter-class>uk.ac.ox.webauth.Filter</filter-class>
   <init-param>
     <param-name>WebAuthDebug</param-name>
     <param-value>true</param-value>
   </init-param>
   <init-param>
       <param-name>WebAuthServicePrincipal</param-name>
       <param-value>webauth/oucs-matthewb.oucs.ox.ac.uk</param-value>
   </init-param>
   <init-param>
       <param-name>WebAuthKeytab</param-name>
       <param-value>/home/buckett/.webauth.keytab</param-value>
   </init-param>
   <init-param>
       <param-name>WebAuthWebKdcPrincipal</param-name>
       <param-value>service/webkdc@OX.AC.UK</param-value>
   </init-param>
   <init-param>
       <param-name>WebAuthWebKdcURL</param-name>
       <param-value>https://webauth.ox.ac.uk:8443/webkdc-service/</param-value>
   </init-param>
   <init-param>
       <param-name>WebAuthLoginURL</param-name>
       <param-value>https://webauth.ox.ac.uk/login</param-value>
   </init-param>
   <init-param>
       <param-name>WebAuthKeyring</param-name>
       <param-value>/home/buckett/.webauth.keyring</param-value>
   </init-param>
   <init-param>
       <param-name>AutoAddKeys</param-name>
       <param-value>true</param-value>
   </init-param>
   <init-param>
       <param-name>AutoRemoveKeys</param-name>
       <param-value>true</param-value>
   </init-param>
   <init-param>
       <param-name>WebAuthExtraRedirect</param-name>
       <param-value>true</param-value>
   </init-param>
 </filter>
 <!-- Webauth filter end -->

   <filter>
       <filter-name>sakai.request</filter-name>
       <filter-class>org.sakaiproject.util.RequestFilter</filter-class>
   </filter>

   <filter>
       <filter-name>sakai.request.container</filter-name>
       <filter-class>org.sakaiproject.util.RequestFilter</filter-class>
      <init-param>
           <param-name>tool.placement</param-name>
           <param-value>true</param-value>
       </init-param>
       <init-param>
           <param-name>remote.user</param-name>
           <param-value>false</param-value>
       </init-param>
   </filter>

   <filter-mapping>
       <filter-name>sakai.request</filter-name>
       <servlet-name>sakai.login</servlet-name>
       <dispatcher>REQUEST</dispatcher>
       <dispatcher>FORWARD</dispatcher>
       <dispatcher>INCLUDE</dispatcher>
   </filter-mapping>

   <filter-mapping>
       <filter-name>sakai.request.container</filter-name>
       <servlet-name>sakai.login.container</servlet-name>
       <dispatcher>REQUEST</dispatcher>
   </filter-mapping>
 

   <!-- Webauth Filter Mapping Start -->
   <filter-mapping>
       <filter-name>Webauth Filter</filter-name>
       <servlet-name>sakai.login.container</servlet-name>
   </filter-mapping>
   <!-- Webauth Filter Mapping End -->

   <servlet>
       <servlet-name>sakai.login</servlet-name>
       <servlet-class>org.sakaiproject.login.tool.LoginTool</servlet-class>
       <init-param>
           <param-name>container</param-name>
           <param-value>/sakai-login-tool/container</param-value>
       </init-param>
       <load-on-startup>1</load-on-startup>
   </servlet>


You will probably need to change the WebAuth filter configuration to point to the correct keyring/keytab files for you local installation.

The just edit your sakai.properties, making sure these are set.

# LOGIN/LOGOUT

# to include the user id and password for login on the gateway site
top.login=false

# to let the container handle login or not (set to true for single-signon type setups, false for just internal login)
container.login=true

xlogin.enabled=true
xlogin.text=Guests

Now if you startup Sakai it should provide you with two login buttons in the top right of the portal. One that uses WebAuth and one that uses the internal Sakai authentication.

Wednesday, October 25, 2006

Sakai and Log4J

In my digging around with Sakai I came across the fact that the Sakai logging JARs are deployed to tomcat/common, the extra JARs are deployed there are sakai-util-log-dev.jar and log4j-1.2.8.jar. Placing these files in the common classloader means that they are available to both the deployed applications as well as the servlet container (Tomcat) itself. Now often log4j along with commons-logging JARs are placed into the common classloader so that Tomcat (5.5) will use log4j for its own internal logging. If other log4j JARs don't exist in any of the other classloaders all logging will go through the same log4j class and configuration. Applications are still free to provide their own log4j implmenetation along with configuration which should be insulated from the container log4j. This is because the common classloader is checked last (after the webapp and shared ones). Sakai would only need to deploy its logging code to common if it wanted to control the logging of the container as well as it's own logging. Some Sakai log messages may end up in the container logs if any of the Sakai tools log against the servlet context (getServletContext().log(String)). I don't think there is any harm to Sakai by placing the JARs in shared as all that happens is you can't control the container logging. To get Sakai logging working correctly there would also need to have commons-logging in the common classloader, so I'm not convinced that this setup works to control the container logging. As a side note Tomcat ships with a commons-logging-api but this doesn't provide the full logging framework, just enough to get going. Helpful web documents include:

Friday, October 20, 2006

Sakai Classloaders

I am beginning todo a little bit of work with Sakai and was trying to deal with uploaded files from a web form when inside a tool. Now Sakai uses commons-filupload to handle uploaded files and parses them automatically and adds the results back to the request as attributes. I was then trying to access this attribute in my tool with a line: FileItem fileItem = (FileItem)request.getAttribute("file"); This supprisingly was giving me a ClassCastException complaining that it was unable to cast a DefaultFileItem to a FileItem despite the fact that DefaultFileItem implements the FileItem interface. After a little head scratching Alexis suggested classloader issues we found the problem. Sakai has the parsing of the uploaded files in one classloader(the portal, getting commons-fileupload from shared) which then hands control off to the tool in another classloader (the tool, done by dispatching the request across servlet contexts). The problem was that both classloaders had a copy of the commons-fileupload jar and so when the FileItem class what loaded it wasn't in the same classloader as the DefaultFileItem and so couldn't be cast. Removing the copy of commons-fileupload from the tool fixed the problem. This issue would have been a little easier to debug if when the ClassCastException occured they provided the ID of the classloader that the two classes had come from in the exception message.

Globalsign and Java (again)

It seems that I keep having to contact servers with Globalsign certificates and have Java throw a wobbily (java.security.cert.CertPathValidatorException). There are a whole load of globalsign certificates under http://secure.globalsign.net/cacert/ and this time I needed the Server.cacert one. Now my JDK has two extra Globalsign root certificates installed...

Thursday, October 05, 2006

Plusnet LLU Disconnection

Well it seems that Plusnet have finally sorted out the disconnects on the LLU platform as I have been connected for almost 16 hours without a disconnect. The whole issue has been badly dealt with but hey. In side news my exchange has been ADSL2+ enabled as my router now syncs at: Bandwidth (Up/Down) [kbps/kbps]: 619 / 17,509 In speedtests I don't get anywhere near 17mbs but this is probably due to still having 802.11b (11mb) wireless clients. I should really attach a PC directly to the router and see how it does.