1<?php
2/**
3 * Facebook authentication backend
4 * derived from Václav Voborníks FBauth and sentryperm@gmail.coms authgoogle
5 *
6 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
7 * @author     Leo Zachl <leo.zachl@gmail.com>
8 */
9
10define('DOKU_AUTH', dirname(__FILE__));
11// require_once(DOKU_AUTH.'/basic.class.php');
12require_once(DOKU_AUTH.'/lib/autoload.php');
13require_once(DOKU_AUTH.'/dwPersistentData.php');
14
15// define cookie and session id, append server port when securecookie is configured
16if (!defined('AUTHFACEBOOK_COOKIE')) define('AUTHFACEBOOK_COOKIE', 'SPFB'.md5(DOKU_REL.(($conf['securecookie'])?$_SERVER['SERVER_PORT']:'')));
17
18#define('AUTH_USERFILE',DOKU_CONF.'users.auth.php');
19
20class auth_plugin_authfacebook extends auth_plugin_authplain {
21
22  var $users = null;
23  var $_pattern = array();
24
25  var $fbsession = array();
26
27  public function __construct() {
28    global $conf, $config_cascade;
29
30    parent::__construct();
31
32    $this->cando['external'] = true;
33    $this->cando['logout']   = true;
34    $this->cando['delUser']   = false;
35
36    $this->success = true;
37    return;
38
39  }
40
41  function trustExternal($user,$pass,$sticky=true ){
42    global $USERINFO;
43    global $conf;
44    $sticky ? $sticky = true : $sticky = false; //sanity check
45
46    if (!empty($_SESSION[DOKU_COOKIE]['authfacebook']['user'])) {
47      $USERINFO = $_SESSION[DOKU_COOKIE]['authfacebook']['info'];
48      if (!$USERINFO['is_facebook']){
49        $this->cando['modPass'] = true;
50        $this->cando['delUser'] = true;
51      }
52      $_SERVER['REMOTE_USER'] = $_SESSION[DOKU_COOKIE]['authfacebook']['user'];
53      return true;
54    }
55
56    //get authplain form login info
57    if(!empty($user)){
58      if($this->checkPass($user,$pass)){
59        $uinfo  = $this->getUserData($user);
60
61        //set user info
62        $USERINFO['name'] = $uinfo['name'];
63        $USERINFO['mail'] = $uinfo['mail'];
64        $USERINFO['grps'] = $uinfo['grps'];
65        $USERINFO['is_facebook'] = false;
66        $USERINFO['pass'] = ''; // $pass;
67
68        //save data in session
69        $_SERVER['REMOTE_USER'] = $uinfo['name'];
70        $_SESSION[DOKU_COOKIE]['authfacebook']['user'] = $user;
71        $_SESSION[DOKU_COOKIE]['authfacebook']['info'] = $USERINFO;
72        return true;
73      } else {
74        //invalid credentials - log off
75        msg($this->getLang('badlogin'),-1);
76        return false;
77      }
78    }
79
80    if ($_COOKIE[AUTHFACEBOOK_COOKIE]) {
81      $_SESSION[DOKU_COOKIE]['authfacebook']['token'] = $_COOKIE[AUTHFACEBOOK_COOKIE];
82    }
83
84    if (($appId = $this->getConf('applicationID')) && ($appSecret = $this->getConf('applicationSecret'))) {
85      $fb = new Facebook\Facebook(array(
86        'app_id'      => $appId,
87        'app_secret'     => $appSecret,
88        'default_graph_version' => 'v2.12',
89        'persistent_data_handler'     => new MyDokuWikiPersistentDataHandler(),
90      ));
91      $helper = $fb->getRedirectLoginHelper();
92
93      if (isset($_GET['code'])) {
94        //get token
95        try {
96          $accessToken = $helper->getAccessToken();
97          if ($accessToken) {
98            //save token in session
99            $_SESSION[DOKU_COOKIE]['authfacebook']['token'] = $accessToken;
100            //save token in cookies
101            $this->_updateCookie($_SESSION[DOKU_COOKIE]['authfacebook']['token'], time() + 60 * 60 * 24 * 365);
102            try {
103              $response = $fb->get('/me?fields=id,name,email', $accessToken);
104            } catch (FacebookApiException $e) {
105              error_log("2: " . $e);
106            }
107            if ($response) {
108              $me = $response->getGraphUser();
109
110              // the FB-App is only allowed to read the groups of the App-Admin
111              $response = $fb->get('/me/permissions', $accessToken);
112              $permissions = $response->getGraphEdge();
113              if ($me['id'] == $this->getConf('appAdmin'))
114                $this->getFacebookGroups($fb, $permissions, $accessToken);
115
116              $grantedpermissions = array();
117              foreach($permissions as $permission)
118                if ($permission['status'] == 'granted')
119                  $grantedpermissions[] = $permission['permission'];
120              $_SESSION[DOKU_COOKIE]['authfacebook']['permissions'] = $grantedpermissions;
121
122              $USERINFO['name'] = $me['name'];
123              $USERINFO['mail'] = $me['email'];
124              $USERINFO['is_facebook'] = true;
125              $USERINFO['grps'] = array( $this->getConf('defaultgroup'));
126              if (($fbgroupid = $this->getConf('fbgid2group')) != ''){
127                if ($fbg2user = json_decode($fbgroupid,TRUE)){
128                  require(DOKU_CONF.'/fb_groups.php');
129                  foreach($fbg2user as $id => $group){
130                    if (isset($fb_groups[$id]) && isset($fb_groups[$id][$me['id']])) $USERINFO['grps'][] = $group;
131                  }
132                }
133              }
134              if (in_array($me['id'],json_decode($this->getConf('superuser'))))
135                $USERINFO['grps'][] = 'admin';
136
137              touch(DOKU_CONF.'/fb_ids.php');
138              $fb_ids_fd = fopen(DOKU_CONF.'/fb_ids.php','r+');
139              $fb_ids_lock = flock($fb_ids_fd, LOCK_EX | LOCK_NB);
140              require(DOKU_CONF.'/fb_ids.php');
141
142              if (isset($fb_ids[$me['id']])){
143                $user = $fb_ids[$me['id']];
144              } else {
145                $plain_user = $this->retrieveUsers(0,0,array('mail' => '^'.$me['email'].'$'));
146                if (count($plain_user) > 0)
147                  $user = reset(array_keys($plain_user));
148                else {
149                  if (!empty($me['email']))
150                    $user = strtolower(reset(explode('@',$me['email'])));
151                  else
152                    $user = preg_replace("/[^a-z0-9]/","_",strtolower(trim(basename(stripslashes(iconv("utf8","ascii//translit",strtr($me['name'],' ','.')))), ".\x00..\x20")));
153                  $plain_user = $this->retrieveUsers(0,0,array('user' => '^'.$user.'$'));
154                  $ext = ''; $cnt=0;
155                  while (count($plain_user) > 0 || in_array($user.$ext,$fb_ids)){
156                    $cnt++;
157                    $ext = '-'.$cnt;
158                    $plain_user = $this->retrieveUsers(0,0,array('user' => '^'.$user.$ext.'$'));
159                  }
160                  $user = $user.$ext;
161                  $fb_ids[$me['id']] = $user;
162                  if ($fb_ids_lock){
163                    ftruncate($fb_ids_fd, 0); // kürze Datei
164                    fwrite($fb_ids_fd,"<?php\n\$fb_ids = ".var_export($fb_ids,true).";\n");
165                    fflush($fb_ids_fd);
166                  }
167                }
168              }
169              flock($fb_ids_fd, LOCK_UN);
170              fclose($fb_ids_fd);
171
172              $_SESSION[DOKU_COOKIE]['authfacebook']['userid'] = $me['id'];
173              $_SERVER['REMOTE_USER'] = $user;
174              $_SESSION[DOKU_COOKIE]['authfacebook']['user'] = $user;
175              $_SESSION[DOKU_COOKIE]['authfacebook']['pass'] = '';
176              $_SESSION[DOKU_COOKIE]['authfacebook']['info'] = $USERINFO;
177
178              //redirect to login page
179              header("Location: ".wl('start', array(), true, '&'));
180              die();
181
182            } //me
183          } else { // FB session
184            $_SESSION[DOKU_COOKIE]['authfacebook']['auth_url'] = $helper->getLoginUrl(
185              wl('start',array('do'=>'login'),true, '&'),
186              explode(',',$this->getConf('scope'))
187            );
188          }
189        } catch (Exception $e) {
190          $_SESSION[DOKU_COOKIE]['authfacebook']['auth_url'] = $helper->getLoginUrl(
191            wl('start',array('do'=>'login'),true, '&'),
192            explode(',',$this->getConf('scope'))
193          );
194          msg('1: Auth Facebook Error: '. $e->getFile() .':'.$e->getLine().': '.$e->getMessage());
195        }
196      }
197
198      if (!isset($_SESSION[DOKU_COOKIE]['authfacebook']['auth_url']))
199      $_SESSION[DOKU_COOKIE]['authfacebook']['auth_url'] = $helper->getLoginUrl(
200        wl('start',array('do'=>'login'),true, '&'),
201        explode(',',$this->getConf('scope'))
202      );
203    }
204
205    return false;
206  }
207
208  function logOff(){
209    unset($_SESSION[DOKU_COOKIE]['authfacebook']['token']);
210    unset($_SESSION[DOKU_COOKIE]['authfacebook']['user']);
211    unset($_SESSION[DOKU_COOKIE]['authfacebook']['info']);
212    unset($_SESSION[DOKU_COOKIE]['authfacebook']['userid']);
213    // clear the cookie
214    $this->_updateCookie('', time() - 600000);
215    if (($appId = $this->getConf('applicationID')) && ($appSecret = $this->getConf('applicationSecret'))) {
216        $fb = new Facebook\Facebook(array(
217            'app_id' => $appId,
218            'app_secret' => $appSecret,
219            'default_graph_version' => 'v2.3',
220            'persistent_data_handler'     => new MyDokuWikiPersistentDataHandler(),
221        ));
222    }
223    unset($_SESSION[DOKU_COOKIE]['authfacebook']['auth_url']);
224  }
225
226  function _updateCookie($value, $time) {
227    global $conf;
228
229    $cookieDir = empty($conf['cookiedir']) ? DOKU_REL : $conf['cookiedir'];
230    if (version_compare(PHP_VERSION, '5.2.0', '>')) {
231      setcookie(AUTHFACEBOOK_COOKIE, $value, $time, $cookieDir, '', ($conf['securecookie'] && is_ssl()), true);
232    } else {
233      setcookie(AUTHFACEBOOK_COOKIE, $value, $time, $cookieDir, '', ($conf['securecookie'] && is_ssl()));
234    }
235  }
236
237  private function getFacebookGroups($facebook,$permissions, $accessToken){
238    if ($mapgroups = json_decode($this->getConf('fbgid2group'),true)){
239      foreach($permissions as $permission){
240        if ($permission['permission'] == 'user_managed_groups' && $permission['status'] == 'granted'){
241          $groups = $facebook->get('/me/groups', $accessToken);
242          $groups = $groups->getGraphEdge();
243          $usergroups = array();
244          foreach($groups as $group){
245            $usergroups[$group['id']] = $group['name'];
246          }
247          if (is_file(DOKU_CONF.'/fb_groups_orig.php'))
248            include(DOKU_CONF.'/fb_groups_orig.php');
249          else
250            $fb_groups = array();
251          foreach(array_intersect_key($mapgroups,$usergroups) as $groupid => $groupname){
252            $group_members = $facebook->get('/'.$groupid.'/members', $accessToken);
253            if (!empty($group_members))
254              foreach($group_members as $member)
255                $fb_groups[$groupid][$member['id']] = $member['name'];
256
257          }
258          if (!empty($this->getConf('saveAccessKey'))){
259            $token = "\$fb_token = '".$accessToken."';\n";
260          } else {
261            $token;
262          }
263          file_put_contents(DOKU_CONF.'/fb_groups.php',"<?php\n\$fb_groups = ".var_export($fb_groups,true).";\n".$token);
264        }
265      }
266    }
267  }
268
269}
270
271//Setup VIM: ex: et ts=2 enc=utf-8 :
272