【问题标题】:LDAP Security groups Symfony 2LDAP 安全组 Symfony 2
【发布时间】:2014-03-07 09:44:31
【问题描述】:

我很难在我的 Symfony2 项目上获得 LDAP 自定义身份验证。 我首先尝试使用 Fr3dLdapBundle 和其他工具,但无法使其正常工作 + 它不支持安全组。

我终于可以使用这两个链接: - https://groups.google.com/forum/#!topic/symfony2/RUyl15zaH8A - http://symfony.com/doc/current/cookbook/security/custom_authentication_provider.html

但是现在我必须检查某人何时登录,例如他是否在安全组“AdminMyWebsite”中。如果他是,我必须将他的角色设置为 ROLE_ADMIN。但我不知道该怎么做。

LdapProvider:

<?php

namespace EspaceApprenti\UserBundle\Security\Authentication\Provider;

use EspaceApprenti\UserBundle\Security\Authentication\Token\LdapToken;
use Symfony\Component\Debug\Exception\ContextErrorException;
use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserProviderInterface;

class LdapProvider implements AuthenticationProviderInterface {

private $userProvider;
private $providerKey;
private $logger;
private $server;
private $port;
private $domaine;
private $dn;

public function __construct(UserProviderInterface $userProvider, $providerKey, $logger, $server, $port, $domaine, $dn) {
    $this->userProvider = $userProvider;
    $this->providerKey = $providerKey;
    $this->logger = $logger;

    $this->server = $server;
    $this->port = $port;
    $this->domaine = $domaine;
    $this->dn = $dn;
}

public function authenticate(TokenInterface $token) {

    if (!$this->supports($token)) {
        return null;
    }

    $user = $this->userProvider->loadUserByUsername($token->getUsername());

    $username = $token->getUsername();
    $password = $token->getCredentials();

    $this->logger->info(' -- LdapProvider -- ' . $username);
    if ($password) {
        if (!$this->ldapBind($username, $password)) {
            throw new AuthenticationException('Authentication failed ! ');
        }
    }

    $authenticatedToken = new LdapToken($user, $password, $this->providerKey, $user->getRoles());
    $authenticatedToken->setAttributes($token->getAttributes());

    return $authenticatedToken;
}

private function ldapBind($username, $password) {
    // returns true or false        
    $this->logger->info(' -- LdapProvider -> ldapBind() Serveur -- ' . $this->server);
    $this->logger->info(' -- LdapProvider -> ldapBind() Username -- ' . $username);
    $ds = ldap_connect($this->server, $this->port);
    if ($ds) {
        try {
            if (ldap_bind($ds, $this->domaine . '\\' . $username, $password)) {
                return true;
            } else {
                return false;
            }
        } catch (ContextErrorException $e) {
            $this->logger->error(' -- LdapProvider -> ldapBind() Unable to bind to server: Invalid credentials -- ' . $e->getMessage());
        }
    } else {
        $this->logger->info(' -- LdapProvider -> ldapBind() Unable to connect to LAPP Server -- ' . $this->server);
    }

}

public function supports(TokenInterface $token) {
    return $token instanceof LdapToken;
}

}

LdapFactory

<?php

namespace EspaceApprenti\UserBundle\DependencyInjection\Security\Factory;

use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AbstractFactory;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Reference;



class LdapFactory extends AbstractFactory
{
    protected function getListenerId()
{
    return 'security.authentication.listener.ldap';
}

protected function createAuthProvider(ContainerBuilder $container, $id, $config, $userProviderId)
{
    $providerId = 'security.authentication.provider.ldap.'.$id;

    $container
        ->setDefinition($providerId, new DefinitionDecorator('security.authentication.provider.ldap'))
        ->replaceArgument(0, new Reference($userProviderId))                
        ->replaceArgument(1, $id);

    return $providerId;
}

protected function createEntryPoint($container, $id, $config, $defaultEntryPoint)
{
    $entryPointId = 'security.authentication.ldap_entry_point.'.$id;
    $container
        ->setDefinition($entryPointId, new DefinitionDecorator('security.authentication.ldap_entry_point'))
        ->addArgument(new Reference('security.http_utils'))
        ->addArgument($config['login_path'])
        ->addArgument($config['use_forward'])
    ;

    return $entryPointId;
}    

public function getPosition()
{
    return 'form';
}

public function getKey()
{
    return 'ldap';
}

}

LdapListener

<?php

namespace EspaceApprenti\UserBundle\Security\Firewall;

use EspaceApprenti\UserBundle\Security\Authentication\Token\LdapToken;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\Security\Http\Firewall\AbstractAuthenticationListener;
use Symfony\Component\Security\Http\HttpUtils;
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;

class LdapListener extends AbstractAuthenticationListener
{
private $csrfProvider;
protected $logger;

/**
 * {@inheritdoc}
 */
public function __construct(SecurityContextInterface $securityContext, 
        AuthenticationManagerInterface $authenticationManager, 
        SessionAuthenticationStrategyInterface $sessionStrategy, 
        HttpUtils $httpUtils, 
        $providerKey, 
        AuthenticationSuccessHandlerInterface $successHandler, 
        AuthenticationFailureHandlerInterface $failureHandler, 
        array $options = array(), 
        LoggerInterface $logger = null, 
        EventDispatcherInterface $dispatcher = null, 
        CsrfProviderInterface $csrfProvider = null)
{
    parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, array_merge(array(
        'username_parameter' => '_username',
        'password_parameter' => '_password',
        'csrf_parameter'     => '_csrf_token',
        'intention'          => 'authenticate',
        'post_only'          => true,
    ), $options), $logger, $dispatcher);

    $this->csrfProvider = $csrfProvider;
    $this->logger = $logger;
}

/**
 * {@inheritdoc}
 */
protected function requiresAuthentication(Request $request)
{
    if ($this->options['post_only'] && !$request->isMethod('POST')) {
        return false;
    }

    return parent::requiresAuthentication($request);
}

/**
 * {@inheritdoc}
 */
protected function attemptAuthentication(Request $request)
{
    if (null !== $this->csrfProvider) {
        $csrfToken = $request->get($this->options['csrf_parameter'], null, true);

        if (false === $this->csrfProvider->isCsrfTokenValid($this->options['intention'], $csrfToken)) {
            throw new InvalidCsrfTokenException('Invalid CSRF token.');
        }
    }

    if ($this->options['post_only']) {
        $username = trim($request->request->get($this->options['username_parameter'], null, true));
        $password = $request->request->get($this->options['password_parameter'], null, true);
    } else {
        $username = trim($request->get($this->options['username_parameter'], null, true));
        $password = $request->get($this->options['password_parameter'], null, true);
    }
    $this->logger->alert('LdapAuthenticationListener : '. $username);
    $this->logger->alert('LdapAuthenticationListener : '. $this->providerKey);
    $request->getSession()->set(SecurityContextInterface::LAST_USERNAME, $username);

    return $this->authenticationManager->authenticate(new LdapToken($username, $password, $this->providerKey));
}
}

LdapToken

<?php

namespace EspaceApprenti\UserBundle\Security\Authentication\Token;

use Symfony\Component\Security\Core\Authentication\Token\AbstractToken;

class LdapToken extends AbstractToken {

private $credentials;
private $providerKey;

/**
 * Constructor.
 *
 * @param string          $user        The username (like a nickname, email address, etc.), or a UserInterface instance or an object implementing a __toString method.
 * @param string          $credentials This usually is the password of the user
 * @param string          $providerKey The provider key
 * @param RoleInterface[] $roles       An array of roles
 *
 * @throws \InvalidArgumentException
 */
public function __construct($user, $credentials, $providerKey, array $roles = array())
{
    parent::__construct($roles);

    if (empty($providerKey)) {
        throw new \InvalidArgumentException('$providerKey must not be empty.');
    }

    $this->setUser($user);
    $this->credentials = $credentials;
    $this->providerKey = $providerKey;

    parent::setAuthenticated(count($roles) > 0);
}

/**
 * {@inheritdoc}
 */
public function setAuthenticated($isAuthenticated)
{
    if ($isAuthenticated) {
        throw new \LogicException('Cannot set this token to trusted after instantiation.');
    }

    parent::setAuthenticated(false);
}

public function getCredentials()
{
    return $this->credentials;
}

public function getProviderKey()
{
    return $this->providerKey;
}

/**
 * {@inheritdoc}
 */
public function eraseCredentials()
{
    parent::eraseCredentials();

    $this->credentials = null;
}

/**
 * {@inheritdoc}
 */
public function serialize()
{
    return serialize(array($this->credentials, $this->providerKey, parent::serialize()));
}

/**
 * {@inheritdoc}
 */
public function unserialize($serialized)
{
    list($this->credentials, $this->providerKey, $parentStr) = unserialize($serialized);
    parent::unserialize($parentStr);
}

}

谁能帮我解决这个问题?

问候

【问题讨论】:

  • 我不是 100% 确定如何在 Symfony2 中执行此操作,但您需要运行 LDAP 查询来检索用户组(您可以使用 google 获取示例查询)。然后您可以检查返回的组以查看他们是否有权访问该组。我建议您在不使用 symfony2 的情况下手动运行这些程序,这样您就可以了解 LDAP 查询是如何工作的。我以前使用过adldap.sourceforge.net,但它更适合 Active Directory,但它非常好,并且提供了您需要的功能。祝你好运!
  • 嗨,我认为 Fr3dLdapBundle 可以管理组。您可以扩展 LdapManager 并使用它。事实上,将 LDAP 组分配给 symfony 安全组。你必须通过 symfony 安全组创建一个 LDAP 组
  • @PerroinThibault Fr3dLdapBundle 似乎自 Symfony2.1 起已停产。你应该改用BorisMorel/LdapBundle。
  • @ferdynator 不错!这个捆绑包似乎是一个很好的选择,而且效率更高!非常感谢
  • 您知道 BorisMorel 捆绑包是否支持唯一身份验证吗?如果是这样,你有例子吗?谢谢!

标签: php symfony authentication ldap


【解决方案1】:

我解决了我的问题。我在 ldap_bind 之后添加了一个 ldap_search 来检查用户是否是安全组的成员

$ds = ldap_connect($this->server, $this->port);
        if ($ds) {
            try {
                if (ldap_bind($ds, $this->domaine . '\\' . $username, $password)){
                    $user = $this->m->getRepository('EspaceApprentiUserBundle:ApprenticeUser')->findOneBy(array('username' => $username));   
                    $filter = "(&(objectCategory=person)(samAccountName=" . $username . "))";
                    $result = ldap_search($ds, $this->dn, $filter);
                    $entries = ldap_get_entries($ds, $result);
                    if (in_array($this->administrator,$entries[0]['memberof']))
                    { 
                        $user->setRoles(array('ROLE_ADMIN'));
                        $this->m->persist($user);
                        $this->m->flush();
                    } else {
                        $user->setRoles(array('ROLE_USER'));
                        $this->m->persist($user);
                        $this->m->flush();
                    }       
                    return true;
                } else {
                    return false;
                }
            } catch (ContextErrorException $e) {
                $this->logger->error(' -- LdapProvider -> ldapBind() Unable to bind to server: Invalid credentials -- ' . $e->getMessage());
            }
        } else {
            $this->logger->info(' -- LdapProvider -> ldapBind() Unable to connect to LAPP Server -- ' . $this->server);
        }

【讨论】:

    猜你喜欢
    • 2017-06-27
    • 2017-03-31
    • 2014-02-15
    • 2017-11-30
    • 2016-01-06
    • 1970-01-01
    • 1970-01-01
    • 2011-09-22
    • 2017-07-02
    相关资源
    最近更新 更多