xref: /plugin/oauth/action/login.php (revision 542bb44dbfd29ec513ba8fcff2654aa2a64a346a)
1<?php
2
3use dokuwiki\Form\Form;
4use dokuwiki\plugin\oauth\OAuthManager;
5use OAuth\Common\Http\Exception\TokenResponseException;
6
7/**
8 * DokuWiki Plugin oauth (Action Component)
9 *
10 * This adds buttons to the login page and initializes the oAuth flow by redirecting the user
11 * to the third party service
12 *
13 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
14 * @author  Andreas Gohr <andi@splitbrain.org>
15 */
16class action_plugin_oauth_login extends DokuWiki_Action_Plugin
17{
18    /** @var helper_plugin_oauth */
19    protected $hlp;
20
21    /**
22     * Constructor
23     *
24     * Initializes the helper
25     */
26    public function __construct()
27    {
28        $this->hlp = plugin_load('helper', 'oauth');
29    }
30
31    /**
32     * Registers a callback function for a given event
33     *
34     * @param Doku_Event_Handler $controller DokuWiki's event controller object
35     * @return void
36     */
37    public function register(Doku_Event_Handler $controller)
38    {
39        global $conf;
40        if ($conf['authtype'] != 'oauth') return;
41
42        $conf['profileconfirm'] = false; // password confirmation doesn't work with oauth only users
43
44        $controller->register_hook('DOKUWIKI_STARTED', 'BEFORE', $this, 'handleStart');
45        $controller->register_hook('HTML_LOGINFORM_OUTPUT', 'BEFORE', $this, 'handleOldLoginForm'); // @deprecated
46        $controller->register_hook('FORM_LOGIN_OUTPUT', 'BEFORE', $this, 'handleLoginForm');
47        $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handleDoLogin');
48        $controller->register_hook('ACTION_DENIED_TPLCONTENT', 'BEFORE', $this, 'handleDeniedForm');
49    }
50
51    /**
52     * Start an oAuth login or restore  environment after successful login
53     *
54     * @param Doku_Event $event
55     * @return void
56     */
57    public function handleStart(Doku_Event $event)
58    {
59        global $INPUT;
60
61        // see if a login needs to be started
62        $servicename = $INPUT->str('oauthlogin');
63        if (!$servicename) return;
64
65        try {
66            $om = new OAuthManager();
67            $om->startFlow($servicename);
68        } catch (TokenResponseException|Exception $e) {
69            $this->hlp->showException($e, 'login failed');
70        }
71    }
72
73    /**
74     * Add the oAuth login links to login form
75     *
76     * @param Doku_Event $event event object by reference
77     * @return void
78     * @deprecated can be removed in the future
79     */
80    public function handleOldLoginForm(Doku_Event $event)
81    {
82        /** @var Doku_Form $form */
83        $form = $event->data;
84        $html = $this->prepareLoginButtons();
85        if (!$html) return;
86
87        // remove login form if single service is set
88        $singleService = $this->getConf('singleService');
89        if ($singleService) {
90            $form->_content = [];
91        }
92
93        $form->_content[] = form_openfieldset(
94            [
95                '_legend' => $this->getLang('loginwith'),
96                'class' => 'plugin_oauth',
97            ]
98        );
99        $form->_content[] = $html;
100        $form->_content[] = form_closefieldset();
101    }
102
103    /**
104     * Add the oAuth login links to login form
105     *
106     * @param Doku_Event $event event object by reference
107     * @return void
108     * @deprecated can be removed in the future
109     */
110    public function handleLoginForm(Doku_Event $event)
111    {
112        /** @var Form $form */
113        $form = $event->data;
114        $html = $this->prepareLoginButtons();
115        if (!$html) return;
116
117        // remove login form if single service is set
118        $singleService = $this->getConf('singleService');
119        if ($singleService) {
120            do {
121                $form->removeElement(0);
122            } while ($form->elementCount() > 0);
123        }
124
125        $form->addFieldsetOpen($this->getLang('loginwith'))->addClass('plugin_oauth');
126        $form->addHTML($html);
127        $form->addFieldsetClose();
128    }
129
130    /**
131     * Create HTML for the various login buttons
132     *
133     * @return string the HTML
134     */
135    protected function prepareLoginButtons()
136    {
137        $html = '';
138
139        $validDomains = $this->hlp->getValidDomains();
140
141        if (count($validDomains) > 0) {
142            $html .= '<p class="plugin-oauth-emailrestriction">' . sprintf(
143                    $this->getLang('eMailRestricted'),
144                    '<b>' . join(', ', $validDomains) . '</b>'
145                ) . '</p>';
146        }
147
148        $html .= '<div>';
149        foreach ($this->hlp->listServices() as $service) {
150            $html .= $service->loginButton();
151        }
152        $html .= '</div>';
153
154        return $html;
155    }
156
157    /**
158     * When singleservice is wanted, do not show login, but execute login right away
159     *
160     * @param Doku_Event $event
161     * @return bool
162     */
163    public function handleDoLogin(Doku_Event $event)
164    {
165        global $ID;
166        global $INPUT;
167
168        if ($event->data != 'login' && $event->data != 'denied') return true;
169
170        $singleService = $this->getConf('singleService');
171        if (!$singleService) return true;
172
173        if ($INPUT->server->str('REMOTE_USER') !== '') {
174            // already logged in
175            return true;
176        }
177
178        $enabledServices = $this->hlp->listServices();
179        if (count($enabledServices) !== 1) {
180            msg($this->getLang('wrongConfig'), -1);
181            return false;
182        }
183
184        $service = array_shift($enabledServices);
185
186        $url = wl($ID, ['oauthlogin' => $service->getServiceID()], true, '&');
187        send_redirect($url);
188        return true; // never reached
189    }
190
191    /**
192     * Do not show a login form on restricted pages when SingleService is enabled
193     *
194     * This can happen when the user is already logged in, but still doesn't have enough permissions
195     *
196     * @param Doku_Event $event
197     * @return void
198     */
199    public function handleDeniedForm(Doku_Event $event)
200    {
201        if ($this->getConf('singleService')) {
202            $event->preventDefault();
203            $event->stopPropagation();
204        }
205    }
206}
207