การเชื่อมต่อกับเซิร์ฟเวอร์แยกวิเคราะห์บน VPS โดยใช้ https (ใบรับรองที่ทำด้วยตัวเองสำหรับ SSL)

ด้วยเหตุผลบางประการ ผู้ใช้แยกวิเคราะห์ต้องย้ายสภาพแวดล้อม Parse ไปยัง VPS (เป็นกรณีนี้สำหรับคำถามของฉัน) หรือ Heroku, AWS (ไม่ต้องการแพลตฟอร์มเหล่านี้) ฯลฯ มี Parse SDK ใหม่สำหรับ Android (1.13.0) ซึ่งอนุญาตให้เริ่มต้นการเชื่อมต่อโดยใช้อินเทอร์เฟซ Parse ใหม่ดังต่อไปนี้:

Parse.initialize(new Parse.Configuration.Builder(this)
                .applicationId("myAppId")
                .clientKey(null) 
                .addNetworkInterceptor(new ParseLogInterceptor())
                .server("https://VPS_STATIC_IP_ADDRESS/parse/").build());

คำขอประเภทนี้ดำเนินการโดยใช้พอร์ต 443 ไฟล์ตัวเชื่อมต่อ .js (nodejs) ที่เหมาะสมได้รับการแก้ไขแล้ว เพื่อให้พอร์ต 443 เชื่อมต่อกับพอร์ต 1337 (พอร์ตผู้ฟัง) ภายในเครื่อง และใช้งานได้เมื่อเข้าถึง Parse Server ในเบราว์เซอร์ (จากระยะไกล แน่นอน: จาก VPS ภายนอก) ซึ่งคุณสามารถใช้ใบรับรองที่ลงนามด้วยตนเองและไปต่อได้ แต่เมื่อแอป Android (ตัวเรียกใช้งาน) พยายามเชื่อมต่อ จะเชื่อมต่อไม่ได้เนื่องจากใบรับรองที่ลงนามด้วยตนเอง มีความเป็นไปได้จากภายใน Parse SDK ที่จะใช้ใบรับรองที่ลงนามด้วยตนเองหรือไม่

ป.ล. เป็นความจริงหรือไม่ที่มีข้อบกพร่องเกี่ยวกับปัญหานี้ และนี่คือสาเหตุที่เวอร์ชัน 1.13.1 Parse ได้รับการเผยแพร่? ถ้าใช่ จะไปหา jar-library ของเวอร์ชันนี้ได้ที่ไหน?

ขอบคุณ!


person LowLevel    schedule 18.06.2016    source แหล่งที่มา
comment
คุณน่าจะแก้ไขการพิมพ์ผิดในชื่อ...   -  person Croc    schedule 12.07.2016


คำตอบ (1)


ฉันเพิ่งแก้ไขอันนี้ - Parse SDK สำหรับ Android ไม่ได้มาพร้อมกับการสนับสนุนนอกกรอบในใบรับรอง SelfSigned คุณต้องแก้ไขโค้ดด้วยตัวเอง

ขั้นตอนแรก - โค้ดที่เกี่ยวข้องอยู่ใน ParseHttpClient

  public static ParseHttpClient createClient(int socketOperationTimeout,
      SSLSessionCache sslSessionCache) {
    String httpClientLibraryName;
    ParseHttpClient httpClient;
    if (hasOkHttpOnClasspath()) {
      httpClientLibraryName = OKHTTP_NAME;
      httpClient =  new ParseOkHttpClient(socketOperationTimeout, sslSessionCache);
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
      httpClientLibraryName = URLCONNECTION_NAME;
      httpClient =  new ParseURLConnectionHttpClient(socketOperationTimeout, sslSessionCache);
    } else {
      httpClientLibraryName = APACHE_HTTPCLIENT_NAME;
      httpClient =  new ParseApacheHttpClient(socketOperationTimeout, sslSessionCache);
    }
    PLog.i(TAG, "Using " + httpClientLibraryName + " library for networking communication.");
    return httpClient;   }

หากการสนับสนุนเป้าหมายของคุณเป็นเวอร์ชันขั้นสูงกว่า KITKAT - จากนั้นคุณจะต้องเพิ่มในตัวสร้าง ParseURLConnectionHttpClient:

    HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier(){

            public boolean verify(String hostname, SSLSession session) {
                if(hostname.equals("YOUR TARGET SERVER")) {
                    return true;
                }
                return false;
            }});

ในกรณีอื่นๆ (เวอร์ชันเก่า) โค้ดจะตกเป็นของ Apache ฉันไม่สามารถใช้งานได้ ดังนั้นฉันจึงทำสิ่งต่อไปนี้: ฉันเพิ่มไลบรารี okhttp ลงในแอปของฉัน (ใช้เวอร์ชัน 2.4 - อันเดียวกับที่แยกวิเคราะห์ระบุใน build ล่าสุดมีชื่อแพ็คเกจที่แตกต่างกัน) จากนั้นโค้ดจะเข้าสู่เงื่อนไขแรกเนื่องจากจะพบ okhttp บนเส้นทาง คุณควรแทนที่ลำดับ if เงื่อนไขเพื่อให้เกิดขึ้นในเวอร์ชันที่น้อยกว่า KITKAT เท่านั้น

ใน ParseOkHttpClient เพิ่มรหัสใบรับรองที่ลงนามด้วยตนเองต่อไปนี้:

   public void initCert() {
    try {
        Log.i("PARSE","initCert");

        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        String yairCert = "-----BEGIN CERTIFICATE-----\n" +
                YOUR CERTIFICATE HERE
                "-----END CERTIFICATE-----\n";
        InputStream caInput = new ByteArrayInputStream(yairCert.getBytes());
        Certificate ca = null;
        try {
            ca = cf.generateCertificate(caInput);
            System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
        } catch (CertificateException e) {
            e.printStackTrace();
        } finally {
            try {
                caInput.close();
            } catch (IOException e) {
                Log.e("PARSE_BUG","Failure on Cert installing",e);
                e.printStackTrace();
            }
        }

        // Create a KeyStore containing our trusted CAs
        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);

        // Create a TrustManager that trusts the CAs in our KeyStore
        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);

        // Create an SSLContext that uses our TrustManager
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, tmf.getTrustManagers(), null);
        Log.i("PARSE","Initiating Self Signed cert");
        okHttpClient.setSslSocketFactory(context.getSocketFactory());
        try {
            cf = CertificateFactory.getInstance("X.509");
        } catch (CertificateException e) {
            Log.e("PARSE_BUG","Failure on Cert installing",e);
            e.printStackTrace();
        }
    } catch (IOException e) {
        Log.e("PARSE_BUG","Failure on Cert installing",e);
        e.printStackTrace();
    } catch (CertificateException e) {
        Log.e("PARSE_BUG","Failure on Cert installing",e);
        e.printStackTrace();

    } catch (NoSuchAlgorithmException e) {
        Log.e("PARSE_BUG","Failure on Cert installing",e);
        e.printStackTrace();
    } catch (KeyStoreException e) {
        Log.e("PARSE_BUG","Failure on Cert installing",e);
        e.printStackTrace();
    } catch (KeyManagementException e) {
        Log.e("PARSE_BUG","Failure on Cert installing",e);
        e.printStackTrace();
    }

และส่วนสุดท้ายคือการเรียกเมธอดนี้ + การตรวจสอบชื่อโฮสต์ ซึ่งควรจะเกิดขึ้นใน Constructor ด้วยเช่นกัน initCert(); okHttpClient.setHostnameVerifier(ใหม่ HostnameVerifier() { @แทนที่การตรวจสอบบูลีนสาธารณะ (สตริง s, SSLSession sslSession) { if(s.equals("เซิร์ฟเวอร์เป้าหมายของคุณ")) { return true; } return false; } });

แค่นั้นแหละ. สร้าง PARSE ในเครื่องและปรับใช้กับแอปของคุณ และมันจะทำงานได้อย่างมีเสน่ห์

สนุก

person Croc    schedule 11.07.2016