xref: /plugin/oauth/action/login.php (revision 74b4d4a4cf1d79813740d8ba18696e5fb2b4089b)
1<?php
2
3use dokuwiki\Form\Form;
4use dokuwiki\plugin\oauth\SessionManager;
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    }
49
50    /**
51     * Start an oAuth login or restore  environment after successful login
52     *
53     * @param Doku_Event $event
54     * @return void
55     */
56    public function handleStart(Doku_Event $event)
57    {
58        global $INPUT;
59
60        // login has been done, but there's environment to be restored
61        // TODO when is this the case?
62        $sessionManager = SessionManager::getInstance();
63        if ($sessionManager->getDo() || $sessionManager->getRev()) {
64            $this->restoreSessionEnvironment();
65            return;
66        }
67
68        // see if a login needs to be started
69        $servicename = $INPUT->str('oauthlogin');
70        if ($servicename) $this->startOAuthLogin($servicename);
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        $form->_content[] = form_openfieldset(
88            [
89                '_legend' => $this->getLang('loginwith'),
90                'class' => 'plugin_oauth',
91            ]
92        );
93        $form->_content[] = $html;
94        $form->_content[] = form_closefieldset();
95    }
96
97    /**
98     * Add the oAuth login links to login form
99     *
100     * @param Doku_Event $event event object by reference
101     * @return void
102     * @deprecated can be removed in the future
103     */
104    public function handleLoginForm(Doku_Event $event)
105    {
106        /** @var Form $form */
107        $form = $event->data;
108        $html = $this->prepareLoginButtons();
109        if (!$html) return;
110
111        $form->addFieldsetOpen($this->getLang('loginwith'))->addClass('plugin_oauth');
112        $form->addHTML($html);
113        $form->addFieldsetClose();
114    }
115
116    /**
117     * Create HTML for the various login buttons
118     *
119     * @return string the HTML
120     */
121    protected function prepareLoginButtons()
122    {
123        $html = '';
124
125        $validDomains = $this->hlp->getValidDomains();
126
127        if (count($validDomains) > 0) {
128            $html .= '<p class="plugin-oauth-emailrestriction">' . sprintf(
129                    $this->getLang('eMailRestricted'),
130                    '<b>' . join(', ', $validDomains) . '</b>'
131                ) . '</p>';
132        }
133
134        foreach ($this->hlp->listServices() as $service) {
135            $html .= $service->loginButton();
136        }
137
138        return $html;
139    }
140
141    /**
142     * When singleservice is wanted, do not show login, but execute login right away
143     *
144     * @param Doku_Event $event
145     * @return bool
146     */
147    public function handleDoLogin(Doku_Event $event)
148    {
149        global $ID;
150
151        if ($event->data != 'login') return true;
152
153        $singleService = $this->getConf('singleService');
154        if (!$singleService) return true;
155
156        $enabledServices = $this->hlp->listServices();
157        if (count($enabledServices) !== 1) {
158            msg($this->getLang('wrongConfig'), -1);
159            return false;
160        }
161
162        $service = array_shift($enabledServices);
163
164        $url = wl($ID, ['oauthlogin' => $service->getServiceID()], true, '&');
165        send_redirect($url);
166        return true; // never reached
167    }
168
169    /**
170     * start the oauth login
171     *
172     * This will redirect to the external service and stop processing in this request.
173     * The second part of the login will happen in auth
174     *
175     * @see auth_plugin_oauth
176     */
177    protected function startOAuthLogin($servicename)
178    {
179        global $ID;
180//        $service = $this->hlp->loadService($servicename);
181//        if (is_null($service)) return;
182//
183//        // remember service in session
184//        $sessionManager = SessionManager::getInstance();
185//        $sessionManager->setServiceName($servicename);
186//        $sessionManager->setPid($ID);
187//        $sessionManager->saveState();
188
189        try {
190            $om = new \dokuwiki\plugin\oauth\OAuthManager();
191            $om->startFlow($servicename);
192        } catch (TokenResponseException|Exception $e) {
193            $this->hlp->showException($e, 'login failed');
194        }
195    }
196
197    /**
198     * Restore the request environment that had been set before the oauth shuffle
199     * @todo this should be handled by the session manager, if we really need it
200     */
201    protected function restoreSessionEnvironment()
202    {
203        global $INPUT, $ACT, $TEXT, $PRE, $SUF, $SUM, $RANGE, $DATE_AT, $REV;
204
205        $sessionManager = SessionManager::getInstance();
206        $ACT = $sessionManager->getDo();
207        $_REQUEST = $sessionManager->getRequest();
208
209        $REV = $INPUT->int('rev');
210        $DATE_AT = $INPUT->str('at');
211        $RANGE = $INPUT->str('range');
212        if ($INPUT->post->has('wikitext')) {
213            $TEXT = cleanText($INPUT->post->str('wikitext'));
214        }
215        $PRE = cleanText(substr($INPUT->post->str('prefix'), 0, -1));
216        $SUF = cleanText($INPUT->post->str('suffix'));
217        $SUM = $INPUT->post->str('summary');
218
219        $sessionManager->setDo('');
220        $sessionManager->setRequest([]);
221        $sessionManager->saveState();
222    }
223}
224