<< Previous | Home

Reserved characters in WebSphere Application Server passwords... Really!?

Had somewhat of a surprise today when IBM Support informed us that the issue our customer was experiencing could be due to unsupported characters in the password of the user mapped to the connectionsAdmin J2C alias. Say what!? But apparently there are restrictions on the different characters one can use. The password we were using had exclamation point (!) in it which is a no no. The customer is currently on WebSphere Application Server and support suggested we try and upgrade to Funny thing is that the customer has been using that password for years so it must have worked previously.

IBM Connections wiki: Special characters in password

WebSphere Application Server 8.5.5 InfoCenter: Characters that are valid for user IDs and passwords

First Git hook for Atlassian Bitbucket (formerly Atlassian Stash)

For my current project I've setup a full CI pipeline to automate the build process of the application (an EAR-file in this case) and deploy it to the test server. The build itself is a Maven build that runs all the tests and builds the EAR file. We are a number of people working on the application - some do frontend work (mainly JavaScript) and I do the backend. The Git repository we use is split into three branches as it concerns this project - one for backend (feature/eventboard_backend), one for frontend (feature/eventboard_frontend) and one that merges the two into the final result for building (feature/eventboard). So I was setting all this up - had the build script ready, the build server ready (Atlassian Bamboo), the deployment script working over SCP/SSH but I needed a nice way to automatically merge the two development branches into the main branch for the build.

The way I solved it was to write a Git post-receive hook on the Git server side (Atlassian Bitbucket). This post-receive hook detects a push to either of the two development branches and when it does merges the two into the main branch and pushes it branch back up. This push is in turn detected by Atlassian Bamboo that then kicks of the build and the deployment. So nice. Even though it took me a couple of hours to configure it has already saved so much time and all builds and deployments are consistant.

Today I extended the build script to monitor another branch so I now both deploy into our "bleeding edge" environment and our test environment.

The post-receive hook is written in bash and is as below. It took me a while to grok but a hook is simply a script that runs as the server OS user when ever something happens. The script is free to run as another user so my script runs as a special Git user so we can distinguish between which users does what. It also means that I could restrict access to feature/eventboard branch so it's only writable by this build user.

The only caveat about this hook was that we are using Atlassian Bitbucket which apparently only accepts hooks written in Java. There is however a way to add bash-based hooks directly in the file system on the server under /<bitbucket-home>/shared/data/repositories/<repoid> where the repoid can be found in the repository settings on the Bitbucket server if logged in as admin.



while read oldrev newrev refname
        branch=$(git rev-parse --symbolic --abbrev-ref $refname)
        echo "Currently on branch '$branch'"
        if [ "$MONITOR_BRANCH1" == "$branch" ] || [ "$MONITOR_BRANCH2" == "$branch" ]; then
                echo "Detected commit on $MONITOR_BRANCH1 or $MONITOR_BRANCH2 - merging..."
                if [ ! -d "$WORKING_DIR" ]; then
                        mkdir -p $WORKING_DIR
                cd $WORKING_DIR
                unset GIT_DIR
                if [ ! -d "$CHECKOUT_NAME" ]; then
                        # repo doesn't exit - abort
                        echo "*** Required repo for post-receive hook not configured - exiting..."
                        cd $CHECKOUT_NAME
                        git reset --hard
                        git checkout $MERGE_INTO_BRANCH
                        git pull origin $MERGE_INTO_BRANCH
                git fetch origin $MONITOR_BRANCH1:$MONITOR_BRANCH1
                git fetch origin $MONITOR_BRANCH2:$MONITOR_BRANCH2
                git merge $MONITOR_BRANCH1 $MONITOR_BRANCH2 -m "Merged \
                          '$MONITOR_BRANCH1' and '$MONITOR_BRANCH2' into \
                git push origin $MERGE_INTO_BRANCH

Using Tomcat APR (Apache Native Runtime) on Mac

I had to document some steps using the Apache Portable Runtime (APR) and TLS configuration and for that needed APR on my Mac. I couldn't really make it work at first but after fiddling a bit I figured it out. There are the steps in bullet form:

Download APR and compile

  • Download APR from Apache (http://apr.apache.org/). I downloaded v. 1.5.2.
  • Compile in Terminal.
    • CFLAGS='-arch x86_64' ./configure
    • make
    • make test
    • make install

Install OpenSSL with headers

The OpenSSL on Mac doesn't come with the header files so you cannot compile the Tomcat native library by default. To fix that use Homebrew to install a new version of OpenSSL first.
  • Install Homebrew per instructions on the website
  • brew install openssl

Compile Tomcat native library

The Tomcat native library is supplied with the Tomcat download. My Tomcat was v. 8.0.17. Steps as below:
  • cd Tomcat8.0.17/bin
  • gunzip tomcat-native.tar.gz
  • tar xf tomcat-native.tar
  • cd tomcat-native-1.1.32-src/jni/native
  • CFLAGS='-arch x86_64' ./configure --with-apr=/usr/local/apr --with-ssl=/usr/local/opt/openssl
  • make
  • make install

Configure Tomcat to use APR

This step is basically just to make sure that the Tomcat native library is on the Java Library path. Do as follows:
  • cd Tomcat8.0.17/bin
  • vi setenv.sh
  • Add text: JAVA_OPTS="-Djava.library.path=/usr/local/apr/lib"

Now when you run Tomcat using catalina.sh you should see a line like below stating what version of the native library was loaded.

15-May-2016 18:14:01.106 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent 
     Loaded APR based Apache Tomcat Native library 1.1.32 using APR version 1.5.2.

Further reading:

Test agents in Eclipse by extending AgentBase

I continuously get questions on how I do Java agent development and I'm happy to answer them as I hope that some of the answers I provide means that more and more Domino developers see Java as a strong alternative to LotusScript for background processing. Most times the approach I recommend is a mock object approach that I wrote about waaaaaay back in 2006 (did I really write that 10 years ago?!?!?).

If / when you want to read the posts please start from part no. 1. Here's a link to all 5 parts:

The approach doesn't handle importing the code back into Domino Designer but it does allow you to "mock" the Notes side of the API and allows you to write, test and debug your agents in Eclipse. Then when they're completely done you can import it back into Notes without any changes. This is the approach I would choose and that I still use when writing Java agents here 10 years later.

Hope this helps but if it doesn't please let me know.

Working with routes from the IBM Bluemix CLI

Today I played with routes on IBM Bluemix. Routes are how you access the app on IBM Bluemix so basically they are hostnames mapped to apps. By default apps are assigned a hostname under mybluemix.net but once you've proved a domain belongs to you you may also may custom domain names to your apps. Of course you still need to create a CNAME record in DNS to make it map correctly but you get the point. Working with routes is possible from the GUI but the command line interface (CLI) is more efficient. Below are the commands I use to work with routes. All of the commands assumes you're already logged in... Actual commands in bold.

Listing the routes (as you can see some routes are not bound to apps): cf routes

Getting routes as lekkim ...

space   host                                                domain            apps   
dev     ontime-ibm-connected-2015-verse-demo-contribution   mybluemix.net     IBM ConnectED 2015 Verse Demo Contribution   
dev     otgc-verse                                          mybluemix.net     IBM ConnectED 2015 Verse Demo Contribution   
dev     mikkel-otgcms-test                                  mybluemix.net     Mikkel OTGCMS Test   
dev     mikkel-otgcms-test                                  ontimesuite.com   Mikkel OTGCMS Test   
dev     neodashboard-oauth                                  mybluemix.net     neodashboard-oauth   
dev     spring-boot-demo-mikkel                             mybluemix.net     Spring-Boot-Demo-Mikkel   
dev     engageugdemo                                        mybluemix.net     engageugdemo   
dev     engagedemoapp1                                      mybluemix.net        
dev     engagementdemo1                                     mybluemix.net        
dev     engageugdemoapp                                     mybluemix.net  
Map a route called myapp.ontimesuite.com to the engageugdemo app: cf map-route engageugdemo ontimesuite.com -n myapp
Creating route myapp.ontimesuite.com for org lekkim / space dev as lekkim...

Unmap a route called myapp.ontimesuite.com from the engageugdemo app: cf unmap-route engageugdemo ontimesuite.com -n myapp
Removing route myapp.ontimesuite.com from app engageugdemo in org lekkim / space dev as lekkim...

Permently delete the myapp.ontimesuite.com route from your account: cf delete-route ontimesuite.com -n myapp
Deleting route engageugdemo.ontimesuite.com...

Tags : , , ,

Slides and recorded, narrated, demo from my Engage.ug session on OAuth

Last week at the Engage user group in Eindhoven, The Netherlands, I gave a session on OAuth 2.0, how the protocol works and how easy it is the code against. The demo I showed at the end of the session showed just how easy it is and how little code is required to make a fully functioning OAuth 2.0 Client. Below you'll find the slides on Slideshare as well as a recorded, narrated, demo. The demo walks you through coding an OAuth 2.0 app in Eclipse and deploying it to IBM Bluemix.

Oh and do remember... Never, EVER, use a library until you understand the protocol.


Have a Synology Diskstation at home which I among other things use as an OpenVPN server. When I'm traveling I enjoy being able to watch Danish TV without any geographical restrictions. I do this by having my OpenVPN profile (ovpn file) tunnel all traffic through the VPN incl. DNS. It also means that I can use it to safely browse if on a questionable wifi such as no-encryption hotel wifi or conference wifi. The two commands you need to add to the configuration generated by the OpenVPN server on the Synology ( being by DNS in the house) is as follows:

dhcp-option DNS"
redirect-gateway def1

Certificate bananza...

Helped a collegue yesterday for a few hours configuring his system with TLS certificates and showed code to enable authentication using client certificates. All easy enough if you know how... :) Start by creating keys and certificates for a server and a person and create a Domino KYR keystore using the kyrtool from IBM. The below commands were all executed on Linux.

# change dir
cd /local/notesdata/

# generate key and self-signed cert for server
openssl genrsa -out server.key 4096
cat server.key 
openssl req -new -sha256 -key server.key -out server.csr
openssl x509 -req -days 3650 -sha256 -in server.csr -signkey server.key -out server.pem

# use kyrtool to generate kyr-file for Domino (all calls to startup below is actually 
# /opt/ibm/domino/bin/tools/startup
startup /opt/ibm/domino/bin/kyrtool =/local/notesdata/notes.ini
startup /opt/ibm/domino/bin/kyrtool =/local/notesdata/notes.ini create 
          -k ./server.kyr -p password
cat server.key > server.txt
cat server.pem  >> server.txt 
cat server.txt 
startup /opt/ibm/domino/bin/kyrtool =/local/notesdata/notes.ini 
          verify ./server.txt 
startup /opt/ibm/domino/bin/kyrtool =/local/notesdata/notes.ini 
          import all -k ./server.kyr -i ./server.txt
startup /opt/ibm/domino/bin/kyrtool =/local/notesdata/notes.ini 
          show keys -k ./server.kyr 
startup /opt/ibm/domino/bin/kyrtool =/local/notesdata/notes.ini 
          show certs -k ./server.kyr 

# generate PKCS#12 for a user
openssl genrsa -out person.key 4096
openssl req -new -sha256 -key person.key -out person.csr
openssl x509 -req -days 3650 -sha256 -in person.csr -CA server.pem 
          -CAkey server.key -out person.pem -CAcreateserial
openssl x509 -in person.pem -text -noout
openssl pkcs12 -export -out person.p12 -inkey person.key -in person.pem -certfile server.pem
Import the the person.p12 file on a person document in Domino Directory. Now copy server.kyr and server.sth to the Domino data dirctory and create an Internet Sites document using the keystore. Also edit the Internet Site document to allow certificate based authentication. The code below uses the PKCS#12 file to do an authenticated request using certificates as authentication.
package demo.intravision.certauth;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class Main {

   public static void main(String[] args) {
      try {
         new Main().run();
      } catch (Throwable t) {
   public void run() throws Exception {
      // get url and open connection
      URL url = new URL("https://secure.krynn.local/testauth.nsf/username.json?open&login");
      HttpURLConnection con = (HttpURLConnection)url.openConnection();
      // apply SSL context (sets up the certificate to use for authentication etc)
      // read from url
      BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
      StringBuilder b = new StringBuilder();
      String line = null;
      while (null != (line = reader.readLine())) {
      // show data
      // disconnect

   private void applySSLContext(HttpURLConnection con) throws Exception {
      // password
      final char[] password = "password".toCharArray();
      // input stream to pkcs12 file
      InputStream certificateInputStream = new FileInputStream("/Users/lekkim/Downloads/aran.p12");
      // load key and key manager
      KeyStore ks = KeyStore.getInstance("PKCS12");
      ks.load(certificateInputStream, password);
      KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
      kmf.init(ks, password);
      // get trust manager
      X509TrustManager customTrustMgr = this.getTrustManager();
      // build ssl context
      SSLContext sc = SSLContext.getInstance("TLSv1.2");
      sc.init(kmf.getKeyManagers(), null == customTrustMgr ? null : new TrustManager[]{customTrustMgr}, null);
      // set socket facory if https
      if (con instanceof HttpsURLConnection) {
         HttpsURLConnection httpsCon = (HttpsURLConnection)con; 
   private X509TrustManager getTrustManager() throws Exception {
      // returning null uses the trust from the JVM cacerts keystore
      if ("1".equals("2")) return null;
      // define trust manager
      X509TrustManager customTrustMgr = new X509TrustManager() {
          public X509Certificate[] getAcceptedIssuers() {
             return new X509Certificate[]{};

          public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {

          public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
      return customTrustMgr;