У меня есть код Scala, которому удалось успешно согласовать прокси (NTLM) и получить доступ к Интернету, указав имя пользователя и пароль так:
// Based upon http://rolandtapken.de/blog/2012-04/java-process-httpproxyuser-and-httpproxypassword
Authenticator.setDefault(new Authenticator() {
override protected def getPasswordAuthentication: PasswordAuthentication = {
if (getRequestorType eq RequestorType.PROXY) {
val prot = getRequestingProtocol.toLowerCase
// This allows us to only return a PasswordAuthentication when we have
// all four of the host, port, user and password _and_ the host and
// port match the actual proxy wanting authentication.
for {
host <- Option(System.getProperty(prot + ".proxyHost"))
if getRequestingHost.equalsIgnoreCase(host)
port <- Try(augmentString(System.getProperty(prot + ".proxyPort")).toInt).toOption
if port == getRequestingPort
user <- Option(System.getProperty(prot + ".proxyUser"))
pass <- Option(System.getProperty(prot + ".proxyPassword"))
} yield return new PasswordAuthentication(user, pass.toCharArray)
}
// One of the if-statements failed. No authentication for you!
null
}
})
Однако теперь мне была предложена новая комбинация имени пользователя и пароля, а пароль содержит @. Я пробовал использовать пароль напрямую, избегая его (с помощью \ и \\ в случае необходимости двухуровневого экранирования), url-encoding it (т.е. заменяя @ на %40) и даже HTML-кодирование (@ и @) безрезультатно.
Я знаю, что пароль работает, поскольку он используется в других системах для приложений, отличных от JVM, для доступа к Интернету, устанавливая переменную http_proxy, но она здесь не работает.
Любые идеи?
ИЗМЕНИТЬ
Чтобы попытаться очистить некоторые вещи, я попытался упростить свой код:
Authenticator.setDefault(new Authenticator() {
def urlEncode(str: String): String = {
val res = URLEncoder.encode(str, "UTF-8")
// To confirm it working
println(s"${str} -> ${res}")
res
}
override protected def getPasswordAuthentication: PasswordAuthentication = {
if (getRequestorType eq RequestorType.PROXY) {
return new PasswordAuthentication(urlEncode("username"), urlEncode("[email protected]").toCharArray);
}
null
}
})
Среда, в которой он выполняется, находится в кластере Spark (выполняется с spark-submit) в ящике Linux. Прокси-сервер - это корпоративный NTLM.
Если я использую известную комбинацию имени пользователя и пароля, которая не содержит @, тогда это работает. Если я изменил его на один, содержащий @, тогда он не сработает.
Я попытался сделать val res = str внутри функции urlEncode (в случае, если он не должен быть закодирован в URL), попытался иметь \\@ (с кодировкой URL и без) и ^@ (с и без кодировки URL). Каждый раз я получаю исключение Unable to tunnel through proxy. Proxy returns "HTTP/1.1 407 Proxy Authorization Required".
Я знаю, что имя пользователя и пароль действительны, поскольку они в настоящее время установлены в переменной https_proxy, которая успешно используется curl и т.д.
Поэтому, если тот факт, что прокси-сервер не настроен на работающем сервере Spark, каким-то образом влияет на то, что с ним происходит, мне кажется, что библиотеки JVM не поддерживают наличие @ в аутентификаторе для прокси (по крайней мере).