xref: /plugin/oauth/auth.php (revision 2e94f0b8bfa63adcf4d6ecc092b35a59dde77be3)
180852c15SAndreas Gohr<?php
280852c15SAndreas Gohr/**
380852c15SAndreas Gohr * DokuWiki Plugin oauth (Auth Component)
480852c15SAndreas Gohr *
580852c15SAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
680852c15SAndreas Gohr * @author  Andreas Gohr <andi@splitbrain.org>
780852c15SAndreas Gohr */
880852c15SAndreas Gohr
980852c15SAndreas Gohr// must be run within Dokuwiki
1080852c15SAndreas Gohrif(!defined('DOKU_INC')) die();
1180852c15SAndreas Gohr
12f10e09e2SAndreas Gohrclass auth_plugin_oauth extends auth_plugin_authplain {
1380852c15SAndreas Gohr
14f866280eSAndreas Gohr    /**
15f866280eSAndreas Gohr     * Constructor
16f866280eSAndreas Gohr     *
17f866280eSAndreas Gohr     * Sets capabilities.
18f866280eSAndreas Gohr     */
1980852c15SAndreas Gohr    public function __construct() {
20f10e09e2SAndreas Gohr        parent::__construct();
2180852c15SAndreas Gohr
22f10e09e2SAndreas Gohr        $this->cando['external'] = true;
2380852c15SAndreas Gohr    }
2480852c15SAndreas Gohr
25f866280eSAndreas Gohr    /**
26f866280eSAndreas Gohr     * Handle the login
27f866280eSAndreas Gohr     *
28f866280eSAndreas Gohr     * This either trusts the session data (if any), processes the second oAuth step or simply
29f866280eSAndreas Gohr     * executes a normal plugin against local users.
30f866280eSAndreas Gohr     *
31f866280eSAndreas Gohr     * @param string $user
32f866280eSAndreas Gohr     * @param string $pass
33f866280eSAndreas Gohr     * @param bool   $sticky
34f866280eSAndreas Gohr     * @return bool
35f866280eSAndreas Gohr     */
36f10e09e2SAndreas Gohr    function trustExternal($user, $pass, $sticky = false) {
37a7a8f46aSAndreas Gohr        global $conf;
38a7a8f46aSAndreas Gohr        global $USERINFO;
3980852c15SAndreas Gohr
40*2e94f0b8SAndreas Gohr        // are we in login progress?
41*2e94f0b8SAndreas Gohr        if(isset($_SESSION[DOKU_COOKIE]['oauth-inprogress'])) {
42*2e94f0b8SAndreas Gohr            $servicename = $_SESSION[DOKU_COOKIE]['oauth-inprogress']['service'];
43*2e94f0b8SAndreas Gohr            $page        = $_SESSION[DOKU_COOKIE]['oauth-inprogress']['id'];
44*2e94f0b8SAndreas Gohr
45*2e94f0b8SAndreas Gohr            unset($_SESSION[DOKU_COOKIE]['oauth-inprogress']);
46*2e94f0b8SAndreas Gohr        }
4780852c15SAndreas Gohr
48a7a8f46aSAndreas Gohr        // check session for existing oAuth login data
49a7a8f46aSAndreas Gohr        $session = $_SESSION[DOKU_COOKIE]['auth'];
50*2e94f0b8SAndreas Gohr        if(!isset($servicename) && isset($session['oauth'])) {
51a7a8f46aSAndreas Gohr            $servicename = $session['oauth'];
52a7a8f46aSAndreas Gohr            // check if session data is still considered valid
53a7a8f46aSAndreas Gohr            if(($session['time'] >= time() - $conf['auth_security_timeout']) &&
54f866280eSAndreas Gohr                ($session['buid'] == auth_browseruid())
55f866280eSAndreas Gohr            ) {
5680852c15SAndreas Gohr
57a7a8f46aSAndreas Gohr                $_SERVER['REMOTE_USER'] = $session['user'];
58a7a8f46aSAndreas Gohr                $USERINFO               = $session['info'];
5980852c15SAndreas Gohr                return true;
60f10e09e2SAndreas Gohr            }
6180852c15SAndreas Gohr        }
6280852c15SAndreas Gohr
63a7a8f46aSAndreas Gohr        // either we're in oauth login or a previous log needs to be rechecked
64*2e94f0b8SAndreas Gohr        if(isset($servicename)) {
65a7a8f46aSAndreas Gohr            /** @var helper_plugin_oauth $hlp */
66a7a8f46aSAndreas Gohr            $hlp     = plugin_load('helper', 'oauth');
67a7a8f46aSAndreas Gohr            $service = $hlp->loadService($servicename);
68a7a8f46aSAndreas Gohr            if(is_null($service)) return false;
69a7a8f46aSAndreas Gohr
70a7a8f46aSAndreas Gohr            // get the token
71a7a8f46aSAndreas Gohr            if($service->checkToken()) {
72a7a8f46aSAndreas Gohr                $uinfo = $service->getUser();
73f866280eSAndreas Gohr
741025aad7SAndreas Gohr                $uinfo['user'] = $this->cleanUser((string) $uinfo['user']);
751025aad7SAndreas Gohr                if(!$uinfo['name']) $uinfo['name'] = $uinfo['user'];
761025aad7SAndreas Gohr
771025aad7SAndreas Gohr                if(!$uinfo['user'] || !$uinfo['mail']) {
781025aad7SAndreas Gohr                    msg("$servicename did not provide the needed user info. Can't log you in", -1);
791025aad7SAndreas Gohr                    return false;
801025aad7SAndreas Gohr                }
811025aad7SAndreas Gohr
82f866280eSAndreas Gohr                // see if the user is known already
83f866280eSAndreas Gohr                $user = $this->getUserByEmail($uinfo['mail']);
84f866280eSAndreas Gohr                if($user) {
85f866280eSAndreas Gohr                    $sinfo = $this->getUserData($user);
863c0138dbSAndreas Gohr                    // check if the user allowed access via this service
873c0138dbSAndreas Gohr                    if(!in_array($this->cleanGroup($servicename), $sinfo['grps'])) {
883c0138dbSAndreas Gohr                        msg(sprintf($this->getLang('authnotenabled'), $servicename), -1);
893c0138dbSAndreas Gohr                        return false;
903c0138dbSAndreas Gohr                    }
91f866280eSAndreas Gohr                    $uinfo['user'] = $user;
92f866280eSAndreas Gohr                    $uinfo['name'] = $sinfo['name'];
93f866280eSAndreas Gohr                    $uinfo['grps'] = array_merge((array) $uinfo['grps'], $sinfo['grps']);
94f866280eSAndreas Gohr                } else {
95f866280eSAndreas Gohr                    // new user, create him - making sure the login is unique by adding a number if needed
96f866280eSAndreas Gohr                    $user  = $uinfo['user'];
97f866280eSAndreas Gohr                    $count = '';
98f866280eSAndreas Gohr                    while($this->getUserData($user.$count)) {
99f866280eSAndreas Gohr                        if($count) {
100f866280eSAndreas Gohr                            $count++;
101f866280eSAndreas Gohr                        } else {
102f866280eSAndreas Gohr                            $count = 1;
103f866280eSAndreas Gohr                        }
104f866280eSAndreas Gohr                    }
105f866280eSAndreas Gohr                    $user            = $user.$count;
106f866280eSAndreas Gohr                    $uinfo['user']   = $user;
107f866280eSAndreas Gohr                    $uinfo['grps']   = (array) $uinfo['grps'];
108f866280eSAndreas Gohr                    $uinfo['grps'][] = $conf['defaultgroup'];
1093c0138dbSAndreas Gohr                    $uinfo['grps'][] = $this->cleanGroup($servicename); // add service as group
110f866280eSAndreas Gohr
1113c0138dbSAndreas Gohr                    //FIXME we should call trigger_user_mod?
112caa5ded4SAndreas Gohr                    $ok = $this->createUser($user, auth_pwgen($user), $uinfo['name'], $uinfo['mail'], $uinfo['grps']);
113caa5ded4SAndreas Gohr                    if(!$ok) {
114caa5ded4SAndreas Gohr                        msg('something went wrong creating your user account. please try again later.', -1);
115caa5ded4SAndreas Gohr                        return false;
116caa5ded4SAndreas Gohr                    }
117caa5ded4SAndreas Gohr
118caa5ded4SAndreas Gohr                    // send notification about the new user
119caa5ded4SAndreas Gohr                    $subscription = new Subscription();
120caa5ded4SAndreas Gohr                    $subscription->send_register($user, $uinfo['name'], $uinfo['mail']);
121f866280eSAndreas Gohr                }
122f866280eSAndreas Gohr
123f866280eSAndreas Gohr                // set user session
124a7a8f46aSAndreas Gohr                $this->setUserSession($uinfo, $servicename);
125a7a8f46aSAndreas Gohr                return true;
126a7a8f46aSAndreas Gohr            }
127a7a8f46aSAndreas Gohr
128a7a8f46aSAndreas Gohr            return false; // something went wrong during oAuth login
12980852c15SAndreas Gohr        }
13080852c15SAndreas Gohr
131a7a8f46aSAndreas Gohr        // do the "normal" plain auth login via form
132a7a8f46aSAndreas Gohr        return auth_login($user, $pass, $sticky);
133a7a8f46aSAndreas Gohr    }
13480852c15SAndreas Gohr
135a7a8f46aSAndreas Gohr    /**
136a7a8f46aSAndreas Gohr     * @param array  $data
137a7a8f46aSAndreas Gohr     * @param string $service
138a7a8f46aSAndreas Gohr     */
139a7a8f46aSAndreas Gohr    protected function setUserSession($data, $service) {
140a7a8f46aSAndreas Gohr        global $USERINFO;
141a7a8f46aSAndreas Gohr        global $conf;
142a7a8f46aSAndreas Gohr
143a7a8f46aSAndreas Gohr        // set up groups
144a7a8f46aSAndreas Gohr        if(!is_array($data['grps'])) {
145a7a8f46aSAndreas Gohr            $data['grps'] = array();
146a7a8f46aSAndreas Gohr        }
147a7a8f46aSAndreas Gohr        $data['grps'][] = $this->cleanGroup($service);
148f866280eSAndreas Gohr        $data['grps']   = array_unique($data['grps']);
14980852c15SAndreas Gohr
150f10e09e2SAndreas Gohr        $USERINFO                               = $data;
151f10e09e2SAndreas Gohr        $_SERVER['REMOTE_USER']                 = $data['user'];
152f10e09e2SAndreas Gohr        $_SESSION[DOKU_COOKIE]['auth']['user']  = $data['user'];
153f10e09e2SAndreas Gohr        $_SESSION[DOKU_COOKIE]['auth']['pass']  = $data['pass'];
154f10e09e2SAndreas Gohr        $_SESSION[DOKU_COOKIE]['auth']['info']  = $USERINFO;
155a7a8f46aSAndreas Gohr        $_SESSION[DOKU_COOKIE]['auth']['buid']  = auth_browseruid();
156a7a8f46aSAndreas Gohr        $_SESSION[DOKU_COOKIE]['auth']['time']  = time();
157a7a8f46aSAndreas Gohr        $_SESSION[DOKU_COOKIE]['auth']['oauth'] = $service;
15880852c15SAndreas Gohr    }
15980852c15SAndreas Gohr
160f866280eSAndreas Gohr    /**
161e32c3607SAndreas Gohr     * Unset additional stuff in session on logout
162e32c3607SAndreas Gohr     */
163e32c3607SAndreas Gohr    public function logOff() {
164e32c3607SAndreas Gohr        parent::logOff();
165e32c3607SAndreas Gohr
166e32c3607SAndreas Gohr        if(isset($_SESSION[DOKU_COOKIE]['auth']['buid'])) {
167e32c3607SAndreas Gohr            unset($_SESSION[DOKU_COOKIE]['auth']['buid']);
168e32c3607SAndreas Gohr        }
169e32c3607SAndreas Gohr        if(isset($_SESSION[DOKU_COOKIE]['auth']['time'])) {
170e32c3607SAndreas Gohr            unset($_SESSION[DOKU_COOKIE]['auth']['time']);
171e32c3607SAndreas Gohr        }
172e32c3607SAndreas Gohr        if(isset($_SESSION[DOKU_COOKIE]['auth']['oauth'])) {
173e32c3607SAndreas Gohr            unset($_SESSION[DOKU_COOKIE]['auth']['oauth']);
174e32c3607SAndreas Gohr        }
175e32c3607SAndreas Gohr    }
176e32c3607SAndreas Gohr
177e32c3607SAndreas Gohr    /**
178f866280eSAndreas Gohr     * Find a user by his email address
179f866280eSAndreas Gohr     *
180f866280eSAndreas Gohr     * @param $mail
181f866280eSAndreas Gohr     * @return bool|string
182f866280eSAndreas Gohr     */
18338378fbbSAndreas Gohr    protected function getUserByEmail($mail) {
184f866280eSAndreas Gohr        if($this->users === null) $this->_loadUserData();
18538378fbbSAndreas Gohr        $mail = strtolower($mail);
186f866280eSAndreas Gohr
187f866280eSAndreas Gohr        foreach($this->users as $user => $uinfo) {
188f866280eSAndreas Gohr            if(strtolower($uinfo['mail']) == $mail) return $user;
18938378fbbSAndreas Gohr        }
19038378fbbSAndreas Gohr
191f866280eSAndreas Gohr        return false;
192f866280eSAndreas Gohr    }
19338378fbbSAndreas Gohr
194f866280eSAndreas Gohr    /**
195f866280eSAndreas Gohr     * Enhance function to check aainst duplicate emails
196f866280eSAndreas Gohr     *
197f866280eSAndreas Gohr     * @param string $user
198f866280eSAndreas Gohr     * @param string $pwd
199f866280eSAndreas Gohr     * @param string $name
200f866280eSAndreas Gohr     * @param string $mail
201f866280eSAndreas Gohr     * @param null   $grps
202f866280eSAndreas Gohr     * @return bool|null|string
203f866280eSAndreas Gohr     */
204f866280eSAndreas Gohr    public function createUser($user, $pwd, $name, $mail, $grps = null) {
205f866280eSAndreas Gohr        if($this->getUserByEmail($mail)) {
206f866280eSAndreas Gohr            msg($this->getLang('emailduplicate'), -1);
207f866280eSAndreas Gohr            return false;
208f866280eSAndreas Gohr        }
209f866280eSAndreas Gohr
21038378fbbSAndreas Gohr        return parent::createUser($user, $pwd, $name, $mail, $grps);
21138378fbbSAndreas Gohr    }
21238378fbbSAndreas Gohr
213f866280eSAndreas Gohr    /**
214f866280eSAndreas Gohr     * Enhance function to check aainst duplicate emails
215f866280eSAndreas Gohr     *
216f866280eSAndreas Gohr     * @param string $user
217f866280eSAndreas Gohr     * @param array  $changes
218f866280eSAndreas Gohr     * @return bool
219f866280eSAndreas Gohr     */
22038378fbbSAndreas Gohr    public function modifyUser($user, $changes) {
2213c0138dbSAndreas Gohr        global $conf;
2223c0138dbSAndreas Gohr
2233c0138dbSAndreas Gohr        if(isset($changes['mail'])) {
2243c0138dbSAndreas Gohr            $found = $this->getUserByEmail($changes['mail']);
2253c0138dbSAndreas Gohr            if($found != $user) {
226f866280eSAndreas Gohr                msg($this->getLang('emailduplicate'), -1);
227f866280eSAndreas Gohr                return false;
228f866280eSAndreas Gohr            }
2293c0138dbSAndreas Gohr        }
23038378fbbSAndreas Gohr
2313c0138dbSAndreas Gohr        $ok = parent::modifyUser($user, $changes);
2323c0138dbSAndreas Gohr
2333c0138dbSAndreas Gohr        // refresh session cache
2343c0138dbSAndreas Gohr        touch($conf['cachedir'].'/sessionpurge');
2353c0138dbSAndreas Gohr
2363c0138dbSAndreas Gohr        return $ok;
23738378fbbSAndreas Gohr    }
23838378fbbSAndreas Gohr
23980852c15SAndreas Gohr}
24080852c15SAndreas Gohr
24180852c15SAndreas Gohr// vim:ts=4:sw=4:et: