View source
<?php
define('SIMPLE_LDAP_SSO_COOKIE', 'SLDAPSSO');
define('SIMPLE_LDAP_SSO_FLOOD', 'simple_ldap_sso_failed_login');
function simple_ldap_sso_configured() {
$configured =& drupal_static(__FUNCTION__);
if (!isset($configured)) {
$errors = simple_ldap_configuration_errors();
$configured = empty($errors);
}
return $configured;
}
function simple_ldap_configuration_errors() {
$errors = array();
drupal_load('module', 'simple_ldap');
drupal_load('module', 'simple_ldap_user');
if (!variable_get('simple_ldap_sso_encryption_key')) {
$errors[] = t('You must specify an encryption key.');
}
if (variable_get('simple_ldap_readonly') && (!variable_get('simple_ldap_sso_binddn') || !variable_get('simple_ldap_sso_bindpw'))) {
$errors[] = t('This site is in read only mode, so you must specify separate LDAP credentials with read/write access.');
}
if (!variable_get('simple_ldap_sso_attribute_sid')) {
$errors[] = t('You must specify the LDAP attribute used to store the hashed session id.');
}
$session_inc_path = __DIR__ . '/simple_ldap_sso.session.inc';
if (DRUPAL_ROOT . '/' . variable_get('session_inc') != $session_inc_path) {
$errors[] = t('You must set the session_inc variable to Simple LDAP SSO’s session include file.');
}
if (!extension_loaded('mcrypt')) {
$t_args['@url'] = 'http://php.net/mcrypt';
$errors[] = t('You must have the <a href="@url">PHP mcrypt extension</a> installed.', $t_args);
}
return $errors;
}
function simple_ldap_sso_detect_sid() {
if (simple_ldap_sso_configured() && isset($_COOKIE[session_name()]) && isset($_COOKIE[SIMPLE_LDAP_SSO_COOKIE]) && !simple_ldap_sso_session_exists()) {
if (!simple_ldap_sso_populate_session()) {
simple_ldap_sso_delete_cookie();
$message = 'Possible break-in attempt detected.';
$t_args = array();
watchdog(__FUNCTION__, $message, $t_args, WATCHDOG_ALERT);
}
}
}
function simple_ldap_sso_session_exists() {
global $is_https;
$sid = $_COOKIE[session_name()];
$sql = $is_https ? "SELECT uid FROM {sessions} WHERE ssid = :sid" : "SELECT uid FROM {sessions} WHERE sid = :sid";
return db_query($sql, array(
':sid' => $sid,
))
->fetchField();
}
function simple_ldap_sso_populate_session() {
if (!($data = simple_ldap_sso_get_cookie_data())) {
return FALSE;
}
$key = array(
'sid' => $data['sid'],
'ssid' => $data['ssid'],
);
if ($data['uid'] == 1) {
return FALSE;
}
unset($data['name']);
$data['session'] = '';
if (simple_ldap_user_variable_get('simple_ldap_user_sync') == 'hook_user_login') {
simple_ldap_sso_queue_user_sync();
}
$query = db_merge('sessions')
->key($key)
->fields($data);
return $query
->execute();
}
function simple_ldap_sso_get_cookie_data($cookie_value = NULL) {
$result =& drupal_static(__FUNCTION__);
if (isset($result)) {
return $result;
}
if (!isset($cookie_value)) {
if (!isset($_COOKIE[SIMPLE_LDAP_SSO_COOKIE])) {
$result = FALSE;
return $result;
}
$cookie_value = $_COOKIE[SIMPLE_LDAP_SSO_COOKIE];
}
$result = simple_ldap_sso_decrypt($cookie_value);
if ($result && ($uid = simple_ldap_sso_validate_user($result))) {
$result['uid'] = $uid;
}
else {
$result = FALSE;
}
return $result;
}
function simple_ldap_sso_validate_user(array $data) {
$result = db_query("SELECT uid FROM {users} WHERE name = :name", array(
':name' => $data['name'],
));
$uid = $result
->fetchField();
if (!$uid) {
require_once DRUPAL_ROOT . '/includes/common.inc';
$account = new stdClass();
$account->uid = db_next_id(db_query('SELECT MAX(uid) FROM {users}')
->fetchField());
$account->created = REQUEST_TIME;
$account->name = $data['name'];
$account->status = 1;
drupal_write_record('users', $account);
$uid = isset($account->uid) ? $account->uid : FALSE;
simple_ldap_sso_queue_user_sync();
}
return $uid ? $uid : FALSE;
}
function simple_ldap_sso_validate_ldap() {
global $is_https;
$sid_key = $is_https ? 'ssid' : 'sid';
$cookie_data = simple_ldap_sso_get_cookie_data();
if (!$cookie_data || !isset($cookie_data[$sid_key])) {
return FALSE;
}
$sso = SimpleLdapSSO::singleton($cookie_data['name']);
return $sso
->validateSid($cookie_data[$sid_key]);
}
function simple_ldap_sso_encrypt(array $data) {
$text = serialize($data);
return _simple_ldap_encrypt_decrypt($text, TRUE);
}
function simple_ldap_sso_decrypt($string) {
$serialized = _simple_ldap_encrypt_decrypt($string, FALSE);
if ($serialized && ($data = @unserialize($serialized))) {
return $data;
}
return FALSE;
}
function _simple_ldap_encrypt_decrypt($text, $encrypt = TRUE) {
$key = hash('sha256', variable_get('simple_ldap_sso_encryption_key'), TRUE);
$cipher = 'rijndael-256';
$mode = MCRYPT_MODE_CBC;
$iv_size = mcrypt_get_iv_size($cipher, $mode);
if ($encrypt) {
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$hmac = hash('sha256', trim($text));
$text = $hmac . $text;
$encrypted_text = mcrypt_encrypt($cipher, $key, $text, $mode, $iv);
$output = base64_encode($iv . $encrypted_text);
}
else {
$decoded = base64_decode($text);
$iv = substr($decoded, 0, $iv_size);
$data = substr($decoded, $iv_size);
$output = mcrypt_decrypt($cipher, $key, $data, $mode, $iv);
$hmac = substr($output, 0, 64);
$output = substr($output, 64);
if ($hmac != hash('sha256', trim($output))) {
$message = 'Possible break-in attempted. The HMAC does not match on the encrypted text.';
watchdog(__FUNCTION__, $message, array(), WATCHDOG_ALERT);
$output = '';
}
}
return $output;
}
function simple_ldap_sso_set_cookie(array $data) {
$value = simple_ldap_sso_encrypt($data);
$params = session_get_cookie_params();
$expire = $params['lifetime'] ? REQUEST_TIME + $params['lifetime'] : 0;
setcookie(SIMPLE_LDAP_SSO_COOKIE, $value, $expire, $params['path'], $params['domain'], (bool) variable_get('https'), $params['httponly']);
}
function simple_ldap_sso_delete_cookie() {
$params = session_get_cookie_params();
setcookie(SIMPLE_LDAP_SSO_COOKIE, '', REQUEST_TIME - 3600, $params['path'], $params['domain'], (bool) variable_get('https'), $params['httponly']);
}
function simple_ldap_sso_ldap_save_sid($name, $sid) {
$sso = SimpleLdapSSO::singleton($name);
$sso
->saveSid($sid);
}
function simple_ldap_sso_ldap_delete_sid($name) {
$sso = SimpleLdapSSO::singleton($name);
try {
$sso
->deleteSid();
} catch (Exception $e) {
$message = 'Unable to delete sid from LDAP for user %name. Error: @e';
$t_args = array(
'%name' => $name,
'@e' => (string) $e,
);
watchdog(__FUNCTION__, $message, $t_args, WATCHDOG_WARNING);
}
}
function simple_ldap_sso_abort() {
global $user;
$message = 'Possible break-in attempt detected for uid @uid and session id @id.';
$t_args = array(
'@uid' => $user->uid,
'@id' => session_id(),
);
watchdog(__FUNCTION__, $message, $t_args, WATCHDOG_ALERT);
simple_ldap_sso_user_logout($user);
session_destroy();
drupal_set_message(t('A problem was encountered when attempting to sign you in on this site.'), 'error');
}
function simple_ldap_sso_does_session_need_validation() {
return !isset($_SESSION['simple_ldap_sso_needs_validation']) || $_SESSION['simple_ldap_sso_needs_validation'];
}
function simple_ldap_sso_session_is_valid() {
$_SESSION['simple_ldap_sso_needs_validation'] = FALSE;
}
function simple_ldap_sso_session_needs_validation() {
$_SESSION['simple_ldap_sso_needs_validation'] = TRUE;
}
function simple_ldap_sso_queue_user_sync() {
drupal_static('simple_ldap_sso_user_needs_sync', TRUE);
}
function simple_ldap_sso_user_needs_sync() {
return drupal_static(__FUNCTION__, FALSE);
}