../

任意のページごとの閲覧・編集制限 -- Ynak

※旧「BASIC認証で任意のページごとに閲覧制限や編集制限をかける方法」。名前が長すぎなので修正しました。--Ynak

やりたいこと

任意のページごとに閲覧制限や編集制限をかけたい。*1

具体的には

  1. ××ページは全員が閲覧できるが、内容を編集できるのは○○だけ。
  2. △△ページは□□だけが閲覧・編集できる。
  3. ○△ページは□□だけが閲覧できるが、編集は○○だけ。

というようなことをやりたい。

現状

  • 他のWikiEnginesでは、実装されているものもある。
  • PukiWiki1.3.xでは、実装されていない。
  • かろうじて使用できるのがページ内容の凍結であるが、PukiWiki全体で1つのパスワード設定しかできないので、運用面で困る。

方針

PukiWiki/1.4/BasicAuthで紹介されている方法をそのまま使えば、全ページに対する編集権限を設定できる。

更に、コメント部で紹介された方法*2を使用すれば、正規表現で定義されたページ名に対する編集権限を1セット設定できる。

しかし、最終目標には少々足りていないので、更なる改造が必要。

仕様

pukiwiki.ini.phpで

ユーザIDパスワード
正規表現によるページ名のパターン閲覧できるユーザID(カンマ区切り)
正規表現によるページ名のパターン編集できるユーザID(カンマ区切り)

を定義することで、ちょっとUNIXライクな読み書き*3権限の設定ができる。

改造方法*4

PukiWiki1.3.4をベースに改造する方法は以下の通り。

ja.lng

以下を追加する。

$_msg_auth = 'PukiWikiAuth';
$_title_cannotread = '$1 は閲覧できません';

en.lng

以下を追加する。

$_msg_auth = 'PukiWikiAuth';
$_title_cannotread = '$1 is not readable';

func.php

以下を追加する。

/////////////////////////////////////////////////////////////////
// Basic認証による権限チェック
function edit_auth() {
     global $get, $_title_cannotedit;
     global $edit_auth, $auth_users, $_msg_auth;
     global $vars, $edit_auth_pages;
 
    // 編集認証フラグをチェック (システム全体として編集認証するかどうか)
     if (!$edit_auth) {
         return;
     }

     // 認証が必要なページかどうかをチェック
     $edit_auth_users = "";
     while (list($key, $val) = each($edit_auth_pages)) {
         if (preg_match($key, $vars['page'])) {
             $edit_auth_users = $val;
            break;
        }
     }
     if ($edit_auth_users == "") {
         return;
     }

//  
    // 認証を行う
    if ((!isset($_SERVER['PHP_AUTH_USER']) or
        !preg_match("/".$_SERVER['PHP_AUTH_USER']."/", $edit_auth_users) or
         !array_key_exists($_SERVER['PHP_AUTH_USER'], $auth_users) or
         $auth_users[$_SERVER['PHP_AUTH_USER']] != $_SERVER['PHP_AUTH_PW']))
     {
         header('WWW-Authenticate: Basic realm="'.$_msg_auth.'"');
         header('HTTP/1.0 401 Unauthorized');
         // press cancel.
         $body = $title = str_replace('$1', htmlspecialchars(strip_bracket($get['page'])), $_title_cannotedit);
         $page = str_replace('$1',make_search($get['page']),$_title_cannotedit);
         catbody($title, $page, $body);
         exit;
     }
 }

function read_auth() {
     global $get, $_title_cannotread;
     global $read_auth, $auth_users, $_msg_auth;
     global $vars, $read_auth_pages;
 
    // 閲覧認証フラグをチェック (システム全体として編集認証するかどうか)
     if (!$read_auth) {
         return;
     }

     // 認証が必要なページかどうかをチェック
     $read_auth_users = "";
     while (list($key, $val) = each($read_auth_pages)) {
         if (preg_match($key, $vars['page'])) {
             $read_auth_users = $val;
            break;
        }
     }
     if ($read_auth_users == "") {
         return;
     }

    // 認証を行う
    if ((!isset($_SERVER['PHP_AUTH_USER']) or
        !preg_match("/".$_SERVER['PHP_AUTH_USER']."/", $read_auth_users) or
         !array_key_exists($_SERVER['PHP_AUTH_USER'], $auth_users) or
         $auth_users[$_SERVER['PHP_AUTH_USER']] != $_SERVER['PHP_AUTH_PW']))
     {
         header('WWW-Authenticate: Basic realm="'.$_msg_auth.'"');
         header('HTTP/1.0 401 Unauthorized');
         // press cancel.
         $body = $title = str_replace('$1', htmlspecialchars(strip_bracket($get['page'])), $_title_cannotread);
         $page = str_replace('$1',make_search($get['page']),$_title_cannotread);
         catbody($title, $page, $body);
         exit;
     }
}

pukiwiki.php

編集制限が必要な追加・編集・プレビュー等の箇所に

edit_auth();

を、閲覧制限が必要な表示関係の箇所に

read_auth();

を挿入する。

  • 103行付近
       // 追加
       else if(arg_check("add"))
       {
           edit_auth(); // ★これを挿入!
  • 113行付近
       // 編集
       else if(arg_check("edit"))
       {
           edit_auth(); // ★これを挿入!
  • 124行付近
       // プレビュー
       else if(arg_check("preview") || $post["preview"] || $post["template"])
       {
           edit_auth(); // ★これを挿入!
  • 195行付近
       // 書き込みもしくは追加もしくはコメントの挿入
       else if($post["write"])
       {
           edit_auth(); // ★これを挿入!
  • 384行付近
       // 差分の表示
       else if(arg_check("diff"))
       {
           read_auth(); // ★これを挿入!
  • 462行付近
       // バックアップ
       else if($do_backup && arg_check("backup"))
       {
           read_auth(); // ★これを挿入!
  • 629行付近
           // WikiName、BracketNameが示すページを表示
           if(is_page($get["page"]))
           {
               read_auth(); // ★これを挿入!
  • 641行付近
           else if(preg_match("/($InterWikiName)/",$get["page"],$match))
           {
               read_auth(); // ★これを挿入!
  • 722行付近
           if(preg_match("/^(($BracketName)|($WikiName))$/",$get["page"])) {
               edit_auth(); // ★これを挿入!
  • 736行付近
       // 何も指定されない場合、トップページを表示
       else
       {
           read_auth(); // ★これを挿入!

pukiwiki.ini.php

以下のように設定を追加する。

下記は設定例のため、設定内容は適切に変更すること。

//////////////////////////////////////////////////
// 閲覧・編集制限の設定
// 認証のアカウント
// ユーザ名とパスワードを記入。
$auth_users = array(
 'foo' => 'foo_passwd',
 'bar' => 'bar_passwd',
 'hoge' => 'hoge_passwd',
);

// 編集時に認証が必要か
$edit_auth = 1;
 
// 編集認証をかけるページ名のパターンを正規表現で設定する。
// マッチしたページに編集認証をかける。
// カンマ区切りで複数ユーザを書いても良い。
$edit_auth_pages = array(
 '/Barの公開日記/' => 'bar',
 '/ひきこもるほげ/' => 'hoge',
 '/(ネタバレ|ねたばれ)/' => 'foo',
);

// 閲覧時に認証が必要か
$read_auth = 1;
 
// 閲覧認証をかけるページ名のパターンを正規表現で設定する。
// マッチしたページに編集認証をかける。
// カンマ区切りで複数ユーザを書いても良い。
$read_auth_pages = array(
 '/ひきこもるほげ/' => 'hoge',
 '/(ネタバレ|ねたばれ)/' => 'foo,bar,hoge',
);

上の例では

  • 「Barの公開日記」は、誰でも閲覧できて、barだけが編集できる。
  • 「ひきこもるほげ」ページは、hogeだけが閲覧・編集できる。
  • 「映画紹介~ネタバレ注意」ページは、foo, bar, hogeの三人だけが閲覧できて、かつ、編集はfooだけが可能。 のような設定となる。

かなり強引にUNIXっぽく表現すると、こうなる。

アクセス権   ユーザID   グループ   ページ名
-rw----r--   bar        なし       Barの公開日記
-rw-------   hoge       なし       HogeOnly
-rw-r-----   foo        hoges      映画紹介~ネタバレ注意

※グループhogesには、barとhogeが所属するとする。

注意点

  • 初めてPHPをさわった人間が改造しているので、実装的に問題があるかも。
    • 添削希望。
  • 閲覧認証をかけたページは、編集認証も必須。
    • でないと、「編集」リンクから内容が読めてしまったり、挙動が怪しくなったりする。*5
    • 編集可能ユーザは、閲覧可能ユーザのサブセットとなるように設定すること。
  • edit_auth_pagesなどのvalue部分と、BASIC認証のユーザ名の比較をpreg_matchで行っているので、あるユーザIDのサブセットとなるようなユーザIDがあるとややこしくなる。
    • 例えば、'hogefoobar'というユーザIDがあって、このユーザだけが編集できるようなページを以下のように設定する状況を考える。
      $edit_auth_pages = array(
       '/Secret/' => 'hogefoobar',
      );
    • ここでもし、'hoge'、'foo'、'bar'というユーザIDが存在していれば、そのいずれかのユーザIDでBASIC認証を突破すれば、このSecretページにアクセスできてしまう。
    • とりあえず、pukiwiki.ini.phpにユーザID設定をする人が気を付ければ良いので、気にしていませんが、良い回避法があれば修正してください。

コメント

  • うおお、 おみごと。ページ単位の認証ってニーズ高いですもんね。 -- yateeight? 2003-05-17 (土) 17:10:37
  • 実は、オートリンクとNoBracketNameが素敵なので1.4に乗り換えようとしてます。で、1.4も同じように改造しようとしてますが、1.3.4とだいぶ作りが違うので難儀してるところです。 -- Ynak 2003-05-17 (土) 20:30:32
  • おっと、includeプラグインで無権限者による閲覧ができる穴発見。 -- Ynak 2003-05-17 (土) 21:10:03
  • 他にもcalendar_viewerとかその手のプラグインで続々抜け穴を発見。プラグインを無効にするか、プラグインの頭のところでread_auth()を呼ぶようにしないとだめっぽいです。 -- Ynak 2003-05-17 (土) 21:23:11
  • 編集系プラグインはあまりないですが、閲覧系プラグインは結構あるので対処も大変ですね・・・。 -- Ynak 2003-05-17 (土) 21:24:26
  • 暫定対処として、include,calendar_read,calendar_editは使わないのではずして、calendar_viewerは改造して第1引数を無効にしてみました。 -- Ynak 2003-05-17 (土) 23:15:53
  • ページ単位じゃなくって、全体(どのページも)に認証かけるのはどうすればよろしいのでしょうか?「新規」も制限かけたいのですが。 -- Naox? 2003-05-18 (日) 09:12:37
  • Wikino -- Naox? 2003-05-18 (日) 09:13:42
  • 全ページに均一に認証をかけるのであれば、ページ名を"/.*/"とかにするとか、PukiWiki/1.4/BasicAuthのそのままの方法でやるとかが良いと思います。 -- Ynak 2003-05-18 (日) 12:00:09
  • あと、ここの改造方法では、新規ページ作成も制限対象に含まれています。 -- Ynak 2003-05-18 (日) 12:02:16
  • ./wiki/なディレクトリを、Webで公開しているディレクトリであれば、その文書ファイル名を直接指定したら読めませんか?ということで、そういう場合の読者の無意味さがあるので、注意書きでも追加しないとねぇ。ということが1点。ページ単位での制御を行う上で、ページを追加時に、この php に定義を追加していくことの運用の手間というところを、なんとかすると、もっとよくなると思います。の2点。で、config じゃないですけど、とあるページで制御しつつ、そのページに制限を行う。の組み合わせはどうかなぁ?と。 -- upk 2003-05-18 (日) 16:05:06
  • 確かに普通にインストールすると./wiki/配下のファイルは直接指定可能なんですね。というわけで対策を考えてみました。結果としては、wikiディレクトリに.htaccessでApacheによるBASIC認証をかける、で直接参照を防御できました。 -- Ynak 2003-05-22 (木) 19:20:45
  • pconfigの導入ですが、確かに便利そうなのですが、ユーザのパスワードなどの情報はさすがにページ上で管理するのは気が引けますね・・・。でも、制限対象ページ名のパターンとかアクセス可能ユーザの対応であれば、pconfigを使ってWikiページ上で設定するのもありですね。余力があれば考えてみます。 -- Ynak 2003-05-22 (木) 19:28:17
  • こういう機能かなり前から欲しかったです。できれば1.4に取り込んで欲しい位です。 -- 2003-06-05 (木) 20:46:09
  • ユーザ管理プログラムと管理ファイルだけ別物にしてもいいかもしれませんね。/etc/passwdみたいにユーザ名、グループ名などを「:」で区切ったファイルpasswd.phpみたいな。 -- 2003-06-05 (木) 20:47:29

*1 Wikiの思想に逆行するのは重々承知の上です。
*2 多少修正が必要であるが。
*3 関係ないけど、送りがなを詰めると読書になるって知ってた?
*4 diff形式じゃなくてすみません。
*5 UNIXでも、rw-(閲覧認証&編集認証の同時設定)はOKだけど、 -w-(編集認証のみ)はいろいろと問題が発生するのと似てる。

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2008-12-02 (火) 18:24:23
Site admin: PukiWiki Development Team

PukiWiki 1.5.2+ © 2001-2019 PukiWiki Development Team. Powered by PHP 5.6.40-0+deb8u7. HTML convert time: 0.283 sec.

OSDN