CakePHP(LDAP)中的备用身份验证源

时间:2009-09-09 01:01:10

标签: php authentication cakephp ldap

我正在开发CakePHP项目,目前正在构建用户身份验证的一部分。问题是我的身份验证信息(即:密码)没有存储在我的数据库中 - 身份验证源是LDAP,但我的问题同样适用于任何非数据库源。

似乎Cake仅在本地数据库中存在密码时处理它们。 The Cake Cookbook suggests您可以通过使用$this->Auth->authorize变量告诉它不同的控制器/模型/对象提供授权过程,但是查看代码(特别是the Auth::startup() function)看起来像Cake会始终尝试查询数据库第一个,检查匹配的用户名/密码,然后查看您使用Auth->authorize指定的备用对象。也就是说,更改authorize仅添加二级过滤器,它不会替换数据库查找。

// The process
1. User provides details
2. Cake checks the database
3. If OK, then check the custom object method
4. If OK, return true

// What I'd like:
1. User provides details.
2. Check the custom object method
3. If OK, return true
4. Profit.

有关如何执行此操作的任何想法,希望不会破解核心文件?

3 个答案:

答案 0 :(得分:8)

假设您只是绑定LDAP并从MySQL存储/检索用户数据,这种方法将作为“桥梁”,自动为成功登录创建帐户:

// app/controllers/components/ldap_auth.php
<?php
App::import('Component', 'Auth');
class LdapAuthComponent extends AuthComponent {
/**
 * Don't hash passwords
 */
    function hashPasswords($data){
        return $data;
    }
/**
 * We will initially identify the user
 */
    function identify($user=null, $conditions=null) {
        // bind credentials against ldap
        $ldapUser = $this->_ldapAuth($user); // do your stuff
        if (!$ldapUser) {
            return null; // if bind fails, then return null (as stated in api)
        }
        // get the cake model you would normally be authenticating against
        $model =& $this->getModel(); // default is User
        // check for existing User in mysql
        $user = $model->find('first', array('conditions' => array(
            'username' => $ldapUser['cn']
        ));
        // if no existing User, create a new User
        if (!$user) {
            $user = $model->save(array('User' => array(
                'username' => $ldapUser['cn'],
                // .. map needed ldap fields to mysql fields ..
            )));
            if (!$user) {
                $this->cakeError('ldapCreateUser');
            }
            // pass the id of the newly created User to Auth's identify
            return parent::identify($model->id, $conditions);
        }
        // pass the id of the existing User to Auth's identify
        return parent::identify($user[$this->userModel][$model->primaryKey], $conditions);
    }
/**
 * Lets check LDAP
 *
 * @return mixed Array of user data from ldap, or false if bind fails
 */
    function _ldapAuth($user) {
        $username = $user[$this->userModel][$this->fields['username']];
        $password = $user[$this->userModel][$this->fields['password']];
        // use the php ldap functions here
        return $ldapUser;
    }
}
?>

要使用,请在应用中将所有对Auth的引用替换为LdapAuth,或按照instructions here

请注意,虽然受保护的_ldapAuth()方法可以被抽象为LdapUser模型,但该模型从{{ 1}},LDAP服务器连接设置位于LdapSource配置中,database.php 适用于使用可配置字段映射,这些都不是“完成它”的要求。 :)

答案 1 :(得分:1)

Auth::authorize确实不是模型数据的替代品,它只是增加了它。

  

<强> 5.2.6.10 authorize

     

通常,AuthComponent会尝试通过将您输入的登录凭据与用户模型中存储的凭据进行比较来验证您输入的登录凭据是否准确。但是,有时您可能希望在确定正确的凭据时执行一些额外的工作

这应该不是问题,因为LDAP细节应该在模型中抽象出来。 Cake仍将检查模型的用户名和密码,但它从LDAP目录透明地获取答案。您只需要为模型实现LDAP datasource。也许这些two articles可以帮助您入门。

答案 2 :(得分:0)

我能够以相对狡猾但可能接受的方式破解蛋糕的方式。

我在“用户”表格中添加了“密码”字段,并将每个人的密码设置为“a”(尽管您可以使用任何内容)。

然后我在我的模型中添加了自定义散列函数:

function hashPasswords($data) {
    $data['User']['password'] = 'a';
    return $data;
}

并告诉我的控制器使用该模型进行散列:

$this->Auth->authenticate = ClassRegistry::init('User');

这意味着现在蛋糕的第一步将始终通过(假设表中存在用户名)。 authorize函数现在可以执行其操作,并使用您喜欢的任何方法进行适当的检查。

它基本上改变了这个过程:

// The process
1. User provides details
2. Cake checks the database **and always returns OK**
3. If OK, then check the custom object method
4. If OK, return true