shared_credentials_provider.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. package credentials
  2. import (
  3. "fmt"
  4. "os"
  5. "github.com/go-ini/ini"
  6. "github.com/aws/aws-sdk-go/aws/awserr"
  7. "github.com/aws/aws-sdk-go/internal/shareddefaults"
  8. )
  9. // SharedCredsProviderName provides a name of SharedCreds provider
  10. const SharedCredsProviderName = "SharedCredentialsProvider"
  11. var (
  12. // ErrSharedCredentialsHomeNotFound is emitted when the user directory cannot be found.
  13. ErrSharedCredentialsHomeNotFound = awserr.New("UserHomeNotFound", "user home directory not found.", nil)
  14. )
  15. // A SharedCredentialsProvider retrieves credentials from the current user's home
  16. // directory, and keeps track if those credentials are expired.
  17. //
  18. // Profile ini file example: $HOME/.aws/credentials
  19. type SharedCredentialsProvider struct {
  20. // Path to the shared credentials file.
  21. //
  22. // If empty will look for "AWS_SHARED_CREDENTIALS_FILE" env variable. If the
  23. // env value is empty will default to current user's home directory.
  24. // Linux/OSX: "$HOME/.aws/credentials"
  25. // Windows: "%USERPROFILE%\.aws\credentials"
  26. Filename string
  27. // AWS Profile to extract credentials from the shared credentials file. If empty
  28. // will default to environment variable "AWS_PROFILE" or "default" if
  29. // environment variable is also not set.
  30. Profile string
  31. // retrieved states if the credentials have been successfully retrieved.
  32. retrieved bool
  33. }
  34. // NewSharedCredentials returns a pointer to a new Credentials object
  35. // wrapping the Profile file provider.
  36. func NewSharedCredentials(filename, profile string) *Credentials {
  37. return NewCredentials(&SharedCredentialsProvider{
  38. Filename: filename,
  39. Profile: profile,
  40. })
  41. }
  42. // Retrieve reads and extracts the shared credentials from the current
  43. // users home directory.
  44. func (p *SharedCredentialsProvider) Retrieve() (Value, error) {
  45. p.retrieved = false
  46. filename, err := p.filename()
  47. if err != nil {
  48. return Value{ProviderName: SharedCredsProviderName}, err
  49. }
  50. creds, err := loadProfile(filename, p.profile())
  51. if err != nil {
  52. return Value{ProviderName: SharedCredsProviderName}, err
  53. }
  54. p.retrieved = true
  55. return creds, nil
  56. }
  57. // IsExpired returns if the shared credentials have expired.
  58. func (p *SharedCredentialsProvider) IsExpired() bool {
  59. return !p.retrieved
  60. }
  61. // loadProfiles loads from the file pointed to by shared credentials filename for profile.
  62. // The credentials retrieved from the profile will be returned or error. Error will be
  63. // returned if it fails to read from the file, or the data is invalid.
  64. func loadProfile(filename, profile string) (Value, error) {
  65. config, err := ini.Load(filename)
  66. if err != nil {
  67. return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsLoad", "failed to load shared credentials file", err)
  68. }
  69. iniProfile, err := config.GetSection(profile)
  70. if err != nil {
  71. return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsLoad", "failed to get profile", err)
  72. }
  73. id, err := iniProfile.GetKey("aws_access_key_id")
  74. if err != nil {
  75. return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsAccessKey",
  76. fmt.Sprintf("shared credentials %s in %s did not contain aws_access_key_id", profile, filename),
  77. err)
  78. }
  79. secret, err := iniProfile.GetKey("aws_secret_access_key")
  80. if err != nil {
  81. return Value{ProviderName: SharedCredsProviderName}, awserr.New("SharedCredsSecret",
  82. fmt.Sprintf("shared credentials %s in %s did not contain aws_secret_access_key", profile, filename),
  83. nil)
  84. }
  85. // Default to empty string if not found
  86. token := iniProfile.Key("aws_session_token")
  87. return Value{
  88. AccessKeyID: id.String(),
  89. SecretAccessKey: secret.String(),
  90. SessionToken: token.String(),
  91. ProviderName: SharedCredsProviderName,
  92. }, nil
  93. }
  94. // filename returns the filename to use to read AWS shared credentials.
  95. //
  96. // Will return an error if the user's home directory path cannot be found.
  97. func (p *SharedCredentialsProvider) filename() (string, error) {
  98. if len(p.Filename) != 0 {
  99. return p.Filename, nil
  100. }
  101. if p.Filename = os.Getenv("AWS_SHARED_CREDENTIALS_FILE"); len(p.Filename) != 0 {
  102. return p.Filename, nil
  103. }
  104. if home := shareddefaults.UserHomeDir(); len(home) == 0 {
  105. // Backwards compatibility of home directly not found error being returned.
  106. // This error is too verbose, failure when opening the file would of been
  107. // a better error to return.
  108. return "", ErrSharedCredentialsHomeNotFound
  109. }
  110. p.Filename = shareddefaults.SharedCredentialsFilename()
  111. return p.Filename, nil
  112. }
  113. // profile returns the AWS shared credentials profile. If empty will read
  114. // environment variable "AWS_PROFILE". If that is not set profile will
  115. // return "default".
  116. func (p *SharedCredentialsProvider) profile() string {
  117. if p.Profile == "" {
  118. p.Profile = os.Getenv("AWS_PROFILE")
  119. }
  120. if p.Profile == "" {
  121. p.Profile = "default"
  122. }
  123. return p.Profile
  124. }