<?php if (!defined('PmWiki')) exit(); /* People's login information is stored on their profile page. The group to which they belong corresponds to the group their profile page is in. To grant access to everyone in that group, simply set the password to @Group with 'Group' being the group you want to grant access to. For individuals, just list their username in the password list. To exclude an individual, use -username. To exclude a group, use -@Group. Groups that are named $SitePrefix.${some default password key} are recognized as @_site_{some default password key}. For example, if $SitePrefix=SitePre, then members of the group SitePreedit get all the privalages of the @_site_edit password. Similarly, the members of SitePreadmin get all the privalages of @_site_admin. You cannot set $SitePrefix to _site_. Don't ask, you just can't. By the way, @_site_edit and the like will not work anymore. However you can still use @nopass. There is just no way around this. You will have to use the $SitePrefix thing mentioned above to get something equivalent. All in all it seemed like a small price to pay for the extra versatility. People can always edit the page that stores their own information. I thought it would be a safe bet that anyone that wanted to store login information in this fashion would want this to be the case. When using this recipe, the default password values do not really have any use anymore. I thought about making use of them as a default password for the groups, and may impelement that in the future, but decided against it for the preseant because it just did not seem to add anything. You need to include this recipe before you include editattr. */ # let Site.AuthForm know that we're doing user-based authorization $EnableAuthUser = 1; $AuthFunction='AuthProfile'; //$AuthProfileCascade['admin']=array_keys($AuthProfileCascade); SDVA($AuthProfileSearchPatterns, array('!-deleted-\d+$!')); SDVA($GroupPasswords, array()); SDV($SitePrefix, 'Site'); #cannot be _site_ SDV($GroupDelimiter, '@'); $AuthProfileSearchPatterns[] = '!\.(All)?Recent(Changes|Uploads|Pages)$!'; $AuthProfileSearchPatterns[] = '!\.Group(Print)?(Header|Footer|Attributes)$!'; $AuthProfileSearchPatterns[] = '!^PmWiki\.!'; $AuthProfileSearchPatterns[] = '!^Site\.!'; $AuthProfileSearchPatterns[] = '!\.SideBar!'; $AuthProfileSearchPatterns[] = '!^Issues\.!'; if (!$AuthId) $AuthListDefaults=$AuthList; Markup('AuthProfile[[~','<[[~','/\\[\\[~(.*?)\\]\\]/e',"GetAuthorPage('$1')"); function GetAuthorPage($author){ global $AuthProfileSearchPatterns; $pages=@ListPages($AuthProfileSearchPatterns); foreach ($pages as $pn){ $thispage=ReadPage($pn, READPAGE_CURRENT); if($thispage["username"]==$author) return "[[$pn|$author]]"; } return $author; } function check_username($pagename, $fn, &$new) { global $MessagesFmt, $EnablePost, $AuthProfileSearchPatterns, $GroupDelimiter, $AllowName, $AuthListDefaults; if(!@$new[$fn]) return; $flagged=($new[$fn]==$AllowName or in_array($new[$fn],$AuthListDefaults) or preg_match('/^admin(istrator.*)?$/i',$new[$fn])); $search=$AuthProfileSearchPatterns; $search[]="!^$pagename$!"; $pages=@ListPages($search); foreach ($pages as $pn) { $page=ReadPage($pn,READPAGE_CURRENT); if($new[$fn]==$page["username"] or $flagged){ $MessagesFmt[] = "<h3 class='wikimessage'>$[That username is taken. Please choose another.]</h3>"; $EnablePost=false; return; } } if(preg_match("/^($GroupDelimiter|-)/",$new[$fn]) or preg_match("/[, ]/",$new[$fn])){ $MessagesFmt[] = "<h3 class='wikimessage'>$[Commas, and whitespaces are not allowed in your username.<br>It also cannot start with $GroupDelimiter or a hyphen.]</h3>"; $EnablePost=false; return; } } if (@$_POST['authid']) { $id=stripmagic(@$_POST['authid']); $pw=stripmagic(@$_POST['authpw']); $authid=''; $authlist=array(); $pages=@ListPages($AuthProfileSearchPatterns); foreach ($pages as $pn) { $thispage=ReadPage($pn, READPAGE_CURRENT); if($thispage["username"]==$id and $thispage["password"]==$pw){ $authid = $id; $authgroup=FmtPageName('$Group', $pn); $authlist[$GroupDelimiter.$authgroup] = true; $authlist['-'.$GroupDelimiter.$authgroup] = false; break; } } if($id=='admin' and crypt($pw,$AuthProfileSalt)==$DefaultPasswords['admin']) {$authid = $id;} if (!$authid) $GLOBALS['InvalidLogin'] = true; else{ if (!isset($AuthId)) $AuthId = $authid; SessionAuth($pagename, array('authid' => $authid, 'authlist' => $authlist)); } } else SessionAuth($pagename); /* This is the section where the username and passwords fields are added. This could be the source of security vulnerabilities if not handled with care. I worry about people having authority to publish but not set passwords being able to set new usernames and passwords. A clever enough person might be able to construct a bogus html POST that updates the page without ever using the edit form. The editattr script is only included if you are trying to edit the page first, but more importantly, The login fields "username" and password" are only included if the person has attr authorization on the page. That should cover the possibility of constructing a bogus html POST. */ if(CondAuth($pagename,'attr')){ $EditAttrFields['username'] = array('attribute' => 1, 'filter' => 'check_username'); $EditAttrFields['password'] = array('attribute' => 1); } if ( $action == 'edit' ) require_once("$FarmD/cookbook/editattr.php"); function AuthProfile($pagename, $level, $authprompt=true, $since=0) { global $DefaultPasswords, $GroupAttributesFmt, $AllowName, $SitePrefix, $GroupDelimiter, $AuthProfileCascade, $FmtV, $AuthPromptFmt, $PageStartFmt, $PageEndFmt, $AuthId, $AuthList, $NoHTMLCache; static $groupcache, $sitecache, $justhigher; SDV($GroupAttributesFmt,'$Group/GroupAttributes'); SDV($AllowName,'@nopass'); $page = ReadPage($pagename, $since); if (!$page) return false; if (!isset($authcache)) SessionAuth($pagename, (@$_POST['authpw']) ? array('authpw' => array($_POST['authpw'] => 1)) : ''); if (@$AuthId) { $AuthList[$AuthId] = true; $AuthList["-$AuthId"] = false; #undo what PmWikiAuth will do while it is still the default #authorization mechanism. unset($AuthList["id:$AuthId"]); unset($AuthList["id:-$AuthId"]); unset($AuthList["id:*"]); unset($AuthList['']); } if(!isset($justhigher)) foreach(array_keys($DefaultPasswords) as $k) foreach($AuthProfileCascade as $higherauth=>$v) if(in_array($k, (array)$v)) $justhigher[$k][]=$GroupDelimiter.$SitePrefix.$higherauth; $group=FmtPageName('$Group',$pagename); if(@!isset($sitecache[$group])) { $PasswordGroup=substr($group,strlen($SitePrefix)); $issitegroup=in_array($PasswordGroup, array_keys($DefaultPasswords)); $authhigher=AuthHigherThan('edit'); foreach(array_keys($DefaultPasswords) as $k){ if(($k=='edit' or in_array($k,$authhigher)) and $issitegroup){ if($justhigher[$PasswordGroup]) $sitecache[$group][$k]=implode(', ',$justhigher[$PasswordGroup]); else $sitecache[$group][$k]='@lock'; } else $sitecache[$group][$k]=$GroupDelimiter.$SitePrefix.$k; } } $groupattr = FmtPageName($GroupAttributesFmt, $pagename); if(@!isset($groupcache[$groupattr])) { $gp = ReadPage($groupattr, READPAGE_CURRENT); foreach(array_keys($DefaultPasswords) as $k) $groupcache[$groupattr][$k]=$gp["passwd$k"]; } foreach(array_keys($DefaultPasswords) as $k) { if(@$page["passwd$k"]) { $page['=pwsource'][$k]='page'; $page['=passwd'][$k]=$page["passwd$k"]; $page['=auth'][$k]=UserIsAuthorized($page['=passwd'][$k]); continue; } if(@$groupcache[$groupattr][$k]) { $page['=pwsource'][$k]='group'; $page['=passwd'][$k]=$groupcache[$groupattr][$k]; $page['=auth'][$k]=UserIsAuthorized($page['=passwd'][$k]); continue; } else{ $page['=pwsource'][$k]='site'; $page['=passwd'][$k]=$sitecache[$group][$k]; $page['=auth'][$k]=UserIsAuthorized($page['=passwd'][$k]); } } #make sure that you can edit your own page if(@$AuthId and @$AuthId==$page["username"]) $page['=auth']['attr']=true; AuthCascade($page); #ok, an admin can do anything. if ($AuthId=='admin') foreach(array_keys($DefaultPasswords) as $k) $page['=auth'][$k]=true; if (@$page['=passwd']['read']) $NoHTMLCache |= 2; if ($level=='ALWAYS' || @$page['=auth'][$level]) return $page; if (!$authprompt) return false; $GLOBALS['AuthNeeded'] = (@$_POST['authpw']) ? $page['=pwsource'][$level] . ' ' . $level : ''; PCache($pagename, $page); $postvars = ''; foreach($_POST as $k=>$v) { if ($k == 'authpw' || $k == 'authid') continue; $k = htmlspecialchars(stripmagic($k), ENT_QUOTES); $v = str_replace('$', '$', htmlspecialchars(stripmagic($v), ENT_COMPAT)); $postvars .= "<input type='hidden' name='$k' value=\"$v\" />\n"; } $FmtV['$PostVars'] = $postvars; $r = str_replace("'", '%37', stripmagic($_SERVER['REQUEST_URI'])); SDV($AuthPromptFmt,array(&$PageStartFmt, "<p><b>$[Password required]</b></p> <form name='authform' action='$r' method='post'> $[Password]: <input tabindex='1' type='password' name='authpw' value='' /> <input type='submit' value='OK' />\$PostVars</form> <script language='javascript' type='text/javascript'><!-- document.authform.authpw.focus() //--></script>", &$PageEndFmt)); PrintFmt($pagename,$AuthPromptFmt); exit; } function UserIsAuthorized($args) { global $AuthList, $AllowName; foreach(preg_split("/[\s,]+/", $args) as $name) if(@$AuthList[$name] || $name==$AllowName) return true; return false; } function AuthHigherThan($auth){ global $AuthProfileCascade; static $AuthHigherThanList; foreach($AuthProfileCascade as $higherauth=>$v) if(in_array($auth, (array)$v) and !in_array($higherauth,$AuthHigherThanList[$auth])){ $AuthHigherThanList[$auth][]=$higherauth; $AuthEvenHigherThanList=AuthHigherThan($higherauth); $AuthHigherThanList[$auth]=array_merge($AuthHigherThanList[$auth],$AuthEvenHigherThanList); } return $AuthHigherThanList[$auth]; } function AuthCascade(&$page){ global $AuthProfileCascade; foreach($AuthProfileCascade as $k=>$v) if (@$page['=auth'][$k]) foreach((array)$v as $value) if(!@$page['=auth'][$value]){ $page['=auth'][$value] = $page['=auth'][$k]; if ($page['=passwd'][$value] = $page['=passwd'][$k]) # assign $page['=pwsource'][$value] = "cascade:$k"; AuthCascade($page); } }