[英]soap webservice client using apache cxf, for ntlm authentication
我想使用CXF开发一个SOAP客户端来连接到SharePoint
。 身份验证方案是NTLM 。
我在一台机器的登录用户(运行SOAP客户端)可以访问SharePoint的情况下被阻止。 CXF soap客户端始终使用登录用户。 我想指定一些其他用户凭据 (而不是登录)。
由于CXF使用in-JDK HttpURLConnection
; 我读到的有关HttpURLConnection
是,当登录用户通过NTLM身份验证时,它会绕过指定的凭据。
代码在CXF 2.7.11版上进行了尝试。
我尝试过的解决方案:
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(".");
问题:
这不适用于上面指定的方案,因为它始终使用登录的凭据。 当我指定无效凭据时,它不会失败。
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
。
我尝试了另一种解决方案是使用sun.net.www.protocol.http.ntlm.NTLMAuthenticationCallback
,绕过登录用户的身份验证,提到这里 。 使用此方法以及上述解决方案#1。 这有效/无效凭据的预期工作,代码绕过登录的凭据:)。 但是当我指定无效凭据时,我没有得到HTTP 401
错误,而是我得到了
无法发送消息,服务器达到最大重试次数20
我试图避免这个解决方案,因为它使用java的内部包,没有办法直接确定HTTP 401
错误。
我能做些什么才能找到完整的解决方案?
试试这个拦截器。 这将避免自动验证。
public class DisableAutomaticNTLMAuthOutInterceptor extends AbstractPhaseInterceptor<Message>
{
private boolean isFieldsAvailable;
private Field tryTransparentNTLMProxyField;
private Field tryTransparentNTLMServerField;
public DisableAutomaticNTLMAuthOutInterceptor() {
super(Phase.PRE_STREAM);
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Void run() {
try {
DisableAutomaticNTLMAuthOutInterceptor.this.tryTransparentNTLMServerField = HttpURLConnection.class.getDeclaredField("tryTransparentNTLMServer");
DisableAutomaticNTLMAuthOutInterceptor.this.tryTransparentNTLMServerField.setAccessible(true);
DisableAutomaticNTLMAuthOutInterceptor.this.tryTransparentNTLMProxyField = HttpURLConnection.class.getDeclaredField("tryTransparentNTLMProxy");
DisableAutomaticNTLMAuthOutInterceptor.this.tryTransparentNTLMProxyField.setAccessible(true);
DisableAutomaticNTLMAuthOutInterceptor.this.isFieldsAvailable = true;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
});
}
@Override
public void handleMessage(final Message message) throws Fault {
if (this.isFieldsAvailable)
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Void run() {
try {
Object httpConnection = message.get("http.connection");
if (httpConnection != null) {
DisableAutomaticNTLMAuthOutInterceptor.this.processHttpConnection(message.get("http.connection"));
}
} catch (Throwable t) {
t.printStackTrace();
}
return null;
}
});
}
private void processHttpConnection(Object httpConnection) throws IllegalArgumentException, IllegalAccessException {
if (HttpURLConnection.class.isAssignableFrom(httpConnection.getClass())) {
tryTransparentNTLMServerField.set(httpConnection, Boolean.FALSE);
tryTransparentNTLMProxyField.set(httpConnection, Boolean.FALSE);
} else {
Field tempField = null;
for (Field field : httpConnection.getClass().getDeclaredFields()) {
if (HttpURLConnection.class.isAssignableFrom(field.getType())) {
field.setAccessible(true);
tempField = field;
break;
}
}
if (tempField != null) {
processHttpConnection(tempField.get(httpConnection));
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.