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
  • Setup Cache-Control:private, max-age=0
  • Content-Type:text/html を設定します。文字セット=utf-8
  • セットアップ サーバー:Microsoft-IIS/8.0
  • X-AspNet バージョンのセットアップ:4.0.30319
  • Persistent-Auth:true の設定
  • X-Powered-By:ASP.NET のセットアップ
  • セットアップ日:2013 年 9 月 17 日 (火) 20:57:45 GMT
  • セットアップ コンテンツの長さ:11549

「Persistent-Auth:true は、現時点で私が懸念している主なものです。SoapObjects を問題なく取得しており、その 1 つの接続から必要なデータを取得できますが、Web にアクセスしようとするとすぐにこれはおそらく認証が成功した後にヒットする可能性がありますが、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());
    }
}

これはすべて、「xml」を XMLPullParser メソッドに渡す AsyncTask のバックグラウンド タスクとして問題なく機能します。

ここでの主な質問は、なぜ私が得ているのかということです:

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クラスのcallメソッドを変更しました=>

      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 に答える