Sts.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. <?php
  2. namespace QCloud\COSSTS;
  3. class Sts{
  4. // 临时密钥计算样例
  5. function _hex2bin($data) {
  6. $len = strlen($data);
  7. return pack("H" . $len, $data);
  8. }
  9. // obj 转 query string
  10. function json2str($obj, $notEncode = false) {
  11. ksort($obj);
  12. $arr = array();
  13. if(!is_array($obj)){
  14. throw new \Exception('$obj must be an array, the actual value is:' . json_encode($obj));
  15. }
  16. foreach ($obj as $key => $val) {
  17. array_push($arr, $key . '=' . ($notEncode ? $val : rawurlencode($val)));
  18. }
  19. return join('&', $arr);
  20. }
  21. // 计算临时密钥用的签名
  22. function getSignature($opt, $key, $method, $config) {
  23. $host = "sts.tencentcloudapi.com";
  24. if (array_key_exists('domain', $config)) {
  25. $host = $config['domain'];
  26. }
  27. if (array_key_exists('endpoint', $config)) {
  28. $host = "sts." . $config['endpoint'];
  29. }
  30. $formatString = $method . $host . '/?' . $this->json2str($opt, 1);
  31. $sign = hash_hmac('sha1', $formatString, $key);
  32. $sign = base64_encode($this->_hex2bin($sign));
  33. return $sign;
  34. }
  35. // v2接口的key首字母小写,v3改成大写,此处做了向下兼容
  36. function backwardCompat($result) {
  37. if(!is_array($result)){
  38. throw new \Exception('$result must be an array, the actual value is:' . json_encode($result));
  39. }
  40. $compat = array();
  41. foreach ($result as $key => $value) {
  42. if(is_array($value)) {
  43. $compat[lcfirst($key)] = $this->backwardCompat($value);
  44. } elseif ($key == 'Token') {
  45. $compat['sessionToken'] = $value;
  46. } else {
  47. $compat[lcfirst($key)] = $value;
  48. }
  49. }
  50. return $compat;
  51. }
  52. // 获取临时密钥
  53. function getTempKeys($config) {
  54. $result = null;
  55. try{
  56. if(array_key_exists('policy', $config)){
  57. $policy = $config['policy'];
  58. }else{
  59. if(array_key_exists('bucket', $config)){
  60. $ShortBucketName = substr($config['bucket'],0, strripos($config['bucket'], '-'));
  61. $AppId = substr($config['bucket'], 1 + strripos($config['bucket'], '-'));
  62. }else{
  63. throw new \Exception("bucket== null");
  64. }
  65. if(array_key_exists('allowPrefix', $config)){
  66. $resource = array();
  67. foreach($config['allowPrefix'] as &$val) {
  68. if (!(strpos($val, '/') === 0)) {
  69. $allow = '/' . $val;
  70. }
  71. $resource[] = 'qcs::cos:' . $config['region'] . ':uid/' . $AppId . ':' . $config['bucket'] . '/' . $val;
  72. }
  73. // 处理万象资源
  74. if(array_key_exists('allowCiSource', $config) && $config['allowCiSource'] === true) {
  75. $resource[] = 'qcs::ci:' . $config['region'] . ':uid/' . $AppId . ':' . 'bucket/' . $config['bucket'] . '/*';
  76. }
  77. }else{
  78. throw new \Exception("allowPrefix == null");
  79. }
  80. if(!array_key_exists('region', $config)) {
  81. throw new \Exception("region == null");
  82. }
  83. if (!array_key_exists('condition', $config)) {
  84. $policy = array(
  85. 'version'=> '2.0',
  86. 'statement'=> array(
  87. array(
  88. 'action'=> $config['allowActions'],
  89. 'effect'=> 'allow',
  90. 'resource'=> $resource
  91. )
  92. )
  93. );
  94. } else {
  95. $policy = array(
  96. 'version'=> '2.0',
  97. 'statement'=> array(
  98. array(
  99. 'action'=> $config['allowActions'],
  100. 'effect'=> 'allow',
  101. 'resource'=> $resource,
  102. 'condition'=>$config['condition']
  103. )
  104. )
  105. );
  106. }
  107. }
  108. $policyStr = str_replace('\\/', '/', json_encode($policy));
  109. $Action = 'GetFederationToken';
  110. $Nonce = rand(10000, 20000);
  111. $Timestamp = time();
  112. $Method = 'POST';
  113. if(array_key_exists('durationSeconds', $config)){
  114. if(!(is_integer($config['durationSeconds']))){
  115. throw new \Exception("durationSeconds must be a int type");
  116. }
  117. }
  118. $params = array(
  119. 'SecretId'=> $config['secretId'],
  120. 'Timestamp'=> $Timestamp,
  121. 'Nonce'=> $Nonce,
  122. 'Action'=> $Action,
  123. 'DurationSeconds'=> $config['durationSeconds'],
  124. 'Version'=>'2018-08-13',
  125. 'Name'=> 'cos',
  126. 'Region'=> $config['region'],
  127. 'Policy'=> urlencode($policyStr)
  128. );
  129. $params['Signature'] = $this->getSignature($params, $config['secretKey'], $Method, $config);
  130. $url = 'https://sts.tencentcloudapi.com/';
  131. if(array_key_exists('url', $config)) {
  132. $url = $config['url'];
  133. }
  134. if(!array_key_exists('url', $config) && array_key_exists('domain', $config)) {
  135. $url = 'https://sts.' . $config['domain'];
  136. }
  137. if(array_key_exists('endpoint', $config)) {
  138. $url = 'https://sts.' . $config['endpoint'];
  139. }
  140. $ch = curl_init($url);
  141. if(array_key_exists('proxy', $config)){
  142. $config['proxy'] && curl_setopt($ch, CURLOPT_PROXY, $config['proxy']);
  143. }
  144. curl_setopt($ch, CURLOPT_HEADER, 0);
  145. curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,0);
  146. curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,0);
  147. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  148. curl_setopt($ch, CURLOPT_POST, 1);
  149. curl_setopt($ch, CURLOPT_POSTFIELDS, $this->json2str($params));
  150. $result = curl_exec($ch);
  151. if(curl_errno($ch)) $result = curl_error($ch);
  152. curl_close($ch);
  153. $result = json_decode($result, 1);
  154. if (isset($result['Response'])) {
  155. $result = $result['Response'];
  156. if(isset($result['Error'])){
  157. throw new \Exception("get cam failed");
  158. }
  159. $result['startTime'] = $result['ExpiredTime'] - $config['durationSeconds'];
  160. }
  161. $result = $this->backwardCompat($result);
  162. return $result;
  163. }catch(\Exception $e){
  164. if($result == null){
  165. $result = "error: " . $e->getMessage();
  166. }else{
  167. $result = json_encode($result);
  168. }
  169. throw new \Exception($result);
  170. }
  171. }
  172. // 获取临时密钥-兼容万象资源 不在维护,请使用getTempKeys函数,$config的ci_source字段
  173. function getTempKeys4Ci($config) {
  174. $result = null;
  175. try{
  176. if(array_key_exists('policy', $config)){
  177. $policy = $config['policy'];
  178. }else{
  179. if(array_key_exists('bucket', $config)){
  180. $ShortBucketName = substr($config['bucket'],0, strripos($config['bucket'], '-'));
  181. $AppId = substr($config['bucket'], 1 + strripos($config['bucket'], '-'));
  182. }else{
  183. throw new Exception("bucket== null");
  184. }
  185. $resource = array();
  186. $resource[] = 'qcs::ci:' . $config['region'] . ':uid/' . $AppId . ':' . 'bucket/' . $config['bucket'] . '/*';
  187. if(array_key_exists('allowPrefix', $config)){
  188. foreach($config['allowPrefix'] as &$val) {
  189. if (!(strpos($val, '/') === 0)) {
  190. $allow = '/' . $val;
  191. }
  192. $resource[] = 'qcs::cos:' . $config['region'] . ':uid/' . $AppId . ':' . $config['bucket'] . '/' . $val;
  193. }
  194. }else{
  195. throw new \Exception("allowPrefix == null");
  196. }
  197. if(!array_key_exists('region', $config)) {
  198. throw new \Exception("region == null");
  199. }
  200. if (!array_key_exists('condition', $config)) {
  201. $policy = array(
  202. 'version'=> '2.0',
  203. 'statement'=> array(
  204. array(
  205. 'action'=> $config['allowActions'],
  206. 'effect'=> 'allow',
  207. 'resource'=> $resource
  208. )
  209. )
  210. );
  211. } else {
  212. $policy = array(
  213. 'version'=> '2.0',
  214. 'statement'=> array(
  215. array(
  216. 'action'=> $config['allowActions'],
  217. 'effect'=> 'allow',
  218. 'resource'=> $resource,
  219. 'condition'=>$config['condition']
  220. )
  221. )
  222. );
  223. }
  224. }
  225. $policyStr = str_replace('\\/', '/', json_encode($policy));
  226. $Action = 'GetFederationToken';
  227. $Nonce = rand(10000, 20000);
  228. $Timestamp = time();
  229. $Method = 'POST';
  230. if(array_key_exists('durationSeconds', $config)){
  231. if(!(is_integer($config['durationSeconds']))){
  232. throw new \Exception("durationSeconds must be a int type");
  233. }
  234. }
  235. $params = array(
  236. 'SecretId'=> $config['secretId'],
  237. 'Timestamp'=> $Timestamp,
  238. 'Nonce'=> $Nonce,
  239. 'Action'=> $Action,
  240. 'DurationSeconds'=> $config['durationSeconds'],
  241. 'Version'=>'2018-08-13',
  242. 'Name'=> 'cos',
  243. 'Region'=> $config['region'],
  244. 'Policy'=> urlencode($policyStr)
  245. );
  246. $params['Signature'] = $this->getSignature($params, $config['secretKey'], $Method, $config);
  247. $url = 'https://sts.tencentcloudapi.com/';
  248. if(array_key_exists('url', $config)) {
  249. $url = $config['url'];
  250. }
  251. if(!array_key_exists('url', $config) && array_key_exists('domain', $config)) {
  252. $url = 'https://sts.' . $config['domain'];
  253. }
  254. if(array_key_exists('endpoint', $config)) {
  255. $url = 'https://sts.' . $config['endpoint'];
  256. }
  257. $ch = curl_init($url);
  258. if(array_key_exists('proxy', $config)){
  259. $config['proxy'] && curl_setopt($ch, CURLOPT_PROXY, $config['proxy']);
  260. }
  261. curl_setopt($ch, CURLOPT_HEADER, 0);
  262. curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,0);
  263. curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,0);
  264. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  265. curl_setopt($ch, CURLOPT_POST, 1);
  266. curl_setopt($ch, CURLOPT_POSTFIELDS, $this->json2str($params));
  267. $result = curl_exec($ch);
  268. if(curl_errno($ch)) $result = curl_error($ch);
  269. curl_close($ch);
  270. $result = json_decode($result, 1);
  271. if (isset($result['Response'])) {
  272. $result = $result['Response'];
  273. if(isset($result['Error'])){
  274. throw new \Exception("get cam failed");
  275. }
  276. $result['startTime'] = $result['ExpiredTime'] - $config['durationSeconds'];
  277. }
  278. $result = $this->backwardCompat($result);
  279. return $result;
  280. }catch(\Exception $e){
  281. if($result == null){
  282. $result = "error: " . $e->getMessage();
  283. }else{
  284. $result = json_encode($result);
  285. }
  286. throw new \Exception($result);
  287. }
  288. }
  289. //申请角色授权
  290. function getRoleCredential($config) {
  291. $result = null;
  292. try{
  293. if(array_key_exists('policy', $config)){
  294. $policy = $config['policy'];
  295. }else{
  296. if(array_key_exists('bucket', $config)){
  297. $ShortBucketName = substr($config['bucket'],0, strripos($config['bucket'], '-'));
  298. $AppId = substr($config['bucket'], 1 + strripos($config['bucket'], '-'));
  299. }else{
  300. throw new \Exception("bucket== null");
  301. }
  302. if(array_key_exists('allowPrefix', $config)){
  303. $resource = array();
  304. foreach($config['allowPrefix'] as &$val) {
  305. if (!(strpos($val, '/') === 0)) {
  306. $allow = '/' . $val;
  307. }
  308. $resource[] = 'qcs::cos:' . $config['region'] . ':uid/' . $AppId . ':' . $config['bucket'] . '/' . $val;
  309. }
  310. }else{
  311. throw new \Exception("allowPrefix == null");
  312. }
  313. if(!array_key_exists('region', $config)) {
  314. throw new \Exception("region == null");
  315. }
  316. if (!array_key_exists('condition', $config)) {
  317. $policy = array(
  318. 'version'=> '2.0',
  319. 'statement'=> array(
  320. array(
  321. 'action'=> $config['allowActions'],
  322. 'effect'=> 'allow',
  323. 'resource'=> $resource
  324. )
  325. )
  326. );
  327. } else {
  328. $policy = array(
  329. 'version'=> '2.0',
  330. 'statement'=> array(
  331. array(
  332. 'action'=> $config['allowActions'],
  333. 'effect'=> 'allow',
  334. 'resource'=> $resource,
  335. 'condition'=>$config['condition']
  336. )
  337. )
  338. );
  339. }
  340. }
  341. if (array_key_exists('roleArn', $config)) {
  342. $RoleArn = $config['roleArn'];
  343. } else {
  344. throw new \Exception("roleArn == null");
  345. }
  346. $policyStr = str_replace('\\/', '/', json_encode($policy));
  347. $Action = 'AssumeRole';
  348. $Nonce = rand(10000, 20000);
  349. $Timestamp = time();
  350. $Method = 'POST';
  351. $ExternalId = "";
  352. if (array_key_exists('externalId', $config)) {
  353. $ExternalId = $config['externalId'];
  354. }
  355. if(array_key_exists('durationSeconds', $config)){
  356. if(!(is_integer($config['durationSeconds']))){
  357. throw new \Exception("durationSeconds must be a int type");
  358. }
  359. }
  360. $params = array(
  361. 'SecretId'=> $config['secretId'],
  362. 'Timestamp'=> $Timestamp,
  363. 'RoleArn'=> $RoleArn,
  364. 'Action'=> $Action,
  365. 'Nonce'=> $Nonce,
  366. 'DurationSeconds'=> $config['durationSeconds'],
  367. 'Version'=>'2018-08-13',
  368. 'RoleSessionName'=> 'cos',
  369. 'Region'=> $config['region'],
  370. 'ExternalId' => $ExternalId,
  371. 'Policy'=> urlencode($policyStr)
  372. );
  373. $params['Signature'] = $this->getSignature($params, $config['secretKey'], $Method, $config);
  374. $url = 'https://sts.internal.tencentcloudapi.com/';
  375. if(array_key_exists('endpoint', $config)) {
  376. $url = 'https://sts.' . $config['endpoint'];
  377. }
  378. $ch = curl_init($url);
  379. if(array_key_exists('proxy', $config)){
  380. $config['proxy'] && curl_setopt($ch, CURLOPT_PROXY, $config['proxy']);
  381. }
  382. curl_setopt($ch, CURLOPT_HEADER, 0);
  383. curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,0);
  384. curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,0);
  385. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  386. curl_setopt($ch, CURLOPT_POST, 1);
  387. curl_setopt($ch, CURLOPT_POSTFIELDS, $this->json2str($params));
  388. $result = curl_exec($ch);
  389. if(curl_errno($ch)) $result = curl_error($ch);
  390. curl_close($ch);
  391. $result = json_decode($result, 1);
  392. if (isset($result['Response'])) {
  393. $result = $result['Response'];
  394. if(isset($result['Error'])){
  395. throw new \Exception("get cam failed");
  396. }
  397. $result['startTime'] = $result['ExpiredTime'] - $config['durationSeconds'];
  398. }
  399. $result = $this->backwardCompat($result);
  400. return $result;
  401. }catch(\Exception $e){
  402. if($result == null){
  403. $result = "error: " . $e->getMessage();
  404. }else{
  405. $result = json_encode($result);
  406. }
  407. throw new \Exception($result);
  408. }
  409. }
  410. // get policy
  411. function getPolicy($scopes){
  412. if (!is_array($scopes)){
  413. return null;
  414. }
  415. $statements = array();
  416. for($i=0, $counts=count($scopes); $i < $counts; $i++){
  417. $actions=array();
  418. $resources = array();
  419. array_push($actions, $scopes[$i]->get_action());
  420. array_push($resources, $scopes[$i]->get_resource());
  421. $statement = array(
  422. 'action' => $actions,
  423. 'effect' => $scopes[$i]->get_effect(),
  424. 'resource' => $resources
  425. );
  426. array_push($statements, $statement);
  427. }
  428. $policy = array(
  429. 'version' => '2.0',
  430. 'statement' => $statements
  431. );
  432. return $policy;
  433. }
  434. }
  435. ?>