Ldap用户有动态dn必须按照用户名搜索用户以获取他的dn并与其绑定
我只有一个用户来源(sql),但我希望在ldap或数据库中进行密码检查
使用此配置,用户已通过身份验证,但未在数据库中加载且没有正确的角色
如果我在form_login_ldap中移除提供程序:my_chain_provider
我有这样的错误:“如果不首先绑定连接,则无法执行查询。”
我找不到合适的配置
security.yaml
postgresql-9.6
Python 2.7.12
SQLAlchemy 1.1.12
service.yaml
security:
providers:
my_chain_provider:
chain:
providers: [fos_userbundle, my_ldap]
my_ldap:
ldap:
service: Symfony\Component\Ldap\Ldap
base_dn: DC=domain,DC=be
search_dn: "CN=admin,OU=apps,DC=domain,DC=be"
search_password: mdp
default_roles: ROLE_USER
fos_userbundle:
id: fos_user.user_provider.username_email
encoders:
Symfony\Component\Security\Core\User\User: bcrypt
AcDomain\Travaux\Entity\Security\User: bcrypt # ou sha512
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
secured_area:
pattern: ^/
provider: fos_userbundle
form_login:
provider: my_chain_provider
use_referer: true
form_login_ldap:
provider: my_chain_provider
service: Symfony\Component\Ldap\Ldap
dn_string: 'DC=domain,DC=be'
query_string: 'sAMAccountName=*{username}*'
logout: true
anonymous: true
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
由于
答案 0 :(得分:0)
我找到了正确的配置
service.yaml
security:
providers:
sql_provider:
id: AcMarche\Travaux\Security\UserProvider
ldap_provider:
ldap:
service: Symfony\Component\Ldap\Ldap
base_dn: '%env(ACLDAP_DN)%'
search_dn: '%env(ACLDAP_USER)%'
search_password: '%env(ACLDAP_PASSWORD)%'
default_roles: ROLE_USER
uid_key: sAMAccountName
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
secured_area:
pattern: ^/
provider: sql_provider
form_login:
use_referer: true
remember_me: true
form_login_ldap:
provider: ldap_provider
use_referer: true
remember_me: true
service: Symfony\Component\Ldap\Ldap
dn_string: '%env(ACLDAP_DN)%'
query_string: '(&(|(sAMAccountName=*{username}*))(objectClass=person))'
security.yaml
form_login:
use_referer: true
remember_me: true
guard:
authenticators:
- AcDomain\Travaux\Security\FormLoginAuthenticator
但是使用此配置我还有另一个问题:
我的用户使用datable中的密码进行身份验证,用户加载了我的实体:AcDomain \ Travaux \ Entity \ Security \ User
但是,如果他使用ldap用户的日志加载了实体symfony核心: 的Symfony \组件\安全\核心\用户\用户
所以我用守护FormLoginAuthenticator
创建了自己的身份验证 class FormLoginAuthenticator extends AbstractFormLoginAuthenticator
{
use TargetPathTrait;
private $userRepository;
private $router;
private $encoder;
private $ldap;
/**
* @var CsrfTokenManagerInterface
*/
private $csrfTokenManager;
public function __construct(
UserRepository $userRepository,
UserPasswordEncoderInterface $encoder,
RouterInterface $router,
StaffLdap $ldap,
CsrfTokenManagerInterface $csrfTokenManager
) {
$this->router = $router;
$this->userRepository = $userRepository;
$this->encoder = $encoder;
$this->ldap = $ldap;
$this->csrfTokenManager = $csrfTokenManager;
}
/**
* Return the URL to the login page.
*
* @return string
*/
protected function getLoginUrl()
{
return $this->router->generate('travaux_login');
}
/**
* Does the authenticator support the given Request?
*
* If this returns false, the authenticator will be skipped.
*
* @param Request $request
*
* @return bool
*/
public function supports(Request $request)
{
if ($request->getPathInfo() == '/login_check' && $request->isMethod('POST')) {
return true;
}
return false;
}
/**
* Get the authentication credentials from the request and return them
* as any type (e.g. an associate array).
*
* Whatever value you return here will be passed to getUser() and checkCredentials()
*
* For example, for a form login, you might:
*
* return array(
* 'username' => $request->request->get('_username'),
* 'password' => $request->request->get('_password'),
* );
*
* Or for an API token that's on a header, you might use:
*
* return array('api_key' => $request->headers->get('X-API-TOKEN'));
*
* @param Request $request
*
* @return mixed Any non-null value
*
* @throws \UnexpectedValueException If null is returned
*/
public function getCredentials(Request $request)
{
return [
'username' => $request->request->get('_username'),
'password' => $request->request->get('_password'),
'token' => $request->request->get('_csrf_token'),
];
}
/**
* Return a UserInterface object based on the credentials.
*
* The *credentials* are the return value from getCredentials()
*
* You may throw an AuthenticationException if you wish. If you return
* null, then a UsernameNotFoundException is thrown for you.
*
* @param mixed $credentials
* @param UserProviderInterface $userProvider
*
* @throws AuthenticationException
*
* @return UserInterface|null
*/
public function getUser($credentials, UserProviderInterface $userProvider)
{
$username = $credentials['username'];
$user = null;
try {
return $this->userRepository->loadUserByUsername($username);
} catch (NonUniqueResultException $e) {
}
return null;
}
/**
* Returns true if the credentials are valid.
*
* If any value other than true is returned, authentication will
* fail. You may also throw an AuthenticationException if you wish
* to cause authentication to fail.
*
* The *credentials* are the return value from getCredentials()
*
* @param mixed $credentials
* @param UserInterface $user
*
* @return bool
*
* @throws AuthenticationException
*/
public function checkCredentials($credentials, UserInterface $user)
{
$token = $credentials['token'];
if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken('authenticate', $token))) {
throw new InvalidCsrfTokenException('Invalid CSRF token.');
}
$entry = $this->ldap->getEntry($user->getUsername());
if ($entry instanceof Entry) {
$dn = $entry->getDn();
try {
$this->ldap->bind($dn, $credentials['password']);
return true;
} catch (\Exception $exception) {
//throw new BadCredentialsException($exception->getMessage());
}
}
//try check password in db
return $this->encoder->isPasswordValid($user, $credentials['password']);
}
/**
* Called when authentication executed and was successful!
*
* This should return the Response sent back to the user, like a
* RedirectResponse to the last page they visited.
*
* If you return null, the current request will continue, and the user
* will be authenticated. This makes sense, for example, with an API.
*
* @param Request $request
* @param TokenInterface $token
* @param string $providerKey The provider (i.e. firewall) key
*
* @return Response|null
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
$targetPath = $this->getTargetPath($request->getSession(), $providerKey);
return new RedirectResponse($targetPath);
// return new RedirectResponse($this->router->generate('intervention'));
}
FormLoginAuthenticator.php
class StaffLdap
{
private $ldap;
private $dn;
public function __construct(string $host, $dn, string $user, string $password)
{
$this->ldap = Ldap::create(
'ext_ldap',
array(
'host' => $host,
'encryption' => 'ssl',
)
);
$this->dn = $dn;
$this->ldap->bind($user, $password);
}
/**
* @param $uid
* @return \Symfony\Component\Ldap\Entry|null
*
*/
public function getEntry($uid)
{
$filter = "(&(|(sAMAccountName=*$uid*))(objectClass=person))";
$query = $this->ldap->query($this->dn, $filter, ['maxItems' => 1]);
$results = $query->execute();
if ($results->count() > 0) {
return $results[0];
}
return null;
}
/**
* @param $user
* @param $password
* @throws LdapException
*/
public function bind($user, $password)
{
try {
$this->ldap->bind($user, $password);
} catch (\Exception $exception) {
throw new BadCredentialsException($exception->getMessage());
}
}
/**
* @return \Symfony\Component\Ldap\Adapter\EntryManagerInterface
*/
public function getEntryManager()
{
return $this->ldap->getEntryManager();
}
}
StaffLdap.php
AcDomain\Travaux\Security\StaffLdap:
$host: '%env(ACLDAP_URL)%'
$dn: '%env(ACLDAP_DN)%'
$user: '%env(ACLDAP_USER)%'
$password: '%env(ACLDAP_PASSWORD)%'
}
service.yaml
ARG