axis2客户端中的NTLM身份验证返回错误401

时间:2012-05-10 07:11:25

标签: axis2

我使用axis2创建客户端代码并使用NTLM身份验证访问wcf webservice。我的客户端代码是

    Service1Stub stub = new Service1Stub();             
    Options options = stub._getServiceClient().getOptions();    
    HttpTransportProperties.Authenticator   auth = new HttpTransportProperties.Authenticator();
    auth.setUsername("administrator");
    auth.setPassword("passwrd");
    auth.setHost("172.16.12.25"); 
    auth.setDomain("MY-PC");        
    List<String> authSchemes = new ArrayList<String>();         
    authSchemes.add(HttpTransportProperties.Authenticator.NTLM);        
    auth.setAuthSchemes(authSchemes); 

    options.setProperty(HTTPConstants.AUTHENTICATE, auth); 
    options.setProperty(HTTPConstants.CHUNKED, Boolean.FALSE); 
    stub._getServiceClient().setOptions(options); 

当我运行客户端代码时,它返回以下错误

    org.apache.axis2.AxisFault: Transport error: 401 Error: Unauthorized
        at org.apache.axis2.transport.http.HTTPSender.handleResponse(HTTPSender.java:310)
        at org.apache.axis2.transport.http.HTTPSender.sendViaPost(HTTPSender.java:194)
        at org.apache.axis2.transport.http.HTTPSender.send(HTTPSender.java:75)
        at org.apache.axis2.transport.http.CommonsHTTPTransportSender.writeMessageWithCommons(CommonsHTTPTransportSender.java:404)
        at org.apache.axis2.transport.http.CommonsHTTPTransportSender.invoke(CommonsHTTPTransportSender.java:231)
        at org.apache.axis2.engine.AxisEngine.send(AxisEngine.java:443)
        at org.apache.axis2.description.OutInAxisOperationClient.send(OutInAxisOperation.java:406)
        at org.apache.axis2.description.OutInAxisOperationClient.executeImpl(OutInAxisOperation.java:229)
        at org.apache.axis2.client.OperationClient.execute(OperationClient.java:165)
        at org.tempuri.Service1Stub.welcomeData(Service1Stub.java:473)
        at ws.client.Client.myservice(Client.java:159)
        at ws.client.Client.main(Client.java:50)

我的标题日志是

     >> "POST /Service1/Service1.svc HTTP/1.1[\r][\n]"
     >> "Content-Type: text/xml; charset=UTF-8[\r][\n]"
     >> "SOAPAction: "http://tempuri.org/IService1/WelcomeData"[\r][\n]"
     >> "User-Agent: Axis2[\r][\n]"
     >> "Content-Length: 278[\r][\n]"
     >> "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGMAAAAAAAAAewAAAAkACQBAAAAADQANAEkAAAANAA0AVgAAAAAAAAB7AAAABlIAAFZJTk9USC1QQ0FETUlOSVNUUkFUT1IxNzIuMTYuMTIuMjQ11kmkEIwyUVitHBvTPwhExpcylZ9vkdwd[\r][\n]"
     >> "Host: 172.16.12.25[\r][\n]"
     >> "[\r][\n]"
     >> "<?xml version='1.0' encoding='UTF-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><ns1:WelcomeData xmlns:ns1="http://tempuri.org/"><ns1:helloservice>Hello Servie</ns1:helloservice></ns1:WelcomeData></soapenv:Body></soapenv:Envelope>"
     << "HTTP/1.1 401 Unauthorized[\r][\n]"
     << "HTTP/1.1 401 Unauthorized[\r][\n]"
     << "Content-Type: text/html[\r][\n]"
     << "Server: Microsoft-IIS/7.5[\r][\n]"
     << "WWW-Authenticate: NTLM[\r][\n]"
     << "X-Powered-By: ASP.NET[\r][\n]"
     << "Date: Thu, 10 May 2012 19:30:20 GMT[\r][\n]"
     << "Content-Length: 1293[\r][\n]"
     << "[\r][\n]"
     << "<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">[\r][\n]"
     << "<html xmlns="http://www.w3.org/1999/xhtml">[\r][\n]"
     << "<head>[\r][\n]"
     << "<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>[\r][\n]"
     << "<title>401 - Unauthorized: Access is denied due to invalid credentials.</title>[\r][\n]"
     << "<style type="text/css">[\r][\n]"
     << "<!--[\r][\n]"
     << "body{margin:0;font-size:.7em;font-family:Verdana, Arial, Helvetica, sans-serif;background:#EEEEEE;}[\r][\n]"
     << "fieldset{padding:0 15px 10px 15px;} [\r][\n]"
     << "h1{font-size:2.4em;margin:0;color:#FFF;}[\r][\n]"
     << "h2{font-size:1.7em;margin:0;color:#CC0000;} [\r][\n]"
     << "h3{font-size:1.2em;margin:10px 0 0 0;color:#000000;} [\r][\n]"
     << "#header{width:96%;margin:0 0 0 0;padding:6px 2% 6px 2%;font-family:"trebuchet MS", Verdana, sans-serif;color:#FFF;[\r][\n]"
     << "background-color:#555555;}[\r][\n]"
     << "#content{margin:0 0 0 2%;position:relative;}[\r][\n]"
     << ".content-container{background:#FFF;width:96%;margin-top:8px;padding:10px;position:relative;}[\r][\n]"
     << "-->[\r][\n]"
     << "</style>[\r][\n]"
     << "</head>[\r][\n]"
     << "<body>[\r][\n]"
     << "<div id="header"><h1>Server Error</h1></div>[\r][\n]"
     << "<div id="content">[\r][\n]"
     << " <div cla"
     << "ss="content-container"><fieldset>[\r][\n]"
     << "  <h2>401 - Unauthorized: Access is denied due to invalid credentials.</h2>[\r][\n]"
     << "  <h3>You do not have permission to view this directory or page using the credentials that you supplied.</h3>[\r][\n]"
     << " </fieldset></div>[\r][\n]"
     << "</div>[\r][\n]"
     << "</body>[\r][\n]"
     << "</html>[\r][\n]

我不知道我犯了什么错误。

4 个答案:

答案 0 :(得分:1)

据我所知,Axis2 1.6的标准版本仍然使用HTTPClient 3.1和NTLMv1,大多数Windows服务器默认禁用它们。更改此设置需要修补Axis2或更改服务器上的注册表设置。

这是一个开发线程的链接,其中包含最近25-05-2012的补丁:
https://issues.apache.org/jira/browse/AXIS2-4318

答案 1 :(得分:1)

不确定您是否已找到通过NTLM身份验证访问WCF的方法..但这是我为解决此问题所做的工作..

HttpClient不支持NTLM v2因此我使用JCIFS库返回NTLM v1,2,3消息类型,如本网站所述

http://devsac.blogspot.com/2010/10/supoprt-for-ntlmv2-with-apache.html

我刚刚使用上述网站上的JCIFS_NTLMScheme.java文件注册了auth方案,它确实有效!!!!

示例客户端:

    List authSchema = new ArrayList();
    AuthPolicy.registerAuthScheme(AuthPolicy.NTLM, org.tempuri.JCIFS_NTLMScheme.class);
    HttpTransportProperties.Authenticator auth = new HttpTransportProperties.Authenticator();
    auth.setUsername("");
    auth.setPassword("");
    auth.setDomain("");
    auth.setHost("");
    auth.setPort();
    List authPrefs = new ArrayList(1);
    authPrefs.add(AuthPolicy.NTLM);
    auth.setAuthSchemes(authPrefs);
    stub._getServiceClient().getOptions().setProperty(org.apache.axis2.transport.http.HTTPConstants.AUTHENTICATE, auth); 

答案 2 :(得分:0)

正如@WLPhoenix指出的那样,Axis2使用旧的Apache Commons HTTP,它只支持旧的反向工程NTLM实现。在新的Apache HTTPComponents 4.2.3中,为新的,公开记录的NTLM标准添加了支持,该标准适用于较新版本的Windows Server和IIS (source)

这是一种使用自定义Apache Commons HTTP AuthScheme向新的Apache HTTPComponents 4 NTLMScheme反向移植以在Axis2中使用的方法。

public class BackportedNTLMScheme extends org.apache.http.impl.auth.NTLMScheme implements org.apache.commons.httpclient.auth.AuthScheme {

    @Override
    public String authenticate(final Credentials credentials, final HttpMethod method) throws AuthenticationException {
        org.apache.commons.httpclient.NTCredentials oldCredentials;
        try {
            oldCredentials = (org.apache.commons.httpclient.NTCredentials) credentials;
        } catch (final ClassCastException e) {
            throw new InvalidCredentialsException(
                    "Credentials cannot be used for NTLM authentication: " 
                    + credentials.getClass().getName());
        }
        final org.apache.http.auth.Credentials adaptedCredentials = new NTCredentials(oldCredentials.getUserName(), oldCredentials.getPassword(), oldCredentials.getHost(), oldCredentials.getDomain());

        try {
            final Header header = super.authenticate(adaptedCredentials, null);
            return header.getValue();
        } catch (final org.apache.http.auth.AuthenticationException e) {
            throw new AuthenticationException("AuthenticationException", e);
        }
    }

    @Override
    public void processChallenge(final String challenge) throws MalformedChallengeException {
        final String s = AuthChallengeParser.extractScheme(challenge);
        if (!s.equalsIgnoreCase(getSchemeName())) {
            throw new MalformedChallengeException("Invalid NTLM challenge: " + challenge);
        }
        int challengeIdx = challenge.indexOf(' ');
        final CharArrayBuffer challengeBuffer;
        if(challengeIdx != -1){
            challengeBuffer = new CharArrayBuffer(challenge.length());
            challengeBuffer.append(challenge);
        } else {
            challengeBuffer = new CharArrayBuffer(0);
            challengeIdx = 0;
        }
        try {
            parseChallenge(challengeBuffer, challengeIdx, challengeBuffer.length());
        } catch (final org.apache.http.auth.MalformedChallengeException e) {
            throw new MalformedChallengeException("MalformedChallengeException", e);
        }
    }

    @Override
    @Deprecated
    public String getID() {
        throw new RuntimeException("deprecated BackportedNTLMScheme.getID()");
    }


    @Override
    @Deprecated
    public String authenticate(final Credentials credentials, final String method, final String uri) throws AuthenticationException {
        throw new RuntimeException("deprecated BackportedNTLMScheme.authenticate(Credentials, String, String)");
    }
}

用法

// given a stubbed AXIS SOAP client called MyAxisClient:
MyAxisClientStub myAxisClient = new MyAxisClientStub();
ServiceClient serviceClient = myAxisClient._getServiceClient();

// use new NTLM
AuthPolicy.registerAuthScheme(AuthPolicy.NTLM, BackportedNTLMScheme.class);
Authenticator authenticator = new Authenticator();
authenticator.setAuthSchemes(Arrays.asList(AuthPolicy.NTLM));
authenticator.setDomain("my-auth-domain");
authenticator.setHost("my-auth-host");
authenticator.setUsername("my-username");
authenticator.setPassword("my-password");
serviceClient.getOptions().setProperty(HTTPConstants.AUTHENTICATE, authenticator);

//call MyAxisClient methods

我在Windows Server 2008 R2上的IIS 7.5上进行了测试。

答案 3 :(得分:0)

直到同事发现修复了 401 Unauthorized 的问题,我才能让它工作。

import org.apache.commons.httpclient.auth.CredentialsNotAvailableException;
import org.apache.commons.httpclient.auth.CredentialsProvider;
import org.apache.commons.httpclient.params.DefaultHttpParams;
import org.apache.commons.httpclient.NTCredentials;

final NTCredentials credentials = new NTCredentials(username, password, host, domain);    
final CredentialsProvider myCredentialsProvider = new CredentialsProvider() {
        public Credentials getCredentials(final AuthScheme scheme, final String host, int port, boolean proxy) throws CredentialsNotAvailableException {
            return credentials;
        }
    };

    DefaultHttpParams.getDefaultParams().setParameter("http.authentication.credential-provider", myCredentialsProvider);