2014-03-07 59 views
3

我努力在我的Symfony2项目上获得LDAP自定义身份验证。 我第一次尝试使用Fr3dLdapBundle和其他人,但它不可能工作+它不支持安全组。LDAP安全组Symfony 2

我终于得到它与这两个环节的工作: - 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); 
} 

} 

任何人都可以帮助我吗?

Regards

+0

我不是100%肯定有关如何做到这一点在Symfony2中的成员但你需要运行一个LDAP查询,以获得用户组(您可以使用谷歌获取示例查询)。然后,您可以检查返回的组,看看他们是否可以访问该组。我会建议如何在不使用symfony2的情况下手动运行这些程序,这样您就可以了解LDAP查询的工作方式。我以前使用过http://adldap.sourceforge.net/,但是它更适合Active Directory,但它非常好,并提供了您所需的功能。祝你好运! – mic

+0

嗨,我认为Fr3dLdapBundle可以管理组。您可以扩展LdapManager并使用它。实际上,将LDAP组分配给symfony安全组。您必须通过symfony安全组 –

+1

@ProroinThibault创建一个LDAP组,'Fr3dLdapBundle'自从'Symfony2.1'后似乎不再使用。您应该改用[BorisMorel/LdapBundle](https://github.com/BorisMorel/LdapBundle)。 – ferdynator

回答

1

我解决了我的问题。我加了ldap_search中的ldap_bind后检查,如果用户是安全组

$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); 
     }