Difference between revisions of "D4Science Portal HTTPS x509 Certificate Authentication"

From Gcube Wiki
Jump to: navigation, search
Line 1: Line 1:
 +
== How to configure Apache HTTP server and Apache Tomcat to handle X.509 certificates ==
 +
 +
The following setup shows how to configure Apache HTTP server in HTTPS so that X.509 client credentials can be forwarded to an internal Apache Tomcat instance.
 +
 +
=== Apache HTTP server ===
 +
Two VirtualHost should ne configured. The first one to handle HTTP requests on standard port 80, and redirect all of them to port 443 (HTTPS).
 +
 +
<pre>
 +
<VirtualHost *:80>
 +
ServerAdmin webmaster@localhost
 +
ServerName devportal.d4science.research-infrastructures.eu
 +
 +
DocumentRoot /var/www/
 +
 +
ErrorLog /var/log/apache2/error.log
 +
CustomLog /var/log/apache2/access.log combined
 +
 +
 +
        ProxyPreserveHost on
 +
        RewriteEngine on
 +
#RewriteRule (.*) https://devportal.d4science.research-infrastructures.eu$1 [R,L]
 +
 +
    #RewriteRule ^(.*)$ http://localhost:9090$1 [P,L]
 +
        Redirect permanent / https://newportal.d4science.research-infrastructures.eu/
 +
</VirtualHost>
 +
</pre>
 +
 +
The second virtual host is meant to handle HTTPS requests, asking clients to optionally authenticate with an X.509 certificates.
 +
 +
<pre>
 +
<VirtualHost *:443>
 +
ServerAdmin webmaster@localhost
 +
ServerName devportal.d4science.research-infrastructures.eu
 +
 +
DocumentRoot /var/www/
 +
<Directory />
 +
Options FollowSymLinks
 +
AllowOverride None
 +
</Directory>
 +
<Directory /var/www/>
 +
Options Indexes FollowSymLinks MultiViews
 +
AllowOverride None
 +
Order allow,deny
 +
allow from all
 +
</Directory>
 +
 +
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
 +
<Directory "/usr/lib/cgi-bin">
 +
AllowOverride None
 +
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
 +
Order allow,deny
 +
Allow from all
 +
</Directory>
 +
 +
ErrorLog /var/log/apache2/error.log
 +
 +
# Possible values include: debug, info, notice, warn, error, crit,
 +
# alert, emerg.
 +
LogLevel warn
 +
 +
CustomLog /var/log/apache2/access.log combined
 +
ServerSignature On
 +
 +
    Alias /doc/ "/usr/share/doc/"
 +
    <Directory "/usr/share/doc/">
 +
        Options Indexes MultiViews FollowSymLinks
 +
        AllowOverride None
 +
        Order deny,allow
 +
        Deny from all
 +
        Allow from 127.0.0.0/255.0.0.0 ::1/128
 +
    </Directory>
 +
 +
    SSLEngine on
 +
    SSLCertificateFile    /etc/apache2/ssl/containercert.pem
 +
    SSLCertificateKeyFile /etc/apache2/ssl/containerkey.pem
 +
 +
    SSLProxyEngine on
 +
 +
    SSLCACertificatePath /etc/grid-security/certificates/
 +
    SSLVerifyClient optional
 +
    SSLVerifyDepth 2
 +
 +
# this option is mandatory to force apache to forward the client cert data to tomcat
 +
    SSLOptions +ExportCertData
 +
 +
    <Proxy *>
 +
      AddDefaultCharset Off
 +
      Order deny,allow
 +
      Allow from all
 +
    </Proxy>
 +
 +
    ProxyPass / ajp://localhost:8020/
 +
    ProxyPassReverse / ajp://localhost:8020/
 +
 +
</VirtualHost>
 +
</pre>
 +
 +
The connection between Apache HTTP Server and Apache Tomcat is done via an AJP connector and Reverse Proxy directive. This means that the following modules need to be installed and loaded into Apache HTTP Server:
 +
* proxy
 +
* proxy_http
 +
* proxy_ajp
 +
 +
to install a new module into apache2 use the following command:
 +
 +
<pre>
 +
a2enmod <module_name>
 +
</pre>
 +
 +
=== Apache Tomcat ===
 +
 +
An AJP connector needs to be declared in order to enable communication between Apache HTTP Server and Apache Tomcat, with a redirect to port 8443 to handle the HTTPS connection inside Tomcat.
 +
 +
<pre>
 +
    <!-- Define an AJP 1.3 Connector on port 8020 -->
 +
    <Connector port="8020"
 +
              enableLookups="false" redirectPort="8443" protocol="AJP/1.3" URIEncoding="UTF-8" />
 +
</pre>
 +
 +
Eventually, a Connector needs to declared for port 8443 to handle the HTTPS connection in Tomcat.
 +
 +
<pre>
 +
    <Connector port="8443" maxHttpHeaderSize="8192"
 +
              maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
 +
              enableLookups="false" disableUploadTimeout="true"
 +
              acceptCount="100" scheme="https" secure="true"
 +
              clientAuth="want" sslProtocol="TLS" emptySessionPath="true" />
 +
</pre>
 +
 +
== D4Science Portal HTTPS x509 Certificate Authentication ==
 +
 
This is a custom Auto login hook that provides customised authentication for X509 certificate users.<br/>
 
This is a custom Auto login hook that provides customised authentication for X509 certificate users.<br/>
 
'''Set the dev/deploy environment'''
 
'''Set the dev/deploy environment'''

Revision as of 16:27, 27 September 2010

How to configure Apache HTTP server and Apache Tomcat to handle X.509 certificates

The following setup shows how to configure Apache HTTP server in HTTPS so that X.509 client credentials can be forwarded to an internal Apache Tomcat instance.

Apache HTTP server

Two VirtualHost should ne configured. The first one to handle HTTP requests on standard port 80, and redirect all of them to port 443 (HTTPS).

<VirtualHost *:80>
	ServerAdmin webmaster@localhost
	ServerName devportal.d4science.research-infrastructures.eu
	
	DocumentRoot /var/www/
	
	ErrorLog /var/log/apache2/error.log
	CustomLog /var/log/apache2/access.log combined


        ProxyPreserveHost on
        RewriteEngine on
	#RewriteRule (.*) https://devportal.d4science.research-infrastructures.eu$1 [R,L]

    	#RewriteRule ^(.*)$ http://localhost:9090$1 [P,L]
        Redirect permanent / https://newportal.d4science.research-infrastructures.eu/
</VirtualHost>

The second virtual host is meant to handle HTTPS requests, asking clients to optionally authenticate with an X.509 certificates.

<VirtualHost *:443>
	ServerAdmin webmaster@localhost
	ServerName devportal.d4science.research-infrastructures.eu
	
	DocumentRoot /var/www/
	<Directory />
		Options FollowSymLinks
		AllowOverride None
	</Directory>
	<Directory /var/www/>
		Options Indexes FollowSymLinks MultiViews
		AllowOverride None
		Order allow,deny
		allow from all
	</Directory>

	ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
	<Directory "/usr/lib/cgi-bin">
		AllowOverride None
		Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
		Order allow,deny
		Allow from all
	</Directory>

	ErrorLog /var/log/apache2/error.log

	# Possible values include: debug, info, notice, warn, error, crit,
	# alert, emerg.
	LogLevel warn

	CustomLog /var/log/apache2/access.log combined
	ServerSignature On

    Alias /doc/ "/usr/share/doc/"
    <Directory "/usr/share/doc/">
        Options Indexes MultiViews FollowSymLinks
        AllowOverride None
        Order deny,allow
        Deny from all
        Allow from 127.0.0.0/255.0.0.0 ::1/128
    </Directory>

    SSLEngine on
    SSLCertificateFile    /etc/apache2/ssl/containercert.pem
    SSLCertificateKeyFile /etc/apache2/ssl/containerkey.pem

    SSLProxyEngine on

    SSLCACertificatePath /etc/grid-security/certificates/
    SSLVerifyClient optional
    SSLVerifyDepth 2

# this option is mandatory to force apache to forward the client cert data to tomcat
    SSLOptions +ExportCertData

    <Proxy *>
       AddDefaultCharset Off
       Order deny,allow
       Allow from all
    </Proxy>
 
    ProxyPass / ajp://localhost:8020/
    ProxyPassReverse / ajp://localhost:8020/

</VirtualHost>

The connection between Apache HTTP Server and Apache Tomcat is done via an AJP connector and Reverse Proxy directive. This means that the following modules need to be installed and loaded into Apache HTTP Server:

* proxy
* proxy_http
* proxy_ajp

to install a new module into apache2 use the following command:

a2enmod <module_name>

Apache Tomcat

An AJP connector needs to be declared in order to enable communication between Apache HTTP Server and Apache Tomcat, with a redirect to port 8443 to handle the HTTPS connection inside Tomcat.

    <!-- Define an AJP 1.3 Connector on port 8020 -->
    <Connector port="8020" 
               enableLookups="false" redirectPort="8443" protocol="AJP/1.3" URIEncoding="UTF-8" />

Eventually, a Connector needs to declared for port 8443 to handle the HTTPS connection in Tomcat.

    <Connector port="8443" maxHttpHeaderSize="8192"
               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
               enableLookups="false" disableUploadTimeout="true"
               acceptCount="100" scheme="https" secure="true"
               clientAuth="want" sslProtocol="TLS" emptySessionPath="true" />

D4Science Portal HTTPS x509 Certificate Authentication

This is a custom Auto login hook that provides customised authentication for X509 certificate users.
Set the dev/deploy environment

  1. Unzip the file [1] onto your "plugin-sdk/hooks" folder.
  2. Copy the AutoLoginCustom.java(please find below) source to the src folder
  3. Add the following line to portal.properties file:
    auto.login.hooks=com.liferay.portal.security.auth.BasicAuthHeaderAutoLogin,com.liferay.portal.security.auth.AutoLoginCustom
  4. Run "ant war" - The war file will be created in the plugins-sdk/dist folder.
  5. Copy the war file to Liferay_home/deploy
  6. Restart liferay instance

Auto Login hook is now ready to be tested and used.

Configuration needed at liferay Web UI:

  1. The X509 User should have "Job Title" field configured to the X509 certificate DN

The field "Job Title" was chosen, because the field length is long enough to hold X509 certificate DN unlike other fields. This feature can be changed to use custom attribute field as per needs and requirements.
The code for AutoLoginCustom.java:

package com.liferay.portal.security.auth;

import java.security.cert.X509Certificate;
import java.util.Iterator;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.liferay.portal.SystemException;
import com.liferay.portal.model.User;
import com.liferay.portal.security.auth.AutoLogin;
import com.liferay.portal.security.auth.AutoLoginException;
import com.liferay.portal.service.UserLocalServiceUtil;
import com.liferay.portal.security.auth.BasicAuthHeaderAutoLogin;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;



public class AutoLoginCustom implements AutoLogin{

	String[] credentials = new String[3];
	private static Log logger = LogFactory.getLog(AutoLoginCustom.class); 
		
	public String[] login(HttpServletRequest req, HttpServletResponse resp)
	throws AutoLoginException {
		// TODO Auto-generated method stub
		List<User> users = null;
		User loginUser = null;
		long userId = 0;
		String requestDN = this.getUserDN(req);
		if(requestDN != null){
			try {
				
				users = UserLocalServiceUtil.getUsers(0, UserLocalServiceUtil.getUsersCount());
			} catch (SystemException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			Iterator<User> userIter = users.iterator();
			
			while(userIter.hasNext()){

				User user = (User)userIter.next();
				if(user.getJobTitle().equals(requestDN)){
					loginUser = user;
					logger.info("X509 certificate user logs in: " + loginUser.getFirstName());
					break;
				}
			}


		}

		if(loginUser!=null){
			userId = loginUser.getUserId();

			credentials[0]=String.valueOf(userId);
			credentials[1] = loginUser.getPassword();
			credentials[2] = Boolean.FALSE.toString();
		}

		return credentials;
	}
	private X509Certificate[] getCerts(HttpServletRequest req) {
		return (X509Certificate[]) req.getAttribute("javax.servlet.request.X509Certificate");
	}

	private String getUserDN(HttpServletRequest req) {
		X509Certificate certs[] = this.getCerts(req);
		if (certs != null && certs.length > 0) {
			String DN = certs[0].getSubjectDN().getName();
			String parsedDN = DN.replace(", ", ",");
			return parsedDN;
		}
		else {
			return null;
		}
	}
}


Reference

  1. http://www.liferay.com/community/wiki/-/wiki/Main/Hook+Plugin+Template