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

2023-12-07

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

我尝试了多种不同的方法,因此无需过多讨论这些方法,我将采用最有效的方法。我现在使用为 NTLM 和 ksoap 创建的类,名为Ntlm运输

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

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
  • 设置缓存控制:私有,最大年龄=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


我还为 Android 的 Windows 身份验证而苦苦挣扎。 我发现 android-ntlm-masterhttps://github.com/masconsult/android-ntlm。将此类添加为项目中的库。

更改位于 NtlmTransport.java 类中。我进行了更改callNtlmTransport 类的方法 =>

      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/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android:NTLM 身份验证、ksoap 和持久连接 的相关文章

随机推荐