Apache2, PKI / Certificate authentication and LDAP authorisation example

I recently took over a system from a colleague which was built up using Apache, so I did my first steps using PHP. This document describes how to enable the sever with certificate authentication, something I havent found on the web.
How can I extract the user dn from the certificate ? I use the certificate data from apache, modify the presentation and do a ldap query using this one. Then I can enable users in the ldap group in order to authenticate them againts the server. Different groups with different rights are possible using user variables.

I set up a PHP Script for the Apache 2 which required PKI protection and a user management using given LDAP groups.

The following steps lead to a solution :
You have to put the CA in the cafile (PEM encoded, all in one file). Then you can test the https://servername connection. A real DNS name for the certificate is needer here to order a PKI certificate.

Create a private key for the server :

opensslreq -newkey rsa:2048 -keyout private.key -out request.csr -days 1095

– length 2048 bit
– algorithm RSA
– lifetime 1095 days= 3 years

Unprotect the server key from the password (otherwise, daemon would ask every restart for the password):

openssl rsa -in private.key > server-key.pem (B)

Use the request.csr for a certificate request against the ca (if you dont have a trust center available, maybe you have a look at open-ca).

You will receive a certificate for the server, put it in server.crt. (A) Get the keys for the ca until the root of the ca and put it in one file using base64 PEM format (C) server-chain.crt. In my example, this file is the same file like the client CA (D)

Important are the following ssl.conf options for apache :


#   Server Certificate:
# Point SSLCertificateFile at a PEM encoded certificate.  If
# the certificate is encrypted, then you will be prompted for a
# pass phrase.  Note that a kill -HUP will prompt again.  A new
# certificate can be generated using the genkey(1) command.
SSLCertificateFile /etc/pki/tls/certs/server.crt (A)

#   Server Private Key:
#   If the key is not combined with the certificate, use this
#   directive to point at the key file.  Keep in mind that if
#   you’ve both a RSA and a DSA private key you can configure
#   both in parallel (to also allow the use of DSA ciphers, etc.)
SSLCertificateKeyFile /etc/pki/tls/private/server-key.pem (B)

#   Server Certificate Chain:
#   Point SSLCertificateChainFile at a file containing the
#   concatenation of PEM encoded CA certificates which form the
#   certificate chain for the server certificate. Alternatively
#   the referenced file can be the same as SSLCertificateFile
#   when the CA certificates are directly appended to the server
#   certificate for convinience.
SSLCertificateChainFile /etc/pki/tls/certs/server-chain.crt (C)

#   Certificate Authority (CA):
#   Set the CA certificate verification path where to find CA
#   certificates for client authentication or alternatively one
#   huge file containing all of them (file must be PEM encoded)
SSLCACertificateFile /etc/pki/tls/certs/ssl_ca_certfile.crt (D)

#   Client Authentication (Type):
#   Client certificate verification type and depth.  Types are
#   none, optional, require and optional_no_ca.  Depth is a
#   number which specifies how deeply to verify the certificate
#   issuer chain before deciding the certificate is not valid.
SSLVerifyClient require
SSLVerifyDepth 10

/etc/sysconfig/apache2 set
APACHE_SERVER_FLAGS=”SSL”

and finally
SSLOptions +ExportCertData

to export the certificate data. Using this, its possible to get the certifcate of the user.


<?php

if (!isset($_SERVER[‘SSL_CLIENT_S_DN’])) {
echo (“No PKI info, please contact server admins”);
#header(“location:../no_access.php”);
break;
} else {
$client_c_dn = $_SERVER[‘SSL_CLIENT_S_DN’];

}

# This little hack reformats the presentation of the user to an ldap friendly format
$client_c_cn=””;
$parts=explode(“/”,$client_c_dn);

for ($i=sizeof($parts)-1;$i>0;–$i) {

if (strlen($parts[$i])>1) {
#echo $parts[$i];
$client_c_cn=$client_c_cn.$parts[$i];

if ($i!=1){
#echo “,”;
$client_c_cn=$client_c_cn.”,”;
}
}

}

#echo $client_c_cn;

ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7);
$ldapconn = ldap_connect(“ldaps://ldapserver”, 636) or die (“Cant connect to server”);
ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldapconn, LDAP_OPT_REFERRALS, 0);
$ldapuser=”cn=ldapuser,[…]c=de”;
$ldappwd=”password”;

ldap_bind($ldapconn, $ldapuser, $ldappwd);

$basis_dn = “cn=ldapgroup,[…],c=de”;

$sr=ldap_search($ldapconn, $basis_dn, “member=$client_c_cn”);

$info = ldap_get_entries($ldapconn, $sr);

if (ldap_count_entries($ldapconn,$sr) &gt; 0) {
ldap_close($ldapconn);
echo “Ldap group found”;

session_start();
$_SESSION[‘User’] = $client_c_cn;

header (“location:sapplication.php”);
break;

}
ldap_close($ldapconn);
# No LDAP Group found

#header(“location:../no_groupaccess.php”);
echo (“No ldap group found, please contact server admins”);
break;

Now you can check that the session variable has been set using


<?php
session_start();
#echo ("Start, user set:");
#echo $_SESSION['User'];

if(!isset($_SESSION[‘User’])){
header(“location:index.php”);
#echo (“No user variable found”);
break;
}
…program code starts here…

Using similar code, you can use pki 2factor authentication for the apache2 and use ldap to make a authorisation description per PHP page or per PHP function.

Feel free to ask for any more details.

How to create your own self signed ca :
http://oshogsb.blogspot.com/2007/07/how-to-create-custom-ca-and.html

Leave a comment