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