1<?php
2/**
3 * Login/Logout logging plugin
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Andreas Gohr <gohr@cosmocode.de>
7 */
8
9class action_plugin_loglog extends DokuWiki_Action_Plugin
10{
11    /**
12     * @var \helper_plugin_loglog_logging
13     */
14    protected $logHelper;
15
16    /**
17     * @var \helper_plugin_loglog_main
18     */
19    protected $mainHelper;
20
21    /**
22     * @var \helper_plugin_loglog_alert
23     */
24    protected $alertHelper;
25
26    public function __construct()
27    {
28        $this->mainHelper = $this->loadHelper('loglog_main');
29        $this->logHelper = $this->loadHelper('loglog_logging');
30        $this->alertHelper = $this->loadHelper('loglog_alert');
31    }
32
33    /** @inheritDoc */
34    function register(Doku_Event_Handler $controller)
35    {
36        // tasks to perform on login/logoff
37        $controller->register_hook(
38            'ACTION_ACT_PREPROCESS',
39            'BEFORE',
40            $this,
41            'handleAuth'
42        );
43
44        // allow other plugins to emit logging events
45        $controller->register_hook(
46            'PLUGIN_LOGLOG_LOG',
47            'BEFORE',
48            $this,
49            'handleCustom'
50        );
51
52        // autologout plugin
53        $controller->register_hook(
54            'ACTION_AUTH_AUTOLOGOUT',
55            'BEFORE',
56            $this,
57            'handleAutologout'
58        );
59
60        // log admin access
61        $controller->register_hook(
62            'ACTION_ACT_PREPROCESS',
63            'BEFORE',
64            $this,
65            'handleAdminAccess'
66        );
67
68        // log user modifications
69        $controller->register_hook(
70            'AUTH_USER_CHANGE',
71            'BEFORE',
72            $this,
73            'handleUsermod'
74        );
75
76        // log admin actions triggered via Ajax
77        $controller->register_hook(
78            'AJAX_CALL_UNKNOWN',
79            'AFTER',
80            $this,
81            'handleAjax'
82        );
83
84        // log other admin actions
85        $controller->register_hook(
86            'DOKUWIKI_STARTED',
87            'AFTER',
88            $this,
89            'handleOther'
90        );
91
92        // log other admin actions
93        $controller->register_hook(
94            'INDEXER_TASKS_RUN',
95            'AFTER',
96            $this,
97            'handleReport'
98        );
99    }
100
101    /**
102     * Log login/logoff actions and optionally trigger alerts
103     * if configured thresholds have just been exceeded
104     *
105     * @param $msg
106     * @param null|string $user
107     */
108    protected function logAuth($msg, $user = null)
109    {
110        $this->logHelper->writeLine($msg, $user);
111
112        // trigger alert notifications if necessary
113        $this->alertHelper->checkAlertThresholds();
114    }
115
116    /**
117     * Log usage of admin tools
118     *
119     * @param array $data
120     * @param string $more
121     */
122    protected function logAdmin(array $data = [], $more = '')
123    {
124        global $INPUT;
125        $msg = 'admin';
126        $page = $INPUT->str('page');
127        if ($page) $msg .= " - $page";
128        if ($more && $more !== $page) $msg .= " - $more";
129        $this->logHelper->writeLine($msg,null, $data);
130    }
131
132    /**
133     * Handle custom logging events
134     *
135     * @param Doku_Event $event
136     * @param mixed $param data passed to the event handler
137     */
138    public function handleCustom(Doku_Event $event, $param)
139    {
140        if (isset($event->data['message'])) {
141            $log = $event->data['message'];
142        } else {
143            return;
144        }
145        if (isset($event->data['user'])) {
146            $user = $event->data['user'];
147        } else {
148            $user = null;
149        }
150
151        $this->logHelper->writeLine($log, $user);
152    }
153
154    /**
155     * Handle autologoffs by the autologout plugin
156     *
157     * @param Doku_Event $event
158     * @param mixed $param data passed to the event handler
159     */
160    public function handleAutologout(Doku_Event $event, $param)
161    {
162        $this->logAuth('has been automatically logged off');
163    }
164
165    /**
166     * catch standard logins/logouts, check if any alert notifications should be sent
167     *
168     * @param Doku_Event $event
169     * @param mixed $param data passed to the event handler
170     */
171    public function handleAuth(Doku_Event $event, $param)
172    {
173        // log authentication events
174        $act = act_clean($event->data);
175        if ($act == 'logout') {
176            $this->logAuth('logged off');
177        } elseif (!empty($_SERVER['REMOTE_USER']) && $act == 'login') {
178            if (isset($_REQUEST['r'])) {
179                $this->logAuth('logged in permanently');
180            } else {
181                $this->logAuth('logged in temporarily');
182            }
183        } elseif ($_REQUEST['u'] && empty($_REQUEST['http_credentials']) && empty($_SERVER['REMOTE_USER'])) {
184            $this->logAuth('failed login attempt');
185        }
186    }
187
188    /**
189     * Log access to admin pages
190     *
191     * @param Doku_Event $event
192     */
193    public function handleAdminAccess(Doku_Event $event)
194    {
195        global $ACT;
196        if ($ACT === 'admin') {
197            $this->logAdmin();
198        }
199    }
200
201    /**
202     * Log user modifications
203     *
204     * @param Doku_Event $event
205     */
206    public function handleUsermod(Doku_Event $event)
207    {
208        $modType = $event->data['type'];
209        $modUser = $event->data['params'][0];
210        if (is_array($modUser)) $modUser = implode(', ', $modUser);
211
212        // check if admin or user are modifying the data
213        global $ACT;
214        if ($ACT === 'profile') {
215            $this->logHelper->writeLine('user profile',null, [$modType . ' user', $modUser]);
216        } else {
217            $this->logAdmin([$modType . ' user', $modUser]);
218        }
219    }
220
221    /**
222     * Catch admin actions performed via Ajax
223     *
224     * @param Doku_Event $event
225     */
226    public function handleAjax(Doku_Event $event)
227    {
228        global $INPUT;
229
230        // extension manager
231        if ($event->data === 'plugin_extension') {
232            $this->logAdmin([$INPUT->str('act') . ' ' . $INPUT->str('ext')], 'extension');
233        }
234    }
235
236    /**
237     * Log activity in select core admin modules
238     *
239     * @param \Doku_Event $event
240     */
241    public function handleOther(\Doku_Event $event)
242    {
243        global $INPUT;
244
245        // configuration manager
246        if ($INPUT->str('page') === 'config'
247            && $INPUT->bool('save') === true
248            && !empty($INPUT->arr('config'))
249        ) {
250            $this->logAdmin(['save config']);
251        }
252
253        // extension manager
254        if ($INPUT->str('page') === 'extension') {
255            if ($INPUT->post->has('fn')) {
256                $actions = $INPUT->post->arr('fn');
257                foreach ($actions as $action => $extensions) {
258                    foreach ($extensions as $extname => $label) {
259                        $this->logAdmin([$action, $extname]);
260                    }
261                }
262            } elseif ($INPUT->post->str('installurl')) {
263                $this->logAdmin(['installurl', $INPUT->post->str('installurl')]);
264            } elseif (isset($_FILES['installfile'])) {
265                $this->logAdmin(['installfile', $_FILES['installfile']['name']]);
266            }
267        }
268
269        // ACL manager
270        if ($INPUT->str('page') === 'acl' && $INPUT->has('cmd')) {
271            $cmd = $INPUT->extract('cmd')->str('cmd');
272            $del = $INPUT->arr('del');
273            if ($cmd === 'update' && !empty($del)) {
274                $cmd = 'delete';
275                $rule = $del;
276            } else {
277                $rule = [
278                    'ns' => $INPUT->str('ns'),
279                    'acl_t' => $INPUT->str('acl_t'),
280                    'acl_w' => $INPUT->str('acl_w'),
281                    'acl' => $INPUT->str('acl')
282                ];
283            }
284
285            $this->logAdmin([$cmd, $rule]);
286        }
287    }
288
289    /**
290     * Handle monthly usage reports
291     *
292     * @param Doku_Event $event
293     */
294    public function handleReport(Doku_Event $event)
295    {
296        $reportHelper = new helper_plugin_loglog_report();
297        $reportHelper->handleReport();
298    }
299}
300
301