Содержание
Этот небольшой модуль (mod) позволяет вам настраивать права доступа зависящие не только от имени пользователя и группы, но и от того откуда этот пользователь подключается. Инструкции по установке, приведенные ниже, относятся к версии 2005-07-13 DokuWiki. Я буду стараться обновлять их для всех последующих версий, но «в идеале» я бы хотел увидеть эту функциональность вошедшей в основную систему.
Как это работает?
Работа модуля достаточно проста. Используйте ACL для того, чтобы добавить новое правило для отдельного IP или для целой сети. Привожу пример:
* %192.168.1.0/24 1 # Это правило дает любому клиенту из сети 192.168.1.0/255.255.255.0 право на чтение всего wiki. start %192.168.2.10 2 # Это правило дает клиенту с IP 192.168.2.10 право на редактирование домашней статьи.
В настоящий момент я не изменял существующую панель управления ACL для того, чтобы включить новый тип элементов, поэтому все эти правила добавляются точно также, как вы добавляете новых пользователей. Просто добавьте перед IP символ '%', выберите необходимые права доступа и разделы wiki. Все остальное работает точно также как и раньше.
Моя система ищет все элементы начинающиеся с % и пытается сравнить с ip-адресом, с которого подсоединился пользователь. Если элемент не содержит /xx на конце, то производиться точное сравнение с ip-адресом. Если на конце присутствует маска (как в примере выше), то будет сравниваться только часть ip-адреса, соответствующая маске. Таким образом элемент 192.168.1.0/30 позволит доступ 192.168.1.0, 192.168.1.1, 192.168.1.2 и 192.168.1.3, и никому больше. Более подробно о маске подсети написано в статье Subnetwork_mask.
Я все еще не слишком хорошо протестировал, но до сих пор все работало замечательно. Если вы обнаружите какие-либо проблемы с моим модулем, или у вас есть какие-либо советы, пожелания или потребности, можете написать мне по адресу max [at] mxserve [dot] net.
Install Instructions
The whole mod makes only 2 changes to inc/auth.php. Most of this code is actually a copy of the code that is used to check username and group access, I simply modified it to make it work with IPs.
- On line 307 (or somewhere around that), change this:
//we did this already //looks like there is something wrong with the ACL //break here return $perm;
to this:
//we did this already //looks like there is something wrong with the ACL //break here //return $perm; break;
- After this line (should be 310):
}while(1); //this should never loop endless
add the following code:
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // IP ACL Mod - Max Khitrov <max@mxserve.net> // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // First we get the IP of the client $user_ip = $_SERVER[REMOTE_ADDR]; // Take all ACL entries that begin with % and see if they can be matched to // the client's ip (exact match first, namespace second). $matches = preg_grep('/^'.$id.'\s+(%[0-9\.\/]+)\s+/',$AUTH_ACL); if(count($matches)){ foreach($matches as $match){ $match = preg_replace('/#.*$/','',$match); //ignore comments if ($match == '') continue; $acl = preg_split('/\s+/',$match); $acl[1] = substr($acl[1], 1, strlen($acl[1]) - 1); if (strpos($acl[1], '/') === false) { // This is an exact IP entry, see if it matches the user IP if ($user_ip == $acl[1]) $perm = $acl[2]; } else { // This is a network entry $ip = preg_split('/\//',$acl[1]); if ((ip2long($user_ip) & ~(pow(2, 32-$ip[1])-1)) == (ip2long($ip[0]) & ~(pow(2, 32-$ip[1])-1))) $perm = $acl[2]; } if($perm > -1){ //we had a match - return it return $perm; } } } $ns = getNS($id); if($ns){ $path = $ns.':\*'; }else{ $path = '\*'; //root document } do{ $matches = preg_grep('/^'.$path.'\s+(%[0-9\.\/]+)\s+/',$AUTH_ACL); if(count($matches)){ foreach($matches as $match){ $match = preg_replace('/#.*$/','',$match); //ignore comments if ($match == '') continue; $acl = preg_split('/\s+/',$match); if($acl[2] > AUTH_DELETE) $acl[2] = AUTH_DELETE; //no admins in the ACL! $acl[1] = substr($acl[1], 1, strlen($acl[1]) - 1); if (strpos($acl[1], '/') === false) { // This is an exact IP entry, see if it matches the user IP if ($user_ip == $acl[1]) if($acl[2] > $perm) $perm = $acl[2]; } else { // This is a network entry $ip = preg_split('/\//',$acl[1]); if ((ip2long($user_ip) & ~(pow(2, 32-$ip[1])-1)) == (ip2long($ip[0]) & ~(pow(2, 32-$ip[1])-1))) if($acl[2] > $perm) $perm = $acl[2]; } } //we had a match - return it return $perm; } //get next higher namespace $ns = getNS($ns); if($path != '\*'){ $path = $ns.':\*'; if($path == ':\*') $path = '\*'; }else{ //we did this already //looks like there is something wrong with the ACL //break here return $perm; } }while(1); //this should never loop endless // ~~~~~~~~~~~~~~ // END IP ACL Mod // ~~~~~~~~~~~~~~
Install Instructions for the 2006-03-09b release
In function auth_aclcheck, around line 321, immediately following the «do{» line, insert the code shown below.
It's slightly tricky to set up the permissions, because the main loop is trying to validate your identity (typically «@ALL») and your IP address at the same time. The upshot is that to get wiki-wide access you have to specify your IP-based permissions in acl.auth.php for every namespace, not just «*». Otherwise, if you have something like:
somenamespace:* @ALL 0
It will override something like:
* %192.168.1.1 1 # This IP gets read access to the whole wiki
That means you won't get read access in «somenamespace», even if you're at IP 192.168.1.1.
Here's the code to insert after the «do{».
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // IP ACL Mod - Max Khitrov <max@mxserve.net> // Modified by Scott Gilbertson to work with a newer DokuWiki version // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // First we get the IP of the client $user_ip = $_SERVER[REMOTE_ADDR]; // Take all ACL entries that begin with % and see if they can be matched to // the client's ip (exact match first, namespace second). $matches = preg_grep('/^'.$path.'\s+(%[0-9\.\/]+)\s+/',$AUTH_ACL); if(count($matches)){ foreach($matches as $match){ $match = preg_replace('/#.*$/','',$match); //ignore comments if ($match == '') continue; $acl = preg_split('/\s+/',$match); $acl[1] = substr($acl[1], 1, strlen($acl[1]) - 1); if (strpos($acl[1], '/') === false) { // This is an exact IP entry, see if it matches the user IP if ($user_ip == $acl[1]) { $perm = $acl[2]; } } else { // This is a network entry $ip = preg_split('/\//',$acl[1]); if ((ip2long($user_ip) & ~(pow(2, 32-$ip[1])-1)) == (ip2long($ip[0]) & ~(pow(2, 32-$ip[1])-1))) { $perm = $acl[2]; } } if($perm > -1){ //we had a match - return it return $perm; } } } $matches = preg_grep('/^'.$path.'\s+(%[0-9\.\/]+)\s+/',$AUTH_ACL); if(count($matches)){ foreach($matches as $match){ $match = preg_replace('/#.*$/','',$match); //ignore comments if ($match == '') continue; $acl = preg_split('/\s+/',$match); if($acl[2] > AUTH_DELETE) $acl[2] = AUTH_DELETE; //no admins in the ACL! $acl[1] = substr($acl[1], 1, strlen($acl[1]) - 1); if (strpos($acl[1], '/') === false) { // This is an exact IP entry, see if it matches the user IP if ($user_ip == $acl[1]) if($acl[2] > $perm) $perm = $acl[2]; } else { // This is a network entry $ip = preg_split('/\//',$acl[1]); if ((ip2long($user_ip) & ~(pow(2, 32-$ip[1])-1)) == (ip2long($ip[0]) & ~(pow(2,32-$ip[1])-1))) if($acl[2] > $perm) $perm = $acl[2]; } } //we had a match - return it //return $perm; } // ~~~~~~~~~~~~~~ // END IP ACL Mod // ~~~~~~~~~~~~~~
Another (simpler) approach
If you don't need netmask support, but you can live with simpler class-network granularity, this approach might work for you. Here, every user automatically is member of four additional groups, based on his IP address. If he accesses for example from IP 123.45.67.89
, he is by default member of following groups as well:
ip:123
ip:123.45
ip:123.45.67
ip:123.45.67.89
This means, if you want to give rights (only) to users from Apple, you would use the ACL Plugin to set the rights for the group «ip:17
To patch the 2007-06-26 version of dokuwiki, replace the lines 363-372 of inc/auth.php
with the following code:
// --- patch to allow IP-Based access rights (replaces original lines 363-372) ---- //add ALL group $groups[] = '@ALL'; //add IP-based groups: $ip = explode('.',$_SERVER["REMOTE_ADDR"]); $groups[] = '@ip%3a' . $ip[0] . '%2e' . $ip[1] . '%2e' . $ip[2] . '%2e' . $ip[3]; # Full Address $groups[] = '@ip%3a' . $ip[0] . '%2e' . $ip[1] . '%2e' . $ip[2]; # Class C $groups[] = '@ip%3a' . $ip[0] . '%2e' . $ip[1]; # Class B $groups[] = '@ip%3a' . $ip[0]; # Class A if ($user){ //add User $groups[] = $user; } //build regexp $regexp = join('|',$groups); // --- End of Patch ----
Please mail emarks, suggestions etc. to bihler [at] iai [dot] uni [dash] bonn [dot] de.