1<?php
2/**
3 * DokuWiki HTTP authentication plugin
4 * https://www.dokuwiki.org/plugin:authhttp
5 *
6 * This is authhttp's action plugin which
7 * a.) skips the 'login' action as it does not make sense with HTTP
8 *     authentication.
9 * b.) modifies DokuWiki's register form so that
10 *     i.) the username is hard-coded to match the username from the
11 *         HTTP authentication.
12 *     ii.) the password text fields are replaced by hidden fields with
13 *          a random password that won't do any harm.
14 *
15 * All of this code ONLY applies when DokuWiki's configured auth plugin is authsplit
16 * (https://www.dokuwiki.org/plugin:authsplit) and authhttp is its primary auth plugin.
17 * If authhttp is used on its own (ie. as DokuWiki's auth plugin), users will never
18 * see a login or a register screen anyway.
19 *
20 * @license GPL 3 http://www.gnu.org/licenses/gpl-3.0.html
21 * @author  Pieter Hollants <pieter@hollants.com>
22 */
23
24// must be run within Dokuwiki
25if(!defined('DOKU_INC')) die();
26
27/* We have to distinguish between the plugin being loaded and the plugin
28   actually being used for authentication. */
29$active = (
30    $conf['authtype'] == 'authhttp' ||
31    (
32        $conf['authtype'] == 'authsplit' &&
33        $conf['plugin']['authsplit']['primary_authplugin'] == 'authhttp'
34    )
35);
36
37class action_plugin_authhttp extends DokuWiki_Action_Plugin {
38    public function __construct() {
39        global $conf, $active;
40
41        if ($active) {
42            /* We register an event handler to skip the login action below, but
43               we also don't want the template to show a 'login' link in the
44               first place.
45
46               DokuWiki has no capability setting for 'login', so we need a
47               little hack that pretends the admin disabled the login action
48               himself. */
49            $disableactions = explode(',', $conf['disableactions']);
50            $disableactions = array_map('trim', $disableactions);
51            if (!in_array('login', $disableactions)) {
52                $disableactions[] = 'login';
53            }
54            $conf['disableactions'] = implode(',', $disableactions);
55
56            /* We also don't want DokuWiki to generate passwords on its own and
57               mail them to the users upon registration. We need to use the same
58               hack as above, pretending the admin disabled password generation
59               himself. */
60            $conf['autopasswd'] = 0;
61        }
62    }
63
64    /**
65     * Register the event handlers
66     */
67    function register(Doku_Event_Handler $controller){
68        global $active;
69
70        if ($active) {
71            $controller->register_hook('ACTION_ACT_PREPROCESS',
72                                       'AFTER',
73                                       $this,
74                                       'skip_login_action',
75                                       NULL);
76
77            /* Legacy DokuWiki releases with old form class */
78            $controller->register_hook('HTML_REGISTERFORM_OUTPUT',
79                                       'BEFORE',
80                                       $this,
81                                       'modify_register_form_legacy',
82                                       NULL);
83
84            /* Newer DokuWiki releases with rewritten form class */
85            $controller->register_hook('REGISTERFORM_OUTPUT',
86                                       'BEFORE',
87                                       $this,
88                                       'modify_register_form',
89                                       NULL);
90        }
91    }
92
93    /**
94     * Event handler to skip the 'login' action
95     */
96    function skip_login_action(&$event, $param) {
97        /* Some actions handled in inc/actions.php:act_dispatch() result in $ACT
98           being modified to 'login', eg. 'register'. */
99        if ($event->data == 'login') {
100            /* With HTTP authentication, there is no sense in showing a login form,
101               so we directly redirect to a 'show' action instead. By using
102               act_redirect() instead of modifying $event->data, we make sure
103               DokuWiki's entire auth logic can work, which is eg. required so that
104               after a user's registration he gets logged in automatically. */
105            act_redirect($ID, 'show');
106        }
107    }
108
109    /**
110     * Event handler to modify the registration form
111     * Version for legacy DokuWiki releases with old form class
112     */
113    function modify_register_form_legacy(&$event, $param) {
114        $form = $event->data;
115
116        /* Hard-code the HTTP authentication user name as login name for registration as
117           registering as anyone else than the already externally authenticated user does
118           not make much sense. */
119        $pos = $form->findElementByAttribute('name', 'login');
120        if (!$pos)
121            return;
122        $elem = $form->getElementAt($pos);
123        $elem['value'] = $_SERVER['PHP_AUTH_USER'];
124        $elem['readonly'] = 'readonly';
125        $form->replaceElement($pos, $elem);
126
127        /* We do not want DokuWiki to auto-generate a password and mail it to the user.
128           Then, however, inc/auth.php's register() will insist on a non-null password,
129           so we supply a random one in hidden form fields. As this code only runs when
130           both authhttp AND authsplit are active, the password won't end up anywhere
131           since authhttp is the primary auth plugin in that case and does not offer the
132           modPass capability. */
133        $pwd = auth_pwgen();
134        foreach (array('pass', 'passchk') as $name) {
135            $pos = $form->findElementByAttribute('name', $name);
136            $form->replaceElement($pos, NULL);
137            $form->addHidden($name, $pwd);
138        }
139    }
140
141    /**
142     * Event handler to modify the registration form
143     * Version for newer DokuWiki releases with rewritten form class
144     */
145    function modify_register_form(&$event, $param) {
146        $form = $event->data;
147
148        /* Hard-code the HTTP authentication user name as login name for registration as
149           registering as anyone else than the already externally authenticated user does
150           not make much sense. */
151        $pos = $form->findPositionByAttribute('name', 'login');
152        if (!$pos)
153            return;
154        $elem = $form->getElementAt($pos);
155        $elem['value'] = $_SERVER['PHP_AUTH_USER'];
156        $elem['readonly'] = 'readonly';
157        $form->replaceElement($elem, $pos);
158
159        /* We do not want DokuWiki to auto-generate a password and mail it to the user.
160           Then, however, inc/auth.php's register() will insist on a non-null password,
161           so we supply a random one in hidden form fields. As this code only runs when
162           both authhttp AND authsplit are active, the password won't end up anywhere
163           since authhttp is the primary auth plugin in that case and does not offer the
164           modPass capability. */
165        $pwd = auth_pwgen();
166        foreach (array('pass', 'passchk') as $name) {
167            $pos = $form->findPositionByAttribute('name', $name);
168            $form->replaceElement(NULL, $pos);
169            $form->setHiddenField($name, $pwd);
170        }
171    }
172}
173