Skip to content

Commit 5bd03c7

Browse files
authored
Merge #3232 from nkomonen-amazon/builderIdAdditional
auth: prompt existing builder id signout on new builder id
2 parents 6b73fb8 + 4de75bc commit 5bd03c7

File tree

3 files changed

+45
-30
lines changed

3 files changed

+45
-30
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Feature",
3+
"description": "Option to sign out of existing Builder ID when adding a new one"
4+
}

src/credentials/auth.ts

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -199,10 +199,6 @@ export class ProfileStore {
199199
public async addProfile(id: string, profile: SsoProfile): Promise<StoredProfile<SsoProfile>>
200200
public async addProfile(id: string, profile: IamProfile): Promise<StoredProfile<IamProfile>>
201201
public async addProfile(id: string, profile: Profile): Promise<StoredProfile> {
202-
if (this.getProfile(id) !== undefined) {
203-
throw new Error(`Profile already exists: ${id}`)
204-
}
205-
206202
return this.putProfile(id, this.initMetadata(profile))
207203
}
208204

@@ -770,9 +766,7 @@ const switchConnections = Commands.register('aws.auth.switchConnections', (auth:
770766
}
771767
})
772768

773-
async function signout(auth: Auth) {
774-
const conn = auth.activeConnection
775-
769+
async function signout(auth: Auth, conn: Connection | undefined = auth.activeConnection) {
776770
if (conn?.type === 'sso') {
777771
// TODO: does deleting the connection make sense UX-wise?
778772
// this makes it disappear from the list of available connections
@@ -865,39 +859,54 @@ export async function createStartUrlPrompter(title: string, ignoreScopes = true)
865859
export async function createBuilderIdConnection(auth: Auth) {
866860
const newProfile = createBuilderIdProfile()
867861
const existingConn = (await auth.listConnections()).find(isBuilderIdConnection)
868-
if (existingConn && !hasScopes(existingConn, newProfile.scopes)) {
869-
return migrateBuilderId(auth, existingConn, newProfile)
862+
if (!existingConn) {
863+
return auth.createConnection(newProfile)
864+
}
865+
866+
const userResponse = await promptLogoutExistingBuilderIdConnection()
867+
if (userResponse !== 'signout') {
868+
throw new CancellationError('user')
870869
}
871870

872-
return existingConn ?? (await auth.createConnection(newProfile))
871+
await signout(auth, existingConn)
872+
873+
return auth.createConnection(newProfile)
874+
}
875+
876+
/**
877+
* Prompts the user to log out of an existing Builder ID connection.
878+
*
879+
* @returns The name of the action performed by the user
880+
*/
881+
async function promptLogoutExistingBuilderIdConnection(): Promise<'signout' | 'cancel'> {
882+
const items: DataQuickPickItem<'signout' | 'cancel'>[] = [
883+
{
884+
data: 'signout',
885+
label: `Currently signed in with ${getIdeProperties().company} Builder ID. Sign out to add another?`,
886+
detail: `This will sign out of your current ${
887+
getIdeProperties().company
888+
} Builder ID and open the sign-in page in browser.`,
889+
},
890+
{ data: 'cancel', label: 'Cancel' },
891+
]
892+
const resp = await showQuickPick(items, {
893+
title: `Sign in to different ${getIdeProperties().company} Builder ID`,
894+
buttons: createCommonButtons() as vscode.QuickInputButton[],
895+
})
896+
897+
return resp === undefined ? 'cancel' : resp
873898
}
874899

875900
Commands.register('aws.auth.help', async () => {
876901
vscode.env.openExternal(vscode.Uri.parse(authHelpUrl))
877902
telemetry.aws_help.emit()
878903
})
904+
879905
Commands.register('aws.auth.signout', () => {
880906
telemetry.ui_click.emit({ elementId: 'devtools_signout' })
881-
882907
return signout(Auth.instance)
883908
})
884909

885-
// XXX: right now users can only have 1 builder id connection, so de-dupe
886-
// This logic can be removed or re-purposed once we have access to identities
887-
async function migrateBuilderId(auth: Auth, existingConn: SsoConnection, newProfile: SsoProfile) {
888-
const newConn = await auth.createConnection(newProfile)
889-
const shouldUseConnection = auth.activeConnection?.id === existingConn.id
890-
await auth.deleteConnection(existingConn).catch(err => {
891-
getLogger().warn(`auth: failed to remove old connection "${existingConn.id}": %s`, err)
892-
})
893-
894-
if (shouldUseConnection) {
895-
return auth.useConnection(newConn)
896-
}
897-
898-
return newConn
899-
}
900-
901910
const addConnection = Commands.register('aws.auth.addConnection', async () => {
902911
const c9IamItem = createIamItem()
903912
c9IamItem.detail =

src/test/credentials/auth.test.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,11 @@ describe('Auth', function () {
134134
assert.strictEqual(auth.activeConnection, undefined)
135135
})
136136

137-
it('throws when creating a duplicate connection', async function () {
138-
await auth.createConnection(ssoProfile)
139-
await assert.rejects(() => auth.createConnection(ssoProfile))
137+
it('does not throw when creating a duplicate connection', async function () {
138+
const initialConn = await auth.createConnection({ ...ssoProfile, scopes: ['a'] })
139+
const duplicateConn = await auth.createConnection({ ...ssoProfile, scopes: ['b'] })
140+
assert.deepStrictEqual(initialConn.scopes, ['a'])
141+
assert.deepStrictEqual(duplicateConn.scopes, ['a', 'b'])
140142
})
141143

142144
it('throws when using an invalid connection that was deleted', async function () {

0 commit comments

Comments
 (0)