2012-01-07 31 views
7

私はSharepoint Webサービスにアクセスし、SOAP処理を行うAndroidアプリケーションを開発しています。私はJCIFSのように様々な方法を試しました。AndroidのNTLM認証

ここで私を助けることができますか?私は何日もそれをグーグルで見つけましたが、この問題を抱えている人は誰もがイライラしています。

おかげで、 インドラジット

答えて

5

私はNTLMの専門家ではありませんが、JCIFSライブラリを使用してバックエンドに接続し、ヘッダーを使って手作業で作業することに成功しました。

また、OkHttp 3ライブラリをネットワーク接続に使用していますが、おそらく他のライブラリに自分のコードを適合させることができます。

主なアイデアは、接続するサーバーとネゴシエートする必要があるということです。

ステップ1:

WWW認証をネゴシエート:

WWW認証:

あなたが失敗するだろう第一の時間を接続して、ヘッダ内のいくつかの情報を受信しよう: NTLM

ステップ2:

jcifsライブラリーを使用してタイプ1の鍵(オプションのドメイン&ワークステーション・パラメーターを使用)を生成し、再度接続を試みる必要があります。 あなたは再び失敗したが、いくつかの有用なヘッダの情報が届きます:

WWW認証:very_long_challenge_key NTLMを

ステップ3:あなたがその挑戦とタイプ3のキーを生成する必要が

jcifsライブラリを使用して、key + login + passwordを入力します。その後、接続は成功します!瓶はここで見つけることができます

compile files('libs/jcifs-1.3.18.jar') 
compile 'com.squareup.okhttp3:okhttp:3.4.1' 

は今、いくつかのコードは、あなたのアプリのbuild.gradleファイルにライブラリへの依存関係を追加https://jcifs.samba.org/src/

その後NTLMAuthenticatorクラス

import android.support.annotation.NonNull; 

import java.io.IOException; 
import java.util.List; 

import jcifs.ntlmssp.NtlmFlags; 
import jcifs.ntlmssp.Type1Message; 
import jcifs.ntlmssp.Type2Message; 
import jcifs.ntlmssp.Type3Message; 
import jcifs.util.Base64; 
import okhttp3.Authenticator; 
import okhttp3.Credentials; 
import okhttp3.Request; 
import okhttp3.Response; 
import okhttp3.Route; 

/** 
* Created by Arnaud Guyon on 07.02.17. 
*/ 

public class NTLMAuthenticator implements Authenticator { 

    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; 

    private String mLogin; 
    private String mPassword; 
    private String mDomain; 
    private String mWorkstation; 

    public NTLMAuthenticator(@NonNull String login, @NonNull String password) { 
     this(login, password, "", ""); 
    } 

    public NTLMAuthenticator(@NonNull String login, @NonNull String password, @NonNull String domain, @NonNull String workstation) { 
     mLogin = login; 
     mPassword = password; 
     mDomain = domain; 
     mWorkstation = workstation; 
    } 

    @Override 
    public Request authenticate(Route route, Response response) throws IOException { 

     List<String> authHeaders = response.headers("WWW-Authenticate"); 
     if (authHeaders != null) { 
      boolean negociate = false; 
      boolean ntlm = false; 
      String ntlmValue = null; 
      for (String authHeader : authHeaders) { 
       if (authHeader.equalsIgnoreCase("Negotiate")) { 
        negociate = true; 
       } 
       if (authHeader.equalsIgnoreCase("NTLM")) { 
        ntlm = true; 
       } 
       if (authHeader.startsWith("NTLM ")) { 
        ntlmValue = authHeader.substring(5); 
       } 
      } 

      if (negociate && ntlm) { 
       String type1Msg = generateType1Msg(mDomain, mWorkstation); 
       String header = "NTLM " + type1Msg; 
       return response.request().newBuilder().header("Authorization", header).build(); 
      } else if (ntlmValue != null) { 
       String type3Msg = generateType3Msg(mLogin, mPassword, mDomain, mWorkstation, ntlmValue); 
       String ntlmHeader = "NTLM " + type3Msg; 
       return response.request().newBuilder().header("Authorization", ntlmHeader).build(); 
      } 
     } 

     if (responseCount(response) <= 3) { 
      String credential = Credentials.basic(mLogin, mPassword); 
      return response.request().newBuilder().header("Authorization", credential).build(); 
     } 

     return null; 
    } 

    private String generateType1Msg(@NonNull String domain, @NonNull String workstation) { 
     final Type1Message type1Message = new Type1Message(TYPE_1_FLAGS, domain, workstation); 
     byte[] source = type1Message.toByteArray(); 
     return Base64.encode(source); 
    } 

    private String generateType3Msg(final String login, final String password, final String domain, final String workstation, final String challenge) { 
     Type2Message type2Message; 
     try { 
      byte[] decoded = Base64.decode(challenge); 
      type2Message = new Type2Message(decoded); 
     } catch (final IOException exception) { 
      exception.printStackTrace(); 
      return null; 
     } 
     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, password, domain, 
       login, workstation, type3Flags); 
     return Base64.encode(type3Message.toByteArray()); 
    } 

    private int responseCount(Response response) { 
     int result = 1; 
     while ((response = response.priorResponse()) != null) { 
      result++; 
     } 
     return result; 
    } 

} 

次に、OkHttpClientを作成するときに、この認証ツールを追加します。

OkHttpClient okHttpClient = new OkHttpClient.Builder() 
     .authenticator(new NTLMAuthenticator(login, password)) 
     // .some other init here if necessary 
     .build(); 

そして、いつものようにあなたの要求をしてください。

+0

"いつものようにあなたの要求を行う"ことについて詳しく説明できますか?私はOkHttpに慣れていません –

+1

ここにOkHttpの簡単なサンプルがあります:https://square.github.io/okhttp/#overview –