集成Dokuwiki,单点登陆

未登录情形,访问dokuwiki(简称wiki),会自动分配一个生存期为session的cookie值。

这个名为DokuWiki的Cookie值由以下代码分配。

inc/init.php
// init session
if (!headers_sent() && !defined('NOSESSION')){
    session_name("DokuWiki");
    if (version_compare(PHP_VERSION, '5.2.0', '>')) {
        session_set_cookie_params(0,DOKU_REL,'',($conf['securecookie'] && is_ssl()),true);
    }else{
        session_set_cookie_params(0,DOKU_REL,'',($conf['securecookie'] && is_ssl()));
    }
    session_start();
 
    // load left over messages
    if(isset($_SESSION[DOKU_COOKIE]['msg'])){
        $MSG = $_SESSION[DOKU_COOKIE]['msg'];
        unset($_SESSION[DOKU_COOKIE]['msg']);
    }
}

输入用户名和密码后具体登陆过程在

inc/auth.php
/**
 * This tries to login the user based on the sent auth credentials
 *
 * The authentication works like this: if a username was given
 * a new login is assumed and user/password are checked. If they
 * are correct the password is encrypted with blowfish and stored
 * together with the username in a cookie - the same info is stored
 * in the session, too. Additonally a browserID is stored in the
 * session.
 *
 * If no username was given the cookie is checked: if the username,
 * crypted password and browserID match between session and cookie
 * no further testing is done and the user is accepted
 *
 * If a cookie was found but no session info was availabe the
 * blowfish encrypted password from the cookie is decrypted and
 * together with username rechecked by calling this function again.
 *
 * On a successful login $_SERVER[REMOTE_USER] and $USERINFO
 * are set.
 *
 * @author  Andreas Gohr <andi@splitbrain.org>
 *
 * @param   string  $user    Username
 * @param   string  $pass    Cleartext Password
 * @param   bool    $sticky  Cookie should not expire
 * @param   bool    $silent  Don't show error on bad auth
 * @return  bool             true on successful auth
 */
function auth_login($user,$pass,$sticky=false,$silent=false){
    global $USERINFO;
    global $conf;
    global $lang;
    global $auth;
    $sticky ? $sticky = true : $sticky = false; //sanity check
 
    if (!$auth) return false;
 
    if(!empty($user)){
        //usual login
        if ($auth->checkPass($user,$pass)){
            // make logininfo globally available
            $_SERVER['REMOTE_USER'] = $user;
            auth_setCookie($user,PMA_blowfish_encrypt($pass,auth_cookiesalt()),$sticky);
            return true;
        }else{
            //invalid credentials - log off
            if(!$silent) msg($lang['badlogin'],-1);
            auth_logoff();
            return false;
        }
    }else{
        // read cookie information
        list($user,$sticky,$pass) = auth_getCookie();
        // get session info
        $session = $_SESSION[DOKU_COOKIE]['auth'];
        if($user && $pass){
            // we got a cookie - see if we can trust it
            if(isset($session) &&
                    $auth->useSessionCache($user) &&
                    ($session['time'] >= time()-$conf['auth_security_timeout']) &&
                    ($session['user'] == $user) &&
                    ($session['pass'] == $pass) &&  //still crypted
                    ($session['buid'] == auth_browseruid()) ){
                // he has session, cookie and browser right - let him in
                $_SERVER['REMOTE_USER'] = $user;
                $USERINFO = $session['info']; //FIXME move all references to session
                return true;
            }
            // no we don't trust it yet - recheck pass but silent
            $pass = PMA_blowfish_decrypt($pass,auth_cookiesalt());
            return auth_login($user,$pass,$sticky,true);
        }
    }
    //just to be sure
    auth_logoff(true);
    return false;
}

验证成功后,由函数auth_setCookie()来写入Cookie信息

auth_setCookie($user,PMA_blowfish_encrypt($pass,auth_cookiesalt()),$sticky);

auth_setCookie()涉及加密,由PMA_blowfish_encrypt()来完成。

inc/blowfish.php
// higher-level functions:
/**
 * Encryption using blowfish algorithm
 *
 * @param   string  original data
 * @param   string  the secret
 *
 * @return  string  the encrypted result
 *
 * @access  public
 *
 * @author  lem9
 */
function PMA_blowfish_encrypt($data, $secret)
{
    $pma_cipher = new Horde_Cipher_blowfish;
    $encrypt = '';
 
    $data .= '_'; // triming fixed for DokuWiki FS#1690 FS#1713
    $mod = strlen($data) % 8;
 
    if ($mod > 0) {
        $data .= str_repeat("\0", 8 - $mod);
    }
 
    foreach (str_split($data, 8) as $chunk) {
        $encrypt .= $pma_cipher->encryptBlock($chunk, $secret);
    }
    return base64_encode($encrypt);
}

把这个过程再现,把cookie信息写入即可实现dokuwiki登陆了。但需要从dokuwiki里面抽取的东西确实不少。于是,采用了cURL来模拟登陆,获取Set-Cookie的头信息,然后在写入http response头部即可。

myexample.php
/**
 * cURL模拟wiki登陆,将cookie信息写入到用户浏览器
 * 
 * @param string $user_name 用户名,不可以是邮箱,只限用户名
 * @param string $password 密码
 * 
 */
function my_wiki_login($user_name, $password)
{
	global $_SCONFIG;
 
	//请求地址
	$url = $_SCONFIG['wiki']['wikihost']."doku.php";
 
	//参数
	$params = "do=login&id=start&u=".urlencode($user_name)."&p=".urlencode($password);
 
	//cURL模拟请求登陆页面
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
	curl_setopt($ch, CURLOPT_HEADER, 1);//输出头部
	curl_setopt($ch, CURLOPT_NOBODY, 1);//关闭BODY输出	
	curl_setopt($ch, CURLOPT_POST, 1);//post
	curl_setopt($ch, CURLOPT_POSTFIELDS, $params);//参数
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);//返回请求输出
	$res = curl_exec($ch);//do exec
	curl_close($ch);
 
	//获取Set-Cookie头部
	$res_arr = explode("\r\n", $res);
	foreach( $res_arr as $head_line)
	{
		if( preg_match("/^set\-cookie\:/i", $head_line) ) {
			//$cookie_header_arr[] = $head_line;
 
			/* set http response header */
			header($head_line, 0);//replace=false
		}
	}
 
	//return $cookie_header_arr;
	return true;
}

上述代码首先找到set-cookie的头信息,然后再使用header()函数,写入即可。这样就可以一次登陆啦。

登陆后的Cookie信息

dokuwiki/login_analysis.txt · 最后更改: 2010/05/05 23:08 由 admin
 
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki