gongstring技术博客
最新文章
源码解读
软件安装
常见问题
大数据
常用工具
鸡汤文
备案号:鄂ICP备15015839号-1
鄂公网安备 42010202001692号
gradle使用https地址报ssl异常解决办法
2020-08-27 09:38:05
作者: gongstring
常见问题
/
gradle使用https地址报ssl异常解决办法
## 异常内容 ``` org.gradle.internal.resource.transport.http.HttpRequestException: Could not GET 'https://gitlab.gongstring.com/gradle-scripts/raw/master/scripts/root.gradle'. at org.gradle.internal.resource.transport.http.HttpClientHelper.performRequest(HttpClientHelper.java:101) at org.gradle.internal.resource.transport.http.HttpClientHelper.performRawGet(HttpClientHelper.java:84) at org.gradle.internal.resource.transport.http.HttpClientHelper.performGet(HttpClientHelper.java:88) at org.gradle.internal.resource.transport.http.HttpResourceAccessor.openResource(HttpResourceAccessor.java:43) at org.gradle.internal.resource.transport.http.HttpResourceAccessor.openResource(HttpResourceAccessor.java:28) at org.gradle.internal.resource.transfer.DefaultExternalResourceConnector.openResource(DefaultExternalResourceConnector.java:56) at org.gradle.internal.resource.transfer.ProgressLoggingExternalResourceAccessor.openResource(ProgressLoggingExternalResourceAccessor.java:38) at org.gradle.internal.resource.transfer.AccessorBackedExternalResource.withContentIfPresent(AccessorBackedExternalResource.java:130) at org.gradle.internal.resource.BuildOperationFiringExternalResourceDecorator$11.call(BuildOperationFiringExternalResourceDecorator.java:237) at org.gradle.internal.resource.BuildOperationFiringExternalResourceDecorator$11.call(BuildOperationFiringExternalResourceDecorator.java:229) at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:409) at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:399) at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:157) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:242) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:150) at org.gra ``` ## 原因分析 以gradle6.6.1为例,下载源码,定位异常地点代码,可以看到使用apache的httpClient发送GET请求,并且如果是https,需要导入证书才能解决报错,关于如何通过jdk导入证书,可以到百度家问问。*本文是通过修改源码,彻底忽略掉https的检查,毕竟是在本地使用。* 接下来分析下怎么修改: 源码路径: subprojects/resources-http/src/main/java/org/gradle/internal/resource/transport/http/HttpResourcesPluginServiceRegistry ``` private static class GlobalScopeServices { SslContextFactory createSslContextFactory() { return new DefaultSslContextFactory(); } ResourceConnectorFactory createHttpConnectorFactory(SslContextFactory sslContextFactory) { return new HttpConnectorFactory(sslContextFactory); } } ``` 发现此处并没有提供自定义功能,而是默认使用了自带的DefaultSslContextFactory实现SslContextFactory接口,其中最主要是createSslContext方法,用于根据配置,获取ssl,前面提到的通过jdk导入ssl证书解决,就是通过这里实现。源码如下: ``` @Override public SSLContext createSslContext() { return cache.getUnchecked(getCurrentProperties()); } private static class SslContextCacheLoader extends CacheLoader
, SSLContext> { @Override public SSLContext load(Map
props) { // TODO: We should see if we can go back to using HttpClient again. // This implementation is borrowed from the Apache HttpClient project // https://github.com/apache/httpclient/blob/4.2.2/httpclient/src/main/java/org/apache/http/conn/ssl/SSLSocketFactory.java#L246-L354 try { TrustManagerFactory tmFactory = initTrustManagerFactory(props); KeyManagerFactory kmFactory = initKeyManagerFactory(props); SSLContext sslcontext = SSLContext.getInstance("TLS"); sslcontext.init(kmFactory.getKeyManagers(), tmFactory.getTrustManagers(), null); return sslcontext; } catch (GeneralSecurityException | IOException e) { throw new SSLInitializationException(e.getMessage(), e); } } .... } ``` ## 解决思路 写一个实现类IgnoreSslContextFactory,实现SslContextFactory接口,并且修改HttpResourcesPluginServiceRegistry中的实现类为新创建的实现类。目的是通过自定义的SSLContext对象,实现httpClient请求时,绕开ssl认证。 IgnoreSslContextFactory.java ``` package org.gradle.internal.resource.transport.http; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.ssl.SSLContextBuilder; import org.apache.http.ssl.SSLInitializationException; import org.apache.http.ssl.TrustStrategy; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import java.security.cert.CertificateException; public class IgnoreSslContextFactory implements SslContextFactory { @Override public SSLContext createSslContext() { try { SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { @Override public boolean isTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws CertificateException { return true; } }).build(); HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE; SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); return sslContext; } catch (Exception e) { throw new SSLInitializationException(e.getMessage(), e); } } } ``` 修改HttpResourcesPluginServiceRegistry ``` /* * Copyright 2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.gradle.internal.resource.transport.http; import org.gradle.authentication.http.BasicAuthentication; import org.gradle.authentication.http.DigestAuthentication; import org.gradle.authentication.http.HttpHeaderAuthentication; import org.gradle.internal.authentication.AuthenticationSchemeRegistry; import org.gradle.internal.authentication.DefaultBasicAuthentication; import org.gradle.internal.authentication.DefaultDigestAuthentication; import org.gradle.internal.authentication.DefaultHttpHeaderAuthentication; import org.gradle.internal.resource.connector.ResourceConnectorFactory; import org.gradle.internal.service.ServiceRegistration; import org.gradle.internal.service.scopes.AbstractPluginServiceRegistry; public class HttpResourcesPluginServiceRegistry extends AbstractPluginServiceRegistry { @Override public void registerGlobalServices(ServiceRegistration registration) { registration.addProvider(new GlobalScopeServices()); } @Override public void registerBuildServices(ServiceRegistration registration) { registration.addProvider(new AuthenticationSchemeAction()); } private static class GlobalScopeServices { SslContextFactory createSslContextFactory() { // return new DefaultSslContextFactory(); //自定义忽略ssl证书 return new IgnoreSslContextFactory(); } ResourceConnectorFactory createHttpConnectorFactory(SslContextFactory sslContextFactory) { return new HttpConnectorFactory(sslContextFactory); } } private static class AuthenticationSchemeAction { public void configure(ServiceRegistration registration, AuthenticationSchemeRegistry authenticationSchemeRegistry) { authenticationSchemeRegistry.registerScheme(BasicAuthentication.class, DefaultBasicAuthentication.class); authenticationSchemeRegistry.registerScheme(DigestAuthentication.class, DefaultDigestAuthentication.class); authenticationSchemeRegistry.registerScheme(HttpHeaderAuthentication.class, DefaultHttpHeaderAuthentication.class); } } } ``` ## 打包 由于此处并没有完整解决gradle的编译功能,各种报错,待一一解锁。此处用最简单的方式,直接替换里面的class,以gradle6.6.1为例,在gradle安装目录的lib目录中,找到gradle-resources-http-6.6.1.jar文件,用压缩软件打开,找到/org/gradle/internal/resource/transport/http/,将编译好的*HttpResourcesPluginServiceRegistry.class*和*IgnoreSslContextFactory.class*拖进去即可。 关于这两个class如何获得,可以单独建一个项目,将lib里面的jar包整个导入,项目即可正常编译成class ## 成品 这个是已经编译好的[gradle-resources-http-6.6.1.jar](https://gitee.com/gongstring_prod/gongstring.com-asserts/raw/master/upload/libs/gradle-resources-http-6.6.1.jar),可以直接下载替换,也是可行的。