feat: channel group test
parent
8af2c047b3
commit
5c3fd6eff4
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue