我想使用CXF开发一个SOAP客户端来连接SharePoint,身份验证方案是NTLM。但是,我遇到了一个问题:当运行SOAP客户端的机器上已登录的用户拥有访问SharePoint的权限时,CXF SOAP客户端总是使用已登录的用户,而我想指定其他用户凭据(不是已登录的用户)。CXF使用JDK中的HttpURLConnection,在HttpURLConnection中,当已登录的用户经过NTLM身份验证时,指定的凭据将被忽略。这些代码在CXF版本2.7.11上尝试过。
我尝试过的解决方法如下:
2)
我尝试过的解决方法如下:
1)设置通道授权
String username = "user";
String password = "password";
JaxWsProxyfactoryBean factory1 = new JaxWsProxyfactoryBean();
factory1.setServiceClass(WebsSoap.class);
factory1.setAddress(url);
factory1.setUsername(username);
factory1.setPassword(password);
WebsSoap service = (WebsSoap) factory1.create();
Client client = ClientProxy.getClient(service);
HTTPconduit conduit = (HTTPconduit) client.getconduit();
conduit.getAuthorization().setAuthorizationType("NTLM");
conduit.getAuthorization().setUserName(username);
conduit.getAuthorization().setPassword(password);
HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setConnectionTimeout(36000);
httpClientPolicy.setAllowChunking(false);
conduit.setClient(httpClientPolicy);
service.getWeb(".");
问题:
对于上述场景,这种方法不起作用,因为它始终使用已登录的凭据。当我指定无效凭据时,它也不会失败。
2) AsyncHTTPConduit
另一种解决方案是使用AsyncHTTPConduit
,它使用HttpAsyncClient
而不是HttpURLConnection
。这是因为HTTP组件不会绕过指定的凭据,可以忽略已登录的用户(我已经使用HttpClient
测试客户端成功验证了这一点)。
以下是代码片段:
Bus bus = BusFactory.getDefaultBus();
bus.setProperty( "use.async.http.conduit", "true" );
Client client = ClientProxy.getClient( service );
HTTPConduit http = (HTTPConduit)client.getConduit();
if ( http instanceof AsyncHTTPConduit ) {
AsyncHTTPConduit conduit = (AsyncHTTPConduit)http;
DefaultHttpAsyncClient defaultHttpAsyncClient;
try {
defaultHttpAsyncClient = conduit.getHttpAsyncClient();
}
catch ( IOException exception ) {
throw new RuntimeException( exception );
}
defaultHttpAsyncClient.getCredentialsProvider().setCredentials( AuthScope.ANY,
new NTCredentials( "username", "password", "", "domain" ) );
conduit.getClient().setAllowChunking( false );
conduit.getClient().setAutoRedirect( true );
}
问题:
上述代码引发错误:
在传送带上检测到授权循环。
以上代码快照显示了使用现已被弃用的DefaultHttpAsyncClient
,现在应该使用CloseableHttpAsyncClient
。但是,CloseableHttpAsyncClient
没有提供一种方法来指定凭据给一个已经存在的CloseableHttpAsyncClient
对象。不确定如何在此情况下使用CloseableHttpAsyncClient
。
3) 其他解决方案
我尝试的另一种解决方案是使用sun.net.www.protocol.http.ntlm.NTLMAuthenticationCallback
,绕过已登录用户的身份验证,如此处所述。将此方法与上面提到的解决方案#1结合使用。对于有效/无效的凭据,此方法按预期工作,并且代码可以绕过已登录的凭据 :)
但是,当我指定无效凭据时,我没有收到HTTP
401
错误,而是收到无法发送消息,服务器达到最大重试20次
我尝试避免使用此解决方案,因为它使用了Java的内部包,并且没有直接确定HTTP 401
错误的方法。
我该怎么做才能得出一个完整的解决方案?