在使用 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