mirror of
https://github.com/google/nomulus.git
synced 2025-05-01 04:27:51 +02:00
Dagger updated to 2.13, along with all its dependencies. Also allows us to have multiple config files for different environment (prod, sandbox, alpha, local, etc) and specify which one to use on the command line with a --env flag. Therefore the same binary can be used in all environments. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=176551289
251 lines
10 KiB
Java
251 lines
10 KiB
Java
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package google.registry.proxy;
|
|
|
|
import static com.google.common.truth.Truth.assertThat;
|
|
import static google.registry.proxy.handler.ProxyProtocolHandler.REMOTE_ADDRESS_KEY;
|
|
import static google.registry.proxy.handler.SslServerInitializer.CLIENT_CERTIFICATE_PROMISE_KEY;
|
|
import static google.registry.util.ResourceUtils.readResourceBytes;
|
|
import static google.registry.util.X509Utils.getCertificateHash;
|
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
|
|
|
import google.registry.testing.FakeClock;
|
|
import io.netty.buffer.ByteBuf;
|
|
import io.netty.buffer.Unpooled;
|
|
import io.netty.channel.embedded.EmbeddedChannel;
|
|
import io.netty.handler.codec.http.FullHttpRequest;
|
|
import io.netty.handler.codec.http.FullHttpResponse;
|
|
import io.netty.handler.codec.http.HttpResponseStatus;
|
|
import io.netty.handler.codec.http.cookie.Cookie;
|
|
import io.netty.handler.codec.http.cookie.DefaultCookie;
|
|
import io.netty.handler.ssl.util.SelfSignedCertificate;
|
|
import io.netty.util.concurrent.Promise;
|
|
import java.security.cert.X509Certificate;
|
|
import org.junit.Before;
|
|
import org.junit.Test;
|
|
import org.junit.runner.RunWith;
|
|
import org.junit.runners.JUnit4;
|
|
|
|
/** End-to-end tests for {@link EppProtocolModule}. */
|
|
@RunWith(JUnit4.class)
|
|
public class EppProtocolModuleTest extends ProtocolModuleTest {
|
|
|
|
private static final int HEADER_LENGTH = 4;
|
|
|
|
private static final String CLIENT_ADDRESS = "epp.client.tld";
|
|
|
|
private static final byte[] HELLO_BYTES =
|
|
("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
|
|
+ "<epp xmlns=\"urn:ietf:params:xml:ns:epp-1.0\">\n"
|
|
+ " <hello/>\n"
|
|
+ "</epp>\n")
|
|
.getBytes(UTF_8);
|
|
|
|
private X509Certificate certificate;
|
|
|
|
public EppProtocolModuleTest() {
|
|
super(TestComponent::eppHandlers);
|
|
}
|
|
|
|
/** Verifies that the epp message content is represented by the buffers. */
|
|
private static void assertBufferRepresentsContent(ByteBuf buffer, byte[] expectedContents) {
|
|
// First make sure that buffer length is expected content length plus header length.
|
|
assertThat(buffer.readableBytes()).isEqualTo(expectedContents.length + HEADER_LENGTH);
|
|
// Then check if the header value is indeed expected content length plus header length.
|
|
assertThat(buffer.readInt()).isEqualTo(expectedContents.length + HEADER_LENGTH);
|
|
// Finally check the buffer contains the expected contents.
|
|
byte[] actualContents = new byte[expectedContents.length];
|
|
buffer.readBytes(actualContents);
|
|
assertThat(actualContents).isEqualTo(expectedContents);
|
|
}
|
|
|
|
/**
|
|
* Read all available outbound frames and make a composite {@link ByteBuf} consisting all of them.
|
|
*
|
|
* <p>This is needed because {@link io.netty.handler.codec.LengthFieldPrepender} does not
|
|
* necessary output only one {@link ByteBuf} from one input message. We need to reassemble the
|
|
* frames together in order to obtain the processed message (prepended with length header).
|
|
*/
|
|
private static ByteBuf getAllOutboundFrames(EmbeddedChannel channel) {
|
|
ByteBuf combinedBuffer = Unpooled.buffer();
|
|
ByteBuf buffer;
|
|
while ((buffer = channel.readOutbound()) != null) {
|
|
combinedBuffer.writeBytes(buffer);
|
|
}
|
|
return combinedBuffer;
|
|
}
|
|
|
|
/** Get a {@link ByteBuf} that represents the raw epp request with the given content. */
|
|
private ByteBuf getByteBufFromContent(byte[] content) {
|
|
ByteBuf buffer = Unpooled.buffer();
|
|
buffer.writeInt(content.length + HEADER_LENGTH);
|
|
buffer.writeBytes(content);
|
|
return buffer;
|
|
}
|
|
|
|
private FullHttpRequest makeEppHttpRequest(byte[] content, Cookie... cookies) {
|
|
return TestUtils.makeEppHttpRequest(
|
|
new String(content, UTF_8),
|
|
PROXY_CONFIG.epp.relayHost,
|
|
PROXY_CONFIG.epp.relayPath,
|
|
TestModule.provideFakeAccessToken().get(),
|
|
getCertificateHash(certificate),
|
|
PROXY_CONFIG.epp.serverHostname,
|
|
CLIENT_ADDRESS,
|
|
cookies);
|
|
}
|
|
|
|
private FullHttpResponse makeEppHttpResponse(byte[] content, Cookie... cookies) {
|
|
return TestUtils.makeEppHttpResponse(
|
|
new String(content, UTF_8), HttpResponseStatus.OK, cookies);
|
|
}
|
|
|
|
@Override
|
|
@Before
|
|
public void setUp() throws Exception {
|
|
testComponent = makeTestComponent(new FakeClock());
|
|
certificate = new SelfSignedCertificate().cert();
|
|
initializeChannel(
|
|
ch -> {
|
|
ch.attr(REMOTE_ADDRESS_KEY).set(CLIENT_ADDRESS);
|
|
ch.attr(CLIENT_CERTIFICATE_PROMISE_KEY).set(ch.eventLoop().newPromise());
|
|
addAllTestableHandlers(ch);
|
|
});
|
|
Promise<X509Certificate> unusedPromise =
|
|
channel.attr(CLIENT_CERTIFICATE_PROMISE_KEY).get().setSuccess(certificate);
|
|
}
|
|
|
|
@Test
|
|
public void testSuccess_singleFrameInboundMessage() throws Exception {
|
|
// First inbound message is hello.
|
|
assertThat((FullHttpRequest) channel.readInbound()).isEqualTo(makeEppHttpRequest(HELLO_BYTES));
|
|
|
|
byte[] inputBytes = readResourceBytes(getClass(), "testdata/login.xml").read();
|
|
|
|
// Verify inbound message is as expected.
|
|
assertThat(channel.writeInbound(getByteBufFromContent(inputBytes))).isTrue();
|
|
assertThat((FullHttpRequest) channel.readInbound()).isEqualTo(makeEppHttpRequest(inputBytes));
|
|
|
|
// Nothing more to read.
|
|
assertThat((Object) channel.readInbound()).isNull();
|
|
assertThat(channel.isActive()).isTrue();
|
|
}
|
|
|
|
@Test
|
|
public void testSuccess_SingleFrame_MultipleInboundMessages() throws Exception {
|
|
// First inbound message is hello.
|
|
channel.readInbound();
|
|
|
|
byte[] inputBytes1 = readResourceBytes(getClass(), "testdata/login.xml").read();
|
|
byte[] inputBytes2 = readResourceBytes(getClass(), "testdata/logout.xml").read();
|
|
|
|
// Verify inbound messages are as expected.
|
|
assertThat(
|
|
channel.writeInbound(
|
|
Unpooled.wrappedBuffer(
|
|
getByteBufFromContent(inputBytes1), getByteBufFromContent(inputBytes2))))
|
|
.isTrue();
|
|
assertThat((FullHttpRequest) channel.readInbound()).isEqualTo(makeEppHttpRequest(inputBytes1));
|
|
assertThat((FullHttpRequest) channel.readInbound()).isEqualTo(makeEppHttpRequest(inputBytes2));
|
|
|
|
// Nothing more to read.
|
|
assertThat((Object) channel.readInbound()).isNull();
|
|
assertThat(channel.isActive()).isTrue();
|
|
}
|
|
|
|
@Test
|
|
public void testSuccess_MultipleFrames_MultipleInboundMessages() throws Exception {
|
|
// First inbound message is hello.
|
|
channel.readInbound();
|
|
|
|
byte[] inputBytes1 = readResourceBytes(getClass(), "testdata/login.xml").read();
|
|
byte[] inputBytes2 = readResourceBytes(getClass(), "testdata/logout.xml").read();
|
|
ByteBuf inputBuffer =
|
|
Unpooled.wrappedBuffer(
|
|
getByteBufFromContent(inputBytes1), getByteBufFromContent(inputBytes2));
|
|
|
|
// The first frame does not contain the entire first message because it is missing 4 byte of
|
|
// header length.
|
|
assertThat(channel.writeInbound(inputBuffer.readBytes(inputBytes1.length))).isFalse();
|
|
|
|
// The second frame contains the first message, and part of the second message.
|
|
assertThat(channel.writeInbound(inputBuffer.readBytes(inputBytes2.length))).isTrue();
|
|
assertThat((FullHttpRequest) channel.readInbound()).isEqualTo(makeEppHttpRequest(inputBytes1));
|
|
|
|
// The third frame contains the rest of the second message.
|
|
assertThat(channel.writeInbound(inputBuffer)).isTrue();
|
|
assertThat((FullHttpRequest) channel.readInbound()).isEqualTo(makeEppHttpRequest(inputBytes2));
|
|
|
|
// Nothing more to read.
|
|
assertThat((Object) channel.readInbound()).isNull();
|
|
assertThat(channel.isActive()).isTrue();
|
|
}
|
|
|
|
@Test
|
|
public void testSuccess_simpleOutboundMessage() throws Exception {
|
|
// First inbound message is hello.
|
|
channel.readInbound();
|
|
|
|
byte[] outputBytes = readResourceBytes(getClass(), "testdata/login_response.xml").read();
|
|
|
|
// Verify outbound message is as expected.
|
|
assertThat(channel.writeOutbound(makeEppHttpResponse(outputBytes))).isTrue();
|
|
assertBufferRepresentsContent(getAllOutboundFrames(channel), outputBytes);
|
|
|
|
// Nothing more to write.
|
|
assertThat((Object) channel.readOutbound()).isNull();
|
|
assertThat(channel.isActive()).isTrue();
|
|
}
|
|
|
|
@Test
|
|
public void testSuccess_setAndReadCookies() throws Exception {
|
|
// First inbound message is hello.
|
|
channel.readInbound();
|
|
|
|
byte[] outputBytes1 = readResourceBytes(getClass(), "testdata/login_response.xml").read();
|
|
Cookie cookie1 = new DefaultCookie("name1", "value1");
|
|
Cookie cookie2 = new DefaultCookie("name2", "value2");
|
|
|
|
// Verify outbound message is as expected.
|
|
assertThat(channel.writeOutbound(makeEppHttpResponse(outputBytes1, cookie1, cookie2))).isTrue();
|
|
assertBufferRepresentsContent(getAllOutboundFrames(channel), outputBytes1);
|
|
|
|
// Verify inbound message contains cookies.
|
|
byte[] inputBytes1 = readResourceBytes(getClass(), "testdata/logout.xml").read();
|
|
assertThat(channel.writeInbound(getByteBufFromContent(inputBytes1))).isTrue();
|
|
assertThat((FullHttpRequest) channel.readInbound())
|
|
.isEqualTo(makeEppHttpRequest(inputBytes1, cookie1, cookie2));
|
|
|
|
// Second outbound message change cookies.
|
|
byte[] outputBytes2 = readResourceBytes(getClass(), "testdata/logout_response.xml").read();
|
|
Cookie cookie3 = new DefaultCookie("name3", "value3");
|
|
cookie2 = new DefaultCookie("name2", "newValue2");
|
|
|
|
// Verify outbound message is as expected.
|
|
assertThat(channel.writeOutbound(makeEppHttpResponse(outputBytes2, cookie2, cookie3))).isTrue();
|
|
assertBufferRepresentsContent(getAllOutboundFrames(channel), outputBytes2);
|
|
|
|
// Verify inbound message contains updated cookies.
|
|
byte[] inputBytes2 = readResourceBytes(getClass(), "testdata/login.xml").read();
|
|
assertThat(channel.writeInbound(getByteBufFromContent(inputBytes2))).isTrue();
|
|
assertThat((FullHttpRequest) channel.readInbound())
|
|
.isEqualTo(makeEppHttpRequest(inputBytes2, cookie1, cookie2, cookie3));
|
|
|
|
// Nothing more to write or read.
|
|
assertThat((Object) channel.readOutbound()).isNull();
|
|
assertThat((Object) channel.readInbound()).isNull();
|
|
assertThat(channel.isActive()).isTrue();
|
|
}
|
|
}
|