diff options
Diffstat (limited to 'inc/auth')
-rw-r--r-- | inc/auth/ldap.php | 281 | ||||
-rw-r--r-- | inc/auth/mysql.php | 182 | ||||
-rw-r--r-- | inc/auth/pgsql.php | 135 | ||||
-rw-r--r-- | inc/auth/plain.php | 113 |
4 files changed, 711 insertions, 0 deletions
diff --git a/inc/auth/ldap.php b/inc/auth/ldap.php new file mode 100644 index 000000000..2f0f4f1ff --- /dev/null +++ b/inc/auth/ldap.php @@ -0,0 +1,281 @@ +<?php +/** + * LDAP authentication backend + * + * tested with openldap 2.x on Debian only + * + * PHPs LDAP extension is needed + * + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author Andreas Gohr <andi@splitbrain.org> + */ + +//check for LDAP extension on load +if(!function_exists('ldap_connect')) + msg("LDAP extension not found",-1); + +/** + * Connect to the LDAP server + * + * Holds the connection in global scope for multiple use + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function auth_ldap_connect(){ + global $LDAP_CONNECTION; + global $conf; + $cnf = $conf['auth']['ldap']; + + if(!$LDAP_CONNECTION){ + $LDAP_CONNECTION = @ldap_connect($cnf['server']); + if(!$LDAP_CONNECTION){ + msg("LDAP: couldn't connect to LDAP server",-1); + return false; + } + //set protocol version + if($cnf['version']){ + if(!@ldap_set_option($LDAP_CONNECTION, + LDAP_OPT_PROTOCOL_VERSION, + $cnf['version'])){ + msg('Setting LDAP Protocol version '.$cnf['version'].' failed',-1); + if($cnf['debug']) + msg('LDAP errstr: '.htmlspecialchars(ldap_error($LDAP_CONNECTION)),0); + + } else { + //use TLS (needs version 3) + if($cnf['starttls']) { + if (!@ldap_start_tls($LDAP_CONNECTION)){ + msg('Starting TLS failed',-1); + if($cnf['debug']) + msg('LDAP errstr: '.htmlspecialchars(ldap_error($LDAP_CONNECTION)),0); + } + } + // needs version 3 + if(isset($cnf['referrals'])) { + if(!@ldap_set_option($LDAP_CONNECTION, + LDAP_OPT_REFERRALS, + $cnf['referrals'])){ + msg('Setting LDAP referrals to off failed',-1); + if($cnf['debug']) + msg('LDAP errstr: '.htmlspecialchars(ldap_error($LDAP_CONNECTION)),0); + } + } + } + } + } + return $LDAP_CONNECTION; +} + +/** + * Check user+password [required auth function] + * + * Checks if the given user exists and the given + * plaintext password is correct by trying to bind + * to the LDAP server + * + * @author Andreas Gohr <andi@splitbrain.org> + * @return bool + */ +function auth_checkPass($user,$pass){ + global $conf; + $cnf = $conf['auth']['ldap']; + + //reject empty password + if(empty($pass)) return false; + + //connect to LDAP Server + $conn = auth_ldap_connect(); + if(!$conn) return false; + + // indirect user bind + if(!empty($cnf['binddn']) and !empty($cnf['bindpw'])) { + //use superuser credentials + if(!@ldap_bind($conn,$cnf['binddn'],$cnf['bindpw'])){ + if($cnf['debug']) msg('LDAP errstr: '.htmlspecialchars(ldap_error($conn)),0); + return false; + } + + // special bind string + } else if(!empty($cnf['binddn']) and !empty($cnf['usertree']) and !empty($cnf['userfilter'])) { + $dn = auth_ldap_makeFilter($cnf['binddn'], array('user'=>$user,'server'=>$cnf['server'])); + + // direct user bind + } else if(strpos($cnf['usertree'], '%{user}')) { + $dn = auth_ldap_makeFilter($cnf['usertree'], array('user'=>$user,'server'=>$cnf['server'])); + + // Anonymous bind + } else { + if(!@ldap_bind($conn)){ + msg("LDAP: can not bind anonymously",-1); + if($cnf['debug']) msg('LDAP errstr: '.htmlspecialchars(ldap_error($conn)),0); + return false; + } + } + + // Try to bind to with the dn if we have one. + if(!empty($dn)) { + // User/Password bind + if(!@ldap_bind($conn,$dn,$pass)){ + if($cnf['debug']) msg('LDAP errstr: '.htmlspecialchars(ldap_error($conn)),0); + return false; + } + return true; + } else { + // See if we can find the user + $info = auth_getUserData($user); + if(empty($info['dn'])) { + return false; + } else { + $dn = $info['dn']; + } + // Try to bind with the dn provided + if(!@ldap_bind($conn,$dn,$pass)){ + if($cnf['debug']) msg('LDAP errstr: '.htmlspecialchars(ldap_error($conn)),0); + return false; + } + return true; + } + + return false; +} + +/** + * Return user info [required auth function] + * + * Returns info about the given user needs to contain + * at least these fields: + * + * name string full name of the user + * mail string email addres of the user + * grps array list of groups the user is in + * + * This LDAP specific function returns the following + * addional fields: + * + * dn string distinguished name (DN) + * uid string Posix User ID + * + * @author Andreas Gohr <andi@splitbrain.org> + * @author Trouble + * @author Dan Allen <dan.j.allen@gmail.com> + * @auhtor <evaldas.auryla@pheur.org> + */ +function auth_getUserData($user){ + global $conf; + $cnf = $conf['auth']['ldap']; + + //connect to LDAP Server + $conn = auth_ldap_connect(); + if(!$conn) return false; + + $info['user']= $user; + $info['server']= $cnf['server']; + + //get info for given user + $base = auth_ldap_makeFilter($cnf['usertree'], $info); + if(!empty($cnf['userfilter'])) { + $filter = auth_ldap_makeFilter($cnf['userfilter'], $info); + } else { + $filter = "(ObjectClass=*)"; + } + + $sr = @ldap_search($conn, $base, $filter); + $result = @ldap_get_entries($conn, $sr); + if($cnf['debug']) msg('LDAP errstr: '.htmlspecialchars(ldap_error($conn)),0); + + // Don't accept more or less than one response + if($result['count'] != 1){ + return false; //user not found + } + + $user_result = $result[0]; + + //general user info + $info['dn']= $user_result['dn']; + $info['mail']= $user_result['mail'][0]; + $info['name']= $user_result['cn'][0]; + + #overwrite if other attribs are specified. + foreach($cnf['mapping'] as $localkey => $key) { + if(is_array($key)) { + //use regexp to clean up user_result + list($key, $regexp) = each($key); + foreach($user_result[$key] as $grp){ + if (preg_match($regexp,$grp,$match)) { + if($localkey == 'grps') { + $info[$localkey][] = $match[1]; + } else { + $info[$localkey] = $match[1]; + } + } + } + } else { + $info[$localkey] = $user_result[$key][0]; + } + } + + //get groups for given user if grouptree is given + if (!empty($cnf['grouptree'])) { + $base = auth_ldap_makeFilter($cnf['grouptree'], $user_result); + $filter = auth_ldap_makeFilter($cnf['groupfilter'], $user_result); + + $sr = @ldap_search($conn, $base, $filter); + if(!$sr){ + msg("LDAP: Reading group memberships failed",-1); + if($cnf['debug']) msg('LDAP errstr: '.htmlspecialchars(ldap_error($conn)),0); + return false; + } + $result = ldap_get_entries($conn, $sr); + foreach($result as $grp){ + if(!empty($grp['cn'][0])) + $info['grps'][] = $grp['cn'][0]; + } + } + + //if no groups were found always return the default group + if(!count($info['grps'])) $info['grps'][] = $conf['defaultgroup']; + + return $info; +} + +/** + * Create a new User [required auth function] + * + * Not implemented + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function auth_createUser($user,$pass,$name,$mail){ + msg("Sorry. Creating users is not supported by the LDAP backend",-1); + return null; +} + + +/** + * Make ldap filter strings. + * + * Used by auth_getUserData to make the filter + * strings for grouptree and groupfilter + * + * filter string ldap search filter with placeholders + * placeholders array array with the placeholders + * + * @author Troels Liebe Bentsen <tlb@rapanden.dk> + * @return string + */ +function auth_ldap_makeFilter($filter, $placeholders) { + preg_match_all("/%{([^}]+)/", $filter, $matches, PREG_PATTERN_ORDER); + //replace each match + foreach ($matches[1] as $match) { + //take first element if array + if(is_array($placeholders[$match])) { + $value = $placeholders[$match][0]; + } else { + $value = $placeholders[$match]; + } + $filter = str_replace('%{'.$match.'}', $value, $filter); + } + return $filter; +} + +//Setup VIM: ex: et ts=2 enc=utf-8 : diff --git a/inc/auth/mysql.php b/inc/auth/mysql.php new file mode 100644 index 000000000..758fe3b77 --- /dev/null +++ b/inc/auth/mysql.php @@ -0,0 +1,182 @@ +<?php +/** + * MySQL authentication backend + * + * PHP's MySQL extension is needed + * + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author Andreas Gohr <andi@splitbrain.org> + */ + +//check for MySQL extension on load +if(!function_exists('mysql_connect')) + msg("MySQL extension not found",-1); + +/** + * Execute SQL + * + * Executes SQL statements and returns the results as list + * of hashes. Returns false on error. Returns auto_increment + * IDs on INSERT statements. + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function auth_mysql_runsql($sql_string) { + global $conf; + $cnf = $conf['auth']['mysql']; + + $link = @mysql_connect ($cnf['server'], $cnf['user'], $cnf['password']); + if(!$link){ + msg('MySQL: Connection to database failed!',-1); + return false; + } + $result = @mysql_db_query($cnf['database'],$sql_string,$link); + if(!$result){ + msg('MySQL: '.mysql_error($link)); + return false; + } + + //mysql_db_query returns 1 on a insert statement -> no need to ask for results + if ($result != 1) { + for($i=0; $i< mysql_num_rows($result); $i++) { + $temparray = mysql_fetch_assoc($result); + $resultarray[]=$temparray; + } + mysql_free_result ($result); + } elseif (mysql_insert_id($link)) { + $resultarray = mysql_insert_id($link); //give back ID on insert + } else + $resultarray = 0; // asure that the return value is valid + + mysql_close ($link); + return $resultarray; +} + +/** + * Check user+password [required auth function] + * + * Checks if the given user exists and the given + * plaintext password is correct. Furtheron it + * might be checked wether the user is member of + * the right group + * + * @author Andreas Gohr <andi@splitbrain.org> + * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> + * @return bool + */ +function auth_checkPass($user,$pass){ + global $conf; + $cnf = $conf['auth']['mysql']; + + $sql = str_replace('%u',addslashes($user),$cnf['passcheck']); + $sql = str_replace('%g',addslashes($conf['defaultgroup']),$sql); + $result = auth_mysql_runsql($sql); + + if(count($result)){ + return(auth_verifyPassword($pass,$result[0]['pass'])); + }else{ + return(false); + } +} + +/** + * Return user info [required auth function] + * + * Returns info about the given user needs to contain + * at least these fields: + * + * name string full name of the user + * mail string email addres of the user + * grps array list of groups the user is in + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function auth_getUserData($user){ + global $conf; + $cnf = $conf['auth']['mysql']; + + $sql = str_replace('%u',addslashes($user),$cnf['userinfo']); + $result = auth_mysql_runsql($sql); + if(!count($result)) return false; + $info = $result[0]; + + $sql = str_replace('%u',addslashes($user),$cnf['groups']); + $result = auth_mysql_runsql($sql); + if(!count($result)){ + $info['grps'][] = $conf['defaultgroup']; + }else{ + foreach($result as $row){ + $info['grps'][] = $row['group']; + } + } + + return $info; +} + +/** + * Create a new User [required auth function] + * + * user string username + * pass string password + * name string full name of the user + * mail string email address + * + * Returns false if the user already exists, null when an error + * occoured and the cleartext password of the new user if + * everything went well. + * + * The user HAS TO be added to the default group by this + * function + * + * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net> + */ +function auth_createUser($user,$pass,$name,$mail){ + global $conf; + $cnf = $conf['auth']['mysql']; + + //check if user exists + $info = auth_getUserData($user); + if ($info != false) return false; + + //get groupid of default group + if($cnf['getgroupid']){ + $sql = str_replace('%g',addslashes($conf['defaultgroup']),$cnf['getgroupid']); + $result = auth_mysql_runsql($sql); + if($result === false) return null; + if (count($result) == 1){ + $gid = $result[0]['gid']; + }else{ + msg("MySQL: Couldn't find the default group",-1); + return null; + } + } + + //prepare the insert + $sql = str_replace('%u' ,addslashes($user),$cnf['adduser']); + $sql = str_replace('%p' ,addslashes(auth_cryptPassword($pass)),$sql); + $sql = str_replace('%n' ,addslashes($name),$sql); + $sql = str_replace('%e' ,addslashes($mail),$sql); + $sql = str_replace('%gid',addslashes($gid),$sql); + $sql = str_replace('%g' ,addslashes($conf['defaultgroup']),$sql); + + //do the insert + $uid = auth_mysql_runsql($sql); + if($uid == 0){ + msg("Registering of the new user '$user' failed!", -1); + return null; + } + + //add to default group + if ($cnf['addusergroup']) { + $sql = str_replace('%uid',addslashes($uid),$cnf['addusergroup']); + $sql = str_replace('%u' ,addslashes($user),$sql); + $sql = str_replace('%gid',addslashes($gid),$sql); + $sql = str_replace('%g' ,addslashes($conf['defaultgroup']),$sql); + $result = auth_mysql_runsql($sql); + if($result === false) msg("MySQL: couldn't add user to the default group"); + } + + return $pass; +} + +//Setup VIM: ex: et ts=2 enc=utf-8 : diff --git a/inc/auth/pgsql.php b/inc/auth/pgsql.php new file mode 100644 index 000000000..b063f405e --- /dev/null +++ b/inc/auth/pgsql.php @@ -0,0 +1,135 @@ +<?php +/** + * PgSQL authentication backend + * (shamelessly based on the original auth_mysql.php ;-) + * + * PHP's PgSQL extension is needed + * + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author Alexander Marx < mad-ml [at] madness [dot] at > + */ + +//check for Postgresql extension on load +if(!function_exists('pg_connect')) + msg("PgSQL extension not found",-1); + +/** + * Execute SQL + * + * Executes SQL statements and returns the results as list + * of hashes. Returns false on error. + * + */ +function auth_pgsql_runsql($sql_string) { + global $conf; + $cnf = $conf['auth']['pgsql']; + + if($cnf['port']) { + $port=" port=".$cnf['port']; + } + + $dsn="host=".$cnf['server']." dbname=".$cnf['database'].$port." user=".$cnf['user']." password=".$cnf['password']; + $link = pg_connect($dsn); + if(!$link){ + msg('PgSQL: Connection to database failed!',-1); + return false; + } + + $result = pg_query($link, $sql_string); + if(!$result){ + msg('PgSQL: '.pg_last_error($link)); + return false; + } + + for($i=0; $i< pg_num_rows($result); $i++) { + $temparray = pg_fetch_assoc($result); + $resultarray[]=$temparray; + } + pg_free_result($result); + pg_close($link); + return $resultarray; +} + +/** + * Check user+password [required auth function] + * + * Checks if the given user exists and the given + * plaintext password is correct + * + * @author Andreas Gohr <andi@splitbrain.org> + * @return bool + */ +function auth_checkPass($user,$pass){ + global $conf; + $cnf = $conf['auth']['pgsql']; + + $sql = str_replace('%u',addslashes($user),$cnf['userinfo']); + $result = auth_pgsql_runsql($sql); + if(count($result)>0) { + $info=$result[0]; + return auth_verifyPassword($pass, $info['pass']); + } else { + return false; + } +} + +/** + * Return user info [required auth function] + * + * Returns info about the given user needs to contain + * at least these fields: + * + * name string full name of the user + * mail string email addres of the user + * grps array list of groups the user is in + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function auth_getUserData($user){ + global $conf; + $cnf = $conf['auth']['pgsql']; + + $sql = str_replace('%u',addslashes($user),$cnf['userinfo']); + $result = auth_pgsql_runsql($sql); + if(!count($result)) return false; + $info = $result[0]; + + $sql = str_replace('%u',addslashes($user),$cnf['groups']); + $result = auth_pgsql_runsql($sql); + if(!count($result)) return false; + foreach($result as $row){ + $info['grps'][] = $row['group']; + } + + return $info; +} + +/** + * Create a new User [required auth function] + */ +function auth_createUser($user,$pass,$name,$mail) { + global $conf; + $cnf = $conf['auth']['pgsql']; + + if($cnf['createuser']) { + $sql = str_replace('%u',addslashes($user),$cnf['userinfo']); + $result = auth_pgsql_runsql($sql); + if(count($result)>0) return false; + + $sql = str_replace('%u',addslashes($user),$cnf['createuser']); + $sql = str_replace('%p',auth_cryptPassword($pass),$sql); + $sql = str_replace('%f',addslashes($name),$sql); + $sql = str_replace('%e',addslashes($mail),$sql); + $sql = str_replace('%g',addslashes($conf['defaultgroup']),$sql); + + $result=auth_pgsql_runsql($sql); + if(count($result)) + return $pass; + } else { + msg("Sorry. Your PgSQL backend is not configured to create new users.",-1); + } + return null; +} + +//Setup VIM: ex: et ts=2 enc=utf-8 : + diff --git a/inc/auth/plain.php b/inc/auth/plain.php new file mode 100644 index 000000000..eaa01b79d --- /dev/null +++ b/inc/auth/plain.php @@ -0,0 +1,113 @@ +<?php +/** + * Plaintext authentication backend + * + * If you want to authenticate against something + * else then the builtin flatfile auth system + * you have to reimplement the "required auth + * functions" + * + * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) + * @author Andreas Gohr <andi@splitbrain.org> + */ + +// we only accept page ids for auth_plain +if(isset($_REQUEST['u'])) + $_REQUEST['u'] = cleanID($_REQUEST['u']); + +/** + * Check user+password [required auth function] + * + * Checks if the given user exists and the given + * plaintext password is correct + * + * @author Andreas Gohr <andi@splitbrain.org> + * @return bool + */ +function auth_checkPass($user,$pass){ + $users = auth_plain_loadUserData(); + + if(!isset($users[$user])) return false; + + return auth_verifyPassword($pass,$users[$user]['pass']); +} + +/** + * Return user info [required auth function] + * + * Returns info about the given user needs to contain + * at least these fields: + * + * name string full name of the user + * mail string email addres of the user + * grps array list of groups the user is in + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function auth_getUserData($user){ + $users = auth_plain_loadUserData(); + return $users[$user]; +} + +/** + * Create a new User [required auth function] + * + * Returns false if the user already exists, null when an error + * occured and the cleartext password of the new user if + * everything went well. + * + * The new user HAS TO be added to the default group by this + * function! + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function auth_createUser($user,$pass,$name,$mail){ + global $conf; + + $users = auth_plain_loadUserData(); + if(isset($users[$user])) return false; + + $userline = join(':',array($user, + auth_cryptPassword($pass), + $name, + $mail, + $conf['defaultgroup'])); + $userline .= "\n"; + $fh = fopen(DOKU_INC.'conf/users.auth.php','a'); + if($fh){ + fwrite($fh,$userline); + fclose($fh); + return $pass; + } + msg('The users.auth.php file is not writable. Please inform the Wiki-Admin',-1); + return null; +} + +/** + * Load all user data + * + * Used by the plaintext auth functions + * loads the user file into a datastructure + * + * @author Andreas Gohr <andi@splitbrain.org> + */ +function auth_plain_loadUserData(){ + $data = array(); + $lines = file(DOKU_INC.'conf/users.auth.php'); + foreach($lines as $line){ + $line = preg_replace('/#.*$/','',$line); //ignore comments + $line = trim($line); + if(empty($line)) continue; + + $row = split(":",$line,5); + $groups = split(",",$row[4]); + $data[$row[0]]['pass'] = $row[1]; + $data[$row[0]]['name'] = urldecode($row[2]); + $data[$row[0]]['mail'] = $row[3]; + $data[$row[0]]['grps'] = $groups; + } + return $data; +} + + +//Setup VIM: ex: et ts=2 enc=utf-8 : |