Skip to content

Commit 2e45eb4

Browse files
committed
Make token optional when using mTLS
Closes #394.
1 parent d5d4033 commit 2e45eb4

File tree

9 files changed

+182
-102
lines changed

9 files changed

+182
-102
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
- Various recent connections fixes (details coming soon).
1010
- IDEs are now sorted by version.
1111

12+
### Changed
13+
14+
- If using a certificate and key, it is assumed that token authentication is not
15+
required, and all token prompts are skipped.
16+
1217
### Added
1318

1419
- New setting for a setup command that will run in the directory of the IDE

gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
pluginGroup=com.coder.gateway
44
pluginName=coder-gateway
55
# SemVer format -> https://semver.org
6-
pluginVersion=2.11.0
6+
pluginVersion=2.11.1
77
# See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
88
# for insight into build numbers and IntelliJ Platform versions.
99
pluginSinceBuild=233.6745

src/main/kotlin/com/coder/gateway/CoderGatewayConnectionProvider.kt

+25-19
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ class CoderGatewayConnectionProvider : GatewayConnectionProvider {
106106
throw IllegalArgumentException("Query parameter \"$URL\" is missing")
107107
}
108108

109-
val (client, username) = authenticate(deploymentURL, parameters.token())
109+
val client = authenticate(deploymentURL, parameters.token())
110110

111111
// TODO: If the workspace is missing we could launch the wizard.
112112
val workspaceName = parameters.workspace() ?: throw IllegalArgumentException("Query parameter \"$WORKSPACE\" is missing")
@@ -189,29 +189,35 @@ class CoderGatewayConnectionProvider : GatewayConnectionProvider {
189189
}
190190

191191
/**
192-
* Return an authenticated Coder CLI and the user's name, asking for the
193-
* token as long as it continues to result in an authentication failure.
192+
* Return an authenticated Coder CLI, asking for the token as long as it
193+
* continues to result in an authentication failure and token authentication
194+
* is required.
194195
*/
195-
private fun authenticate(deploymentURL: String, queryToken: String?, lastToken: Pair<String, TokenSource>? = null): Pair<CoderRestClient, String> {
196-
// Use the token from the query, unless we already tried that.
197-
val isRetry = lastToken != null
198-
val token = if (!queryToken.isNullOrBlank() && !isRetry)
199-
Pair(queryToken, TokenSource.QUERY)
200-
else CoderRemoteConnectionHandle.askToken(
201-
deploymentURL.toURL(),
202-
lastToken,
203-
isRetry,
204-
useExisting = true,
205-
settings,
206-
)
207-
if (token == null) { // User aborted.
196+
private fun authenticate(deploymentURL: String, queryToken: String?, lastToken: Pair<String, TokenSource>? = null): CoderRestClient {
197+
val token = if (settings.requireTokenAuth) {
198+
// Use the token from the query, unless we already tried that.
199+
val isRetry = lastToken != null
200+
if (!queryToken.isNullOrBlank() && !isRetry)
201+
Pair(queryToken, TokenSource.QUERY)
202+
else CoderRemoteConnectionHandle.askToken(
203+
deploymentURL.toURL(),
204+
lastToken,
205+
isRetry,
206+
useExisting = true,
207+
settings)
208+
} else null
209+
if (settings.requireTokenAuth && token == null) { // User aborted.
208210
throw IllegalArgumentException("Unable to connect to $deploymentURL, query parameter \"$TOKEN\" is missing")
209211
}
210-
val client = CoderRestClientService(deploymentURL.toURL(), token.first)
212+
val client = CoderRestClientService(deploymentURL.toURL(), token?.first)
211213
return try {
212-
Pair(client, client.me().username)
214+
client.authenticate()
215+
client
213216
} catch (ex: AuthenticationResponseException) {
214-
authenticate(deploymentURL, queryToken, token)
217+
// If doing token auth we can ask and try again.
218+
if (settings.requireTokenAuth) {
219+
authenticate(deploymentURL, queryToken, token)
220+
} else throw ex
215221
}
216222
}
217223

src/main/kotlin/com/coder/gateway/CoderRemoteConnectionHandle.kt

+1
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ class CoderRemoteConnectionHandle {
228228
if (isRetry) "gateway.connector.view.workspaces.token.rejected"
229229
else if (tokenSource == TokenSource.CONFIG) "gateway.connector.view.workspaces.token.injected"
230230
else if (tokenSource == TokenSource.QUERY) "gateway.connector.view.workspaces.token.query"
231+
else if (tokenSource == TokenSource.LAST_USED) "gateway.connector.view.workspaces.token.last-used"
231232
else if (existingToken.isNotBlank()) "gateway.connector.view.workspaces.token.comment"
232233
else "gateway.connector.view.workspaces.token.none",
233234
url.host,

src/main/kotlin/com/coder/gateway/models/TokenSource.kt

+1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ enum class TokenSource {
77
CONFIG, // Pulled from the Coder CLI config.
88
USER, // Input by the user.
99
QUERY, // From the Gateway link as a query parameter.
10+
LAST_USED, // Last used token.
1011
}
1112

src/main/kotlin/com/coder/gateway/settings/CoderSettings.kt

+10-2
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,15 @@ open class CoderSettings(
183183
}
184184

185185
/**
186-
* Return the URL and token from the config, if it exists.
186+
* Return the URL and token from the config, if it exists. Both the url and
187+
* session files must exist if using token auth, otherwise only url must
188+
* exist.
187189
*/
188190
fun readConfig(dir: Path): Pair<String?, String?> {
189191
logger.info("Reading config from $dir")
190192
return try {
191-
Files.readString(dir.resolve("url")) to Files.readString(dir.resolve("session"))
193+
val token = if (requireTokenAuth) Files.readString(dir.resolve("session")) else null
194+
Files.readString(dir.resolve("url")) to token
192195
} catch (e: Exception) {
193196
// SSH has not been configured yet, or using some other authorization mechanism.
194197
null to null
@@ -246,6 +249,11 @@ open class CoderSettings(
246249
}
247250
}
248251

252+
val requireTokenAuth: Boolean
253+
get() {
254+
return tls.certPath.isBlank() || tls.keyPath.isBlank()
255+
}
256+
249257
/**
250258
* Return the name of the binary (with extension) for the provided OS and
251259
* architecture.

0 commit comments

Comments
 (0)