Skip to content

Commit f30fb2e

Browse files
authored
fix(credentials): Make finding existing credential filenames more robust (#2972)
Problem: - Currently the way we find existing credential filenames is by seeing if a few keys are in the credentials document. This isn't really robust and breaks down for different profile types. Solution: - Re-use the sharedCredentialsProvider to provide validation when trying to find existing credential filenames. This will ensure that if we find a credentials file, it has at least one valid profile name
1 parent ded5f8f commit f30fb2e

File tree

2 files changed

+92
-12
lines changed

2 files changed

+92
-12
lines changed

src/shared/credentials/userCredentialsUtils.ts

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
*/
55

66
import * as path from 'path'
7-
7+
import * as vscode from 'vscode'
88
import { mkdirp, writeFile } from 'fs-extra'
99
import { getConfigFilename, getCredentialsFilename } from '../../credentials/sharedCredentials'
1010
import { fileExists } from '../filesystemUtilities'
1111
import { SystemUtilities } from '../systemUtilities'
12+
import { loadSharedConfigFiles, Profile } from './credentialsFile'
13+
import { SharedCredentialsProvider } from '../../credentials/providers/sharedCredentialsProvider'
1214

1315
const header = `
1416
# AWS credentials file used by AWS CLI, SDKs, and tools.
@@ -58,20 +60,49 @@ export class UserCredentialsUtils {
5860
* @returns array of filenames for files found.
5961
*/
6062
public static async findExistingCredentialsFilenames(isCredentialsRequired = false): Promise<string[]> {
61-
const candidateFiles: string[] = [getCredentialsFilename(), getConfigFilename()]
63+
const configFilename = getConfigFilename()
64+
const credentialsFileName = getCredentialsFilename()
65+
66+
const configs = await loadSharedConfigFiles({
67+
config: vscode.Uri.file(configFilename),
68+
credentials: vscode.Uri.file(credentialsFileName),
69+
})
70+
const credentials = new Map([
71+
[credentialsFileName, configs.credentialsFile],
72+
[configFilename, configs.configFile],
73+
])
74+
75+
const credentialFiles = []
76+
for (const [filename, profiles] of credentials.entries()) {
77+
const exists = await SystemUtilities.fileExists(filename)
78+
if (!exists) {
79+
continue
80+
}
6281

63-
const existsResults: boolean[] = await Promise.all(
64-
candidateFiles.map(async filename => {
65-
const exists = await SystemUtilities.fileExists(filename)
66-
if (!exists || !isCredentialsRequired) {
67-
return exists
82+
if (!isCredentialsRequired) {
83+
credentialFiles.push(filename)
84+
continue
85+
}
86+
87+
// ensure that the given filename has at least one valid profile
88+
const validProfiles = []
89+
const allProfiles = new Map(Object.entries(profiles).filter(item => item[1] !== undefined)) as Map<
90+
string,
91+
Profile
92+
>
93+
for (const profile of Object.keys(profiles)) {
94+
const credProvider = new SharedCredentialsProvider(profile, allProfiles)
95+
if (await credProvider.isAvailable()) {
96+
validProfiles.push(profile)
6897
}
69-
const contents = await SystemUtilities.readFile(filename)
70-
return /aws_access_key_id|aws_secret_access_key|aws_session_token/i.test(contents)
71-
})
72-
)
98+
}
99+
100+
if (validProfiles.length !== 0) {
101+
credentialFiles.push(filename)
102+
}
103+
}
73104

74-
return candidateFiles.filter((filename, index) => existsResults[index])
105+
return credentialFiles
75106
}
76107

77108
/**

src/test/shared/credentials/userCredentialsUtils.test.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,39 @@ describe('UserCredentialsUtils', function () {
9393
assert.strictEqual(foundFiles.length, 0)
9494
})
9595

96+
it('returns credentials files if profiles are required and config does not exist', async function () {
97+
const credentialsFilename = path.join(tempFolder, 'credentials-exists-profiles-required-no-config-test')
98+
const configFilename = path.join(tempFolder, 'config-not-exist-profiles-required-but-no-config-test')
99+
100+
sinon.stub(process, 'env').value({
101+
AWS_SHARED_CREDENTIALS_FILE: credentialsFilename,
102+
AWS_CONFIG_FILE: configFilename,
103+
} as EnvironmentVariables)
104+
105+
createCredentialsFile(credentialsFilename, ['default'])
106+
107+
const foundFiles: string[] = await UserCredentialsUtils.findExistingCredentialsFilenames(true)
108+
assert.strictEqual(foundFiles.length, 1)
109+
})
110+
111+
it('returns config files if profiles are required and credentials does not exist', async function () {
112+
const credentialsFilename = path.join(
113+
tempFolder,
114+
'credentials-exists-profiles-required-no-credentials-test'
115+
)
116+
const configFilename = path.join(tempFolder, 'config-not-exist-profiles-required-but-no-credentials-test')
117+
118+
sinon.stub(process, 'env').value({
119+
AWS_SHARED_CREDENTIALS_FILE: credentialsFilename,
120+
AWS_CONFIG_FILE: configFilename,
121+
} as EnvironmentVariables)
122+
123+
createCredentialsFile(configFilename, ['default'])
124+
125+
const foundFiles: string[] = await UserCredentialsUtils.findExistingCredentialsFilenames(true)
126+
assert.strictEqual(foundFiles.length, 1)
127+
})
128+
96129
it('returns empty result if files dont contain credentials', async function () {
97130
const credentialsFilename = path.join(tempFolder, 'credentials-both-exist-but-no-credentials-test')
98131
const configFilename = path.join(tempFolder, 'config-both-exist-but-no-credentials-test')
@@ -108,6 +141,22 @@ describe('UserCredentialsUtils', function () {
108141
const foundFiles: string[] = await UserCredentialsUtils.findExistingCredentialsFilenames(true)
109142
assert.strictEqual(foundFiles.length, 0)
110143
})
144+
145+
it('returns empty result if files contains nonsense', async function () {
146+
const credentialsFilename = path.join(tempFolder, 'credentials-both-exist-but-contain-nonsense-test')
147+
const configFilename = path.join(tempFolder, 'config-both-exist-but-contain-nonsense-test')
148+
149+
sinon.stub(process, 'env').value({
150+
AWS_SHARED_CREDENTIALS_FILE: credentialsFilename,
151+
AWS_CONFIG_FILE: configFilename,
152+
} as EnvironmentVariables)
153+
154+
fs.writeFileSync(credentialsFilename, 'adfadfgwergsdfgsdfgjsdifgsdfugi')
155+
fs.writeFileSync(configFilename, 'adfadfgwergsdfgsdfgjsdifgsdfugi')
156+
157+
const foundFiles: string[] = await UserCredentialsUtils.findExistingCredentialsFilenames(true)
158+
assert.strictEqual(foundFiles.length, 0)
159+
})
111160
})
112161

113162
describe('generateCredentialsFile', function () {

0 commit comments

Comments
 (0)