profile_provider.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. package credentials
  2. import (
  3. "errors"
  4. "fmt"
  5. "os"
  6. "strings"
  7. "github.com/alibabacloud-go/tea/tea"
  8. "github.com/aliyun/credentials-go/credentials/internal/utils"
  9. ini "gopkg.in/ini.v1"
  10. )
  11. type profileProvider struct {
  12. Profile string
  13. }
  14. var providerProfile = newProfileProvider()
  15. var hookState = func(info os.FileInfo, err error) (os.FileInfo, error) {
  16. return info, err
  17. }
  18. // NewProfileProvider receive zero or more parameters,
  19. // when length of name is 0, the value of field Profile will be "default",
  20. // and when there are multiple inputs, the function will take the
  21. // first one and discard the other values.
  22. func newProfileProvider(name ...string) Provider {
  23. p := new(profileProvider)
  24. if len(name) == 0 {
  25. p.Profile = "default"
  26. } else {
  27. p.Profile = name[0]
  28. }
  29. return p
  30. }
  31. // resolve implements the Provider interface
  32. // when credential type is rsa_key_pair, the content of private_key file
  33. // must be able to be parsed directly into the required string
  34. // that NewRsaKeyPairCredential function needed
  35. func (p *profileProvider) resolve() (*Config, error) {
  36. path, ok := os.LookupEnv(ENVCredentialFile)
  37. if !ok {
  38. defaultPath, err := checkDefaultPath()
  39. if err != nil {
  40. return nil, err
  41. }
  42. path = defaultPath
  43. if path == "" {
  44. return nil, nil
  45. }
  46. } else if path == "" {
  47. return nil, errors.New(ENVCredentialFile + " cannot be empty")
  48. }
  49. value, section, err := getType(path, p.Profile)
  50. if err != nil {
  51. return nil, err
  52. }
  53. switch value.String() {
  54. case "access_key":
  55. config, err := getAccessKey(section)
  56. if err != nil {
  57. return nil, err
  58. }
  59. return config, nil
  60. case "sts":
  61. config, err := getSTS(section)
  62. if err != nil {
  63. return nil, err
  64. }
  65. return config, nil
  66. case "bearer":
  67. config, err := getBearerToken(section)
  68. if err != nil {
  69. return nil, err
  70. }
  71. return config, nil
  72. case "ecs_ram_role":
  73. config, err := getEcsRAMRole(section)
  74. if err != nil {
  75. return nil, err
  76. }
  77. return config, nil
  78. case "ram_role_arn":
  79. config, err := getRAMRoleArn(section)
  80. if err != nil {
  81. return nil, err
  82. }
  83. return config, nil
  84. case "rsa_key_pair":
  85. config, err := getRSAKeyPair(section)
  86. if err != nil {
  87. return nil, err
  88. }
  89. return config, nil
  90. default:
  91. return nil, errors.New("invalid type option, support: access_key, sts, ecs_ram_role, ram_role_arn, rsa_key_pair")
  92. }
  93. }
  94. func getRSAKeyPair(section *ini.Section) (*Config, error) {
  95. publicKeyId, err := section.GetKey("public_key_id")
  96. if err != nil {
  97. return nil, errors.New("missing required public_key_id option in profile for rsa_key_pair")
  98. }
  99. if publicKeyId.String() == "" {
  100. return nil, errors.New("public_key_id cannot be empty")
  101. }
  102. privateKeyFile, err := section.GetKey("private_key_file")
  103. if err != nil {
  104. return nil, errors.New("missing required private_key_file option in profile for rsa_key_pair")
  105. }
  106. if privateKeyFile.String() == "" {
  107. return nil, errors.New("private_key_file cannot be empty")
  108. }
  109. sessionExpiration, _ := section.GetKey("session_expiration")
  110. expiration := 0
  111. if sessionExpiration != nil {
  112. expiration, err = sessionExpiration.Int()
  113. if err != nil {
  114. return nil, errors.New("session_expiration must be an int")
  115. }
  116. }
  117. config := &Config{
  118. Type: tea.String("rsa_key_pair"),
  119. PublicKeyId: tea.String(publicKeyId.String()),
  120. PrivateKeyFile: tea.String(privateKeyFile.String()),
  121. SessionExpiration: tea.Int(expiration),
  122. }
  123. err = setRuntimeToConfig(config, section)
  124. if err != nil {
  125. return nil, err
  126. }
  127. return config, nil
  128. }
  129. func getRAMRoleArn(section *ini.Section) (*Config, error) {
  130. accessKeyId, err := section.GetKey("access_key_id")
  131. if err != nil {
  132. return nil, errors.New("missing required access_key_id option in profile for ram_role_arn")
  133. }
  134. if accessKeyId.String() == "" {
  135. return nil, errors.New("access_key_id cannot be empty")
  136. }
  137. accessKeySecret, err := section.GetKey("access_key_secret")
  138. if err != nil {
  139. return nil, errors.New("missing required access_key_secret option in profile for ram_role_arn")
  140. }
  141. if accessKeySecret.String() == "" {
  142. return nil, errors.New("access_key_secret cannot be empty")
  143. }
  144. roleArn, err := section.GetKey("role_arn")
  145. if err != nil {
  146. return nil, errors.New("missing required role_arn option in profile for ram_role_arn")
  147. }
  148. if roleArn.String() == "" {
  149. return nil, errors.New("role_arn cannot be empty")
  150. }
  151. roleSessionName, err := section.GetKey("role_session_name")
  152. if err != nil {
  153. return nil, errors.New("missing required role_session_name option in profile for ram_role_arn")
  154. }
  155. if roleSessionName.String() == "" {
  156. return nil, errors.New("role_session_name cannot be empty")
  157. }
  158. roleSessionExpiration, _ := section.GetKey("role_session_expiration")
  159. expiration := 0
  160. if roleSessionExpiration != nil {
  161. expiration, err = roleSessionExpiration.Int()
  162. if err != nil {
  163. return nil, errors.New("role_session_expiration must be an int")
  164. }
  165. }
  166. config := &Config{
  167. Type: tea.String("ram_role_arn"),
  168. AccessKeyId: tea.String(accessKeyId.String()),
  169. AccessKeySecret: tea.String(accessKeySecret.String()),
  170. RoleArn: tea.String(roleArn.String()),
  171. RoleSessionName: tea.String(roleSessionName.String()),
  172. RoleSessionExpiration: tea.Int(expiration),
  173. }
  174. err = setRuntimeToConfig(config, section)
  175. if err != nil {
  176. return nil, err
  177. }
  178. return config, nil
  179. }
  180. func getEcsRAMRole(section *ini.Section) (*Config, error) {
  181. roleName, _ := section.GetKey("role_name")
  182. config := &Config{
  183. Type: tea.String("ecs_ram_role"),
  184. }
  185. if roleName != nil {
  186. config.RoleName = tea.String(roleName.String())
  187. }
  188. err := setRuntimeToConfig(config, section)
  189. if err != nil {
  190. return nil, err
  191. }
  192. return config, nil
  193. }
  194. func getBearerToken(section *ini.Section) (*Config, error) {
  195. bearerToken, err := section.GetKey("bearer_token")
  196. if err != nil {
  197. return nil, errors.New("missing required bearer_token option in profile for bearer")
  198. }
  199. if bearerToken.String() == "" {
  200. return nil, errors.New("bearer_token cannot be empty")
  201. }
  202. config := &Config{
  203. Type: tea.String("bearer"),
  204. BearerToken: tea.String(bearerToken.String()),
  205. }
  206. return config, nil
  207. }
  208. func getSTS(section *ini.Section) (*Config, error) {
  209. accesskeyid, err := section.GetKey("access_key_id")
  210. if err != nil {
  211. return nil, errors.New("missing required access_key_id option in profile for sts")
  212. }
  213. if accesskeyid.String() == "" {
  214. return nil, errors.New("access_key_id cannot be empty")
  215. }
  216. accessKeySecret, err := section.GetKey("access_key_secret")
  217. if err != nil {
  218. return nil, errors.New("missing required access_key_secret option in profile for sts")
  219. }
  220. if accessKeySecret.String() == "" {
  221. return nil, errors.New("access_key_secret cannot be empty")
  222. }
  223. securityToken, err := section.GetKey("security_token")
  224. if err != nil {
  225. return nil, errors.New("missing required security_token option in profile for sts")
  226. }
  227. if securityToken.String() == "" {
  228. return nil, errors.New("security_token cannot be empty")
  229. }
  230. config := &Config{
  231. Type: tea.String("sts"),
  232. AccessKeyId: tea.String(accesskeyid.String()),
  233. AccessKeySecret: tea.String(accessKeySecret.String()),
  234. SecurityToken: tea.String(securityToken.String()),
  235. }
  236. return config, nil
  237. }
  238. func getAccessKey(section *ini.Section) (*Config, error) {
  239. accesskeyid, err := section.GetKey("access_key_id")
  240. if err != nil {
  241. return nil, errors.New("missing required access_key_id option in profile for access_key")
  242. }
  243. if accesskeyid.String() == "" {
  244. return nil, errors.New("access_key_id cannot be empty")
  245. }
  246. accessKeySecret, err := section.GetKey("access_key_secret")
  247. if err != nil {
  248. return nil, errors.New("missing required access_key_secret option in profile for access_key")
  249. }
  250. if accessKeySecret.String() == "" {
  251. return nil, errors.New("access_key_secret cannot be empty")
  252. }
  253. config := &Config{
  254. Type: tea.String("access_key"),
  255. AccessKeyId: tea.String(accesskeyid.String()),
  256. AccessKeySecret: tea.String(accessKeySecret.String()),
  257. }
  258. return config, nil
  259. }
  260. func getType(path, profile string) (*ini.Key, *ini.Section, error) {
  261. ini, err := ini.Load(path)
  262. if err != nil {
  263. return nil, nil, errors.New("ERROR: Can not open file " + err.Error())
  264. }
  265. section, err := ini.GetSection(profile)
  266. if err != nil {
  267. return nil, nil, errors.New("ERROR: Can not load section " + err.Error())
  268. }
  269. value, err := section.GetKey("type")
  270. if err != nil {
  271. return nil, nil, errors.New("missing required type option " + err.Error())
  272. }
  273. return value, section, nil
  274. }
  275. func checkDefaultPath() (path string, err error) {
  276. path = utils.GetHomePath()
  277. if path == "" {
  278. return "", errors.New("the default credential file path is invalid")
  279. }
  280. path = strings.Replace("~/.alibabacloud/credentials", "~", path, 1)
  281. _, err = hookState(os.Stat(path))
  282. if err != nil {
  283. return "", nil
  284. }
  285. return path, nil
  286. }
  287. func setRuntimeToConfig(config *Config, section *ini.Section) error {
  288. rawTimeout, _ := section.GetKey("timeout")
  289. rawConnectTimeout, _ := section.GetKey("connect_timeout")
  290. rawProxy, _ := section.GetKey("proxy")
  291. rawHost, _ := section.GetKey("host")
  292. if rawProxy != nil {
  293. config.Proxy = tea.String(rawProxy.String())
  294. }
  295. if rawConnectTimeout != nil {
  296. connectTimeout, err := rawConnectTimeout.Int()
  297. if err != nil {
  298. return fmt.Errorf("please set connect_timeout with an int value")
  299. }
  300. config.ConnectTimeout = tea.Int(connectTimeout)
  301. }
  302. if rawTimeout != nil {
  303. timeout, err := rawTimeout.Int()
  304. if err != nil {
  305. return fmt.Errorf("please set timeout with an int value")
  306. }
  307. config.Timeout = tea.Int(timeout)
  308. }
  309. if rawHost != nil {
  310. config.Host = tea.String(rawHost.String())
  311. }
  312. return nil
  313. }