xref: /plugin/oauth/auth.php (revision 3c0138db6331751d1ea0948f418a981582962f18)
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);
81*3c0138dbSAndreas Gohr                    // check if the user allowed access via this service
82*3c0138dbSAndreas Gohr                    if(!in_array($this->cleanGroup($servicename), $sinfo['grps'])) {
83*3c0138dbSAndreas Gohr                        msg(sprintf($this->getLang('authnotenabled'), $servicename), -1);
84*3c0138dbSAndreas Gohr                        return false;
85*3c0138dbSAndreas 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'];
104*3c0138dbSAndreas Gohr                    $uinfo['grps'][] = $this->cleanGroup($servicename); // add service as group
105f866280eSAndreas Gohr
106*3c0138dbSAndreas Gohr                    //FIXME we should call trigger_user_mod?
107*3c0138dbSAndreas Gohr                    //FIXME we should send a notification
108f866280eSAndreas Gohr                    $this->createUser($user, auth_pwgen($user), $uinfo['name'], $uinfo['mail'], $uinfo['grps']);
109f866280eSAndreas Gohr                }
110f866280eSAndreas Gohr
111f866280eSAndreas Gohr                // set user session
112a7a8f46aSAndreas Gohr                $this->setUserSession($uinfo, $servicename);
113a7a8f46aSAndreas Gohr                return true;
114a7a8f46aSAndreas Gohr            }
115a7a8f46aSAndreas Gohr
116a7a8f46aSAndreas Gohr            return false; // something went wrong during oAuth login
11780852c15SAndreas Gohr        }
11880852c15SAndreas Gohr
119a7a8f46aSAndreas Gohr        // do the "normal" plain auth login via form
120a7a8f46aSAndreas Gohr        return auth_login($user, $pass, $sticky);
121a7a8f46aSAndreas Gohr    }
12280852c15SAndreas Gohr
123a7a8f46aSAndreas Gohr    /**
124a7a8f46aSAndreas Gohr     * @param array  $data
125a7a8f46aSAndreas Gohr     * @param string $service
126a7a8f46aSAndreas Gohr     */
127a7a8f46aSAndreas Gohr    protected function setUserSession($data, $service) {
128a7a8f46aSAndreas Gohr        global $USERINFO;
129a7a8f46aSAndreas Gohr        global $conf;
130a7a8f46aSAndreas Gohr
131a7a8f46aSAndreas Gohr        // set up groups
132a7a8f46aSAndreas Gohr        if(!is_array($data['grps'])) {
133a7a8f46aSAndreas Gohr            $data['grps'] = array();
134a7a8f46aSAndreas Gohr        }
135a7a8f46aSAndreas Gohr        $data['grps'][] = $this->cleanGroup($service);
136f866280eSAndreas Gohr        $data['grps']   = array_unique($data['grps']);
13780852c15SAndreas Gohr
138f10e09e2SAndreas Gohr        $USERINFO                               = $data;
139f10e09e2SAndreas Gohr        $_SERVER['REMOTE_USER']                 = $data['user'];
140f10e09e2SAndreas Gohr        $_SESSION[DOKU_COOKIE]['auth']['user']  = $data['user'];
141f10e09e2SAndreas Gohr        $_SESSION[DOKU_COOKIE]['auth']['pass']  = $data['pass'];
142f10e09e2SAndreas Gohr        $_SESSION[DOKU_COOKIE]['auth']['info']  = $USERINFO;
143a7a8f46aSAndreas Gohr        $_SESSION[DOKU_COOKIE]['auth']['buid']  = auth_browseruid();
144a7a8f46aSAndreas Gohr        $_SESSION[DOKU_COOKIE]['auth']['time']  = time();
145a7a8f46aSAndreas Gohr        $_SESSION[DOKU_COOKIE]['auth']['oauth'] = $service;
14680852c15SAndreas Gohr    }
14780852c15SAndreas Gohr
148f866280eSAndreas Gohr    /**
149e32c3607SAndreas Gohr     * Unset additional stuff in session on logout
150e32c3607SAndreas Gohr     */
151e32c3607SAndreas Gohr    public function logOff() {
152e32c3607SAndreas Gohr        parent::logOff();
153e32c3607SAndreas Gohr
154e32c3607SAndreas Gohr        if(isset($_SESSION[DOKU_COOKIE]['auth']['buid'])) {
155e32c3607SAndreas Gohr            unset($_SESSION[DOKU_COOKIE]['auth']['buid']);
156e32c3607SAndreas Gohr        }
157e32c3607SAndreas Gohr        if(isset($_SESSION[DOKU_COOKIE]['auth']['time'])) {
158e32c3607SAndreas Gohr            unset($_SESSION[DOKU_COOKIE]['auth']['time']);
159e32c3607SAndreas Gohr        }
160e32c3607SAndreas Gohr        if(isset($_SESSION[DOKU_COOKIE]['auth']['oauth'])) {
161e32c3607SAndreas Gohr            unset($_SESSION[DOKU_COOKIE]['auth']['oauth']);
162e32c3607SAndreas Gohr        }
163e32c3607SAndreas Gohr    }
164e32c3607SAndreas Gohr
165e32c3607SAndreas Gohr    /**
166f866280eSAndreas Gohr     * Find a user by his email address
167f866280eSAndreas Gohr     *
168f866280eSAndreas Gohr     * @param $mail
169f866280eSAndreas Gohr     * @return bool|string
170f866280eSAndreas Gohr     */
17138378fbbSAndreas Gohr    protected function getUserByEmail($mail) {
172f866280eSAndreas Gohr        if($this->users === null) $this->_loadUserData();
17338378fbbSAndreas Gohr        $mail = strtolower($mail);
174f866280eSAndreas Gohr
175f866280eSAndreas Gohr        foreach($this->users as $user => $uinfo) {
176f866280eSAndreas Gohr            if(strtolower($uinfo['mail']) == $mail) return $user;
17738378fbbSAndreas Gohr        }
17838378fbbSAndreas Gohr
179f866280eSAndreas Gohr        return false;
180f866280eSAndreas Gohr    }
18138378fbbSAndreas Gohr
182f866280eSAndreas Gohr    /**
183f866280eSAndreas Gohr     * Enhance function to check aainst duplicate emails
184f866280eSAndreas Gohr     *
185f866280eSAndreas Gohr     * @param string $user
186f866280eSAndreas Gohr     * @param string $pwd
187f866280eSAndreas Gohr     * @param string $name
188f866280eSAndreas Gohr     * @param string $mail
189f866280eSAndreas Gohr     * @param null   $grps
190f866280eSAndreas Gohr     * @return bool|null|string
191f866280eSAndreas Gohr     */
192f866280eSAndreas Gohr    public function createUser($user, $pwd, $name, $mail, $grps = null) {
193f866280eSAndreas Gohr        if($this->getUserByEmail($mail)) {
194f866280eSAndreas Gohr            msg($this->getLang('emailduplicate'), -1);
195f866280eSAndreas Gohr            return false;
196f866280eSAndreas Gohr        }
197f866280eSAndreas Gohr
19838378fbbSAndreas Gohr        return parent::createUser($user, $pwd, $name, $mail, $grps);
19938378fbbSAndreas Gohr    }
20038378fbbSAndreas Gohr
201f866280eSAndreas Gohr    /**
202f866280eSAndreas Gohr     * Enhance function to check aainst duplicate emails
203f866280eSAndreas Gohr     *
204f866280eSAndreas Gohr     * @param string $user
205f866280eSAndreas Gohr     * @param array  $changes
206f866280eSAndreas Gohr     * @return bool
207f866280eSAndreas Gohr     */
20838378fbbSAndreas Gohr    public function modifyUser($user, $changes) {
209*3c0138dbSAndreas Gohr        global $conf;
210*3c0138dbSAndreas Gohr
211*3c0138dbSAndreas Gohr        if(isset($changes['mail'])) {
212*3c0138dbSAndreas Gohr            $found = $this->getUserByEmail($changes['mail']);
213*3c0138dbSAndreas Gohr            if($found != $user) {
214f866280eSAndreas Gohr                msg($this->getLang('emailduplicate'), -1);
215f866280eSAndreas Gohr                return false;
216f866280eSAndreas Gohr            }
217*3c0138dbSAndreas Gohr        }
21838378fbbSAndreas Gohr
219*3c0138dbSAndreas Gohr        $ok = parent::modifyUser($user, $changes);
220*3c0138dbSAndreas Gohr
221*3c0138dbSAndreas Gohr        // refresh session cache
222*3c0138dbSAndreas Gohr        touch($conf['cachedir'].'/sessionpurge');
223*3c0138dbSAndreas Gohr
224*3c0138dbSAndreas Gohr        return $ok;
22538378fbbSAndreas Gohr    }
22638378fbbSAndreas Gohr
22780852c15SAndreas Gohr}
22880852c15SAndreas Gohr
22980852c15SAndreas Gohr// vim:ts=4:sw=4:et: