Якоря доверия не найдены только на устройстве, но работают на эмуляторе?

Все в названии, я не понимаю, почему мой код работает в эмуляторе, а не на моем устройстве. Он выдает исключение «якоря доверия не найдены»! Как это возможно? Я пробовал реализацию okhttp.builder о trustManager, но все же... Помогите пожалуйста!!

Вот мой класс:

public abstract class NewsFragment extends Fragment {

    private static final String TAAG = NewsFragment.class.getSimpleName();
    protected ItemAdapter mArticleAdapter;
    protected RecyclerView mRecyclerView;
    protected NewsFragment.OnNewSelectedInterface mListener;
    protected ItemAdapter.OnNewsInsertedInterface mListener2;
    protected RecyclerView.LayoutManager mManager;
    protected SwipeRefreshLayout mSwipeRefreshLayout;

    public static final String KEY_LIST = "key_list";

    public interface OnNewSelectedInterface {
        void onListNewSelected(int index, ArrayList<Article> articles);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {

        setHasOptionsMenu(true);

        View view = inflater.inflate(R.layout.list_present_news, container, false);

        mListener = (NewsFragment.OnNewSelectedInterface) getActivity();
        mListener2 = (ItemAdapter.OnNewsInsertedInterface) getActivity();
        mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipeContainer);
        mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerview);
        mManager = new LinearLayoutManager(getActivity());
        mArticleAdapter = new ItemAdapter(getActivity(), new ArrayList<>(), mListener, mListener2);

        if (!isNetworkAvailable()) alertUserAboutError();

        mRecyclerView.setAdapter(mArticleAdapter);
        mRecyclerView.setLayoutManager(mManager);

        mSwipeRefreshLayout.setRefreshing(true);
        new Downloader().execute(getUrl());
        //new Downloader().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, getUrl());

        refreshData();

        setDividerRecyclerView();

        return view;
    }

    private void setDividerRecyclerView() {
        DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView
                .getContext(), DividerItemDecoration.VERTICAL);
        mRecyclerView.addItemDecoration(dividerItemDecoration);
    }

    private void alertUserAboutError() {
        AlertDialogFragment alertDialogFragment = new AlertDialogFragment();
        alertDialogFragment.show(getActivity().getFragmentManager(), "error_dialog");
    }

    protected abstract String[] getUrl();

    private boolean isNetworkAvailable() {
        ConnectivityManager manager = (ConnectivityManager)
                getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = manager.getActiveNetworkInfo();
        boolean isAvailable = false;
        if (networkInfo != null && networkInfo.isConnected()) {
            isAvailable = true;
        }
        return isAvailable;
    }

    private void refreshData() {
        mSwipeRefreshLayout.setOnRefreshListener(() -> {
            mArticleAdapter.clear();
            new Downloader().execute(getUrl());
        });

        mSwipeRefreshLayout.setColorSchemeResources(
                android.R.color.holo_orange_light,
                android.R.color.holo_red_light);
    }

    private class Downloader extends AsyncTask<String, Void, ArrayList<Article>> {

        ArrayList<Article> mArticleArrayList = new ArrayList<>();
            OkHttpClient mClient = new OkHttpClient();


        @Override
        protected ArrayList<Article> doInBackground(String... strings) {

            for (String aMUrl : getUrl()) {
                Request mRequest = new Request.Builder().url(aMUrl).build();
                try {
                    Response response = mClient.newCall(mRequest).execute();
                    try {
                        if (response.isSuccessful()) {
                            String json = response.body().string();
                            mArticleArrayList = getMultipleUrls(json);
                        }
                    } catch (IOException | JSONException e) {
                        e.printStackTrace();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return mArticleArrayList;
        }

        @Override
        protected void onPostExecute(ArrayList<Article> articles) {
            mArticleAdapter.addAll(articles);
            mSwipeRefreshLayout.setRefreshing(false);
            Log.v(TAAG, String.valueOf(mArticleAdapter.getItemCount()));
        }

        private ArrayList<Article> getMultipleUrls(String jsonData) throws JSONException {

            if (mArticleArrayList == null || mArticleArrayList.size() == 0) {
                mArticleArrayList = getArticleForecast(jsonData);
            } else {
                mArticleArrayList.addAll(getArticleForecast(jsonData));
            }

            return mArticleArrayList;
        }

        private ArrayList<Article> getArticleForecast(String jsonData) throws JSONException {
            JSONObject forecast = new JSONObject(jsonData);
            JSONArray articles = forecast.getJSONArray("articles");

            ArrayList<Article> listArticles = new ArrayList<>(articles.length());

            for (int i = 0; i < articles.length(); i++) {
                JSONObject jsonArticle = articles.getJSONObject(i);
                Article article = new Article();

                String urlImage = jsonArticle.getString("urlToImage");

                article.setTitle(jsonArticle.getString("title"));
                article.setDescription(jsonArticle.getString("description"));
                article.setImageView(urlImage);
                article.setArticleUrl(jsonArticle.getString("url"));
                article.setUrlToImage(jsonArticle.getString("urlToImage"));

                listArticles.add(i, article);
            }

            return listArticles;
        }
    }
}

А вот лог:

05-04 23:39:01.382 9856-9997/com.silho.ideo.knewsproject W/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
05-04 23:39:01.382 9856-9997/com.silho.ideo.knewsproject W/System.err:     at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:306)
05-04 23:39:01.382 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:242)
05-04 23:39:01.382 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:200)
05-04 23:39:01.382 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.connection.RealConnection.buildConnection(RealConnection.java:174)
05-04 23:39:01.382 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:114)
05-04 23:39:01.382 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:196)
05-04 23:39:01.382 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:132)
05-04 23:39:01.382 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:101)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:179)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at okhttp3.RealCall.execute(RealCall.java:63)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at com.silho.ideo.knewsproject.Fragments.PresentNews.NewsFragment$Downloader.doInBackground(NewsFragment.java:170)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at com.silho.ideo.knewsproject.Fragments.PresentNews.NewsFragment$Downloader.doInBackground(NewsFragment.java:143)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at android.os.AsyncTask$2.call(AsyncTask.java:288)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
05-04 23:39:01.383 9856-9997/com.silho.ideo.knewsproject W/System.err:     at java.lang.Thread.run(Thread.java:818)

Я также нашел это на сайте okhttp, но он также не работает:

public OkHttpClient.Builder sslSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager) Задает фабрику сокетов и диспетчер доверия, используемые для защиты соединений HTTPS. Если не установлено, будут использоваться системные значения по умолчанию. Большинство приложений не должны вызывать этот метод, а вместо этого использовать системные значения по умолчанию. Эти классы включают в себя специальные оптимизации, которые могут быть потеряны, если реализации декорированы.

При необходимости вы можете самостоятельно создать и настроить значения по умолчанию с помощью следующего кода:

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
       TrustManagerFactory.getDefaultAlgorithm());
   trustManagerFactory.init((KeyStore) null);
   TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
   if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
     throw new IllegalStateException("Unexpected default trust managers:"
         + Arrays.toString(trustManagers));
   }
   X509TrustManager trustManager = (X509TrustManager) trustManagers[0];

   SSLContext sslContext = SSLContext.getInstance("TLS");
   sslContext.init(null, new TrustManager[] { trustManager }, null);
   SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

   OkHttpClient client = new OkHttpClient.Builder()
       .sslSocketFactory(sslSocketFactory, trustManager);
       .build();

person samuel zaffran    schedule 04.05.2017    source источник


Ответы (1)


У меня была аналогичная проблема с моим приложением для Android (и с моим внутренним сервером Spring Boot). Я думаю, что ваша проблема связана с тем, что вы используете самоподписанный сертификат. Решение состоит в том, чтобы встроить в папку ресурсов вашего приложения диспетчер доверия (в формате PKCS12), содержащий доверенный сертификат.

1. Добавьте хранилище ключей с сертификатом в папку с ресурсами:

Местоположение надежного магазина

2. Затем настройте OkHttpClient со встроенным менеджером доверия следующим образом: (измените пароль на свой)

fun getOkHttpClient(context: Context): OkHttpClient {

val password = "keystore_password".toCharArray()

val keyStore = KeyStore
    .getInstance("PKCS12").apply {
        load(context.assets.open("trust_store.p12"), password)
    }

val trustManagerFactory = TrustManagerFactory
    .getInstance(TrustManagerFactory.getDefaultAlgorithm())
    .apply { init(keyStore) }

val keyManagerFactory = KeyManagerFactory
    .getInstance(KeyManagerFactory.getDefaultAlgorithm())
    .apply { init(keyStore, password) }

val sslContext = SSLContext.getInstance("SSL")
    .apply {
        init(keyManagerFactory.keyManagers, trustManagerFactory.trustManagers, SecureRandom())
    }

return OkHttpClient.Builder()
    .sslSocketFactory(sslContext.socketFactory,
        trustManagerFactory.trustManagers[0] as X509TrustManager)
    .hostnameVerifier { hostname, _ -> hostname == apiHostname } // Return true if you want to trust all hostnames
    .build()

}

Если вы хотите доверять всем именам хостов, просто верните true в функциональном блоке hostnameVerifier, но я не рекомендую вам делать это, так как это может подвергнуть ваше приложение угрозам безопасности.

Обратите внимание, что при использовании собственного хранилища доверенных сертификатов ваше приложение будет доверять только сертификатам, содержащимся в этом хранилище доверенных сертификатов.

person Domenico    schedule 01.01.2021