Shinnara's Blog
Talking with Shinnara :: NaraTalk.com


지난 주인가요? phpBB 와 기존의 사이트(시스템 A)의 사용자 계정을 연동하여, 단일 로그인으로 처리하는 부분에 대한 글을 썼었습니다.  시스템 A의 로그인 정보를 이용하여 phpBB에 로그인하는 것은 잘 되는데, 만약 시스템 A에서 로그아웃을 하게 되면, phpBB 역시 로그아웃을 해주어야 합니다. 그렇지 않으면 시스템A에서는 로그 아웃이 된 상태인데, phpBB 페이지로 들어가면 해당 사용자가 로그인한 것으로 인식되는 문제가 발생하게됩니다.

phpBB는 로그 아웃시 includes/sessions.php 에 선언된 session_end() 함수를 이용하여 세션을 정리하게 됩니다. 따라서 여기서도 해당 내용을 호출하면 됩니다. 시스템 A의 로그아웃을 처리하는 함수에서 직접 includes/sessions.php 를 include 하여 해당 함수를 호출할 수 도 있으나, 그렇게 되면 의존성의 측면에서 전체 시스템의 모습이 안 좋아질 수 있으므로, 간단한 파일을 하나 더 생성합니다. 저의 경우는 phpBB 디렉토리 바로 아래에 session_end.php 라는 이름으로 만들었습니다.

[session_end.php]

<?php

define('IN_PHPBB', true);
$phpbb_root_path = './';
include($phpbb_root_path . 'extension.inc');
include($phpbb_root_path . 'common.'.$phpEx);

$userdata = session_pagestart($user_ip, PAGE_LOGIN);
init_userprefs($userdata);

session_end($userdata['session_id'], $userdata['user_id']);

?>


위의 파일을 로그 아웃을 하는 쪽에서 include 하면 되겠지요, 아래처럼요..

...
session_unset();
include("/phpBB2/session_end.php");
...





0 Trackback, 0 Comment

TRACKBACK :: http://naratalk.com/trackback/220 관련글 쓰기

댓글을 달아 주세요




0. 들어가기

며칠 전 프로젝트를 위해서 drupal 과 phpBB 를 설치하는 포스팅을 올렸습니다. phpBB 가 현재의 프로젝트에 더 적합한 툴이라고 판단되어, phpBB 를 사용하기로 결정하였습니다.

설치 후, 제일 먼저 할 일은 과연 어떻게 하면 phpBB 와 기존의 사용자 시스템을 통합시키냐하는 것이었습니다. phpBB 의 소스를 뒤적거리면서 동작 방법을 검사하다 보니 phpBB가 어떻게 작동하는지 대강 알게 되었습니다.

다음의 내용은 완전하게 테스트가 된 내용이 아님을 알려드립니다. 분명 많은 부분에서 더 나은 코드를 작성할 수 있을 것입니다. 여기서는 어떻게 하면 연동이 가능한지에 대한 rough 한 소개를 위주로 하겠습니다.

대상이 되는 phpBB 는 2.0.22 버전입니다.

사용자 삽입 이미지

먼저 phpBB가 어떻게 사용자 정보를 유지하는 지를 알아야 할텐데요, phpBB 의 페이지들은 기본적으로 common.php 를 include 합니다. 또한 common.php 는 includes/sessions.php 를 로드하게 되는데, sessions.php 가 사용자의 정보를 얻는 기능을 수행합니다.

phpBB 의 viewforum.php 의 내용을 잠시 살펴보면

...

define('IN_PHPBB', true);
$phpbb_root_path = './';
include($phpbb_root_path . 'extension.inc');
include($phpbb_root_path . 'common.'.$phpEx);

...

$userdata = session_pagestart($user_ip, $forum_id);
init_userprefs($userdata);

...

이런 내용을 찾아볼 수 있습니다. 위에서 이야기한 대로 common.php 를 로드하고, sessions.php 에 정의된 session_pagestart() 함수를 통해 사용자 데이터를 얻는 과정입니다.

따라서 $userdata 에 대한 정보를 우리가 원하는 값으로 얻어 낼 수 있다면, 사용자 시스템의 통합을 이루어 낼 수 있을 것입니다.

여기서 설명하고 있는 대상 시스템( 이하 시스템 A)에 대해 잠깐 살펴보면,

이메일 주소를 아이디로 사용하고, 사용자의 이름을 세션 정보에 각각 s_id , s_name 이란 형태로 저장하고 있습니다.

$_SESSION['s_id'] = "shinnara@gmail.com";
$_SESSION['s_name'] = "Shinnara";

이 정보를 이용해서 phpBB 에 별도의 추가적인 사용자 입력 없이 시스템 A 에 로그인 한 정보 그대로 phpBB를 사용할 수 있도록 하는것이 목적입니다. 그리고 phpBB를 통한 로그인은 없도록 합니다. (이는 매우 중요한 가정사항입니다. 로그인 통합 후에  스킨 편집을 통하여 phpBB를 통한 로그인이 안되도록 해야합니다)


1. session 사용하도록 설정하기

phpBB는 자체적으로 새로운 session 을 만들어서 동작하기 때문에 다른 어플리케이션에서 만들어진 session 값을 얻어올 수 없습니다. 쿠키를 사용해서 내용을 전달할 수도 있지만, 이미 시스템 A가 세션을 사용하기 있기 때문에 이를 활용하려고 합니다.

phpBB 에서 시스템 A의 세션 값을 가져오기 위해 common.php 에 아래의 코드를  가장 앞쪽에 삽입합니다.

<?php

// for using external session values  -- Shinnara
session_start();


/***************************************************************************
 *                                common.php
 *                            -------------------
 *   begin                : Saturday, Feb 23, 2001
 *   copyright            : (C) 2001 The phpBB Group
 *   email                : support@phpbb.com
 *
 *   $Id: common.php,v 1.74.2.25 2006/05/26 17:46:59 grahamje Exp $
 *
 ***************************************************************************/

common.php 의 수정 사항은 이것이 전부입니다.



2. sessions.php 수정하기 (1) - session_pagestart()

앞서 이야기 했듯이 phpBB의 페이지들은 사용자 정보를 얻기 위해 session_pagestart() 함수를 사용합니다. 이 함수 외에도 sessions.php 에는 session_begin(), session_end() 함수를 포함하고 있습니다. 이중 session_begin()은 phpBB와 관련된 세션 정보가 없을 때 새로운 세션 정보를 만들어내는 역할을 하며, 통합 과정에 있어 매우 중요한 역할을 합니다.

먼저 session_pagestart()를 살펴봅니다.

 phpBB는 로그인을 하지 않더라도 일단 페이지가 불리게 되면 세션이 하나 만들어지게 됩니다. 이 역할을 session_begin()에서 수행하게 되며, 이를 위한 코드가 session_pagestart() 에서 마지막 부분에 위치한 아래의 코드입니다.


    //
    // If we reach here then no (valid) session exists. So we'll create a new one,
    // using the cookie user_id if available to pull basic user prefs.
    //
    $user_id = ( isset($sessiondata['userid']) ) ? intval($sessiondata['userid']) : ANONYMOUS;
 
 
    if ( !($userdata = session_begin($user_id, $user_ip, $thispage_id, TRUE)) )
    {
        message_die(CRITICAL_ERROR, 'Error creating user session', '', __LINE__, __FILE__, $sql);
    }
 
 
    return $userdata;


phpBB는 로그인을 하지 않더라도 세션을 만들며, 이때 $user_id 로 ANONYMOUS 인 -1 의 값을 갖게 됩니다. 이 값은 phpBB가 설치될 때 phpBB의 데이터베이스에 기본 사용자로 등록되어 있습니다. 페이지가 두번째 이상 불려지면 위의 코드는 더 이상 수행되지 않고 session_pagestart() 의 중간 부분에 있는 아래 코드가 실행되게 됩니다.

    //
    // Does a session exist?
    //
    if ( !empty($session_id) )
    {
     
        //
        // session_id exists so go ahead and attempt to grab all
        // data in preparation
        //
        $sql = "SELECT u.*, s.*
            FROM " . SESSIONS_TABLE . " s, " . USERS_TABLE . " u
            WHERE s.session_id = '$session_id'
                AND u.user_id = s.session_user_id";
        if ( !($result = $db->sql_query($sql)) )
        {
            message_die(CRITICAL_ERROR, 'Error doing DB query userdata row fetch', '', __LINE__, __FILE__, $sql);
        }

        $userdata = $db->sql_fetchrow($result);
       


        //
        // Did the session exist in the DB?
        //
       
         
        if ( isset($userdata['user_id']) )
        {
         
            //
            // Do not check IP assuming equivalence, if IPv4 we'll check only first 24
            // bits ... I've been told (by vHiker) this should alleviate problems with
            // load balanced et al proxies while retaining some reliance on IP security.
            //
            $ip_check_s = substr($userdata['session_ip'], 0, 6);
            $ip_check_u = substr($user_ip, 0, 6);

위의 코드 뒷쪽으로는 세션 테이블과 유저 테이블을 업데이트 하는 코드가 있게 됩니다. 이 부분은 이번 통합과정에서 큰 관련이 없고 중요한 것은 "if ( isset($userdata['user_id']) ) " 부분입니다.

로그인 여부와 상관없이 세션은 무조건 만들어지기 때문에 위의 if 문에서 true 이더라도 로그인이 되었다고 할 수 없습니다. 즉, ANONYMOUS 를 user_id 로 갖고 있는 경우가 있는 것입니다.  user_id 가  ANONYMOUS  인 경우는 다음의 경우를 생각해볼 수 있습니다.

 (1) 시스템 A에 로그인이 되어 있지 않은 상태,
 (2) 시스템 A에는 로그인이 되어 있으나, phpBB에는 로그인이 되어 있지 않은 상태


(1)의 경우라면, 고려할  사항이 아닙니다. (2)의 경우라면 시스템 A의 세션 정보를 이용해서 phpBB에 로그인을 시켜야 겠지요.

따라서 세션 값은 있지만 user_id 가 ANONYMOUS 인 경우, session_begin() 을 통해 새로운 세션을 열어 주도록합니다. 위의 코드를 아래와 같이 고칩니다.

        //
        // Did the session exist in the DB?
        //
       
         
        if ( isset($userdata['user_id']) )
        {
         
          if( $userdata['user_id'] == ANONYMOUS )
          {
            $userdata = session_begin(ANONYMOUS, $user_ip, $thispage_id, TRUE);
          }
         
            //
            // Do not check IP assuming equivalence, if IPv4 we'll check only first 24

위에서 파란색으로 표시된 부분을 삽입하면 됩니다.

이것으로 session_pagestart() 부분의 수정은 끝입니다.



3. sessions.php 수정하기 (2) - session_begin()

session_begin() 함수가 동작하는 기본 원리 역시 그리 복잡하지 않습니다. 자세한 내용은 원래의 코드를 주의 깊게 보시면 쉽게 알아내실 수 있으며 여기서는 통합을 위한 과정만 간략히 설명하도록 하겠습니다.

session_begin() 의 중간을 살펴보시면,

    // First off attempt to join with the autologin value if we have one
    // If not, just use the user_id value
    //
    $userdata = array();

 
    if ($user_id != ANONYMOUS)
    {   
       ... getting user
    }
 
    //
    // At this point either $userdata should be populated or
    // one of the below is true


위와 같은 코드 구조를 보실 수 있습니다. $user_id 가 ANONYMOUS 가 아닌 경우,  즉 등록된 사용자의 로그인인 경우 사용자 데이터를 데이터베이스로부터 가져오는 작업을 수행합니다.

우리가 추가해야 할 부분은 바로 ANONYMOUS 인 경우입니다. 위의 코드는 ANONYMOUS 인 부분에 대해 언급하고 있지 않습니다. 따라서  else { }  절을 만듭니다.

else{} 절에서 처리는 시스템 A에 대한 로그인 여부에 따라 달라집니다. 즉, 시스템 A의 세션 정보에 s_id 와 s_name 이 존재하면 이를 이용해서 phpBB에 대한 로그인을 처리합니다.

시스템 A의 세션 정보가 존재하는 경우도 다음의 두 경우로 생각해볼 수 있습니다.

  (3) phpBB 에 이미 시스템 A의 사용자 계정이 추가된 경우,
  (4) phpBB 에 시스템 A의 계정으로 처음 접속한 경우,(즉 데이터 베이스에 추가되어 있지 않은 경우)


본 통합에서는 시스템 A의 계정으로 phpBB에 접근할 경우, 첫 접속시 phpBB에 사용자 계정을 만들고, 이후부터는 해당 내용을 이용해서 로그인을 수행하도록 했습니다.

따라서 시스템 A의 세션 정보를 이용해서 이미 phpBB에 등록된 계정인지를 알아내야 합니다. 시스템 A는 아이디로 이메일을 사용했기 때문에, 이 정보를 이용해서 사용자 계정이 등록되었는지를 체크합니다.

$mim_user_id = $_SESSION['s_id'];

$sql = "SELECT * FROM ".USERS_TABLE." WHERE user_email='".$mim_user_id."' AND user_active = 1";

만약 존재한다면 위의 쿼리에서 나온 데이터를 이용해서 $userdata 를 반환하면 되고, 그렇지 않을 경우 새로운 사용자로 추가합니다. 이에 대한 코드는 다음과 같습니다. 위에서 설명한 것과 같이 if ($user_id != ANONYMOUS) 에 대한 else  {} 절로 추가합니다.

    if ($user_id != ANONYMOUS)
    {   
       ... getting user
    }
else
    {  // Make USERDATA from External Session Information
   
        $mim_user_name= $_SESSION['s_name'];
        $mim_user_id = $_SESSION['s_id'];
       
        if( !$mim_user_name || !mim_user_id)
        {
               
         
        }else{
         
         
          $sql = "SELECT * FROM ".USERS_TABLE." WHERE user_email='".$mim_user_id."' AND user_active = 1";
         
          if (!($result = $db->sql_query($sql)))
          {
            message_die(GENERAL_ERROR, 'Could not obtain user data associating with $mim_user_id information', '', __LINE__, __FILE__, $sql);
                   
          }
       
        if( $userdata = $db->sql_fetchrow($result) )
        {
           // nothing to do        
        }  else {
         
          $userdata = add_user_data_to_db($mim_user_name,$mim_user_id);
        }
        $db->sql_freeresult($result);
       
          $login=1;
         
        }
        
    }  // end of if user_id != anonymous


그리 어려운 부분은 아니지요? 소스 코드를 보면 원래 sessions.php 에는 없는 함수가 하나 등장합니다. 바로 add_user_data_to_db 인데요, 이것은 앞서 설명한 것과 같이 시스템 A의 사용자를 phpBB에 등록하기 위한 함수입니다.


4. sessions.php 수정하기 (3) - add_user_data_to_db()

add_user_data_to_db() 는 시스템 A의 사용자 계정을 이용해서 phpBB 사용자 계정을 만드는 과정으로, phpBB의 includes/usercp_register.php 의 코드를 상당 부분 차용했습니다.

사용자 계정 설정과 관련해서 더 많은 옵션을 부여할 수 있으나, 여기서는 단순히 id 를 공유하는 것이 목적이므로, 이러한 옵션에 대해서는 필요시 수정하시기 바랍니다. ^^

사용자가 추가될 때마다 phpbb_users , phpbb_groups, phpbb_user_group 의 세 테이블에 레코드가 하나씩 생기게 되며, 아래는 이를 구현한 내용입니다.

//
// for adding a new account from the external system account.
// - Shinnara
//
function add_user_data_to_db($s_name,$s_id)
{
     
      global $db;
     
      $sql = "SELECT MAX(user_id) AS total
                FROM " . USERS_TABLE;
               
           
            if ( !($result = $db->sql_query($sql)) )
            {
                message_die(GENERAL_ERROR, 'Could not obtain next user_id information', '', __LINE__, __FILE__, $sql);
            }

            if ( !($row = $db->sql_fetchrow($result)) )
            {
                message_die(GENERAL_ERROR, 'Could not obtain next user_id information', '', __LINE__, __FILE__, $sql);
            }
            $user_id = $row['total'] + 1;

           
            $sql = "INSERT INTO ". USERS_TABLE . " (user_id,username,user_password,user_regdate, user_email, user_active , user_level,user_posts,user_timezone,user_style,user_lang,user_dateformat,user_new_privmsg,user_unread_privmsg, ";
            $sql .= "user_last_privmsg,user_login_tries,user_viewemail,user_allow_viewonline,user_notify,user_notify_pm,user_popup_pm,user_rank,user_allowbbcode,user_allowsmile,user_allowavatar,";
            $sql .= "user_avatar_type,user_attachsig) ";
            $sql .= " VALUES ($user_id,'".str_replace("\'", "''", $s_name)."','nopassword',".time().",'$s_id',1,0,0,0.00,1,'english','D M d, Y g:i a',0,0,";
            $sql .= "0,0,0,1,0,1,1,0,1,1,1,";
            $sql .= "0,1)";
           
                       

            if ( !($result = $db->sql_query($sql, BEGIN_TRANSACTION)) )
            {
             
                message_die(GENERAL_ERROR, 'Could not insert data into users table', '', __LINE__, __FILE__, $sql);
            }

     
            $sql = "INSERT INTO " . GROUPS_TABLE . " (group_name, group_description, group_single_user, group_moderator)
                VALUES ('', 'Personal User', 1, 0)";
            if ( !($result = $db->sql_query($sql)) )
            {
             
                message_die(GENERAL_ERROR, 'Could not insert data into groups table', '', __LINE__, __FILE__, $sql);
            }
     
            $group_id = $db->sql_nextid();

            $sql = "INSERT INTO " . USER_GROUP_TABLE . " (user_id, group_id, user_pending)
                VALUES ($user_id, $group_id, 0)";
            if( !($result = $db->sql_query($sql, END_TRANSACTION)) )
            {
                message_die(GENERAL_ERROR, 'Could not insert data into user_group table', '', __LINE__, __FILE__, $sql);
            }
           
           
            // getting user data from db
           
             $sql = "SELECT * FROM ".USERS_TABLE." WHERE user_email='".$s_id."' AND user_active = 1";
            if ( !($result = $db->sql_query($sql)) )
            {
              message_die(GENERAL_ERROR, 'Could not obtain userdata information', '', __LINE__, __FILE__, $sql);
            }
           
            $userdata = $db->sql_fetchrow($result);
            $db->sql_freeresult($result);
       
            return $userdata;
}


이 부분 역시 , 그리 어려운 내용이 아닙니다. 많은 분들이 더 깔끔하게 고치시리라 믿습니다. 이것으로 phpBB를 기존의 시스템과 통합하기 위한 작업이 모두 끝났습니다.


5. 결론

phpBB를 기존 시스템의 사용자 정보를 이용하여 사용할 수 있는 쉬운 방법을 알아보았습니다. 제 환경에서 테스트해 본 결과 정상적으로 동작함을 확인할 수 있었습니다. 스킨등을 수정함으로써 보다 유기적으로 통합시킬 수 있으니, 이에 대한 부분은 여러분의 몫으로 남겨놓겠습니다.

위의 방법은 session_start() 를 사용함으로써 보안에 취약해 질 수 있는 문제점을 가지고 있습니다. session 과 관련된 내용은 사이트의 전반적인 보안 규정에 따라 적절히 보완해주시기 바랍니다.

감사합니다 .


관련소스:

1 Trackback, 0 Comment

TRACKBACK :: http://naratalk.com/trackback/213 관련글 쓰기

  1. Subject: phpBB Login Integration : Log out 처리하기

    Tracked from Talking with Shinnara :: NaraTalk.com  삭제

    지난 주인가요? phpBB 와 기존의 사이트(시스템 A)의 사용자 계정을 연동하여, 단일 로그인으로 처리하는 부분에 대한 글을 썼었습니다. 시스템 A의 로그인 정보를 이용하여 phpBB에 로그인하는 것은 잘 되는데, 만약 시스템 A에서 로그아웃을 하게 되면, phpBB 역시 로그아웃을 해주어야 합니다. 그렇지 않으면 시스템A에서는 로그 아웃이 된 상태인데, phpBB 페이지로 들어가면 해당 사용자가 로그인한 것으로 인식되는 문제가 발생하게됩니다. p..

    2007/11/15 14:23

댓글을 달아 주세요

phpBB 설치하기

Computer/Programming/FreeBSD 2007/11/06 14:01 by Shinnara
어제에 이어 또다시 게시판, 포럼관련 소프트웨어를 설치하는 이야기를 씁니다. 드루팔이 매우 훌륭한 소프트웨어임에는 틀림이 없지만 당장 프로젝트에 적용시키기에는 시간이 걸릴 것 같아, 다양한 솔루션을 찾아보고자 해서 다른 시도를 해봅니다.

이번에 선택한 툴은 phpBB .

리눅스 관련 문서 한글화 프로젝트로 유명한 KLDP 가 현재의 Drupal 을 쓰기 이전에 쓰고 있던 시스템입니다. 아직 자세한 내용은 모르는데 인지도가 꽤 있는 것 같습니다. 일단 설치를 해서 사용을 해봐야 어떤 시스템인지를 알 것 같습니다.


1. 다운 받아 압축 풀기

현재 3.0 RC7 이 있지만, 실제 서비스에 베타버전을 사용하기에는 무리가 있을 것 같아 2.0.22 의 Stable 버전을 사용하였습니다.

다운을 받아서 압축을 풉니다.

[shinnara /home/httpd/phpbb2]$ ls
admin/          docs/           index.php       posting.php     viewonline.php
cache/          extension.inc   install/        privmsg.php     viewtopic.php
common.php      faq.php         language/       profile.php
config.php      groupcp.php     login.php       search.php
contrib/        images/         memberlist.php  templates/
db/             includes/       modcp.php       viewforum.php
[shinnara /home/httpd/phpbb2]$






2. 데이터 베이스 세팅하기

데이터 베이스를 추가하는 부분은 어제의 Drupal 설치 포스팅을 참고하시기바랍니다.


3. 브라우저로 인스톨 페이지 보기

브라우저의 주소창에 압축화일을 풀어 놓은 경로를 입력합니다. 저는 웹서버의 Root 밑에 phpbb2 라는 디렉토리에 압축을 풀었기때문에 다음과 같이 입력합니다.

http://192.168.0.145/phpbb2

( 제가 설치한 머신의 아이피주소가 192.168.0.145 입니다 )

이어서 설치 화면이 나타나게 되며, 여기에 해당 정보를 입력합니다.
사용자 삽입 이미지

start Install 버튼을 누르면 해당 데이터 베이스에 테이블을 설치하는 등의 작업이 이루어집니다. 그리고 그 정보를 phpbb 의 루트 디렉토리에 config.php 로 저장을 하게 되는데 이때 퍼미션이 거부되면 웹 페이지에서 다운 받아서 업로드 할 수 있도록 링크를 제공합니다.


4. 설치 후 확인할 것들

설치를 한 후 install 디렉토리와 contrib 디렉토리를 지웁니다. 이는 혹시 있을지 모르는 보안 사고에 대비하기 위함입니다.



5. 관리자로 로그인 하기

Step 4 에서 두 디렉토리를 정상적으로 삭제해야만 로그인을 할 수 있습니다. 위에서 설정한 관리자 계정으로 로그인을 하게 되면 아래와 같은 페이지를 볼 수 있습니다.


사용자 삽입 이미지


테스트 포럼이 하나 만들어져있습니다.

아래쪽의 Go to Administration Panel 을 클릭해서 관리자 페이지로 들어갑니다.

이 때 한번 더 아이디와 패스워드를 확인합니다.

관리자 메뉴를 통해 다양한 내용을 설정할 수 있는데, 이와 관련된 내용은 다음번에 다루도록 하겠습니다.

phpBB 도 Drupal 처럼 설치 자체는 어려운 일이 아닙니다. 이제 환경에 맞게 설정하는 일만 남은 것 같습니다.

먼저 해야할 일이 다른 어플리케이션에서의 로그인 정보를 연동하는 것인데, 이에 대한 정보를 빨리 정리해서 올리도록 하겠습니다.








0 Trackback, 0 Comment

TRACKBACK :: http://naratalk.com/trackback/210 관련글 쓰기

댓글을 달아 주세요

1 
다...... (264)
Computer/Programming (106)
Links (14)
책 읽는 즐거움 (7)
끄적임 (66)
즐거운 과학 나라 (7)
일본 (5)
Study (4)