JAX-WS Sharepoint 401 Unauthorized NTLM

2022-09-04 08:21:58

我尝试通过 JAX-WS 访问 Sharepoint 列表,如此处所述

但是,在运行下面的代码时,我得到:

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 Web 服务时,我遇到了同样的问题,以下是对我有用的方法:

首先,创建身份验证器:

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覆盖传递域名。

我在互联网上看到过多篇帖子,建议使用类似于Marcel Levy在上面的建议使用NTLM身份验证器实例(这是根据Oracle提供的JAVA 6文档定义的方式)。但是,这个解决方案对我不起作用(我正在开发一个独立于任何应用程序服务器逻辑的独立程序)。

我用谷歌搜索并尝试了很多解决这个问题的方法。显然,最简单的代码是使用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 没有使用 NTCredentials 实例配置 HTTP 客户端 (4.3.x) 的有效方法。请参考错误 https://issues.apache.org/jira/browse/CXF-5671


顺便说一句,如果您有一条需要传输的简单消息,只需使用HTTP客户端(我使用4.3.4..不确定早期版本)与NTCredentials Instance。这也为我带来了魔力。示例如下:

    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();

推荐