xref: /plugin/oauth/auth.php (revision 290e9b1f10bf4135eb82799dc58da0055064d995)
180852c15SAndreas Gohr<?php
23e7ac5b1SAndreas Gohr
3e170f465SAndreas Gohruse dokuwiki\plugin\oauth\OAuthManager;
4e170f465SAndreas Gohruse dokuwiki\plugin\oauth\Session;
5e170f465SAndreas Gohruse dokuwiki\Subscriptions\RegistrationSubscriptionSender;
6e170f465SAndreas Gohruse OAuth\Common\Exception\Exception as OAuthException;
7e170f465SAndreas Gohr
880852c15SAndreas Gohr/**
980852c15SAndreas Gohr * DokuWiki Plugin oauth (Auth Component)
1080852c15SAndreas Gohr *
1180852c15SAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
1280852c15SAndreas Gohr * @author  Andreas Gohr <andi@splitbrain.org>
1380852c15SAndreas Gohr */
143e7ac5b1SAndreas Gohrclass auth_plugin_oauth extends auth_plugin_authplain
153e7ac5b1SAndreas Gohr{
16e170f465SAndreas Gohr    /** @var helper_plugin_oauth */
17e170f465SAndreas Gohr    protected $hlp;
18e170f465SAndreas Gohr
19a1fa007aSNaoto Kobayashi    /** @var OAuthManager */
20a1fa007aSNaoto Kobayashi    protected $om;
21a1fa007aSNaoto Kobayashi
22e170f465SAndreas Gohr    // region standard auth methods
2380852c15SAndreas Gohr
243e7ac5b1SAndreas Gohr    /** @inheritDoc */
253e7ac5b1SAndreas Gohr    public function __construct()
263e7ac5b1SAndreas Gohr    {
27f10e09e2SAndreas Gohr        parent::__construct();
28f10e09e2SAndreas Gohr        $this->cando['external'] = true;
29e170f465SAndreas Gohr        $this->hlp = $this->loadHelper('oauth');
3080852c15SAndreas Gohr    }
3180852c15SAndreas Gohr
323e7ac5b1SAndreas Gohr    /** @inheritDoc */
33311a6606SAnna Dabrowska    public function trustExternal($user, $pass, $sticky = false)
343e7ac5b1SAndreas Gohr    {
35a02a5d81SAnna Dabrowska        global $INPUT;
36438dcc52SMichael Grosse
378523e9d0SAndreas Gohr        // handle redirects from farmer to animal wiki instances
388523e9d0SAndreas Gohr        if ($INPUT->has('state') && plugin_load('helper', 'farmer')) {
39d9be1cb5SAnna Dabrowska            $this->handleFarmState($INPUT->str('state'));
40438dcc52SMichael Grosse        }
4180852c15SAndreas Gohr
4274b4d4a4SAndreas Gohr        try {
4374b4d4a4SAndreas Gohr            // either oauth or "normal" plain auth login via form
44a1fa007aSNaoto Kobayashi            $this->om = new OAuthManager();
45568565b9SAndreas Gohr            if ($this->om->continueFlow()) return true;
461cdd3f90SAndreas Gohr            if ($this->getConf('singleService')) {
471cdd3f90SAndreas Gohr                return false; // no normal login in singleService mode
481cdd3f90SAndreas Gohr            }
49568565b9SAndreas Gohr            return null; // triggers the normal auth_login()
50e170f465SAndreas Gohr        } catch (OAuthException $e) {
51e170f465SAndreas Gohr            $this->hlp->showException($e);
5228002081SAndreas Gohr            auth_logoff(); // clears all session and cookie data
5374b4d4a4SAndreas Gohr            return false;
54a7a8f46aSAndreas Gohr        }
55a7a8f46aSAndreas Gohr    }
5680852c15SAndreas Gohr
57f2e164b0SMichael Große    /**
58311a6606SAnna Dabrowska     * Enhance function to check against duplicate emails
59311a6606SAnna Dabrowska     *
60e170f465SAndreas Gohr     * @inheritdoc
61311a6606SAnna Dabrowska     */
62311a6606SAnna Dabrowska    public function createUser($user, $pwd, $name, $mail, $grps = null)
63311a6606SAnna Dabrowska    {
64311a6606SAnna Dabrowska        if ($this->getUserByEmail($mail)) {
65311a6606SAnna Dabrowska            msg($this->getLang('emailduplicate'), -1);
66311a6606SAnna Dabrowska            return false;
67311a6606SAnna Dabrowska        }
68311a6606SAnna Dabrowska
69311a6606SAnna Dabrowska        return parent::createUser($user, $pwd, $name, $mail, $grps);
70311a6606SAnna Dabrowska    }
71311a6606SAnna Dabrowska
72311a6606SAnna Dabrowska    /**
73311a6606SAnna Dabrowska     * Enhance function to check against duplicate emails
74311a6606SAnna Dabrowska     *
75e170f465SAndreas Gohr     * @inheritdoc
76311a6606SAnna Dabrowska     */
77311a6606SAnna Dabrowska    public function modifyUser($user, $changes)
78311a6606SAnna Dabrowska    {
79311a6606SAnna Dabrowska        global $conf;
80311a6606SAnna Dabrowska
81311a6606SAnna Dabrowska        if (isset($changes['mail'])) {
82311a6606SAnna Dabrowska            $found = $this->getUserByEmail($changes['mail']);
83311a6606SAnna Dabrowska            if ($found && $found != $user) {
84311a6606SAnna Dabrowska                msg($this->getLang('emailduplicate'), -1);
85311a6606SAnna Dabrowska                return false;
86311a6606SAnna Dabrowska            }
87311a6606SAnna Dabrowska        }
88311a6606SAnna Dabrowska
89311a6606SAnna Dabrowska        $ok = parent::modifyUser($user, $changes);
90311a6606SAnna Dabrowska
91311a6606SAnna Dabrowska        // refresh session cache
92311a6606SAnna Dabrowska        touch($conf['cachedir'] . '/sessionpurge');
93311a6606SAnna Dabrowska        return $ok;
94311a6606SAnna Dabrowska    }
95311a6606SAnna Dabrowska
96311a6606SAnna Dabrowska    /**
97311a6606SAnna Dabrowska     * Unset additional stuff in session on logout
98311a6606SAnna Dabrowska     */
99311a6606SAnna Dabrowska    public function logOff()
100311a6606SAnna Dabrowska    {
101311a6606SAnna Dabrowska        parent::logOff();
102a1fa007aSNaoto Kobayashi        if (isset($this->om)) {
103a1fa007aSNaoto Kobayashi            $this->om->logout();
104a1fa007aSNaoto Kobayashi        }
105e170f465SAndreas Gohr        (Session::getInstance())->clear();
106311a6606SAnna Dabrowska    }
107311a6606SAnna Dabrowska
108e170f465SAndreas Gohr    // endregion
109e170f465SAndreas Gohr
110311a6606SAnna Dabrowska    /**
111e170f465SAndreas Gohr     * Register a new user logged in by oauth
112f2e164b0SMichael Große     *
113e170f465SAndreas Gohr     * It ensures the username is unique, by adding a number if needed.
114e170f465SAndreas Gohr     * Default and service name groups are set here.
115e170f465SAndreas Gohr     * Registration notifications are triggered.
116a02a5d81SAnna Dabrowska     *
117e170f465SAndreas Gohr     * @param array $userinfo This will be updated with the new username
118b2b9fbc7SMichael Große     * @param string $servicename
119b2b9fbc7SMichael Große     *
120b2b9fbc7SMichael Große     * @return bool
121e170f465SAndreas Gohr     * @todo - should this be part of the OAuthManager class instead?
122b2b9fbc7SMichael Große     */
123e170f465SAndreas Gohr    public function registerOAuthUser(&$userinfo, $servicename)
1243e7ac5b1SAndreas Gohr    {
125b2b9fbc7SMichael Große        global $conf;
126a02a5d81SAnna Dabrowska        $user = $userinfo['user'];
127b2b9fbc7SMichael Große        $count = '';
128b2b9fbc7SMichael Große        while ($this->getUserData($user . $count)) {
129b2b9fbc7SMichael Große            if ($count) {
130b2b9fbc7SMichael Große                $count++;
131b2b9fbc7SMichael Große            } else {
132b2b9fbc7SMichael Große                $count = 1;
133b2b9fbc7SMichael Große            }
134b2b9fbc7SMichael Große        }
135*290e9b1fSAndreas Gohr        $user .= $count;
136a02a5d81SAnna Dabrowska        $userinfo['user'] = $user;
137e170f465SAndreas Gohr        $groups_on_creation = [];
138b2b9fbc7SMichael Große        $groups_on_creation[] = $conf['defaultgroup'];
139b2b9fbc7SMichael Große        $groups_on_creation[] = $this->cleanGroup($servicename); // add service as group
140a02a5d81SAnna Dabrowska        $userinfo['grps'] = array_merge((array)$userinfo['grps'], $groups_on_creation);
141b2b9fbc7SMichael Große
142e170f465SAndreas Gohr        // the password set here will remain unknown to the user
143b2b9fbc7SMichael Große        $ok = $this->triggerUserMod(
144b2b9fbc7SMichael Große            'create',
145e170f465SAndreas Gohr            [
146e170f465SAndreas Gohr                $user,
147e170f465SAndreas Gohr                auth_pwgen($user),
148e170f465SAndreas Gohr                $userinfo['name'],
149e170f465SAndreas Gohr                $userinfo['mail'],
1504928b245SAndreas Gohr                $userinfo['grps'],
151e170f465SAndreas Gohr            ]
152b2b9fbc7SMichael Große        );
153b2b9fbc7SMichael Große        if (!$ok) {
154b2b9fbc7SMichael Große            return false;
155b2b9fbc7SMichael Große        }
156b2b9fbc7SMichael Große
157e170f465SAndreas Gohr        // send notification about the new user
158e170f465SAndreas Gohr        $subscriptionSender = new RegistrationSubscriptionSender();
159e170f465SAndreas Gohr        $subscriptionSender->sendRegister($user, $userinfo['name'], $userinfo['mail']);
160e170f465SAndreas Gohr
161b2b9fbc7SMichael Große        return true;
162b2b9fbc7SMichael Große    }
163b2b9fbc7SMichael Große
164b2b9fbc7SMichael Große    /**
165a02a5d81SAnna Dabrowska     * Find a user by email address
166b2b9fbc7SMichael Große     *
167b2b9fbc7SMichael Große     * @param $mail
168b2b9fbc7SMichael Große     * @return bool|string
169b2b9fbc7SMichael Große     */
17074b4d4a4SAndreas Gohr    public function getUserByEmail($mail)
1713e7ac5b1SAndreas Gohr    {
1728b214edcSAndreas Gohr        if ($this->users === null) {
1738b214edcSAndreas Gohr            $this->loadUserData();
1748b214edcSAndreas Gohr        }
175b2b9fbc7SMichael Große        $mail = strtolower($mail);
176b2b9fbc7SMichael Große
177a02a5d81SAnna Dabrowska        foreach ($this->users as $user => $userinfo) {
178*290e9b1fSAndreas Gohr            if (strtolower($userinfo['mail']) === $mail) return $user;
179b2b9fbc7SMichael Große        }
180b2b9fbc7SMichael Große
181b2b9fbc7SMichael Große        return false;
182b2b9fbc7SMichael Große    }
183b2b9fbc7SMichael Große
184b2b9fbc7SMichael Große    /**
1852a8b22d5SAndreas Gohr     * Fall back to plain auth strings
1862a8b22d5SAndreas Gohr     *
1872a8b22d5SAndreas Gohr     * @inheritdoc
1882a8b22d5SAndreas Gohr     */
1892a8b22d5SAndreas Gohr    public function getLang($id)
1902a8b22d5SAndreas Gohr    {
1912a8b22d5SAndreas Gohr        $result = parent::getLang($id);
1922a8b22d5SAndreas Gohr        if ($result) return $result;
1932a8b22d5SAndreas Gohr
1942a8b22d5SAndreas Gohr        $parent = new auth_plugin_authplain();
1952a8b22d5SAndreas Gohr        return $parent->getLang($id);
1962a8b22d5SAndreas Gohr    }
1972a8b22d5SAndreas Gohr
1982a8b22d5SAndreas Gohr    /**
199b8ca6a42SAnna Dabrowska     * Farmer plugin support
200b8ca6a42SAnna Dabrowska     *
201b8ca6a42SAnna Dabrowska     * When coming back to farmer instance via OAUTH redirectURI, we need to redirect again
202b8ca6a42SAnna Dabrowska     * to a proper animal instance detected from $state
203b2b9fbc7SMichael Große     *
204311a6606SAnna Dabrowska     * @param $state
205b2b9fbc7SMichael Große     */
206e170f465SAndreas Gohr    protected function handleFarmState($state)
2073e7ac5b1SAndreas Gohr    {
208311a6606SAnna Dabrowska        /** @var \helper_plugin_farmer $farmer */
209311a6606SAnna Dabrowska        $farmer = plugin_load('helper', 'farmer', false, true);
210311a6606SAnna Dabrowska        $data = json_decode(base64_decode(urldecode($state)));
211311a6606SAnna Dabrowska        if (empty($data->animal) || $farmer->getAnimal() == $data->animal) {
212311a6606SAnna Dabrowska            return;
213827232fcSMichael Große        }
214311a6606SAnna Dabrowska        $animal = $data->animal;
215311a6606SAnna Dabrowska        $allAnimals = $farmer->getAllAnimals();
216311a6606SAnna Dabrowska        if (!in_array($animal, $allAnimals)) {
217311a6606SAnna Dabrowska            msg('Animal ' . $animal . ' does not exist!');
218311a6606SAnna Dabrowska            return;
219827232fcSMichael Große        }
220311a6606SAnna Dabrowska        global $INPUT;
221311a6606SAnna Dabrowska        $url = $farmer->getAnimalURL($animal) . '/doku.php?' . $INPUT->server->str('QUERY_STRING');
222311a6606SAnna Dabrowska        send_redirect($url);
223b2b9fbc7SMichael Große    }
224b2b9fbc7SMichael Große}
225