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