Authentication protocol with certificates on HTTP servers.

April 2006

  1. Objective
  2. Introduction.
  3. Steps.
  4. Implementation
  5. Example.
  6. Nisu topics.

Objective

This document describes a simple way to perform authentication with X509 on a HTTP server (no TLS) using an auxiliar HTTPS server in a different domain, without propagate cookies.

Introduction.

To use X509 authentication in a web page you need HTTPS. To have a HTTPS server working for a domain, you need a different IP for every server (or group of servers, if you use expensive wildcard certificates). If you do not have money to get a SSL certificate for every server, or you have not enough IPs, you can use this simple protocol.
The implementation is done with PHP.

Steps.

  1. Client connects whit HTTP server.
  2. If not authenticated, server redirects (using Location header), perhaps at user request, to the HTTPS authentication URL, indicating the return URL.
  3. The HTTPS URL performs X509 client authentication, opening a (new) session for the client, and if authentication is successfull, stores data from certificate in session variables.
  4. Then, it redirects client to original HTTP server with an additional parameter indicating how client data can be obtained.
  5. Client goes to the redirected URL on HTTP server.
  6. HTTP server connect by itself to HTTPS server, obtaining authentication data.

Implementation

HTTP script that wants client authentication:
	// step 1
	if (! $_SESSION['authenticated']) {
	  $sslServer='https://serverwithTLS/authScript.php';
	  $myscr='http://'.$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'];
	  $reto_auth=$_GET['reto_auth'];
	  // step 5: 'reto_auth' is given by step 4
	  if ($reto_auth) {
	    // step 6: connects to obtain auth data
	    $data=unserialize(file_get_contents("$reto_auth"));
	    "test $data against valid users"
	    if ($ok)
	      $_SESSION['authenticated']=$data;
	    else
	      die("Unknown user");
	    // hide authetication details and recover URL
	    header("Location: $myscr?".$_SESSION['QS']);
	    die();
	  }
	  else {
	    if ($_GET['wantauth'])
	      // step 2
	      header("Location: $sslServer?reto=yes&url=".urlencode("$myscr?extraparams&"));
	    else {
	      $_SESSION['QS']=$_SERVER['QUERY_STRING'];
	      die("Please, click <a href=\"$myscr?wantauth=yes\">here</a> to authenticate");
	    }
	    die();
	  }
	}
	
HTTPS authentication script must be configured with TLS authentication optional, or it should be really two scripts, one with TLS authentication required, the other without authentication.
	// step 6
	// no authentication required, based on session
	if ($_REQUEST['rauth']) {
	  // returns serialized session from step 3
	  echo serialize($_SESSION);
	  session_destroy();
	  session_unset();
	}
	else {
	  // step 3
	  // no database required, using $_SESSION
	  "take certificate data"
	  // authetication with valid certificated has been suggested by server
	  if ($correct) { // certificate present, some certificate field required, etc.
	    $_SESSION[.......]="certificate data"
	    if ($_GET['reto']) {
	      // builds step 4
	      $rah='reto_auth='.urlencode('
	          https://'.$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'].
		  '?rauth=yes&PHPSESSID='.session_id());
	      // step 4
	      // url should end whit & or ?
	      header("Location: ".$_GET['url'].$rah);
	    }
	    else
	      die("Bad invocation");
	  }
	  else
	    // message will be shown only if authentication is optional
	    die("No certificate or not valid for this purpouse");
	}
	
Security is based in the random nature of PHPSESSID.

Example.

  1. The client accesses URL = http://poorserver.com/hello.php?data=22
  2. The client is not authenticated, is prompted.
  3. At request, the script hello.php sends to client:
    Location https://richserver.com/authscript.php?reto=yes&url=http%3A%2F%2Fpoorserver.com%2Fhello.php%3F
  4. Client connects to this URL, that, after successfull X509 authentication, returns:
    Location: http://poorserver.com/hello.php?reto_auth=https%3A%2F%2Frichserver.com%2Fauthscript.php%3Freto_auth%3Dyes%26PHPSESSID%3Dffdd4789b077820f4ae5ffeff4f5cc03
  5. Client conects this URL and hello.php, internally, goes to
    https://richserver.com/authscript.php?reto_auth=yes&PHPSESSID=ffdd4789b077820f4ae5ffeff4f5cc03
    and obtains the certificate data, and can perform user validation.
  6. The script hello.php stats session as autheticated and returns
    Location: http://poorserver.com/hello.php?data=22
  7. Client goes to original URL, but authenticated.
Select Style - Legal