0

我们正在尝试使用使用 okhttp 客户端将对象上传到存储桶的 minio-java 客户端。目前我们使用的服务器仅支持服务器身份验证而不支持双向 tls,这主要意味着我们必须验证服务器提供给定 CA 证书的证书。出于这个原因,我们确实创建了以下方法来简单地将 ca 证书文件传递到trustedstore。

private OkHttpClient addCertificates(OkHttpClient httpClient,
                                     Path certificatesDir) throws CertificateException, KeyStoreException, NoSuchAlgorithmException, IOException, UnrecoverableKeyException, KeyManagementException
{
    // TODO: remove printing of certificates
    String certContents = Files.readString(certificatesDir);
    log.debug("certificate contents: {}", certContents);
    
    Collection<? extends Certificate> certificates = null;
    try (FileInputStream fis = new FileInputStream(certificatesDir.toFile().getAbsolutePath()))
    {
        certificates = CertificateFactory.getInstance("X.509").generateCertificates(fis);
    }

    if (certificates == null || certificates.isEmpty())
    {
        throw new IllegalArgumentException("expected non-empty set of trusted certificates");
    }

    char[] password = "password".toCharArray();

    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    keyStore.load(null, password);

    int index = 0;
    for (Certificate certificate : certificates)
    {
        String certificateAlias = Integer.toString(index++);
        keyStore.setCertificateEntry(certificateAlias, certificate);
    }
    
    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    trustManagerFactory.init(keyStore);
    TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
    
    SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
    sslContext.init(null, trustManagers, null);
    SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

    return httpClient.newBuilder().sslSocketFactory(sslSocketFactory, (X509TrustManager) trustManagers[0]).build();
}

如果能帮助我们了解 minio 如何在 MinioClient.java 中使用下面的“enableExternalCertificates”来分离 ca/client 证书,这需要一个 SSL 证书文件,那就太好了。

private OkHttpClient enableExternalCertificates(OkHttpClient httpClient, String filename)
    throws GeneralSecurityException, IOException {
  Collection<? extends Certificate> certificates = null;
  try (FileInputStream fis = new FileInputStream(filename)) {
    certificates = CertificateFactory.getInstance("X.509").generateCertificates(fis);
  }

  if (certificates == null || certificates.isEmpty()) {
    throw new IllegalArgumentException("expected non-empty set of trusted certificates");
  }

  char[] password = "password".toCharArray(); // Any password will work.

  // Put the certificates a key store.
  KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
  // By convention, 'null' creates an empty key store.
  keyStore.load(null, password);

  int index = 0;
  for (Certificate certificate : certificates) {
    String certificateAlias = Integer.toString(index++);
    keyStore.setCertificateEntry(certificateAlias, certificate);
  }

  // Use it to build an X509 trust manager.
  KeyManagerFactory keyManagerFactory =
      KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
  keyManagerFactory.init(keyStore, password);
  TrustManagerFactory trustManagerFactory =
      TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
  trustManagerFactory.init(keyStore);

  final KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
  final TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();

  SSLContext sslContext = SSLContext.getInstance("TLS");
  sslContext.init(keyManagers, trustManagers, null);
  SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

  return httpClient
      .newBuilder()
      .sslSocketFactory(sslSocketFactory, (X509TrustManager) trustManagers[0])
      .build();
}

目前,我们确实有以下例外,我不确定这些例外是否与证书有关。

--- 连接异常 ---

java.net.ConnectException:无法在 okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:248) 的 okhttp3.internal.connection.RealConnection.connect(RealConnection.java) 处连接到 object-storage/10.10.10.10:9000 :166) 在 okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:257) 在 okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135) 在 okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation. java:114) 在 okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42) 在 okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) 在 okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain .java:121) 在 okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93) 在 okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) 在 okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) 在 okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java :93) 在 okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147) 在 okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:126) 在 okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain. java:147) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121) at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:254) at okhttp3.RealCall.execute(RealCall.java:92) at io。 minio.MinioClient.execute(MinioClient.java:635) 在 io.minio.MinioClient.getRegion(MinioClient.java:805) 在 io.minio。MinioClient.execute(MinioClient.java:568) at io.minio.MinioClient.executeHead(MinioClient.java:837) at io.minio.MinioClient.bucketExists(MinioClient.java:2209) at com.ericsson.sc.s3c.S3MinioClientHandler .bucketExists(S3MinioClientHandler.java:201) 在 com.ericsson.sc.s3c.S3Agent.checkBucket(S3Agent.java:80) 在 com.ericsson.sc.s3c.S3Agent.lambda$uploadFileToBucket$3(S3Agent.java:57)在 java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) 在 java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177) 在 java .base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655) 在 java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) 在 java.base/java.util.stream .AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) 在 java.base/java.util.stream。在 java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) 在 java.base/java.util.stream.AbstractPipeline 的 ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)。 com.ericsson.sc.s3c.S3Agent.lambda$uploadFileToBucket$4(S3Agent.java:51) 的 java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497) 的评估(AbstractPipeline.java:234) ) 在 io.reactivex.internal.operators.completable.CompletableFromAction.subscribeActual(CompletableFromAction.java:35) 在 io.reactivex.Completable.subscribe(Completable.java:2309) 在 io.reactivex.internal.operators.mixed.FlowableConcatMapCompletable$ ConcatMapCompletableObserver.drain(FlowableConcatMapCompletable.java:253) 在 io.reactivex.internal.operators.mixed.FlowableConcatMapCompletable$ConcatMapCompletableObserver.onNext(FlowableConcatMapCompletable.java:118) 在 io.reactivex.internal.operators.flowable.FlowableDoOnEach$DoOnEachSubscriber.onNext(FlowableDoOnEach.java:92) 在 io.reactivex.internal.operators.flowable.FlowableOnBackpressureLatest$BackpressureLatestSubscriber.drain(FlowableOnBackpressureLatest.java:129)在 io.reactivex.internal.operators.flowable.FlowableOnBackpressureLatest$BackpressureLatestSubscriber.onNext(FlowableOnBackpressureLatest.java:68) 在 io.reactivex.internal.operators.flowable.FlowableThrottleLatest$ThrottleLatestSubscriber.drain(FlowableThrottleLatest.java:221) 在 io.reactivex .internal.operators.flowable.FlowableThrottleLatest$ThrottleLatestSubscriber.onNext(FlowableThrottleLatest.java:119) 在 io.reactivex.internal.operators.flowable.FlowableDoOnEach$DoOnEachSubscriber.onNext(FlowableDoOnEach.java:92) 在 io.reactivex.internal.util .NotificationLite。在 io.reactivex.internal.operators.flowable.FlowableReplay$ReplaySubscriber.onNext(FlowableReplay. java:388) 在 io.reactivex.internal.operators.flowable.FlowableDoOnEach$DoOnEachSubscriber.onNext(FlowableDoOnEach.java:92) 在 io.reactivex.internal.operators.flowable.FlowableDoOnEach$DoOnEachSubscriber.onNext(FlowableDoOnEach.java:92)在 io.reactivex.internal.operators.flowable.FlowableFlatMapSingle$FlatMapSingleSubscriber.innerSuccess(FlowableFlatMapSingle.java:175) 在 io.reactivex.internal.operators.flowable.FlowableFlatMapSingle$FlatMapSingleSubscriber$InnerObserver.onSuccess(FlowableFlatMapSingle.java:364) 在 io .reactivex.internal.operators.single.SingleSubscribeOn$SubscribeOnObserver。onSuccess(SingleSubscribeOn.java:68) at io.reactivex.internal.operators.single.SingleFromCallable.subscribeActual(SingleFromCallable.java:56) at io.reactivex.Single.subscribe(Single.java:3603) at io.reactivex.internal .operators.single.SingleSubscribeOn$SubscribeOnObserver.run(SingleSubscribeOn.java:89) at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:578) at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java :66) 在 io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57) 在 java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) 在 java.base/java。 util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) 在 java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) 在 java.base/java.util.concurrent。java.base/java.lang.Thread.run(Thread.java:834) 处的 ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) 原因:java.net.ConnectException:Java 处的连接超时(连接超时) .base/java.net.PlainSocketImpl.socketConnect(Native Method) at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:399) at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java: 242) 在 java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:224) 在 java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) 在 java.base/java.net.Socket .connect(Socket.java:609) at okhttp3.internal.platform.Platform.connectSocket(Platform.java:129) at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:246) ... 省略了 64 个常用帧64个常用框架省略

--- 套接字异常 ---

java.net.SocketException:在 okio.Okio 的 java.base/java.net.SocketInputStream.read(SocketInputStream.java:140) 处的 java.base/java.net.SocketInputStream.read(SocketInputStream.java:186) 处的连接重置$2.read(Okio.java:140) at okio.AsyncTimeout$2.read(AsyncTimeout.java:237) at okio.RealBufferedSource.read(RealBufferedSource.java:47) at okhttp3.internal.http1.Http1Codec$AbstractSource.read( Http1Codec.java:363) 在 okhttp3.internal.http1.Http1Codec$UnknownLengthSource.read(Http1Codec.java:507) 在 okio.Buffer.writeAll(Buffer.java:1135) 在 okio.RealBufferedSource.readString(RealBufferedSource.java:199) ) 在 io.minio.MinioClient.getRegion(MinioClient.java:805) 在 io.minio.MinioClient.execute(MinioClient.java:663) 在 io.minio.MinioClient 的 okhttp3.ResponseBody.string(ResponseBody.java:176) .putObject(MinioClient.java:4584) 在 io.minio.MinioClient。putObject(MinioClient.java:2726) at io.minio.MinioClient.uploadObject(MinioClient.java:2890) at com.ericsson.sc.s3c.S3MinioClientHandler.uploadFile(S3MinioClientHandler.java:237) at com.ericsson.sc.s3c .S3Agent.lambda$uploadFileToBucket$3(S3Agent.java:60) 在 java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) 在 java.base/java.util.stream。 ReferencePipeline$2$1.accept(ReferencePipeline.java:177) at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline. java:484) 在 java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) 在 java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) 在 java .base/java.util.stream.ForEachOps$ForEachOp$OfRef。evaluateSequential(ForEachOps.java:173) 在 java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) 在 java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)在 com.ericsson.sc.s3c.S3Agent.lambda$uploadFileToBucket$4(S3Agent.java:51) 在 io.reactivex.internal.operators.completable.CompletableFromAction.subscribeActual(CompletableFromAction.java:35) 在 io.reactivex.Completable。在 io.reactivex.internal.operators.mixed.FlowableConcatMapCompletable$ConcatMapCompletableObserver.onNext(FlowableConcatMapCompletable. java:118) 在 io.reactivex.internal.operators.flowable.FlowableDoOnEach$DoOnEachSubscriber.onNext(FlowableDoOnEach.java:92) 在 io.reactivex.internal.operators.flowable.FlowableOnBackpressureLatest$BackpressureLatestSubscriber.onNext(FlowableOnBackpressureLatest.java:68) 在 io.reactivex.internal.operators.flowable.FlowableOnBackpressureLatest$BackpressureLatestSubscriber.drain(FlowableOnBackpressureLatest.java:129) .reactivex.internal.operators.flowable.FlowableThrottleLatest$ThrottleLatestSubscriber.drain(FlowableThrottleLatest.java:221) 在 io.reactivex.internal.operators.flowable.FlowableThrottleLatest$ThrottleLatestSubscriber.onNext(FlowableThrottleLatest.java:119) 在 io.reactivex.internal .operators.flowable.FlowableDoOnEach$DoOnEachSubscriber.onNext(FlowableDoOnEach.java:92) 在 io.reactivex.internal.util.NotificationLite.accept(NotificationLite.java:224) 在 io.reactivex.internal.operators.flowable.FlowableReplay$BoundedReplayBuffer .replay(FlowableReplay.java:855) 在 io.reactivex.internal.operators.flowable.FlowableReplay$ReplaySubscriber.onNext(FlowableReplay.java:388) 在 io.reactivex.internal.operators.flowable.FlowableDoOnEach$DoOnEachSubscriber.onNext(FlowableDoOnEach.java:92)在 io.reactivex.internal.operators.flowable.FlowableDoOnEach$DoOnEachSubscriber.onNext(FlowableDoOnEach.java:92) 在 io.reactivex.internal.operators.flowable.FlowableFlatMapSingle$FlatMapSingleSubscriber.innerSuccess(FlowableFlatMapSingle.java:175) 在 io.reactivex .internal.operators.flowable.FlowableFlatMapSingle$FlatMapSingleSubscriber$InnerObserver.onSuccess(FlowableFlatMapSingle.java:364) at io.reactivex.internal.operators.single.SingleSubscribeOn$SubscribeOnObserver.onSuccess(SingleSubscribeOn.java:68) at io.reactivex.internal .operators.single.SingleFromCallable.subscribeActual(SingleFromCallable.java:56) 在 io。io.reactivex.internal.operators.single.SingleSubscribeOn$SubscribeOnObserver.run(SingleSubscribeOn.java:89) 处的 reactivex.Single.subscribe(Single.java:3603) io.reactivex.Scheduler$DisposeTask.run(Scheduler.java: 578)在 io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66) 在 io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57) 在 java.base/java.util.concurrent .FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor .java:1128) 在 java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) 在 java.base/java.lang.Thread.run(Thread.java:834)第 3603 章.ScheduledRunnable.run(ScheduledRunnable.java:66) at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264 ) 在 java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) 在 java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) 在 java.base/ java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) 在 java.base/java.lang.Thread.run(Thread.java:834)第 3603 章.ScheduledRunnable.run(ScheduledRunnable.java:66) at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264 ) 在 java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) 在 java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) 在 java.base/ java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) 在 java.base/java.lang.Thread.run(Thread.java:834)在 io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66) 在 io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:578) 在 io.reactivex.internal 运行(SingleSubscribeOn.java:89) .schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57) 在 java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) 在 java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run (ScheduledThreadPoolExecutor.java:304) 在 java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) 在 java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ) 在 java.base/java.lang.Thread.run(Thread.java:834)在 io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66) 在 io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:578) 在 io.reactivex.internal 运行(SingleSubscribeOn.java:89) .schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57) 在 java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) 在 java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run (ScheduledThreadPoolExecutor.java:304) 在 java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) 在 java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ) 在 java.base/java.lang.Thread.run(Thread.java:834)java:66) 在 io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57) 在 java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) 在 java.base/java .util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) 在 java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) 在 java.base/java.util.concurrent.ThreadPoolExecutor $Worker.run(ThreadPoolExecutor.java:628) 在 java.base/java.lang.Thread.run(Thread.java:834)java:66) 在 io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57) 在 java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) 在 java.base/java .util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) 在 java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) 在 java.base/java.util.concurrent.ThreadPoolExecutor $Worker.run(ThreadPoolExecutor.java:628) 在 java.base/java.lang.Thread.run(Thread.java:834)ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) 在 java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) 在 java.base/java.lang.Thread.run(Thread.java:第834章)ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) 在 java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) 在 java.base/java.lang.Thread.run(Thread.java:第834章)

我认为检查存储桶是否存在后的第一个异常可能与端点主机名“对象存储”的解析有关,但我们仍然有 IP 地址,并且所有其他请求(如存储桶创建)可能有“连接重置”异常由于第一个例外,因为我们仍然使用相同的客户端。但是,我们确实注意到新客户端有时会直接生成“连接重置”异常。

根据minio,使用的文件名对应于环境变量SSL_CERT_FILE,它对应于TLS证书文件的路径(例如自签名TLS证书)。此外,如果我们不生成自己的自定义 http 客户端,MinioClient.Builder.build() 将创建默认 HTTP 客户端对象,并使用上面的 enableExternalCertificates() 加载此类 TLS 证书。至于http客户端的工作人员,我想这个论坛是最合适的。

任何建议将不胜感激。

4

0 回答 0