gradle使用https地址报ssl异常解决办法

原创
08/27 10:03
阅读数 12

异常内容

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<Map<String, String>, SSLContext> {
        @Override
        public SSLContext load(Map<String, String> 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.classIgnoreSslContextFactory.class拖进去即可。

关于这两个class如何获得,可以单独建一个项目,将lib里面的jar包整个导入,项目即可正常编译成class

成品

这个是已经编译好的gradle-resources-http-6.6.1.jar,可以直接下载替换,也是可行的。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
在线直播报名
返回顶部
顶部