Skip to content

Commit 30a4abf

Browse files
committed
fix(toolkit): correctly use the endpoint URL for the selected profile
aws#2007 The Toolkit doesn't read the endpoint configured in an AWS profile config. The endpoint even before these changes is already being read from the AWS config file, and it's included in the CredentialsProvider object, but there wasn't a way to retrieve that. We're adding `getEndpointUrl()` method to the different providers, and then we're retrieving that endpoint in: 1. when loading the current profile, to add it to the credentialsCache (`auth.ts -> createCachedCredentials()`, `loginManager.ts -> login()`). Because of this, then we can get this endpoint alongside the credentials when creating a new AWS client. 2. when creating the list of connections that then will be displayed for the user to pick (`packages/core/src/auth/auth.ts -> getIamConnection()`) (this required to make `getIamConnection` an async
1 parent bfee0a9 commit 30a4abf

29 files changed

+429
-29
lines changed

packages/core/src/auth/auth.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ export class Auth implements AuthService, ConnectionManager {
215215
const provider = await this.getCredentialsProvider(id, profile)
216216
await this.authenticate(id, () => this.createCachedCredentials(provider), shouldInvalidate)
217217

218-
return this.getIamConnection(id, profile)
218+
return await this.getIamConnection(id, profile)
219219
}
220220
}
221221

@@ -253,7 +253,8 @@ export class Auth implements AuthService, ConnectionManager {
253253
if (profile === undefined) {
254254
throw new Error(`Connection does not exist: ${id}`)
255255
}
256-
const conn = profile.type === 'sso' ? this.getSsoConnection(id, profile) : this.getIamConnection(id, profile)
256+
const conn =
257+
profile.type === 'sso' ? this.getSsoConnection(id, profile) : await this.getIamConnection(id, profile)
257258

258259
this.#activeConnection = conn
259260
this.#onDidChangeActiveConnection.fire(conn)
@@ -705,7 +706,7 @@ export class Auth implements AuthService, ConnectionManager {
705706
if (profile.type === 'sso') {
706707
return this.getSsoConnection(id, profile)
707708
} else {
708-
return this.getIamConnection(id, profile)
709+
return await this.getIamConnection(id, profile)
709710
}
710711
}
711712

@@ -805,17 +806,21 @@ export class Auth implements AuthService, ConnectionManager {
805806
)
806807
}
807808

808-
private getIamConnection(
809+
private async getIamConnection(
809810
id: Connection['id'],
810811
profile: StoredProfile<IamProfile>
811-
): IamConnection & StatefulConnection {
812+
): Promise<IamConnection & StatefulConnection> {
813+
// Get the provider to extract the endpoint URL
814+
const provider = await this.getCredentialsProvider(id, profile)
815+
const endpointUrl = provider.getEndpointUrl?.()
812816
return {
813817
id,
814818
type: 'iam',
815819
state: profile.metadata.connectionState,
816820
label:
817821
profile.metadata.label ?? (profile.type === 'iam' && profile.subtype === 'linked' ? profile.name : id),
818822
getCredentials: async () => this.getCredentials(id, await this.getCredentialsProvider(id, profile)),
823+
endpointUrl,
819824
}
820825
}
821826

@@ -832,6 +837,8 @@ export class Auth implements AuthService, ConnectionManager {
832837
label: profile.metadata?.label ?? this.getSsoProfileLabel(profile),
833838
getToken: () => this.getToken(id, provider),
834839
getRegistration: () => provider.getClientRegistration(),
840+
// SsoConnection is managed internally in the AWS Toolkit, so the endpointUrl can't be configured
841+
endpointUrl: undefined,
835842
}
836843
}
837844

@@ -856,8 +863,8 @@ export class Auth implements AuthService, ConnectionManager {
856863
private async createCachedCredentials(provider: CredentialsProvider) {
857864
const providerId = provider.getCredentialsId()
858865
globals.loginManager.store.invalidateCredentials(providerId)
859-
const { credentials } = await globals.loginManager.store.upsertCredentials(providerId, provider)
860-
await globals.loginManager.validateCredentials(credentials, provider.getDefaultRegion())
866+
const { credentials, endpointUrl } = await globals.loginManager.store.upsertCredentials(providerId, provider)
867+
await globals.loginManager.validateCredentials(credentials, endpointUrl, provider.getDefaultRegion())
861868

862869
return credentials
863870
}

packages/core/src/auth/connection.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ export function createSsoProfile(
111111
export interface SsoConnection extends SsoProfile {
112112
readonly id: string
113113
readonly label: string
114+
readonly endpointUrl: string | undefined
114115

115116
/**
116117
* Retrieves a bearer token, refreshing or re-authenticating as-needed.
@@ -129,6 +130,7 @@ export interface IamConnection {
129130
// This may change in the future after refactoring legacy implementations
130131
readonly id: string
131132
readonly label: string
133+
readonly endpointUrl: string | undefined
132134
getCredentials(): Promise<Credentials>
133135
}
134136

packages/core/src/auth/credentials/store.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { CredentialsProviderManager } from '../providers/credentialsProviderMana
1212
export interface CachedCredentials {
1313
credentials: AWS.Credentials
1414
credentialsHashCode: string
15+
endpointUrl?: string
1516
}
1617

1718
/**
@@ -92,6 +93,7 @@ export class CredentialsStore {
9293
const credentials = {
9394
credentials: await credentialsProvider.getCredentials(),
9495
credentialsHashCode: credentialsProvider.getHashCode(),
96+
endpointUrl: credentialsProvider.getEndpointUrl?.(),
9597
}
9698

9799
this.credentialsCache[asString(credentialsId)] = credentials

packages/core/src/auth/credentials/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export const SharedCredentialsKeys = {
1212
AWS_SESSION_TOKEN: 'aws_session_token',
1313
CREDENTIAL_PROCESS: 'credential_process',
1414
CREDENTIAL_SOURCE: 'credential_source',
15+
ENDPOINT_URL: 'endpoint_url',
1516
REGION: 'region',
1617
ROLE_ARN: 'role_arn',
1718
SOURCE_PROFILE: 'source_profile',

packages/core/src/auth/credentials/utils.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { isValidResponse } from '../../shared/wizards/wizard'
2121
const credentialsTimeout = 300000 // 5 minutes
2222
const credentialsProgressDelay = 1000
2323

24-
export function asEnvironmentVariables(credentials: Credentials): NodeJS.ProcessEnv {
24+
export function asEnvironmentVariables(credentials: Credentials, endpointUrl?: string): NodeJS.ProcessEnv {
2525
const environmentVariables: NodeJS.ProcessEnv = {}
2626

2727
environmentVariables.AWS_ACCESS_KEY = credentials.accessKeyId
@@ -30,6 +30,9 @@ export function asEnvironmentVariables(credentials: Credentials): NodeJS.Process
3030
environmentVariables.AWS_SECRET_ACCESS_KEY = credentials.secretAccessKey
3131
environmentVariables.AWS_SESSION_TOKEN = credentials.sessionToken
3232
environmentVariables.AWS_SECURITY_TOKEN = credentials.sessionToken
33+
if (endpointUrl !== undefined) {
34+
environmentVariables.AWS_ENDPOINT_URL = endpointUrl
35+
}
3336

3437
return environmentVariables
3538
}

packages/core/src/auth/deprecated/loginManager.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,19 +65,19 @@ export class LoginManager {
6565

6666
try {
6767
provider = await getProvider(args.providerId)
68-
69-
const credentials = (await this.store.upsertCredentials(args.providerId, provider))?.credentials
68+
const { credentials, endpointUrl } = await this.store.upsertCredentials(args.providerId, provider)
7069
if (!credentials) {
7170
throw new Error(`No credentials found for id ${asString(args.providerId)}`)
7271
}
7372

74-
const accountId = await this.validateCredentials(credentials, provider.getDefaultRegion())
73+
const accountId = await this.validateCredentials(credentials, endpointUrl, provider.getDefaultRegion())
7574
this.awsContext.credentialsShim = createCredentialsShim(this.store, args.providerId, credentials)
7675
await this.awsContext.setCredentials({
7776
credentials,
7877
accountId: accountId,
7978
credentialsId: asString(args.providerId),
8079
defaultRegion: provider.getDefaultRegion(),
80+
endpointUrl: provider.getEndpointUrl?.(),
8181
})
8282

8383
telemetryResult = 'Succeeded'
@@ -111,8 +111,12 @@ export class LoginManager {
111111
}
112112
}
113113

114-
public async validateCredentials(credentials: Credentials, region = this.defaultCredentialsRegion) {
115-
const stsClient = new DefaultStsClient(region, credentials)
114+
public async validateCredentials(
115+
credentials: Credentials,
116+
endpointUrl?: string,
117+
region = this.defaultCredentialsRegion
118+
) {
119+
const stsClient = new DefaultStsClient(region, credentials, endpointUrl)
116120
const accountId = (await stsClient.getCallerIdentity()).Account
117121
if (!accountId) {
118122
throw new Error('Could not determine Account Id for credentials')

packages/core/src/auth/providers/credentials.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ export interface CredentialsProvider {
112112
*/
113113
getTelemetryType(): CredentialType
114114
getDefaultRegion(): string | undefined
115+
/**
116+
* Gets the endpoint URL configured for this profile, if any.
117+
*/
118+
getEndpointUrl?(): string | undefined
115119
getHashCode(): string
116120
getCredentials(): Promise<AWS.Credentials>
117121
/**

packages/core/src/auth/providers/envVarsCredentialsProvider.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,9 @@ export class EnvVarsCredentialsProvider implements CredentialsProvider {
6161
}
6262
return this.credentials
6363
}
64+
65+
public getEndpointUrl(): string | undefined {
66+
const env = process.env as EnvironmentVariables
67+
return env.AWS_ENDPOINT_URL?.toString()
68+
}
6469
}

packages/core/src/auth/providers/sharedCredentialsProvider.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ export class SharedCredentialsProvider implements CredentialsProvider {
105105
return this.profile[SharedCredentialsKeys.REGION]
106106
}
107107

108+
public getEndpointUrl(): string | undefined {
109+
return this.profile[SharedCredentialsKeys.ENDPOINT_URL]?.trim()
110+
}
111+
108112
public async canAutoConnect(): Promise<boolean> {
109113
if (isSsoProfile(this.profile)) {
110114
const tokenProvider = SsoAccessTokenProvider.create({

packages/core/src/auth/providers/ssoCredentialsProvider.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,9 @@ export class SsoCredentialsProvider implements CredentialsProvider {
6161
private async hasToken() {
6262
return (await this.tokenProvider.getToken()) !== undefined
6363
}
64+
65+
// SsoCredentials are managed internally in the AWS Toolkit, so the endpointUrl can't be configured
66+
public getEndpointUrl(): undefined {
67+
return undefined
68+
}
6469
}

0 commit comments

Comments
 (0)