Files
server/usr/share/psa-pear/pear/php/Horde/Auth/X509.php
2026-01-07 20:52:11 +01:00

155 lines
4.9 KiB
PHP

<?php
/**
* Copyright 2013-2017 Horde LLC (http://www.horde.org)
*
* See the enclosed file COPYING for license information (LGPL). If you did
* not receive this file, see http://www.horde.org/licenses/lgpl21.
*
* @author Michael J Rubinsky <mrubinsk@horde.org>
* @category Horde
* @license http://www.horde.org/licenses/lgpl21 LGPL-2.1
* @package Auth
* @since 2.1.0
*/
/**
* The Horde_Auth_X509 class provides an authentication driver for using X509
* client certificates. Since X509 certificates do not provide the password,
* if the server setup requires the use of per-user passwords, a callback
* function may be passed to obtain it from.
*
* @author Michael J Rubinsky <mrubinsk@horde.org>
* @category Horde
* @copyright 2013-2017 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL-2.1
* @package Auth
* @since 2.1.0
*/
class Horde_Auth_X509 extends Horde_Auth_Base
{
/**
* An array of capabilities, so that the driver can report which
* operations it supports and which it doesn't.
*
* @var array
*/
protected $_capabilities = array(
'transparent' => true
);
/**
* Constructor.
*
* @param array $params Parameters:
* - password: (string) If available, the password to use for the session.
* DEFAULT: no password used.
* - username_field: (string) Name of the $_SERVER field that
* the username can be found in. DEFAULT: 'SSL_CLIENT_S_DN_EMAILADDRESS'.
* - certificate_field: (string) Name of the $_SERVER field that contains
* the full certificate. DEFAULT: 'SSL_CLIENT_CERT'
* - ignore_purpose: (boolean) If true, will ignore any usage restrictions
* on the presented client certificate. I.e., if openssl_x509_checkpurpose
* returns false, authentication may still proceed. DEFAULT: false - ONLY
* ENABLE THIS IF YOU KNOW WHY YOU ARE DOING SO.
* - filter: (array) An array where the keys are field names and the
* values are the values those certificate fields MUST
* match to be considered valid. Keys in the format of
* fieldone:fieldtwo will be taken as parent:child.
* DEFAULT: no additionachecks applied.
*
* @throws InvalidArgumentException
*/
public function __construct(array $params = array())
{
$params = array_merge(array(
'password' => false,
'username_field' => 'SSL_CLIENT_S_DN_CN',
'certificate_field' => 'SSL_CLIENT_CERT',
'ignore_purpose' => true,
'filter' => array()
), $params);
parent::__construct($params);
}
/**
* Not implemented.
*
* @param string $userId The userID to check.
* @param array $credentials An array of login credentials.
*
* @throws Horde_Auth_Exception
*/
protected function _authenticate($userId, $credentials)
{
throw new Horde_Auth_Exception('Unsupported.');
}
/**
* Automatic authentication: checks if the username is set in the
* configured header.
*
* @return boolean Whether or not the client is allowed.
*/
public function transparent()
{
if (!is_callable('openssl_x509_parse')) {
throw new Horde_Auth_Exception('SSL not enabled on server.');
}
if (empty($_SERVER[$this->_params['username_field']]) ||
empty($_SERVER[$this->_params['certificate_field']])) {
return false;
}
// Valid for client auth?
$cert = openssl_x509_read($_SERVER[$this->_params['certificate_field']]);
if (!$this->_params['ignore_purpose'] &&
!openssl_x509_checkpurpose($cert, X509_PURPOSE_SSL_CLIENT) &&
!openssl_x509_checkpurpose($cert, X509_PURPOSE_ANY)) {
return false;
}
$c_parsed = openssl_x509_parse($cert);
foreach ($this->_params['filter'] as $key => $value) {
$keys = explode(':', $key);
$c = $c_parsed;
foreach ($keys as $k) {
$c = $c[$k];
}
if ($c != $value) {
return false;
}
}
// Handle any custom validation added by sub classes.
if (!$this->_validate($cert)) {
return false;
}
// Free resources.
openssl_x509_free($cert);
// Set credentials
$this->setCredential('userId', $_SERVER[$this->_params['username_field']]);
$cred = array('certificate_id' => $c_parsed['hash']);
if (!empty($this->_params['password'])) {
$cred['password'] = $this->_params['password'];
}
$this->setCredential('credentials', $cred);
return true;
}
/**
* Perform additional validation of certificate fields.
*
* @return boolean
*/
protected function _validate($certificate)
{
return true;
}
}