1<?php 2// must be run within Dokuwiki 3if(!defined('DOKU_INC')) die(); 4define('GOOGLE_API_DIR', dirname(__FILE__).'/google/'); 5 6global $conf; 7// define cookie and session id, append server port when securecookie is configured 8if (!defined('AUTHGOOGLE_COOKIE')) define('AUTHGOOGLE_COOKIE', 'SPGG'.md5(DOKU_REL.(($conf['securecookie'])?$_SERVER['SERVER_PORT']:''))); 9 10/** 11 * Google Auth 2.0 authentication backend 12 * 13 * @author sentryperm@gmail.com 14 */ 15class auth_plugin_authgoogle extends auth_plugin_authplain { 16 17 public function __construct() { 18 global $config_cascade; 19 parent::__construct(); 20 21 // fix if acl no used 22 $this->success = true; 23 24 $this->cando['external'] = true; 25 $this->cando['logout'] = true; 26 } 27 28 function trustExternal($user, $pass, $sticky = false) { 29 global $USERINFO, $ID; 30 31 //get user info in session 32 if (!empty($_SESSION[DOKU_COOKIE]['authgoogle']['info'])) { 33 $USERINFO['name'] = $_SESSION[DOKU_COOKIE]['authgoogle']['info']['name']; 34 $USERINFO['mail'] = $_SESSION[DOKU_COOKIE]['authgoogle']['info']['mail']; 35 $USERINFO['grps'] = $_SESSION[DOKU_COOKIE]['authgoogle']['info']['grps']; 36 $USERINFO['is_google'] = $_SESSION[DOKU_COOKIE]['authgoogle']['info']['is_google']; 37 $_SERVER['REMOTE_USER'] = $_SESSION[DOKU_COOKIE]['authgoogle']['user']; 38 return true; 39 } 40 41 //get form login info 42 if(!empty($user)){ 43 if($this->checkPass($user,$pass)){ 44 $uinfo = $this->getUserData($user); 45 46 //set user info 47 $USERINFO['name'] = $uinfo['name']; 48 $USERINFO['mail'] = $uinfo['email']; 49 $USERINFO['grps'] = $uinfo['grps']; 50 $USERINFO['pass'] = $pass; 51 52 //save data in session 53 $_SERVER['REMOTE_USER'] = $uinfo['name']; 54 $_SESSION[DOKU_COOKIE]['authgoogle']['user'] = $uinfo['name']; 55 $_SESSION[DOKU_COOKIE]['authgoogle']['info'] = $USERINFO; 56 57 return true; 58 }else{ 59 //invalid credentials - log off 60 msg($this->getLang('badlogin'),-1); 61 return false; 62 } 63 } 64 65 //if token saved in cookies - get it 66 if ($_COOKIE[AUTHGOOGLE_COOKIE]) { 67 $_SESSION[DOKU_COOKIE]['authgoogle']['token'] = $_COOKIE[AUTHGOOGLE_COOKIE]; 68 } 69 70 //set our referer for redirection, if we're hitting login 71 if (!empty($_SERVER['HTTP_REFERER'])) { 72 $_SESSION[DOKU_COOKIE]['authgoogle']['referer'] = $_SERVER['HTTP_REFERER']; 73 } 74 75 //google auth 76 require_once GOOGLE_API_DIR.'/Google_Client.php'; 77 require_once GOOGLE_API_DIR.'/contrib/Google_Oauth2Service.php'; 78 79 $client = new Google_Client(); 80 $client->setApplicationName("Google Application"); 81 $client->setClientId($this->getConf('client_id')); 82 $client->setClientSecret($this->getConf('client_secret')); 83 $client->setRedirectUri(wl('start',array('do'=>'login'),true, '&')); 84 $client->setAccessType('online'); 85 $client->setApprovalPrompt('auto'); 86 87 $oauth2 = new Google_Oauth2Service($client); 88 //get code from google redirect link 89 if (isset($_GET['code'])) { 90 //get token 91 try { 92 $client->authenticate($_GET['code']); 93 //save token in session 94 $_SESSION[DOKU_COOKIE]['authgoogle']['token'] = $client->getAccessToken(); 95 //save token in cookies 96 $this->_updateCookie($_SESSION[DOKU_COOKIE]['authgoogle']['token'], time() + 60 * 60 * 24 * 365); 97 //redirect to login page 98 header("Location: ".wl('start', array('do'=>'login'), true, '&')); 99 die(); 100 } catch (Exception $e) { 101 msg('Auth Google Error: '.$e->getMessage()); 102 } 103 } 104 //save state and auth_url in session 105 $_SESSION[DOKU_COOKIE]['authgoogle']['state'] = $state; 106 $_SESSION[DOKU_COOKIE]['authgoogle']['auth_url'] = $client->createAuthUrl(); 107 $_SESSION[DOKU_COOKIE]['authgoogle']['auth_url'] .= "&state=".$state; 108 109 //set token in client 110 if (isset($_SESSION[DOKU_COOKIE]['authgoogle']['token'])) { 111 try { 112 $client->setAccessToken($_SESSION[DOKU_COOKIE]['authgoogle']['token']); 113 } catch (Exception $e){ 114 $this->logOff(); 115 return false; 116 } 117 } 118 119 //if successed auth 120 if ($client->getAccessToken()) { 121 122 // If the access token is expired, ask the user to login again 123 if($client->isAccessTokenExpired()) { 124 $authUrl = $client->createAuthUrl(); 125 header('Location: ' . filter_var($authUrl, FILTER_SANITIZE_URL)); 126 } 127 128 $user = $oauth2->userinfo->get(); 129 $email = filter_var($user['email'], FILTER_SANITIZE_EMAIL); 130 //$img = filter_var($user['picture'], FILTER_VALIDATE_URL); 131 //$personMarkup = "$email<div><img src='$img?sz=50'></div>"; 132 133 //Check verify email in google 134 if (!$user['verified_email']) { 135 msg('Auth Google Error: '.$email.' not verifed in google account'); 136 $this->logOff(); 137 return false; 138 } 139 140 //check email in list allows 141 if (!$this->_check_email_domain($email)) { 142 msg('Auth Google Error: access denied for '.$email); 143 $this->logOff(); 144 return false; 145 } 146 147 //create and update user in base 148 $login = 'google'.$user['id']; 149 $udata = $this->getUserData($login); 150 if (!$udata) { 151 //default groups 152 $grps = null; 153 if ($this->getConf('default_groups')) $grps = explode(' ', $this->getConf('default_groups')); 154 //create user 155 $this->createUser($login, md5(rand().$login), $user['name'], $email, $grps); 156 $udata = $this->getUserData($login); 157 } elseif ($udata['name'] != $user['name'] || $udata['email'] != $email) { 158 //update user 159 $this->modifyUser($login, array('name'=>$user['name'], 'email'=>$email)); 160 } 161 162 //set user info 163 $USERINFO['pass'] = ""; 164 $USERINFO['name'] = $user['name']; 165 $USERINFO['mail'] = $email; 166 $USERINFO['grps'] = $udata['grps']; 167 $USERINFO['is_google'] = true; 168 $_SERVER['REMOTE_USER'] = $user['name']; 169 170 //save user info in session 171 $_SESSION[DOKU_COOKIE]['authgoogle']['user'] = $_SERVER['REMOTE_USER']; 172 $_SESSION[DOKU_COOKIE]['authgoogle']['info'] = $USERINFO; 173 174 // update token 175 $_SESSION['token'] = $client->getAccessToken(); 176 177 //if login page - redirect to original referer or, if none, start page. 178 if (isset($_GET['do']) && $_GET['do']=='login') { 179 $referer = $_SESSION[DOKU_COOKIE]['authgoogle']['referer']; 180 $redirect = empty($referer) ? wl('start', '', true) : $referer; 181 header("Location: ".$referer); 182 } 183 184 return true; 185 } else { 186 //no auth 187 } 188 189 return false; 190 } 191 192 function _check_email_domain($email) { 193 //check email in allow domains 194 if ($this->getConf('allowed_domains')) { 195 $domains = preg_split("/[ ]+/is", $this->getConf('allowed_domains')); 196 foreach ($domains as $domain) { 197 $domain = trim($domain); 198 //all domains 199 if ($domain == '*') return true; 200 //email 201 if ($email == $domain) return true; 202 //domain 203 if (preg_match("/^\\*@([^@ ]+)/is", $domain, $m)) { 204 if (preg_match("/@([^@ ]+)$/is", $email, $n)) { 205 if ($m[1] == $n[1]) return true; 206 } 207 } 208 } 209 } 210 return false; 211 } 212 213 function logOff(){ 214 unset($_SESSION[DOKU_COOKIE]['authgoogle']['token']); 215 unset($_SESSION[DOKU_COOKIE]['authgoogle']['user']); 216 unset($_SESSION[DOKU_COOKIE]['authgoogle']['info']); 217 // clear the cookie 218 $this->_updateCookie('', time() - 600000); 219 } 220 221 function _updateCookie($value, $time) { 222 global $conf; 223 224 $cookieDir = empty($conf['cookiedir']) ? DOKU_REL : $conf['cookiedir']; 225 if (version_compare(PHP_VERSION, '5.2.0', '>')) { 226 setcookie(AUTHGOOGLE_COOKIE, $value, $time, $cookieDir, '', ($conf['securecookie'] && is_ssl()), true); 227 } else { 228 setcookie(AUTHGOOGLE_COOKIE, $value, $time, $cookieDir, '', ($conf['securecookie'] && is_ssl())); 229 } 230 } 231 232 function cleanUser($user){ 233 234 /* Sometimes system ask for a user in email format and we need to replace @ for _ 235 In this case, the user is not the logged in one. This happens mostly in the admin tools*/ 236 if(filter_var($user, FILTER_VALIDATE_EMAIL)){ 237 return str_replace("@", "_",$user); 238 } 239 /* Sometimes system ask for $login info, that is generated in the registration process some lines above 240 In this case we return the same username 241 TODO: check with a regexp */ 242 if(substr( $user, 0, 6 ) === "google"){ 243 return $user; 244 } 245 /* When ACL checks the username, it ask for the name of the user (that can be a serious security bug) 246 so, if the system ask for the name of the current user, I send the email replacing @ for _ cause the 247 user logged with googleauth can't change its email by hand. 248 */ 249 if ($user == $_SESSION[DOKU_COOKIE]['authgoogle']['user'] ){ 250 return str_replace("@", "_", $_SESSION[DOKU_COOKIE]['authgoogle']['info']['mail']); 251 } 252 /*Every other case return the same that you sent*/ 253 return $user; 254 } 255} 256?> 257