xref: /plugin/oauth/auth.php (revision caa5ded4ab08b0e357614b09720b307b0a5a4236)
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 $INPUT;
38a7a8f46aSAndreas Gohr        global $conf;
39a7a8f46aSAndreas Gohr        global $USERINFO;
4080852c15SAndreas Gohr
41a7a8f46aSAndreas Gohr        $servicename = $INPUT->str('oa');
4280852c15SAndreas Gohr
43a7a8f46aSAndreas Gohr        // check session for existing oAuth login data
44a7a8f46aSAndreas Gohr        $session = $_SESSION[DOKU_COOKIE]['auth'];
45a7a8f46aSAndreas Gohr        if(!$servicename && isset($session['oauth'])) {
46a7a8f46aSAndreas Gohr            $servicename = $session['oauth'];
47a7a8f46aSAndreas Gohr            // check if session data is still considered valid
48a7a8f46aSAndreas Gohr            if(($session['time'] >= time() - $conf['auth_security_timeout']) &&
49f866280eSAndreas Gohr                ($session['buid'] == auth_browseruid())
50f866280eSAndreas Gohr            ) {
5180852c15SAndreas Gohr
52a7a8f46aSAndreas Gohr                $_SERVER['REMOTE_USER'] = $session['user'];
53a7a8f46aSAndreas Gohr                $USERINFO               = $session['info'];
5480852c15SAndreas Gohr                return true;
55f10e09e2SAndreas Gohr            }
5680852c15SAndreas Gohr        }
5780852c15SAndreas Gohr
58a7a8f46aSAndreas Gohr        // either we're in oauth login or a previous log needs to be rechecked
59a7a8f46aSAndreas Gohr        if($servicename) {
60a7a8f46aSAndreas Gohr            /** @var helper_plugin_oauth $hlp */
61a7a8f46aSAndreas Gohr            $hlp     = plugin_load('helper', 'oauth');
62a7a8f46aSAndreas Gohr            $service = $hlp->loadService($servicename);
63a7a8f46aSAndreas Gohr            if(is_null($service)) return false;
64a7a8f46aSAndreas Gohr
65a7a8f46aSAndreas Gohr            // get the token
66a7a8f46aSAndreas Gohr            if($service->checkToken()) {
67a7a8f46aSAndreas Gohr                $uinfo = $service->getUser();
68f866280eSAndreas Gohr
691025aad7SAndreas Gohr                $uinfo['user'] = $this->cleanUser((string) $uinfo['user']);
701025aad7SAndreas Gohr                if(!$uinfo['name']) $uinfo['name'] = $uinfo['user'];
711025aad7SAndreas Gohr
721025aad7SAndreas Gohr                if(!$uinfo['user'] || !$uinfo['mail']) {
731025aad7SAndreas Gohr                    msg("$servicename did not provide the needed user info. Can't log you in", -1);
741025aad7SAndreas Gohr                    return false;
751025aad7SAndreas Gohr                }
761025aad7SAndreas Gohr
77f866280eSAndreas Gohr                // see if the user is known already
78f866280eSAndreas Gohr                $user = $this->getUserByEmail($uinfo['mail']);
79f866280eSAndreas Gohr                if($user) {
80f866280eSAndreas Gohr                    $sinfo = $this->getUserData($user);
813c0138dbSAndreas Gohr                    // check if the user allowed access via this service
823c0138dbSAndreas Gohr                    if(!in_array($this->cleanGroup($servicename), $sinfo['grps'])) {
833c0138dbSAndreas Gohr                        msg(sprintf($this->getLang('authnotenabled'), $servicename), -1);
843c0138dbSAndreas Gohr                        return false;
853c0138dbSAndreas Gohr                    }
86f866280eSAndreas Gohr                    $uinfo['user'] = $user;
87f866280eSAndreas Gohr                    $uinfo['name'] = $sinfo['name'];
88f866280eSAndreas Gohr                    $uinfo['grps'] = array_merge((array) $uinfo['grps'], $sinfo['grps']);
89f866280eSAndreas Gohr                } else {
90f866280eSAndreas Gohr                    // new user, create him - making sure the login is unique by adding a number if needed
91f866280eSAndreas Gohr                    $user  = $uinfo['user'];
92f866280eSAndreas Gohr                    $count = '';
93f866280eSAndreas Gohr                    while($this->getUserData($user.$count)) {
94f866280eSAndreas Gohr                        if($count) {
95f866280eSAndreas Gohr                            $count++;
96f866280eSAndreas Gohr                        } else {
97f866280eSAndreas Gohr                            $count = 1;
98f866280eSAndreas Gohr                        }
99f866280eSAndreas Gohr                    }
100f866280eSAndreas Gohr                    $user            = $user.$count;
101f866280eSAndreas Gohr                    $uinfo['user']   = $user;
102f866280eSAndreas Gohr                    $uinfo['grps']   = (array) $uinfo['grps'];
103f866280eSAndreas Gohr                    $uinfo['grps'][] = $conf['defaultgroup'];
1043c0138dbSAndreas Gohr                    $uinfo['grps'][] = $this->cleanGroup($servicename); // add service as group
105f866280eSAndreas Gohr
1063c0138dbSAndreas Gohr                    //FIXME we should call trigger_user_mod?
107*caa5ded4SAndreas Gohr                    $ok = $this->createUser($user, auth_pwgen($user), $uinfo['name'], $uinfo['mail'], $uinfo['grps']);
108*caa5ded4SAndreas Gohr                    if(!$ok) {
109*caa5ded4SAndreas Gohr                        msg('something went wrong creating your user account. please try again later.', -1);
110*caa5ded4SAndreas Gohr                        return false;
111*caa5ded4SAndreas Gohr                    }
112*caa5ded4SAndreas Gohr
113*caa5ded4SAndreas Gohr                    // send notification about the new user
114*caa5ded4SAndreas Gohr                    $subscription = new Subscription();
115*caa5ded4SAndreas Gohr                    $subscription->send_register($user, $uinfo['name'], $uinfo['mail']);
116f866280eSAndreas Gohr                }
117f866280eSAndreas Gohr
118f866280eSAndreas Gohr                // set user session
119a7a8f46aSAndreas Gohr                $this->setUserSession($uinfo, $servicename);
120a7a8f46aSAndreas Gohr                return true;
121a7a8f46aSAndreas Gohr            }
122a7a8f46aSAndreas Gohr
123a7a8f46aSAndreas Gohr            return false; // something went wrong during oAuth login
12480852c15SAndreas Gohr        }
12580852c15SAndreas Gohr
126a7a8f46aSAndreas Gohr        // do the "normal" plain auth login via form
127a7a8f46aSAndreas Gohr        return auth_login($user, $pass, $sticky);
128a7a8f46aSAndreas Gohr    }
12980852c15SAndreas Gohr
130a7a8f46aSAndreas Gohr    /**
131a7a8f46aSAndreas Gohr     * @param array  $data
132a7a8f46aSAndreas Gohr     * @param string $service
133a7a8f46aSAndreas Gohr     */
134a7a8f46aSAndreas Gohr    protected function setUserSession($data, $service) {
135a7a8f46aSAndreas Gohr        global $USERINFO;
136a7a8f46aSAndreas Gohr        global $conf;
137a7a8f46aSAndreas Gohr
138a7a8f46aSAndreas Gohr        // set up groups
139a7a8f46aSAndreas Gohr        if(!is_array($data['grps'])) {
140a7a8f46aSAndreas Gohr            $data['grps'] = array();
141a7a8f46aSAndreas Gohr        }
142a7a8f46aSAndreas Gohr        $data['grps'][] = $this->cleanGroup($service);
143f866280eSAndreas Gohr        $data['grps']   = array_unique($data['grps']);
14480852c15SAndreas Gohr
145f10e09e2SAndreas Gohr        $USERINFO                               = $data;
146f10e09e2SAndreas Gohr        $_SERVER['REMOTE_USER']                 = $data['user'];
147f10e09e2SAndreas Gohr        $_SESSION[DOKU_COOKIE]['auth']['user']  = $data['user'];
148f10e09e2SAndreas Gohr        $_SESSION[DOKU_COOKIE]['auth']['pass']  = $data['pass'];
149f10e09e2SAndreas Gohr        $_SESSION[DOKU_COOKIE]['auth']['info']  = $USERINFO;
150a7a8f46aSAndreas Gohr        $_SESSION[DOKU_COOKIE]['auth']['buid']  = auth_browseruid();
151a7a8f46aSAndreas Gohr        $_SESSION[DOKU_COOKIE]['auth']['time']  = time();
152a7a8f46aSAndreas Gohr        $_SESSION[DOKU_COOKIE]['auth']['oauth'] = $service;
15380852c15SAndreas Gohr    }
15480852c15SAndreas Gohr
155f866280eSAndreas Gohr    /**
156e32c3607SAndreas Gohr     * Unset additional stuff in session on logout
157e32c3607SAndreas Gohr     */
158e32c3607SAndreas Gohr    public function logOff() {
159e32c3607SAndreas Gohr        parent::logOff();
160e32c3607SAndreas Gohr
161e32c3607SAndreas Gohr        if(isset($_SESSION[DOKU_COOKIE]['auth']['buid'])) {
162e32c3607SAndreas Gohr            unset($_SESSION[DOKU_COOKIE]['auth']['buid']);
163e32c3607SAndreas Gohr        }
164e32c3607SAndreas Gohr        if(isset($_SESSION[DOKU_COOKIE]['auth']['time'])) {
165e32c3607SAndreas Gohr            unset($_SESSION[DOKU_COOKIE]['auth']['time']);
166e32c3607SAndreas Gohr        }
167e32c3607SAndreas Gohr        if(isset($_SESSION[DOKU_COOKIE]['auth']['oauth'])) {
168e32c3607SAndreas Gohr            unset($_SESSION[DOKU_COOKIE]['auth']['oauth']);
169e32c3607SAndreas Gohr        }
170e32c3607SAndreas Gohr    }
171e32c3607SAndreas Gohr
172e32c3607SAndreas Gohr    /**
173f866280eSAndreas Gohr     * Find a user by his email address
174f866280eSAndreas Gohr     *
175f866280eSAndreas Gohr     * @param $mail
176f866280eSAndreas Gohr     * @return bool|string
177f866280eSAndreas Gohr     */
17838378fbbSAndreas Gohr    protected function getUserByEmail($mail) {
179f866280eSAndreas Gohr        if($this->users === null) $this->_loadUserData();
18038378fbbSAndreas Gohr        $mail = strtolower($mail);
181f866280eSAndreas Gohr
182f866280eSAndreas Gohr        foreach($this->users as $user => $uinfo) {
183f866280eSAndreas Gohr            if(strtolower($uinfo['mail']) == $mail) return $user;
18438378fbbSAndreas Gohr        }
18538378fbbSAndreas Gohr
186f866280eSAndreas Gohr        return false;
187f866280eSAndreas Gohr    }
18838378fbbSAndreas Gohr
189f866280eSAndreas Gohr    /**
190f866280eSAndreas Gohr     * Enhance function to check aainst duplicate emails
191f866280eSAndreas Gohr     *
192f866280eSAndreas Gohr     * @param string $user
193f866280eSAndreas Gohr     * @param string $pwd
194f866280eSAndreas Gohr     * @param string $name
195f866280eSAndreas Gohr     * @param string $mail
196f866280eSAndreas Gohr     * @param null   $grps
197f866280eSAndreas Gohr     * @return bool|null|string
198f866280eSAndreas Gohr     */
199f866280eSAndreas Gohr    public function createUser($user, $pwd, $name, $mail, $grps = null) {
200f866280eSAndreas Gohr        if($this->getUserByEmail($mail)) {
201f866280eSAndreas Gohr            msg($this->getLang('emailduplicate'), -1);
202f866280eSAndreas Gohr            return false;
203f866280eSAndreas Gohr        }
204f866280eSAndreas Gohr
20538378fbbSAndreas Gohr        return parent::createUser($user, $pwd, $name, $mail, $grps);
20638378fbbSAndreas Gohr    }
20738378fbbSAndreas Gohr
208f866280eSAndreas Gohr    /**
209f866280eSAndreas Gohr     * Enhance function to check aainst duplicate emails
210f866280eSAndreas Gohr     *
211f866280eSAndreas Gohr     * @param string $user
212f866280eSAndreas Gohr     * @param array  $changes
213f866280eSAndreas Gohr     * @return bool
214f866280eSAndreas Gohr     */
21538378fbbSAndreas Gohr    public function modifyUser($user, $changes) {
2163c0138dbSAndreas Gohr        global $conf;
2173c0138dbSAndreas Gohr
2183c0138dbSAndreas Gohr        if(isset($changes['mail'])) {
2193c0138dbSAndreas Gohr            $found = $this->getUserByEmail($changes['mail']);
2203c0138dbSAndreas Gohr            if($found != $user) {
221f866280eSAndreas Gohr                msg($this->getLang('emailduplicate'), -1);
222f866280eSAndreas Gohr                return false;
223f866280eSAndreas Gohr            }
2243c0138dbSAndreas Gohr        }
22538378fbbSAndreas Gohr
2263c0138dbSAndreas Gohr        $ok = parent::modifyUser($user, $changes);
2273c0138dbSAndreas Gohr
2283c0138dbSAndreas Gohr        // refresh session cache
2293c0138dbSAndreas Gohr        touch($conf['cachedir'].'/sessionpurge');
2303c0138dbSAndreas Gohr
2313c0138dbSAndreas Gohr        return $ok;
23238378fbbSAndreas Gohr    }
23338378fbbSAndreas Gohr
23480852c15SAndreas Gohr}
23580852c15SAndreas Gohr
23680852c15SAndreas Gohr// vim:ts=4:sw=4:et: