Category Archives: Computer engineering

Apache and forwarding a client certificate Id to WebSocket

Recently I came across a problem of forwarding a certificate Id to backend service for the authentication purposes. I also do not want to handle SSL at services.

Let’s say I have a server setup as follows: There is an Angular website on port 4200 and REST/Websocket services on port 3000. REST services are accessible over endpoint /kumuluz and Websocket connections via /v1/devices. As a common facade to access these services I set up Apache as a reverse proxy as in an example configuration below.

To extract a field from a client certificate (e.g. CN in my case) and forward request to a backend REST server with an additional header field is not a problem. I just extract property %{SSL_CLIENT_S_DN_CN}s and set a header field clientId.

The problem comes, when you would like to do the same for the Websocket connections – you cannot set header for these type of connections. But you can do a workaround (the point of this post): Tell clients to connect to the endpoint /v1/devices/CLIENT_ID and then check if the parameter matches the client id of underlying client certificate. Now you forced the client to use the correct ids in URL, which you can use for authentication as Apache forwards only requests where SSLRequire successes.



   ServerName portal.zitnik.si
   Redirect permanent / https://portal.zitnik.si/



        ServerAdmin slavko@zitnik.si
        ServerName portal.zitnik.si
        ServerAlias portal.zitnik.si

        DocumentRoot /var/www

        ProxyPreserveHost On
        ProxyRequests Off

        ProxyPass /images !
        
        ProxyPass /v1/devices ws://localhost:3000/v1/devices
        ProxyPassReverse /v1/devices ws://localhost:3000/v1/devices

        ProxyPass /kumuluz http://localhost:3000
        ProxyPassReverse /kumuluz http://localhost:3000

        ProxyPass / http://localhost:4200/
        ProxyPassReverse / http://localhost:4200/

        RedirectMatch ^/$ https://portal.zitnik.si

        SSLEngine on
        SSLCertificateFile /home/slavkoz/certs/portal.zitnik.si.crt
        SSLCertificateKeyFile /home/slavkoz/certs/portal.zitnik.si.key

        SSLCACertificateFile /home/slavkoz/certs/CA.pem
        SSLVerifyClient none
        RequestHeader set clientId ""

        
                SSLVerifyClient require
                SSLVerifyDepth 1

                RequestHeader set clientId "%{SSL_CLIENT_S_DN_CN}s"
        

        
                SSLVerifyClient require
                SSLVerifyDepth 1

                SetEnvIf Request_URI "/v1/devices/(.*)$" CLIENT_ID=$1
                SSLRequire       %{SSL_CLIENT_S_DN_CN}  eq %{ENV:CLIENT_ID}
        

Creating a Mac OS .app from a runnable JAR file

Here we solve a problem that many developers face when bundling java applications into an .app. We are going to correctly set the current working path for your Java Application.

Mac OS applications (.app files) are basically packages with a specific folder structure. You can easily explore each app’s structure by clicking on it using right click in Finder and selecting “Show Package Contents”.

Screen Shot 2016-02-21 at 11.42.41

Screen Shot 2016-02-21 at 11.42.53

 

Creating a custom .app

Create a folder PROGRAM_NAME.app. The Finder will ask you the following, which you will answer as add.

Screen Shot 2016-02-21 at 11.46.37

Now, show contents of you app and inside it create a folder structure /Contents/MacOS. Also create a blank script file launcher.sh (in my case, I am using Sociogram as a program name).

Screen Shot 2016-02-21 at 12.49.45
This script needs to be an executable, so open Terminal and run a command like this:

chmod a+x Sociogram.app/Contents/MacOS/launcher.sh

Maybe you have noticed that your .app does not have an icon. Therefore you need an .icns icon. I used a web service (https://iconverticons.com/online/) to convert my PNG file to an appropriate ICNS file.

Now, create a folder Resources and copy your icon there:

Screen Shot 2016-02-21 at 12.51.25

 

The last step now is to create a config file Info.plist that will define, which is an executable file in your app and where is your .app icon:

Screen Shot 2016-02-21 at 12.54.14

After these steps, you should have prepared an .app file, which looks like as follows:

Screen Shot 2016-02-21 at 12.55.39

Creating a runnable script for a JAR

First, let use create a Java Application that will print out the current working directory and package it into a runnable JAR (sociogram.jar):

import javax.swing.*;
import java.awt.*;
 
/**
 * Created by slavkoz on 21/02/16.
 */
public class Runner {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
 
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        panel.add(new JTextField(System.getProperty("user.dir")), BorderLayout.CENTER);
        frame.setContentPane(panel);
 
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }
}

If we now just run that jar from a launcher script, the default working directory for Java would be “/”, so we may have problem accessing resources, that are packaged inside our .app.

Therefore, let us create an executable socioRunner script that will accept current working dir and run our java application from there. We put the script in the same directory as the launcher script.

#!/bin/sh
 
DIR=$1
APP_JAR="sociogram.jar"
APP_NAME="Sociogram 5.0"
 
cd "$DIR"
java -Xdock:name="$APP_NAME" -Xdock:icon="$DIR/../Resources/application.icns" -cp "$DIR;.;" -jar "$DIR/$APP_JAR"

Now, we can update the launcher script, which will detect the directory, where it resides and run the socioRunner script with a parameter:

#!/bin/sh
 
# Set the working directory
DIR=$(cd "$(dirname "$0")"; pwd)
 
# Run the application
exec "$DIR/socioRunner" $DIR

So, voila, now we get the following result when the .app application is run from Finder:

Screen Shot 2016-02-21 at 13.32.45

You can download the whole .app file from here: https://blog.zitnik.si/manual_upload/Sociogram.app.zip

A simple custom solution to multi-language support using JS

Recently, I needed to add a multi-language support to a website that was run using PHP. Sure, I could use some i18n PHP framework to deliver translated web-page directly from a server, but I decided to design a simple approach based on Javascript.

Here it goes …

The default language is supposed to be slovene, so visiting a page by url http://mywebpage would show a slovene version. To get a webpage in a specific language, you need to explicitly define the language using a parameter, like so: http://mywebpage?lang={sl, hr, en}. Of course, this is used in a header of a web page for a languages selection menu:

<a id="lang-sl" href="/?lang=sl">Slovenski</a>|
<a id="lang-hr" href="/?lang=hr">Hrvatski</a>|
<a id="lang-en" href="/?lang=en">English</a>

In the webpage, I introduced a “lang” HTML tag, which acts as a placeholder for a language-specific text:

<lang id="home" />

For each language I create a separate JS file that includes a map variable, whose keys are ids used in HTML placeholders and values are translated texts. For example, a file “lang.sl.js” includes slovene translations:

var lang = {
    home: "Domov",
    about: "O programu",
    functionalities: "Funkcionalnosti",
    ....
};

Now, as we have everything prepared, we are going to write a JS script that (A) automatically detects a selected language from query string, (B)  includes an appropriate translation file and (C) automatically populates prepared HTML placeholders. I do this as follows:

$(document).ready(function() {
 
	$.urlParam = function(name){
		var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
		if (results==null){
		   return null;
		}
		else{
		   return results[1] || 0;
		}
	}
 
	function loadJS(file) {
		var jsElm = document.createElement("script");
		jsElm.type = "application/javascript";
		jsElm.src = file;
 
		$("body").prepend(jsElm);
	}
 
	if ($.urlParam("lang") == "en") {
		loadJS("js/lang.en.js");
		$("#lang-en").css("font-weight", "bolder");
	} else if ($.urlParam("lang") == "hr") {
		loadJS("js/lang.hr.js");
		$("#lang-hr").css("font-weight", "bolder");
	} else {
		loadJS("js/lang.sl.js");
		$("#lang-sl").css("font-weight", "bolder");	
	}
 
	function fillIn(key, value) {
		document.getElementById(key).innerHTML = value;	 	
	}
 
 
	//Fill in translations	
	for(var key in lang) {
	  fillIn(key, lang[key]);
	}
 
});

Additionally to that basic example I added some exceptions to insert language-specific values into some HTML tag attributes.

Such approach works like a charm for about 200 language keys – I have not tested for more. The whole site is served by an RPi and JS loading of language-specific texts is not noticeable on a client.