1<?php 2/** 3 * g2fa Google 2-Factor Authentication Plugin 4 * 5 * Dokuwiki Admin Plugin 6 * 7 * @author Andreas Boehler <dev@aboehler.at> 8 */ 9// must be run within Dokuwiki 10if(!defined('DOKU_INC')) die(); 11require_once(dirname(__FILE__).'/GoogleAuthenticator.php'); 12require_once(dirname(__FILE__).'/TokenHelper.php'); 13 14/** 15 * All DokuWiki plugins to extend the admin function 16 * need to inherit from this class 17 */ 18class admin_plugin_authg2fa extends DokuWiki_Admin_Plugin { 19 20 protected $_auth = null; 21 protected $_tokens = array(); 22 protected $_start = 0; 23 protected $_pagesize = 20; 24 protected $_filter = array(); 25 protected $_disabled = ""; 26 protected $_user_total = 0; 27 protected $_tokenHelper = null; 28 protected $_unhide = ""; 29 30 /** 31 * Constructor 32 */ 33 public function admin_plugin_authg2fa() { 34 /** @var DokuWiki_Auth_Plugin $auth */ 35 global $auth; 36 37 $this->setupLocale(); 38 39 if (!isset($auth)) { 40 return; 41 //$this->_disabled = $this->lang['noauth']; 42 } else if (!$auth->canDo('getUsers')) { 43 return; 44 //$this->_disabled = $this->lang['nosupport']; 45 } else { 46 47 // we're good to go 48 $this->_auth = & $auth; 49 50 } 51 $this->_tokenHelper = new TokenHelper(); 52 53 $this->_tokens = $this->_tokenHelper->getTokens(); 54 } 55 56 public function handle() { 57 global $INPUT; 58 if(is_null($this->_auth)) return false; 59 if(!isset($_REQUEST['fn']) || !checkSecurityToken()) return; 60 61 // extract the command and any specific parameters 62 // submit button name is of the form - fn[cmd][param(s)] 63 $fn = $INPUT->param('fn'); 64 65 if (is_array($fn)) { 66 $cmd = key($fn); 67 $param = is_array($fn[$cmd]) ? key($fn[$cmd]) : null; 68 } else { 69 $cmd = $fn; 70 $param = null; 71 } 72 73 if ($cmd != "search") { 74 $this->_start = $INPUT->int('start', 0); 75 $this->_filter = $this->_retrieveFilter(); 76 } 77 78 switch($cmd) { 79 case "csecret" : $this->_tokenHelper->createTokenForUser($param); $this->_tokens = $this->_tokenHelper->getTokens(); break; 80 case "nsecret" : $this->_createTokenForAllUsers(); break; 81 case "dsecret" : $this->_tokenHelper->deleteTokenForUser($param); $this->_tokens = $this->_tokenHelper->getTokens(); break; 82 case "ssecret" : $this->_unhide = $param; break; 83 } 84 85 86 $this->_user_total = $this->_auth->canDo('getUserCount') ? $this->_auth->getUserCount($this->_filter) : -1; 87 88 // page handling 89 switch($cmd){ 90 case 'start' : $this->_start = 0; break; 91 case 'prev' : $this->_start -= $this->_pagesize; break; 92 case 'next' : $this->_start += $this->_pagesize; break; 93 case 'last' : $this->_start = $this->_user_total; break; 94 } 95 $this->_validatePagination(); 96 97 return true; 98 } 99 100 public function html() { 101 global $ID; 102 103 $user_list = $this->_auth->retrieveUsers($this->_start, $this->_pagesize, $this->_filter); 104 $page_buttons = $this->_pagination(); 105 106 if($this->_unhide != "") 107 { 108 if(isset($this->_tokens[$this->_unhide])) { 109 $ga = new PHPGangsta_GoogleAuthenticator(); 110 $url = $ga->getQRCodeGoogleUrl(urlencode('DokuWiki:'.$this->_unhide), $this->_tokens[$this->_unhide]); 111 ptln('Showing QR Code for user '.$this->_unhide.':<br />'); 112 ptln('<img src="'.$url.'" alt="Google 2FA QR Image"><br />'); 113 } 114 } 115 116 ptln("<form action=\"".wl($ID)."\" method=\"post\">"); 117 formSecurityToken(); 118 ptln("<div class=\"table\">"); 119 ptln("<table class=\"inline\">"); 120 ptln('<tr><th>User</th><th>Secret</th><th>Action</th></tr>'); 121 foreach($user_list as $user => $userinfo) 122 { 123 extract($userinfo); 124 ptln('<tr>'); 125 ptln('<td>'.hsc($user).'</td>'); 126 if(isset($this->_tokens[$user])) 127 $secret = $this->_tokens[$user]; 128 else 129 $secret = ""; 130 if($this->_unhide == hsc($user)) { 131 ptln('<td>'.$secret.'</td>'); 132 $this->_unhide = ""; 133 } 134 else { 135 if($secret != "") { 136 ptln('<td>********</td>'); 137 } 138 else { 139 ptln('<td></td>'); 140 } 141 } 142 ptln("<td>"); 143 ptln("<input type=\"submit\" name=\"fn[ssecret][".hsc($user)."]\" class=\"button\" value=\"Show Secret/QR Code\" />"); 144 ptln("<input type=\"submit\" name=\"fn[csecret][".hsc($user)."]\" class=\"button\" value=\"Create new Secret\" />"); 145 ptln("<input type=\"submit\" name=\"fn[dsecret][".hsc($user)."]\" class=\"button\" value=\"Delete Secret\" />"); 146 ptln("</td>"); 147 ptln('</tr>'); 148 149 } 150// ptln('</table>'); 151 ptln("<td colspan=\"3\">"); 152 ptln("<span class=\"medialeft\">"); 153 ptln("<input type=\"submit\" name=\"fn[nsecret]\" class=\"button\" value=\"Create Secrets for all\" />"); 154 ptln(" <input type=\"hidden\" name=\"do\" value=\"admin\" />"); 155 ptln(" <input type=\"hidden\" name=\"page\" value=\"authg2fa\" />"); 156 ptln(" </span>"); 157 ptln(" <span class=\"mediaright\">"); 158 ptln(" <input type=\"submit\" name=\"fn[start]\" ".$page_buttons['start']." class=\"button\" value=\"Start\" />"); 159 ptln(" <input type=\"submit\" name=\"fn[prev]\" ".$page_buttons['prev']." class=\"button\" value=\"Prev\" />"); 160 ptln(" <input type=\"submit\" name=\"fn[next]\" ".$page_buttons['next']." class=\"button\" value=\"Next\" />"); 161 ptln(" <input type=\"submit\" name=\"fn[last]\" ".$page_buttons['last']." class=\"button\" value=\"Last\" />"); 162 ptln(" </span>"); 163 ptln("</td>"); 164 ptln("</table>"); 165 ptln("</form>"); 166 ptln("</div>"); 167 return true; 168 } 169 170 /** 171 * Validate and improve the pagination values 172 */ 173 protected function _validatePagination() { 174 175 if ($this->_start >= $this->_user_total) { 176 $this->_start = $this->_user_total - $this->_pagesize; 177 } 178 if ($this->_start < 0) $this->_start = 0; 179 180 $this->_last = min($this->_user_total, $this->_start + $this->_pagesize); 181 } 182 183 /** 184 * Get the current search terms 185 * 186 * @return array 187 */ 188 protected function _retrieveFilter() { 189 global $INPUT; 190 191 $t_filter = $INPUT->arr('filter'); 192 193 // messy, but this way we ensure we aren't getting any additional crap from malicious users 194 $filter = array(); 195 196 if (isset($t_filter['user'])) $filter['user'] = $t_filter['user']; 197 if (isset($t_filter['name'])) $filter['name'] = $t_filter['name']; 198 if (isset($t_filter['mail'])) $filter['mail'] = $t_filter['mail']; 199 if (isset($t_filter['grps'])) $filter['grps'] = $t_filter['grps']; 200 201 return $filter; 202 } 203 204 /** 205 * Return an array of strings to enable/disable pagination buttons 206 * 207 * @return array with enable/disable attributes 208 */ 209 protected function _pagination() { 210 211 $disabled = 'disabled="disabled"'; 212 213 $buttons['start'] = $buttons['prev'] = ($this->_start == 0) ? $disabled : ''; 214 215 if ($this->_user_total == -1) { 216 $buttons['last'] = $disabled; 217 $buttons['next'] = ''; 218 } else { 219 $buttons['last'] = $buttons['next'] = (($this->_start + $this->_pagesize) >= $this->_user_total) ? $disabled : ''; 220 } 221 222 return $buttons; 223 } 224 225 protected function _createTokenForAllUsers() { 226 $user_list = $this->_auth->retrieveUsers($this->_start, $this->_pagesize, $this->_filter); 227 foreach($user_list as $user => $user_info) 228 { 229 if(!isset($this->_tokens[$user])) 230 $this->_tokenHelper->createTokenForUser($user); 231 } 232 $this->_tokens = $this->_tokenHelper->getTokens(); 233 } 234 235 236 237 238 239} 240