Showing posts with label Maven. Show all posts
Showing posts with label Maven. Show all posts

Sunday, February 3, 2013

Versioning in a multi-app environment

I recently was published at IBM's developer works (see article) - woo hoo! But one thing I omitted was the matter of versioning.

Our floor is made up of many teams with many apps, some depending on the binaries of others. What makes our life harder is one team breaking another team's build when they change a library that is shared.

One conclusion we've drawn is never use Maven SNAPSHOTs. A build should always work or (if there is a genuine error) always fail. It should never be non-deterministic.

If shared code changes, other teams should be told in the daily stand-up that is attended by team representatives. Then, those dependent teams can change their versions in their sandbox and check it in when the code has been reconciled.

In short: if nothing has changed, builds should be absolutely predictable. 

Tuesday, March 6, 2012

Three curious things about Maven

1. The order of goals is significant. Goals clean install do not produce the same result as install clean. For example:

$ mvn clean install > /dev/null
$ ls
pom.xml target
$ mvn install clean > /dev/null
$ ls
pom.xml



2. You might know that you can show the dependency tree with mvn dependency:tree but did you know you can show where in that tree a certain artifact is? This is done by specifying

-Dincludes=[GROUP_ID]:[ARTIFACT_ID][:VERSION]

For example:

$ mvn dependency:tree -Dincludes=:spring-context

selectively shows all the dependencies with the artifact of spring-context.


3. If a library appears multiple times but with different versions, Maven re-orders the dependencies based on how deep in the tree they are. From the Apache documentation:

Dependency mediation - this determines what version of a dependency will be used when multiple versions of an artifact are encountered. Currently, Maven 2.0 only supports using the "nearest definition" which means that it will use the version of the closest dependency to your project in the tree of dependencies. You can always guarantee a version by declaring it explicitly in your project's POM. Note that if two dependency versions are at the same depth in the dependency tree, until Maven 2.0.8 it was not defined which one would win, but since Maven 2.0.9 it's the order in the declaration that counts: the first declaration wins.

"nearest definition" means that the version used will be the closest one to your project in the tree of dependencies, eg. if dependencies for A, B, and C are defined as A -> B -> C -> D 2.0 and A -> E -> D 1.0, then D 1.0 will be used when building A because the path from A to D through E is shorter. You could explicitly add a dependency to D 2.0 in A to force the use of D 2.0

Friday, August 12, 2011

Tomcat/Maven plugin

My consultancy contract has come to an end so now I have time to attend my much neglected blog.

In the last few months, I have been Maven-izing and modularizing a legacy application. (Architectural tip: err on the side of being too modularized. It's much easier to fuse modules together than to split them.)

Anyway, one of the jobs was to improve the developer experience by having a web app running via Maven. The advantages include the project working straight out of the box with no awkward manual configuration. But it was only partially working with the Tomcat Maven Plugin. Some parts of the page were not loading because of NullPointerExceptions in our code. And yet, when I pointed a standalone version of Tomcat at the same exploded WAR, everything worked.

Using Firebug's debugger and single-stepping through Javascript code revealed nothing amiss. But stepping through code of the Tomcat embedded in the Maven plugin, I found this in org.apache.catalina.authenticator.AuthenticatorBase:

if (session != null && changeSessionIdOnAuthentication) {

Manager manager = request.getContext().getManager();

manager.changeSessionId(session);

request.changeSessionId(session.getId());

}

So, session IDs were changing on each call. Indeed, Firebug did show that each AJAX call had a different JSESSIONID.

Further investigation shows that the Maven Tomcat Plugin uses Tomcat 6.0.29 (you can tell this by looking at the plugin's pom.xml). Our non-Maven Tomcat was 6.0.14.

What could be different? The change of a patch version number suggests bug-fixes and not new functionality. And what is this changeSessionIdOnAuthentication field?

It happens that we had a bespoke security plugin which extends Tomcat's AuthenticatorBase and authenticates on every HTTP call. With the default value of changeSessionIdOnAuthentication being true, this was causing the session to be discarded on the 6.0.29 Tomcat instance and so all fields in the session object to be uninitialized, ergo the NullPointerExceptions.

The changeSessionIdOnAuthentication field was added some time between releases 6.0.14 and 6.0.29. According to the Tomcat documentation, it is used "to prevent session fixation attacks".

These attacks are when somebody sends you a link to a website for which you have an account. The link includes the JSESSIONID that the attacker has been given by the website. You enter your credentials and the HTTP session associated with this JSESSIONID now carries some flag to say you have logged in. After this, the person who sent you the link can go to the website and as long as he is using the same JSESSIONID as you, he too can see your account since the associated HTTP sessions says you are authenticated.

The changeSessionIdOnAuthentication field being set to true means that as soon as you log in, you get a new JSESSIONID and the attacker is foiled.

Since our developers don't need to worry about this, we turned the functionality off in the server.xml file that the Maven plugin is told to use with:

<host name="localhost"... >
.
.
.
<valve classname="our.implementation.of.AuthenticatorBase" changeSessionIdOnAuthentication="false"...