Android:NTLM身份验证,ksoap和持久连接

时间:2013-09-17 22:18:23

标签: java android windows-authentication ksoap2 ntlm

在使用iOS并处理auth挑战而没有太多学习曲线之后,我发现Windows身份验证在Java / Android中的过程要复杂得多。

我尝试了多种不同的方法,所以如果没有太多的方法,我将会找到一个大部分工作的方法。我现在正在使用为NTLM和ksoap创建的类NtlmTransport

我现在已成功通过以下方式进行身份验证:

NtlmTransport httpTransport = new NtlmTransport();
            httpTransport.setCredentials(serverURL, Login.username, Login.password, deviceIp, "DOMAINNAME");
            httpTransport.call(SOAP_ACTION, envelope);

如果您查看NtlmTransport类,您会看到它从setupNtlm()返回以下标题:

  • status line HTTP / 1.1 200 OK
  • 设置缓存控制:private,max-age = 0
  • 设置内容类型:text / html;字符集= UTF-8
  • 设置服务器:Microsoft-IIS / 8.0
  • 安装X-AspNet-Version:4.0.30319
  • 设置Persistent-Auth:true
  • 安装X-Powered-By:ASP.NET
  • 设置日期:2013年9月17日星期二20:57:45 GMT
  • 设置内容长度:11549

" Persistent-Auth:true是我此时关注的主要问题。我很好地获得了SoapObjects并且可以从一个连接获得我需要的数据,但是一旦我尝试再次访问Web服务,这可能是在成功验证后被击中,我可以&# 39;使用HttpTransportSE访问不同的方法:

private void setSomething() {

    xml = null;
    final String SOAP_ACTION = "http://this.ismy.org/AWebServiceMethod";
    final String METHOD_NAME = "AWebServiceMethod";
    final String URL = protocol + "://" + host  + ":" + port + "/WebService.asmx";
    SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
    SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
    envelope.dotNet = true;
    envelope.setOutputSoapObject(request);
    envelope.implicitTypes = true;
    envelope.setAddAdornments(false);

    try
    {
        HttpTransportSE transport = new HttpTransportSE(URL);
        transport.debug = true;
        transport.call(SOAP_ACTION, envelope);
        xml = transport.responseDump.toString();
        Log.d(TAG, xml);
    }
    catch(SocketException ex)
    {
        Log.e("SocketException : " , "Error on setSomething() " + ex.getMessage());
    }
    catch (Exception e)
    {
        Log.e("Exception : " , "Error on setSomething() " + e.getMessage());
    }
}

这一切都可以正常作为AsyncTask的后台任务,然后传递" xml"到XMLPullParser方法。

这里的主要问题是为什么我会得到:

  

setSomething()上的错误未找到身份验证挑战

...

IIS成功验证用户200后,为什么要求我再次进行身份验证?我怎样才能坚持第一次经过身份验证的挑战,以便在WebService.asmx中找到我想要的任何方法?如有必要,需要添加/更改哪些标头才能创建会话?我错过了什么使得整个NTLM流程能够工作并持续存在,而不仅仅是需要通过身份验证挑战的WS方法?

编辑:添加库代码

这是JCIFS from Apache

的链接
public static final class JCIFSEngine implements NTLMEngine {

    private static final int TYPE_1_FLAGS =
            NtlmFlags.NTLMSSP_NEGOTIATE_56 |
                    NtlmFlags.NTLMSSP_NEGOTIATE_128 |
                    NtlmFlags.NTLMSSP_NEGOTIATE_NTLM2 |
                    NtlmFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
                    NtlmFlags.NTLMSSP_REQUEST_TARGET;

    public String generateType1Msg(final String domain, final String workstation)
            throws NTLMEngineException {
        final Type1Message type1Message = new Type1Message(TYPE_1_FLAGS, domain, workstation);
        return jcifs.util.Base64.encode(type1Message.toByteArray());
    }

    public String generateType3Msg(final String username, final String password,
                                   final String domain, final String workstation, final String challenge)
            throws NTLMEngineException {
        Type2Message type2Message;
        try {
            type2Message = new Type2Message(jcifs.util.Base64.decode(challenge));
        } catch (final IOException exception) {
            throw new NTLMEngineException("Invalid NTLM type 2 message", exception);
        }
        final int type2Flags = type2Message.getFlags();
        final int type3Flags = type2Flags
                & (0xffffffff ^ (NtlmFlags.NTLMSSP_TARGET_TYPE_DOMAIN | NtlmFlags.NTLMSSP_TARGET_TYPE_SERVER));
        final Type3Message type3Message = new Type3Message(type2Message, Login.password, "",
                Login.username, deviceIp, type3Flags);

            System.out.println("type3Message: " + type3Message.toByteArray());

        return jcifs.util.Base64.encode(type3Message.toByteArray());
    }
}

" NtlmFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN&#34>造成这个问题?还有另一面我应该为保持活着设置的旗帜吗?此外,我找到了一个很好的资源,可以列出一些NTLM标志以及更多:http://fossies.org/dox/jcifs-1.3.17/interfacejcifs_1_1ntlmssp_1_1NtlmFlags.html

1 个答案:

答案 0 :(得分:2)

我也在努力解决Android的Windows身份验证问题。 我在https://github.com/masconsult/android-ntlm找到了android-ntlm-master。在项目中将此类添加为库。

更改是在NtlmTransport.java类中。我对NtlmTransport类的调用方法进行了更改=>

      public List call(String soapAction, SoapEnvelope envelope,
                        List headers, File outputFile)
        throws IOException, XmlPullParserException {

    HttpResponse resp = null;
    try {
        //setupNtlm(urlString, user, password);  
         DefaultHttpClient httpclient = new DefaultHttpClient();
         httpclient.getAuthSchemes().register("ntlm", new NTLMSchemeFactory());
         httpclient.getCredentialsProvider().setCredentials(            
                new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),               
                new NTCredentials(user, password, "", "")
         );
         HttpPost httpget = new HttpPost(urlString);       
         httpget.addHeader("soapaction",  soapAction);        
         httpget.addHeader("Content-Type", "text/xml; charset=utf-8");
         byte[] requestData = null;
         try {
             requestData = createRequestData(envelope);                 
         } catch (IOException iOException) {
         }
         ByteArrayEntity byteArrayEntity = new ByteArrayEntity(requestData);
         httpget.setEntity(byteArrayEntity);                
         resp = httpclient.execute(httpget); 

         if(resp  == null) {
            System.out.println("Response is null");
         }
         HttpEntity respEntity = resp.getEntity();

         InputStream is = respEntity.getContent();
         if(is == null) {
            System.out.println("InputStream is null");
         }
         parseResponse(envelope, is);

    } catch (Exception ex) {
        // ex.printStackTrace();
    }

    if (resp != null) {
        return Arrays.asList(resp.getAllHeaders());
    } else {
        return null;
    }
}

以下是我打电话的代码:

    SoapObject request = new SoapObject(NAMESPACE, PRODUCT_DETAILS_METHOD_NAME);
    request.addProperty("ListingID", Integer.parseInt(Product_ID));
    NtlmTransport httpTransport = new NtlmTransport();
    httpTransport.setCredentials(URL, USERNAME, PASSWORD, "","");
    SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
    envelope.dotNet = true; 
    envelope.implicitTypes = true;
    envelope.setOutputSoapObject(request);              
    httpTransport.call(PRODUCT_DETAILS_SOAP_ACTION, envelope);
    SoapObject response = (SoapObject) envelope.getResponse();

它对我有用。

您可以在此处找到更多内容:https://suhas1989.wordpress.com/2015/01/28/ntlm-authentication-in-android/