简体   繁体   English

客户端无法使用自签名证书连接到REST API

[英]Client can't connect to REST API using self-signed certificate

I'm trying to connect my Android client to TOMCAT REST API. 我正在尝试将我的Android客户端连接到TOMCAT REST API。 Everything works fine as long as HTTP is used. 只要使用HTTP,一切正常。 Unfortunately HTTPS has to be implemented. 不幸的是,必须实施HTTPS。

After server side HTTPS implementation server looks fine (server is using self-signed certificate. Created using JAVA KEYTOOL). 在服务器端HTTPS实现服务器看起来正常之后(服务器正在使用自签名证书。使用JAVA KEYTOOL创建)。

Unfortunately I can't connect Android client due to some reason. 不幸的是,由于某些原因,我无法连接Android客户端。

At first the error was: "Trust anchor for certification path not found". 最初的错误是:“找不到证书路径的信任锚”。 I tried use Android Developer guides but I had problem with access to .crt / cer file using "AsyncTask". 我尝试使用Android Developer指南,但是使用“ AsyncTask”访问.crt / cer文件时遇到问题。 So I decided that "ALLOW_ALL_HOSTNAME_VERIFIER" will work for the moment. 因此,我决定暂时可以使用“ ALLOW_ALL_HOSTNAME_VERIFIER”。 HTTPS CLIENT class look like this: HTTPS CLIENT类如下所示:

(commented part is HTTP version) (注释部分为HTTP版本)

import android.util.Base64;
import android.os.Build;
import android.annotation.TargetApi;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.SingleClientConnManager;

import android.os.AsyncTask;
import android.util.Log;

public class UrlUtil extends AsyncTask<String, Void, String> {

    @TargetApi(Build.VERSION_CODES.O_MR1)
    @Override
    protected String doInBackground(String... strings) {

        StringBuilder jsonResult = new StringBuilder();
        String message = null;

        try {
            //setup SSL
            HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
            DefaultHttpClient client = new DefaultHttpClient();
            SchemeRegistry registry = new SchemeRegistry();
            SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
            socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
            registry.register(new Scheme("https", socketFactory, 443));
            SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry);
            DefaultHttpClient httpClient = new DefaultHttpClient(mgr, client.getParams());
            // Set verifier
            HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);

            String cred = "xxxx:yyyy";
            String encoding = Base64.encodeToString(cred.getBytes(), Base64.DEFAULT);
            // Example send http request
            HttpPost httpPost = new HttpPost(strings[0]);
            httpPost.setHeader("Authorization", "Basic " + encoding);
            HttpResponse response = httpClient.execute(httpPost);
            InputStream is = response.getEntity().getContent(); //outputs an inputstream

            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            StringBuilder sb = new StringBuilder();
            String line = null;

            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }

            is.close();
            Log.d("httpstest",sb.toString());
            return sb.toString();

        } catch (IOException e) {  }
        return null;

//            try {
//                URL url = new URL(strings[0]);
//
//                Authenticator.setDefault(new Authenticator() {
//                    protected PasswordAuthentication getPasswordAuthentication() {
//                        return new PasswordAuthentication("user", "userPass".toCharArray());
//                    }
//                });
//                HttpURLConnection connection = (HttpURLConnection) new URL(url.toString()).openConnection();
//                connection.setUseCaches(false);
//                connection.connect();
//                InputStream inputStream = connection.getInputStream();
//                InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
//                BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
//                message = org.apache.commons.io.IOUtils.toString(bufferedReader);
//
//            } catch (MalformedURLException e) {
//                e.printStackTrace();
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//
//
//
//        } catch (Exception e) {  }
//
//        return message;
    }
}

Error info: 错误信息:

07/09 18:27:29: Launching app
$ adb install-multiple -r -t -p org.pilat.eko_raporty20 C:\Users\Pilat\Desktop\AndroidStudioProjects\ekoraporty20\app\build\intermediates\split-apk\debug\slices\slice_9.apk 
Split APKs installed in 2 s 675 ms
$ adb shell am start -n "org.pilat.eko_raporty20/org.pilat.eko_raporty20.activity.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Client not ready yet..Waiting for process to come online
Connected to process 944 on device lenovo-lenovo_p2a42-ZY223TJMN2
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
D/LenovoAppIconTheme: ExtraResources;cleanCachedIcon;clear cache..
W/ActivityThread: Application org.pilat.eko_raporty20 can be debugged on port 8100...
W/System: ClassLoader referenced unknown path: /data/app/org.pilat.eko_raporty20-1/lib/arm64
I/InstantRun: starting instant run server: is main process
I/Typeface: setThemeFont(): sThemeFontPath = ,fontPath = 
W/Typeface: setThemeFont(): FontPath Not Changed!
W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable
V/BoostFramework: mAcquireFunc method = public int com.qualcomm.qti.Performance.perfLockAcquire(int,int[])
V/BoostFramework: mReleaseFunc method = public int com.qualcomm.qti.Performance.perfLockRelease()
    mAcquireTouchFunc method = public int com.qualcomm.qti.Performance.perfLockAcquireTouch(android.view.MotionEvent,android.util.DisplayMetrics,int,int[])
    mIOPStart method = public int com.qualcomm.qti.Performance.perfIOPrefetchStart(int,java.lang.String)
    mIOPStop method = public int com.qualcomm.qti.Performance.perfIOPrefetchStop()
V/BoostFramework: BoostFramework() : mPerf = com.qualcomm.qti.Performance@e5acceb
    BoostFramework() : mPerf = com.qualcomm.qti.Performance@fdb0a48
D/NetworkSecurityConfig: No Network Security Config specified, using platform default
I/DpmTcmClient: RegisterTcmMonitor from: org.apache.http.impl.conn.TcmIdleTimerMonitor
I/System.out: [socket][0] connection /"ip":"port";LocalPort=-1(0)
I/System.out: [socket][/100.82.169.168:35907] connected
I/System.out: close [socket][/100.82.169.168:35907]
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
    Process: org.pilat.eko_raporty20, PID: 944
    java.lang.RuntimeException: Unable to start activity ComponentInfo{org.pilat.eko_raporty20/org.pilat.eko_raporty20.activity.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.String.toString()' on a null object reference
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2659)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2720)
        at android.app.ActivityThread.-wrap12(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1466)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6111)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.String.toString()' on a null object reference
        at org.pilat.eko_raporty20.activity.MainActivity.onCreate(MainActivity.java:126)
        at android.app.Activity.performCreate(Activity.java:6734)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2612)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2720) 
        at android.app.ActivityThread.-wrap12(ActivityThread.java) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1466) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:154) 
        at android.app.ActivityThread.main(ActivityThread.java:6111) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) 
Application terminated.
  1. Why I get no data from server? 为什么我没有从服务器获取数据?

    (I don't understend: I/System.out: [socket][0] connection /"ip":"port";LocalPort=-1(0)) (我不明白:I / System.out:[socket] [0]连接/“ ip”:“端口”; LocalPort = -1(0))

  2. How to do it the right way? 如何正确地做呢?

    The preferred option is to make it work using self-signed cert if there is no other option it can work accepting all certs. 如果没有其他选择可以接受所有证书,则首选选项是使其使用自签名证书来工作。

Thanks in advance :-) 提前致谢 :-)

Result of two days of internet searching and trying many options is to use Android Developer option: https://developer.android.com/training/articles/security-ssl Than you will have problem with adding cert file. 经过两天的互联网搜索并尝试了许多选项的结果是使用Android Developer选项: https : //developer.android.com/training/articles/security-ssl比起添加证书文件,您将遇到问题。 Android will not see it. Android将看不到它。 You can add certificate by adding new constructor to your AsyncTask class. 您可以通过将新的构造函数添加到AsyncTask类来添加证书。 It should look something like this: 它看起来应该像这样:

    Public class UrlUtil extends AsyncTask<String, String, String> {

        private Context context;

        public UrlUtil (Context myContext) {
            this.context = myContext;
        }

        public UrlUtil () {};

        @TargetApi(Build.VERSION_CODES.O_MR1)
        @Override
        protected String doInBackground(String... params) {...}

...}

You execute AsyncTask like this: 您可以像这样执行AsyncTask:

new UrlUtil(this).execute("https://myserver:myport/restofpath").get()

Where "this" is ACTIVITY context. 其中“ this”是ACTIVITY上下文。

Certificate file should be placed in ASSETS folder. 证书文件应放在ASSETS文件夹中。 If you don't have one in your project the easiest way to add one is to right click on your project NEW / FOLDER / ASSETS FOLDER. 如果您的项目中没有一个,最简单的添加方法是右键单击项目的“新建” /“文件夹” /“资产文件夹”。 To add file to ASSETS FOLDER you can't simply use Drag&Drop. 要将文件添加到“资产文件夹”,您不能简单地使用“拖放”。 You have to find folder in your OS explorer and place it into the folder. 您必须在OS资源管理器中找到文件夹并将其放入该文件夹中。

I hope you will find it useful :-) 我希望您会发现它有用:-)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM