2017-03-10 30 views
1

我試圖讓Symfony防火牆的LDAP驗證工作,但有麻煩。主要問題似乎源於Symfony LdapUserProvider - 嘗試使用ldap_bind()時不需要用戶提供的用戶名和密碼。Symfony LDAP auth使用用戶名和密碼綁定

所以,我有這個作爲我的防火牆配置:

$app->register(new SilexProvider\SecurityServiceProvider(), [ 
    'security.firewalls' => [ 
     'secured' => [ 
      'pattern' => '^.*$', 
      'http' => true, 
      'users' => new \Symfony\Component\Security\Core\User\LdapUserProvider(
       \Symfony\Component\Ldap\Ldap::create('ext_ldap', [ 
        'connection_string' => 'ldap://MY_LDAP_DOMAIN', 
       ]), 
       'dc=MY_DC_1,dc=MY_DC_2', 
       'uid={username},cn=users,cn=accounts,dc=MY_DC_1,dc=MY_DC_2' 
      ), 
     ], 
    ], 
]); 

但我{username}部分不是由用戶提供的用戶名替換時ldap_bind方法被調用。所以,傳遞到ldap_binddn字符串實際上是uid={username},cn=users,cn=accounts,dc=MY_DC_1,dc=MY_DC_2 - 用戶名不會被替換。

如果我期待通過代碼,雖然這是預期的,因爲LdapUserProvider->loadUserByUsername()在做任何字符串替換之前調用bind。另一個問題是它直到很晚才知道用戶提供的密碼,因此bind調用再次沒有用戶提供的密碼。

我該如何設置它,以便它能正確替換我的dn和密碼?如果使用這些2條基本線路(如$data是有效用戶的陣列):

$ldap = ldap_connect('MY_LDAP_DOMAIN'); 
$bind = ldap_bind($ldap, 'uid=' . $data['username'] . ',cn=users,cn=accounts,dc=MY_DC_1,dc=MY_DC_2', $data['password']); 

然後,它結合完美。如何將這兩行轉換成Symfony防火牆能夠理解的情況?

回答

3

你必須在現有的代碼2個主要問題:

  1. 的Symfony的LdapUserProvider組件在默認情況下使用Active Directory(Windows)中的模式:sAMAccountName={username},而不是打開LDAP的uid={username}
  2. 您使用內置在http安全防火牆中,默認情況下使用DaoAuthenticationProvider身份驗證提供程序。如果使用LDAP身份驗證,則需要使用LdapBindAuthenticationProvider

第一個問題可以通過傳遞用戶標識符鍵來解決,以LdapUserProvider

$app['ldap.users'] = function() use ($app) { 
    return new LdapUserProvider(
     // your LDAP adapter 
     $app['ldap'], 
     // base DN 
     'dc=example,dc=com', 
     // you don't need search DN 
     null, 
     // you don't need search password 
     null, 
     // list of default roles, can be empty array 
     ['ROLE_USER'], 
     // user identifier key for LDAP 
     // this identitfer must be set explicitly 
     'uid' 
    ); 
}; 

通知第三和第四參數可以null,因爲他們將永遠不會被使用:LdapBindAuthenticationProvider會先調用,所以LDAP連接已經被綁定。

第二個問題需要一點點編碼。 Symfony內置了http_basic_ldap身份驗證提供程序,非常適合您的需求。不幸的是,Silex沒有一個,所以你需要自己做。使用Silex文檔以供參考:Defining a custom Authentication Provider

這是我對Silex的form_login_ldap實現的示例。 註冊所有LDAP相關的服務:

$app // register other services 
    ->register(new LdapServiceProvider()) 
    ->register(new LdapUsersServiceProvider()) 
    ->register(new LdapSecurityServiceProvider()) 
    ->register(new \Silex\Provider\SecurityServiceProvider(), [ 
     'security.firewalls' => [ 
      'login' => [ 
       'pattern' => '^/login$', 
      ], 
      'secured' => [ 
       'pattern' => '^.*$', 
       'form_login_ldap' => [ 
        'login_path' => 'login', 
        'check_path' => 'login_check', 
        'default_target_path' => 'backoffice', 
       ], 
       'users' => $this['ldap.users'], 
      ], 
     ], 
    ]) 
; 

服務供應商LDAP適配器

use Pimple\Container; 
use Pimple\ServiceProviderInterface; 
use Symfony\Component\Ldap\Ldap; 

class LdapServiceProvider implements ServiceProviderInterface 
{ 
    public function register(Container $app) 
    { 
     $app['ldap'] = function() { 
      return Ldap::create('ext_ldap', [ 
       'connection_string' => 'ldap.example.com', 
      ]); 
     }; 
    } 
} 

服務提供商LDAP用戶

use Pimple\Container; 
use Pimple\ServiceProviderInterface; 
use Symfony\Component\Security\Core\User\LdapUserProvider; 

class LdapUsersServiceProvider implements ServiceProviderInterface 
{ 
    public function register(Container $app) 
    { 
     $app['ldap.users'] = function() use ($app) { 
      return new LdapUserProvider(
       $app['ldap'], 
       'dc=example,dc=com', 
       null, 
       null, 
       ['ROLE_USER'], 
       'uid' 
      ); 
     }; 
    } 
} 

服務提供商的安全認證監聽器廠爲LDAP表格(對你來說最有意思的部分)

use Pimple\Container; 
use Pimple\ServiceProviderInterface; 
use Symfony\Component\Security\Core\Authentication\Provider\LdapBindAuthenticationProvider; 

class LdapSecurityServiceProvider implements ServiceProviderInterface 
{ 
    public function register(Container $app) 
    { 
     $app['security.authentication_listener.factory.form_login_ldap'] = $app->protect(function ($name, $options) use ($app) { 
      // define the authentication provider object 
      $app['security.authentication_provider.'.$name.'.form_login_ldap'] = function() use ($app, $name) { 
       return new LdapBindAuthenticationProvider(
        $app['security.user_provider.'.$name], 
        $app['security.user_checker'], 
        $name, 
        $app['ldap'], 
        'uid={username},dc=example,dc=com', 
        $app['security.hide_user_not_found'] 
       ); 
      }; 

      // define the authentication listener object 
      $app['security.authentication_listener.'.$name.'.form_login_ldap'] = $app['security.authentication_listener.form._proto']($name, $options); 

      // define the entry point object 
      $app[$entryPoint = 'security.entry_point.'.$name.'.form_login_ldap'] = $app['security.entry_point.form._proto']($name, array()); 

      return array(
       // the authentication provider id 
       'security.authentication_provider.'.$name.'.form_login_ldap', 
       // the authentication listener id 
       'security.authentication_listener.'.$name.'.form_login_ldap', 
       // the entry point id 
       $entryPoint, 
       // the position of the listener in the stack 
       'form' 
      ); 
     }); 
    } 
}