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