JAX-WS Sharepoint 401 Несанкционированный NTLM
Я пытаюсь получить доступ к списку Sharepoint через JAX-WS, как описано здесь
Однако при запуске кода ниже я получаю:
java.lang.Exception: Exception. See stacktrace.com.sun.xml.internal.ws.client.ClientTransportException: The server sent HTTP status code 401: Unauthorized
Sharepoint требует аутентификации NTLM. В чем может быть проблема? Большое спасибо!
public static ListsSoap sharePointListsAuth(String userName, String password) throws Exception {
ListsSoap port = null;
if (userName != null && password != null) {
try {
Lists service = new Lists();
port = service.getListsSoap();
System.out.println("Web Service Auth Username: " + userName);
((BindingProvider) port).getRequestContext().put(BindingProvider.USERNAME_PROPERTY, userName);
((BindingProvider) port).getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, password);
} catch (Exception e) {
throw new Exception("Error: " + e.toString());
}
} else {
throw new Exception("Couldn't authenticate: Invalid connection details given.");
}
return port;
}
Ответы
Ответ 1
Я столкнулся с такой же проблемой при подключении с JAX-WS к веб-сервисам Exchange, и вот что сработало для меня:
Сначала создайте аутентификатор:
import java.net.Authenticator;
import java.net.PasswordAuthentication;
public class NtlmAuthenticator extends Authenticator {
private final String username;
private final char[] password;
public NtlmAuthenticator(final String username, final String password) {
super();
this.username = new String(username);
this.password = password.toCharArray();
}
@Override
public PasswordAuthentication getPasswordAuthentication() {
return (new PasswordAuthentication (username, password));
}
}
В вашем приложении настройте аутентификатор по умолчанию:
String username = "DOMAIN\\USERNAME";
String password = "PASSWORD"
NtlmAuthenticator authenticator = new NtlmAuthenticator(username, password);
Authenticator.setDefault(authenticator);
Обратите внимание, что я использую метод # 2 для указания домена, как описано в документации Java.
Ответ 2
Основываясь на моих знаниях, переопределение параметров BindingProvider НЕ задает требуемое имя пользователя и пароль. Простейший способ доказать это заключается в том, что невозможно передать доменное имя через переопределение BP.
Я видел несколько сообщений в Интернете, предлагая способ, аналогичный предложению Марселя Леви в приведенном выше примере, использовать экземпляр аутентификации NTLM (такой способ определяется как документация JAVA 6, доступная из Oracle). Но это решение не сработало для меня (я разрабатывал автономную программу независимо от любой логики сервера приложений).
Я googled и попробовал много решений для этой проблемы. По-видимому, самый простой код, который работал, как показано ниже, использует библиотеку JCIFS
//Set the jcifs properties
jcifs.Config.setProperty("jcifs.smb.client.domain", "domainname");
jcifs.Config.setProperty("jcifs.netbios.wins", "xxx.xxx.xxx.xxx");
jcifs.Config.setProperty("jcifs.smb.client.soTimeout", "300000"); // 5 minutes
jcifs.Config.setProperty("jcifs.netbios.cachePolicy", "1200"); // 20 minutes
jcifs.Config.setProperty("jcifs.smb.client.username", "username");
jcifs.Config.setProperty("jcifs.smb.client.password", "password");
//Register the jcifs URL handler to enable NTLM
jcifs.Config.registerSmbURLHandler();
По-видимому, CXF 3.0 не имеет действительного способа настройки HTTP-клиента (4.3.x) с экземпляром NTCredentials. Пожалуйста, обратитесь к ошибке https://issues.apache.org/jira/browse/CXF-5671
Кстати, если у вас есть простое сообщение, которое нужно передать, просто используйте HTTP Client (я работал с 4.3.4.. не уверен в более ранних версиях) с экземпляром NTCredentials. Это тоже помогло мне. Образец выглядит так:
final NTCredentials ntCredentials = new NTCredentials("username", "Passworrd","destination", "domain");
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY, ntCredentials);
CloseableHttpClient httpclient = HttpClientBuilder.create()
.setDefaultCredentialsProvider(credsProvider)
.build();
Ответ 3
Насколько я знаю, вы не можете выполнять аутентификацию NTLM через BindingProvider.
Если вы знакомы с фреймворком Spring, вы можете использовать Spring-WS. Spring -WS поддерживает транспорт с Apache HttpClient 4.x через класс HttpComponentsMessageSender. Apache HttpClient 4.x имеет хорошую поддержку для проверки подлинности NTLM. Вы можете использовать классы JAX-WS, созданные с помощью инструмента wsimport, в качестве аргумента для marshalSendAndReceive.