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 
9 class 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