IJPL-148832 add proxy authentication tests

GitOrigin-RevId: 0fc1c6338e055d8e0a2361246c3dd67cad5ec11b
This commit is contained in:
Vadim Salavatov
2024-06-03 13:00:09 +02:00
committed by intellij-monorepo-bot
parent 93c45b8263
commit 33b99a6ddb
6 changed files with 258 additions and 38 deletions

84
.idea/libraries/ktor_server_cio.xml generated Normal file
View File

@@ -0,0 +1,84 @@
<component name="libraryTable">
<library name="ktor-server-cio" type="repository">
<properties maven-id="io.ktor:ktor-server-cio-jvm:2.3.8">
<verification>
<artifact url="file://$MAVEN_REPOSITORY$/io/ktor/ktor-server-cio-jvm/2.3.8/ktor-server-cio-jvm-2.3.8.jar">
<sha256sum>cc3bd3576f00159c7fbcb7349f436cd328fb4063233cdf9e2b9c0e30e3d0ea87</sha256sum>
</artifact>
<artifact url="file://$MAVEN_REPOSITORY$/io/ktor/ktor-server-host-common-jvm/2.3.8/ktor-server-host-common-jvm-2.3.8.jar">
<sha256sum>fedfad16c0de46a3c3568be4f5c2734aca14980603f3f04935feff5cd0adf041</sha256sum>
</artifact>
<artifact url="file://$MAVEN_REPOSITORY$/io/ktor/ktor-server-core-jvm/2.3.8/ktor-server-core-jvm-2.3.8.jar">
<sha256sum>ea23ede29486791cc7d38fe5d648142d009fcd2d2c23a01d296250577acfe13d</sha256sum>
</artifact>
<artifact url="file://$MAVEN_REPOSITORY$/com/typesafe/config/1.4.3/config-1.4.3.jar">
<sha256sum>8ada4c185ce72416712d63e0b5afdc5f009c0cdf405e5f26efecdf156aa5dfb6</sha256sum>
</artifact>
<artifact url="file://$MAVEN_REPOSITORY$/io/ktor/ktor-serialization-jvm/2.3.8/ktor-serialization-jvm-2.3.8.jar">
<sha256sum>7d942475bf3995fe080c5f103532e51736d0c474aea3d9f6133a4031ae08799a</sha256sum>
</artifact>
<artifact url="file://$MAVEN_REPOSITORY$/io/ktor/ktor-events-jvm/2.3.8/ktor-events-jvm-2.3.8.jar">
<sha256sum>ed5e0657a1ed5857d12717f1df20fa22bf00ddb88ae9d2558de4ed51d7f4151e</sha256sum>
</artifact>
<artifact url="file://$MAVEN_REPOSITORY$/io/ktor/ktor-http-cio-jvm/2.3.8/ktor-http-cio-jvm-2.3.8.jar">
<sha256sum>ba4bbc9b86ba9ff09a106e6a96e9cb559c5e1a9f092abbd82bab1a1345544f45</sha256sum>
</artifact>
<artifact url="file://$MAVEN_REPOSITORY$/io/ktor/ktor-http-jvm/2.3.8/ktor-http-jvm-2.3.8.jar">
<sha256sum>5d729636363fc35e220ac31dd0103633c8ab1af1264c07fbccd3f2c25b0bb318</sha256sum>
</artifact>
<artifact url="file://$MAVEN_REPOSITORY$/io/ktor/ktor-websockets-jvm/2.3.8/ktor-websockets-jvm-2.3.8.jar">
<sha256sum>3ccc86a35b4301945ba20c8a7ef70e10911558525c3a28274aa36f32ffc2ade9</sha256sum>
</artifact>
<artifact url="file://$MAVEN_REPOSITORY$/io/ktor/ktor-network-jvm/2.3.8/ktor-network-jvm-2.3.8.jar">
<sha256sum>f076335b06e4758f2b3e318eb367007c8fddfc71a9766cdeca3e7b5fb9709f7a</sha256sum>
</artifact>
<artifact url="file://$MAVEN_REPOSITORY$/io/ktor/ktor-utils-jvm/2.3.8/ktor-utils-jvm-2.3.8.jar">
<sha256sum>1ce33e66d42d74828c2e09c75a8f68310023cdc0d2920db77dc0ddc37bea8628</sha256sum>
</artifact>
<artifact url="file://$MAVEN_REPOSITORY$/io/ktor/ktor-io-jvm/2.3.8/ktor-io-jvm-2.3.8.jar">
<sha256sum>4c33dd51a1d6d734c8c127cea96a1cfa024dc1d451ed1e2a86c297fa05f1dc29</sha256sum>
</artifact>
</verification>
<exclude>
<dependency maven-id="org.jetbrains.kotlin:kotlin-stdlib-jdk7" />
<dependency maven-id="org.jetbrains.kotlin:kotlin-stdlib-jdk8" />
<dependency maven-id="org.jetbrains.kotlinx:kotlinx-coroutines-jdk8" />
<dependency maven-id="org.slf4j:slf4j-api" />
<dependency maven-id="org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm" />
<dependency maven-id="org.jetbrains.kotlin:kotlin-stdlib-common" />
<dependency maven-id="org.jetbrains.kotlin:kotlin-reflect" />
<dependency maven-id="org.jetbrains.kotlinx:kotlinx-coroutines-core" />
<dependency maven-id="org.fusesource.jansi:jansi" />
</exclude>
</properties>
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/ktor/ktor-server-cio-jvm/2.3.8/ktor-server-cio-jvm-2.3.8.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/ktor/ktor-server-host-common-jvm/2.3.8/ktor-server-host-common-jvm-2.3.8.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/ktor/ktor-server-core-jvm/2.3.8/ktor-server-core-jvm-2.3.8.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/com/typesafe/config/1.4.3/config-1.4.3.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/ktor/ktor-serialization-jvm/2.3.8/ktor-serialization-jvm-2.3.8.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/ktor/ktor-events-jvm/2.3.8/ktor-events-jvm-2.3.8.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/ktor/ktor-http-cio-jvm/2.3.8/ktor-http-cio-jvm-2.3.8.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/ktor/ktor-http-jvm/2.3.8/ktor-http-jvm-2.3.8.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/ktor/ktor-websockets-jvm/2.3.8/ktor-websockets-jvm-2.3.8.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/ktor/ktor-network-jvm/2.3.8/ktor-network-jvm-2.3.8.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/ktor/ktor-utils-jvm/2.3.8/ktor-utils-jvm-2.3.8.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/ktor/ktor-io-jvm/2.3.8/ktor-io-jvm-2.3.8.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/ktor/ktor-server-cio-jvm/2.3.8/ktor-server-cio-jvm-2.3.8-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/ktor/ktor-server-host-common-jvm/2.3.8/ktor-server-host-common-jvm-2.3.8-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/ktor/ktor-server-core-jvm/2.3.8/ktor-server-core-jvm-2.3.8-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/com/typesafe/config/1.4.3/config-1.4.3-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/ktor/ktor-serialization-jvm/2.3.8/ktor-serialization-jvm-2.3.8-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/ktor/ktor-events-jvm/2.3.8/ktor-events-jvm-2.3.8-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/ktor/ktor-http-cio-jvm/2.3.8/ktor-http-cio-jvm-2.3.8-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/ktor/ktor-http-jvm/2.3.8/ktor-http-jvm-2.3.8-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/ktor/ktor-websockets-jvm/2.3.8/ktor-websockets-jvm-2.3.8-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/ktor/ktor-network-jvm/2.3.8/ktor-network-jvm-2.3.8-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/ktor/ktor-utils-jvm/2.3.8/ktor-utils-jvm-2.3.8-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/ktor/ktor-io-jvm/2.3.8/ktor-io-jvm-2.3.8-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@@ -10,13 +10,17 @@ public interface JavaProxyProperty {
String HTTP_HOST = "http.proxyHost";
String HTTP_PORT = "http.proxyPort";
/** note that this property is not supported by JDK itself, but is used quite broadly in libraries */
String HTTP_PROXY_USER = "http.proxyUser";
/** note that this property is not supported by JDK itself, but is used quite broadly in libraries */
String HTTP_PROXY_PASSWORD = "http.proxyPassword";
String HTTP_NON_PROXY_HOSTS = "http.nonProxyHosts";
String HTTPS_HOST = "https.proxyHost";
String HTTPS_PORT = "https.proxyPort";
/** note that this property is not supported by JDK itself, but is used quite broadly in libraries */
String HTTPS_PROXY_USER = "https.proxyUser";
/** note that this property is not supported by JDK itself, but is used quite broadly in libraries */
String HTTPS_PROXY_PASSWORD = "https.proxyPassword";
String SOCKS_HOST = "socksProxyHost";
@@ -28,12 +32,12 @@ public interface JavaProxyProperty {
String USE_SYSTEM_PROXY = "java.net.useSystemProxies";
/**
* @deprecated correct jvm system property is {@link JavaProxyProperty#HTTP_PROXY_USER}/{@link JavaProxyProperty#HTTPS_PROXY_USER}
* @deprecated it is likely that {@link JavaProxyProperty#HTTP_PROXY_USER}/{@link JavaProxyProperty#HTTPS_PROXY_USER} should be used instead
*/
@Deprecated
String HTTP_USERNAME = "proxy.authentication.username";
/**
* @deprecated correct jvm system property is {@link JavaProxyProperty#HTTP_PROXY_PASSWORD}/{@link JavaProxyProperty#HTTPS_PROXY_PASSWORD}
* @deprecated it is likely that {@link JavaProxyProperty#HTTP_PROXY_PASSWORD}/{@link JavaProxyProperty#HTTPS_PROXY_PASSWORD} should be used instead
*/
@Deprecated
String HTTP_PASSWORD = "proxy.authentication.password";

View File

@@ -98,5 +98,6 @@
<orderEntry type="module" module-name="intellij.java.impl" scope="TEST" />
<orderEntry type="module" module-name="intellij.platform.util.io.storages" />
<orderEntry type="library" name="kotlinx-collections-immutable" level="project" />
<orderEntry type="library" scope="TEST" name="ktor-server-cio" level="project" />
</component>
</module>

View File

@@ -0,0 +1,113 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.util.net
import com.intellij.credentialStore.Credentials
import com.intellij.platform.util.coroutines.childScope
import com.intellij.testFramework.junit5.TestApplication
import io.ktor.server.cio.HttpServer
import io.ktor.server.cio.HttpServerSettings
import io.ktor.server.cio.backend.httpServer
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Test
import java.net.Authenticator
import kotlin.test.assertEquals
@TestApplication
class PlatformProxyAuthTest {
@Test
fun testJdkAuthenticatorIsOverridden() {
assertEquals(Authenticator.getDefault(), JdkProxyProvider.getInstance().authenticator)
}
@Test
fun testHttpConnectionThroughProxyWithAuthentication(): Unit = runBlocking {
val serverScope = childScope("embedded http proxy server", Dispatchers.IO)
val proxyServer = serverScope.embeddedHttpProxyServer(3141)
proxyServer.serverSocket.await()
//launchTestHttpWebServer(3142)
withProxyConfiguration(ProxyConfiguration.proxy(ProxyConfiguration.ProxyProtocol.HTTP, "0.0.0.0", 3141)) {
withKnownProxyCredentials("0.0.0.0", 3141, null) {
val conn = HttpConnectionUtils.openHttpConnection("http://0.0.0.0:3142/path")
conn.setAuthenticator(createResetPlatformAuthenticator())
assertEquals(407, conn.responseCode)
conn.disconnect()
}
withKnownProxyCredentials("0.0.0.0", 3141, Credentials("myuser", "mypassword")) {
val conn = HttpConnectionUtils.openHttpConnection("http://0.0.0.0:3142/path")
conn.setAuthenticator(createResetPlatformAuthenticator())
assertEquals(200, conn.responseCode)
conn.disconnect()
}
withKnownProxyCredentials("0.0.0.0", 3141, Credentials("myuser", "wrongpassword")) {
val conn = HttpConnectionUtils.openHttpConnection("http://0.0.0.0:3142/path")
conn.setAuthenticator(createResetPlatformAuthenticator())
assertEquals(407, conn.responseCode)
conn.disconnect()
}
}
serverScope.cancel()
}
}
/**
* Based on recorded squid proxy interaction
*/
private fun CoroutineScope.embeddedHttpProxyServer(
port: Int,
): HttpServer {
return httpServer(HttpServerSettings(port = port)) { req ->
assertEquals("http://0.0.0.0:3142/path", req.uri.toString())
val resp = if (req.headers["Proxy-authorization"] != "Basic bXl1c2VyOm15cGFzc3dvcmQ=") {
// content cut out
"""
HTTP/1.1 407 Proxy Authentication Required
Server: squid/6.9
Mime-Version: 1.0
Date: Mon, 03 Jun 2024 10:10:42 GMT
Content-Type: text/html;charset=utf-8
Content-Length: 0
X-Squid-Error: ERR_CACHE_ACCESS_DENIED 0
Vary: Accept-Language
Content-Language: en
Proxy-Authenticate: Basic realm="Squid proxy-caching web server"
Cache-Status: localhost
Via: 1.1 localhost (squid/6.9)
Connection: close
""".trimIndent()
} else {
"""
HTTP/1.1 200 OK
Content-Length: 13
Content-Type: text/plain; charset=UTF-8
Date: Mon, 03 Jun 2024 10:10:42 GMT
Cache-Status: localhost;fwd=stale;detail=match
Via: 1.1 localhost (squid/6.9)
Connection: close
Hello, World!""".trimIndent()
}.replace("\n", "\r\n").toByteArray()
output.writeFully(resp, 0, resp.size)
output.flush()
req.close()
}
}
/*
private fun CoroutineScope.launchTestHttpWebServer(port: Int): Job {
return launch(CoroutineName("embedded http web server") + Dispatchers.IO) {
embeddedServer(CIO, port) {
routing {
get("/path") {
call.respondText("Hello, World!")
}
}
}.start()
}
}
*/

View File

@@ -1,15 +1,10 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.util.net
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.use
import com.intellij.testFramework.PlatformTestUtil
import com.intellij.testFramework.junit5.TestApplication
import com.intellij.testFramework.registerExtension
import org.junit.jupiter.api.Test
import java.io.IOException
import java.net.Authenticator
import java.net.InetSocketAddress
import java.net.Proxy
import java.net.ProxySelector
@@ -21,17 +16,12 @@ import kotlin.test.assertFalse
import kotlin.test.assertTrue
@TestApplication
class PlatformProxyTest {
class PlatformProxySelectorTest {
@Test
fun testJdkProxySelectorIsOverriden() {
fun testJdkProxySelectorIsOverridden() {
assertEquals(ProxySelector.getDefault(), JdkProxyProvider.getInstance().proxySelector)
}
@Test
fun testJdkAuthenticatorIsOverriden() {
assertEquals(Authenticator.getDefault(), JdkProxyProvider.getInstance().authenticator)
}
@Test
fun testJdkProxyHonorsProxySettings() {
val proxySelector = JdkProxyProvider.getInstance().proxySelector
@@ -79,6 +69,7 @@ class PlatformProxyTest {
else -> emptyList()
}
}
override fun connectFailed(uri: URI?, sa: SocketAddress?, ioe: IOException?) = Unit
}) {
assertEquals(listOf(Proxy(Proxy.Type.SOCKS, InetSocketAddress.createUnresolved("p1.domain.com", 502))), proxySelector.select(URI.create("http://sub.example.com")))
@@ -145,28 +136,4 @@ class PlatformProxyTest {
assertEquals(NO_PROXY_LIST, proxySelector.select(URI.create("http://sub.example.com")))
}
}
private fun <T> withCustomProxySelector(proxySelector: ProxySelector, body: () -> T): T {
JdkProxyCustomizer.getInstance().customizeProxySelector(proxySelector).use {
return body()
}
}
private fun <T> withProxySettingsOverride(proxySettingsOverrideProvider: ProxySettingsOverrideProvider, body: () -> T): T {
Disposer.newDisposable().use { disposable ->
ApplicationManager.getApplication().registerExtension(ProxySettingsOverrideProvider.EP_NAME, proxySettingsOverrideProvider, disposable)
return body()
}
}
private fun <T> withProxyConfiguration(proxyConf: ProxyConfiguration, body: () -> T): T {
val previous = ProxySettings.getInstance().getProxyConfiguration()
ProxySettings.getInstance().setProxyConfiguration(proxyConf)
assertEquals(ProxySettings.getInstance().getProxyConfiguration(), proxyConf)
try {
return body()
} finally {
ProxySettings.getInstance().setProxyConfiguration(previous)
}
}
}

View File

@@ -0,0 +1,51 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.util.net
import com.intellij.credentialStore.Credentials
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.use
import com.intellij.testFramework.registerExtension
import java.net.Authenticator
import java.net.ProxySelector
import kotlin.test.assertEquals
internal fun <T> withCustomProxySelector(proxySelector: ProxySelector, body: () -> T): T {
JdkProxyCustomizer.getInstance().customizeProxySelector(proxySelector).use {
return body()
}
}
internal fun <T> withProxySettingsOverride(proxySettingsOverrideProvider: ProxySettingsOverrideProvider, body: () -> T): T {
Disposer.newDisposable().use { disposable ->
ApplicationManager.getApplication().registerExtension(ProxySettingsOverrideProvider.EP_NAME, proxySettingsOverrideProvider, disposable)
return body()
}
}
internal fun <T> withProxyConfiguration(proxyConf: ProxyConfiguration, body: () -> T): T {
val previous = ProxySettings.getInstance().getProxyConfiguration()
ProxySettings.getInstance().setProxyConfiguration(proxyConf)
assertEquals(ProxySettings.getInstance().getProxyConfiguration(), proxyConf)
try {
return body()
}
finally {
ProxySettings.getInstance().setProxyConfiguration(previous)
}
}
internal fun <T> withKnownProxyCredentials(host: String, port: Int, credentials: Credentials?, body: () -> T): T {
val store = ProxyCredentialStore.getInstance()
val previousCreds = store.getCredentials(host, port)
val previousRemembered = store.areCredentialsRemembered(host, port)
store.setCredentials(host, port, credentials, false)
assertEquals(store.getCredentials(host, port), credentials)
try {
return body()
} finally {
store.setCredentials(host, port, previousCreds, previousRemembered)
}
}
internal fun createResetPlatformAuthenticator(): Authenticator = IdeProxyAuthenticator(PlatformProxyAuthentication(ProxyCredentialStore.getInstance(), DisabledProxyAuthPromptsManager.getInstance()))