Skip to content

Commit 92109d6

Browse files
authored
fix(auth): more UX improvements #2981
Problem: * Lack of validation when entering start URL * Walkthrough is outdated * SSO connection labels are too long Solution: * Add validation to SSO start URL * Update the walkthrough * Use start URL subdomain as label
1 parent f932f97 commit 92109d6

File tree

7 files changed

+43
-15
lines changed

7 files changed

+43
-15
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3124,7 +3124,8 @@
31243124
"markdown": "resources/walkthrough/setup-connect.md"
31253125
},
31263126
"completionEvents": [
3127-
"onContext:config.aws.profile"
3127+
"onCommand:aws.login",
3128+
"onCommand:aws.credentials.profile.create"
31283129
]
31293130
},
31303131
{
29.8 KB
Loading
17.8 KB
Loading
-11.8 KB
Binary file not shown.
-13.1 KB
Binary file not shown.

resources/walkthrough/setup-connect.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,17 @@ To interact with Amazon Web Services \(AWS\) through the AWS Toolkit for Visual
1515
>
1616
> ![AWS Toolkit Command palette, Connect to AWS](./images/aws-toolkit-commandpalette.png)
1717
18-
2. Choose a profile from the list\.
18+
2. Choose a connection from the list\.
1919

20-
![AWS Toolkit command palette choose profile window](./images/aws-toolkit-choose-profile.png)
20+
![AWS Toolkit command palette choose profile window](./images/aws-toolkit-choose-connection.png)
2121

22-
If you don't have a credentials profile set up, you are prompted to set one up\. Look for a pop\-up in the lower\-right corner of the editor\. Choose **Yes**, and then follow the setup wizard to enter a profile name, your access key ID, and your secret access key\.
22+
If you don't have a connection set up, you are prompted to set one up\. Choose **Enter IAM Credentials** in order to view resources in the AWS Explorer. SSO connections cannot be used to view resources in the AWS Explorer at this time.
2323

24-
![AWS Toolkit setup profile prompt.](./images/aws-toolkit-cred-prompt.png)
24+
![AWS Toolkit setup profile prompt.](./images/aws-toolkit-add-connection.png)
2525

2626
> **Note**
2727
>
28-
> If you want to provide an external credential process instead of using AWS\-supported credentials, choose **No** and see [Using an external credential process](https://docs.aws.amazon.com/toolkit-for-vscode/latest/userguide/external-credential-process.html) instead\.
28+
> If you want to provide an external credential process instead of using AWS\-supported credentials, exit the wizard and see [Using an external credential process](https://docs.aws.amazon.com/toolkit-for-vscode/latest/userguide/external-credential-process.html) instead\.
2929
3030
3. Open the **AWS: Explorer** Side Bar, which we call the **_AWS Explorer_**, to verify the connection\. You will see either a list of AWS Regions \(if you have made any Regions visible in the **AWS Explorer**\) or a message to add Regions to the **AWS Explorer**\.
3131

src/credentials/auth.ts

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import { SsoClient } from './sso/clients'
2525
import { getLogger } from '../shared/logger'
2626
import { CredentialsProviderManager } from './providers/credentialsProviderManager'
2727
import { asString, CredentialsProvider, fromString } from './providers/credentials'
28-
import { once, shared } from '../shared/utilities/functionUtils'
28+
import { once } from '../shared/utilities/functionUtils'
2929
import { getResourceFromTreeNode } from '../shared/treeview/utils'
3030
import { Instance } from '../shared/utilities/typeConstructors'
3131
import { TreeNode } from '../shared/treeview/resourceTreeDataProvider'
@@ -284,6 +284,10 @@ export class Auth implements AuthService, ConnectionManager {
284284
return this.#activeConnection
285285
}
286286

287+
public get hasConnections() {
288+
return this.store.listProfiles().length !== 0
289+
}
290+
287291
public async restorePreviousSession(): Promise<Connection | undefined> {
288292
const id = this.store.getCurrentProfileId()
289293
if (id === undefined) {
@@ -751,12 +755,36 @@ export const createIamItem = () =>
751755
detail: 'Activates working with resources in the Explorer. Not supported by CodeWhisperer. Requires an access key ID and secret access key.',
752756
} as DataQuickPickItem<'iam'>)
753757

754-
export const createStartUrlPrompter = (title: string) =>
755-
createInputBox({
758+
export const isIamConnection = (conn?: Connection): conn is IamConnection => conn?.type === 'iam'
759+
export const isSsoConnection = (conn?: Connection): conn is SsoConnection => conn?.type === 'sso'
760+
761+
export async function createStartUrlPrompter(title: string) {
762+
const existingConnections = (await Auth.instance.listConnections())
763+
.filter(isSsoConnection)
764+
.map(conn => vscode.Uri.parse(conn.startUrl))
765+
766+
function validateSsoUrl(url: string) {
767+
if (!url.match(/^(http|https):\/\//i)) {
768+
return 'URLs must start with http:// or https://. Example: https://d-xxxxxxxxxx.awsapps.com/start'
769+
}
770+
771+
try {
772+
const uri = vscode.Uri.parse(url, true)
773+
if (existingConnections.find(conn => conn.authority.toLowerCase() === uri.authority.toLowerCase())) {
774+
return 'A connection for this start URL already exists. Sign out before creating a new one.'
775+
}
776+
} catch (err) {
777+
return `URL is malformed: ${UnknownError.cast(err).message}`
778+
}
779+
}
780+
781+
return createInputBox({
756782
title: `${title}: Enter Start URL`,
757-
placeholder: 'https://d-xxxxxxxxxx.awsapps.com/start',
783+
placeholder: "Enter start URL for your organization's SSO",
758784
buttons: createCommonButtons(),
785+
validateInput: validateSsoUrl,
759786
})
787+
}
760788

761789
// TODO: add specific documentation URL
762790
Commands.register('aws.auth.help', async () => (await Commands.get('aws.help'))?.execute())
@@ -775,7 +803,8 @@ const addConnection = Commands.register('aws.auth.addConnection', async () => {
775803
case 'iam':
776804
return await globals.awsContextCommands.onCommandCreateCredentialsProfile()
777805
case 'sso': {
778-
const startUrl = await createStartUrlPrompter('SSO Connection').prompt()
806+
const startUrlPrompter = await createStartUrlPrompter('SSO Connection')
807+
const startUrl = await startUrlPrompter.prompt()
779808
if (!isValidResponse(startUrl)) {
780809
throw new CancellationError('user')
781810
}
@@ -838,20 +867,18 @@ export class AuthNode implements TreeNode<Auth> {
838867

839868
public constructor(public readonly resource: Auth) {}
840869

841-
// Guard against race conditions when rendering the node
842-
private listConnections = shared(() => this.resource.listConnections())
843870
public async getTreeItem() {
844871
// Calling this here is robust but `TreeShim` must be instantiated lazily to stop side-effects
845872
await this.resource.tryAutoConnect()
846873

847-
const conn = this.resource.activeConnection
848-
if (conn === undefined && (await this.listConnections()).length === 0) {
874+
if (!this.resource.hasConnections) {
849875
const item = new vscode.TreeItem(`Connect to ${getIdeProperties().company} to Get Started...`)
850876
item.command = addConnection.build().asCommand({ title: 'Add Connection' })
851877

852878
return item
853879
}
854880

881+
const conn = this.resource.activeConnection
855882
const itemLabel =
856883
conn?.label !== undefined
857884
? localize('aws.auth.node.connected', `Connected with {0}`, conn.label)

0 commit comments

Comments
 (0)