У меня есть форма входа в Symfony, аутентифицирующая сервер Ldap. Я могу успешно запросить и аутентифицировать пользователя, используя имя samaccountname или userprincipalname и ключ uid в настройках моей конфигурации. Я хочу, чтобы пользователь мог вводить либо свое имя пользователя, либо имя пользователя@domain.com.
Я пробовал preg_replace для имени пользователя в методе loadUserbyUsername() в LdapUserProviderClass (я знаю, что это не идеально). Это берет имя пользователя, такое как [email protected], и передает имя пользователя. Мне удалось убедиться, что с сервера Ldap был возвращен правильный пользователь, но я все еще возвращаюсь к форме входа с «Недействительными учетными данными». Я считаю, что причина, по которой это происходит в запросе класса AuthenticationUtils, обрабатывается, а имя пользователя в запросе по-прежнему [email protected], и это не соответствует имени пользователя в пользовательском объекте, полученном из аутентификации Ldap, которая является именем пользователя. Если у кого-нибудь есть совет о том, как разрешить аутентификацию как [email protected], так и имени пользователя в Ldap, я был бы очень признателен.
SecurityController.php
public function login(Request $request, AuthenticationUtils $authenticationUtils): Response
{
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
$newLastUsername = trim(preg_replace('/@.*/', '',$lastUsername));
return $this->render('security/login.html.twig', ['last_username' => $newLastUsername, 'error' => $error]);
}
безопасность.yml
providers:
dsg_ldap:
ldap:
service: Symfony\Component\Ldap\Ldap
base_dn: '%env(BASE_DSN)%'
search_dn: '%env(SEARCH_DN)%'
search_password: '%env(SEARCH_PWD)%'
uid_key: '%env(UID_KEY)%'
#filter: '({uid_key} = {_username})'
default_roles: ROLE_USER
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
form_login_ldap:
login_path: login
check_path: login
service: Symfony\Component\Ldap\Ldap
provider: dsg_ldap
dn_string: '%env(DN_STRING)%\{username}'
Мой LdapUserProvider.php
class LdapUserProvider extends SymfonyLdapUserProvider
{
/** @var array maps ldap groups to roles */
private $groupMapping = [
'**' => '**',
'**' => '**',
'**' => '**',
'**' => '**'
];
/** @var string extracts group name from dn string */
private $groupNameRegExp = '/CN=(.+?),/';
protected function loadUser($username, Entry $entry)
{
$roles = ['ROLE_USER'];
// Check if the entry has attribute with the group
if (!$entry->hasAttribute('memberOf')) {
return new User($username, '', $roles);
}
// Iterate through each group entry line
foreach ($entry->getAttribute('memberOf') as $groupLine) {
// Extract the group name from the line
$groupName = $this->getGroupName($groupLine);
// Check if the group is in the mapping
if (array_key_exists($groupName, $this->groupMapping)) {
// Map the group to the role(s) the user will have
$roles[] = $this->groupMapping[$groupName];
}
}
// Create and return the user object
return new User($username, null, $roles);
}
/**
* Get the group name from the DN
* @param string $dn
* @return string
*/
private function getGroupName($dn)
{
$matches = [];
return preg_match($this->groupNameRegExp, $dn, $matches) ? $matches[1] : '';
}
}
Symfony\Component\Security\Core\User\LdapUserProvider.php
public function loadUserByUsername($username)
{
try {
$this->ldap->bind($this->searchDn, $this->searchPassword);
// what i added
$username = trim(preg_replace('/@.*/', '',$username));
$username = $this->ldap->escape($username, '', LdapInterface::ESCAPE_FILTER);
$query = str_replace('{username}', $username, $this->defaultSearch);
$search = $this->ldap->query($this->baseDn, $query);
} catch (ConnectionException $e) {
throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username), 0, $e);
}
$entries = $search->execute();
$count = \count($entries);
if (!$count) {
throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username));
}
if ($count > 1) {
throw new UsernameNotFoundException('More than one user found');
}
$entry = $entries[0];
try {
if (null !== $this->uidKey) {
$username = $this->getAttributeValue($entry, $this->uidKey);
}
} catch (InvalidArgumentException $e) {
}
return $this->loadUser($username, $entry);
}




В функции loadUserByUsername добавьте еще один запрос, если первый не удался. Ваш $this->defaultSearch, вероятно, является константой, представляющей фильтр LDAP.
Если вы создадите ту же строку в первом if (!$count) {...} вот так:
$query = str_replace('{username}', $username, "(userPrincipalName = {username})");
а затем выполните этот запрос, вы выполняете второй поиск userPrincipalName, который имеет форму пользователь@домен
Спасибо, что дал мне знать. Если ответ правильный, вы можете отметить его как таковой ;-)
Спасибо! Я смог заставить его работать, добавив ваши предложения. Кроме того, мне пришлось изменить dn_string: '%env(DN_STRING)%\{username}' на dn_string: ' '.