zen.php 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. <?php
  2. /**
  3. * The zen file of sso module of ZenTaoPMS.
  4. *
  5. * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
  6. * @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
  7. * @author Yidong Wang <yidong@easycorp.ltd>
  8. * @package sso
  9. * @link https://www.zentao.net
  10. */
  11. class ssoZen extends sso
  12. {
  13. /**
  14. * Get feishu accessToken.
  15. *
  16. * @param object $appConfig
  17. * @access protected
  18. * @return array
  19. */
  20. protected function getFeishuAccessToken($appConfig)
  21. {
  22. $appUrl = $this->config->sso->feishuAppInfoAPI;
  23. $appParams = array('app_id' => $appConfig->appId, 'app_secret' => $appConfig->appSecret);
  24. $appResult = common::http($appUrl, $appParams, array(), array(), 'json');
  25. if(empty($appResult)) return array('result' => 'fail', 'message' => $this->lang->sso->feishuResponseEmpty);
  26. $appInfo = json_decode($appResult);
  27. if(!isset($appInfo->msg) || $appInfo->msg != 'ok') return array('result' => 'fail', 'message' => $appResult);
  28. return array('result' => 'success', 'token' => $appInfo->app_access_token);
  29. }
  30. /**
  31. * Get feishu userToken.
  32. *
  33. * @param string $code
  34. * @param string $accessToken
  35. * @access protected
  36. * @return array
  37. */
  38. protected function getFeishuUserToken($code, $accessToken)
  39. {
  40. $tokenUrl = $this->config->sso->feishuTokenAPI;
  41. $tokenHeaders = array('Authorization: Bearer ' . $accessToken);
  42. $tokenParams = array('grant_type' => 'authorization_code', 'code' => $code);
  43. $tokenResult = common::http($tokenUrl, $tokenParams, array(), $tokenHeaders, 'json');
  44. if(empty($tokenResult)) return array('result' => 'fail', 'message' => $this->lang->sso->feishuResponseEmpty);
  45. $tokenInfo = json_decode($tokenResult);
  46. if(!isset($tokenInfo->msg) or $tokenInfo->msg != 'success') return array('result' => 'fail', 'message' => $tokenResult);
  47. return array('result' => 'success', 'token' => $tokenInfo->data->access_token);
  48. }
  49. /**
  50. * Get bind feishu user.
  51. *
  52. * @param string $userToken
  53. * @param object $feishuConfig
  54. * @access protected
  55. * @return array
  56. */
  57. protected function getBindFeishuUser($userToken, $feishuConfig)
  58. {
  59. $userUrl = $this->config->sso->feishuUserInfoAPI;
  60. $userHeaders = array('Authorization: Bearer ' . $userToken);
  61. $userResult = common::http($userUrl, array(), array(), $userHeaders, 'json');
  62. if(empty($userResult)) return array('result' => 'fail', 'message' => $this->lang->sso->feishuResponseEmpty);
  63. $userInfo = json_decode($userResult);
  64. if(!isset($userInfo->msg) or $userInfo->msg != 'success') return array('result' => 'fail', 'message' => $userResult);
  65. $openID = $userInfo->data->open_id;
  66. /* Get the user relationship bound in webhook. */
  67. $account = $this->loadModel('webhook')->getBindAccount($feishuConfig->id, 'webhook', $openID);
  68. if(empty($account)) return array('result' => 'fail', 'message' => $this->lang->sso->unbound);
  69. $user = $this->loadModel('user')->getById($account);
  70. return array('result' => 'success', 'user' => $user);
  71. }
  72. /**
  73. * Build user data for createUser method.
  74. *
  75. * @access protected
  76. * @return object
  77. */
  78. protected function buildUserForCreate()
  79. {
  80. return form::data($this->config->sso->form->createUser)->setDefault('ranzhi', $this->post->account)->get();
  81. }
  82. /**
  83. * Idenfy from SSO.
  84. *
  85. * @param string $locate
  86. * @access protected
  87. * @return bool
  88. */
  89. protected function idenfyFromSSO($locate)
  90. {
  91. if($this->get->status != 'success' || md5($this->get->data) != $this->get->md5) return false;
  92. $userIP = helper::getRemoteIp();
  93. $last = $this->server->request_time;
  94. $data = json_decode(base64_decode($this->get->data));
  95. if($data->auth != $this->computeAuth($data->token)) return false;
  96. $user = $this->sso->getBindUser($data->account);
  97. if(!$user)
  98. {
  99. $this->session->set('ssoData', $data);
  100. return $this->locate($this->createLink('sso', 'bind', "referer=" . helper::safe64Encode($locate)));
  101. }
  102. if($this->loadModel('user')->isLogon() and $this->session->user->account == $user->account) return $this->locate($locate);
  103. $user->last = date(DT_DATETIME1, (int)$last);
  104. $user->lastTime = $user->last;
  105. $user = $this->user->checkNeedModifyPassword($user, 0);
  106. $this->dao->update(TABLE_USER)->set('visits = visits + 1')->set('ip')->eq($userIP)->set('last')->eq($last)->where('account')->eq($user->account)->exec();
  107. $this->user->login($user);
  108. return $this->locate($locate);
  109. }
  110. /**
  111. * Locate notify link.
  112. *
  113. * @param string $location
  114. * @param string $referer
  115. * @access protected
  116. * @return void
  117. */
  118. protected function locateNotifyLink($location, $referer)
  119. {
  120. $isGet = strpos($location, '&') !== false;
  121. $requestType = $this->get->requestType;
  122. if(isset($requestType)) $isGet = $requestType == 'GET' ? true : false;
  123. if($isGet) $location = $this->buildLocationByGET($location, $referer);
  124. if(!$isGet) $location = $this->buildLocationByPATHINFO($location, $referer);
  125. if(!empty($_GET['sessionid']))
  126. {
  127. $sessionConfig = json_decode(base64_decode($this->get->sessionid), false);
  128. $location .= '&' . $sessionConfig->session_name . '=' . $sessionConfig->session_id;
  129. }
  130. $this->locate($location);
  131. }
  132. /**
  133. * Build location by GET.
  134. *
  135. * @param string $location
  136. * @param string $referer
  137. * @access private
  138. * @return string
  139. */
  140. private function buildLocationByGET($location, $referer)
  141. {
  142. if(strpos($location, '&') === false)
  143. {
  144. $position = strrpos($location, '/') + 1;
  145. $uri = substr($location, 0 ,$position);
  146. $param = str_replace('.html', '', substr($location, $position));
  147. list($module, $method) = explode('-', $param);
  148. $location = $uri . 'index.php?m=' . $module . '&f=' . $method;
  149. }
  150. return rtrim($location, '&') . '&' . $this->buildSSOParams($referer);
  151. }
  152. /**
  153. * Build location by PATH_INFO.
  154. *
  155. * @param string $location
  156. * @param string $referer
  157. * @access private
  158. * @return string
  159. */
  160. private function buildLocationByPATHINFO($location, $referer)
  161. {
  162. if(strpos($location, '&') !== false)
  163. {
  164. list($uri, $param) = explode('index.php', $location);
  165. $param = substr($param, 1);
  166. parse_str($param, $result);
  167. $location = $uri . $result['m'] . '-' . $result['f'] . '.html';
  168. }
  169. return rtrim($location, '?') . '?' . $this->buildSSOParams($referer);
  170. }
  171. /**
  172. * Build SSO params.
  173. *
  174. * @param string $referer
  175. * @access private
  176. * @return string
  177. */
  178. private function buildSSOParams($referer)
  179. {
  180. $userIP = helper::getRemoteIp();
  181. $token = $this->get->token;
  182. $auth = $this->computeAuth($token);
  183. $callback = urlencode(common::getSysURL() . inlink('login', "type=return"));
  184. return "token=$token&auth=$auth&userIP=$userIP&callback=$callback&referer=$referer";
  185. }
  186. /**
  187. * Compute auth.
  188. *
  189. * @access private
  190. * @return string
  191. * @param string $token
  192. */
  193. private function computeAuth($token)
  194. {
  195. $userIP = helper::getRemoteIp();
  196. $code = $this->config->sso->code;
  197. $key = $this->config->sso->key;
  198. return md5($code . $userIP . $token . $key);
  199. }
  200. }