Skip to content
Snippets Groups Projects
Commit 74381ddf authored by Liam Morland's avatar Liam Morland
Browse files

ISTWCMS-4591: Create service uw_ldap with class UWLdap

parent 68279c4b
No related branches found
No related tags found
1 merge request!45ISTWCMS-4591: Create service uw_ldap with class UWLdap
uw_cfg_common.ldap:
type: config_object
label: 'LDAP settings'
mapping:
user:
type: string
label: 'LDAP user name'
pwd:
type: string
label: 'LDAP password'
<?php
namespace Drupal\uw_cfg_common\Service;
use Drupal\Component\Utility\Html;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Logger\LoggerChannelTrait;
use Drupal\Core\Session\AccountProxy;
/**
* Class for interfacing with UW's LDAP infrastructure.
*/
class UWLdap {
use LoggerChannelTrait;
/**
* Information about the LDAP server.
*
* @var array
*/
protected $ldapServer = [
'server' => 'ldaps://ldap-nexus.uwaterloo.ca',
'base_dn' => 'dc=nexus, dc=uwaterloo, dc=ca',
// The name of the UID field.
'uid' => 'sAMAccountName',
// Config keys in uw_cfg_common.ldap from which to load the user and
// password.
'user' => 'user',
'pwd' => 'pwd',
];
/**
* The config factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* The current user object.
*
* @var \Drupal\Core\Session\AccountProxy
*/
protected $currentUser;
/**
* Constructor with dependency injection.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
* @param \Drupal\Core\Session\AccountProxy $current_user
* The current user object.
*/
public function __construct(ConfigFactoryInterface $config_factory, AccountProxy $current_user) {
$this->configFactory = $config_factory;
$this->currentUser = $current_user;
}
/**
* Open a connection to the LDAP server.
*
* @return bool
* TRUE if the connection succeeded, FALSE otherwise.
*/
protected function openConnection(): bool {
// Return early if opening a connection has already been attempted. It will
// not retry after a failed connection attempt.
if (isset($this->ldapServer['connection'])) {
return (bool) $this->ldapServer['connection'];
}
// Load LDAP user and password from config.
foreach (['user', 'pwd'] as $field) {
if (isset($this->ldapServer[$field])) {
$this->ldapServer[$field] = $this->configFactory->get('uw_cfg_common.ldap')->get($this->ldapServer[$field]);
}
else {
$this->ldapServer[$field] = NULL;
}
}
// Do not attempt connection if no username or password.
if (!isset($this->ldapServer['user']) || !isset($this->ldapServer['pwd'])) {
$this->getLogger('uw_cfg_common')->error('Unable to connect to LDAP server. Missing username or password.');
$this->ldapServer['connection'] = FALSE;
return FALSE;
}
// Connect and bind to the server. Log errors if any.
$ldap_connect = ldap_connect($this->ldapServer['server']);
if (!$ldap_connect || !ldap_bind($ldap_connect, $this->ldapServer['user'], $this->ldapServer['pwd'])) {
// Log errors on failure.
ldap_get_option($ldap_connect, LDAP_OPT_ERROR_NUMBER, $error_number);
ldap_get_option($ldap_connect, LDAP_OPT_DIAGNOSTIC_MESSAGE, $error_message);
ldap_get_option($ldap_connect, LDAP_OPT_ERROR_STRING, $error_string);
$variables = [
'@error_number' => $error_number,
'@error_message' => $error_message,
'@error_string' => $error_string,
];
$this->getLogger('uw_cfg_common')->error('Unable to connect to LDAP server. Error number: @error_number; Error message: @error_message; Error string: @error_string', $variables);
$ldap_connect = FALSE;
}
// Store connection object.
$this->ldapServer['connection'] = $ldap_connect;
return (bool) $ldap_connect;
}
/**
* Wrapper for ldap_search() and ldap_get_entries().
*
* @param string $filter
* Filter for the LDAP search.
* @param array $attributes
* Attributes to the LDAP search.
*
* @return array|null
* Array of results from LDAP search or NULL on error.
*/
public function search(string $filter, array $attributes = []): ?array {
if (!$this->openConnection()) {
return NULL;
}
// Attempt search and get the entries if successful. Otherwise, return NULL.
$results = ldap_search($this->ldapServer['connection'], $this->ldapServer['base_dn'], $filter, $attributes);
if ($results) {
$results = ldap_get_entries($this->ldapServer['connection'], $results);
if ($results) {
return $results;
}
}
return NULL;
}
/**
* Do an LDAP lookup for a person.
*
* @param string $username
* The user to lookup.
*
* @return array|null
* An array of LDAP results or NULL on failure.
*/
public function lookupPerson(string $username): ?array {
// Configure the userid filter.
$filter = '(' . $this->ldapServer['uid'] . '=' . $username . ')';
$result = $this->search($filter);
// Return formatted results if the search is successful.
if (isset($result[0])) {
return $this->formatResults($result[0]);
}
return NULL;
}
/**
* Make formatting changes to LDAP query results.
*
* @param array $results
* The LDAP query results.
*
* @return array
* The input array with formatting changes.
*/
public static function formatResults(array $results): array {
foreach ($results as $key => $value) {
if (is_array($value)) {
foreach ($value as $sub_key => $sub_value) {
if (is_string($sub_value)) {
if (in_array($key, ['objectguid', 'objectsid', 'sidhistory'], TRUE)) {
$results[$key][$sub_key] = self::formatGuid($sub_value);
}
else {
$results[$key][$sub_key] = utf8_encode($sub_value);
}
}
}
}
}
return $results;
}
/**
* Converts a binary guid into a string representation.
*
* @param string $guid
* The guid as a binary string.
*
* @return string
* The guid as a displayable string.
*/
protected static function formatGuid(string $guid): string {
$guid = bin2hex($guid);
// Format $guid so it matches what other LDAP tool displays for AD GUIDs.
if (strlen($guid) === 32) {
$guid = strtoupper(substr($guid, 6, 2) . substr($guid, 4, 2) . substr($guid, 2, 2) . substr($guid, 0, 2) . '-' . substr($guid, 10, 2) . substr($guid, 8, 2) . '-' . substr($guid, 14, 2) . substr($guid, 12, 2) . '-' . substr($guid, 16, 4) . '-' . substr($guid, 20));
}
return $guid;
}
}
services:
uw_cfg_common.uw_ldap:
class: Drupal\uw_cfg_common\Service\UWLdap
arguments: ['@config.factory', '@current_user']
uw_cfg_common.uw_service:
class: Drupal\uw_cfg_common\Service\UWService
arguments: ['@entity_type.manager', '@database', '@simplify_menu.menu_items', '@path_alias.manager']
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment