Skip to content

Commit 2c7383d

Browse files
manodnyabaws-toolkit-automationjuanbenjrli
authored
Sign in with Idc for CodeCatalyst (#4126)
* Support sign in to CodeCatalyst via Identity Center (#4059) * Support SSO sign in for CodeCatalyst in IDEA * Support SSO sign in for CodeCatalyst in the Gateway * Fix codecatalyst scope * Add new GW authentication dialog * Fix merge conflicts * Small refactor of GW auth dialog * Refactor auth dialog panel building to dedupe code * Empty-Commit * Fix broken unit tests * Fix tests, lint errors, small fixes * Fix lint errors * Addressed PR feedback * Fix lint errors * Add support for opening CodeCatalyst dev env using Idc (#4079) * Support SSO sign in for CodeCatalyst in IDEA * Support SSO sign in for CodeCatalyst in the Gateway * Fix codecatalyst scope * Add new GW authentication dialog * Fix merge conflicts * Small refactor of GW auth dialog * Refactor auth dialog panel building to dedupe code * Empty-Commit * Fix broken unit tests * Fix tests, lint errors, small fixes * Fix lint errors * Support starting a dev env via Idc from an external url * Addressed PR feedback * Addressed PR feedback * Fix lint errors * Include conn parameters in workspace list * Addressed PR feedback * Fix getting started panel * Avoid throwing error when canceling auth dialog in GW (#4111) Co-authored-by: manodnyab <[email protected]> * Fix sign out message in GW (#4097) * Fix sign out message in GW * Remove unused message bundle entry --------- Co-authored-by: manodnyab <[email protected]> * Fix Auth Setup Dialog For CodeCatalyst (#4102) * Fix getting started panel for CodeCatalyst * Fix getting started panel button label, supported auth table * Remove notice banner in setup auth dialog for CodeCatalyst (#4103) * Remove notice in setup auth dialog for CodeCatalyst * add support for idc in gs page * Fix duplicate + invalid SSO session found when connected to remote dev env (#4107) * Add IDC as connection type for CC metrics (#4123) * add entrypoint for metrics * added changelog * detekt * Fix switching between accounts in CodeCatalyst (#4122) * Fix switching between accounts in CodeCatalyst * fixed tests * extra line * feedback changes * feedback 2 * detekt --------- Co-authored-by: aws-toolkit-automation <[email protected]> Co-authored-by: juanbenj <[email protected]> Co-authored-by: Richard Li <[email protected]>
1 parent 400016f commit 2c7383d

File tree

53 files changed

+1009
-472
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1009
-472
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" : "Add support for IAM Identity Center connections for CodeCatalyst"
4+
}

core/src/software/aws/toolkits/core/credentials/ToolkitCredentialsProvider.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ class ToolkitBearerTokenProvider(val delegate: ToolkitBearerTokenProviderDelegat
137137
message("iam_identity_center.service_name", extractOrgID(startUrl))
138138
}
139139

140-
fun diskSessionIdentifier(profileName: String) = "diskSessionProfile;$profileName"
140+
fun diskSessionIdentifier(profileName: String) = "sso-session:$profileName"
141141
fun diskSessionDisplayName(profileName: String) = "IAM Identity Center Session ($profileName)"
142142
}
143143
}

jetbrains-core/resources/META-INF/plugin.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,7 @@
784784
<action class="software.aws.toolkits.jetbrains.settings.ShowSettingsAction" id="aws.settings.show" icon="AllIcons.General.Settings"/>
785785

786786
<group id="aws.toolkit.sono.id.actions">
787-
<action class="software.aws.toolkits.jetbrains.core.credentials.sono.SonoLogoutAction" id="aws.toolkit.sono.id.logout"/>
787+
<action class="software.aws.toolkits.jetbrains.core.credentials.sono.SonoLogoutAction" id="aws.toolkit.caws.logout"/>
788788
<action class="software.aws.toolkits.jetbrains.services.caws.actions.OpenCawsProfileAction" id="aws.toolkit.caws.profile"/>
789789
<action class="software.aws.toolkits.jetbrains.ui.feedback.SubmitFeedbackInGateway" id="aws.toolkit.submit.caws.dev.env.feedback"/>
790790
</group>

jetbrains-core/resources/META-INF/services/caws.xml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,12 @@
55
<depends optional="true" config-file="services/caws-ext-git.xml">Git4Idea</depends>
66

77
<extensions defaultExtensionNs="com.intellij">
8-
<projectService serviceImplementation="software.aws.toolkits.jetbrains.core.credentials.sono.SonoCredentialManager"/>
9-
<applicationService serviceImplementation="software.aws.toolkits.jetbrains.core.credentials.sono.SonoCredentialManager"/>
8+
<projectService serviceImplementation="software.aws.toolkits.jetbrains.core.credentials.sono.CodeCatalystCredentialManager"/>
9+
<applicationService serviceImplementation="software.aws.toolkits.jetbrains.core.credentials.sono.CodeCatalystCredentialManager"/>
1010
<applicationService serviceImplementation="software.aws.toolkits.jetbrains.settings.CawsSpaceTracker"/>
1111
<projectService serviceImplementation="software.aws.toolkits.jetbrains.services.caws.projectstate.CawsProjectSettings"/>
1212
</extensions>
1313

14-
<extensions defaultExtensionNs="aws.toolkit">
15-
<startupAuthFactory implementation="software.aws.toolkits.jetbrains.core.credentials.sono.SonoDiskProfileAuthFactory"/>
16-
</extensions>
17-
1814
<actions>
1915
<group id="aws.caws.devtools.actions.loggedin">
2016
<action class="software.aws.toolkits.jetbrains.core.explorer.devToolsTab.nodes.actions.CopyCawsRepositoryUrl" id="aws.caws.devtools.actions.copyCloneUrl"/>

jetbrains-core/src/software/aws/toolkits/jetbrains/core/credentials/DefaultToolkitAuthManager.kt

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -81,21 +81,21 @@ class DefaultToolkitAuthManager : ToolkitAuthManager, PersistentStateComponent<T
8181

8282
override fun listConnections(): List<ToolkitConnection> = connections.toList() + transientConnections
8383

84-
override fun tryCreateTransientSsoConnection(profile: AuthProfile, callback: (BearerSsoConnection) -> Unit): BearerSsoConnection {
85-
val connection = (connectionFromProfile(profile) as BearerSsoConnection).also {
84+
override fun tryCreateTransientSsoConnection(profile: AuthProfile, callback: (AwsBearerTokenConnection) -> Unit): AwsBearerTokenConnection {
85+
val connection = (connectionFromProfile(profile) as AwsBearerTokenConnection).also {
8686
callback(it)
8787
transientConnections.add(it)
8888
}
8989

9090
return connection
9191
}
9292

93-
override fun getOrCreateSsoConnection(profile: UserConfigSsoSessionProfile): BearerSsoConnection {
94-
(transientConnections.firstOrNull { it.id == profile.id } as? BearerSsoConnection)?.let {
93+
override fun getOrCreateSsoConnection(profile: UserConfigSsoSessionProfile): AwsBearerTokenConnection {
94+
(transientConnections.firstOrNull { it.id == profile.id } as? AwsBearerTokenConnection)?.let {
9595
return it
9696
}
9797

98-
val connection = connectionFromProfile(profile) as BearerSsoConnection
98+
val connection = connectionFromProfile(profile) as AwsBearerTokenConnection
9999
transientConnections.add(connection)
100100

101101
return connection
@@ -130,11 +130,15 @@ class DefaultToolkitAuthManager : ToolkitAuthManager, PersistentStateComponent<T
130130
}
131131

132132
private fun deleteConnection(predicate: (ToolkitConnection) -> Boolean) {
133+
val deleted = mutableListOf<ToolkitConnection>()
133134
connections.removeAll { connection ->
134135
predicate(connection).also {
135-
if (it && connection is Disposable) {
136-
disposeAndNotify(connection)
137-
}
136+
deleted.add(connection)
137+
}
138+
}
139+
for (connection in deleted) {
140+
if (connection is Disposable) {
141+
disposeAndNotify(connection)
138142
}
139143
}
140144
}
@@ -222,7 +226,8 @@ class DefaultToolkitAuthManager : ToolkitAuthManager, PersistentStateComponent<T
222226
is DetectedDiskSsoSessionProfile -> DetectedDiskSsoSessionConnection(
223227
sessionProfileName = profile.profileName,
224228
startUrl = profile.startUrl,
225-
region = profile.ssoRegion
229+
region = profile.ssoRegion,
230+
scopes = profile.scopes
226231
)
227232
}
228233

jetbrains-core/src/software/aws/toolkits/jetbrains/core/credentials/DefaultToolkitConnectionManager.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ class DefaultToolkitConnectionManager : ToolkitConnectionManager, PersistentStat
124124
if (featuresToPin.isNotEmpty()) {
125125
application.executeOnPooledThread {
126126
pinningManager.pinFeatures(oldConnection, newConnection, featuresToPin)
127-
application.messageBus.syncPublisher(ToolkitConnectionManagerListener.TOPIC).activeConnectionChanged(newConnection)
128127
}
129128
}
130129
}

jetbrains-core/src/software/aws/toolkits/jetbrains/core/credentials/ToolkitAuthManager.kt

Lines changed: 21 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
package software.aws.toolkits.jetbrains.core.credentials
55

66
import com.intellij.openapi.Disposable
7-
import com.intellij.openapi.application.ApplicationManager
87
import com.intellij.openapi.components.service
98
import com.intellij.openapi.extensions.ExtensionPointName
109
import com.intellij.openapi.project.Project
@@ -24,6 +23,7 @@ import software.aws.toolkits.jetbrains.core.credentials.sono.isSono
2423
import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.BearerTokenAuthState
2524
import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.BearerTokenProvider
2625
import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.BearerTokenProviderListener
26+
import software.aws.toolkits.jetbrains.core.gettingstarted.deleteSsoConnectionCW
2727
import software.aws.toolkits.jetbrains.utils.computeOnEdt
2828
import software.aws.toolkits.jetbrains.utils.runUnderProgressIfNeeded
2929
import software.aws.toolkits.resources.message
@@ -42,14 +42,11 @@ interface AwsCredentialConnection : ToolkitConnection {
4242
interface AwsBearerTokenConnection : ToolkitConnection {
4343
val startUrl: String
4444
val region: String
45+
val scopes: List<String>
4546

4647
override fun getConnectionSettings(): TokenConnectionSettings
4748
}
4849

49-
interface BearerSsoConnection : AwsBearerTokenConnection {
50-
val scopes: List<String>
51-
}
52-
5350
sealed interface AuthProfile
5451

5552
data class ManagedSsoProfile(
@@ -71,7 +68,8 @@ data class UserConfigSsoSessionProfile(
7168
data class DetectedDiskSsoSessionProfile(
7269
var profileName: String = "",
7370
var startUrl: String = "",
74-
var ssoRegion: String = ""
71+
var ssoRegion: String = "",
72+
var scopes: List<String> = emptyList()
7573
) : AuthProfile
7674

7775
/**
@@ -92,10 +90,10 @@ interface ToolkitAuthManager {
9290

9391
/**
9492
* Creates a connection that is not visible to the rest of the toolkit unless authentication succeeds
95-
* @return [BearerSsoConnection] on success
93+
* @return [AwsBearerTokenConnection] on success
9694
*/
97-
fun tryCreateTransientSsoConnection(profile: AuthProfile, callback: (BearerSsoConnection) -> Unit): BearerSsoConnection
98-
fun getOrCreateSsoConnection(profile: UserConfigSsoSessionProfile): BearerSsoConnection
95+
fun tryCreateTransientSsoConnection(profile: AuthProfile, callback: (AwsBearerTokenConnection) -> Unit): AwsBearerTokenConnection
96+
fun getOrCreateSsoConnection(profile: UserConfigSsoSessionProfile): AwsBearerTokenConnection
9997

10098
fun deleteConnection(connection: ToolkitConnection)
10199
fun deleteConnection(connectionId: String)
@@ -134,7 +132,7 @@ fun loginSso(project: Project?, startUrl: String, region: String, requestedScope
134132
val logger = getLogger<ToolkitAuthManager>()
135133
// requested Builder ID, but one already exists
136134
// TBD: do we do this for regular SSO too?
137-
if (connection.isSono() && connection is BearerSsoConnection && requestedScopes.all { it in connection.scopes }) {
135+
if (connection.isSono() && connection is AwsBearerTokenConnection && requestedScopes.all { it in connection.scopes }) {
138136
val signOut = computeOnEdt {
139137
MessageDialogBuilder.yesNo(
140138
message("toolkit.login.aws_builder_id.already_connected.title"),
@@ -150,13 +148,13 @@ fun loginSso(project: Project?, startUrl: String, region: String, requestedScope
150148
"Forcing reauth on ${connection.id} since user requested Builder ID while already connected to Builder ID"
151149
}
152150

153-
logoutFromSsoConnection(project, connection as AwsBearerTokenConnection)
151+
logoutFromSsoConnection(project, connection)
154152
return@let null
155153
}
156154
}
157155

158156
// There is an existing connection we can use
159-
if (connection is BearerSsoConnection && !requestedScopes.all { it in connection.scopes }) {
157+
if (connection is AwsBearerTokenConnection && !requestedScopes.all { it in connection.scopes }) {
160158
allScopes.addAll(connection.scopes)
161159

162160
logger.info {
@@ -165,7 +163,7 @@ fun loginSso(project: Project?, startUrl: String, region: String, requestedScope
165163
are not a complete subset of current scopes (${connection.scopes})
166164
""".trimIndent()
167165
}
168-
logoutFromSsoConnection(project, connection as AwsBearerTokenConnection)
166+
logoutFromSsoConnection(project, connection)
169167
// can't reuse since requested scopes are not in current connection. forcing reauth
170168
return@let null
171169
}
@@ -204,11 +202,14 @@ internal fun reauthConnection(project: Project?, connection: ToolkitConnection):
204202
return provider
205203
}
206204

205+
@Suppress("UnusedParameter")
207206
fun logoutFromSsoConnection(project: Project?, connection: AwsBearerTokenConnection, callback: () -> Unit = {}) {
208207
try {
209-
ApplicationManager.getApplication().messageBus.syncPublisher(BearerTokenProviderListener.TOPIC).invalidate(connection.id)
210208
ToolkitAuthManager.getInstance().deleteConnection(connection.id)
211-
project?.let { ToolkitConnectionManager.getInstance(it).switchConnection(null) }
209+
if (connection is ProfileSsoManagedBearerSsoConnection) {
210+
// TODO: Connection handling in GettingStartedAuthUtils needs to be refactored
211+
deleteSsoConnectionCW(connection)
212+
}
212213
} finally {
213214
callback()
214215
}
@@ -238,19 +239,12 @@ fun AwsBearerTokenConnection.lazyIsUnauthedBearerConnection(): Boolean {
238239

239240
fun reauthConnectionIfNeeded(project: Project?, connection: ToolkitConnection): BearerTokenProvider {
240241
val tokenProvider = (connection.getConnectionSettings() as TokenConnectionSettings).tokenProvider.delegate as BearerTokenProvider
241-
242-
return reauthProviderIfNeeded(project, tokenProvider, connection.isSono())
242+
return reauthProviderIfNeeded(project, tokenProvider)
243243
}
244244

245-
fun reauthProviderIfNeeded(project: Project?, tokenProvider: BearerTokenProvider, isBuilderId: Boolean): BearerTokenProvider {
246-
maybeReauthProviderIfNeeded(project, tokenProvider, isBuilderId) {
247-
val title = if (isBuilderId) {
248-
message("credentials.sono.login.pending")
249-
} else {
250-
message("credentials.sso.login.pending")
251-
}
252-
253-
runUnderProgressIfNeeded(project, title, true) {
245+
fun reauthProviderIfNeeded(project: Project?, tokenProvider: BearerTokenProvider): BearerTokenProvider {
246+
maybeReauthProviderIfNeeded(project, tokenProvider) {
247+
runUnderProgressIfNeeded(project, message("credentials.pending.title"), true) {
254248
tokenProvider.reauthenticate()
255249
}
256250
}
@@ -262,7 +256,6 @@ fun reauthProviderIfNeeded(project: Project?, tokenProvider: BearerTokenProvider
262256
fun maybeReauthProviderIfNeeded(
263257
project: Project?,
264258
tokenProvider: BearerTokenProvider,
265-
isBuilderId: Boolean,
266259
onReauthRequired: (SsoOidcException?) -> Any
267260
): Boolean {
268261
val state = tokenProvider.state()
@@ -275,13 +268,7 @@ fun maybeReauthProviderIfNeeded(
275268

276269
BearerTokenAuthState.NEEDS_REFRESH -> {
277270
try {
278-
val title = if (isBuilderId) {
279-
message("credentials.sono.login.refreshing")
280-
} else {
281-
message("credentials.sso.login.refreshing")
282-
}
283-
284-
return runUnderProgressIfNeeded(project, title, true) {
271+
return runUnderProgressIfNeeded(project, message("credentials.refreshing"), true) {
285272
tokenProvider.resolveToken()
286273
BearerTokenProviderListener.notifyCredUpdate(tokenProvider.id)
287274
return@runUnderProgressIfNeeded false

jetbrains-core/src/software/aws/toolkits/jetbrains/core/credentials/ToolkitConnectionImpls.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ sealed class ManagedBearerSsoConnection(
5656
cache: DiskCache = diskCache,
5757
override val id: String,
5858
override val label: String
59-
) : BearerSsoConnection, Disposable {
59+
) : AwsBearerTokenConnection, Disposable {
6060

6161
private val provider =
6262
tokenConnection(
@@ -81,6 +81,7 @@ class DetectedDiskSsoSessionConnection(
8181
val sessionProfileName: String,
8282
override val startUrl: String,
8383
override val region: String,
84+
override val scopes: List<String>,
8485
displayNameOverride: String? = null
8586
) : AwsBearerTokenConnection, Disposable {
8687
override val id = ToolkitBearerTokenProvider.diskSessionIdentifier(sessionProfileName)

jetbrains-core/src/software/aws/toolkits/jetbrains/core/credentials/metadataservice/ContainerCredentialProviderFactory.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ import software.aws.toolkits.core.credentials.CredentialsChangeListener
1616
import software.aws.toolkits.core.region.AwsRegion
1717
import software.aws.toolkits.core.utils.debug
1818
import software.aws.toolkits.core.utils.getLogger
19-
import software.aws.toolkits.jetbrains.services.caws.CawsConstants
19+
import software.aws.toolkits.jetbrains.utils.isCodeCatalystDevEnv
2020

2121
class ContainerCredentialProviderFactory : CredentialProviderFactory {
2222
init {
23-
if (System.getenv(CawsConstants.CAWS_ENV_ID_VAR) != null) {
23+
if (isCodeCatalystDevEnv()) {
2424
throw ExtensionNotApplicableException.INSTANCE
2525
}
2626
}

jetbrains-core/src/software/aws/toolkits/jetbrains/core/credentials/metadataservice/InstanceRoleCredentialProviderFactory.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ import software.aws.toolkits.core.region.AwsRegion
1818
import software.aws.toolkits.core.utils.debug
1919
import software.aws.toolkits.core.utils.getLogger
2020
import software.aws.toolkits.core.utils.warn
21-
import software.aws.toolkits.jetbrains.services.caws.CawsConstants
21+
import software.aws.toolkits.jetbrains.utils.isCodeCatalystDevEnv
2222

2323
class InstanceRoleCredentialProviderFactory : CredentialProviderFactory {
2424
init {
25-
if (System.getenv(CawsConstants.CAWS_ENV_ID_VAR) != null) {
25+
if (isCodeCatalystDevEnv()) {
2626
throw ExtensionNotApplicableException.INSTANCE
2727
}
2828
}

0 commit comments

Comments
 (0)