diff --git a/scfs-api-core/pom.xml b/scfs-api-core/pom.xml
index b20c346..70c8f30 100644
--- a/scfs-api-core/pom.xml
+++ b/scfs-api-core/pom.xml
@@ -32,5 +32,18 @@
httpclient5
5.2.3
+
+
+ ch.qos.logback
+ logback-classic
+ 1.2.12
+ test
+
+
+ ch.qos.logback
+ logback-core
+ 1.2.12
+ test
+
diff --git a/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/CertificateProvider.java b/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/CertificateProvider.java
index bf461de..1b97340 100644
--- a/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/CertificateProvider.java
+++ b/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/CertificateProvider.java
@@ -22,4 +22,9 @@ public interface CertificateProvider {
* @return X.509证书实例
*/
X509Certificate getAvailableCertificate();
+
+ /**
+ * 校验证书是否有效
+ */
+ boolean isAvailableCertificate(String serialNumber);
}
diff --git a/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/DefaultValidator.java b/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/DefaultValidator.java
index 436e2d5..28ac73d 100644
--- a/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/DefaultValidator.java
+++ b/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/DefaultValidator.java
@@ -46,6 +46,16 @@ public final class DefaultValidator implements Validator {
validateResponseSignature(response, channel);
}
+ @Override
+ public void validate(HttpRequest newRequest) {
+ // 校验证书
+ CertificateProvider provider = getProfile().getSignature().getCertificateProvider();
+ Signer signer = getProfile().getSignature().getSigner();
+ if (!provider.isAvailableCertificate(signer.getCertificateSerial())) {
+ throw new ValidationException(String.format("证书已失效, 序列号:%s", signer.getCertificateSerial()));
+ }
+ }
+
public void isInvalidHttpCode(OriginalResponse response) {
if (response.getStatusCode() < HTTP_OK || response.getStatusCode() >= HTTP_MULT_CHOICE) {
throw new ValidationException(String.format("校验失败, HttpStatusCode=%s, Request-Id=%s, HttpResponseBody=%s",
diff --git a/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/LocalCertificateProvider.java b/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/LocalCertificateProvider.java
index 9fb0139..b8454e0 100644
--- a/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/LocalCertificateProvider.java
+++ b/scfs-api-core/src/main/java/com/czcb/scfs/api/core/cipher/LocalCertificateProvider.java
@@ -5,6 +5,7 @@ import org.slf4j.LoggerFactory;
import java.security.cert.X509Certificate;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import static com.czcb.scfs.api.core.util.Strings.timeRange;
@@ -24,11 +25,9 @@ public final class LocalCertificateProvider implements CertificateProvider {
private X509Certificate availableCertificate;
public LocalCertificateProvider(List certificates) {
- if (certificates.isEmpty()) {
- throw new IllegalArgumentException("The parameter list of constructor is empty.");
+ if (certificates != null && !certificates.isEmpty()) {
+ certificates.forEach(this::addX509Certificate);
}
-
- certificates.forEach(this::addX509Certificate);
}
/**
@@ -44,8 +43,9 @@ public final class LocalCertificateProvider implements CertificateProvider {
public void addX509Certificate(X509Certificate certificate) {
if (!validity.withinValidity(certificate)) {
- logger.error("证书已失效, 序列号:{}, 有效范围:[{}]", toHexUpper(certificate.getSerialNumber()), timeRange(certificate));
- return;
+ String serialNumberHexUpper = toHexUpper(certificate.getSerialNumber());
+ String timeRange = timeRange(certificate);
+ logger.error("证书已失效, 序列号:{}, 有效期:[{}]", serialNumberHexUpper, timeRange);
}
certificates.put(toHexUpper(certificate.getSerialNumber()), certificate);
@@ -62,10 +62,12 @@ public final class LocalCertificateProvider implements CertificateProvider {
availableCertificate = validity.getLongestCertificate(certificates);
}
- if (availableCertificate == null) {
- throw new IllegalArgumentException("没有有效的证书");
- }
-
return availableCertificate;
}
+
+ @Override
+ public boolean isAvailableCertificate(String serialNumber) {
+ X509Certificate certificate = getCertificate(serialNumber);
+ return Objects.nonNull(certificate) && validity.withinValidity(certificate);
+ }
}
diff --git a/scfs-api-core/src/main/java/com/czcb/scfs/api/core/http/AbstractApiClient.java b/scfs-api-core/src/main/java/com/czcb/scfs/api/core/http/AbstractApiClient.java
index 8da22ca..aa8b32f 100644
--- a/scfs-api-core/src/main/java/com/czcb/scfs/api/core/http/AbstractApiClient.java
+++ b/scfs-api-core/src/main/java/com/czcb/scfs/api/core/http/AbstractApiClient.java
@@ -53,6 +53,9 @@ public abstract class AbstractApiClient implements ApiClient {
public HttpResponse exchange(HttpRequest request, Class responseClass) {
// 组装请求对象
HttpRequest newRequest = assembleRequest(request);
+ // 请求校验
+ validateRequest(newRequest);
+
// 打印请求数据
httpLogger.logRequest(newRequest, getHttpVersion());
@@ -155,6 +158,10 @@ public abstract class AbstractApiClient implements ApiClient {
return credential.buildRequestAuthorization(request, channel);
}
+ private void validateRequest(HttpRequest newRequest) {
+ validator.validate(newRequest);
+ }
+
/**
* 校验响应
*
diff --git a/scfs-api-core/src/test/java/com/czcb/scfs/api/core/http/ApiClientBuilderTest.java b/scfs-api-core/src/test/java/com/czcb/scfs/api/core/http/ApiClientBuilderTest.java
index 72b0a02..b5d4b66 100644
--- a/scfs-api-core/src/test/java/com/czcb/scfs/api/core/http/ApiClientBuilderTest.java
+++ b/scfs-api-core/src/test/java/com/czcb/scfs/api/core/http/ApiClientBuilderTest.java
@@ -29,7 +29,7 @@ class ApiClientBuilderTest {
list.add(certificate);
CertificateProvider certificateProvider = new LocalCertificateProvider(list);
Privacy privacy = new TestPrivacy(privateKey, certificateProvider);
- Signature signature = new DefaultSignature(certificateProvider, new TestSigner(privateKey,""), new TestVerifier(certificateProvider));
+ Signature signature = new DefaultSignature(certificateProvider, new TestSigner(privateKey, ""), new TestVerifier(certificateProvider));
return new TestProfile(
privacy,
@@ -106,7 +106,7 @@ class ApiClientBuilderTest {
list.add(certificate);
CertificateProvider certificateProvider = new LocalCertificateProvider(list);
Privacy privacy = new TestPrivacy(privateKey, certificateProvider);
- Signature signature = new DefaultSignature(certificateProvider, new TestSigner(privateKey,""), new TestVerifier(certificateProvider));
+ Signature signature = new DefaultSignature(certificateProvider, new TestSigner(privateKey, ""), new TestVerifier(certificateProvider));
return new TestProfile(
privacy,
@@ -126,7 +126,7 @@ class ApiClientBuilderTest {
list.add(certificate);
CertificateProvider certificateProvider = new LocalCertificateProvider(list);
Privacy privacy = new TestPrivacy(privateKey, certificateProvider);
- Signature signature = new DefaultSignature(certificateProvider, new TestSigner(privateKey,""), new TestVerifier(certificateProvider));
+ Signature signature = new DefaultSignature(certificateProvider, new TestSigner(privateKey, ""), new TestVerifier(certificateProvider));
return new TestProfile(
privacy,
diff --git a/scfs-api-core/src/test/java/com/czcb/scfs/api/core/http/client/ApacheHttpclientV3Test.java b/scfs-api-core/src/test/java/com/czcb/scfs/api/core/http/client/ApacheHttpclientV3Test.java
index ac15e08..2e5251e 100644
--- a/scfs-api-core/src/test/java/com/czcb/scfs/api/core/http/client/ApacheHttpclientV3Test.java
+++ b/scfs-api-core/src/test/java/com/czcb/scfs/api/core/http/client/ApacheHttpclientV3Test.java
@@ -45,7 +45,7 @@ class ApacheHttpclientV3Test {
CertificateProvider certificateProvider = new LocalCertificateProvider(list);
Privacy privacy = new TestPrivacy(privateKey, certificateProvider);
Signature signature = new DefaultSignature(certificateProvider,
- new TestSigner(privateKey,"6CDDAA92CAD75998325027647847330C1756291"),
+ new TestSigner(privateKey, "6CDDAA92CAD75998325027647847330C1756291"),
new TestVerifier(certificateProvider));
return new TestProfile(
diff --git a/scfs-api-test/src/main/resources/invalid_rsa_certificate.pem b/scfs-api-test/src/main/resources/invalid_rsa_certificate.pem
new file mode 100644
index 0000000..378e3b8
--- /dev/null
+++ b/scfs-api-test/src/main/resources/invalid_rsa_certificate.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIDeTCCAmGgAwIBAgIhAII88+MQ8uLtGvhVBudKldxDAQBv3vL9AZlT+vTeEqi/MA0GCSqGSIb3
+DQEBCwUAMIGNMQswCQYDVQQGEwJDTjESMBAGA1UECAwJ5rWZ5rGf55yBMRIwEAYDVQQHDAnmna3l
+t57luIIxITAfBgNVBAoMGOa1meaxn+eooOW3nuWVhuS4mumTtuihjDEYMBYGA1UECwwP5pWw5a2X
+6YeR6J6N6YOoMRkwFwYDVQQDDBBzY2ZzLmN6Y2IuY29tLmNuMB4XDTIzMDYxODA5MDczMVoXDTI0
+MDYxODA5MDczMVowUjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCea1meaxn+ecgTESMBAGA1UEBwwJ
+5p2t5bee5biCMRswGQYDVQQKDBLnqKDlt57llYbkuJrpk7booYwwggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQCfHOgnUYbFi780EX9xQTdWPvCyBhaEnU5Y2p1bW4dHoumgEtjQOkLlRe3U
+g1lu6TfhuE9YOQ9+V+Dsnzt7MXIRI7KlOuwpfwXn3e/MYP5ZtDBUiuSGNNVSP39wgb6aYXhvFY/L
+m9gaO8Q4rauzK94Clw4sH3a7J6ST50xHss8VjSVFUkcPhpH+OJBTUrXWiccZCn01XDz0vmq6J3Au
+jM55WBEmoz2r9iiVdCjZsgB4veQIpCKuMvJsEXVgRzULUnaqdX+7BTDBs30kCGyyBarR+wXLAKNQ
+1nENFs1IGM99I+O8UsD6CvUnt2t7l3B8/qIlOSfds8x+BoUxQwhmUaMjAgMBAAEwDQYJKoZIhvcN
+AQELBQADggEBACRCHOYH8ncOiYjMm3As7OFdnVDuGByMoZsDucqwrs0mJZVdp3OMgvGhC9zkzdZX
+sJFKQeIRp/13cD1SKxtwfU7w4J+/FWpWPEG9Jf2bLqurYivu0tTa1xe5SDL4unNaj/o7BA0vaKJe
+gagyULAilNCGBCfy59BSR/GQbgAC6pdl3soMx/s1c9BcZVplbq12/rmStGce6h3QqNjwpRMowbVW
+XswXhr08AUevF7UriDjHkCsa6MqQ5x+ShV9qO1f2LDYBQRnM2Ty44EV5eUbHyKOJAYF+WqT6IRiA
+2sMZrKRTHaNZB4j0Vc87HuxDtTNh/EEXU2sO31WZHs3ymAChbC4=
+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/scfs-api-test/src/main/resources/invalid_rsa_private_key.pem b/scfs-api-test/src/main/resources/invalid_rsa_private_key.pem
new file mode 100644
index 0000000..18b2861
--- /dev/null
+++ b/scfs-api-test/src/main/resources/invalid_rsa_private_key.pem
@@ -0,0 +1,24 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCfHOgnUYbFi780EX9xQTdWPvCy
+BhaEnU5Y2p1bW4dHoumgEtjQOkLlRe3Ug1lu6TfhuE9YOQ9+V+Dsnzt7MXIRI7KlOuwpfwXn3e/M
+YP5ZtDBUiuSGNNVSP39wgb6aYXhvFY/Lm9gaO8Q4rauzK94Clw4sH3a7J6ST50xHss8VjSVFUkcP
+hpH+OJBTUrXWiccZCn01XDz0vmq6J3AujM55WBEmoz2r9iiVdCjZsgB4veQIpCKuMvJsEXVgRzUL
+UnaqdX+7BTDBs30kCGyyBarR+wXLAKNQ1nENFs1IGM99I+O8UsD6CvUnt2t7l3B8/qIlOSfds8x+
+BoUxQwhmUaMjAgMBAAECggEAQ+meKz4QdJvnse0wBKKN4Hl/2bRggxzzVliFJnvEG27tIb45nXLo
+n5x/3R9tGjpf+C9namP8eXQ/1C9Iv5XEto0SkJS8PR/y4NspIYZaueX/ZO5diOzfCjqBBf/S32jv
+8xX0aLbtf5D3+SsjaJe2LEvWKD4Luuk6RUjJlaa73dnSuGFSuvYV8MvFdHtfU8L8ZRoqZwmM9QTg
++Gpix4z6Hy/Mmi1xRl0EhIITq+mV9wR9Ock/0o12nvsNDyDSyrrt3niXTTkVCbct+t4UFwtnrZyH
+dwl1OQ+WleTkUQY+wNgpq4jLjwGowXnqXlKff3tvXEt+3tpdOS8i+kXYwIrvIQKBgQDVnldDo2iq
+TwLcZjXbreHskn/4hvWYUPqucEZ93jmyYNKUKPlXkVnc+kXnS0uuM5JZpi/7+FDkTqwHK83ET4/n
+kTC9zM+K7KyIBbljclPjzXYJAW7nwD8A/vKx6CWi++f4buYc+lttsTprdAZ4/kWPTnvNJSjhSTAR
+SQ32HxkiIQKBgQC+rjujW31WN4d2j48+K0B+7bIQON+VtmBZ48u2ZIQOi4PdoBvHv8HqQyhJlR+6
+z49k5WczSqAXdG2+nIgs8fpjj0lc7YiMIYs0VsLodOToH9J2MfXjWi+A4Y2vbfcjfUuCWhKSZs6B
+eMLNe1LPIBDmlT3A1X83qkCpvAYYQWAkwwKBgFVtslZRZk0dtfYwRf+phT1XxSe9yT/1uprCOd6i
+XY6RnAU2cajsbvSpfgUmnoh3BWMmy+/HeYokUDW59ds5OkKQVN7CpolXZxQqvd4gXZ4vj7HASfsS
+bd/XFXXCcjLA7R70MsCJ+sBebQ+F4gTHI0hRSb9bygJ2g2uWPKgd/a4hAoGABCtZIHxKpEz4iE4h
+SrG1alEWOKaVtPdU6gJCHQ3bmVnRm1H56Yc23UF0qw84r2QEdadSd1ulXn3sPGO90oXD/NNQPljv
+SGkfWxiekGil7LFtb6ot/zeknEPSTkiwQ7VkpkgD6fGXiFs0nzuYFvFTjUcsH4BLlNMDMPLsizE6
+wfMCgYANvw4Lq1cVfHAl3f6IZlpWHPFEEJbPcBLu9+qtUlZjleCaWA8WXuiBxkqaIkeVi3JMst34
+adfIfBsAk4FeyLpkiTYNjOckZvXFXYKA3a05l/RJ5rsnnI9GRh+3Gk3V+87OU7HwMU6jNZmQiPIO
+/jerEvZ9A5tbuzKkfJj2F0ZXfw==
+-----END PRIVATE KEY-----
\ No newline at end of file