Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit250db54

Browse files
committed
Add test for proxy authorization
1 parent6b25cf9 commit250db54

File tree

4 files changed

+136
-31
lines changed

4 files changed

+136
-31
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import com.coder.gateway.models.TokenSource
66
importcom.coder.gateway.models.WorkspaceAgentModel
77
importcom.coder.gateway.sdk.CoderCLIManager
88
importcom.coder.gateway.sdk.CoderRestClient
9+
importcom.coder.gateway.sdk.defaultProxy
10+
importcom.coder.gateway.sdk.defaultVersion
911
importcom.coder.gateway.sdk.ex.AuthenticationResponseException
1012
importcom.coder.gateway.sdk.toURL
1113
importcom.coder.gateway.sdk.v2.models.Workspace
@@ -140,7 +142,7 @@ class CoderGatewayConnectionProvider : GatewayConnectionProvider {
140142
if (token==null) {// User aborted.
141143
throwIllegalArgumentException("Unable to connect to$deploymentURL,$TOKEN is missing")
142144
}
143-
val client=CoderRestClient(deploymentURL, token.first,null, settings)
145+
val client=CoderRestClient(deploymentURL, token.first,defaultVersion(), settings, defaultProxy())
144146
returntry {
145147
Pair(client, client.me().username)
146148
}catch (ex:AuthenticationResponseException) {

‎src/main/kotlin/com/coder/gateway/sdk/CoderRestClientService.kt‎

Lines changed: 58 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import java.io.File
3434
importjava.io.FileInputStream
3535
importjava.net.HttpURLConnection.HTTP_CREATED
3636
importjava.net.InetAddress
37+
importjava.net.ProxySelector
3738
importjava.net.Socket
3839
importjava.net.URL
3940
importjava.nio.file.Path
@@ -75,63 +76,91 @@ class CoderRestClientService {
7576
* @throws [AuthenticationResponseException] if authentication failed.
7677
*/
7778
funinitClientSession(url:URL,token:String,settings:CoderSettingsState):User {
78-
client=CoderRestClient(url, token,null, settings)
79+
client=CoderRestClient(url, token,defaultVersion(), settings, defaultProxy())
7980
me= client.me()
8081
buildVersion= client.buildInfo().version
8182
isReady=true
8283
return me
8384
}
8485
}
8586

86-
classCoderRestClient(
87+
/**
88+
* Holds proxy information. Exists only to interface with tests since they
89+
* cannot create an HttpConfigurable instance.
90+
*/
91+
data classProxyValues (
92+
valusername:String?,
93+
valpassword:String?,
94+
valuseAuth:Boolean,
95+
valselector:ProxySelector,
96+
)
97+
98+
fundefaultProxy():ProxyValues {
99+
val inst=HttpConfigurable.getInstance()
100+
returnProxyValues(
101+
inst.proxyLogin,
102+
inst.plainProxyPassword,
103+
inst.PROXY_AUTHENTICATION,
104+
inst.onlyBySettingsSelector
105+
)
106+
}
107+
108+
fundefaultVersion():String {
109+
// This is the id from the plugin.xml.
110+
returnPluginManagerCore.getPlugin(PluginId.getId("com.coder.gateway"))!!.version
111+
}
112+
113+
classCoderRestClient @JvmOverloads constructor(
87114
varurl:URL,vartoken:String,
88-
privatevarpluginVersion:String?,
89-
privatevarsettings:CoderSettingsState,
115+
privatevalpluginVersion:String,
116+
privatevalsettings:CoderSettingsState,
117+
privatevalproxyValues:ProxyValues? =null,
90118
) {
91-
privatevar httpClient:OkHttpClient
92-
privatevar retroRestClient:CoderV2RestFacade
119+
privateval httpClient:OkHttpClient
120+
privateval retroRestClient:CoderV2RestFacade
93121

94122
init {
95123
val gson:Gson=GsonBuilder().registerTypeAdapter(Instant::class.java,InstantConverter()).setPrettyPrinting().create()
96-
if (pluginVersion.isNullOrBlank()) {
97-
pluginVersion=PluginManagerCore.getPlugin(PluginId.getId("com.coder.gateway"))!!.version// this is the id from the plugin.xml
98-
}
99-
100-
val proxy=HttpConfigurable.getInstance()
101124

102125
val socketFactory= coderSocketFactory(settings)
103126
val trustManagers= coderTrustManagers(settings.tlsCAPath)
104-
httpClient=OkHttpClient.Builder()
105-
.proxySelector(proxy.onlyBySettingsSelector)
106-
.proxyAuthenticator { _, response->
107-
val login= proxy.proxyLogin
108-
val pass= proxy.plainProxyPassword
109-
if (proxy.PROXY_AUTHENTICATION&& login!=null&& pass!=null) {
110-
val credentials=Credentials.basic(login, pass)
111-
response.request.newBuilder()
112-
.header("Proxy-Authorization", credentials)
113-
.build()
114-
}elsenull
115-
}
127+
var builder=OkHttpClient.Builder()
128+
129+
if (proxyValues!=null) {
130+
builder= builder
131+
.proxySelector(proxyValues.selector)
132+
.proxyAuthenticator { _, response->
133+
if (proxyValues.useAuth&& proxyValues.username!=null&& proxyValues.password!=null) {
134+
val credentials=Credentials.basic(proxyValues.username, proxyValues.password)
135+
response.request.newBuilder()
136+
.header("Proxy-Authorization", credentials)
137+
.build()
138+
}elsenull
139+
}
140+
}
141+
142+
httpClient= builder
116143
.sslSocketFactory(socketFactory, trustManagers[0]asX509TrustManager)
117144
.hostnameVerifier(CoderHostnameVerifier(settings.tlsAlternateHostname))
118145
.addInterceptor { it.proceed(it.request().newBuilder().addHeader("Coder-Session-Token", token).build()) }
119146
.addInterceptor { it.proceed(it.request().newBuilder().addHeader("User-Agent","Coder Gateway/${pluginVersion} (${SystemInfo.getOsNameAndVersion()};${SystemInfo.OS_ARCH})").build()) }
120147
.addInterceptor {
121148
var request= it.request()
122149
val headers= getHeaders(url, settings.headerCommand)
123-
if (headers.size>0) {
124-
valbuilder= request.newBuilder()
125-
headers.forEach { h->builder.addHeader(h.key, h.value) }
126-
request=builder.build()
150+
if (headers.isNotEmpty()) {
151+
valreqBuilder= request.newBuilder()
152+
headers.forEach { h->reqBuilder.addHeader(h.key, h.value) }
153+
request=reqBuilder.build()
127154
}
128155
it.proceed(request)
129156
}
130-
//this should always be last if we want to see previous interceptors logged
157+
//This should always be last if we want to see previous interceptors logged.
131158
.addInterceptor(HttpLoggingInterceptor().apply { setLevel(HttpLoggingInterceptor.Level.BASIC) })
132159
.build()
133160

134-
retroRestClient=Retrofit.Builder().baseUrl(url.toString()).client(httpClient).addConverterFactory(GsonConverterFactory.create(gson)).build().create(CoderV2RestFacade::class.java)
161+
retroRestClient=Retrofit.Builder().baseUrl(url.toString()).client(httpClient)
162+
.addConverterFactory(GsonConverterFactory.create(gson))
163+
.build().create(CoderV2RestFacade::class.java)
135164
}
136165

137166
/**

‎src/main/kotlin/com/coder/gateway/views/CoderGatewayRecentWorkspaceConnectionsView.kt‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import com.coder.gateway.icons.CoderIcons
99
importcom.coder.gateway.models.RecentWorkspaceConnection
1010
importcom.coder.gateway.models.WorkspaceAgentModel
1111
importcom.coder.gateway.sdk.CoderRestClient
12+
importcom.coder.gateway.sdk.defaultProxy
13+
importcom.coder.gateway.sdk.defaultVersion
1214
importcom.coder.gateway.sdk.toURL
1315
importcom.coder.gateway.sdk.v2.models.WorkspaceStatus
1416
importcom.coder.gateway.sdk.v2.models.toAgentModels
@@ -254,7 +256,7 @@ class CoderGatewayRecentWorkspaceConnectionsView(private val setContentCallback:
254256
deployments[dir]?:try {
255257
val url=Path.of(dir).resolve("url").toFile().readText()
256258
val token=Path.of(dir).resolve("session").toFile().readText()
257-
DeploymentInfo(CoderRestClient(url.toURL(), token,null, settings))
259+
DeploymentInfo(CoderRestClient(url.toURL(), token,defaultVersion(), settings, defaultProxy()))
258260
}catch (e:Exception) {
259261
logger.error("Unable to create client from$dir", e)
260262
DeploymentInfo(error="Error trying to read$dir:${e.message}")

‎src/test/groovy/CoderRestClientTest.groovy‎

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import java.time.Instant
2626
@Unroll
2727
classCoderRestClientTestextendsSpecification {
2828
privateCoderSettingsState settings=newCoderSettingsState()
29+
2930
/**
3031
* Create, start, and return a server that mocks the Coder API.
3132
*
@@ -99,6 +100,48 @@ class CoderRestClientTest extends Specification {
99100
return [srv,"https://localhost:"+ srv.address.port]
100101
}
101102

103+
defmockProxy() {
104+
HttpServer srv=HttpServer.create(newInetSocketAddress(0),0)
105+
srv.createContext("/",newHttpHandler() {
106+
voidhandle(HttpExchangeexchange) {
107+
int code
108+
String response
109+
110+
if (exchange.requestHeaders.getFirst("Proxy-Authorization")!="Basic Zm9vOmJhcg==") {
111+
code=HttpURLConnection.HTTP_PROXY_AUTH
112+
response="authentication required"
113+
}else {
114+
try {
115+
HttpURLConnection conn=newURL(exchange.getRequestURI().toString()).openConnection()
116+
exchange.requestHeaders.each{
117+
conn.setRequestProperty(it.key, it.value.join(","))
118+
}
119+
BufferedReader br=newBufferedReader(newInputStreamReader(conn.inputStream))
120+
StringBuilder responseBuilder=newStringBuilder();
121+
String line
122+
while ((line= br.readLine())!=null) {
123+
responseBuilder.append(line)
124+
}
125+
br.close()
126+
response= responseBuilder.toString()
127+
code= conn.responseCode
128+
}catch (Exception error) {
129+
code=HttpURLConnection.HTTP_INTERNAL_ERROR
130+
response= error.message
131+
println(error)// Print since it will not show up in the error.
132+
}
133+
}
134+
135+
byte[] body= response.getBytes()
136+
exchange.sendResponseHeaders(code, body.length)
137+
exchange.responseBody.write(body)
138+
exchange.close()
139+
}
140+
})
141+
srv.start()
142+
return srv
143+
}
144+
102145
def"gets workspaces"() {
103146
given:
104147
def (srv, url)= mockServer(workspaces)
@@ -278,4 +321,33 @@ class CoderRestClientTest extends Specification {
278321
cleanup:
279322
srv.stop(0)
280323
}
324+
325+
def"uses proxy"() {
326+
given:
327+
def (srv1, url1)= mockServer([DataGen.workspace("ws1")])
328+
def srv2= mockProxy()
329+
def client=newCoderRestClient(newURL(url1),"token","test", settings,newProxyValues(
330+
"foo",
331+
"bar",
332+
true,
333+
newProxySelector() {
334+
@Override
335+
List<Proxy>select(URIuri) {
336+
return [newProxy(Proxy.Type.HTTP,newInetSocketAddress("localhost", srv2.address.port))]
337+
}
338+
339+
@Override
340+
voidconnectFailed(URIuri,SocketAddresssa,IOExceptionioe) {
341+
getDefault().connectFailed(uri, sa, ioe);
342+
}
343+
}
344+
))
345+
346+
expect:
347+
client.workspaces()*.name== ["ws1"]
348+
349+
cleanup:
350+
srv1.stop(0)
351+
srv2.stop(0)
352+
}
281353
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp