2

在使用 iOS 并在没有太多学习曲线的情况下处理身份验证挑战之后,我发现 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() 返回以下标头:

  • 状态行 HTTP/1.1 200 OK
  • 设置 Cache-Control:private, max-age=0
  • 设置内容类型:text/html;字符集=utf-8
  • 安装服务器:Microsoft-IIS/8.0
  • 设置 X-AspNet-版本:4.0.30319
  • 设置持久身份验证:true
  • 设置 X-Powered-By:ASP.NET
  • 设置日期:2013 年 9 月 17 日星期二 20:57:45 GMT
  • 设置内容长度:11549

“Persistent-Auth:true 是我目前关心的主要问题。我得到 SoapObjects 就好了,可以从那个连接中获取我需要的数据,但是一旦我尝试访问网络再次服务,这大概可以在成功验证后被击中,我无法使用 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 方法?

编辑:添加库代码

这是来自 Apache 的 JCIFS的链接

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”会导致这个问题吗?我应该为保持活动设置另一个标志吗?此外,我还找到了一个很好的资源来获取 NTLM 标志和更多信息:http: //fossies.org/dox/jcifs-1.3.17/interfacejcifs_1_1ntlmssp_1_1NtlmFlags.html

4

1 回答 1

3

我还在为来自 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/

于 2014-12-08T13:35:17.157 回答