summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--_test/cases/inc/auth_nameencode.test.php28
-rw-r--r--conf/acl.auth.php.dist9
-rw-r--r--inc/auth.php23
-rw-r--r--inc/auth/plain.class.php2
-rw-r--r--lib/plugins/acl/admin.php171
5 files changed, 145 insertions, 88 deletions
diff --git a/_test/cases/inc/auth_nameencode.test.php b/_test/cases/inc/auth_nameencode.test.php
new file mode 100644
index 000000000..6deb7de9f
--- /dev/null
+++ b/_test/cases/inc/auth_nameencode.test.php
@@ -0,0 +1,28 @@
+<?php
+
+require_once DOKU_INC.'inc/init.php';
+require_once DOKU_INC.'inc/auth.php';
+
+class auth_nameencode_test extends UnitTestCase {
+
+ function test_simple(){
+ $in = 'hey$you';
+ $out = 'hey%24you';
+ $this->assertEqual(auth_nameencode($in),$out);
+ }
+
+ function test_complex(){
+ $in = 'hey $ you !$%! foo ';
+ $out = 'hey%20%24%20you%20%21%24%25%21%20foo%20';
+ $this->assertEqual(auth_nameencode($in),$out);
+ }
+
+ function test_complexutf8(){
+ $in = 'häü $ yü !$%! foo ';
+ $out = 'häü%20%24%20yü%20%21%24%25%21%20foo%20';
+ $this->assertEqual(auth_nameencode($in),$out);
+ }
+
+}
+
+//Setup VIM: ex: et ts=4 enc=utf-8 :
diff --git a/conf/acl.auth.php.dist b/conf/acl.auth.php.dist
index 3b0745648..3fa9741c5 100644
--- a/conf/acl.auth.php.dist
+++ b/conf/acl.auth.php.dist
@@ -2,7 +2,14 @@
# <?php exit()?>
# Don't modify the lines above
#
-# Access Control
+# Access Control Lists
+#
+# Editing this file by hand shouldn't be necessary. Use the ACL
+# Manager interface instead.
+#
+# If your auth backend allows special char like spaces in groups
+# or user names you need to urlencode them (only chars <128, leave
+# UTF-8 multibyte chars as is)
#
# none 0
# read 1
diff --git a/inc/auth.php b/inc/auth.php
index 6280cf1c1..79cae52e7 100644
--- a/inc/auth.php
+++ b/inc/auth.php
@@ -264,16 +264,18 @@ function auth_aclcheck($id,$user,$groups){
# if no ACL is used always return upload rights
if(!$conf['useacl']) return AUTH_UPLOAD;
+ $user = auth_nameencode($user);
+
//if user is superuser return 255 (acl_admin)
if($conf['superuser'] == $user) { return AUTH_ADMIN; }
//make sure groups is an array
if(!is_array($groups)) $groups = array();
- //prepend groups with @
+ //prepend groups with @ and nameencode
$cnt = count($groups);
for($i=0; $i<$cnt; $i++){
- $groups[$i] = '@'.$groups[$i];
+ $groups[$i] = '@'.auth_nameencode($groups[$i]);
}
//if user is in superuser group return 255 (acl_admin)
if(in_array($conf['superuser'], $groups)) { return AUTH_ADMIN; }
@@ -351,6 +353,23 @@ function auth_aclcheck($id,$user,$groups){
}
/**
+ * Encode ASCII special chars
+ *
+ * Some auth backends allow special chars in their user and groupnames
+ * The special chars are encoded with this function. Only ASCII chars
+ * are encoded UTF-8 multibyte are left as is (different from usual
+ * urlencoding!).
+ *
+ * Decoding can be done with rawurldecode
+ *
+ * @author Andreas Gohr <gohr@cosmocode.de>
+ * @see rawurldecode()
+ */
+function auth_nameencode($name){
+ return preg_replace('/([\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f])/e',"'%'.dechex(ord('\\1'))",$name);
+}
+
+/**
* Create a pronouncable password
*
* @author Andreas Gohr <andi@splitbrain.org>
diff --git a/inc/auth/plain.class.php b/inc/auth/plain.class.php
index 3ed014262..d3df1c0dd 100644
--- a/inc/auth/plain.class.php
+++ b/inc/auth/plain.class.php
@@ -15,6 +15,8 @@ define('AUTH_USERFILE',DOKU_CONF.'users.auth.php');
// we only accept page ids for auth_plain
if(isset($_REQUEST['u']))
$_REQUEST['u'] = cleanID($_REQUEST['u']);
+if(isset($_REQUEST['acl_user']))
+ $_REQUEST['acl_user'] = cleanID($_REQUEST['acl_user']);
class auth_plain extends auth_basic {
diff --git a/lib/plugins/acl/admin.php b/lib/plugins/acl/admin.php
index 5dc62edab..7295141cd 100644
--- a/lib/plugins/acl/admin.php
+++ b/lib/plugins/acl/admin.php
@@ -8,7 +8,7 @@
if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once(DOKU_PLUGIN.'admin.php');
-
+
/**
* All DokuWiki plugins to extend the admin function
* need to inherit from this class
@@ -16,12 +16,12 @@ require_once(DOKU_PLUGIN.'admin.php');
class admin_plugin_acl extends DokuWiki_Admin_Plugin {
- function admin_plugin_acl(){
- $this->setupLocale();
- }
+ function admin_plugin_acl(){
+ $this->setupLocale();
+ }
+
-
/**
* return some info
*/
@@ -35,33 +35,33 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
'url' => 'http://wiki.splitbrain.org/wiki:acl',
);
}
-
+
/**
* return prompt for admin menu
*/
function getMenuText($language) {
return $this->lang['admin_acl'];
}
-
+
/**
* return sort order for position in admin menu
*/
function getMenuSort() {
return 1;
}
-
+
/**
* handle user request
*/
function handle() {
global $AUTH_ACL;
-
+
$cmd = $_REQUEST['acl_cmd'];
$scope = $_REQUEST['acl_scope'];
$type = $_REQUEST['acl_type'];
$user = $_REQUEST['acl_user'];
$perm = $_REQUEST['acl_perm'];
-
+
if(is_array($perm)){
//use the maximum
sort($perm);
@@ -69,30 +69,30 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
}else{
$perm = 0;
}
-
+
//sanitize
- $user = cleanID($user);
+ $user = auth_nameencode($user);
if($type == '@') $user = '@'.$user;
if($user == '@all') $user = '@ALL'; //special group! (now case insensitive)
$perm = (int) $perm;
if($perm > AUTH_DELETE) $perm = AUTH_DELETE;
//FIXME sanitize scope!!!
-
+
//nothing to do?
if(empty($cmd) || empty($scope) || empty($user)) return;
-
-
+
+
if($cmd == 'save'){
$this->admin_acl_del($scope, $user);
- $this->admin_acl_add($scope, $user, $perm);
+ $this->admin_acl_add($scope, $user, $perm);
}elseif($cmd == 'delete'){
$this->admin_acl_del($scope, $user);
}
-
+
// reload ACL config
$AUTH_ACL = file(DOKU_CONF.'acl.auth.php');
}
-
+
/**
* ACL Output function
*
@@ -104,26 +104,26 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
*/
function html() {
global $ID;
-
+
print $this->locale_xhtml('intro');
-
+
ptln('<div class="acladmin">');
ptln('<table class="inline">');
-
+
//new
$this->admin_acl_html_new();
-
+
//current config
$acls = $this->get_acl_config($ID);
foreach ($acls as $id => $acl){
- $this->admin_acl_html_current($id,$acl);
+ $this->admin_acl_html_current($id,$acl);
}
-
+
ptln('</table>');
ptln('</div>');
}
-
-
+
+
/**
* Get matching ACL lines for a page
*
@@ -138,9 +138,9 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
*/
function get_acl_config($id){
global $AUTH_ACL;
-
+
$acl_config=array();
-
+
// match exact name
$matches = preg_grep('/^'.$id.'\s+.*/',$AUTH_ACL);
if(count($matches)){
@@ -151,7 +151,7 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
$acl_config[$acl[0]][] = array( 'name' => $acl[1], 'perm' => $acl[2]);
}
}
-
+
$specific_found=array();
// match ns
while(($id=getNS($id)) !== false){
@@ -166,7 +166,7 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
}
}
}
-
+
//include *-config
$matches = preg_grep('/^\*\s+.*/',$AUTH_ACL);
if(count($matches)){
@@ -180,15 +180,15 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
}
}
}
-
+
//sort
//FIXME: better sort algo: first sort by key, then sort by first value
krsort($acl_config, SORT_STRING);
-
+
return($acl_config);
}
-
-
+
+
/**
* adds new acl-entry to conf/acl.auth.php
*
@@ -196,19 +196,19 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
*/
function admin_acl_add($acl_scope, $acl_user, $acl_level){
$acl_config = join("",file(DOKU_CONF.'acl.auth.php'));
-
+
// max level for pagenames is edit
if(strpos($acl_scope,'*') === false) {
if($acl_level > AUTH_EDIT) $acl_level = AUTH_EDIT;
}
-
+
$new_acl = "$acl_scope\t$acl_user\t$acl_level\n";
-
+
$new_config = $acl_config.$new_acl;
-
+
return io_saveFile(DOKU_CONF.'acl.auth.php', $new_config);
}
-
+
/**
* remove acl-entry from conf/acl.auth.php
*
@@ -216,17 +216,17 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
*/
function admin_acl_del($acl_scope, $acl_user){
$acl_config = file(DOKU_CONF.'acl.auth.php');
-
+
$acl_pattern = '^'.preg_quote($acl_scope,'/').'\s+'.$acl_user.'\s+[0-8].*$';
-
+
// save all non!-matching #FIXME invert is available from 4.2.0 only!
$new_config = preg_grep("/$acl_pattern/", $acl_config, PREG_GREP_INVERT);
-
+
return io_saveFile(DOKU_CONF.'acl.auth.php', join('',$new_config));
}
-
+
// --- HTML OUTPUT FUNCTIONS BELOW --- //
-
+
/**
* print tablerows with the current permissions for one id
*
@@ -237,26 +237,26 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
$cur = $id;
$ret = '';
$opt = array();
-
+
//prepare all options
-
+
// current page
$opt[] = array('key'=> $id, 'val'=> $id.' ('.$this->lang['page'].')');
-
+
// additional namespaces
while(($id=getNS($id)) !== false){
$opt[] = array('key'=> $id.':*', 'val'=> $id.':* ('.$this->lang['namespace'].')');
}
-
+
// the top namespace
$opt[] = array('key'=> '*', 'val'=> '* ('.$this->lang['namespace'].')');
-
+
// set sel on second entry (current namespace)
$opt[1]['sel'] = ' selected="selected"';
-
+
// flip options
$opt = array_reverse($opt);
-
+
// create HTML
$att = array( 'name' => 'acl_scope',
'class' => 'edit',
@@ -266,10 +266,10 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
$ret .= '<option value="'.$o['key'].'"'.$o['sel'].'>'.$o['val'].'</option>';
}
$ret .= '</select>';
-
+
return $ret;
}
-
+
/**
* print tablerows with the current permissions for one id
*
@@ -278,26 +278,26 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
*/
function admin_acl_html_new(){
global $ID;
- global $lang;
-
+ global $lang;
+
// table headers
ptln('<tr>',2);
ptln(' <th class="leftalign" colspan="3">'.$this->lang['acl_new'].'</th>',2);
ptln('</tr>',2);
-
+
ptln('<tr>',2);
-
+
ptln('<td class="centeralign" colspan="3">',4);
-
+
ptln(' <form method="post" action="'.wl($ID).'">',4);
ptln(' <input type="hidden" name="do" value="admin" />',4);
ptln(' <input type="hidden" name="page" value="acl" />',4);
ptln(' <input type="hidden" name="acl_cmd" value="save" />',4);
-
+
//scope select
ptln($this->lang['acl_perms'],4);
- ptln($this->admin_acl_html_dropdown($ID),4);
-
+ ptln($this->admin_acl_html_dropdown($ID),4);
+
$att = array( 'name' => 'acl_type',
'class' => 'edit',
'title' => $this->lang['acl_user'].'/'.$this->lang['acl_group']);
@@ -305,22 +305,22 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
ptln(' <option value="@">'.$this->lang['acl_group'].'</option>',4);
ptln(' <option value="">'.$this->lang['acl_user'].'</option>',4);
ptln(' </select>',4);
-
+
$att = array( 'name' => 'acl_user',
'type' => 'text',
'class' => 'edit',
'title' => $this->lang['acl_user'].'/'.$this->lang['acl_group']);
ptln(' <input '.html_attbuild($att).' />',4);
ptln(' <br />');
-
+
ptln( $this->admin_acl_html_checkboxes(0,false),8);
-
+
ptln(' <input type="submit" class="edit" value="'.$lang['btn_save'].'" />',4);
ptln(' </form>');
ptln('</td>',4);
ptln('</tr>',2);
}
-
+
/**
* print tablerows with the current permissions for one id
*
@@ -330,14 +330,14 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
function admin_acl_html_current($id,$permissions){
global $lang;
global $ID;
-
+
//is it a page?
if(substr($id,-1) == '*'){
$ispage = false;
}else{
$ispage = true;
}
-
+
// table headers
ptln(' <tr>');
ptln(' <th class="leftalign" colspan="3">');
@@ -350,11 +350,12 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
ptln('<em>'.$id.'</em>',6);
ptln(' </th>');
ptln(' </tr>');
-
+
sort($permissions);
-
+
foreach ($permissions as $conf){
//userfriendly group/user display
+ $conf['name'] = rawurldecode($conf['name']);
if(substr($conf['name'],0,1)=="@"){
$group = $this->lang['acl_group'];
$name = substr($conf['name'],1);
@@ -364,10 +365,10 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
$name = $conf['name'];
$type = '';
}
-
+
ptln('<tr>',2);
- ptln('<td class="leftalign">'.$group.' '.$name.'</td>',4);
-
+ ptln('<td class="leftalign">'.htmlspecialchars($group.' '.$name).'</td>',4);
+
// update form
ptln('<td class="centeralign">',4);
ptln(' <form method="post" action="'.wl($ID).'">',4);
@@ -381,14 +382,14 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
ptln(' <input type="submit" class="edit" value="'.$lang['btn_update'].'" />',4);
ptln(' </form>');
ptln('</td>',4);
-
-
+
+
// deletion form
-
+
$ask = $lang['del_confirm'].'\\n';
$ask .= $id.' '.$conf['name'].' '.$conf['perm'];
ptln('<td class="centeralign">',4);
- ptln(' <form method="post" action="'.wl($ID).'" onsubmit="return confirm(\''.$ask.'\')">',4);
+ ptln(' <form method="post" action="'.wl($ID).'" onsubmit="return confirm(\''.str_replace('\\\\n','\\n',addslashes($ask)).'\')">',4);
ptln(' <input type="hidden" name="do" value="admin" />',4);
ptln(' <input type="hidden" name="page" value="acl" />',4);
ptln(' <input type="hidden" name="acl_cmd" value="delete" />',4);
@@ -398,13 +399,13 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
ptln(' <input type="submit" class="edit" value="'.$lang['btn_delete'].'" />',4);
ptln(' </form>',4);
ptln('</td>',4);
-
+
ptln('</tr>',2);
}
-
+
}
-
-
+
+
/**
* print the permission checkboxes
*
@@ -413,13 +414,13 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
*/
function admin_acl_html_checkboxes($setperm,$ispage){
global $lang;
-
+
static $label = 0; //number labels
$ret = '';
-
+
foreach(array(AUTH_READ,AUTH_EDIT,AUTH_CREATE,AUTH_UPLOAD,AUTH_DELETE) as $perm){
$label += 1;
-
+
//general checkbox attributes
$atts = array( 'type' => 'checkbox',
'id' => 'pbox'.$label,
@@ -429,7 +430,7 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
if($setperm >= $perm) $atts['checked'] = 'checked';
# if($perm > AUTH_READ) $atts['onchange'] = #FIXME JS to autoadd lower perms
if($ispage && $perm > AUTH_EDIT) $atts['disabled'] = 'disabled';
-
+
//build code
$ret .= '<label for="pbox'.$label.'" title="'.$this->lang['acl_perm'.$perm].'">';
$ret .= '<input '.html_attbuild($atts).' />';
@@ -438,5 +439,5 @@ class admin_plugin_acl extends DokuWiki_Admin_Plugin {
}
return $ret;
}
-
+
}