У меня есть код 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 не поддерживают наличие @
в аутентификаторе для прокси (по крайней мере).