- 追加された行はこの色です。
- 削除された行はこの色です。
[[../]]
*任意のページごとの閲覧・編集制限 -- [[Ynak]] [#v9339fac]
※旧「BASIC認証で任意のページごとに閲覧制限や編集制限をかける方法~1.4対応版」。名前が長すぎたので修正しました。--[[Ynak]]
#contents
**やりたいこと [#n42484d9]
任意のページごとに閲覧制限や編集制限をかけたい。
具体的には
+××ページは全員が閲覧できるが、内容を編集できるのは○○だけ。
+△△ページは□□だけが閲覧・編集できる。
+○△ページは○○と□□が閲覧できるが、編集は○○だけ。
というようなことをやりたい。
**現状 [#adb35022]
-PukiWiki1.3.4では、[[../任意のページごとの閲覧・編集制限]]の改造により対応した。
-PukiWiki1.4rc2では、[[PukiWiki/1.4/BasicAuth]]で紹介された方法が実装されているが、最終目標には足りない。
**方針 [#q932cfc2]
PukiWiki1.3.4と同様の方法で実装する。
**仕様 [#k68a7826]
pukiwiki.ini.phpで
|ユーザID|パスワード|
|正規表現によるページ名のパターン|閲覧できるユーザID(カンマ区切り)|
|正規表現によるページ名のパターン|編集できるユーザID(カンマ区切り)|
を定義することで、ちょっとUNIXライクな読み書き権限の設定ができる。
更に、1.4対応版では以下に対応した。
-単語検索で、閲覧制限のかかったページ内容を検索対象にする・しないを選択できる。
--現在ログイン中のユーザに閲覧許可されたページの内容は検索対象となり、許可されないページの内容は無視される。
--ページ名は閲覧制限の対象外であるため、常に検索対象となる。
-includeプラグインで、閲覧制限のかかったページのincludeを行った場合は、現在ログイン中のユーザに閲覧許可されたページはincludeされ、許可されないページの内容はincludeされない。
-calendar_viewerプラグインで、(以下同文)。
**改造方法((diff形式じゃなくてすみません。)) [#z09a482c]
PukiWiki1.4rc2をベースに改造する方法は以下の通り。
***ja.lng [#zc8f5ab3]
以下を追加する。
$_msg_auth = 'PukiWikiAuth';
$_title_cannotread = '$1 は閲覧できません';
***en.lng [#l587107a]
以下を追加する。
$_msg_auth = 'PukiWikiAuth';
$_title_cannotread = '$1 is not readable';
***func.php [#s255aec7]
以下をコメントアウトする。
-111行付近 edit_auth
//// 編集時の認証 ★まるごとコメントアウト
//function edit_auth($page)
//{
// global $edit_auth,$edit_auth_users,$_msg_auth,$_title_cannotedit;
//
// if ($edit_auth and
// (!isset($_SERVER['PHP_AUTH_USER']) or
// !array_key_exists($_SERVER['PHP_AUTH_USER'],$edit_auth_users) or
// $edit_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($page)),$_title_cannotedit);
// $page = str_replace('$1',make_search($page),$_title_cannotedit);
//
// catbody($title,$page,$body);
// exit;
// }
//}
以下のように修正する。
-86行付近 check_editable
// ★まんべんなく変更してるのでまるごと置換した方がよいかも。
// 編集不可能なページを編集しようとしたとき
function check_editable($page, $auth_flag, $exit_flag)
{
global $script,$_title_cannotedit,$_msg_unfreeze;
if (edit_auth($page, $auth_flag) and is_editable($page))
{
return true;
}
if ($exit_flag) {
$body = $title = str_replace('$1',htmlspecialchars(strip_bracket($page)),$_title_cannotedit);
if(is_freeze($page))
{
$body .= "(<a href=\"$script?cmd=unfreeze&page=".
rawurlencode($page)."\">$_msg_unfreeze</a>)";
}
// Modified by Ynak -- fix bugs
$page = str_replace('$1',make_search($page),$_title_cannotedit);
catbody($title,$page,$body);
exit;
}
return false;
}
-167行付近
// 検索
function do_search($word,$type='AND',$non_format=FALSE)
{
global $script,$vars,$whatsnew,$non_list,$search_non_list;
global $_msg_andresult,$_msg_orresult,$_msg_notfoundresult;
global $search_auth; // ★これを追加
$database = array();
$retval = array();
$b_type = ($type == 'AND'); // AND:TRUE OR:FALSE
$keys = preg_split('/\s+/',preg_quote($word,'/'),-1,PREG_SPLIT_NO_EMPTY);
$_pages = get_existpages();
$pages = array();
foreach ($_pages as $page)
{
if ($page == $whatsnew
or (!$search_non_list and preg_match("/$non_list/",$page)))
{
continue;
}
// ★このif~else文を追加
// 検索対象ページの制限をかけるかどうか (ページ名は制限外)
if ($search_auth and !check_readable($page,false,false)) {
$source = get_source(); // 検索対象ページ内容を空に。
} else {
$source = get_source($page);
}
if (!$non_format)
{
array_unshift($source,$page); // ページ名も検索対象に
}
以下をまるごと追加する。
-一番最後とか
// 編集認証
// 第2,第3引数を変更する用途は今のところないが、閲覧との対象性を持たせた。
function edit_auth($page, $auth_flag) {
global $_title_cannotedit,$edit_auth,$auth_users,$_msg_auth,$edit_auth_pages;
// 編集認証フラグをチェック (システム全体として編集認証するかどうか)
if (!$edit_auth) {
return true;
}
// 認証が必要なページかどうかをチェック
$edit_auth_users = "";
reset($edit_auth_pages);
while (list($key, $val) = each($edit_auth_pages)) {
if (preg_match($key, $page)) {
$edit_auth_users = $val;
break;
}
}
if ($edit_auth_users == "") {
return true;
}
// 認証を行う
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']))
{
if ($auth_flag) {
header('WWW-Authenticate: Basic realm="'.$_msg_auth.'"');
header('HTTP/1.0 401 Unauthorized');
}
return false;
}
return true;
}
// 閲覧不可能なページを閲覧しようとしたとき (?)
// ※あまり必要性を感じないが、editの場合と対称性を持たせるために導入。
function check_readable($page, $auth_flag, $exit_flag) {
global $_title_cannotread;
if (read_auth($page, $auth_flag)) {
return true;
}
if ($exit_flag) {
$body = $title = str_replace('$1',htmlspecialchars(strip_bracket($page)), $_title_cannotread);
$page = str_replace('$1',make_search($page),$_title_cannotread);
catbody($title, $page, $body);
exit;
}
return false;
}
// 閲覧認証
function read_auth($page, $auth_flag) {
global $read_auth,$auth_users,$_msg_auth,$read_auth_pages;
// 閲覧認証フラグをチェック
if (!$read_auth) {
return true;
}
// 認証が必要なページかどうかをチェック
$read_auth_users = "";
reset($read_auth_pages);
while (list($key, $val) = each($read_auth_pages)) {
if (preg_match($key, $page)) {
$read_auth_users = $val;
break;
}
}
if ($read_auth_users == "") {
return true;
}
// 現在のログイン状態で認証チェック
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']))
{
if ($auth_flag) {
header('WWW-Authenticate: Basic realm="'.$_msg_auth.'"');
header('HTTP/1.0 401 Unauthorized');
}
return false;
}
return true;
}
***plugin/read.ini.php [#j9ecdfd0]
以下のように修正する。
-13行付近
// WikiName、BracketNameが示すページを表示
if (is_page($get['page'])) {
check_readable($get['page'],true,true); // ★これを追加
***plugin/edit.ini.php [#p47b1f5d]
以下のように修正する。
-13行付近
// check_editable($vars['page']); // ★コメントアウト
check_editable($vars['page'], true, true); // ★追加
***plugin/diff.ini.php [#x32cfbaa]
以下のように修正する。
-11行付近
global $_msg_notfound,$_msg_goto,$_msg_addline,$_msg_delline,$_title_diff;
check_readable($get['page'],true,true); // ★追加
***plugin/backup.ini.php [#lf545e64]
以下のように修正する。
-16行付近
if (!$do_backup) { return; }
check_readable($get['page'], true, true); // ★追加
***plugin/calendar_viewer.ini.php [#bf9dc5ab]
以下のように修正する。
-180行付近
$vars["page"] = $page;
// ★このif~else文を追加
// 現状で閲覧許可がある場合だけ表示する
if (check_readable($page,false,false)) {
$body = convert_html(get_source($page));
} else {
$body = $page." は閲覧制限がかかっているためcalendar_viewerによる参照はできません";
}
$r_page = rawurlencode($page);
***plugin/include.ini.php [#f2431a83]
以下のように修正する。
-37行付近
$_page = $vars['page'];
$get['page'] = $post['page'] = $vars['page'] = $page;
// $body = convert_html(get_source($page)); // ★これをコメントアウトして
// ★この下のif~elseを追加する
// includeのときは、認証画面をいちいち出さず、後始末もこちらでつける
if (check_readable($page, false, false)) {
$body = convert_html(get_source($page));
} else {
$body = $page." は閲覧制限がかかっているためincludeできません";
}
***plugin/そのほか [#n2b34772]
-calendar_edit.ini.php
-calendar_read.ini.php
無効化するのが望ましい?((よくわからなかったので自信なし。))
***pukiwiki.ini.php [#ta903a47]
以下のように設定を追加する。
下記は設定例のため、設定内容は適切に変更すること。
//////////////////////////////////////////////////
// 閲覧・編集制限の設定
// 認証のアカウント
// ユーザ名とパスワードを記入。
$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',
);
// 検索時に認証が必要か
// 0: 閲覧が許可されていないページ内容も検索対象とする
// 1: 検索時のログインユーザに許可されたページのみ検索対象とする
// ※どちらの場合も、ページ名は公開情報なので検索対象となる。
$search_auth = 0;
上の例では
-「Barの公開日記」は、誰でも閲覧できて、barだけが編集できる。
-「ひきこもるほげ」ページは、hogeだけが閲覧・編集できる。
-「映画紹介~ネタバレ注意」ページは、foo, bar, hogeの三人だけが閲覧できて、かつ、編集はfooだけが可能。
のような設定となる。
かなり強引にUNIXっぽく表現すると、こうなる。
アクセス権 ユーザID グループ ページ名
-rw----r-- bar なし Barの公開日記
-rw------- hoge なし HogeOnly
-rw-r----- foo hoges 映画紹介~ネタバレ注意
※グループhogesには、barとhogeが所属するとする。
**注意点 [#s0de784b]
-PHPをさわったばかり人間が改造しているので、実装的に問題があるかも。
--添削希望。
-閲覧認証をかけたページは、編集認証も必須。
--でないと、「編集」リンクから内容が読めてしまったり、挙動が怪しくなったりする。((UNIXでも、rw-(閲覧認証&編集認証の同時設定)はOKだけど、 -w-(編集認証のみ)はいろいろと問題が発生するのと似てる。))
--編集可能ユーザは、閲覧可能ユーザのサブセットとなるように設定すること。
-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設定をする人が気を付ければ良いので、気にしていませんが、良い回避法があれば修正してください。
*コメント [#r335f6c6]
-できるだけ1.4の設計思想(?)を優先して、きれいにまとめてみたつもりです。 -- [[Ynak]] &new{2003-05-20 (火) 23:28:16};
-pcommentもセキュリティホールになりますね。改造しないと。 -- [[Ynak]] &new{2003-05-22 (木) 00:09:00};
-あと、メイン機能系では添付ファイルのアクセス制限に未対応ですが、これをやるのはかなりの大工事になりそうですね。ページごとにサブディレクトリを作って、とかやればいいのかな? -- [[Ynak]] &new{2003-05-22 (木) 00:10:39};
#comment