목차

XE, Rhymix와 Dokuwiki 연동하기

한줄 요약: 아니 이게 무슨 삽질…

놀랍게도 XE와는 다르게 global context 단위에서 Rhymix와 Dokuwiki의 함수가 겹치기 때문에 config/config.inc.php를 불러오는 것이 불가능하다.

깔끔하게 회원 연동하는 방법이 있을 수도 있지만, 여기서는 그냥 서버에서 원격으로 부를 php 파일을 하나 더 만들고 그 파일을 거쳐서 불러오는 것으로 대체한다.

global context가 겹치는 부분 외에 XE와 Rhymix가 딱히 다른부분이 없기 때문에 XE, Rhymix 둘 다 동일하게 사용할 수 있다.

세팅 점검

지난번처럼 preload.php등을 고칠 필요는 없다.

대신 phpinfo()에서 allow_url_fopen이 가능한지, 또한 자신의 서버가 https인 경우에는 OpenSSL이 설치되어있는지까지도 확인한다.

만약 allow_url_fopen이 되지 않았다면, curl을 쓰든 socket을 직접 불러서 쓰든 알아서 해야 할 것이다.

쿠기 관련도 보안을 위해 각종 옵션들이 켜져있다면 조금 곤란할 수도 있다 ㅜㅜ

userinfo.php

doku.php가 있는 위키 루트 폴더에 userinfo.php 파일을 다음과 같이 만들었다.

PHP 7.4는 될 것이라고 생각하니, const, [] 같은건 적당히 사용했다.

userinfo.php
<?php
function endsWith( $haystack, $needle ) {
    $length = strlen( $needle );
    if( !$length ) {
        return true;
    }
    return substr( $haystack, -$length ) === $needle;
}
 
$baseFile = basename(__FILE__);
$scriptName = $_SERVER['SCRIPT_NAME'];
if(!endsWith($scriptName, $baseFile)){
    return;//혹시나 의도와 다르게 php파일을 부르는 경우를 막기 위해..
}
 
define("__ZBXE__",true);
define("__XE__",true);
mb_internal_encoding("UTF-8");
mb_regex_encoding("UTF-8");
 
const SESSION_KEY = "hash 값으로 사용할 아무 문자열, 영문자 적당히 섞어서 16글자쯤";
 
const XE_PATH = "../xe/config/config.inc.php";//config.inc.php가 있는 경로, rhymix일 수도 있다.
 
$time = $_REQUEST['time']??'';
$hash = $_REQUEST['hash']??'';
 
if(!$time || !$hash){
    die(json_encode([
        'result'=>false,
        'reason'=>'invalid input'
    ]));
}
 
 
$myTime = time();
$srcTime = intval($time);
 
if(abs($myTime - $srcTime) >= 2){
    die(json_encode([
        'result'=>false,
        'reason'=>'invalid time'
    ]));
}
 
header("Content-Type: application/json");
if(!file_exists(XE_PATH)){
    die(json_encode([
        'result'=>false,
        'reason'=>'no path'
    ]));
}
 
if(hash('sha256', SESSION_KEY.$time, false) != $hash){
    die(json_encode([
        'result'=>false,
        'reason'=>'invalid session hash'
    ]));
}
 
require(XE_PATH);
if (!class_exists('Context')) {
    die(json_encode([
        'result'=>false,
        'reason'=>'No XE Context'
    ]));
}
 
$oContext = \Context::getInstance();
$oContext->init();
$logged_info = $oContext->get("logged_info");
if(!$logged_info){
    die(json_encode([
        'result'=>true,
        'user_id'=>null,
        'name'=>null,
        'mail'=>null,
        'grps'=>null,
    ]));
}
die(json_encode([
    'result'=>true,
    'user_id'=>$logged_info->user_id,
    'name'=>$logged_info->nick_name,
    'mail'=>$logged_info->email_address,
    'grps'=> @array_values(@array_filter($logged_info->group_list))
]));

authxe plugin 추가

lib/plugins 폴더에 authxe 폴더를 추가하고 아래 파일을 추가했다.

auth.php
<?php
// must be run within Dokuwiki
if (!defined('DOKU_INC')) die();
 
const SESSION_KEY = "위에 적었던 그 문자열을 복사 붙여넣기";
 
class auth_plugin_authxe extends \dokuwiki\Extension\AuthPlugin
{
  public function __construct()
  {
    parent::__construct();
    $this->cando['external'] = true;
    $this->cando['logout'] = false;
  }
 
  function trustExternal($user, $pass, $sticky = false)
  {
    global $USERINFO;
    $baseDir = getBaseURL(true);
    $targetPath = $baseDir . 'userinfo.php';//만약 위 파일의 경로가 다르다면 여기도 고쳐준다.
 
    $arrContextOptions = array(
      "ssl" => array(
        "verify_peer" => true,
      ),
      "http" => array(
        'header' => "Accept-language: ko\r\nCookie: ".session_name()."=".session_id()."\r\n"
      )
    );
 
    $time = ''.time();
    $hash = hash('sha256', SESSION_KEY.$time, false);
 
    $result = @file_get_contents("{$targetPath}?time={$time}&hash={$hash}", false, stream_context_create($arrContextOptions));
    if(!$result){
      return false;
    }
    $logged_info = json_decode($result);
    if(!$logged_info->result){
      throw new \RuntimeException($logged_info->reason);
    }
 
    if(!$logged_info->user_id){
      return false;
    }
 
    $USERINFO['name'] = $logged_info->name;
    $USERINFO['mail'] = $logged_info->mail;
    $USERINFO['grps'] = $logged_info->grps;
    $_SERVER['REMOTE_USER'] = $logged_info->user_id;
    $_SESSION[DOKU_COOKIE]['auth']['user'] = $logged_info->user_id;
    $_SESSION[DOKU_COOKIE]['auth']['info'] = $USERINFO;
    return true;
  }
}

plugin.info.txt 파일이 없으면 또 dokuwiki가 뭐라고 해서 넣어주었다.

plugin.info.txt
base    authxe
author  Hide_D
email   hided62@gmail.com
date    2021-09-23
name    AuthXE
desc    AuthXE, AuthRhymix
url     https://hided.net

그리고 나서 conf/local.php의 내용을

$conf['authtype'] = 'authxe';
$conf['disableactions'] = 'register,resendpwd,profile,profile_delete';

정도로 수정해주면 된다.