control.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. <?php
  2. /**
  3. * The control file of sso module of ZenTaoPMS.
  4. *
  5. * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
  6. * @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
  7. * @author Yidong Wang <yidong@cnezsoft.com>
  8. * @package sso
  9. * @version $Id: control.php 4460 2013-02-26 02:28:02Z chencongzhi520@gmail.com $
  10. * @link https://www.zentao.net
  11. */
  12. class sso extends control
  13. {
  14. /**
  15. * SSO login.
  16. *
  17. * @param string $type notify|return
  18. * @access public
  19. * @return void
  20. */
  21. public function login($type = 'notify')
  22. {
  23. $referer = empty($_GET['referer']) ? '' : $this->get->referer;
  24. $locate = empty($referer) ? getWebRoot() : base64_decode($referer);
  25. $this->app->loadConfig('sso');
  26. if(!$this->config->sso->turnon) return print($this->locate($locate));
  27. if($type != 'return') return $this->ssoZen->locateNotifyLink($this->config->sso->addr, $referer);
  28. $this->ssoZen->idenfyFromSSO($locate);
  29. return $this->locate($this->createLink('user', 'login', empty($referer) ? '' : "referer=$referer"));
  30. }
  31. /**
  32. * SSO logout.
  33. *
  34. * @param string $type
  35. * @access public
  36. * @return void
  37. */
  38. public function logout($type = 'notify')
  39. {
  40. if($type != 'return')
  41. {
  42. $userIP = helper::getRemoteIp();
  43. $token = $this->get->token;
  44. $auth = $this->ssoZen->computeAuth($token);
  45. $callback = urlencode(common::getSysURL() . inlink('logout', "type=return"));
  46. $location = $this->config->sso->addr;
  47. $sign = strpos($location, '&') !== false ? '&' : '?';
  48. $location = rtrim($location, $sign) . "{$sign}token={$token}&auth={$auth}&userIP={$userIP}&callback={$callback}";
  49. return $this->locate($location);
  50. }
  51. if($this->get->status == 'success')
  52. {
  53. session_destroy();
  54. helper::setcookie('za', false);
  55. helper::setcookie('zp', false);
  56. return $this->locate($this->createLink('user', 'login'));
  57. }
  58. return $this->locate($this->createLink('user', 'logout'));
  59. }
  60. /**
  61. * Ajax set config.
  62. *
  63. * @access public
  64. * @return void
  65. */
  66. public function ajaxSetConfig()
  67. {
  68. if(!$this->app->user->admin) return print('deny');
  69. if($_POST)
  70. {
  71. $ssoConfig = new stdclass();
  72. $ssoConfig->turnon = 1;
  73. $ssoConfig->addr = $this->post->addr;
  74. $ssoConfig->code = trim($this->post->code);
  75. $ssoConfig->key = trim($this->post->key);
  76. $this->loadModel('setting')->setItems('system.sso', $ssoConfig);
  77. if(dao::isError()) return print('fail');
  78. return print('success');
  79. }
  80. }
  81. /**
  82. * Bind user.
  83. *
  84. * @param string $referer
  85. * @access public
  86. * @return void
  87. */
  88. public function bind($referer = '')
  89. {
  90. if(!$this->session->ssoData) return;
  91. $ssoData = $this->session->ssoData;
  92. if($ssoData->auth != $this->computeAuth($ssoData->token)) return;
  93. $this->loadModel('user');
  94. if($_POST)
  95. {
  96. $user = $this->sso->bind();
  97. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  98. $user->last = date(DT_DATETIME1);
  99. $this->user->login($user);
  100. unset($_SESSION['ssoData']);
  101. return $this->send(array('result' => 'success', 'load' => helper::safe64Decode($referer)));
  102. }
  103. $this->view->title = $this->lang->sso->bind;
  104. $this->view->users = $this->user->getPairs('noclosed|nodeleted');
  105. $this->view->data = $ssoData;
  106. $this->display();
  107. }
  108. /**
  109. * Get pairs of user.
  110. *
  111. * @access public
  112. * @return void
  113. */
  114. public function getUserPairs()
  115. {
  116. if(!$this->sso->checkKey()) return false;
  117. $users = $this->loadModel('user')->getPairs('noclosed|nodeleted');
  118. echo json_encode($users);
  119. }
  120. /**
  121. * Get bind users with ranzhi.
  122. *
  123. * @access public
  124. * @return void
  125. */
  126. public function getBindUsers()
  127. {
  128. if(!$this->sso->checkKey()) return false;
  129. $users = $this->sso->getBindUsers();
  130. echo json_encode($users);
  131. }
  132. /**
  133. * Bind user from ranzhi.
  134. *
  135. * @access public
  136. * @return void
  137. */
  138. public function bindUser()
  139. {
  140. if($_POST)
  141. {
  142. $this->dao->update(TABLE_USER)->set('ranzhi')->eq('')->where('ranzhi')->eq($this->post->ranzhiAccount)->exec();
  143. $this->dao->update(TABLE_USER)->set('ranzhi')->eq($this->post->ranzhiAccount)->where('account')->eq($this->post->zentaoAccount)->exec();
  144. if(dao::isError()) return print(implode("\n", dao::getError()));
  145. return print('success');
  146. }
  147. }
  148. /**
  149. * Create user from ranzhi.
  150. *
  151. * @access public
  152. * @return void
  153. */
  154. public function createUser()
  155. {
  156. if($_POST)
  157. {
  158. $user = $this->ssoZen->buildUserForCreate();
  159. $result = $this->sso->createUser($user);
  160. if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $result['id']));
  161. if($result['status'] != 'success') return print($result['data']);
  162. return print('success');
  163. }
  164. }
  165. /**
  166. * Get todo list for ranzhi.
  167. *
  168. * @param string $account
  169. * @access public
  170. * @return void
  171. */
  172. public function getTodoList($account = '')
  173. {
  174. if(!$this->sso->checkKey()) return false;
  175. $user = $this->dao->select('*')->from(TABLE_USER)->where('ranzhi')->eq($account)->andWhere('deleted')->eq(0)->fetch();
  176. if($user) $account = $user->account;
  177. $datas = array();
  178. $datas['task'] = $this->dao->select("id,name")->from(TABLE_TASK)->where('assignedTo')->eq($account)->andWhere('status')->in('wait,doing')->andWhere('deleted')->eq(0)->fetchPairs();
  179. $datas['bug'] = $this->dao->select("id,title")->from(TABLE_BUG)->where('assignedTo')->eq($account)->andWhere('status')->eq('active')->andWhere('deleted')->eq(0)->fetchPairs();
  180. echo json_encode($datas);
  181. }
  182. /**
  183. * Get the link to the Feishu single sign-on configuration.
  184. *
  185. * @access public
  186. * @return void
  187. */
  188. public function getFeishuSSO()
  189. {
  190. $httpType = ((isset($_SERVER['HTTPS']) and $_SERVER['HTTPS'] == 'on') or (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) and $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) ? 'https://' : 'http://';
  191. $applicationHome = $httpType . $_SERVER['HTTP_HOST'] . $this->createLink('sso', 'feishuAuthen');
  192. $redirectLink = $httpType . $_SERVER['HTTP_HOST'] . $this->createLink('sso', 'feishuLogin');
  193. echo $this->lang->sso->homeURL . $applicationHome;
  194. echo '<br>';
  195. echo $this->lang->sso->redirectURL . $redirectLink;
  196. }
  197. /**
  198. * Get the pre-authorization code for Feishu code.
  199. *
  200. * @access public
  201. * @return void
  202. */
  203. public function feishuAuthen()
  204. {
  205. $params = $_SERVER["QUERY_STRING"];
  206. parse_str($params, $params);
  207. $webhookID = isset($params['id']) ? (int)$params['id'] : 0;
  208. $httpType = ((isset($_SERVER['HTTPS']) and $_SERVER['HTTPS'] == 'on') or (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) and $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) ? 'https://' : 'http://';
  209. $redirectURI = $httpType . $_SERVER['HTTP_HOST'] . $this->createLink('sso', 'feishuLogin');
  210. if($webhookID) $redirectURI .= (strpos($redirectURI, '?') === false ? '?' : '&') . "id={$webhookID}";
  211. $feishuConfig = $this->loadModel('webhook')->getByType('feishuuser', $webhookID);
  212. if(empty($feishuConfig)) $this->showError($this->lang->sso->feishuConfigEmpty);
  213. $appConfig = json_decode($feishuConfig->secret);
  214. $appID = $appConfig->appId;
  215. $url = sprintf($this->config->sso->feishuAuthAPI, urlencode($redirectURI), $appID);
  216. $this->locate($url);
  217. }
  218. /**
  219. * Get the identity of the logged-in user.
  220. *
  221. * @access public
  222. * @return void
  223. */
  224. public function feishuLogin()
  225. {
  226. $params = $_SERVER["QUERY_STRING"];
  227. parse_str($params, $params);
  228. $webhookID = isset($params['id']) ? (int)$params['id'] : 0;
  229. $code = isset($params['code']) ? $params['code'] : '';
  230. $feishuConfig = $this->loadModel('webhook')->getByType('feishuuser', $webhookID);
  231. if(empty($feishuConfig)) $this->showError($this->lang->sso->feishuConfigEmpty);
  232. $appConfig = json_decode($feishuConfig->secret);
  233. /* Obtain the access credentials of the Feishu app. */
  234. $appResult = $this->ssoZen->getFeishuAccessToken($appConfig);
  235. if($appResult['result'] == 'fail') return $this->showError($appResult['message']);
  236. $accessToken = $appResult['token'];
  237. /* Verify the identity of the logged in user. */
  238. $tokenResult = $this->ssoZen->getFeishuUserToken($code, $accessToken);
  239. if($tokenResult['result'] == 'fail') return $this->showError($tokenResult['message']);
  240. $userToken = $tokenResult['token'];
  241. /* Get login user information. */
  242. $userResult = $this->ssoZen->getBindFeishuUser($userToken, $feishuConfig);
  243. if($userResult['result'] == 'fail') return $this->showError($userResult['message']);
  244. $user = $userResult['user'];
  245. $this->session->set('rand', '');
  246. $user = $this->loadModel('user')->identify($user->account, $user->password);
  247. $this->user->login($user);
  248. $this->locate($this->createLink('my', 'index'));
  249. }
  250. /**
  251. * Display the error message.
  252. *
  253. * @param string $message
  254. * @access public
  255. * @return void
  256. */
  257. public function showError($message = '')
  258. {
  259. $this->view->title = $this->lang->sso->deny;
  260. $this->view->message = $message;
  261. $this->display('sso', 'error');
  262. }
  263. }