Selbstsigniertes SSL Zertifikat für Tomcat und APR erstellen

Im letzten Blog-Eintrag zeigte ich, wie man die Tomcat-Native-Libraries mit APR installieren kann. Soll dazu SSL verwendet werden, benötigt der APR-Connector dazu ein PEM-kodiertes SSL-Zertifkat.

Ein selbstsigniertes Zertifikat lässt sich relativ leicht selbst erstellen.

Zunächst wird ein privater Schlüssel erzeugt:
openssl req -new -out tomcat.csr -keyout tomcat.pem
Generating a 1024 bit RSA private key
.......................................++++++
.++++++
writing new private key to 'tomcat.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:DE
State or Province Name (full name) [Some-State]:Hamburg
Locality Name (eg, city) []:Hamburg
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Timo Meinen
Organizational Unit Name (eg, section) []:localhost
Common Name (eg, YOUR name) []:localhost
Email Address []:timomeinen@gmail.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Anschließend liegen zwei Dateien im Verzeichnis: Der private Schlüssel tomcat.pem und der Certifikation-Request tomcat.csr.

Mit dem folgenden Befehl kann man ein unverschlüsseltes Zertifikat erzeugen:
openssl rsa -in tomcat.pem -out tomcat.key
Enter pass phrase for tomcat.pem:
writing RSA key

Der letzte Schritt ist die Selbstsignierung des Zertifikates. Dieses kann dann gemeinsam mit dem privaten Schlüssel in Tomcat konfiguriert werden:
openssl x509 -in tomcat.csr -out tomcat.crt -req -signkey tomcat.key
Signature ok
subject=/C=DE/ST=Hamburg/L=Hamburg/O=Timo Meinen/OU=localhost/CN=localhost/emailAddress=timomeinen@gmail.com
Getting Private key

Die .csr und die .pem Datei kopiert man nun an einen geeigneten Platz z.B.
cp tomcat.* /Applications/apache-tomcat-6.0.26/conf/

Die Konfiguration in Tomcats server.xml ist schnell gemacht:

<connector port="8443" maxThreads="200"
scheme="https" secure="true" SSLEnabled="true"
SSLCertificateFile="/Applications/apache-tomcat-6.0.26/conf/tomcat.crt"
SSLCertificateKeyFile="/Applications/apache-tomcat-6.0.26/conf/tomcat.pem"
SSLPassword="changeit"
clientAuth="optional" SSLProtocol="TLSv1"/>

Der Unterschied zur Konfiguration mit einem Keystore sind die drei Anweisungen SSLCertificateFile, SSLCertificateKeyFile und SSLPassword. Sie werden hier erklärt.

Nun kann Tomcat von APR und OpenSSL profitieren.

Eine schöne Übersicht über das Thema SSL-Zertifakte erstellen gibt es u.a. in Jian Fang's Wiki.

Apache Tomcat Native Libraries unter Mac OS X installieren

Vor knapp zwei Wochen wurde die neue Tomcat Version 6.0.26 veröffentlicht. Zeitgleich wurden die Tomcat-Native-Libraries auf die Version 1.1.20 aktualisiert. Tomcat-Native verbindet die Apache Portable Runtime mit dem Web-Container. Dies bringt höhere Stabilität, höhere Performanz und die Möglichkeit OpenSSL im Tomcat bentuzen zu können.

Hier ist eine Anleitung, um die Native-Libraries unter Mac OS X zu installieren:

Zunächst muss APR installiert werden, was am leichtesten über MacPorts:
sudo port install apr

Auch die tomcat-native gibt es als Port, allerdings nur in der alten Version 1.1.14, die mit der aktuellen Tomcat Version nicht mehr kompatibel ist. Daher gibt es nun zwei Möglichkeiten:

  1. Einen Port-Patch einspielen: Tomcat-Native-1.1.20 Patch
  2. Die Libraries selbst kompilieren

Da das selber kompilieren unter Mac OS X nicht schwierig ist, zeige ich diesen Weg:

Paket herunterladen und entpacken:
http://tomcat.apache.org/download-native.cgi
tar xf tomcat-native-1.1.20-src.tar.gz
cd tomcat-native-1.1.20-src/jni/native/

Mit configure alles konfigurieren:
./configure --with-apr=/usr/local/apr --with-java-home=$JAVA_HOME --with-ssl=/usr
Wer kein SSL benötigt kann einfach --without-ssl angeben.

Kompilieren und installieren:
make
sudo cp .libs/libtcnative* /usr/lib/java/

Wenn man nun den Tomcat startet, kann man in den Log-Meldungen prüfen, ob die Native-Library geladen wird:
/Applications/apache-tomcat-6.0.26/bin/catalina.sh run
19.03.2010 09:20:21 org.apache.catalina.core.AprLifecycleListener init
INFO: Loaded APR based Apache Tomcat Native library 1.1.20.
19.03.2010 09:20:21 org.apache.catalina.core.AprLifecycleListener init
INFO: APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true].

Sollte es zu einer Fehlermeldung kommen, dass der Poller nicht erstellt werden konnte, muss die pollerSize im Connector angepasst werden:
19.03.2010 09:20:41 org.apache.tomcat.util.net.AprEndpoint allocatePoller
INFO: Failed to create poller with specified size of 8192

<connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
pollerSize="1024" >>

Wird kein SSL benutzt ist man nun fertig. Ansonsten ist die SSL Konfiguration in den Connector-Eintragen in der server.xml bei APR-Nutzung anders:

APR Connector configuration
Tomcat SSL howto

Möchte man auf den APR-SSL support verzichten, kann auch einfach das protocol überschrieben werden:

< -- Define a blocking Java
SSL Coyote HTTP/1.1 Connector on port 8443 -->
protocol = "org.apache.coyote.http11.Http11Protocol"
port="8443"

< -- Define a non-blocking Java
SSL Coyote HTTP/1.1 Connector on port 8443 -->
protocol = "org.apache.coyote.http11.Http11NioProtocol"
port="8443"

Hier noch ein kleiner Grund, warum sich der Aufwand lohnt: Unsere aktuelle Web-Anwendung it.projektwerk.com startet ohne APR in ca. 25 Sekunden. Mit APR in 15 Sekunden.

Find all JUnit tests in a project

In einem Kundenprojekt haben wir verschiedene Kategorien von Tests eingeführt: Unit-Tests, Integration-Tests und Selenium-Tests. Da die Tests unterschiedliche Konfigurationen erfordern (z. B. Selenium Server starten) und auch die Testausführung unterschiedlich lang ist, wollten wir diese Tests in Testsuiten von JUnit aufnehmen.

Testsuiten haben einige Vorteile, so lässt sich die Testreihenfolge festlegen (auch wenn Tests prinzipiell unabhängig voneinander sein sollten, kann es bspw. dazu genutzt werden Testdaten in das System einzufahren). Ein weiterer Vorteil besteht darin, dass Testsuiten von allen IDEs und Buildsystemem gestartet werden können. IntelliJ IDEA erlaubt keine regulären Ausdrücke bei der Auswahl der Tests, was dazu führt, dass man die *IntegrationTest.java nicht getrennt von den *Test.java Klassen ausführen kann. Stattdessen müssen immer Einstiegsklassen in die Tests angegeben werden.
Maven, genauer das Surefire-Plugin, dagegen unterstützt nur eine Filterung auf Dateiebene über die Include-Filter.
Testsuiten sind gewönliche Java-Klassen die mit @Suite annotiert werden. Diese Java-Klasse kann nun von allen IDEs und Build-Systemen als Startpunkt für die Tests genutzt werden.

@RunWith(Suite.class)
@Suite.SuiteClasses({
  UserUnitTest.class,
  AnotherUnitTest.class
})
public class UnitTestSuite {}

Der riesengroße Nachteil von Testsuiten ist, dass sie gepflegt werden müssen. Werden neue Tests geschrieben, müssen die Klassen der Suite hinzugefügt werden, da sie sonst vom CI-Server nicht ausgeführt werden. Das führte bei uns im Projekt nach relativ kurzer Zeit dazu, dass einige Testklasse zwar angelegt wurden, aber nicht in der Suite enthalten waren. Zum Glück haben wir die Shell und ein Skript zum Sammeln aller Unit-Tests ist schnell geschrieben:

find src/test/java/ -name '*.java' |
xargs grep -l "@Test" |
xargs grep -L "extends TestSetup" |
xargs grep -L "@RunWith" |
xargs basename |
sed 's/.java/.class,/g' |
sort

Der Phantasie sind natürlich keine Grenzen gesetzt, wie jetzt genau die Tests als Unit-, Integration- oder Selenium-Test erkannt werden. Im Beispiel werden alle Java-Klassen gefunden, die mindestens eine @Test Annotation haben, aber nicht von TestSetup erben und bei denen es sich nicht um Spring-Testcontext-Tests handelt, da diese im Projekt mit @RunWith markiert sind.

Wichtig ist lediglich die geeigneten grep Optionen zu verknüpfen:

  • grep -l: Das kleine L listet alle Treffer
  • grep -L: Findet alle Dateien, die nicht treffen
  • basename: Liefert den Dateinamen, damit er direkt in die Suite-Klasse eingesetzt werden kann
  • sed: Pure Faulheit: Macht aus den .java Endungen .class, damit die Ergebnisse per Copy & Paste eingesetzt werden können

Leider ist immer noch ein manuelles Prüfen der Tests notwendig, selbst wenn uns die Shell-Skripte jetzt alle Klassen liefern. Man könnte also einfach vor jedem Build dieses Skript ausführen, um alle Test-Klassen zu finden.

Gibt es bessere Vorschläge, TestSuiten automatisch zu befüllen? Ich freue mich auf Kommentare.

Silbentrennung in LaTeX mit ngerman und Bindestrich-Wörtern

Bindestrich-Wörter werden von LaTeX typografisch korrekt nur an den Bindestrichen getrennt. Das Paket ngerman bietet für den Bindestrich aber die Befehle "= für einen Bindestrich mit Trennmöglichkeit und "~ für einen Bindestrich ohne Trennmöglichkeit.

Der Vorteil gegenüber einem normalen Bindestrich mit - besteht darin, dass die Standard-Silbentrennung weiterhin funktioniert. Damit lassen sich viele Overfull \hbox-Fehler beseitigen.

LaTeX Zitat-Makro

Damit ich das Format aller Zitate an einer zentralen Stelle verwalten kann, habe ich mir ein kleines Makro geschrieben. Es macht aus

\zitat{bibtexCode}{Ein Zitat ohne Seitenzahl}

ein Zitat mit deutschen Anführungszeichen und kursiver Schrift.

Und mit

\zitat[S. 123]{bibtexCode}{Ein Zitat mit Seitenzahl}

wird sogar die Seitenzahl an den \cite Befehl übergeben.

Hier das Makro:

% Zitat-Abkürzung
\newcommand{\zitat}[3][]{%
\textit{\glqq#3\grqq} %
\ifthenelse{\equal{#1}{}}%
{\cite{#2}}%
{\cite[#1]{#2}}%
}%