* @package sso * @link https://www.zentao.net */ class ssoZen extends sso { /** * Get feishu accessToken. * * @param object $appConfig * @access protected * @return array */ protected function getFeishuAccessToken($appConfig) { $appUrl = $this->config->sso->feishuAppInfoAPI; $appParams = array('app_id' => $appConfig->appId, 'app_secret' => $appConfig->appSecret); $appResult = common::http($appUrl, $appParams, array(), array(), 'json'); if(empty($appResult)) return array('result' => 'fail', 'message' => $this->lang->sso->feishuResponseEmpty); $appInfo = json_decode($appResult); if(!isset($appInfo->msg) || $appInfo->msg != 'ok') return array('result' => 'fail', 'message' => $appResult); return array('result' => 'success', 'token' => $appInfo->app_access_token); } /** * Get feishu userToken. * * @param string $code * @param string $accessToken * @access protected * @return array */ protected function getFeishuUserToken($code, $accessToken) { $tokenUrl = $this->config->sso->feishuTokenAPI; $tokenHeaders = array('Authorization: Bearer ' . $accessToken); $tokenParams = array('grant_type' => 'authorization_code', 'code' => $code); $tokenResult = common::http($tokenUrl, $tokenParams, array(), $tokenHeaders, 'json'); if(empty($tokenResult)) return array('result' => 'fail', 'message' => $this->lang->sso->feishuResponseEmpty); $tokenInfo = json_decode($tokenResult); if(!isset($tokenInfo->msg) or $tokenInfo->msg != 'success') return array('result' => 'fail', 'message' => $tokenResult); return array('result' => 'success', 'token' => $tokenInfo->data->access_token); } /** * Get bind feishu user. * * @param string $userToken * @param object $feishuConfig * @access protected * @return array */ protected function getBindFeishuUser($userToken, $feishuConfig) { $userUrl = $this->config->sso->feishuUserInfoAPI; $userHeaders = array('Authorization: Bearer ' . $userToken); $userResult = common::http($userUrl, array(), array(), $userHeaders, 'json'); if(empty($userResult)) return array('result' => 'fail', 'message' => $this->lang->sso->feishuResponseEmpty); $userInfo = json_decode($userResult); if(!isset($userInfo->msg) or $userInfo->msg != 'success') return array('result' => 'fail', 'message' => $userResult); $openID = $userInfo->data->open_id; /* Get the user relationship bound in webhook. */ $account = $this->loadModel('webhook')->getBindAccount($feishuConfig->id, 'webhook', $openID); if(empty($account)) return array('result' => 'fail', 'message' => $this->lang->sso->unbound); $user = $this->loadModel('user')->getById($account); return array('result' => 'success', 'user' => $user); } /** * Build user data for createUser method. * * @access protected * @return object */ protected function buildUserForCreate() { return form::data($this->config->sso->form->createUser)->setDefault('ranzhi', $this->post->account)->get(); } /** * Idenfy from SSO. * * @param string $locate * @access protected * @return bool */ protected function idenfyFromSSO($locate) { if($this->get->status != 'success' || md5($this->get->data) != $this->get->md5) return false; $userIP = helper::getRemoteIp(); $last = $this->server->request_time; $data = json_decode(base64_decode($this->get->data)); if($data->auth != $this->computeAuth($data->token)) return false; $user = $this->sso->getBindUser($data->account); if(!$user) { $this->session->set('ssoData', $data); return $this->locate($this->createLink('sso', 'bind', "referer=" . helper::safe64Encode($locate))); } if($this->loadModel('user')->isLogon() and $this->session->user->account == $user->account) return $this->locate($locate); $user->last = date(DT_DATETIME1, (int)$last); $user->lastTime = $user->last; $user = $this->user->checkNeedModifyPassword($user, 0); $this->dao->update(TABLE_USER)->set('visits = visits + 1')->set('ip')->eq($userIP)->set('last')->eq($last)->where('account')->eq($user->account)->exec(); $this->user->login($user); return $this->locate($locate); } /** * Locate notify link. * * @param string $location * @param string $referer * @access protected * @return void */ protected function locateNotifyLink($location, $referer) { $isGet = strpos($location, '&') !== false; $requestType = $this->get->requestType; if(isset($requestType)) $isGet = $requestType == 'GET' ? true : false; if($isGet) $location = $this->buildLocationByGET($location, $referer); if(!$isGet) $location = $this->buildLocationByPATHINFO($location, $referer); if(!empty($_GET['sessionid'])) { $sessionConfig = json_decode(base64_decode($this->get->sessionid), false); $location .= '&' . $sessionConfig->session_name . '=' . $sessionConfig->session_id; } $this->locate($location); } /** * Build location by GET. * * @param string $location * @param string $referer * @access private * @return string */ private function buildLocationByGET($location, $referer) { if(strpos($location, '&') === false) { $position = strrpos($location, '/') + 1; $uri = substr($location, 0 ,$position); $param = str_replace('.html', '', substr($location, $position)); list($module, $method) = explode('-', $param); $location = $uri . 'index.php?m=' . $module . '&f=' . $method; } return rtrim($location, '&') . '&' . $this->buildSSOParams($referer); } /** * Build location by PATH_INFO. * * @param string $location * @param string $referer * @access private * @return string */ private function buildLocationByPATHINFO($location, $referer) { if(strpos($location, '&') !== false) { list($uri, $param) = explode('index.php', $location); $param = substr($param, 1); parse_str($param, $result); $location = $uri . $result['m'] . '-' . $result['f'] . '.html'; } return rtrim($location, '?') . '?' . $this->buildSSOParams($referer); } /** * Build SSO params. * * @param string $referer * @access private * @return string */ private function buildSSOParams($referer) { $userIP = helper::getRemoteIp(); $token = $this->get->token; $auth = $this->computeAuth($token); $callback = urlencode(common::getSysURL() . inlink('login', "type=return")); return "token=$token&auth=$auth&userIP=$userIP&callback=$callback&referer=$referer"; } /** * Compute auth. * * @access private * @return string * @param string $token */ private function computeAuth($token) { $userIP = helper::getRemoteIp(); $code = $this->config->sso->code; $key = $this->config->sso->key; return md5($code . $userIP . $token . $key); } }