Exact to support dynamic cert (#11578)
This commit is contained in:
parent
92a1051516
commit
0a9b19c306
|
|
@ -67,6 +67,7 @@ header:
|
||||||
- 'CNAME'
|
- 'CNAME'
|
||||||
- 'Jenkinsfile'
|
- 'Jenkinsfile'
|
||||||
- '**/vendor/**'
|
- '**/vendor/**'
|
||||||
|
- '**/src/test/resources/certs/**'
|
||||||
- 'dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/InternalThreadLocal.java'
|
- 'dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/InternalThreadLocal.java'
|
||||||
- 'dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/InternalThreadLocalMap.java'
|
- 'dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/InternalThreadLocalMap.java'
|
||||||
- 'dubbo-common/src/main/java/org/apache/dubbo/common/timer/HashedWheelTimer.java'
|
- 'dubbo-common/src/main/java/org/apache/dubbo/common/timer/HashedWheelTimer.java'
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,6 @@
|
||||||
<suppressions>
|
<suppressions>
|
||||||
<suppress files="[\\/]src[\\/]main[\\/]java[\\/]com[\\/]alibaba[\\/]com[\\/]caucho[\\/]hessian" checks=".*"/>
|
<suppress files="[\\/]src[\\/]main[\\/]java[\\/]com[\\/]alibaba[\\/]com[\\/]caucho[\\/]hessian" checks=".*"/>
|
||||||
<suppress files="[\\/]build[\\/]generated[\\/]source[\\/]proto" checks=".*"/>
|
<suppress files="[\\/]build[\\/]generated[\\/]source[\\/]proto" checks=".*"/>
|
||||||
|
<suppress files="[\\/]target[\\/]generated-sources[\\/]protobuf" checks=".*"/>
|
||||||
<suppress files="Yylex\.java" checks="AvoidEscapedUnicodeCharacters"/>
|
<suppress files="Yylex\.java" checks="AvoidEscapedUnicodeCharacters"/>
|
||||||
</suppressions>
|
</suppressions>
|
||||||
|
|
@ -20,6 +20,7 @@ import org.apache.dubbo.common.beans.factory.ScopeBeanFactory;
|
||||||
import org.apache.dubbo.common.config.ConfigurationCache;
|
import org.apache.dubbo.common.config.ConfigurationCache;
|
||||||
import org.apache.dubbo.common.convert.ConverterUtil;
|
import org.apache.dubbo.common.convert.ConverterUtil;
|
||||||
import org.apache.dubbo.common.lang.ShutdownHookCallbacks;
|
import org.apache.dubbo.common.lang.ShutdownHookCallbacks;
|
||||||
|
import org.apache.dubbo.common.ssl.CertManager;
|
||||||
import org.apache.dubbo.common.status.reporter.FrameworkStatusReportService;
|
import org.apache.dubbo.common.status.reporter.FrameworkStatusReportService;
|
||||||
import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;
|
import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;
|
||||||
import org.apache.dubbo.common.utils.DefaultSerializeClassChecker;
|
import org.apache.dubbo.common.utils.DefaultSerializeClassChecker;
|
||||||
|
|
@ -38,6 +39,7 @@ public class CommonScopeModelInitializer implements ScopeModelInitializer {
|
||||||
beanFactory.registerBean(ConverterUtil.class);
|
beanFactory.registerBean(ConverterUtil.class);
|
||||||
beanFactory.registerBean(SerializeSecurityManager.class);
|
beanFactory.registerBean(SerializeSecurityManager.class);
|
||||||
beanFactory.registerBean(DefaultSerializeClassChecker.class);
|
beanFactory.registerBean(DefaultSerializeClassChecker.class);
|
||||||
|
beanFactory.registerBean(CertManager.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -380,6 +380,12 @@ public interface LoggerCodeConstants {
|
||||||
|
|
||||||
String CONFIG_DUBBO_BEAN_NOT_FOUND = "5-40";
|
String CONFIG_DUBBO_BEAN_NOT_FOUND = "5-40";
|
||||||
|
|
||||||
|
String CONFIG_SSL_PATH_LOAD_FAILED = "5-41";
|
||||||
|
|
||||||
|
String CONFIG_SSL_CERT_GENERATE_FAILED = "5-42";
|
||||||
|
|
||||||
|
String CONFIG_SSL_CONNECT_INSECURE = "5-43";
|
||||||
|
|
||||||
// Transport module
|
// Transport module
|
||||||
String TRANSPORT_FAILED_CONNECT_PROVIDER = "6-1";
|
String TRANSPORT_FAILED_CONNECT_PROVIDER = "6-1";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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.apache.dubbo.common.ssl;
|
||||||
|
|
||||||
|
public enum AuthPolicy {
|
||||||
|
NONE,
|
||||||
|
SERVER_AUTH,
|
||||||
|
CLIENT_AUTH
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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.apache.dubbo.common.ssl;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public class Cert {
|
||||||
|
private final byte[] keyCertChain;
|
||||||
|
private final byte[] privateKey;
|
||||||
|
private final byte[] trustCert;
|
||||||
|
|
||||||
|
private final String password;
|
||||||
|
|
||||||
|
public Cert(byte[] keyCertChain, byte[] privateKey, byte[] trustCert) {
|
||||||
|
this(keyCertChain, privateKey, trustCert, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Cert(byte[] keyCertChain, byte[] privateKey, byte[] trustCert, String password) {
|
||||||
|
this.keyCertChain = keyCertChain;
|
||||||
|
this.privateKey = privateKey;
|
||||||
|
this.trustCert = trustCert;
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getKeyCertChain() {
|
||||||
|
return keyCertChain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStream getKeyCertChainInputStream() {
|
||||||
|
return keyCertChain != null ? new ByteArrayInputStream(keyCertChain) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getPrivateKey() {
|
||||||
|
return privateKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStream getPrivateKeyInputStream() {
|
||||||
|
return privateKey != null ? new ByteArrayInputStream(privateKey) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getTrustCert() {
|
||||||
|
return trustCert;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStream getTrustCertInputStream() {
|
||||||
|
return trustCert != null ? new ByteArrayInputStream(trustCert) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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.apache.dubbo.common.ssl;
|
||||||
|
|
||||||
|
import org.apache.dubbo.common.URL;
|
||||||
|
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||||
|
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class CertManager {
|
||||||
|
private final List<CertProvider> certProviders;
|
||||||
|
|
||||||
|
public CertManager(FrameworkModel frameworkModel) {
|
||||||
|
this.certProviders = frameworkModel.getExtensionLoader(CertProvider.class).getActivateExtensions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProviderCert getProviderConnectionConfig(URL localAddress, SocketAddress remoteAddress) {
|
||||||
|
for (CertProvider certProvider : certProviders) {
|
||||||
|
if (certProvider.isSupport(localAddress)) {
|
||||||
|
ProviderCert cert = certProvider.getProviderConnectionConfig(localAddress);
|
||||||
|
if (cert != null) {
|
||||||
|
return cert;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Cert getConsumerConnectionConfig(URL remoteAddress) {
|
||||||
|
for (CertProvider certProvider : certProviders) {
|
||||||
|
if (certProvider.isSupport(remoteAddress)) {
|
||||||
|
Cert cert = certProvider.getConsumerConnectionConfig(remoteAddress);
|
||||||
|
if (cert != null) {
|
||||||
|
return cert;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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.apache.dubbo.common.ssl;
|
||||||
|
|
||||||
|
import org.apache.dubbo.common.URL;
|
||||||
|
import org.apache.dubbo.common.extension.ExtensionScope;
|
||||||
|
import org.apache.dubbo.common.extension.SPI;
|
||||||
|
|
||||||
|
@SPI(scope = ExtensionScope.FRAMEWORK)
|
||||||
|
public interface CertProvider {
|
||||||
|
boolean isSupport(URL address);
|
||||||
|
|
||||||
|
ProviderCert getProviderConnectionConfig(URL localAddress);
|
||||||
|
|
||||||
|
Cert getConsumerConnectionConfig(URL remoteAddress);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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.apache.dubbo.common.ssl;
|
||||||
|
|
||||||
|
public class ProviderCert extends Cert {
|
||||||
|
private final AuthPolicy authPolicy;
|
||||||
|
|
||||||
|
public ProviderCert(byte[] keyCertChain, byte[] privateKey, byte[] trustCert, AuthPolicy authPolicy) {
|
||||||
|
super(keyCertChain, privateKey, trustCert);
|
||||||
|
this.authPolicy = authPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProviderCert(byte[] keyCertChain, byte[] privateKey, byte[] trustCert, String password, AuthPolicy authPolicy) {
|
||||||
|
super(keyCertChain, privateKey, trustCert, password);
|
||||||
|
this.authPolicy = authPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthPolicy getAuthPolicy() {
|
||||||
|
return authPolicy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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.apache.dubbo.common.ssl.impl;
|
||||||
|
|
||||||
|
import org.apache.dubbo.common.URL;
|
||||||
|
import org.apache.dubbo.common.constants.LoggerCodeConstants;
|
||||||
|
import org.apache.dubbo.common.extension.Activate;
|
||||||
|
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
||||||
|
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||||
|
import org.apache.dubbo.common.ssl.AuthPolicy;
|
||||||
|
import org.apache.dubbo.common.ssl.Cert;
|
||||||
|
import org.apache.dubbo.common.ssl.CertProvider;
|
||||||
|
import org.apache.dubbo.common.ssl.ProviderCert;
|
||||||
|
import org.apache.dubbo.common.utils.IOUtils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@Activate(order = Integer.MAX_VALUE - 10000)
|
||||||
|
public class SSLConfigCertProvider implements CertProvider {
|
||||||
|
private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(SSLConfigCertProvider.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSupport(URL address) {
|
||||||
|
return address.getOrDefaultApplicationModel().getApplicationConfigManager().getSsl()
|
||||||
|
.isPresent();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProviderCert getProviderConnectionConfig(URL localAddress) {
|
||||||
|
return localAddress.getOrDefaultApplicationModel().getApplicationConfigManager().getSsl()
|
||||||
|
.filter(sslConfig -> Objects.nonNull(sslConfig.getServerKeyCertChainPath()))
|
||||||
|
.filter(sslConfig -> Objects.nonNull(sslConfig.getServerPrivateKeyPath()))
|
||||||
|
.map(sslConfig -> {
|
||||||
|
try {
|
||||||
|
return new ProviderCert(
|
||||||
|
IOUtils.toByteArray(sslConfig.getServerKeyCertChainPathStream()),
|
||||||
|
IOUtils.toByteArray(sslConfig.getServerPrivateKeyPathStream()),
|
||||||
|
sslConfig.getServerTrustCertCollectionPath() != null ? IOUtils.toByteArray(sslConfig.getServerTrustCertCollectionPathStream()) : null,
|
||||||
|
sslConfig.getServerKeyPassword(), AuthPolicy.CLIENT_AUTH);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.warn(LoggerCodeConstants.CONFIG_SSL_PATH_LOAD_FAILED, "", "", "Failed to load ssl config.", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cert getConsumerConnectionConfig(URL remoteAddress) {
|
||||||
|
return remoteAddress.getOrDefaultApplicationModel().getApplicationConfigManager().getSsl()
|
||||||
|
.filter(sslConfig -> Objects.nonNull(sslConfig.getClientKeyCertChainPath()))
|
||||||
|
.filter(sslConfig -> Objects.nonNull(sslConfig.getClientPrivateKeyPath()))
|
||||||
|
.map(sslConfig -> {
|
||||||
|
try {
|
||||||
|
return new Cert(
|
||||||
|
IOUtils.toByteArray(sslConfig.getClientKeyCertChainPathStream()),
|
||||||
|
IOUtils.toByteArray(sslConfig.getClientPrivateKeyPathStream()),
|
||||||
|
sslConfig.getClientTrustCertCollectionPath() != null ? IOUtils.toByteArray(sslConfig.getClientTrustCertCollectionPathStream()) : null,
|
||||||
|
sslConfig.getClientKeyPassword());
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.warn(LoggerCodeConstants.CONFIG_SSL_PATH_LOAD_FAILED, "", "", "Failed to load ssl config.", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}).orElse(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,6 +19,7 @@ package org.apache.dubbo.common.utils;
|
||||||
import org.apache.dubbo.common.constants.CommonConstants;
|
import org.apache.dubbo.common.constants.CommonConstants;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
|
@ -277,4 +278,15 @@ public class IOUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static byte[] toByteArray(final InputStream inputStream) throws IOException {
|
||||||
|
try (final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int n;
|
||||||
|
while (-1 != (n = inputStream.read(buffer))) {
|
||||||
|
byteArrayOutputStream.write(buffer, 0, n);
|
||||||
|
}
|
||||||
|
return byteArrayOutputStream.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,11 @@ public class SslConfig extends AbstractConfig {
|
||||||
private InputStream clientPrivateKeyPathStream;
|
private InputStream clientPrivateKeyPathStream;
|
||||||
private InputStream clientTrustCertCollectionPathStream;
|
private InputStream clientTrustCertCollectionPathStream;
|
||||||
|
|
||||||
|
private String caAddress;
|
||||||
|
private String envType;
|
||||||
|
private String caCertPath;
|
||||||
|
private String oidcTokenPath;
|
||||||
|
|
||||||
public SslConfig() {
|
public SslConfig() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,6 +148,38 @@ public class SslConfig extends AbstractConfig {
|
||||||
this.clientTrustCertCollectionPath = clientTrustCertCollectionPath;
|
this.clientTrustCertCollectionPath = clientTrustCertCollectionPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getCaAddress() {
|
||||||
|
return caAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCaAddress(String caAddress) {
|
||||||
|
this.caAddress = caAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEnvType() {
|
||||||
|
return envType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnvType(String envType) {
|
||||||
|
this.envType = envType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCaCertPath() {
|
||||||
|
return caCertPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCaCertPath(String caCertPath) {
|
||||||
|
this.caCertPath = caCertPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOidcTokenPath() {
|
||||||
|
return oidcTokenPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOidcTokenPath(String oidcTokenPath) {
|
||||||
|
this.oidcTokenPath = oidcTokenPath;
|
||||||
|
}
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
public InputStream getServerKeyCertChainPathStream() throws IOException {
|
public InputStream getServerKeyCertChainPathStream() throws IOException {
|
||||||
if (serverKeyCertChainPath != null) {
|
if (serverKeyCertChainPath != null) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
ssl-config=org.apache.dubbo.common.ssl.impl.SSLConfigCertProvider
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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.apache.dubbo.common.ssl;
|
||||||
|
|
||||||
|
import org.apache.dubbo.common.URL;
|
||||||
|
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
class CertManagerTest {
|
||||||
|
private FrameworkModel frameworkModel;
|
||||||
|
private URL url;
|
||||||
|
@BeforeEach
|
||||||
|
void setup() {
|
||||||
|
FirstCertProvider.setProviderCert(null);
|
||||||
|
FirstCertProvider.setCert(null);
|
||||||
|
FirstCertProvider.setSupport(false);
|
||||||
|
|
||||||
|
SecondCertProvider.setProviderCert(null);
|
||||||
|
SecondCertProvider.setCert(null);
|
||||||
|
SecondCertProvider.setSupport(false);
|
||||||
|
|
||||||
|
frameworkModel = new FrameworkModel();
|
||||||
|
url = URL.valueOf("dubbo://").setScopeModel(frameworkModel.newApplication());
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
void teardown() {
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetConsumerConnectionConfig() {
|
||||||
|
CertManager certManager = new CertManager(frameworkModel);
|
||||||
|
|
||||||
|
Assertions.assertNull(certManager.getConsumerConnectionConfig(url));
|
||||||
|
|
||||||
|
Cert cert1 = Mockito.mock(Cert.class);
|
||||||
|
FirstCertProvider.setCert(cert1);
|
||||||
|
Assertions.assertNull(certManager.getConsumerConnectionConfig(url));
|
||||||
|
|
||||||
|
FirstCertProvider.setSupport(true);
|
||||||
|
Assertions.assertEquals(cert1, certManager.getConsumerConnectionConfig(url));
|
||||||
|
|
||||||
|
Cert cert2 = Mockito.mock(Cert.class);
|
||||||
|
SecondCertProvider.setCert(cert2);
|
||||||
|
Assertions.assertEquals(cert1, certManager.getConsumerConnectionConfig(url));
|
||||||
|
|
||||||
|
SecondCertProvider.setSupport(true);
|
||||||
|
Assertions.assertEquals(cert1, certManager.getConsumerConnectionConfig(url));
|
||||||
|
|
||||||
|
FirstCertProvider.setSupport(false);
|
||||||
|
Assertions.assertEquals(cert2, certManager.getConsumerConnectionConfig(url));
|
||||||
|
|
||||||
|
FirstCertProvider.setSupport(true);
|
||||||
|
FirstCertProvider.setCert(null);
|
||||||
|
Assertions.assertEquals(cert2, certManager.getConsumerConnectionConfig(url));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetProviderConnectionConfig() {
|
||||||
|
CertManager certManager = new CertManager(frameworkModel);
|
||||||
|
|
||||||
|
Assertions.assertNull(certManager.getProviderConnectionConfig(url, null));
|
||||||
|
|
||||||
|
ProviderCert providerCert1 = Mockito.mock(ProviderCert.class);
|
||||||
|
FirstCertProvider.setProviderCert(providerCert1);
|
||||||
|
Assertions.assertNull(certManager.getProviderConnectionConfig(url, null));
|
||||||
|
|
||||||
|
FirstCertProvider.setSupport(true);
|
||||||
|
Assertions.assertEquals(providerCert1, certManager.getProviderConnectionConfig(url, null));
|
||||||
|
|
||||||
|
ProviderCert providerCert2 = Mockito.mock(ProviderCert.class);
|
||||||
|
SecondCertProvider.setProviderCert(providerCert2);
|
||||||
|
Assertions.assertEquals(providerCert1, certManager.getProviderConnectionConfig(url, null));
|
||||||
|
|
||||||
|
SecondCertProvider.setSupport(true);
|
||||||
|
Assertions.assertEquals(providerCert1, certManager.getProviderConnectionConfig(url, null));
|
||||||
|
|
||||||
|
FirstCertProvider.setSupport(false);
|
||||||
|
Assertions.assertEquals(providerCert2, certManager.getProviderConnectionConfig(url, null));
|
||||||
|
|
||||||
|
FirstCertProvider.setSupport(true);
|
||||||
|
FirstCertProvider.setProviderCert(null);
|
||||||
|
Assertions.assertEquals(providerCert2, certManager.getProviderConnectionConfig(url, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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.apache.dubbo.common.ssl;
|
||||||
|
|
||||||
|
import org.apache.dubbo.common.URL;
|
||||||
|
import org.apache.dubbo.common.extension.Activate;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
@Activate(order = -10000)
|
||||||
|
public class FirstCertProvider implements CertProvider {
|
||||||
|
private static final AtomicBoolean isSupport = new AtomicBoolean(false);
|
||||||
|
private static final AtomicReference<ProviderCert> providerCert = new AtomicReference<>();
|
||||||
|
private static final AtomicReference<Cert> cert = new AtomicReference<>();
|
||||||
|
@Override
|
||||||
|
public boolean isSupport(URL address) {
|
||||||
|
return isSupport.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProviderCert getProviderConnectionConfig(URL localAddress) {
|
||||||
|
return providerCert.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cert getConsumerConnectionConfig(URL remoteAddress) {
|
||||||
|
return cert.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setSupport(boolean support) {
|
||||||
|
isSupport.set(support);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setProviderCert(ProviderCert providerCert) {
|
||||||
|
FirstCertProvider.providerCert.set(providerCert);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setCert(Cert cert) {
|
||||||
|
FirstCertProvider.cert.set(cert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,124 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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.apache.dubbo.common.ssl;
|
||||||
|
|
||||||
|
import org.apache.dubbo.common.URL;
|
||||||
|
import org.apache.dubbo.common.ssl.impl.SSLConfigCertProvider;
|
||||||
|
import org.apache.dubbo.common.utils.IOUtils;
|
||||||
|
import org.apache.dubbo.config.SslConfig;
|
||||||
|
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||||
|
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
class SSLConfigCertProviderTest {
|
||||||
|
@Test
|
||||||
|
void testSupported() {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
ApplicationModel applicationModel = frameworkModel.newApplication();
|
||||||
|
SSLConfigCertProvider sslConfigCertProvider = new SSLConfigCertProvider();
|
||||||
|
|
||||||
|
URL url = URL.valueOf("").setScopeModel(applicationModel);
|
||||||
|
Assertions.assertFalse(sslConfigCertProvider.isSupport(url));
|
||||||
|
|
||||||
|
SslConfig sslConfig = new SslConfig();
|
||||||
|
applicationModel.getApplicationConfigManager().setSsl(sslConfig);
|
||||||
|
Assertions.assertTrue(sslConfigCertProvider.isSupport(url));
|
||||||
|
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetProviderConnectionConfig() throws IOException {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
ApplicationModel applicationModel = frameworkModel.newApplication();
|
||||||
|
SSLConfigCertProvider sslConfigCertProvider = new SSLConfigCertProvider();
|
||||||
|
|
||||||
|
URL url = URL.valueOf("").setScopeModel(applicationModel);
|
||||||
|
Assertions.assertNull(sslConfigCertProvider.getProviderConnectionConfig(url));
|
||||||
|
|
||||||
|
SslConfig sslConfig = new SslConfig();
|
||||||
|
sslConfig.setServerKeyCertChainPath("keyCert");
|
||||||
|
sslConfig.setServerPrivateKeyPath("private");
|
||||||
|
applicationModel.getApplicationConfigManager().setSsl(sslConfig);
|
||||||
|
ProviderCert providerCert = sslConfigCertProvider.getProviderConnectionConfig(url);
|
||||||
|
Assertions.assertNull(providerCert);
|
||||||
|
|
||||||
|
sslConfig.setServerKeyCertChainPath(this.getClass().getClassLoader().getResource("certs/cert.pem").getFile());
|
||||||
|
sslConfig.setServerPrivateKeyPath(this.getClass().getClassLoader().getResource("certs/key.pem").getFile());
|
||||||
|
providerCert = sslConfigCertProvider.getProviderConnectionConfig(url);
|
||||||
|
Assertions.assertNotNull(providerCert);
|
||||||
|
Assertions.assertArrayEquals(IOUtils.toByteArray(this.getClass().getClassLoader().getResourceAsStream("certs/cert.pem")),
|
||||||
|
providerCert.getKeyCertChain());
|
||||||
|
Assertions.assertArrayEquals(IOUtils.toByteArray(this.getClass().getClassLoader().getResourceAsStream("certs/key.pem")),
|
||||||
|
providerCert.getPrivateKey());
|
||||||
|
Assertions.assertNull(providerCert.getTrustCert());
|
||||||
|
|
||||||
|
sslConfig.setServerTrustCertCollectionPath(this.getClass().getClassLoader().getResource("certs/ca.pem").getFile());
|
||||||
|
providerCert = sslConfigCertProvider.getProviderConnectionConfig(url);
|
||||||
|
Assertions.assertNotNull(providerCert);
|
||||||
|
Assertions.assertArrayEquals(IOUtils.toByteArray(this.getClass().getClassLoader().getResourceAsStream("certs/cert.pem")),
|
||||||
|
providerCert.getKeyCertChain());
|
||||||
|
Assertions.assertArrayEquals(IOUtils.toByteArray(this.getClass().getClassLoader().getResourceAsStream("certs/key.pem")),
|
||||||
|
providerCert.getPrivateKey());
|
||||||
|
Assertions.assertArrayEquals(IOUtils.toByteArray(this.getClass().getClassLoader().getResourceAsStream("certs/ca.pem")),
|
||||||
|
providerCert.getTrustCert());
|
||||||
|
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetConsumerConnectionConfig() throws IOException {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
ApplicationModel applicationModel = frameworkModel.newApplication();
|
||||||
|
SSLConfigCertProvider sslConfigCertProvider = new SSLConfigCertProvider();
|
||||||
|
|
||||||
|
URL url = URL.valueOf("").setScopeModel(applicationModel);
|
||||||
|
Assertions.assertNull(sslConfigCertProvider.getConsumerConnectionConfig(url));
|
||||||
|
|
||||||
|
SslConfig sslConfig = new SslConfig();
|
||||||
|
sslConfig.setClientKeyCertChainPath("keyCert");
|
||||||
|
sslConfig.setClientPrivateKeyPath("private");
|
||||||
|
applicationModel.getApplicationConfigManager().setSsl(sslConfig);
|
||||||
|
Cert cert = sslConfigCertProvider.getConsumerConnectionConfig(url);
|
||||||
|
Assertions.assertNull(cert);
|
||||||
|
|
||||||
|
sslConfig.setClientKeyCertChainPath(this.getClass().getClassLoader().getResource("certs/cert.pem").getFile());
|
||||||
|
sslConfig.setClientPrivateKeyPath(this.getClass().getClassLoader().getResource("certs/key.pem").getFile());
|
||||||
|
cert = sslConfigCertProvider.getConsumerConnectionConfig(url);
|
||||||
|
Assertions.assertNotNull(cert);
|
||||||
|
Assertions.assertArrayEquals(IOUtils.toByteArray(this.getClass().getClassLoader().getResourceAsStream("certs/cert.pem")),
|
||||||
|
cert.getKeyCertChain());
|
||||||
|
Assertions.assertArrayEquals(IOUtils.toByteArray(this.getClass().getClassLoader().getResourceAsStream("certs/key.pem")),
|
||||||
|
cert.getPrivateKey());
|
||||||
|
|
||||||
|
sslConfig.setClientTrustCertCollectionPath(this.getClass().getClassLoader().getResource("certs/ca.pem").getFile());
|
||||||
|
cert = sslConfigCertProvider.getConsumerConnectionConfig(url);
|
||||||
|
Assertions.assertNotNull(cert);
|
||||||
|
Assertions.assertArrayEquals(IOUtils.toByteArray(this.getClass().getClassLoader().getResourceAsStream("certs/cert.pem")),
|
||||||
|
cert.getKeyCertChain());
|
||||||
|
Assertions.assertArrayEquals(IOUtils.toByteArray(this.getClass().getClassLoader().getResourceAsStream("certs/key.pem")),
|
||||||
|
cert.getPrivateKey());
|
||||||
|
Assertions.assertArrayEquals(IOUtils.toByteArray(this.getClass().getClassLoader().getResourceAsStream("certs/ca.pem")),
|
||||||
|
cert.getTrustCert());
|
||||||
|
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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.apache.dubbo.common.ssl;
|
||||||
|
|
||||||
|
import org.apache.dubbo.common.URL;
|
||||||
|
import org.apache.dubbo.common.extension.Activate;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
@Activate(order = 10000)
|
||||||
|
public class SecondCertProvider implements CertProvider {
|
||||||
|
private static final AtomicBoolean isSupport = new AtomicBoolean(false);
|
||||||
|
private static final AtomicReference<ProviderCert> providerCert = new AtomicReference<>();
|
||||||
|
private static final AtomicReference<Cert> cert = new AtomicReference<>();
|
||||||
|
@Override
|
||||||
|
public boolean isSupport(URL address) {
|
||||||
|
return isSupport.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProviderCert getProviderConnectionConfig(URL localAddress) {
|
||||||
|
return providerCert.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cert getConsumerConnectionConfig(URL remoteAddress) {
|
||||||
|
return cert.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setSupport(boolean support) {
|
||||||
|
isSupport.set(support);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setProviderCert(ProviderCert providerCert) {
|
||||||
|
SecondCertProvider.providerCert.set(providerCert);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setCert(Cert cert) {
|
||||||
|
SecondCertProvider.cert.set(cert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
first=org.apache.dubbo.common.ssl.FirstCertProvider
|
||||||
|
second=org.apache.dubbo.common.ssl.SecondCertProvider
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
|
||||||
|
BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
|
||||||
|
aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla
|
||||||
|
Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0
|
||||||
|
YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT
|
||||||
|
BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7
|
||||||
|
+L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu
|
||||||
|
g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd
|
||||||
|
Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV
|
||||||
|
HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau
|
||||||
|
sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m
|
||||||
|
oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG
|
||||||
|
Dfcog5wrJytaQ6UA0wE=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIC6TCCAlKgAwIBAgIBCjANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET
|
||||||
|
MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
|
||||||
|
dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTEwMDEwOTU4WhcNMjUxMTA3
|
||||||
|
MDEwOTU4WjBaMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8G
|
||||||
|
A1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRMwEQYDVQQDDAp0ZXN0Y2xp
|
||||||
|
ZW50MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDsVEfbob4W3lVCDLOVmx9K
|
||||||
|
cdJnoZdvurGaTY87xNiopmaR8zCR7pFR9BX5L4bNG/PkuVLfVTVAKndyDCQggBBr
|
||||||
|
UTaEITNbfWK9swHJEr20WnKfhS/wo/Xg5sqNNCrFRmnnnwOA4eDlvmYZEzSnJXV6
|
||||||
|
pEro9bBH9uOCWWLqmaev7QIDAQABo4HCMIG/MAkGA1UdEwQCMAAwCwYDVR0PBAQD
|
||||||
|
AgXgMB0GA1UdDgQWBBQAdbW5Vml/CnYwqdP3mOHDARU+8zBwBgNVHSMEaTBnoVqk
|
||||||
|
WDBWMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMY
|
||||||
|
SW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2GCCQCRxhke
|
||||||
|
HRoqBzAJBgNVHREEAjAAMAkGA1UdEgQCMAAwDQYJKoZIhvcNAQELBQADgYEAf4MM
|
||||||
|
k+sdzd720DfrQ0PF2gDauR3M9uBubozDuMuF6ufAuQBJSKGQEGibXbUelrwHmnql
|
||||||
|
UjTyfolVcxEBVaF4VFHmn7u6vP7S1NexIDdNUHcULqxIb7Tzl8JYq8OOHD2rQy4H
|
||||||
|
s8BXaVIzw4YcaCGAMS0iDX052Sy7e2JhP8Noxvo=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAOxUR9uhvhbeVUIM
|
||||||
|
s5WbH0px0mehl2+6sZpNjzvE2KimZpHzMJHukVH0Ffkvhs0b8+S5Ut9VNUAqd3IM
|
||||||
|
JCCAEGtRNoQhM1t9Yr2zAckSvbRacp+FL/Cj9eDmyo00KsVGaeefA4Dh4OW+ZhkT
|
||||||
|
NKcldXqkSuj1sEf244JZYuqZp6/tAgMBAAECgYEAi2NSVqpZMafE5YYUTcMGe6QS
|
||||||
|
k2jtpsqYgggI2RnLJ/2tNZwYI5pwP8QVSbnMaiF4gokD5hGdrNDfTnb2v+yIwYEH
|
||||||
|
0w8+oG7Z81KodsiZSIDJfTGsAZhVNwOz9y0VD8BBZZ1/274Zh52AUKLjZS/ZwIbS
|
||||||
|
W2ywya855dPnH/wj+0ECQQD9X8D920kByTNHhBG18biAEZ4pxs9f0OAG8333eVcI
|
||||||
|
w2lJDLsYDZrCB2ocgA3lUdozlzPC7YDYw8reg0tkiRY5AkEA7sdNzOeQsQRn7++5
|
||||||
|
0bP9DtT/iON1gbfxRzCfCfXdoOtfQWIzTePWtURt9X/5D9NofI0Rg5W2oGy/MLe5
|
||||||
|
/sXHVQJBAIup5XrJDkQywNZyAUU2ecn2bCWBFjwtqd+LBmuMciI9fOKsZtEKZrz/
|
||||||
|
U0lkeMRoSwvXE8wmGLjjrAbdfohrXFkCQQDZEx/LtIl6JINJQiswVe0tWr6k+ASP
|
||||||
|
1WXoTm+HYpoF/XUvv9LccNF1IazFj34hwRQwhx7w/V52Ieb+p0jUMYGxAkEAjDhd
|
||||||
|
9pBO1fKXWiXzi9ZKfoyTNcUq3eBSVKwPG2nItg5ycXengjT5sgcWDnciIzW7BIVI
|
||||||
|
JiqOszq9GWESErAatg==
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
|
@ -243,6 +243,13 @@
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.dubbo</groupId>
|
||||||
|
<artifactId>dubbo-security</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.dubbo</groupId>
|
<groupId>org.apache.dubbo</groupId>
|
||||||
<artifactId>dubbo-reactive</artifactId>
|
<artifactId>dubbo-reactive</artifactId>
|
||||||
|
|
@ -515,6 +522,7 @@
|
||||||
<include>org.apache.dubbo:dubbo-monitor-api</include>
|
<include>org.apache.dubbo:dubbo-monitor-api</include>
|
||||||
<include>org.apache.dubbo:dubbo-monitor-default</include>
|
<include>org.apache.dubbo:dubbo-monitor-default</include>
|
||||||
<include>org.apache.dubbo:dubbo-qos</include>
|
<include>org.apache.dubbo:dubbo-qos</include>
|
||||||
|
<include>org.apache.dubbo:dubbo-security</include>
|
||||||
<include>org.apache.dubbo:dubbo-reactive</include>
|
<include>org.apache.dubbo:dubbo-reactive</include>
|
||||||
<include>org.apache.dubbo:dubbo-spring-security</include>
|
<include>org.apache.dubbo:dubbo-spring-security</include>
|
||||||
<include>org.apache.dubbo:dubbo-registry-api</include>
|
<include>org.apache.dubbo:dubbo-registry-api</include>
|
||||||
|
|
@ -898,6 +906,12 @@
|
||||||
META-INF/dubbo/internal/org.apache.dubbo.registry.client.metadata.MetadataServiceURLBuilder
|
META-INF/dubbo/internal/org.apache.dubbo.registry.client.metadata.MetadataServiceURLBuilder
|
||||||
</resource>
|
</resource>
|
||||||
</transformer>
|
</transformer>
|
||||||
|
<transformer
|
||||||
|
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||||
|
<resource>
|
||||||
|
META-INF/dubbo/internal/org.apache.dubbo.common.ssl.CertProvider
|
||||||
|
</resource>
|
||||||
|
</transformer>
|
||||||
<transformer
|
<transformer
|
||||||
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
|
||||||
<resource>
|
<resource>
|
||||||
|
|
|
||||||
|
|
@ -299,6 +299,11 @@
|
||||||
<artifactId>dubbo-auth</artifactId>
|
<artifactId>dubbo-auth</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.dubbo</groupId>
|
||||||
|
<artifactId>dubbo-security</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.dubbo</groupId>
|
<groupId>org.apache.dubbo</groupId>
|
||||||
<artifactId>dubbo-qos</artifactId>
|
<artifactId>dubbo-qos</artifactId>
|
||||||
|
|
|
||||||
|
|
@ -2599,6 +2599,36 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "org.apache.dubbo.common.ssl.impl.SSLConfigCertProvider",
|
||||||
|
"allPublicMethods": true,
|
||||||
|
"methods": [
|
||||||
|
{
|
||||||
|
"name": "<init>",
|
||||||
|
"parameterTypes": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "org.apache.dubbo.security.cert.DubboCertManager",
|
||||||
|
"allPublicMethods": true,
|
||||||
|
"methods": [
|
||||||
|
{
|
||||||
|
"name": "<init>",
|
||||||
|
"parameterTypes": ["org.apache.dubbo.rpc.model.FrameworkModel"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "org.apache.dubbo.common.ssl.CertManager",
|
||||||
|
"allPublicMethods": true,
|
||||||
|
"methods": [
|
||||||
|
{
|
||||||
|
"name": "<init>",
|
||||||
|
"parameterTypes": ["org.apache.dubbo.rpc.model.FrameworkModel"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory"
|
"name": "org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -2599,6 +2599,36 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "org.apache.dubbo.common.ssl.impl.SSLConfigCertProvider",
|
||||||
|
"allPublicMethods": true,
|
||||||
|
"methods": [
|
||||||
|
{
|
||||||
|
"name": "<init>",
|
||||||
|
"parameterTypes": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "org.apache.dubbo.security.cert.DubboCertManager",
|
||||||
|
"allPublicMethods": true,
|
||||||
|
"methods": [
|
||||||
|
{
|
||||||
|
"name": "<init>",
|
||||||
|
"parameterTypes": ["org.apache.dubbo.rpc.model.FrameworkModel"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "org.apache.dubbo.common.ssl.CertManager",
|
||||||
|
"allPublicMethods": true,
|
||||||
|
"methods": [
|
||||||
|
{
|
||||||
|
"name": "<init>",
|
||||||
|
"parameterTypes": ["org.apache.dubbo.rpc.model.FrameworkModel"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory"
|
"name": "org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
<!--
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You 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.
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<groupId>org.apache.dubbo</groupId>
|
||||||
|
<artifactId>dubbo-plugin</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<skip_maven_deploy>false</skip_maven_deploy>
|
||||||
|
<protobuf-java.version>3.21.12</protobuf-java.version>
|
||||||
|
<grpc.version>1.41.0</grpc.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<artifactId>dubbo-security</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- dubbo -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.dubbo</groupId>
|
||||||
|
<artifactId>dubbo-rpc-api</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.dubbo</groupId>
|
||||||
|
<artifactId>dubbo-rpc-triple</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.dubbo</groupId>
|
||||||
|
<artifactId>dubbo-common</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- dubbo -->
|
||||||
|
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.grpc</groupId>
|
||||||
|
<artifactId>grpc-protobuf</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.grpc</groupId>
|
||||||
|
<artifactId>grpc-stub</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.grpc</groupId>
|
||||||
|
<artifactId>grpc-netty-shaded</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.protobuf</groupId>
|
||||||
|
<artifactId>protobuf-java</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.protobuf</groupId>
|
||||||
|
<artifactId>protobuf-java-util</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcprov-jdk15on</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcpkix-jdk15on</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcprov-ext-jdk15on</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- test -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.dubbo</groupId>
|
||||||
|
<artifactId>dubbo-config-api</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<extensions>
|
||||||
|
<extension>
|
||||||
|
<groupId>kr.motd.maven</groupId>
|
||||||
|
<artifactId>os-maven-plugin</artifactId>
|
||||||
|
<version>1.6.2</version>
|
||||||
|
</extension>
|
||||||
|
</extensions>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.xolstice.maven.plugins</groupId>
|
||||||
|
<artifactId>protobuf-maven-plugin</artifactId>
|
||||||
|
<version>0.6.1</version>
|
||||||
|
<configuration>
|
||||||
|
<protocArtifact>com.google.protobuf:protoc:${protobuf-java.version}:exe:${os.detected.classifier}</protocArtifact>
|
||||||
|
<pluginId>grpc-java</pluginId>
|
||||||
|
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>compile</goal>
|
||||||
|
<goal>compile-custom</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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.apache.dubbo.security.cert;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static org.apache.dubbo.security.cert.Constants.DEFAULT_REFRESH_INTERVAL;
|
||||||
|
|
||||||
|
public class CertConfig {
|
||||||
|
private final String remoteAddress;
|
||||||
|
private final String envType;
|
||||||
|
private final String caCertPath;
|
||||||
|
/**
|
||||||
|
* Path to OpenID Connect Token file
|
||||||
|
*/
|
||||||
|
private final String oidcTokenPath;
|
||||||
|
|
||||||
|
private final int refreshInterval;
|
||||||
|
|
||||||
|
public CertConfig(String remoteAddress, String envType, String caCertPath, String oidcTokenPath) {
|
||||||
|
this(remoteAddress, envType, caCertPath, oidcTokenPath, DEFAULT_REFRESH_INTERVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CertConfig(String remoteAddress, String envType, String caCertPath, String oidcTokenPath, int refreshInterval) {
|
||||||
|
this.remoteAddress = remoteAddress;
|
||||||
|
this.envType = envType;
|
||||||
|
this.caCertPath = caCertPath;
|
||||||
|
this.oidcTokenPath = oidcTokenPath;
|
||||||
|
this.refreshInterval = refreshInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRemoteAddress() {
|
||||||
|
return remoteAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEnvType() {
|
||||||
|
return envType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCaCertPath() {
|
||||||
|
return caCertPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOidcTokenPath() {
|
||||||
|
return oidcTokenPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRefreshInterval() {
|
||||||
|
return refreshInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CertConfig that = (CertConfig) o;
|
||||||
|
return Objects.equals(remoteAddress, that.remoteAddress) && Objects.equals(envType, that.envType) && Objects.equals(caCertPath, that.caCertPath) && Objects.equals(oidcTokenPath, that.oidcTokenPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(remoteAddress, envType, caCertPath, oidcTokenPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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.apache.dubbo.security.cert;
|
||||||
|
|
||||||
|
import org.apache.dubbo.common.deploy.ApplicationDeployListener;
|
||||||
|
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||||
|
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class CertDeployerListener implements ApplicationDeployListener {
|
||||||
|
private final DubboCertManager dubboCertManager;
|
||||||
|
|
||||||
|
|
||||||
|
public CertDeployerListener(FrameworkModel frameworkModel) {
|
||||||
|
dubboCertManager = frameworkModel.getBeanFactory().getBean(DubboCertManager.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStarting(ApplicationModel scopeModel) {
|
||||||
|
scopeModel.getApplicationConfigManager().getSsl().ifPresent(sslConfig -> {
|
||||||
|
if (Objects.nonNull(sslConfig.getCaAddress()) && dubboCertManager != null) {
|
||||||
|
CertConfig certConfig = new CertConfig(sslConfig.getCaAddress(),
|
||||||
|
sslConfig.getEnvType(),
|
||||||
|
sslConfig.getCaCertPath(),
|
||||||
|
sslConfig.getOidcTokenPath());
|
||||||
|
dubboCertManager.connect(certConfig);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStarted(ApplicationModel scopeModel) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStopping(ApplicationModel scopeModel) {
|
||||||
|
dubboCertManager.disConnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStopped(ApplicationModel scopeModel) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(ApplicationModel scopeModel, Throwable cause) {
|
||||||
|
dubboCertManager.disConnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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.apache.dubbo.security.cert;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class CertPair {
|
||||||
|
private final String privateKey;
|
||||||
|
private final String certificate;
|
||||||
|
private final String trustCerts;
|
||||||
|
private final long expireTime;
|
||||||
|
|
||||||
|
public CertPair(String privateKey, String certificate, String trustCerts, long expireTime) {
|
||||||
|
this.privateKey = privateKey;
|
||||||
|
this.certificate = certificate;
|
||||||
|
this.trustCerts = trustCerts;
|
||||||
|
this.expireTime = expireTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPrivateKey() {
|
||||||
|
return privateKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCertificate() {
|
||||||
|
return certificate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTrustCerts() {
|
||||||
|
return trustCerts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getExpireTime() {
|
||||||
|
return expireTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isExpire() {
|
||||||
|
return System.currentTimeMillis() > expireTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CertPair certPair = (CertPair) o;
|
||||||
|
return expireTime == certPair.expireTime && Objects.equals(privateKey, certPair.privateKey) && Objects.equals(certificate, certPair.certificate) && Objects.equals(trustCerts, certPair.trustCerts);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(privateKey, certificate, trustCerts, expireTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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.apache.dubbo.security.cert;
|
||||||
|
|
||||||
|
import org.apache.dubbo.common.beans.factory.ScopeBeanFactory;
|
||||||
|
import org.apache.dubbo.common.utils.ClassUtils;
|
||||||
|
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||||
|
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||||
|
import org.apache.dubbo.rpc.model.ModuleModel;
|
||||||
|
import org.apache.dubbo.rpc.model.ScopeModelInitializer;
|
||||||
|
|
||||||
|
public class CertScopeModelInitializer implements ScopeModelInitializer {
|
||||||
|
public static boolean isSupported() {
|
||||||
|
try {
|
||||||
|
ClassUtils.forName("io.grpc.Channel");
|
||||||
|
ClassUtils.forName("org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder");
|
||||||
|
return true;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initializeFrameworkModel(FrameworkModel frameworkModel) {
|
||||||
|
ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory();
|
||||||
|
if (isSupported()) {
|
||||||
|
beanFactory.registerBean(DubboCertManager.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initializeApplicationModel(ApplicationModel applicationModel) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initializeModuleModel(ModuleModel moduleModel) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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.apache.dubbo.security.cert;
|
||||||
|
|
||||||
|
public interface Constants {
|
||||||
|
int DEFAULT_REFRESH_INTERVAL = 30_000;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,377 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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.apache.dubbo.security.cert;
|
||||||
|
|
||||||
|
import org.apache.dubbo.auth.v1alpha1.DubboCertificateRequest;
|
||||||
|
import org.apache.dubbo.auth.v1alpha1.DubboCertificateResponse;
|
||||||
|
import org.apache.dubbo.auth.v1alpha1.DubboCertificateServiceGrpc;
|
||||||
|
import org.apache.dubbo.common.constants.LoggerCodeConstants;
|
||||||
|
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
||||||
|
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||||
|
import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;
|
||||||
|
import org.apache.dubbo.common.utils.IOUtils;
|
||||||
|
import org.apache.dubbo.common.utils.StringUtils;
|
||||||
|
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||||
|
|
||||||
|
import io.grpc.Channel;
|
||||||
|
import io.grpc.Metadata;
|
||||||
|
import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts;
|
||||||
|
import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder;
|
||||||
|
import io.grpc.netty.shaded.io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name;
|
||||||
|
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
|
||||||
|
import org.bouncycastle.operator.ContentSigner;
|
||||||
|
import org.bouncycastle.operator.OperatorCreationException;
|
||||||
|
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||||
|
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
|
||||||
|
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
|
||||||
|
import org.bouncycastle.util.io.pem.PemObject;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
|
import java.security.KeyPairGenerator;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.PrivateKey;
|
||||||
|
import java.security.PublicKey;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.spec.ECGenParameterSpec;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static io.grpc.stub.MetadataUtils.newAttachHeadersInterceptor;
|
||||||
|
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_SSL_CERT_GENERATE_FAILED;
|
||||||
|
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_SSL_CONNECT_INSECURE;
|
||||||
|
import static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;
|
||||||
|
import static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_GENERATE_CERT_ISTIO;
|
||||||
|
|
||||||
|
public class DubboCertManager {
|
||||||
|
|
||||||
|
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(DubboCertManager.class);
|
||||||
|
|
||||||
|
private final FrameworkModel frameworkModel;
|
||||||
|
/**
|
||||||
|
* gRPC channel to Dubbo Cert Authority server
|
||||||
|
*/
|
||||||
|
protected volatile Channel channel;
|
||||||
|
/**
|
||||||
|
* Cert pair for current Dubbo instance
|
||||||
|
*/
|
||||||
|
protected volatile CertPair certPair;
|
||||||
|
/**
|
||||||
|
* Path to OpenID Connect Token file
|
||||||
|
*/
|
||||||
|
protected volatile CertConfig certConfig;
|
||||||
|
/**
|
||||||
|
* Refresh cert pair for current Dubbo instance
|
||||||
|
*/
|
||||||
|
protected volatile ScheduledFuture<?> refreshFuture;
|
||||||
|
|
||||||
|
public DubboCertManager(FrameworkModel frameworkModel) {
|
||||||
|
this.frameworkModel = frameworkModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void connect(CertConfig certConfig) {
|
||||||
|
if (channel != null) {
|
||||||
|
logger.error(INTERNAL_ERROR, "", "", "Dubbo Cert Authority server is already connected.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (certConfig == null) {
|
||||||
|
// No cert config, return
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(certConfig.getRemoteAddress())) {
|
||||||
|
// No remote address configured, return
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotEmpty(certConfig.getEnvType()) && !"Kubernetes".equalsIgnoreCase(certConfig.getEnvType())) {
|
||||||
|
throw new IllegalArgumentException("Only support Kubernetes env now.");
|
||||||
|
}
|
||||||
|
// Create gRPC connection
|
||||||
|
connect0(certConfig);
|
||||||
|
|
||||||
|
this.certConfig = certConfig;
|
||||||
|
|
||||||
|
// Try to generate cert from remote
|
||||||
|
generateCert();
|
||||||
|
// Schedule refresh task
|
||||||
|
scheduleRefresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create task to refresh cert pair for current Dubbo instance
|
||||||
|
*/
|
||||||
|
protected void scheduleRefresh() {
|
||||||
|
FrameworkExecutorRepository repository = frameworkModel.getBeanFactory().getBean(FrameworkExecutorRepository.class);
|
||||||
|
refreshFuture = repository.getSharedScheduledExecutor().scheduleAtFixedRate(this::generateCert,
|
||||||
|
certConfig.getRefreshInterval(), certConfig.getRefreshInterval(), TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to connect to remote certificate authorization
|
||||||
|
*
|
||||||
|
* @param certConfig certificate authorization address
|
||||||
|
*/
|
||||||
|
protected void connect0(CertConfig certConfig) {
|
||||||
|
String caCertPath = certConfig.getCaCertPath();
|
||||||
|
String remoteAddress = certConfig.getRemoteAddress();
|
||||||
|
logger.info("Try to connect to Dubbo Cert Authority server: " + remoteAddress + ", caCertPath: " + remoteAddress);
|
||||||
|
try {
|
||||||
|
if (StringUtils.isNotEmpty(caCertPath)) {
|
||||||
|
channel = NettyChannelBuilder.forTarget(remoteAddress)
|
||||||
|
.sslContext(
|
||||||
|
GrpcSslContexts.forClient()
|
||||||
|
.trustManager(new File(caCertPath))
|
||||||
|
.build())
|
||||||
|
.build();
|
||||||
|
} else {
|
||||||
|
logger.warn(CONFIG_SSL_CONNECT_INSECURE, "", "",
|
||||||
|
"No caCertPath is provided, will use insecure connection.");
|
||||||
|
channel = NettyChannelBuilder.forTarget(remoteAddress)
|
||||||
|
.sslContext(GrpcSslContexts.forClient()
|
||||||
|
.trustManager(InsecureTrustManagerFactory.INSTANCE)
|
||||||
|
.build())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error(LoggerCodeConstants.CONFIG_SSL_PATH_LOAD_FAILED, "", "", "Failed to load SSL cert file.", e);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void disConnect() {
|
||||||
|
if (refreshFuture != null) {
|
||||||
|
refreshFuture.cancel(true);
|
||||||
|
refreshFuture = null;
|
||||||
|
}
|
||||||
|
if (channel != null) {
|
||||||
|
channel = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isConnected() {
|
||||||
|
return certConfig != null && channel != null && certPair != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CertPair generateCert() {
|
||||||
|
if (certPair != null && !certPair.isExpire()) {
|
||||||
|
return certPair;
|
||||||
|
}
|
||||||
|
synchronized (this) {
|
||||||
|
if (certPair == null || certPair.isExpire()) {
|
||||||
|
try {
|
||||||
|
logger.info("Try to generate cert from Dubbo Certificate Authority.");
|
||||||
|
CertPair certFromRemote = refreshCert();
|
||||||
|
if (certFromRemote != null) {
|
||||||
|
certPair = certFromRemote;
|
||||||
|
} else {
|
||||||
|
logger.error(CONFIG_SSL_CERT_GENERATE_FAILED, "", "", "Generate Cert from Dubbo Certificate Authority failed.");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error(REGISTRY_FAILED_GENERATE_CERT_ISTIO, "", "", "Generate Cert from Istio failed.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return certPair;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request remote certificate authorization to generate cert pair for current Dubbo instance
|
||||||
|
*
|
||||||
|
* @return cert pair
|
||||||
|
* @throws IOException ioException
|
||||||
|
*/
|
||||||
|
protected CertPair refreshCert() throws IOException {
|
||||||
|
KeyPair keyPair = signWithEcdsa();
|
||||||
|
|
||||||
|
if (keyPair == null) {
|
||||||
|
keyPair = signWithRsa();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyPair == null) {
|
||||||
|
logger.error(CONFIG_SSL_CERT_GENERATE_FAILED, "", "", "Generate Key failed. Please check if your system support.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String csr = generateCsr(keyPair);
|
||||||
|
DubboCertificateServiceGrpc.DubboCertificateServiceBlockingStub stub = DubboCertificateServiceGrpc.newBlockingStub(channel);
|
||||||
|
stub = setHeaderIfNeed(stub);
|
||||||
|
|
||||||
|
String privateKeyPem = generatePrivatePemKey(keyPair);
|
||||||
|
DubboCertificateResponse certificateResponse = stub.createCertificate(generateRequest(csr));
|
||||||
|
|
||||||
|
if (certificateResponse == null || !certificateResponse.getSuccess()) {
|
||||||
|
logger.error(CONFIG_SSL_CERT_GENERATE_FAILED, "", "", "Failed to generate cert from Dubbo Certificate Authority. " +
|
||||||
|
"Message: " + (certificateResponse == null ? "null" : certificateResponse.getMessage()));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
logger.info("Successfully generate cert from Dubbo Certificate Authority. Cert expire time: " + certificateResponse.getExpireTime());
|
||||||
|
|
||||||
|
return new CertPair(privateKeyPem,
|
||||||
|
certificateResponse.getCertPem(),
|
||||||
|
String.join("\n", certificateResponse.getTrustCertsList()),
|
||||||
|
certificateResponse.getExpireTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
private DubboCertificateServiceGrpc.DubboCertificateServiceBlockingStub setHeaderIfNeed(DubboCertificateServiceGrpc.DubboCertificateServiceBlockingStub stub) throws IOException {
|
||||||
|
String oidcTokenPath = certConfig.getOidcTokenPath();
|
||||||
|
if (StringUtils.isNotEmpty(oidcTokenPath)) {
|
||||||
|
Metadata header = new Metadata();
|
||||||
|
Metadata.Key<String> key = Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER);
|
||||||
|
header.put(key, "Bearer " +
|
||||||
|
IOUtils.read(new FileReader(oidcTokenPath))
|
||||||
|
.replace("\n", "")
|
||||||
|
.replace("\t", "")
|
||||||
|
.replace("\r", "")
|
||||||
|
.trim());
|
||||||
|
|
||||||
|
stub = stub.withInterceptors(newAttachHeadersInterceptor(header));
|
||||||
|
logger.info("Use oidc token from " + oidcTokenPath + " to connect to Dubbo Certificate Authority.");
|
||||||
|
} else {
|
||||||
|
logger.warn(CONFIG_SSL_CONNECT_INSECURE, "", "",
|
||||||
|
"Use insecure connection to connect to Dubbo Certificate Authority. Reason: No oidc token is provided.");
|
||||||
|
}
|
||||||
|
return stub;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate key pair with RSA
|
||||||
|
*
|
||||||
|
* @return key pair
|
||||||
|
*/
|
||||||
|
protected static KeyPair signWithRsa() {
|
||||||
|
KeyPair keyPair = null;
|
||||||
|
try {
|
||||||
|
KeyPairGenerator kpGenerator = KeyPairGenerator.getInstance("RSA");
|
||||||
|
kpGenerator.initialize(4096);
|
||||||
|
java.security.KeyPair keypair = kpGenerator.generateKeyPair();
|
||||||
|
PublicKey publicKey = keypair.getPublic();
|
||||||
|
PrivateKey privateKey = keypair.getPrivate();
|
||||||
|
ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSA").build(keypair.getPrivate());
|
||||||
|
keyPair = new KeyPair(publicKey, privateKey, signer);
|
||||||
|
} catch (NoSuchAlgorithmException | OperatorCreationException e) {
|
||||||
|
logger.error(CONFIG_SSL_CERT_GENERATE_FAILED, "", "", "Generate Key with SHA256WithRSA algorithm failed. Please check if your system support.", e);
|
||||||
|
}
|
||||||
|
return keyPair;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate key pair with ECDSA
|
||||||
|
*
|
||||||
|
* @return key pair
|
||||||
|
*/
|
||||||
|
protected static KeyPair signWithEcdsa() {
|
||||||
|
KeyPair keyPair = null;
|
||||||
|
try {
|
||||||
|
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
|
||||||
|
KeyPairGenerator g = KeyPairGenerator.getInstance("EC");
|
||||||
|
g.initialize(ecSpec, new SecureRandom());
|
||||||
|
java.security.KeyPair keypair = g.generateKeyPair();
|
||||||
|
PublicKey publicKey = keypair.getPublic();
|
||||||
|
PrivateKey privateKey = keypair.getPrivate();
|
||||||
|
ContentSigner signer = new JcaContentSignerBuilder("SHA256withECDSA").build(privateKey);
|
||||||
|
keyPair = new KeyPair(publicKey, privateKey, signer);
|
||||||
|
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | OperatorCreationException e) {
|
||||||
|
logger.error(CONFIG_SSL_CERT_GENERATE_FAILED, "", "", "Generate Key with secp256r1 algorithm failed. Please check if your system support. "
|
||||||
|
+ "Will attempt to generate with RSA2048.", e);
|
||||||
|
}
|
||||||
|
return keyPair;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DubboCertificateRequest generateRequest(String csr) {
|
||||||
|
return DubboCertificateRequest.newBuilder().setCsr(csr).setType("CONNECTION").build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate private key in pem encoded
|
||||||
|
*
|
||||||
|
* @param keyPair key pair
|
||||||
|
* @return private key
|
||||||
|
* @throws IOException ioException
|
||||||
|
*/
|
||||||
|
private String generatePrivatePemKey(KeyPair keyPair) throws IOException {
|
||||||
|
String key = generatePemKey("RSA PRIVATE KEY", keyPair.getPrivateKey().getEncoded());
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Generated Private Key. \n" + key);
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate content in pem encoded
|
||||||
|
*
|
||||||
|
* @param type content type
|
||||||
|
* @param content content
|
||||||
|
* @return encoded data
|
||||||
|
* @throws IOException ioException
|
||||||
|
*/
|
||||||
|
private String generatePemKey(String type, byte[] content) throws IOException {
|
||||||
|
PemObject pemObject = new PemObject(type, content);
|
||||||
|
StringWriter str = new StringWriter();
|
||||||
|
JcaPEMWriter jcaPEMWriter = new JcaPEMWriter(str);
|
||||||
|
jcaPEMWriter.writeObject(pemObject);
|
||||||
|
jcaPEMWriter.close();
|
||||||
|
str.close();
|
||||||
|
return str.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate CSR (Certificate Sign Request)
|
||||||
|
*
|
||||||
|
* @param keyPair key pair to request
|
||||||
|
* @return csr
|
||||||
|
* @throws IOException ioException
|
||||||
|
*/
|
||||||
|
private String generateCsr(KeyPair keyPair) throws IOException {
|
||||||
|
PKCS10CertificationRequest request = new JcaPKCS10CertificationRequestBuilder(
|
||||||
|
new X500Name("O=" + "cluster.domain"), keyPair.getPublicKey())
|
||||||
|
.build(keyPair.getSigner());
|
||||||
|
|
||||||
|
String csr = generatePemKey("CERTIFICATE REQUEST", request.getEncoded());
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("CSR Request to Dubbo Certificate Authorization. \n" + csr);
|
||||||
|
}
|
||||||
|
return csr;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class KeyPair {
|
||||||
|
private final PublicKey publicKey;
|
||||||
|
private final PrivateKey privateKey;
|
||||||
|
private final ContentSigner signer;
|
||||||
|
|
||||||
|
public KeyPair(PublicKey publicKey, PrivateKey privateKey, ContentSigner signer) {
|
||||||
|
this.publicKey = publicKey;
|
||||||
|
this.privateKey = privateKey;
|
||||||
|
this.signer = signer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PublicKey getPublicKey() {
|
||||||
|
return publicKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrivateKey getPrivateKey() {
|
||||||
|
return privateKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContentSigner getSigner() {
|
||||||
|
return signer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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.apache.dubbo.security.cert;
|
||||||
|
|
||||||
|
import org.apache.dubbo.common.URL;
|
||||||
|
import org.apache.dubbo.common.extension.Activate;
|
||||||
|
import org.apache.dubbo.common.ssl.AuthPolicy;
|
||||||
|
import org.apache.dubbo.common.ssl.Cert;
|
||||||
|
import org.apache.dubbo.common.ssl.CertProvider;
|
||||||
|
import org.apache.dubbo.common.ssl.ProviderCert;
|
||||||
|
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
@Activate
|
||||||
|
public class DubboCertProvider implements CertProvider {
|
||||||
|
private final DubboCertManager dubboCertManager;
|
||||||
|
|
||||||
|
|
||||||
|
public DubboCertProvider(FrameworkModel frameworkModel) {
|
||||||
|
dubboCertManager = frameworkModel.getBeanFactory().getBean(DubboCertManager.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSupport(URL address) {
|
||||||
|
return dubboCertManager != null && dubboCertManager.isConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProviderCert getProviderConnectionConfig(URL localAddress) {
|
||||||
|
CertPair certPair = dubboCertManager.generateCert();
|
||||||
|
if (certPair == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new ProviderCert(certPair.getCertificate().getBytes(StandardCharsets.UTF_8),
|
||||||
|
certPair.getPrivateKey().getBytes(StandardCharsets.UTF_8),
|
||||||
|
certPair.getTrustCerts().getBytes(StandardCharsets.UTF_8), AuthPolicy.NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cert getConsumerConnectionConfig(URL remoteAddress) {
|
||||||
|
CertPair certPair = dubboCertManager.generateCert();
|
||||||
|
if (certPair == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new Cert(certPair.getCertificate().getBytes(StandardCharsets.UTF_8),
|
||||||
|
certPair.getPrivateKey().getBytes(StandardCharsets.UTF_8),
|
||||||
|
certPair.getTrustCerts().getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
import "google/protobuf/struct.proto";
|
||||||
|
|
||||||
|
package org.apache.dubbo.auth.v1alpha1;
|
||||||
|
|
||||||
|
option go_package = "github.com/apache/dubbo-admin/ca/v1alpha1";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
|
|
||||||
|
message DubboCertificateRequest {
|
||||||
|
string csr = 1;
|
||||||
|
string type = 2;
|
||||||
|
|
||||||
|
google.protobuf.Struct metadata = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DubboCertificateResponse {
|
||||||
|
bool success = 1;
|
||||||
|
string cert_pem = 2;
|
||||||
|
repeated string trust_certs = 3;
|
||||||
|
int64 expire_time = 4;
|
||||||
|
string message = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
service DubboCertificateService {
|
||||||
|
rpc CreateCertificate(DubboCertificateRequest)
|
||||||
|
returns (DubboCertificateResponse) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
cert=org.apache.dubbo.security.cert.CertDeployerListener
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
dubbo=org.apache.dubbo.security.cert.DubboCertProvider
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
cert=org.apache.dubbo.security.cert.CertScopeModelInitializer
|
||||||
|
|
@ -0,0 +1,242 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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.apache.dubbo.security.cert;
|
||||||
|
|
||||||
|
import org.apache.dubbo.common.deploy.ApplicationDeployer;
|
||||||
|
import org.apache.dubbo.config.ApplicationConfig;
|
||||||
|
import org.apache.dubbo.config.MetadataReportConfig;
|
||||||
|
import org.apache.dubbo.config.SslConfig;
|
||||||
|
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||||
|
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Disabled;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.mockito.MockedConstruction;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
class CertDeployerListenerTest {
|
||||||
|
@Test
|
||||||
|
void testEmpty1() {
|
||||||
|
AtomicReference<DubboCertManager> reference = new AtomicReference<>();
|
||||||
|
try (MockedConstruction<DubboCertManager> construction =
|
||||||
|
Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {
|
||||||
|
reference.set(mock);
|
||||||
|
})) {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
ApplicationModel applicationModel = frameworkModel.newApplication();
|
||||||
|
applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig("test"));
|
||||||
|
applicationModel.getDeployer().start();
|
||||||
|
Mockito.verify(reference.get(), Mockito.times(0))
|
||||||
|
.connect(Mockito.any());
|
||||||
|
applicationModel.getDeployer().stop();
|
||||||
|
Mockito.verify(reference.get(), Mockito.atLeast(1)).disConnect();
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testEmpty2() {
|
||||||
|
AtomicReference<DubboCertManager> reference = new AtomicReference<>();
|
||||||
|
try (MockedConstruction<DubboCertManager> construction =
|
||||||
|
Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {
|
||||||
|
reference.set(mock);
|
||||||
|
})) {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
ApplicationModel applicationModel = frameworkModel.newApplication();
|
||||||
|
applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig("test"));
|
||||||
|
applicationModel.getApplicationConfigManager().setSsl(new SslConfig());
|
||||||
|
applicationModel.getDeployer().start();
|
||||||
|
Mockito.verify(reference.get(), Mockito.times(0))
|
||||||
|
.connect(Mockito.any());
|
||||||
|
applicationModel.getDeployer().stop();
|
||||||
|
Mockito.verify(reference.get(), Mockito.atLeast(1)).disConnect();
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCreate() {
|
||||||
|
AtomicReference<DubboCertManager> reference = new AtomicReference<>();
|
||||||
|
try (MockedConstruction<DubboCertManager> construction =
|
||||||
|
Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {
|
||||||
|
reference.set(mock);
|
||||||
|
})) {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
ApplicationModel applicationModel = frameworkModel.newApplication();
|
||||||
|
applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig("test"));
|
||||||
|
SslConfig sslConfig = new SslConfig();
|
||||||
|
sslConfig.setCaAddress("127.0.0.1:30060");
|
||||||
|
applicationModel.getApplicationConfigManager().setSsl(sslConfig);
|
||||||
|
|
||||||
|
applicationModel.getDeployer().start();
|
||||||
|
Mockito.verify(reference.get(), Mockito.times(1))
|
||||||
|
.connect(Mockito.any());
|
||||||
|
applicationModel.getDeployer().stop();
|
||||||
|
Mockito.verify(reference.get(), Mockito.atLeast(1))
|
||||||
|
.disConnect();
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFailure() {
|
||||||
|
AtomicReference<DubboCertManager> reference = new AtomicReference<>();
|
||||||
|
try (MockedConstruction<DubboCertManager> construction =
|
||||||
|
Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {
|
||||||
|
reference.set(mock);
|
||||||
|
})) {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
ApplicationModel applicationModel = frameworkModel.newApplication();
|
||||||
|
applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig("test"));
|
||||||
|
SslConfig sslConfig = new SslConfig();
|
||||||
|
sslConfig.setCaAddress("127.0.0.1:30060");
|
||||||
|
applicationModel.getApplicationConfigManager().setSsl(sslConfig);
|
||||||
|
applicationModel.getApplicationConfigManager().addMetadataReport(new MetadataReportConfig("absent"));
|
||||||
|
|
||||||
|
ApplicationDeployer deployer = applicationModel.getDeployer();
|
||||||
|
Assertions.assertThrows(IllegalArgumentException.class, deployer::start);
|
||||||
|
Mockito.verify(reference.get(), Mockito.times(1))
|
||||||
|
.connect(Mockito.any());
|
||||||
|
Mockito.verify(reference.get(), Mockito.atLeast(1))
|
||||||
|
.disConnect();
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testNotFound1() {
|
||||||
|
ClassLoader originClassLoader = Thread.currentThread().getContextClassLoader();
|
||||||
|
ClassLoader newClassLoader = new ClassLoader(originClassLoader) {
|
||||||
|
@Override
|
||||||
|
public Class<?> loadClass(String name) throws ClassNotFoundException {
|
||||||
|
if (name.startsWith("io.grpc.Channel")) {
|
||||||
|
throw new ClassNotFoundException("Test");
|
||||||
|
}
|
||||||
|
return super.loadClass(name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Thread.currentThread().setContextClassLoader(newClassLoader);
|
||||||
|
try (MockedConstruction<DubboCertManager> construction =
|
||||||
|
Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {
|
||||||
|
// ignore
|
||||||
|
})) {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
ApplicationModel applicationModel = frameworkModel.newApplication();
|
||||||
|
applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig("test"));
|
||||||
|
SslConfig sslConfig = new SslConfig();
|
||||||
|
sslConfig.setCaAddress("127.0.0.1:30060");
|
||||||
|
applicationModel.getApplicationConfigManager().setSsl(sslConfig);
|
||||||
|
|
||||||
|
applicationModel.getDeployer().start();
|
||||||
|
applicationModel.getDeployer().stop();
|
||||||
|
Assertions.assertEquals(0, construction.constructed().size());
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
Thread.currentThread().setContextClassLoader(originClassLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testNotFound2() {
|
||||||
|
ClassLoader originClassLoader = Thread.currentThread().getContextClassLoader();
|
||||||
|
ClassLoader newClassLoader = new ClassLoader(originClassLoader) {
|
||||||
|
@Override
|
||||||
|
public Class<?> loadClass(String name) throws ClassNotFoundException {
|
||||||
|
if (name.startsWith("org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder")) {
|
||||||
|
throw new ClassNotFoundException("Test");
|
||||||
|
}
|
||||||
|
return super.loadClass(name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Thread.currentThread().setContextClassLoader(newClassLoader);
|
||||||
|
try (MockedConstruction<DubboCertManager> construction =
|
||||||
|
Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {
|
||||||
|
// ignore
|
||||||
|
})) {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
ApplicationModel applicationModel = frameworkModel.newApplication();
|
||||||
|
applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig("test"));
|
||||||
|
SslConfig sslConfig = new SslConfig();
|
||||||
|
sslConfig.setCaAddress("127.0.0.1:30060");
|
||||||
|
applicationModel.getApplicationConfigManager().setSsl(sslConfig);
|
||||||
|
|
||||||
|
applicationModel.getDeployer().start();
|
||||||
|
applicationModel.getDeployer().stop();
|
||||||
|
Assertions.assertEquals(0, construction.constructed().size());
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
Thread.currentThread().setContextClassLoader(originClassLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParams1() {
|
||||||
|
AtomicReference<DubboCertManager> reference = new AtomicReference<>();
|
||||||
|
try (MockedConstruction<DubboCertManager> construction =
|
||||||
|
Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {
|
||||||
|
reference.set(mock);
|
||||||
|
})) {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
ApplicationModel applicationModel = frameworkModel.newApplication();
|
||||||
|
applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig("test"));
|
||||||
|
SslConfig sslConfig = new SslConfig();
|
||||||
|
sslConfig.setCaAddress("127.0.0.1:30060");
|
||||||
|
sslConfig.setCaCertPath("certs/ca.crt");
|
||||||
|
sslConfig.setOidcTokenPath("token");
|
||||||
|
sslConfig.setEnvType("test");
|
||||||
|
applicationModel.getApplicationConfigManager().setSsl(sslConfig);
|
||||||
|
|
||||||
|
applicationModel.getDeployer().start();
|
||||||
|
Mockito.verify(reference.get(), Mockito.times(1))
|
||||||
|
.connect(new CertConfig("127.0.0.1:30060", "test", "certs/ca.crt", "token"));
|
||||||
|
applicationModel.getDeployer().stop();
|
||||||
|
Mockito.verify(reference.get(), Mockito.atLeast(1))
|
||||||
|
.disConnect();
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Disabled("Enable me until properties from envs work.")
|
||||||
|
@Test
|
||||||
|
void testParams2() {
|
||||||
|
AtomicReference<DubboCertManager> reference = new AtomicReference<>();
|
||||||
|
try (MockedConstruction<DubboCertManager> construction =
|
||||||
|
Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {
|
||||||
|
reference.set(mock);
|
||||||
|
})) {
|
||||||
|
System.setProperty("dubbo.ssl.ca-address", "127.0.0.1:30060");
|
||||||
|
System.setProperty("dubbo.ssl.ca-cert-path", "certs/ca.crt");
|
||||||
|
System.setProperty("dubbo.ssl.oidc-token-path", "token");
|
||||||
|
System.setProperty("dubbo.ssl.env-type", "test");
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
ApplicationModel applicationModel = frameworkModel.newApplication();
|
||||||
|
applicationModel.getApplicationConfigManager().setApplication(new ApplicationConfig("test"));
|
||||||
|
|
||||||
|
applicationModel.getDeployer().start();
|
||||||
|
Mockito.verify(reference.get(), Mockito.times(1))
|
||||||
|
.connect(new CertConfig("127.0.0.1:30060", "test", "certs/ca.crt", "token"));
|
||||||
|
applicationModel.getDeployer().stop();
|
||||||
|
Mockito.verify(reference.get(), Mockito.atLeast(1)).disConnect();
|
||||||
|
frameworkModel.destroy();
|
||||||
|
System.clearProperty("dubbo.ssl.ca-address");
|
||||||
|
System.clearProperty("dubbo.ssl.ca-cert-path");
|
||||||
|
System.clearProperty("dubbo.ssl.oidc-token-path");
|
||||||
|
System.clearProperty("dubbo.ssl.env-type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,284 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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.apache.dubbo.security.cert;
|
||||||
|
|
||||||
|
import org.apache.dubbo.auth.v1alpha1.DubboCertificateResponse;
|
||||||
|
import org.apache.dubbo.auth.v1alpha1.DubboCertificateServiceGrpc;
|
||||||
|
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||||
|
|
||||||
|
import io.grpc.Channel;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.mockito.MockedStatic;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
import static org.awaitility.Awaitility.await;
|
||||||
|
import static org.mockito.Answers.CALLS_REAL_METHODS;
|
||||||
|
|
||||||
|
class DubboCertManagerTest {
|
||||||
|
@Test
|
||||||
|
void test1() {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
DubboCertManager certManager = new DubboCertManager(frameworkModel) {
|
||||||
|
@Override
|
||||||
|
protected void connect0(CertConfig certConfig) {
|
||||||
|
Assertions.assertEquals("127.0.0.1:30060", certConfig.getRemoteAddress());
|
||||||
|
Assertions.assertEquals("caCertPath", certConfig.getCaCertPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CertPair generateCert() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void scheduleRefresh() {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
certManager.connect(new CertConfig("127.0.0.1:30060", null, "caCertPath", "oidc"));
|
||||||
|
Assertions.assertEquals(new CertConfig("127.0.0.1:30060", null, "caCertPath", "oidc"), certManager.certConfig);
|
||||||
|
|
||||||
|
certManager.connect(new CertConfig("127.0.0.1:30060", "Kubernetes", "caCertPath", "oidc123"));
|
||||||
|
Assertions.assertEquals(new CertConfig("127.0.0.1:30060", "Kubernetes", "caCertPath", "oidc123"), certManager.certConfig);
|
||||||
|
|
||||||
|
certManager.connect(new CertConfig("127.0.0.1:30060", "kubernetes", "caCertPath", "oidc345"));
|
||||||
|
Assertions.assertEquals(new CertConfig("127.0.0.1:30060", "kubernetes", "caCertPath", "oidc345"), certManager.certConfig);
|
||||||
|
|
||||||
|
CertConfig certConfig = new CertConfig("127.0.0.1:30060", "vm", "caCertPath", "oidc");
|
||||||
|
Assertions.assertThrows(IllegalArgumentException.class, () -> certManager.connect(certConfig));
|
||||||
|
Assertions.assertEquals(new CertConfig("127.0.0.1:30060", "kubernetes", "caCertPath", "oidc345"), certManager.certConfig);
|
||||||
|
|
||||||
|
certManager.connect(null);
|
||||||
|
Assertions.assertEquals(new CertConfig("127.0.0.1:30060", "kubernetes", "caCertPath", "oidc345"), certManager.certConfig);
|
||||||
|
|
||||||
|
certManager.connect(new CertConfig(null, null, null, null));
|
||||||
|
Assertions.assertEquals(new CertConfig("127.0.0.1:30060", "kubernetes", "caCertPath", "oidc345"), certManager.certConfig);
|
||||||
|
|
||||||
|
certManager.channel = Mockito.mock(Channel.class);
|
||||||
|
certManager.connect(new CertConfig("error", null, "error", "error"));
|
||||||
|
Assertions.assertEquals(new CertConfig("127.0.0.1:30060", "kubernetes", "caCertPath", "oidc345"), certManager.certConfig);
|
||||||
|
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testRefresh() {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
AtomicInteger count = new AtomicInteger(0);
|
||||||
|
DubboCertManager certManager = new DubboCertManager(frameworkModel) {
|
||||||
|
@Override
|
||||||
|
protected CertPair generateCert() {
|
||||||
|
count.incrementAndGet();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
certManager.certConfig = new CertConfig(null, null, null, null, 10);
|
||||||
|
certManager.scheduleRefresh();
|
||||||
|
|
||||||
|
Assertions.assertNotNull(certManager.refreshFuture);
|
||||||
|
await().until(() -> count.get() > 1);
|
||||||
|
certManager.refreshFuture.cancel(false);
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConnect1() {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
DubboCertManager certManager = new DubboCertManager(frameworkModel);
|
||||||
|
CertConfig certConfig = new CertConfig("127.0.0.1:30062", null, null, null);
|
||||||
|
certManager.connect0(certConfig);
|
||||||
|
Assertions.assertNotNull(certManager.channel);
|
||||||
|
Assertions.assertEquals("127.0.0.1:30062", certManager.channel.authority());
|
||||||
|
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConnect2() {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
DubboCertManager certManager = new DubboCertManager(frameworkModel);
|
||||||
|
String file = this.getClass().getClassLoader().getResource("certs/ca.crt").getFile();
|
||||||
|
CertConfig certConfig = new CertConfig("127.0.0.1:30062", null, file, null);
|
||||||
|
certManager.connect0(certConfig);
|
||||||
|
Assertions.assertNotNull(certManager.channel);
|
||||||
|
Assertions.assertEquals("127.0.0.1:30062", certManager.channel.authority());
|
||||||
|
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConnect3() {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
DubboCertManager certManager = new DubboCertManager(frameworkModel);
|
||||||
|
String file = this.getClass().getClassLoader().getResource("certs/broken-ca.crt").getFile();
|
||||||
|
CertConfig certConfig = new CertConfig("127.0.0.1:30062", null, file, null);
|
||||||
|
Assertions.assertThrows(RuntimeException.class, () -> certManager.connect0(certConfig));
|
||||||
|
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDisconnect() {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
DubboCertManager certManager = new DubboCertManager(frameworkModel);
|
||||||
|
ScheduledFuture scheduledFuture = Mockito.mock(ScheduledFuture.class);
|
||||||
|
certManager.refreshFuture = scheduledFuture;
|
||||||
|
certManager.disConnect();
|
||||||
|
Assertions.assertNull(certManager.refreshFuture);
|
||||||
|
Mockito.verify(scheduledFuture, Mockito.times(1)).cancel(true);
|
||||||
|
|
||||||
|
|
||||||
|
certManager.channel = Mockito.mock(Channel.class);
|
||||||
|
certManager.disConnect();
|
||||||
|
Assertions.assertNull(certManager.channel);
|
||||||
|
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConnected() {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
DubboCertManager certManager = new DubboCertManager(frameworkModel);
|
||||||
|
|
||||||
|
Assertions.assertFalse(certManager.isConnected());
|
||||||
|
|
||||||
|
certManager.certConfig = Mockito.mock(CertConfig.class);
|
||||||
|
Assertions.assertFalse(certManager.isConnected());
|
||||||
|
|
||||||
|
certManager.channel = Mockito.mock(Channel.class);
|
||||||
|
Assertions.assertFalse(certManager.isConnected());
|
||||||
|
|
||||||
|
certManager.certPair = Mockito.mock(CertPair.class);
|
||||||
|
Assertions.assertTrue(certManager.isConnected());
|
||||||
|
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGenerateCert() {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
|
||||||
|
AtomicBoolean exception = new AtomicBoolean(false);
|
||||||
|
AtomicReference<CertPair> certPairReference = new AtomicReference<>();
|
||||||
|
DubboCertManager certManager = new DubboCertManager(frameworkModel) {
|
||||||
|
@Override
|
||||||
|
protected CertPair refreshCert() throws IOException {
|
||||||
|
if (exception.get()) {
|
||||||
|
throw new IOException("test");
|
||||||
|
}
|
||||||
|
return certPairReference.get();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
CertPair certPair = new CertPair("", "", "", Long.MAX_VALUE);
|
||||||
|
certPairReference.set(certPair);
|
||||||
|
|
||||||
|
Assertions.assertEquals(certPair, certManager.generateCert());
|
||||||
|
|
||||||
|
certManager.certPair = new CertPair("", "", "", Long.MAX_VALUE - 10000);
|
||||||
|
Assertions.assertEquals(new CertPair("", "", "", Long.MAX_VALUE - 10000), certManager.generateCert());
|
||||||
|
|
||||||
|
certManager.certPair = new CertPair("", "", "", 0);
|
||||||
|
Assertions.assertEquals(certPair, certManager.generateCert());
|
||||||
|
|
||||||
|
certManager.certPair = new CertPair("", "", "", 0);
|
||||||
|
certPairReference.set(null);
|
||||||
|
Assertions.assertEquals(new CertPair("", "", "", 0), certManager.generateCert());
|
||||||
|
|
||||||
|
exception.set(true);
|
||||||
|
Assertions.assertEquals(new CertPair("", "", "", 0), certManager.generateCert());
|
||||||
|
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSignWithRsa() {
|
||||||
|
DubboCertManager.KeyPair keyPair = DubboCertManager.signWithRsa();
|
||||||
|
Assertions.assertNotNull(keyPair);
|
||||||
|
Assertions.assertNotNull(keyPair.getPrivateKey());
|
||||||
|
Assertions.assertNotNull(keyPair.getPublicKey());
|
||||||
|
Assertions.assertNotNull(keyPair.getSigner());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSignWithEcdsa() {
|
||||||
|
DubboCertManager.KeyPair keyPair = DubboCertManager.signWithEcdsa();
|
||||||
|
Assertions.assertNotNull(keyPair);
|
||||||
|
Assertions.assertNotNull(keyPair.getPrivateKey());
|
||||||
|
Assertions.assertNotNull(keyPair.getPublicKey());
|
||||||
|
Assertions.assertNotNull(keyPair.getSigner());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testRefreshCert() throws IOException {
|
||||||
|
try (MockedStatic<DubboCertManager> managerMock = Mockito.mockStatic(DubboCertManager.class, CALLS_REAL_METHODS)) {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
DubboCertManager certManager = new DubboCertManager(frameworkModel);
|
||||||
|
managerMock.when(DubboCertManager::signWithEcdsa).thenReturn(null);
|
||||||
|
managerMock.when(DubboCertManager::signWithRsa).thenReturn(null);
|
||||||
|
|
||||||
|
Assertions.assertNull(certManager.refreshCert());
|
||||||
|
|
||||||
|
managerMock.when(DubboCertManager::signWithEcdsa).thenCallRealMethod();
|
||||||
|
|
||||||
|
certManager.channel = Mockito.mock(Channel.class);
|
||||||
|
try (MockedStatic<DubboCertificateServiceGrpc> mockGrpc = Mockito.mockStatic(DubboCertificateServiceGrpc.class, CALLS_REAL_METHODS)) {
|
||||||
|
DubboCertificateServiceGrpc.DubboCertificateServiceBlockingStub stub = Mockito.mock(DubboCertificateServiceGrpc.DubboCertificateServiceBlockingStub.class);
|
||||||
|
mockGrpc.when(() -> DubboCertificateServiceGrpc.newBlockingStub(Mockito.any(Channel.class))).thenReturn(stub);
|
||||||
|
Mockito.when(stub.createCertificate(Mockito.any())).thenReturn(
|
||||||
|
DubboCertificateResponse.newBuilder()
|
||||||
|
.setSuccess(false).build());
|
||||||
|
|
||||||
|
certManager.certConfig = new CertConfig(null, null, null, null);
|
||||||
|
Assertions.assertNull(certManager.refreshCert());
|
||||||
|
|
||||||
|
String file = this.getClass().getClassLoader().getResource("certs/token").getFile();
|
||||||
|
Mockito.when(stub.withInterceptors(Mockito.any())).thenReturn(stub);
|
||||||
|
certManager.certConfig = new CertConfig(null, null, null, file);
|
||||||
|
|
||||||
|
Assertions.assertNull(certManager.refreshCert());
|
||||||
|
Mockito.verify(stub, Mockito.times(1)).withInterceptors(Mockito.any());
|
||||||
|
|
||||||
|
Mockito.when(stub.createCertificate(Mockito.any())).thenReturn(
|
||||||
|
DubboCertificateResponse.newBuilder()
|
||||||
|
.setSuccess(true)
|
||||||
|
.setCertPem("certPem")
|
||||||
|
.addTrustCerts("trustCerts")
|
||||||
|
.setExpireTime(123456).build());
|
||||||
|
CertPair certPair = certManager.refreshCert();
|
||||||
|
Assertions.assertNotNull(certPair);
|
||||||
|
Assertions.assertEquals("certPem", certPair.getCertificate());
|
||||||
|
Assertions.assertEquals("trustCerts", certPair.getTrustCerts());
|
||||||
|
Assertions.assertEquals(123456, certPair.getExpireTime());
|
||||||
|
|
||||||
|
Mockito.when(stub.createCertificate(Mockito.any())).thenReturn(null);
|
||||||
|
Assertions.assertNull(certManager.refreshCert());
|
||||||
|
}
|
||||||
|
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,150 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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.apache.dubbo.security.cert;
|
||||||
|
|
||||||
|
import org.apache.dubbo.common.ssl.AuthPolicy;
|
||||||
|
import org.apache.dubbo.common.ssl.Cert;
|
||||||
|
import org.apache.dubbo.common.ssl.ProviderCert;
|
||||||
|
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.mockito.MockedConstruction;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
class DubboCertProviderTest {
|
||||||
|
@Test
|
||||||
|
void testEnable() {
|
||||||
|
AtomicReference<DubboCertManager> reference = new AtomicReference<>();
|
||||||
|
try (MockedConstruction<DubboCertManager> construction =
|
||||||
|
Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {
|
||||||
|
reference.set(mock);
|
||||||
|
})) {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
DubboCertProvider provider = new DubboCertProvider(frameworkModel);
|
||||||
|
|
||||||
|
Mockito.when(reference.get().isConnected()).thenReturn(true);
|
||||||
|
Assertions.assertTrue(provider.isSupport(null));
|
||||||
|
|
||||||
|
Mockito.when(reference.get().isConnected()).thenReturn(false);
|
||||||
|
Assertions.assertFalse(provider.isSupport(null));
|
||||||
|
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testEnable1() {
|
||||||
|
ClassLoader originClassLoader = Thread.currentThread().getContextClassLoader();
|
||||||
|
ClassLoader newClassLoader = new ClassLoader(originClassLoader) {
|
||||||
|
@Override
|
||||||
|
public Class<?> loadClass(String name) throws ClassNotFoundException {
|
||||||
|
if (name.startsWith("io.grpc.Channel")) {
|
||||||
|
throw new ClassNotFoundException("Test");
|
||||||
|
}
|
||||||
|
return super.loadClass(name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Thread.currentThread().setContextClassLoader(newClassLoader);
|
||||||
|
try (MockedConstruction<DubboCertManager> construction =
|
||||||
|
Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {
|
||||||
|
// ignore
|
||||||
|
})) {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
DubboCertProvider provider = new DubboCertProvider(frameworkModel);
|
||||||
|
|
||||||
|
Assertions.assertFalse(provider.isSupport(null));
|
||||||
|
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
Thread.currentThread().setContextClassLoader(originClassLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testEnable2() {
|
||||||
|
ClassLoader originClassLoader = Thread.currentThread().getContextClassLoader();
|
||||||
|
ClassLoader newClassLoader = new ClassLoader(originClassLoader) {
|
||||||
|
@Override
|
||||||
|
public Class<?> loadClass(String name) throws ClassNotFoundException {
|
||||||
|
if (name.startsWith("org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder")) {
|
||||||
|
throw new ClassNotFoundException("Test");
|
||||||
|
}
|
||||||
|
return super.loadClass(name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Thread.currentThread().setContextClassLoader(newClassLoader);
|
||||||
|
try (MockedConstruction<DubboCertManager> construction =
|
||||||
|
Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {
|
||||||
|
// ignore
|
||||||
|
})) {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
DubboCertProvider provider = new DubboCertProvider(frameworkModel);
|
||||||
|
|
||||||
|
Assertions.assertFalse(provider.isSupport(null));
|
||||||
|
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
Thread.currentThread().setContextClassLoader(originClassLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getProviderConnectionConfigTest() {
|
||||||
|
AtomicReference<DubboCertManager> reference = new AtomicReference<>();
|
||||||
|
try (MockedConstruction<DubboCertManager> construction =
|
||||||
|
Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {
|
||||||
|
reference.set(mock);
|
||||||
|
})) {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
DubboCertProvider provider = new DubboCertProvider(frameworkModel);
|
||||||
|
Assertions.assertNull(provider.getProviderConnectionConfig(null));
|
||||||
|
|
||||||
|
CertPair certPair = new CertPair("privateKey", "publicKey", "trustCerts", 12345);
|
||||||
|
Mockito.when(reference.get().generateCert()).thenReturn(certPair);
|
||||||
|
ProviderCert providerConnectionConfig = provider.getProviderConnectionConfig(null);
|
||||||
|
Assertions.assertArrayEquals("privateKey".getBytes(), providerConnectionConfig.getPrivateKey());
|
||||||
|
Assertions.assertArrayEquals("publicKey".getBytes(), providerConnectionConfig.getKeyCertChain());
|
||||||
|
Assertions.assertArrayEquals("trustCerts".getBytes(), providerConnectionConfig.getTrustCert());
|
||||||
|
Assertions.assertEquals(AuthPolicy.NONE, providerConnectionConfig.getAuthPolicy());
|
||||||
|
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getConsumerConnectionConfigTest() {
|
||||||
|
AtomicReference<DubboCertManager> reference = new AtomicReference<>();
|
||||||
|
try (MockedConstruction<DubboCertManager> construction =
|
||||||
|
Mockito.mockConstruction(DubboCertManager.class, (mock, context) -> {
|
||||||
|
reference.set(mock);
|
||||||
|
})) {
|
||||||
|
FrameworkModel frameworkModel = new FrameworkModel();
|
||||||
|
DubboCertProvider provider = new DubboCertProvider(frameworkModel);
|
||||||
|
Assertions.assertNull(provider.getConsumerConnectionConfig(null));
|
||||||
|
|
||||||
|
CertPair certPair = new CertPair("privateKey", "publicKey", "trustCerts", 12345);
|
||||||
|
Mockito.when(reference.get().generateCert()).thenReturn(certPair);
|
||||||
|
Cert connectionConfig = provider.getConsumerConnectionConfig(null);
|
||||||
|
Assertions.assertArrayEquals("privateKey".getBytes(), connectionConfig.getPrivateKey());
|
||||||
|
Assertions.assertArrayEquals("publicKey".getBytes(), connectionConfig.getKeyCertChain());
|
||||||
|
Assertions.assertArrayEquals("trustCerts".getBytes(), connectionConfig.getTrustCert());
|
||||||
|
|
||||||
|
frameworkModel.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
|
||||||
|
HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau
|
||||||
|
sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m
|
||||||
|
oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG
|
||||||
|
Dfcog5wrJytaQ6UA0wE=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
|
||||||
|
BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
|
||||||
|
aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla
|
||||||
|
Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0
|
||||||
|
YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT
|
||||||
|
BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7
|
||||||
|
+L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu
|
||||||
|
g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd
|
||||||
|
Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV
|
||||||
|
HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau
|
||||||
|
sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m
|
||||||
|
oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG
|
||||||
|
Dfcog5wrJytaQ6UA0wE=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
tokentokentoken
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
<module>dubbo-qos</module>
|
<module>dubbo-qos</module>
|
||||||
<module>dubbo-auth</module>
|
<module>dubbo-auth</module>
|
||||||
<module>dubbo-reactive</module>
|
<module>dubbo-reactive</module>
|
||||||
|
<module>dubbo-security</module>
|
||||||
<module>dubbo-spring-security</module>
|
<module>dubbo-spring-security</module>
|
||||||
</modules>
|
</modules>
|
||||||
<properties>
|
<properties>
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,9 @@ import org.apache.dubbo.common.utils.StringUtils;
|
||||||
import org.apache.dubbo.remoting.ChannelHandler;
|
import org.apache.dubbo.remoting.ChannelHandler;
|
||||||
import org.apache.dubbo.remoting.Constants;
|
import org.apache.dubbo.remoting.Constants;
|
||||||
import org.apache.dubbo.remoting.RemotingException;
|
import org.apache.dubbo.remoting.RemotingException;
|
||||||
import org.apache.dubbo.remoting.transport.netty4.ssl.SslClientTlsHandler;
|
|
||||||
import org.apache.dubbo.remoting.transport.AbstractClient;
|
import org.apache.dubbo.remoting.transport.AbstractClient;
|
||||||
|
import org.apache.dubbo.remoting.transport.netty4.ssl.SslClientTlsHandler;
|
||||||
|
import org.apache.dubbo.remoting.transport.netty4.ssl.SslContexts;
|
||||||
import org.apache.dubbo.remoting.utils.UrlUtils;
|
import org.apache.dubbo.remoting.utils.UrlUtils;
|
||||||
|
|
||||||
import io.netty.bootstrap.Bootstrap;
|
import io.netty.bootstrap.Bootstrap;
|
||||||
|
|
@ -41,13 +42,13 @@ import io.netty.channel.ChannelOption;
|
||||||
import io.netty.channel.EventLoopGroup;
|
import io.netty.channel.EventLoopGroup;
|
||||||
import io.netty.channel.socket.SocketChannel;
|
import io.netty.channel.socket.SocketChannel;
|
||||||
import io.netty.handler.proxy.Socks5ProxyHandler;
|
import io.netty.handler.proxy.Socks5ProxyHandler;
|
||||||
|
import io.netty.handler.ssl.SslContext;
|
||||||
import io.netty.handler.timeout.IdleStateHandler;
|
import io.netty.handler.timeout.IdleStateHandler;
|
||||||
import io.netty.util.concurrent.EventExecutorGroup;
|
import io.netty.util.concurrent.EventExecutorGroup;
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static org.apache.dubbo.common.constants.CommonConstants.SSL_ENABLED_KEY;
|
|
||||||
import static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_CLIENT_CONNECT_TIMEOUT;
|
import static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_CLIENT_CONNECT_TIMEOUT;
|
||||||
import static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_CONNECT_PROVIDER;
|
import static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_CONNECT_PROVIDER;
|
||||||
import static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_DISCONNECT_PROVIDER;
|
import static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_DISCONNECT_PROVIDER;
|
||||||
|
|
@ -119,14 +120,15 @@ public class NettyClient extends AbstractClient {
|
||||||
.channel(socketChannelClass());
|
.channel(socketChannelClass());
|
||||||
|
|
||||||
bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, Math.max(DEFAULT_CONNECT_TIMEOUT, getConnectTimeout()));
|
bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, Math.max(DEFAULT_CONNECT_TIMEOUT, getConnectTimeout()));
|
||||||
|
SslContext sslContext = SslContexts.buildClientSslContext(getUrl());
|
||||||
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
|
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initChannel(SocketChannel ch) throws Exception {
|
protected void initChannel(SocketChannel ch) throws Exception {
|
||||||
int heartbeatInterval = UrlUtils.getHeartbeat(getUrl());
|
int heartbeatInterval = UrlUtils.getHeartbeat(getUrl());
|
||||||
|
|
||||||
if (getUrl().getParameter(SSL_ENABLED_KEY, false)) {
|
if (sslContext != null) {
|
||||||
ch.pipeline().addLast("negotiation", new SslClientTlsHandler(getUrl()));
|
ch.pipeline().addLast("negotiation", new SslClientTlsHandler(sslContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyClient.this);
|
NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyClient.this);
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import org.apache.dubbo.remoting.RemotingException;
|
||||||
import org.apache.dubbo.remoting.api.WireProtocol;
|
import org.apache.dubbo.remoting.api.WireProtocol;
|
||||||
import org.apache.dubbo.remoting.api.connection.AbstractConnectionClient;
|
import org.apache.dubbo.remoting.api.connection.AbstractConnectionClient;
|
||||||
import org.apache.dubbo.remoting.transport.netty4.ssl.SslClientTlsHandler;
|
import org.apache.dubbo.remoting.transport.netty4.ssl.SslClientTlsHandler;
|
||||||
|
import org.apache.dubbo.remoting.transport.netty4.ssl.SslContexts;
|
||||||
|
|
||||||
import io.netty.bootstrap.Bootstrap;
|
import io.netty.bootstrap.Bootstrap;
|
||||||
import io.netty.buffer.PooledByteBufAllocator;
|
import io.netty.buffer.PooledByteBufAllocator;
|
||||||
|
|
@ -38,6 +39,7 @@ import io.netty.channel.ChannelOption;
|
||||||
import io.netty.channel.ChannelPipeline;
|
import io.netty.channel.ChannelPipeline;
|
||||||
import io.netty.channel.EventLoop;
|
import io.netty.channel.EventLoop;
|
||||||
import io.netty.channel.socket.SocketChannel;
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
import io.netty.handler.ssl.SslContext;
|
||||||
import io.netty.util.AttributeKey;
|
import io.netty.util.AttributeKey;
|
||||||
import io.netty.util.concurrent.DefaultPromise;
|
import io.netty.util.concurrent.DefaultPromise;
|
||||||
import io.netty.util.concurrent.GlobalEventExecutor;
|
import io.netty.util.concurrent.GlobalEventExecutor;
|
||||||
|
|
@ -48,7 +50,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_CLIENT_THREADPOOL;
|
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_CLIENT_THREADPOOL;
|
||||||
import static org.apache.dubbo.common.constants.CommonConstants.SSL_ENABLED_KEY;
|
|
||||||
import static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;
|
import static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;
|
||||||
import static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_CLIENT_CONNECT_TIMEOUT;
|
import static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_CLIENT_CONNECT_TIMEOUT;
|
||||||
import static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_CONNECT_PROVIDER;
|
import static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_CONNECT_PROVIDER;
|
||||||
|
|
@ -107,6 +108,7 @@ public class NettyConnectionClient extends AbstractConnectionClient {
|
||||||
|
|
||||||
final NettyConnectionHandler connectionHandler = new NettyConnectionHandler(this);
|
final NettyConnectionHandler connectionHandler = new NettyConnectionHandler(this);
|
||||||
nettyBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, getConnectTimeout());
|
nettyBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, getConnectTimeout());
|
||||||
|
SslContext sslContext = SslContexts.buildClientSslContext(getUrl());
|
||||||
nettyBootstrap.handler(new ChannelInitializer<SocketChannel>() {
|
nettyBootstrap.handler(new ChannelInitializer<SocketChannel>() {
|
||||||
@Override
|
@Override
|
||||||
protected void initChannel(SocketChannel ch) {
|
protected void initChannel(SocketChannel ch) {
|
||||||
|
|
@ -114,8 +116,8 @@ public class NettyConnectionClient extends AbstractConnectionClient {
|
||||||
final ChannelPipeline pipeline = ch.pipeline();
|
final ChannelPipeline pipeline = ch.pipeline();
|
||||||
NettySslContextOperator nettySslContextOperator = new NettySslContextOperator();
|
NettySslContextOperator nettySslContextOperator = new NettySslContextOperator();
|
||||||
|
|
||||||
if (getUrl().getParameter(SSL_ENABLED_KEY, false)) {
|
if (sslContext != null) {
|
||||||
pipeline.addLast("negotiation", new SslClientTlsHandler(getUrl()));
|
pipeline.addLast("negotiation", new SslClientTlsHandler(sslContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
// pipeline.addLast("logging", new LoggingHandler(LogLevel.INFO)); //for debug
|
// pipeline.addLast("logging", new LoggingHandler(LogLevel.INFO)); //for debug
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ import org.apache.dubbo.remoting.Channel;
|
||||||
import org.apache.dubbo.remoting.ChannelHandler;
|
import org.apache.dubbo.remoting.ChannelHandler;
|
||||||
import org.apache.dubbo.remoting.Constants;
|
import org.apache.dubbo.remoting.Constants;
|
||||||
import org.apache.dubbo.remoting.RemotingException;
|
import org.apache.dubbo.remoting.RemotingException;
|
||||||
import org.apache.dubbo.remoting.transport.netty4.ssl.SslContexts;
|
|
||||||
import org.apache.dubbo.remoting.api.WireProtocol;
|
import org.apache.dubbo.remoting.api.WireProtocol;
|
||||||
import org.apache.dubbo.remoting.api.pu.AbstractPortUnificationServer;
|
import org.apache.dubbo.remoting.api.pu.AbstractPortUnificationServer;
|
||||||
import org.apache.dubbo.remoting.transport.dispatcher.ChannelHandlers;
|
import org.apache.dubbo.remoting.transport.dispatcher.ChannelHandlers;
|
||||||
|
|
@ -39,7 +38,6 @@ import io.netty.channel.ChannelOption;
|
||||||
import io.netty.channel.ChannelPipeline;
|
import io.netty.channel.ChannelPipeline;
|
||||||
import io.netty.channel.EventLoopGroup;
|
import io.netty.channel.EventLoopGroup;
|
||||||
import io.netty.channel.socket.SocketChannel;
|
import io.netty.channel.socket.SocketChannel;
|
||||||
import io.netty.handler.ssl.SslContext;
|
|
||||||
import io.netty.util.concurrent.Future;
|
import io.netty.util.concurrent.Future;
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
|
@ -52,7 +50,6 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;
|
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;
|
||||||
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
|
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
|
||||||
import static org.apache.dubbo.common.constants.CommonConstants.IO_THREADS_KEY;
|
import static org.apache.dubbo.common.constants.CommonConstants.IO_THREADS_KEY;
|
||||||
import static org.apache.dubbo.common.constants.CommonConstants.SSL_ENABLED_KEY;
|
|
||||||
import static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_CLOSE;
|
import static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_CLOSE;
|
||||||
import static org.apache.dubbo.remoting.Constants.EVENT_LOOP_BOSS_POOL_NAME;
|
import static org.apache.dubbo.remoting.Constants.EVENT_LOOP_BOSS_POOL_NAME;
|
||||||
import static org.apache.dubbo.remoting.Constants.EVENT_LOOP_WORKER_POOL_NAME;
|
import static org.apache.dubbo.remoting.Constants.EVENT_LOOP_WORKER_POOL_NAME;
|
||||||
|
|
@ -115,13 +112,6 @@ public class NettyPortUnificationServer extends AbstractPortUnificationServer {
|
||||||
getUrl().getPositiveParameter(IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS),
|
getUrl().getPositiveParameter(IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS),
|
||||||
EVENT_LOOP_WORKER_POOL_NAME);
|
EVENT_LOOP_WORKER_POOL_NAME);
|
||||||
|
|
||||||
final boolean enableSsl = getUrl().getParameter(SSL_ENABLED_KEY, false);
|
|
||||||
final SslContext sslContext;
|
|
||||||
if (enableSsl) {
|
|
||||||
sslContext = SslContexts.buildServerSslContext(getUrl());
|
|
||||||
} else {
|
|
||||||
sslContext = null;
|
|
||||||
}
|
|
||||||
bootstrap.group(bossGroup, workerGroup)
|
bootstrap.group(bossGroup, workerGroup)
|
||||||
.channel(NettyEventLoopFactory.serverSocketChannelClass())
|
.channel(NettyEventLoopFactory.serverSocketChannelClass())
|
||||||
.option(ChannelOption.SO_REUSEADDR, Boolean.TRUE)
|
.option(ChannelOption.SO_REUSEADDR, Boolean.TRUE)
|
||||||
|
|
@ -133,7 +123,7 @@ public class NettyPortUnificationServer extends AbstractPortUnificationServer {
|
||||||
// Do not add idle state handler here, because it should be added in the protocol handler.
|
// Do not add idle state handler here, because it should be added in the protocol handler.
|
||||||
final ChannelPipeline p = ch.pipeline();
|
final ChannelPipeline p = ch.pipeline();
|
||||||
final NettyPortUnificationServerHandler puHandler;
|
final NettyPortUnificationServerHandler puHandler;
|
||||||
puHandler = new NettyPortUnificationServerHandler(getUrl(), sslContext, true, getProtocols(),
|
puHandler = new NettyPortUnificationServerHandler(getUrl(), true, getProtocols(),
|
||||||
NettyPortUnificationServer.this, NettyPortUnificationServer.this.dubboChannels,
|
NettyPortUnificationServer.this, NettyPortUnificationServer.this.dubboChannels,
|
||||||
getSupportedUrls(), getSupportedHandlers());
|
getSupportedUrls(), getSupportedHandlers());
|
||||||
p.addLast("negotiation-protocol", puHandler);
|
p.addLast("negotiation-protocol", puHandler);
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,15 @@ import org.apache.dubbo.common.URL;
|
||||||
import org.apache.dubbo.common.io.Bytes;
|
import org.apache.dubbo.common.io.Bytes;
|
||||||
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
||||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||||
|
import org.apache.dubbo.common.ssl.CertManager;
|
||||||
|
import org.apache.dubbo.common.ssl.ProviderCert;
|
||||||
import org.apache.dubbo.common.utils.NetUtils;
|
import org.apache.dubbo.common.utils.NetUtils;
|
||||||
import org.apache.dubbo.remoting.Channel;
|
import org.apache.dubbo.remoting.Channel;
|
||||||
import org.apache.dubbo.remoting.ChannelHandler;
|
import org.apache.dubbo.remoting.ChannelHandler;
|
||||||
import org.apache.dubbo.remoting.api.ProtocolDetector;
|
import org.apache.dubbo.remoting.api.ProtocolDetector;
|
||||||
import org.apache.dubbo.remoting.api.WireProtocol;
|
import org.apache.dubbo.remoting.api.WireProtocol;
|
||||||
import org.apache.dubbo.remoting.buffer.ChannelBuffer;
|
import org.apache.dubbo.remoting.buffer.ChannelBuffer;
|
||||||
|
import org.apache.dubbo.remoting.transport.netty4.ssl.SslContexts;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
|
@ -33,7 +36,9 @@ import io.netty.channel.ChannelPipeline;
|
||||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||||
import io.netty.handler.ssl.SslContext;
|
import io.netty.handler.ssl.SslContext;
|
||||||
import io.netty.handler.ssl.SslHandler;
|
import io.netty.handler.ssl.SslHandler;
|
||||||
|
import io.netty.handler.ssl.SslHandshakeCompletionEvent;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLSession;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
@ -45,8 +50,6 @@ public class NettyPortUnificationServerHandler extends ByteToMessageDecoder {
|
||||||
|
|
||||||
private static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(
|
private static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(
|
||||||
NettyPortUnificationServerHandler.class);
|
NettyPortUnificationServerHandler.class);
|
||||||
|
|
||||||
private final SslContext sslCtx;
|
|
||||||
private final URL url;
|
private final URL url;
|
||||||
private final ChannelHandler handler;
|
private final ChannelHandler handler;
|
||||||
private final boolean detectSsl;
|
private final boolean detectSsl;
|
||||||
|
|
@ -56,11 +59,10 @@ public class NettyPortUnificationServerHandler extends ByteToMessageDecoder {
|
||||||
private final Map<String, ChannelHandler> handlerMapper;
|
private final Map<String, ChannelHandler> handlerMapper;
|
||||||
|
|
||||||
|
|
||||||
public NettyPortUnificationServerHandler(URL url, SslContext sslCtx, boolean detectSsl,
|
public NettyPortUnificationServerHandler(URL url, boolean detectSsl,
|
||||||
List<WireProtocol> protocols, ChannelHandler handler,
|
List<WireProtocol> protocols, ChannelHandler handler,
|
||||||
Map<String, Channel> dubboChannels, Map<String, URL> urlMapper, Map<String, ChannelHandler> handlerMapper) {
|
Map<String, Channel> dubboChannels, Map<String, URL> urlMapper, Map<String, ChannelHandler> handlerMapper) {
|
||||||
this.url = url;
|
this.url = url;
|
||||||
this.sslCtx = sslCtx;
|
|
||||||
this.protocols = protocols;
|
this.protocols = protocols;
|
||||||
this.detectSsl = detectSsl;
|
this.detectSsl = detectSsl;
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
|
|
@ -84,6 +86,21 @@ public class NettyPortUnificationServerHandler extends ByteToMessageDecoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
|
||||||
|
if (evt instanceof SslHandshakeCompletionEvent) {
|
||||||
|
SslHandshakeCompletionEvent handshakeEvent = (SslHandshakeCompletionEvent) evt;
|
||||||
|
if (handshakeEvent.isSuccess()) {
|
||||||
|
SSLSession session = ctx.pipeline().get(SslHandler.class).engine().getSession();
|
||||||
|
LOGGER.info("TLS negotiation succeed with session: " + session);
|
||||||
|
} else {
|
||||||
|
LOGGER.error(INTERNAL_ERROR, "", "", "TLS negotiation failed when trying to accept new connection.", handshakeEvent.cause());
|
||||||
|
ctx.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.userEventTriggered(ctx, evt);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
|
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
@ -94,8 +111,11 @@ public class NettyPortUnificationServerHandler extends ByteToMessageDecoder {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSsl(in)) {
|
CertManager certManager = url.getOrDefaultFrameworkModel().getBeanFactory().getBean(CertManager.class);
|
||||||
enableSsl(ctx);
|
ProviderCert providerConnectionConfig = certManager.getProviderConnectionConfig(url, ctx.channel().remoteAddress());
|
||||||
|
|
||||||
|
if (providerConnectionConfig != null && isSsl(in)) {
|
||||||
|
enableSsl(ctx, providerConnectionConfig);
|
||||||
} else {
|
} else {
|
||||||
for (final WireProtocol protocol : protocols) {
|
for (final WireProtocol protocol : protocols) {
|
||||||
in.markReaderIndex();
|
in.markReaderIndex();
|
||||||
|
|
@ -136,13 +156,12 @@ public class NettyPortUnificationServerHandler extends ByteToMessageDecoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enableSsl(ChannelHandlerContext ctx) {
|
private void enableSsl(ChannelHandlerContext ctx, ProviderCert providerConnectionConfig) {
|
||||||
ChannelPipeline p = ctx.pipeline();
|
ChannelPipeline p = ctx.pipeline();
|
||||||
if (sslCtx != null) {
|
SslContext sslContext = SslContexts.buildServerSslContext(providerConnectionConfig);
|
||||||
p.addLast("ssl", sslCtx.newHandler(ctx.alloc()));
|
p.addLast("ssl", sslContext.newHandler(ctx.alloc()));
|
||||||
}
|
|
||||||
p.addLast("unificationA",
|
p.addLast("unificationA",
|
||||||
new NettyPortUnificationServerHandler(url, sslCtx, false, protocols,
|
new NettyPortUnificationServerHandler(url, false, protocols,
|
||||||
handler, dubboChannels, urlMapper, handlerMapper));
|
handler, dubboChannels, urlMapper, handlerMapper));
|
||||||
p.remove(this);
|
p.remove(this);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,6 @@ import java.util.Map;
|
||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static org.apache.dubbo.common.constants.CommonConstants.IO_THREADS_KEY;
|
import static org.apache.dubbo.common.constants.CommonConstants.IO_THREADS_KEY;
|
||||||
import static org.apache.dubbo.common.constants.CommonConstants.KEEP_ALIVE_KEY;
|
import static org.apache.dubbo.common.constants.CommonConstants.KEEP_ALIVE_KEY;
|
||||||
import static org.apache.dubbo.common.constants.CommonConstants.SSL_ENABLED_KEY;
|
|
||||||
import static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_CLOSE;
|
import static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_CLOSE;
|
||||||
import static org.apache.dubbo.remoting.Constants.EVENT_LOOP_BOSS_POOL_NAME;
|
import static org.apache.dubbo.remoting.Constants.EVENT_LOOP_BOSS_POOL_NAME;
|
||||||
import static org.apache.dubbo.remoting.Constants.EVENT_LOOP_WORKER_POOL_NAME;
|
import static org.apache.dubbo.remoting.Constants.EVENT_LOOP_WORKER_POOL_NAME;
|
||||||
|
|
@ -128,7 +127,6 @@ public class NettyServer extends AbstractServer {
|
||||||
|
|
||||||
protected void initServerBootstrap(NettyServerHandler nettyServerHandler) {
|
protected void initServerBootstrap(NettyServerHandler nettyServerHandler) {
|
||||||
boolean keepalive = getUrl().getParameter(KEEP_ALIVE_KEY, Boolean.FALSE);
|
boolean keepalive = getUrl().getParameter(KEEP_ALIVE_KEY, Boolean.FALSE);
|
||||||
|
|
||||||
bootstrap.group(bossGroup, workerGroup)
|
bootstrap.group(bossGroup, workerGroup)
|
||||||
.channel(NettyEventLoopFactory.serverSocketChannelClass())
|
.channel(NettyEventLoopFactory.serverSocketChannelClass())
|
||||||
.option(ChannelOption.SO_REUSEADDR, Boolean.TRUE)
|
.option(ChannelOption.SO_REUSEADDR, Boolean.TRUE)
|
||||||
|
|
@ -141,9 +139,7 @@ public class NettyServer extends AbstractServer {
|
||||||
// FIXME: should we use getTimeout()?
|
// FIXME: should we use getTimeout()?
|
||||||
int idleTimeout = UrlUtils.getIdleTimeout(getUrl());
|
int idleTimeout = UrlUtils.getIdleTimeout(getUrl());
|
||||||
NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);
|
NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);
|
||||||
if (getUrl().getParameter(SSL_ENABLED_KEY, false)) {
|
|
||||||
ch.pipeline().addLast("negotiation", new SslServerTlsHandler(getUrl()));
|
ch.pipeline().addLast("negotiation", new SslServerTlsHandler(getUrl()));
|
||||||
}
|
|
||||||
ch.pipeline()
|
ch.pipeline()
|
||||||
.addLast("decoder", adapter.getDecoder())
|
.addLast("decoder", adapter.getDecoder())
|
||||||
.addLast("encoder", adapter.getEncoder())
|
.addLast("encoder", adapter.getEncoder())
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ public class SslClientTlsHandler extends ChannelInboundHandlerAdapter {
|
||||||
SslHandshakeCompletionEvent handshakeEvent = (SslHandshakeCompletionEvent) evt;
|
SslHandshakeCompletionEvent handshakeEvent = (SslHandshakeCompletionEvent) evt;
|
||||||
if (handshakeEvent.isSuccess()) {
|
if (handshakeEvent.isSuccess()) {
|
||||||
SSLSession session = ctx.pipeline().get(SslHandler.class).engine().getSession();
|
SSLSession session = ctx.pipeline().get(SslHandler.class).engine().getSession();
|
||||||
logger.info("TLS negotiation succeed with session: " + session);
|
logger.info("TLS negotiation succeed with: " + session.getPeerHost());
|
||||||
ctx.pipeline().remove(this);
|
ctx.pipeline().remove(this);
|
||||||
} else {
|
} else {
|
||||||
logger.error(INTERNAL_ERROR, "unknown error in remoting module", "", "TLS negotiation failed when trying to accept new connection.", handshakeEvent.cause());
|
logger.error(INTERNAL_ERROR, "unknown error in remoting module", "", "TLS negotiation failed when trying to accept new connection.", handshakeEvent.cause());
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,10 @@ package org.apache.dubbo.remoting.transport.netty4.ssl;
|
||||||
import org.apache.dubbo.common.URL;
|
import org.apache.dubbo.common.URL;
|
||||||
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
||||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||||
import org.apache.dubbo.config.SslConfig;
|
import org.apache.dubbo.common.ssl.AuthPolicy;
|
||||||
import org.apache.dubbo.config.context.ConfigManager;
|
import org.apache.dubbo.common.ssl.Cert;
|
||||||
|
import org.apache.dubbo.common.ssl.CertManager;
|
||||||
|
import org.apache.dubbo.common.ssl.ProviderCert;
|
||||||
|
|
||||||
import io.netty.handler.ssl.ClientAuth;
|
import io.netty.handler.ssl.ClientAuth;
|
||||||
import io.netty.handler.ssl.OpenSsl;
|
import io.netty.handler.ssl.OpenSsl;
|
||||||
|
|
@ -40,19 +42,16 @@ public class SslContexts {
|
||||||
|
|
||||||
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(SslContexts.class);
|
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(SslContexts.class);
|
||||||
|
|
||||||
public static SslContext buildServerSslContext(URL url) {
|
public static SslContext buildServerSslContext(ProviderCert providerConnectionConfig) {
|
||||||
ConfigManager globalConfigManager = url.getOrDefaultApplicationModel().getApplicationConfigManager();
|
|
||||||
SslConfig sslConfig = globalConfigManager.getSsl().orElseThrow(() -> new IllegalStateException("Ssl enabled, but no ssl cert information provided!"));
|
|
||||||
|
|
||||||
SslContextBuilder sslClientContextBuilder;
|
SslContextBuilder sslClientContextBuilder;
|
||||||
InputStream serverKeyCertChainPathStream = null;
|
InputStream serverKeyCertChainPathStream = null;
|
||||||
InputStream serverPrivateKeyPathStream = null;
|
InputStream serverPrivateKeyPathStream = null;
|
||||||
InputStream serverTrustCertStream = null;
|
InputStream serverTrustCertStream = null;
|
||||||
try {
|
try {
|
||||||
serverKeyCertChainPathStream = sslConfig.getServerKeyCertChainPathStream();
|
serverKeyCertChainPathStream = providerConnectionConfig.getKeyCertChainInputStream();
|
||||||
serverPrivateKeyPathStream = sslConfig.getServerPrivateKeyPathStream();
|
serverPrivateKeyPathStream = providerConnectionConfig.getPrivateKeyInputStream();
|
||||||
serverTrustCertStream = sslConfig.getServerTrustCertCollectionPathStream();
|
serverTrustCertStream = providerConnectionConfig.getTrustCertInputStream();
|
||||||
String password = sslConfig.getServerKeyPassword();
|
String password = providerConnectionConfig.getPassword();
|
||||||
if (password != null) {
|
if (password != null) {
|
||||||
sslClientContextBuilder = SslContextBuilder.forServer(serverKeyCertChainPathStream,
|
sslClientContextBuilder = SslContextBuilder.forServer(serverKeyCertChainPathStream,
|
||||||
serverPrivateKeyPathStream, password);
|
serverPrivateKeyPathStream, password);
|
||||||
|
|
@ -63,7 +62,11 @@ public class SslContexts {
|
||||||
|
|
||||||
if (serverTrustCertStream != null) {
|
if (serverTrustCertStream != null) {
|
||||||
sslClientContextBuilder.trustManager(serverTrustCertStream);
|
sslClientContextBuilder.trustManager(serverTrustCertStream);
|
||||||
|
if (providerConnectionConfig.getAuthPolicy() == AuthPolicy.CLIENT_AUTH) {
|
||||||
sslClientContextBuilder.clientAuth(ClientAuth.REQUIRE);
|
sslClientContextBuilder.clientAuth(ClientAuth.REQUIRE);
|
||||||
|
} else {
|
||||||
|
sslClientContextBuilder.clientAuth(ClientAuth.OPTIONAL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new IllegalArgumentException("Could not find certificate file or the certificate is invalid.", e);
|
throw new IllegalArgumentException("Could not find certificate file or the certificate is invalid.", e);
|
||||||
|
|
@ -80,23 +83,26 @@ public class SslContexts {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SslContext buildClientSslContext(URL url) {
|
public static SslContext buildClientSslContext(URL url) {
|
||||||
ConfigManager globalConfigManager = url.getOrDefaultApplicationModel().getApplicationConfigManager();
|
CertManager certManager = url.getOrDefaultFrameworkModel().getBeanFactory().getBean(CertManager.class);
|
||||||
SslConfig sslConfig = globalConfigManager.getSsl().orElseThrow(() -> new IllegalStateException("Ssl enabled, but no ssl cert information provided!"));
|
Cert consumerConnectionConfig = certManager.getConsumerConnectionConfig(url);
|
||||||
|
if (consumerConnectionConfig == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
SslContextBuilder builder = SslContextBuilder.forClient();
|
SslContextBuilder builder = SslContextBuilder.forClient();
|
||||||
InputStream clientTrustCertCollectionPath = null;
|
InputStream clientTrustCertCollectionPath = null;
|
||||||
InputStream clientCertChainFilePath = null;
|
InputStream clientCertChainFilePath = null;
|
||||||
InputStream clientPrivateKeyFilePath = null;
|
InputStream clientPrivateKeyFilePath = null;
|
||||||
try {
|
try {
|
||||||
clientTrustCertCollectionPath = sslConfig.getClientTrustCertCollectionPathStream();
|
clientTrustCertCollectionPath = consumerConnectionConfig.getTrustCertInputStream();
|
||||||
if (clientTrustCertCollectionPath != null) {
|
if (clientTrustCertCollectionPath != null) {
|
||||||
builder.trustManager(clientTrustCertCollectionPath);
|
builder.trustManager(clientTrustCertCollectionPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
clientCertChainFilePath = sslConfig.getClientKeyCertChainPathStream();
|
clientCertChainFilePath = consumerConnectionConfig.getKeyCertChainInputStream();
|
||||||
clientPrivateKeyFilePath = sslConfig.getClientPrivateKeyPathStream();
|
clientPrivateKeyFilePath = consumerConnectionConfig.getPrivateKeyInputStream();
|
||||||
if (clientCertChainFilePath != null && clientPrivateKeyFilePath != null) {
|
if (clientCertChainFilePath != null && clientPrivateKeyFilePath != null) {
|
||||||
String password = sslConfig.getClientKeyPassword();
|
String password = consumerConnectionConfig.getPassword();
|
||||||
if (password != null) {
|
if (password != null) {
|
||||||
builder.keyManager(clientCertChainFilePath, clientPrivateKeyFilePath, password);
|
builder.keyManager(clientCertChainFilePath, clientPrivateKeyFilePath, password);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,9 @@ package org.apache.dubbo.remoting.transport.netty4.ssl;
|
||||||
import org.apache.dubbo.common.URL;
|
import org.apache.dubbo.common.URL;
|
||||||
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
||||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||||
|
import org.apache.dubbo.common.ssl.AuthPolicy;
|
||||||
|
import org.apache.dubbo.common.ssl.CertManager;
|
||||||
|
import org.apache.dubbo.common.ssl.ProviderCert;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
|
@ -36,25 +39,18 @@ import static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERR
|
||||||
public class SslServerTlsHandler extends ByteToMessageDecoder {
|
public class SslServerTlsHandler extends ByteToMessageDecoder {
|
||||||
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(SslServerTlsHandler.class);
|
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(SslServerTlsHandler.class);
|
||||||
|
|
||||||
private final SslContext sslContext;
|
private final URL url;
|
||||||
private final boolean detectSsl;
|
|
||||||
|
|
||||||
|
private final boolean sslDetected;
|
||||||
public SslServerTlsHandler() {
|
|
||||||
this(null, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SslServerTlsHandler(URL url) {
|
public SslServerTlsHandler(URL url) {
|
||||||
this(SslContexts.buildServerSslContext(url));
|
this.url = url;
|
||||||
|
this.sslDetected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SslServerTlsHandler(SslContext sslContext) {
|
public SslServerTlsHandler(URL url, boolean sslDetected) {
|
||||||
this(sslContext, true);
|
this.url = url;
|
||||||
}
|
this.sslDetected = sslDetected;
|
||||||
|
|
||||||
public SslServerTlsHandler(SslContext sslContext, boolean detectSsl) {
|
|
||||||
this.sslContext = sslContext;
|
|
||||||
this.detectSsl = detectSsl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -68,7 +64,7 @@ public class SslServerTlsHandler extends ByteToMessageDecoder {
|
||||||
SslHandshakeCompletionEvent handshakeEvent = (SslHandshakeCompletionEvent) evt;
|
SslHandshakeCompletionEvent handshakeEvent = (SslHandshakeCompletionEvent) evt;
|
||||||
if (handshakeEvent.isSuccess()) {
|
if (handshakeEvent.isSuccess()) {
|
||||||
SSLSession session = ctx.pipeline().get(SslHandler.class).engine().getSession();
|
SSLSession session = ctx.pipeline().get(SslHandler.class).engine().getSession();
|
||||||
logger.info("TLS negotiation succeed with session: " + session);
|
logger.info("TLS negotiation succeed with: " + session.getPeerHost());
|
||||||
// Remove after handshake success.
|
// Remove after handshake success.
|
||||||
ctx.pipeline().remove(this);
|
ctx.pipeline().remove(this);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -86,23 +82,42 @@ public class SslServerTlsHandler extends ByteToMessageDecoder {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSsl(byteBuf)) {
|
if (sslDetected) {
|
||||||
enableSsl(channelHandlerContext);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CertManager certManager = url.getOrDefaultFrameworkModel().getBeanFactory().getBean(CertManager.class);
|
||||||
|
ProviderCert providerConnectionConfig = certManager.getProviderConnectionConfig(url, channelHandlerContext.channel().remoteAddress());
|
||||||
|
|
||||||
|
if (providerConnectionConfig == null) {
|
||||||
|
ChannelPipeline p = channelHandlerContext.pipeline();
|
||||||
|
p.remove(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSsl(byteBuf)) {
|
||||||
|
SslContext sslContext = SslContexts.buildServerSslContext(providerConnectionConfig);
|
||||||
|
enableSsl(channelHandlerContext, sslContext);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (providerConnectionConfig.getAuthPolicy() == AuthPolicy.NONE) {
|
||||||
|
ChannelPipeline p = channelHandlerContext.pipeline();
|
||||||
|
p.remove(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.error(INTERNAL_ERROR, "", "", "TLS negotiation failed when trying to accept new connection.");
|
||||||
|
channelHandlerContext.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSsl(ByteBuf buf) {
|
private boolean isSsl(ByteBuf buf) {
|
||||||
if (detectSsl) {
|
|
||||||
return SslHandler.isEncrypted(buf);
|
return SslHandler.isEncrypted(buf);
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void enableSsl(ChannelHandlerContext ctx) {
|
private void enableSsl(ChannelHandlerContext ctx, SslContext sslContext) {
|
||||||
ChannelPipeline p = ctx.pipeline();
|
ChannelPipeline p = ctx.pipeline();
|
||||||
ctx.pipeline().addAfter(ctx.name(), null, sslContext.newHandler(ctx.alloc()));
|
ctx.pipeline().addAfter(ctx.name(), null, sslContext.newHandler(ctx.alloc()));
|
||||||
p.addLast("unificationA", new SslServerTlsHandler(sslContext, false));
|
p.addLast("unificationA", new SslServerTlsHandler(url, true));
|
||||||
p.remove(this);
|
p.remove(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -194,6 +194,10 @@
|
||||||
<groupId>org.apache.dubbo</groupId>
|
<groupId>org.apache.dubbo</groupId>
|
||||||
<artifactId>dubbo-auth</artifactId>
|
<artifactId>dubbo-auth</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.dubbo</groupId>
|
||||||
|
<artifactId>dubbo-security</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.dubbo</groupId>
|
<groupId>org.apache.dubbo</groupId>
|
||||||
<artifactId>dubbo-qos</artifactId>
|
<artifactId>dubbo-qos</artifactId>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue