credential.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. package credentials
  2. import (
  3. "bufio"
  4. "errors"
  5. "fmt"
  6. "net/http"
  7. "net/url"
  8. "os"
  9. "strings"
  10. "time"
  11. "github.com/alibabacloud-go/debug/debug"
  12. "github.com/alibabacloud-go/tea/tea"
  13. "github.com/aliyun/credentials-go/credentials/request"
  14. "github.com/aliyun/credentials-go/credentials/response"
  15. "github.com/aliyun/credentials-go/credentials/utils"
  16. )
  17. var debuglog = debug.Init("credential")
  18. var hookParse = func(err error) error {
  19. return err
  20. }
  21. // Credential is an interface for getting actual credential
  22. type Credential interface {
  23. GetAccessKeyId() (*string, error)
  24. GetAccessKeySecret() (*string, error)
  25. GetSecurityToken() (*string, error)
  26. GetBearerToken() *string
  27. GetType() *string
  28. }
  29. // Config is important when call NewCredential
  30. type Config struct {
  31. Type *string `json:"type"`
  32. AccessKeyId *string `json:"access_key_id"`
  33. AccessKeySecret *string `json:"access_key_secret"`
  34. RoleArn *string `json:"role_arn"`
  35. RoleSessionName *string `json:"role_session_name"`
  36. PublicKeyId *string `json:"public_key_id"`
  37. RoleName *string `json:"role_name"`
  38. SessionExpiration *int `json:"session_expiration"`
  39. PrivateKeyFile *string `json:"private_key_file"`
  40. BearerToken *string `json:"bearer_token"`
  41. SecurityToken *string `json:"security_token"`
  42. RoleSessionExpiration *int `json:"role_session_expiratioon"`
  43. Policy *string `json:"policy"`
  44. Host *string `json:"host"`
  45. Timeout *int `json:"timeout"`
  46. ConnectTimeout *int `json:"connect_timeout"`
  47. Proxy *string `json:"proxy"`
  48. }
  49. func (s Config) String() string {
  50. return tea.Prettify(s)
  51. }
  52. func (s Config) GoString() string {
  53. return s.String()
  54. }
  55. func (s *Config) SetAccessKeyId(v string) *Config {
  56. s.AccessKeyId = &v
  57. return s
  58. }
  59. func (s *Config) SetAccessKeySecret(v string) *Config {
  60. s.AccessKeySecret = &v
  61. return s
  62. }
  63. func (s *Config) SetSecurityToken(v string) *Config {
  64. s.SecurityToken = &v
  65. return s
  66. }
  67. func (s *Config) SetRoleArn(v string) *Config {
  68. s.RoleArn = &v
  69. return s
  70. }
  71. func (s *Config) SetRoleSessionName(v string) *Config {
  72. s.RoleSessionName = &v
  73. return s
  74. }
  75. func (s *Config) SetPublicKeyId(v string) *Config {
  76. s.PublicKeyId = &v
  77. return s
  78. }
  79. func (s *Config) SetRoleName(v string) *Config {
  80. s.RoleName = &v
  81. return s
  82. }
  83. func (s *Config) SetSessionExpiration(v int) *Config {
  84. s.SessionExpiration = &v
  85. return s
  86. }
  87. func (s *Config) SetPrivateKeyFile(v string) *Config {
  88. s.PrivateKeyFile = &v
  89. return s
  90. }
  91. func (s *Config) SetBearerToken(v string) *Config {
  92. s.BearerToken = &v
  93. return s
  94. }
  95. func (s *Config) SetRoleSessionExpiration(v int) *Config {
  96. s.RoleSessionExpiration = &v
  97. return s
  98. }
  99. func (s *Config) SetPolicy(v string) *Config {
  100. s.Policy = &v
  101. return s
  102. }
  103. func (s *Config) SetHost(v string) *Config {
  104. s.Host = &v
  105. return s
  106. }
  107. func (s *Config) SetTimeout(v int) *Config {
  108. s.Timeout = &v
  109. return s
  110. }
  111. func (s *Config) SetConnectTimeout(v int) *Config {
  112. s.ConnectTimeout = &v
  113. return s
  114. }
  115. func (s *Config) SetProxy(v string) *Config {
  116. s.Proxy = &v
  117. return s
  118. }
  119. func (s *Config) SetType(v string) *Config {
  120. s.Type = &v
  121. return s
  122. }
  123. // NewCredential return a credential according to the type in config.
  124. // if config is nil, the function will use default provider chain to get credential.
  125. // please see README.md for detail.
  126. func NewCredential(config *Config) (credential Credential, err error) {
  127. if config == nil {
  128. config, err = defaultChain.resolve()
  129. if err != nil {
  130. return
  131. }
  132. return NewCredential(config)
  133. }
  134. switch tea.StringValue(config.Type) {
  135. case "access_key":
  136. err = checkAccessKey(config)
  137. if err != nil {
  138. return
  139. }
  140. credential = newAccessKeyCredential(tea.StringValue(config.AccessKeyId), tea.StringValue(config.AccessKeySecret))
  141. case "sts":
  142. err = checkSTS(config)
  143. if err != nil {
  144. return
  145. }
  146. credential = newStsTokenCredential(tea.StringValue(config.AccessKeyId), tea.StringValue(config.AccessKeySecret), tea.StringValue(config.SecurityToken))
  147. case "ecs_ram_role":
  148. checkEcsRAMRole(config)
  149. runtime := &utils.Runtime{
  150. Host: tea.StringValue(config.Host),
  151. Proxy: tea.StringValue(config.Proxy),
  152. ReadTimeout: tea.IntValue(config.Timeout),
  153. ConnectTimeout: tea.IntValue(config.ConnectTimeout),
  154. }
  155. credential = newEcsRAMRoleCredential(tea.StringValue(config.RoleName), runtime)
  156. case "ram_role_arn":
  157. err = checkRAMRoleArn(config)
  158. if err != nil {
  159. return
  160. }
  161. runtime := &utils.Runtime{
  162. Host: tea.StringValue(config.Host),
  163. Proxy: tea.StringValue(config.Proxy),
  164. ReadTimeout: tea.IntValue(config.Timeout),
  165. ConnectTimeout: tea.IntValue(config.ConnectTimeout),
  166. }
  167. credential = newRAMRoleArnCredential(tea.StringValue(config.AccessKeyId), tea.StringValue(config.AccessKeySecret), tea.StringValue(config.RoleArn), tea.StringValue(config.RoleSessionName), tea.StringValue(config.Policy), tea.IntValue(config.RoleSessionExpiration), runtime)
  168. case "rsa_key_pair":
  169. err = checkRSAKeyPair(config)
  170. if err != nil {
  171. return
  172. }
  173. file, err1 := os.Open(tea.StringValue(config.PrivateKeyFile))
  174. if err1 != nil {
  175. err = fmt.Errorf("InvalidPath: Can not open PrivateKeyFile, err is %s", err1.Error())
  176. return
  177. }
  178. defer file.Close()
  179. var privateKey string
  180. scan := bufio.NewScanner(file)
  181. for scan.Scan() {
  182. if strings.HasPrefix(scan.Text(), "----") {
  183. continue
  184. }
  185. privateKey += scan.Text() + "\n"
  186. }
  187. runtime := &utils.Runtime{
  188. Host: tea.StringValue(config.Host),
  189. Proxy: tea.StringValue(config.Proxy),
  190. ReadTimeout: tea.IntValue(config.Timeout),
  191. ConnectTimeout: tea.IntValue(config.ConnectTimeout),
  192. }
  193. credential = newRsaKeyPairCredential(privateKey, tea.StringValue(config.PublicKeyId), tea.IntValue(config.SessionExpiration), runtime)
  194. case "bearer":
  195. if tea.StringValue(config.BearerToken) == "" {
  196. err = errors.New("BearerToken cannot be empty")
  197. return
  198. }
  199. credential = newBearerTokenCredential(tea.StringValue(config.BearerToken))
  200. default:
  201. err = errors.New("Invalid type option, support: access_key, sts, ecs_ram_role, ram_role_arn, rsa_key_pair")
  202. return
  203. }
  204. return credential, nil
  205. }
  206. func checkRSAKeyPair(config *Config) (err error) {
  207. if tea.StringValue(config.PrivateKeyFile) == "" {
  208. err = errors.New("PrivateKeyFile cannot be empty")
  209. return
  210. }
  211. if tea.StringValue(config.PublicKeyId) == "" {
  212. err = errors.New("PublicKeyId cannot be empty")
  213. return
  214. }
  215. return
  216. }
  217. func checkRAMRoleArn(config *Config) (err error) {
  218. if tea.StringValue(config.AccessKeySecret) == "" {
  219. err = errors.New("AccessKeySecret cannot be empty")
  220. return
  221. }
  222. if tea.StringValue(config.RoleArn) == "" {
  223. err = errors.New("RoleArn cannot be empty")
  224. return
  225. }
  226. if tea.StringValue(config.RoleSessionName) == "" {
  227. err = errors.New("RoleSessionName cannot be empty")
  228. return
  229. }
  230. if tea.StringValue(config.AccessKeyId) == "" {
  231. err = errors.New("AccessKeyId cannot be empty")
  232. return
  233. }
  234. return
  235. }
  236. func checkEcsRAMRole(config *Config) (err error) {
  237. return
  238. }
  239. func checkSTS(config *Config) (err error) {
  240. if tea.StringValue(config.AccessKeyId) == "" {
  241. err = errors.New("AccessKeyId cannot be empty")
  242. return
  243. }
  244. if tea.StringValue(config.AccessKeySecret) == "" {
  245. err = errors.New("AccessKeySecret cannot be empty")
  246. return
  247. }
  248. if tea.StringValue(config.SecurityToken) == "" {
  249. err = errors.New("SecurityToken cannot be empty")
  250. return
  251. }
  252. return
  253. }
  254. func checkAccessKey(config *Config) (err error) {
  255. if tea.StringValue(config.AccessKeyId) == "" {
  256. err = errors.New("AccessKeyId cannot be empty")
  257. return
  258. }
  259. if tea.StringValue(config.AccessKeySecret) == "" {
  260. err = errors.New("AccessKeySecret cannot be empty")
  261. return
  262. }
  263. return
  264. }
  265. func doAction(request *request.CommonRequest, runtime *utils.Runtime) (content []byte, err error) {
  266. httpRequest, err := http.NewRequest(request.Method, request.URL, strings.NewReader(""))
  267. if err != nil {
  268. return
  269. }
  270. httpRequest.Proto = "HTTP/1.1"
  271. httpRequest.Host = request.Domain
  272. debuglog("> %s %s %s", httpRequest.Method, httpRequest.URL.RequestURI(), httpRequest.Proto)
  273. debuglog("> Host: %s", httpRequest.Host)
  274. for key, value := range request.Headers {
  275. if value != "" {
  276. debuglog("> %s: %s", key, value)
  277. httpRequest.Header[key] = []string{value}
  278. }
  279. }
  280. debuglog(">")
  281. httpClient := &http.Client{}
  282. httpClient.Timeout = time.Duration(runtime.ReadTimeout) * time.Second
  283. proxy := &url.URL{}
  284. if runtime.Proxy != "" {
  285. proxy, err = url.Parse(runtime.Proxy)
  286. if err != nil {
  287. return
  288. }
  289. }
  290. trans := &http.Transport{}
  291. if proxy != nil && runtime.Proxy != "" {
  292. trans.Proxy = http.ProxyURL(proxy)
  293. }
  294. trans.DialContext = utils.Timeout(time.Duration(runtime.ConnectTimeout) * time.Second)
  295. httpClient.Transport = trans
  296. httpResponse, err := hookDo(httpClient.Do)(httpRequest)
  297. if err != nil {
  298. return
  299. }
  300. debuglog("< %s %s", httpResponse.Proto, httpResponse.Status)
  301. for key, value := range httpResponse.Header {
  302. debuglog("< %s: %v", key, strings.Join(value, ""))
  303. }
  304. debuglog("<")
  305. resp := &response.CommonResponse{}
  306. err = hookParse(resp.ParseFromHTTPResponse(httpResponse))
  307. if err != nil {
  308. return
  309. }
  310. debuglog("%s", resp.GetHTTPContentString())
  311. if resp.GetHTTPStatus() != http.StatusOK {
  312. err = fmt.Errorf("httpStatus: %d, message = %s", resp.GetHTTPStatus(), resp.GetHTTPContentString())
  313. return
  314. }
  315. return resp.GetHTTPContentBytes(), nil
  316. }