feat: channel group test

main
13009 2024-07-03 15:52:25 +08:00
parent 8af2c047b3
commit 5c3fd6eff4
10 changed files with 232 additions and 8 deletions

View File

@ -89,7 +89,7 @@ public class DefaultCredential implements Credential {
private String getChannelNo(HttpRequest request, Channel channel) {
if (channel.isChannelGroupMode()) {
return Strings.toStr(Objects.requireNonNull(request.getRequestBody().getExtraParams().get(CHANNEL_NO)));
return Strings.toStr(Objects.requireNonNull(request.getRequestBody().getExtraParams().get(CHANNEL_NO), "渠道编号为空"));
}
return channel.getChannelNo();
@ -97,7 +97,7 @@ public class DefaultCredential implements Credential {
private String getAppNo(HttpRequest request, Channel channel) {
if (channel.isChannelGroupMode()) {
return Strings.toStr(Objects.requireNonNull(request.getRequestBody().getExtraParams().get(APP_NO)));
return Strings.toStr(Objects.requireNonNull(request.getRequestBody().getExtraParams().get(APP_NO), "应用编码为空"));
}
return channel.getAppNo();

View File

@ -139,6 +139,7 @@ public abstract class AbstractApiClient implements ApiClient {
String ciphertext = cipher.encrypt(secretKey, originalBody);
return httpRequest.newBuilder()
.body(new EncryptRequestBody.Builder()
.extraParams(httpRequest.getRequestBody().getExtraParams())
.originalBody(originalBody)
.body(ciphertext)
.build()

View File

@ -3,7 +3,9 @@ package com.czcb.scfs.api.core.http;
import com.czcb.scfs.api.core.util.Strings;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* @author wangwei
@ -14,10 +16,13 @@ public class EncryptRequestBody implements RequestBody {
private final byte[] body;
// 原始内容
private final byte[] originalBody;
// 额外参数
private final Map<String, Object> extraParams;
private EncryptRequestBody(Builder builder) {
this.body = builder.body;
this.originalBody = builder.originalBody;
this.extraParams = builder.extraParams;
}
@Override
@ -36,12 +41,13 @@ public class EncryptRequestBody implements RequestBody {
@Override
public Map<String, Object> getExtraParams() {
return Collections.emptyMap();
return Collections.unmodifiableMap(extraParams);
}
public static class Builder {
private byte[] body;
private byte[] originalBody;
private Map<String, Object> extraParams;
public Builder body(String body) {
this.body = Strings.toBytes(body);
@ -58,7 +64,16 @@ public class EncryptRequestBody implements RequestBody {
return this;
}
public Builder extraParams(Map<String, Object> extraParams) {
this.extraParams = extraParams;
return this;
}
public EncryptRequestBody build() {
if (Objects.isNull(this.extraParams)) {
this.extraParams = new HashMap<>();
}
return new EncryptRequestBody(this);
}
}

View File

@ -3,7 +3,9 @@ package com.czcb.scfs.api.core.http;
import com.czcb.scfs.api.core.util.Strings;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import static java.util.Objects.requireNonNull;
@ -12,10 +14,12 @@ import static java.util.Objects.requireNonNull;
* @since 2.0.0
*/
public class FileRequestBody implements RequestBody {
private final byte[] body;
private final byte[] body; // 额外参数
private final Map<String, Object> extraParams;
private FileRequestBody(byte[] body) {
private FileRequestBody(byte[] body, Map<String, Object> extraParams) {
this.body = body;
this.extraParams = extraParams;
}
@Override
@ -30,11 +34,12 @@ public class FileRequestBody implements RequestBody {
@Override
public Map<String, Object> getExtraParams() {
return Collections.emptyMap();
return Collections.unmodifiableMap(extraParams);
}
public static class Builder {
private byte[] body;
private Map<String, Object> extraParams;
public Builder body(String body) {
this.body = Strings.toBytes(body);
@ -46,10 +51,19 @@ public class FileRequestBody implements RequestBody {
return this;
}
public Builder extraParams(Map<String, Object> extraParams) {
this.extraParams = extraParams;
return this;
}
public FileRequestBody build() {
requireNonNull(body);
return new FileRequestBody(body);
if (Objects.isNull(extraParams)) {
this.extraParams = new HashMap<>();
}
return new FileRequestBody(body, extraParams);
}
}
}

View File

@ -15,6 +15,7 @@ class ConstantsTest {
Assertions.assertEquals("X-SCFS-Secret-Key", Constants.SECRET_KEY);
Assertions.assertEquals("X-SCFS-Nonce", Constants.NONCE);
Assertions.assertEquals("X-SCFS-Timestamp", Constants.TIMESTAMP);
Assertions.assertEquals("X-SCFS-Channel-Group", Constants.CHANNEL_GROUP);
Assertions.assertEquals("X-SCFS-Request-Id", Constants.REQUEST_ID);
Assertions.assertEquals("X-SCFS-IP-Address", Constants.IP_ADDRESS);
Assertions.assertEquals("X-SCFS-Mac-Address", Constants.MAC_ADDRESS);

View File

@ -4,6 +4,7 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
class EncryptRequestBodyTest {
@ -11,6 +12,7 @@ class EncryptRequestBodyTest {
void getBody() {
EncryptRequestBody requestBody = new EncryptRequestBody.Builder()
.body("123456")
.extraParams(new HashMap<>())
.build();
Assertions.assertArrayEquals("123456".getBytes(StandardCharsets.UTF_8), requestBody.getBody());
@ -27,6 +29,15 @@ class EncryptRequestBodyTest {
Assertions.assertArrayEquals("abc".getBytes(StandardCharsets.UTF_8), requestBody.getOriginalBody());
}
@Test
void getOriginalBodyByte() {
EncryptRequestBody requestBody = new EncryptRequestBody.Builder()
.originalBody("abc".getBytes(StandardCharsets.UTF_8))
.build();
Assertions.assertArrayEquals("abc".getBytes(StandardCharsets.UTF_8), requestBody.getOriginalBody());
}
@Test
void getContentType() {
EncryptRequestBody requestBody = new EncryptRequestBody.Builder()

View File

@ -6,6 +6,7 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
class FileRequestBodyTest {
@ -26,6 +27,19 @@ class FileRequestBodyTest {
Assertions.assertTrue(requestBody.getExtraParams().isEmpty());
}
@Test
void testExtraParams() {
FileRequestBody requestBody = new FileRequestBody.Builder()
.body("123".getBytes(StandardCharsets.UTF_8))
.extraParams(new HashMap<>())
.build();
Assertions.assertArrayEquals("123".getBytes(StandardCharsets.UTF_8), requestBody.getBody());
Assertions.assertNotNull(requestBody.getExtraParams());
Assertions.assertTrue(requestBody.getExtraParams().isEmpty());
}
@Test
void getContentType() {
FileRequestBodyTest.TestApiFileRequest fileRequest = new FileRequestBodyTest.TestApiFileRequest();

View File

@ -0,0 +1,162 @@
package com.czcb.scfs.api.core.http.client;
import com.czcb.scfs.api.core.*;
import com.czcb.scfs.api.core.cipher.*;
import com.czcb.scfs.api.core.http.*;
import com.czcb.scfs.api.core.util.DateTimes;
import com.czcb.scfs.api.core.util.Nonce;
import com.czcb.scfs.api.core.util.Strings;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockserver.client.MockServerClient;
import org.mockserver.junit.jupiter.MockServerExtension;
import org.mockserver.junit.jupiter.MockServerSettings;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import static com.czcb.scfs.api.core.Constants.*;
import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
import static org.mockserver.model.HttpRequest.request;
import static org.mockserver.model.HttpResponse.response;
@ExtendWith(MockServerExtension.class)
@MockServerSettings(ports = {8888})
class ApacheHttpclientGroupTest {
private MockServerClient client;
@BeforeEach
public void beforeEachLifecyleMethod(MockServerClient client) {
this.client = client;
}
/**
*
*/
private Profile profile() {
PrivateKey privateKey = KeyText.loadTestPrivateKeyRSA();
X509Certificate certificate = KeyText.loadTestRSA();
List<X509Certificate> list = new ArrayList<>();
list.add(certificate);
CertificateProvider certificateProvider = new LocalCertificateProvider(list);
Privacy privacy = new TestPrivacy(privateKey, certificateProvider);
Signature signature = new DefaultSignature(certificateProvider,
new TestSigner(privateKey, "6CDDAA92CAD75998325027647847330C1756291"),
new TestVerifier(certificateProvider));
return new TestProfile(
privacy, signature, new DefaultChannel.Builder()
.channelNo("0000")
.appNo("100000")
.enableChannelGroupMode()
.build(), new DefaultHttpProfile.Builder()
.online(false)
.logLevel(LogLevel.FULL)
.compressionEnabled(false)
.host("http://127.0.0.1:8888")
.build()
);
}
@Test
void doRemoteExecute() {
TestResponse mockResponse = new TestResponse();
mockResponse.setName("123456");
// mock 结果
ApiClient apiClient = mock(mockResponse.toJsonResponse().getBody());
// 请求参数
TestRequest request = new TestRequest();
request.setChannelNo("300000");
request.setAppNo("9999");
// 发起调用
HttpResponse<TestResponse> response = apiClient.post("/mock/xxx", request.toJsonRequest(), TestResponse.class);
assertThatJson("{\"name\":\"123456\"}").isEqualTo(response.getServiceResponse().toJsonResponse().getBody());
}
private ApiClient mock(String body) {
ApiClient apiClient = ApiClientBuilder.custom()
.profile(profile())
.build();
// 对称密钥
byte[] secret = apiClient.getProfile().getPrivacy().getSecretCipher().getSecretKey();
// 加密响应报文
String responseBody = apiClient.getProfile().getPrivacy().getSecretCipher().encrypt(secret, body.getBytes(StandardCharsets.UTF_8));
// 加密对称密钥
String secretKey = apiClient.getProfile().getPrivacy().getEncryptor().encrypt(Strings.toStr(secret));
org.mockserver.model.HttpResponse mock = response()
.withHeader(NONCE, Nonce.ofNonce())
.withHeader(SECRET_KEY, secretKey)
.withHeader(REQUEST_ID, Nonce.ofNonce())
.withHeader(BANK_CERTIFICATE_SERIAL, "6CDDAA92CAD75998325027647847330C1756291")
.withHeader(CHANNEL_CERTIFICATE_SERIAL, "6CDDAA92CAD75998325027647847330C1756291")
.withHeader(TIMESTAMP, DateTimes.ofTimestamp());
mock.withBody(responseBody);
String buildAuth = NONCE + "=" + mock.getHeader(NONCE).get(0) + "," +
TIMESTAMP + "=" + mock.getHeader(TIMESTAMP).get(0) + "," +
BANK_CERTIFICATE_SERIAL + "=" + mock.getHeader(BANK_CERTIFICATE_SERIAL).get(0) + "," +
CHANNEL_CERTIFICATE_SERIAL + "=" + mock.getHeader(CHANNEL_CERTIFICATE_SERIAL).get(0) + "," +
SECRET_KEY + "=" + secretKey;
String message = buildAuth + "\n" + responseBody + "\n";
mock.withHeader(SIGNATURE, apiClient.getProfile().getSignature().getSigner().sign(message).getSignature());
client.when(request()
.withHeader("Authorization", "SCFS-SHA256withRSA X-SCFS-Channel-No=300000,X-SCFS-App-No=9999,X-SCFS-Signature=.*")
.withHeader("X-SCFS-Channel-Group", "0000")
.withHeader("X-SCFS-Nonce", ".*")
.withHeader("X-SCFS-Secret-Key", ".*")
.withHeader("X-SCFS-Serial", "6CDDAA92CAD75998325027647847330C1756291")
.withHeader("X-SCFS-Channel-Serial", "6CDDAA92CAD75998325027647847330C1756291")
.withHeader("X-SCFS-Timestamp", ".*")
.withMethod(HttpMethod.POST.getUpperName())
.withPath("/mock/xxx")
).respond(mock);
return apiClient;
}
public static class TestRequest implements ApiRequest {
private String channelNo;
private String appNo;
public String getChannelNo() {
return channelNo;
}
public void setChannelNo(String channelNo) {
this.channelNo = channelNo;
}
public String getAppNo() {
return appNo;
}
public void setAppNo(String appNo) {
this.appNo = appNo;
}
}
public static class TestResponse implements ApiResponse {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}

View File

@ -138,6 +138,12 @@ class ApacheHttpclientTest {
mock.withHeader(SIGNATURE, apiClient.getProfile().getSignature().getSigner().sign(message).getSignature());
client.when(request()
.withHeader("Authorization", "SCFS-SHA256withRSA X-SCFS-Channel-No=0000,X-SCFS-App-No=100000,X-SCFS-Signature=.*")
.withHeader("X-SCFS-Nonce", ".*")
.withHeader("X-SCFS-Secret-Key", ".*")
.withHeader("X-SCFS-Serial", "6CDDAA92CAD75998325027647847330C1756291")
.withHeader("X-SCFS-Channel-Serial", "6CDDAA92CAD75998325027647847330C1756291")
.withHeader("X-SCFS-Timestamp", ".*")
.withMethod(HttpMethod.POST.getUpperName())
.withPath("/mock/xxx")
).respond(mock);

View File

@ -11,6 +11,6 @@ public class TestPrivacyEncryptor extends AbstractPrivacyEncryptor {
* @param publicKey 使
*/
public TestPrivacyEncryptor(PublicKey publicKey) {
super("RSA/ECB/OAEPWithSHA-1AndMGF1Padding", publicKey, null, "");
super("RSA/ECB/OAEPWithSHA-1AndMGF1Padding", publicKey, null, "6CDDAA92CAD75998325027647847330C1756291");
}
}