Android: Uwierzytelnianie NTLM, ksoap i trwałe połączenia
Po pracy z iOS i radzeniu sobie z wyzwaniami uwierzytelniania bez dużej krzywej uczenia się, odkryłem, że Uwierzytelnianie systemu Windows jest znacznie bardziej skomplikowane niż proces w Javie / Androidzie.
Spróbowałem wielu różnych podejść, więc nie wdając się zbytnio w te, przejdę do tego, który działał w przeważającej części. Teraz używam klasy utworzonej dla NTLM i ksoap o nazwie NtlmTransport
Teraz pomyślnie uwierzytelniam się w następujący sposób:
NtlmTransport httpTransport = new NtlmTransport();
httpTransport.setCredentials(serverURL, Login.username, Login.password, deviceIp, "DOMAINNAME");
httpTransport.call(SOAP_ACTION, envelope);
Jeśli spojrzysz na klasę NtlmTransport, zobaczysz, że zwraca następujące nagłówki z setupNtlm ():
status Line HTTP / 1.1 200 OK Konfiguracja kontroli pamięci podręcznej: prywatna, maks. Wiek = 0Setup Content-Type: text / html; charset = utf-8Setup Server: Microsoft-IIS / 8.0Setup X-AspNet-Version: 4.0.30319Setup Persistent-Auth: trueSetup X-Powered-By: ASP.NET Data ustawienia: wt, 17 września 2013 20:57:45 GMTSetup Content-Length: 11549„Trwałe uwierzytelnianie: prawda jest tym, co mnie obecnie niepokoi. Dostaję SoapObjects w porządku i mogę uzyskać potrzebne dane z tego jednego połączenia, ale jak tylko spróbuję uzyskać dostęp do ponownie usługa internetowa, która prawdopodobnie zostanie trafiona po udanym uwierzytelnieniu, nie mogę uzyskać dostępu do innej metody za pomocą 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());
}
}
To wszystko działa dobrze jako zadanie w tle AsyncTask, które następnie przekazuje „xml” do metody XMLPullParser.
Główne pytanie tutaj brzmi: dlaczego otrzymuję:
Błąd na setSomething () Nie znaleziono problemów z uwierzytelnieniem
??
Po tym, jak IIS pomyślnie zweryfikuje użytkownika przy użyciu 200, dlaczego prosi mnie o ponowne uwierzytelnienie? Jak mogę utrzymać to pierwsze uwierzytelnione wyzwanie, aby trafić w dowolną metodę w WebService.asmx? Jakie nagłówki należy dodać / zmienić, aby w razie potrzeby utworzyć sesję? Czego mi brakuje, co sprawia, że cały proces NTLM działa i trwa dłużej niż metoda WS, która musi przejść wyzwania uwierzytelnienia?
EDIT: Dodawanie kodu biblioteki
Oto link doJCIFS z 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());
}
}
Czy więc „NtlmFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN” powoduje ten problem? Czy jest jakaś inna flaga, którą powinienem ustawić dla podtrzymania życia? Znalazłem też świetne źródło listy flag NTLM i nie tylko:http: //fossies.org/dox/jcifs-1.3.17/interfacejcifs_1_1ntlmssp_1_1NtlmFlags.htm