Sha*_*ane 6 php ldap symfony mediawiki-extensions
最近我一直在为MediaWiki开发LDAP身份验证提供程序.在我看来,我一直试图解决这个问题已经很多天了,无法提出解决方案.
我开发此插件的方式是允许配置我们将连接的许多服务器.如果我们无法连接到一台服务器,我们将尝试下一个...依此类推,直到所有用完为止.
为了实现这一点,我在我的类中有一个函数循环尝试连接的服务器,直到成功为止:
private function connect( LdapAuthenticationRequest $req ) {
$dn = $this->config->get( 'BindDN' )[$req->domain];
$pass = $this->config->get( 'BindPass' )[$req->domain];
$servers = $this->config->get( 'Servers' )[$req->domain];
$encryption = $this->config->get( 'EncryptionType' )[$req->domain];
if ( false === $dn ) {
$msgkey = 'ldapauth-attempt-bind-search';
$bind_with = [ null, null ];
} else {
$msgkey = 'ldapauth-attempt-bind-dn-search';
$bind_with = [ $dn, $pass ];
}
$message = new Message( $msgkey, [
'dn' => "{$dn}@{$req->domain}",
] );
$this->logger->info( $message->text() );
foreach ( $servers as $server ) {
if ( false === $server ) {
continue;
}
$ldap = Ldap::create( 'ext_ldap', [
'host' => $server,
'encryption' => $encryption
] );
// Attempt bind - on failure, throw an exception
try {
call_user_func_array( [ $ldap, 'bind' ], $bind_with );
$this->server = $server;
$this->encryption = $encryption;
// log successful bind
$msgkey = 'ldapauth-bind-success';
$message = wfMessage( $msgkey )->text();
$this->logger->info( $message );
return $ldap;
} catch ( SymException $e ) {
if ( false === $dn ) {
$msgkey = 'ldapauth-no-bind-search';
} else {
$msgkey = 'ldapauth-no-bind-dn-search';
}
$message = new Message( $msgkey, [
'dn' => "{$dn}@{$req->domain}",
] );
$message = $message->text();
$this->logger->info( $message );
$this->logger->debug( $e->getMessage() );
}
}
Run Code Online (Sandbox Code Playgroud)
我一直试图想出一个更好的方法来做到这一点,这将允许我更好地对这个类进行单元测试,但到目前为止,我正在绘制空白.
我坚持这个问题的一个重要原因是Symfony的LDAP适配器本质上是硬耦合到我的代码中,因为对connect的调用是对Symfony代码库的静态调用.即我无法传入某些描述的连接器实例,然后尝试连接.我可能只是Ldap::create使用自己的连接包装器进行包装吗?
由于您使用的是 Symfony,我想您最好的选择是LDap使用框架的依赖项注入来注入对象。然而我不是 Symfony 的专家。所以作为一个简单的黑客,我会这样做:
private function connect($req)
{
$dn = $this->config->get('BindDN')[$req->domain];
$pass = $this->config->get('BindPass')[$req->domain];
$servers = $this->config->get('Servers')[$req->domain];
$encryption = $this->config->get('EncryptionType')[$req->domain];
if (false === $dn) {
$msgkey = 'ldapauth-attempt-bind-search';
$bind_with = [null, null];
} else {
$msgkey = 'ldapauth-attempt-bind-dn-search';
$bind_with = [$dn, $pass];
}
$message = new Message($msgkey, [
'dn' => "{$dn}@{$req->domain}",
]);
$this->logger->info($message->text());
foreach ($servers as $server) {
if (false === $server) {
continue;
}
$ldap = $this->createLDAPObject($server, $encryption);
// Attempt bind - on failure, throw an exception
try {
call_user_func_array([$ldap, 'bind'], $bind_with);
$this->server = $server;
$this->encryption = $encryption;
// log successful bind
$msgkey = 'ldapauth-bind-success';
$message = wfMessage($msgkey)->text();
$this->logger->info($message);
return $ldap;
} catch (SymException $e) {
if (false === $dn) {
$msgkey = 'ldapauth-no-bind-search';
} else {
$msgkey = 'ldapauth-no-bind-dn-search';
}
$message = new Message($msgkey, [
'dn' => "{$dn}@{$req->domain}",
]);
$message = $message->text();
$this->logger->info($message);
$this->logger->debug($e->getMessage());
}
}
}
/**
* @param $server
* @param $encryption
* @return mixed
*/
public function createLDAPObject($server, $encryption)
{
return Ldap::create('ext_ldap', [
'host' => $server,
'encryption' => $encryption
]);
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以模拟成员方法createLDAPObject而不是模拟静态方法Ldap::create,这应该更容易。
但是,我建议您重构代码,使其更具可读性和可测试性。
1-首先,call_user_func_array()它并不是真正适合测试,而且我认为您的要求不是太动态,因此您可以将该行替换为$ldap->bind($bind_with[0],$bind_with[1]);
2-您的connect方法太大而无法测试。请阅读代码异味 - 长方法
3-通过将表示与逻辑解耦,可以将该方法重构为更小的版本。例如,您要让Message对象从日志中获取文本$msgkey,这对代码的可读性和可测试性没有帮助。
这是我对这件事的第一个想法:)
快乐的编码和测试:)
| 归档时间: |
|
| 查看次数: |
213 次 |
| 最近记录: |