xref: /plugin/oauth/auth.php (revision 45fc651dfa4d39f84fada97824bab8f6b1e7782c)
1<?php
2
3use dokuwiki\plugin\oauth\OAuthManager;
4use dokuwiki\plugin\oauth\Session;
5use dokuwiki\Subscriptions\RegistrationSubscriptionSender;
6use OAuth\Common\Exception\Exception as OAuthException;
7
8/**
9 * DokuWiki Plugin oauth (Auth Component)
10 *
11 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
12 * @author  Andreas Gohr <andi@splitbrain.org>
13 */
14class auth_plugin_oauth extends auth_plugin_authplain
15{
16    /** @var helper_plugin_oauth */
17    protected $hlp;
18
19    /** @var OAuthManager */
20    protected $om;
21
22    // region standard auth methods
23
24    /** @inheritDoc */
25    public function __construct()
26    {
27        parent::__construct();
28        $this->cando['external'] = true;
29        $this->hlp = $this->loadHelper('oauth');
30    }
31
32    /** @inheritDoc */
33    public function trustExternal($user, $pass, $sticky = false)
34    {
35        global $INPUT;
36
37        // handle redirects from farmer to animal wiki instances
38        if ($INPUT->has('state') && plugin_load('helper', 'farmer')) {
39            $this->handleFarmState($INPUT->str('state'));
40        }
41
42        try {
43            // either oauth or "normal" plain auth login via form
44            $this->om = new OAuthManager();
45            return $this->om->continueFlow() || auth_login($user, $pass, $sticky);
46        } catch (OAuthException $e) {
47            $this->hlp->showException($e);
48            auth_logoff(); // clears all session and cookie data
49            return false;
50        }
51    }
52
53    /**
54     * Enhance function to check against duplicate emails
55     *
56     * @inheritdoc
57     */
58    public function createUser($user, $pwd, $name, $mail, $grps = null)
59    {
60        if ($this->getUserByEmail($mail)) {
61            msg($this->getLang('emailduplicate'), -1);
62            return false;
63        }
64
65        return parent::createUser($user, $pwd, $name, $mail, $grps);
66    }
67
68    /**
69     * Enhance function to check against duplicate emails
70     *
71     * @inheritdoc
72     */
73    public function modifyUser($user, $changes)
74    {
75        global $conf;
76
77        if (isset($changes['mail'])) {
78            $found = $this->getUserByEmail($changes['mail']);
79            if ($found && $found != $user) {
80                msg($this->getLang('emailduplicate'), -1);
81                return false;
82            }
83        }
84
85        $ok = parent::modifyUser($user, $changes);
86
87        // refresh session cache
88        touch($conf['cachedir'] . '/sessionpurge');
89        return $ok;
90    }
91
92    /**
93     * Unset additional stuff in session on logout
94     */
95    public function logOff()
96    {
97        parent::logOff();
98        if (isset($this->om)) {
99            $this->om->logout();
100        }
101        (Session::getInstance())->clear();
102    }
103
104    // endregion
105
106    /**
107     * Register a new user logged in by oauth
108     *
109     * It ensures the username is unique, by adding a number if needed.
110     * Default and service name groups are set here.
111     * Registration notifications are triggered.
112     *
113     * @param array $userinfo This will be updated with the new username
114     * @param string $servicename
115     *
116     * @return bool
117     * @todo - should this be part of the OAuthManager class instead?
118     */
119    public function registerOAuthUser(&$userinfo, $servicename)
120    {
121        global $conf;
122        $user = $userinfo['user'];
123        $count = '';
124        while ($this->getUserData($user . $count)) {
125            if ($count) {
126                $count++;
127            } else {
128                $count = 1;
129            }
130        }
131        $user = $user . $count;
132        $userinfo['user'] = $user;
133        $groups_on_creation = [];
134        $groups_on_creation[] = $conf['defaultgroup'];
135        $groups_on_creation[] = $this->cleanGroup($servicename); // add service as group
136        $userinfo['grps'] = array_merge((array)$userinfo['grps'], $groups_on_creation);
137
138        // the password set here will remain unknown to the user
139        $ok = $this->triggerUserMod(
140            'create',
141            [
142                $user,
143                auth_pwgen($user),
144                $userinfo['name'],
145                $userinfo['mail'],
146                $userinfo['grps'],
147            ]
148        );
149        if (!$ok) {
150            return false;
151        }
152
153        // send notification about the new user
154        $subscriptionSender = new RegistrationSubscriptionSender();
155        $subscriptionSender->sendRegister($user, $userinfo['name'], $userinfo['mail']);
156
157        return true;
158    }
159
160    /**
161     * Find a user by email address
162     *
163     * @param $mail
164     * @return bool|string
165     */
166    public function getUserByEmail($mail)
167    {
168        if ($this->users === null) {
169            $this->loadUserData();
170        }
171        $mail = strtolower($mail);
172
173        foreach ($this->users as $user => $userinfo) {
174            if (strtolower($userinfo['mail']) == $mail) return $user;
175        }
176
177        return false;
178    }
179
180    /**
181     * Fall back to plain auth strings
182     *
183     * @inheritdoc
184     */
185    public function getLang($id)
186    {
187        $result = parent::getLang($id);
188        if($result) return $result;
189
190        $parent = new auth_plugin_authplain();
191        return $parent->getLang($id);
192    }
193
194    /**
195     * Farmer plugin support
196     *
197     * When coming back to farmer instance via OAUTH redirectURI, we need to redirect again
198     * to a proper animal instance detected from $state
199     *
200     * @param $state
201     */
202    protected function handleFarmState($state)
203    {
204        /** @var \helper_plugin_farmer $farmer */
205        $farmer = plugin_load('helper', 'farmer', false, true);
206        $data = json_decode(base64_decode(urldecode($state)));
207        if (empty($data->animal) || $farmer->getAnimal() == $data->animal) {
208            return;
209        }
210        $animal = $data->animal;
211        $allAnimals = $farmer->getAllAnimals();
212        if (!in_array($animal, $allAnimals)) {
213            msg('Animal ' . $animal . ' does not exist!');
214            return;
215        }
216        global $INPUT;
217        $url = $farmer->getAnimalURL($animal) . '/doku.php?' . $INPUT->server->str('QUERY_STRING');
218        send_redirect($url);
219    }
220}
221