Friday, 26 September 2008

My first firefox extension

My first firefox extensions checks the fingerprint of a ssl secured site.For online banking my bank advises me to check the fingerprint of the certificate of their site to make sure it is the right one. Every year the certificate is changed and they proclaim the new fingerprint.

So before login I always had to open the page info by clicking the lock icon, clicked show certificate and then compared the fingerprint displayed there with the one I stored in a file or on a paper. The the popups had to be closed again.

The ssl-fingerprint-check extension does all the work for me.

It can be checked out via anonymous svn with

svn co http://subversion.banapple.de/public/ssl-fingerprint-check


When I access the banks site it automatically compares the fingerprint of the certificate with a predefined value. If it matches a label in the status panel says that the fingerprint is ok or "INVALID FINGERPRINT".

The overlay file defines which xul elements are added to firefox. In this case a statusbarpanel is added to the status bar.

The rest is the javascript code to initialize the extension and handle load events which is defined in ssl-fingerprint-check.js.

Let's go through the code:

first listeners are registered such that the extension gets initialized when firefox starts and uninitialized when it stops.

window.addEventListener("load", function() { sslFingerprintCheck.init(); }, false);
window.addEventListener("unload", function() { sslFingerprintCheck.uninit(); }, false);

The init function gets the firefox browser element and adds a progress listener to it.

init: function() {
var content = document.getElementById("content");

if (content) {
content.addProgressListener(sslFingerprintCheck_urlBarListener,
Components.interfaces.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
}
}

The current fingerprint and the common name of the certificate are hardcoded in the extension. If you want to make use of this extension you will probably have to change that or get an account in Diepholz.

var fingerprint = "ED:75:31:01:CE:09:71:3C:64:AB:EF:BD:28:AE:B5:3F:FF:87:07:B2";
var commonName = "banking.kreissparkasse-diepholz.de";

The progress listener calls the function checkCertificate on various events.
checkCertificate gets the certificate and then compares the fingerprint if the common name matches. It updates the statusbarpanel accordingly.

checkCertificate: function()
{
var certificate = sslFingerprintCheck.getCert();
if (certificate != null) {
//sslFingerprintCheck.debug("fingerprint="+certificate.sha1Fingerprint);
//sslFingerprintCheck.debug("cert="+certificate.commonName);

/* check for one specific commonName at the moment */
if (certificate.commonName == commonName) {
if (certificate.sha1Fingerprint==fingerprint) {
newLabel = "fp ok";
} else {
newLabel = "INVALID FINGERPRINT";
}
} else {
newLabel = "no banking";
}
document.getElementById("ssl-fingerprint-check-panel").label = newLabel;
} else {
document.getElementById("ssl-fingerprint-check-panel").label="no ssl";
}
}


The sites which helped to develop this extension are named in the source code.

To test the extension follow the instructions on
developer.mozilla.org section 'Test'.

Possible improvements for this extension:

  • provide a preferences window where pairs of common names and fingerprints can be managed

  • display a fancy icon for the fingerprint check instead of a label

  • display the icon in the ssl status bar panel right to the lock icon

Saturday, 20 September 2008

My first thunderbird extension

I started my first thunderbird extension.
After some success at the start my motivation now rapidly decreases but I still would like to present my results.
Perhaps some information from it is helpful for other beginners.

The idea was an extension which parses a message to be displayed for text fragments matching some regular expression and then map the matching text to some link.
In my company, for example, we are using Jira.
The tickets in Jira can be accessed by URLs like
http://company-server/jira/browse/PROJECT-1
where PROJECT is an example project name in the company Jira.
I want the extension to map the text "PROJECT-1" to the ticket url.

The great vision was then to have a preferences window where regular expressions and urls can be defined, the mapped links should be displayed inline in the message text.

The source code for the extension can be downloaded via anonymous svn from http://subversion.banapple.de/public/linkator/ .

What I got in the end was an extension which was generally able to process a message and do something with it. So if you want to create an extension which manipulates a message or does some action depending on a message when it is displayed you make take my extension. There is a function called processDocument in content/overlay.js where you can implement your own stuff. The function is called when a message is displayed. You can, for example, set the background color of the message with doc.bgColor="#00FF00".

I am not really convinced if this extension makes sense at all, so my motivation was not good enough to finish it.
The parsing of the message is not finished, links are not really mapped, mapped links are not displayed in the text.
Instead only matching texts are added to a linkator box which is placed above the message.
This box is not finished because it is never cleared from old matches.
But it shows how the xul interface of thunderbird can be extended with overlays.

The extension is a mess but here is how I got there.

First I created a dummy extension with the
Extension Wizard.
To test this (already runnable) extension I inserted a file in my thunderbird profile in the extensions directory as described in http://developer.mozilla.org/en/Building_an_Extension (this page is for firefox extensions but it is all the same for thunderbird).

Then I adjusted content/thunderbirdOverlay.xul until I got a new xul element above the message.

The next step was to implement the behaviour of the extension in content/overlay.js.

I got information about how to do this from the source of other extensions
One was Remote Image Cache which showed how to hook in for message processing.

Other useful references:
The XUL tutorial at http://developer.mozilla.org/En/XUL_Tutorial
http://www.xulplanet.com/

Development was hard. To test it thunderbird always had to be restarted. I would like to hear what tools professional extension writers are using.

Monday, 8 September 2008

On using the BeanShell for system introspection

At work I came across the BeanShell
and its remote server mode.

From a server application you can invoke the command

server(1234);

in a beanshell which starts a tiny HTTP server on port 1234 and a telnet session server on port 1235.
When your server at port 1234 is then accessed via HTTP you get a page containing
an applet containing a JConsole. This applet communicates with the telnet session server.

We ignored the warning about the unrestricted access to all parts of the application
and used the applet in production.

And this helped us to analyze problems we would never have been able to solve
without the remote beanshell. Before we only had logs or beans accessible via JMX.
But these information was fixed after we inserted the log statements or defined
the managed beans.
The remote beanshell allowed us to look into any object which was reachable from
one given entry point object which we set into the beanshell interpreter at startup.

We were even able to call methods on these objects to fix states we did not expect
before to happen.

One disadvantage was that the remote server was not running under the standard port 8080.
Firewall issues prevented us from accessing the remote beanshell from our workstations.
We therefore had to login to our production (windows!) web servers, start a browser there
and call the remote beanshell.

I therefore implemented a servlet providing an Interpreter instance hold in the session.
The code can be checked out via anonymous svn from
http://subversion.banapple.de/public/beanshell-extensions/

The homepage is http://www.banapple.de/beanshell-extensions/index.html.

Friday, 24 August 2007

Just in time compilation of GWT code

From Echo2 to GWT... I am still searching for the best toolkit.

What I liked at Echo2 is that the javascript code for the client is created just in time. There is no compilation step to be made before the deployment like in GWT.
GWT allows to develop an application in hosted mode, so probably there is no big need for a just in time compiler, because you will not deploy the application that often as with echo2 (does this make sense?).

Anyway, perhaps this feature may be useful for somebody.

The javascript code for the GWT client, which is normally deployed after compilation as static files, is produced in this example dynamically by a servlet. The servlet compiles the client code to javascript and caches it.

The source can be downloaded from
http://www.banapple.de/sandbox/JustInTimeCompilerServlet.java

What has to be done?


  1. The sources for the client have to be in the classpath of your web application.

  2. The os dependent GWT library containing the GWTCompiler has to be in the classpath.

  3. The servlet is defined to be accessible under the relative url /gwt-jit (or anything you want).

  4. The HTML page containing the GWT client has to include the GWT module using the servlet url, like in

    <meta name='gwt:module' content='/gwt-jit=de.banapple.MyModule'>




How does it work?

The servlet creates to directories under WEB-INF/. One for holding the
compiled files, one as a temporary directory for the compilation.

The GWT bootstrap code requests the file
/gwt-jit/de.banapple.MyModule.nocache.html.

The servlet first looks whether the file
de.banapple.MyModule.nocache.html
is already in the cache of compiled files.
If not the module is compiled in method handleModule. This method just uses the class com.google.gwt.dev.GWTCompiler, which stores the compiled files in the temporary compilation directory.

Afterwards the temporary files are copied to the cache directory. The GWTCompiler creates a directory with the module name in the temporary compilation directory. When the GWT bootstrap code requests further cache files (those files with names being a hash), the servlet can not determine which module they belong to and can therefore not look into directory named after the module (ok, it could, it would have to search all those module directories). So they are all copied flat into the cache directory, hoping that the filenames of different modules do not clash.

The servlet is definitely not fail-proof, e.g it will not work if two request come in which initiate the compilation. But as a first shot it worked for me.

Sunday, 27 May 2007

On using the echo2 googlemaps component

There is a echo2 component for google maps
here. And it works really good so far.

The author of this component says that the echo2 code has to be patched such that the google map api can be loaded at page load time which is needed for google maps (at least with echo2 version 2.1.0beta5).

I managed to get the component running with echo2 2.1.0rc2 without patching:

The starting point for an echo2 application is a servlet which extends nextapp.echo2.webrender.WebRenderServlet. The normal behaviour of this servlet is to register some services. One of these services is the nextapp.echo2.webcontainer.WindowHtmlService which produces the output in its service method. The trick is now to replace this class with your own implementation.

I made it this way:

The constructor of my HelloWorldServlet which extends nextapp.echo2.webrender.WebRenderServlet and which is the starting point of my echo2 application is the following:

public HelloWorldServlet()
{
super();

final String METHOD = "HelloWorldServlet: ";

ServiceRegistry serviceRegistry = WebRenderServlet.getServiceRegistry();
serviceRegistry.remove(WindowHtmlService.INSTANCE);
serviceRegistry.remove(NewInstanceService.INSTANCE);
serviceRegistry.add(MyNewInstanceService.INSTANCE);
serviceRegistry.add(MyWindowHtmlService.INSTANCE);

log.debug(METHOD+"successful");
}

This removes the old service implementations and replaces it with my own implementations:

package de.banapple.echo2test;

import java.io.IOException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import nextapp.echo2.webcontainer.ContainerInstance;
import nextapp.echo2.webrender.Connection;
import nextapp.echo2.webrender.Service;

public class MyNewInstanceService
implements Service
{
private static Log log = LogFactory.getLog(MyNewInstanceService.class);

public String getId()
{
return "Echo.NewInstance";
}

public int getVersion()
{
return -1;
}

public void service(Connection conn)
throws IOException
{
final String METHOD = "service: ";
log.debug(METHOD+"conn="+conn);

ContainerInstance.newInstance(conn);
MyWindowHtmlService.INSTANCE.service(conn);
}

public static final MyNewInstanceService INSTANCE =
new MyNewInstanceService();

}



package de.banapple.echo2test;

import java.io.IOException;

import nextapp.echo2.webcontainer.ContainerInstance;
import nextapp.echo2.webcontainer.WindowHtmlService;
import nextapp.echo2.webrender.BaseHtmlDocument;
import nextapp.echo2.webrender.Connection;
import nextapp.echo2.webrender.ContentType;
import nextapp.echo2.webrender.output.CssStyle;
import nextapp.echo2.webrender.service.CoreServices;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Element;

public class MyWindowHtmlService
extends WindowHtmlService
{
private static Log log = LogFactory.getLog(MyWindowHtmlService.class);

public void service(Connection conn)
throws IOException
{
final String METHOD = "service: ";
log.debug(METHOD+"conn="+conn);

ContainerInstance ci = (ContainerInstance)conn.getUserInstance();
conn.setContentType(ContentType.TEXT_HTML);
boolean debug = !"false".equals(conn.getServlet().getInitParameter("echo2.debug"));
BaseHtmlDocument baseDoc = new BaseHtmlDocument("c_root");
baseDoc.setGenarator("NextApp Echo v2.1.0.rc2");

/* add google maps api */
baseDoc.addJavaScriptInclude(
"js/googleload.js");

baseDoc.addJavaScriptInclude(ci.getServiceUri(CoreServices.CLIENT_ENGINE));
baseDoc.getBodyElement().setAttribute("onload", "EchoClientEngine.init('" + ci.getServletUri() + "', " + debug + ");");
Element bodyElement = baseDoc.getBodyElement();
CssStyle cssStyle = new CssStyle();
cssStyle.setAttribute("position", "absolute");
cssStyle.setAttribute("font-family", "verdana, arial, helvetica, sans-serif");
cssStyle.setAttribute("font-size", "10pt");
cssStyle.setAttribute("height", "100%");
cssStyle.setAttribute("width", "100%");
cssStyle.setAttribute("padding", "0px");
cssStyle.setAttribute("margin", "0px");
cssStyle.setAttribute("overflow", "hidden");
bodyElement.setAttribute("style", cssStyle.renderInline());
baseDoc.render(conn.getWriter());
}

public static final MyWindowHtmlService INSTANCE =
new MyWindowHtmlService();
}


The implementation of the service method of MyWindowHtmlService is copied from the original implementation and extended with the
baseDoc.addJavaScriptInclude("js/googleload.js"); which loads the google maps api with my key.

Ok, that is not really far away from patching the class, but still... It might work with forthcoming versions of echo2.

Wednesday, 23 May 2007

Maven archetype for echo2 application

While testing echo2
I searched for a maven archetype which creates an initial echo2 application..,
and did not find one.

So I made one available at
http://maven-repository.banapple.de/de/banapple/maven/archetype/

If you are interested download the jar and install it in your local maven repository and then
create your echo2 app with

# mvn archetype:create \
-DarchetypeGroupId=de.banapple.maven.archetype \
-DarchetypeArtifactId=echo2 \
-DarchetypeVersion=1.0-SNAPSHOT \
-DgroupId=<your groupId here> \
-DartifactId=<your artifactId here>


Change to the newly created directy and test the application with

# mvn jetty:run


This starts a jetty server on port 8080 in which the application runs.

The archetype uses echo2 libraries which are deployed on
maven-repository.banapple.de, too.

Thursday, 17 May 2007

Creating POST requests with curl for Axis2 REST service

Axis2 allows to create REST services as easily as SOAP services. By default each
SOAP service has a REST counterpart automatically available.

The responses for REST requests served by Axis2 are the same as SOAP responses but
are missing the enclosing SOAP envelope (this is because REST is handled inte
rnally like a SOAP request). Because of this the responses are currently missing
the REST feature to return links to other resources in the response.

But creating REST requests is somewhat easier than SOAP requests. This article
describes an example where a REST request is sent with curl.

Axis2 uses document-style services by default. The following excerpt of the
webservice WSDL which was used shows the XML schema for the data to be transmitted:


<xs:schema xmlns:ns="http://impl.service.banapple.de/xsd" attributeFormDefault="qualified" elementFormDefault="unqualified" targetNamespace="http://impl.serv ice.banapple.de/xsd">
<xs:element name="createContact">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="incomingData" nillable="true" type="ns10:IncomingData" />
<xs:element maxOccurs="unbounded" name="foreignKeys" nillable="true" type="ns10:IncomingForeignKey" />
<xs:element name="incomingCreator" nillable="true" type="ns10:IncomingCreator" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="createContactResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="return" nillable="true" type="xs:int" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
<xs:schema xmlns:ax242="http://bean.model.banapple.de/xsd" xmlns:ax283="http://lang.java/xsd" xmlns:ax244="http://util.java/xsd" attributeFormDefault="qualified" elementFormDefault="unqualified" targetNamespace="http://bean.model.banapple.de/xsd">
<xs:import namespace="http://util.java/xsd" />
<xs:import namespace="http://lang.java/xsd" />
<xs:element name="IncomingData" type="ns10:IncomingData" />
<xs:complexType name="IncomingData">
<xs:sequence>
<xs:element name="creationDate" type="xs:long" />
<xs:element name="dataTypeName" nillable="true" type="xs:string" />
<xs:element name="dataValue" nillable="true" type="xs:string" />
</xs:sequence>
</xs:complexType>
<xs:element name="IncomingForeignKey" type="ns10:IncomingForeignKey" />
<xs:complexType name="IncomingForeignKey">
<xs:sequence>
<xs:element name="foreignKeyTypeName" nillable="true" type="xs:string" />
<xs:element name="foreignKeyValue" nillable="true" type="xs:string" />
</xs:sequence>
</xs:complexType>
<xs:element name="IncomingCreator" type="ns10:IncomingCreator" />
<xs:complexType name="IncomingCreator">
<xs:sequence>
<xs:element name="name" nillable="true" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:schema>


Two namespaces are used:
http://impl.service.banapple.de/xsd for the element describing the
operation,
http://bean.model.banapple.de/xsd for the parameters of the operation.

The example payload for the request is the following:


<createContact
xmlns="http://impl.service.banapple.de/xsd"
xmlns:bean="http://bean.model.banapple.de/xsd">
<bean:incomingData>
<creationDate>0</creationDate>
<dataTypeName>CUSTOMER_ID</dataTypeName>
<dataValue>300042045</dataValue>
</bean:incomingData>
<foreignKeys>
<foreignKeyTypeName>UCID</foreignKeyTypeName>
<foreignKeyValue>1</foreignKeyValue>
</foreignKeys>
<incomingCreator>
<name>Foobar</name>
</incomingCreator>
</createContact>


The payload was stored in a file createcontact.xml and sent to the
REST service with curl with the command:


curl -H "Content-Type: text/xml; charset=UTF-8"
--data-binary @createcontact.xml
http://localhost:8080/contactdb/rest/DataReceiverService/createContact



It is important to sent the Content-Type header otherwise the REST
service will produce an error response with the not very helpful message

Required element null defined in the schema can not be found in the request