You are here

public function LdapUserProcessor::provisionLdapEntry in Lightweight Directory Access Protocol (LDAP) 8.3

Provision an LDAP entry if none exists.

If one exists do nothing, takes Drupal user as argument.

Parameters

\Drupal\user\Entity\User|string $account: Drupal account object with minimum of name property.

array $ldap_user: LDAP user as pre-populated LDAP entry. Usually not provided.

Return value

array Format: array('status' => 'success', 'fail', or 'conflict'), array('ldap_server' => LDAP server object), array('proposed' => proposed LDAP entry), array('existing' => existing LDAP entry), array('description' = > blah blah)

File

ldap_user/src/Processor/LdapUserProcessor.php, line 296

Class

LdapUserProcessor
Processor for LDAP provisioning.

Namespace

Drupal\ldap_user\Processor

Code

public function provisionLdapEntry($account, array $ldap_user = NULL) {
  $result = [
    'status' => NULL,
    'ldap_server' => NULL,
    'proposed' => NULL,
    'existing' => NULL,
    'description' => NULL,
  ];
  if (is_scalar($account)) {
    $account = user_load_by_name($account);
  }

  // @TODO 2914053.
  if (is_object($account) && $account
    ->id() == 1) {
    $result['status'] = 'fail';
    $result['error_description'] = 'can not provision Drupal user 1';

    // Do not provision or sync user 1.
    return $result;
  }
  if ($account == FALSE || $account
    ->isAnonymous()) {
    $result['status'] = 'fail';
    $result['error_description'] = 'can not provision LDAP user unless corresponding Drupal account exists first.';
    return $result;
  }
  if (!$this->config['ldapEntryProvisionServer']) {
    $result['status'] = 'fail';
    $result['error_description'] = 'no provisioning server enabled';
    return $result;
  }
  $factory = \Drupal::service('ldap.servers');

  /** @var \Drupal\ldap_servers\Entity\Server $ldapServer */
  $ldapServer = $factory
    ->getServerById($this->config['ldapEntryProvisionServer']);
  $params = [
    'direction' => self::PROVISION_TO_LDAP,
    'prov_events' => [
      self::EVENT_CREATE_LDAP_ENTRY,
    ],
    'module' => 'ldap_user',
    'function' => 'provisionLdapEntry',
    'include_count' => FALSE,
  ];
  try {
    $proposedLdapEntry = $this
      ->drupalUserToLdapEntry($account, $ldapServer, $params, $ldap_user);
  } catch (\Exception $e) {
    \Drupal::logger('ldap_user')
      ->error('User or server is missing during LDAP provisioning: %message', [
      '%message',
      $e
        ->getMessage(),
    ]);
    return [
      'status' => 'fail',
      'ldap_server' => $ldapServer,
      'created' => NULL,
      'existing' => NULL,
    ];
  }
  if (is_array($proposedLdapEntry) && isset($proposedLdapEntry['dn']) && $proposedLdapEntry['dn']) {
    $proposedDn = $proposedLdapEntry['dn'];
  }
  else {
    $proposedDn = NULL;
  }
  $proposedDnLowercase = mb_strtolower($proposedDn);
  $existingLdapEntry = $proposedDn ? $ldapServer
    ->checkDnExistsIncludeData($proposedDn, [
    'objectclass',
  ]) : NULL;
  if (!$proposedDn) {
    return [
      'status' => 'fail',
      'description' => t('failed to derive dn and or mappings'),
    ];
  }
  elseif ($existingLdapEntry) {
    $result['status'] = 'conflict';
    $result['description'] = 'can not provision LDAP entry because exists already';
    $result['existing'] = $existingLdapEntry;
    $result['proposed'] = $proposedLdapEntry;
    $result['ldap_server'] = $ldapServer;
  }
  else {

    // Stick $proposedLdapEntry in $ldapEntries array for drupal_alter.
    $ldapEntries = [
      $proposedDnLowercase => $proposedLdapEntry,
    ];
    $context = [
      'action' => 'add',
      'corresponding_drupal_data' => [
        $proposedDnLowercase => $account,
      ],
      'corresponding_drupal_data_type' => 'user',
      'account' => $account,
    ];
    \Drupal::moduleHandler()
      ->alter('ldap_entry_pre_provision', $ldapEntries, $ldapServer, $context);

    // Remove altered $proposedLdapEntry from $ldapEntries array.
    $proposedLdapEntry = $ldapEntries[$proposedDnLowercase];
    $ldapEntryCreated = $ldapServer
      ->createLdapEntry($proposedLdapEntry, $proposedDn);
    $callbackParams = [
      $ldapEntries,
      $ldapServer,
      $context,
    ];
    if ($ldapEntryCreated) {
      \Drupal::moduleHandler()
        ->invokeAll('ldap_entry_post_provision', $callbackParams);
      $result = [
        'status' => 'success',
        'description' => 'ldap account created',
        'proposed' => $proposedLdapEntry,
        'created' => $ldapEntryCreated,
        'ldap_server' => $ldapServer,
      ];

      // Need to store <sid>|<dn> in ldap_user_prov_entries field, which may
      // contain more than one.
      $ldap_user_prov_entry = $ldapServer
        ->id() . '|' . $proposedLdapEntry['dn'];
      if (NULL !== $account
        ->get('ldap_user_prov_entries')) {
        $account
          ->set('ldap_user_prov_entries', []);
      }
      $ldapUserProvisioningEntryExists = FALSE;
      if ($account
        ->get('ldap_user_prov_entries')->value) {
        foreach ($account
          ->get('ldap_user_prov_entries')->value as $fieldValueInstance) {
          if ($fieldValueInstance == $ldap_user_prov_entry) {
            $ldapUserProvisioningEntryExists = TRUE;
          }
        }
      }
      if (!$ldapUserProvisioningEntryExists) {

        // @TODO Serialise?
        $prov_entries = $account
          ->get('ldap_user_prov_entries')->value;
        $prov_entries[] = [
          'value' => $ldap_user_prov_entry,
          'format' => NULL,
          'save_value' => $ldap_user_prov_entry,
        ];
        $account
          ->set('ldap_user_prov_entries', $prov_entries);
        $account
          ->save();
      }
    }
    else {
      $result = [
        'status' => 'fail',
        'proposed' => $proposedLdapEntry,
        'created' => $ldapEntryCreated,
        'ldap_server' => $ldapServer,
        'existing' => NULL,
      ];
    }
  }
  $tokens = [
    '%dn' => isset($result['proposed']['dn']) ? $result['proposed']['dn'] : NULL,
    '%sid' => isset($result['ldap_server']) && $result['ldap_server'] ? $result['ldap_server']
      ->id() : 0,
    '%username' => @$account
      ->getAccountName(),
    '%uid' => @$account
      ->id(),
    '%description' => @$result['description'],
  ];
  if (isset($result['status'])) {
    if ($result['status'] == 'success') {
      $this->detailLog
        ->log('LDAP entry on server %sid created dn=%dn.  %description. username=%username, uid=%uid', $tokens, 'ldap_user');
    }
    elseif ($result['status'] == 'conflict') {
      $this->detailLog
        ->log('LDAP entry on server %sid not created because of existing LDAP entry. %description. username=%username, uid=%uid', $tokens, 'ldap_user');
    }
    elseif ($result['status'] == 'fail') {
      \Drupal::logger('ldap_user')
        ->error('LDAP entry on server %sid not created because of error. %description. username=%username, uid=%uid, proposed dn=%dn', $tokens);
    }
  }
  return $result;
}