github.com/aavshr/aws-sdk-go@v1.41.3/aws/credentials/shared_credentials_provider.go (about)

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