1/*
2 * MinIO Go Library for Amazon S3 Compatible Cloud Storage
3 * Copyright 2017 MinIO, Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package credentials
19
20import (
21	"os"
22	"path/filepath"
23
24	homedir "github.com/mitchellh/go-homedir"
25	ini "gopkg.in/ini.v1"
26)
27
28// A FileAWSCredentials retrieves credentials from the current user's home
29// directory, and keeps track if those credentials are expired.
30//
31// Profile ini file example: $HOME/.aws/credentials
32type FileAWSCredentials struct {
33	// Path to the shared credentials file.
34	//
35	// If empty will look for "AWS_SHARED_CREDENTIALS_FILE" env variable. If the
36	// env value is empty will default to current user's home directory.
37	// Linux/OSX: "$HOME/.aws/credentials"
38	// Windows:   "%USERPROFILE%\.aws\credentials"
39	Filename string
40
41	// AWS Profile to extract credentials from the shared credentials file. If empty
42	// will default to environment variable "AWS_PROFILE" or "default" if
43	// environment variable is also not set.
44	Profile string
45
46	// retrieved states if the credentials have been successfully retrieved.
47	retrieved bool
48}
49
50// NewFileAWSCredentials returns a pointer to a new Credentials object
51// wrapping the Profile file provider.
52func NewFileAWSCredentials(filename string, profile string) *Credentials {
53	return New(&FileAWSCredentials{
54		Filename: filename,
55		Profile:  profile,
56	})
57}
58
59// Retrieve reads and extracts the shared credentials from the current
60// users home directory.
61func (p *FileAWSCredentials) Retrieve() (Value, error) {
62	if p.Filename == "" {
63		p.Filename = os.Getenv("AWS_SHARED_CREDENTIALS_FILE")
64		if p.Filename == "" {
65			homeDir, err := homedir.Dir()
66			if err != nil {
67				return Value{}, err
68			}
69			p.Filename = filepath.Join(homeDir, ".aws", "credentials")
70		}
71	}
72	if p.Profile == "" {
73		p.Profile = os.Getenv("AWS_PROFILE")
74		if p.Profile == "" {
75			p.Profile = "default"
76		}
77	}
78
79	p.retrieved = false
80
81	iniProfile, err := loadProfile(p.Filename, p.Profile)
82	if err != nil {
83		return Value{}, err
84	}
85
86	// Default to empty string if not found.
87	id := iniProfile.Key("aws_access_key_id")
88	// Default to empty string if not found.
89	secret := iniProfile.Key("aws_secret_access_key")
90	// Default to empty string if not found.
91	token := iniProfile.Key("aws_session_token")
92
93	p.retrieved = true
94	return Value{
95		AccessKeyID:     id.String(),
96		SecretAccessKey: secret.String(),
97		SessionToken:    token.String(),
98		SignerType:      SignatureV4,
99	}, nil
100}
101
102// IsExpired returns if the shared credentials have expired.
103func (p *FileAWSCredentials) IsExpired() bool {
104	return !p.retrieved
105}
106
107// loadProfiles loads from the file pointed to by shared credentials filename for profile.
108// The credentials retrieved from the profile will be returned or error. Error will be
109// returned if it fails to read from the file, or the data is invalid.
110func loadProfile(filename, profile string) (*ini.Section, error) {
111	config, err := ini.Load(filename)
112	if err != nil {
113		return nil, err
114	}
115	iniProfile, err := config.GetSection(profile)
116	if err != nil {
117		return nil, err
118	}
119	return iniProfile, nil
120}
121