mirror of
https://github.com/alibaba/canal.git
synced 2026-11-04 00:30:15 +08:00
fix(server/admin): 修复 Canal Admin 认证绕过漏洞 (#2076021)
在 ClientAuthenticationHandler.messageReceived() 的认证失败分支补充 ctx.getChannel().close() 与 return,防止 fall-through 到成功 ACK 分支 导致认证 handler 被移除、后续命令被当作已认证执行。 新增 ClientAuthenticationHandlerTest 覆盖错误密码、seed 为空、 认证成功三条路径。
This commit is contained in:
@@ -52,12 +52,16 @@ public class ClientAuthenticationHandler extends SimpleChannelHandler {
|
|||||||
byte[] errorBytes = AdminNettyUtils.errorPacket(300,
|
byte[] errorBytes = AdminNettyUtils.errorPacket(300,
|
||||||
MessageFormatter.format("auth failed for seed is null", clientAuth.getUsername()).getMessage());
|
MessageFormatter.format("auth failed for seed is null", clientAuth.getUsername()).getMessage());
|
||||||
AdminNettyUtils.write(ctx.getChannel(), errorBytes);
|
AdminNettyUtils.write(ctx.getChannel(), errorBytes);
|
||||||
|
ctx.getChannel().close();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!canalAdmin.auth(clientAuth.getUsername(), clientAuth.getPassword().toStringUtf8(), seed)) {
|
if (!canalAdmin.auth(clientAuth.getUsername(), clientAuth.getPassword().toStringUtf8(), seed)) {
|
||||||
byte[] errorBytes = AdminNettyUtils.errorPacket(300,
|
byte[] errorBytes = AdminNettyUtils.errorPacket(300,
|
||||||
MessageFormatter.format("auth failed for user:{}", clientAuth.getUsername()).getMessage());
|
MessageFormatter.format("auth failed for user:{}", clientAuth.getUsername()).getMessage());
|
||||||
AdminNettyUtils.write(ctx.getChannel(), errorBytes);
|
AdminNettyUtils.write(ctx.getChannel(), errorBytes);
|
||||||
|
ctx.getChannel().close();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] ackBytes = AdminNettyUtils.ackPacket();
|
byte[] ackBytes = AdminNettyUtils.ackPacket();
|
||||||
|
|||||||
@@ -0,0 +1,747 @@
|
|||||||
|
package com.alibaba.otter.canal.admin.handler;
|
||||||
|
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.jboss.netty.buffer.ChannelBuffer;
|
||||||
|
import org.jboss.netty.buffer.ChannelBuffers;
|
||||||
|
import org.jboss.netty.channel.Channel;
|
||||||
|
import org.jboss.netty.channel.ChannelEvent;
|
||||||
|
import org.jboss.netty.channel.ChannelFactory;
|
||||||
|
import org.jboss.netty.channel.ChannelFuture;
|
||||||
|
import org.jboss.netty.channel.ChannelFutureListener;
|
||||||
|
import org.jboss.netty.channel.ChannelHandler;
|
||||||
|
import org.jboss.netty.channel.ChannelHandlerContext;
|
||||||
|
import org.jboss.netty.channel.ChannelPipeline;
|
||||||
|
import org.jboss.netty.channel.ChannelSink;
|
||||||
|
import org.jboss.netty.channel.MessageEvent;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.alibaba.otter.canal.admin.CanalAdmin;
|
||||||
|
import com.alibaba.otter.canal.protocol.AdminPacket;
|
||||||
|
import com.alibaba.otter.canal.protocol.AdminPacket.Ack;
|
||||||
|
import com.alibaba.otter.canal.protocol.AdminPacket.Packet;
|
||||||
|
import com.google.protobuf.ByteString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for {@link ClientAuthenticationHandler} to ensure authentication
|
||||||
|
* failures do not fall-through to the success path (auth bypass).
|
||||||
|
*/
|
||||||
|
public class ClientAuthenticationHandlerTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAuthFailedShouldCloseChannelAndNotRemoveHandlers() throws Exception {
|
||||||
|
// Given a handler with a seed set and an admin that always rejects auth
|
||||||
|
ClientAuthenticationHandler handler = new ClientAuthenticationHandler(new RejectingCanalAdmin());
|
||||||
|
handler.setSeed(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 });
|
||||||
|
|
||||||
|
MockChannel channel = new MockChannel();
|
||||||
|
MockChannelPipeline pipeline = new MockChannelPipeline(channel);
|
||||||
|
channel.pipeline = pipeline;
|
||||||
|
MockChannelHandlerContext ctx = new MockChannelHandlerContext(channel, pipeline);
|
||||||
|
|
||||||
|
MessageEvent event = buildClientAuthEvent("admin", "wrong-password");
|
||||||
|
|
||||||
|
// When the auth packet arrives
|
||||||
|
handler.messageReceived(ctx, event);
|
||||||
|
|
||||||
|
// Then only one error packet is written, channel is closed and handlers are NOT removed
|
||||||
|
Assert.assertEquals("Expected exactly one write for the error packet", 1, channel.writes.size());
|
||||||
|
byte[] written = channel.writes.get(0);
|
||||||
|
Packet response = Packet.parseFrom(written);
|
||||||
|
Assert.assertEquals(AdminPacket.PacketType.ACK, response.getType());
|
||||||
|
Ack ack = Ack.parseFrom(response.getBody());
|
||||||
|
Assert.assertTrue("Expected error ack", ack.getCode() != 0);
|
||||||
|
Assert.assertTrue("Channel should be closed on auth failure", channel.closed);
|
||||||
|
Assert.assertEquals("Auth handler must not be removed on failure", 0, pipeline.removedHandlers.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNullSeedShouldCloseChannelAndNotRemoveHandlers() throws Exception {
|
||||||
|
// Given a handler with NO seed set (e.g. handshake not completed)
|
||||||
|
ClientAuthenticationHandler handler = new ClientAuthenticationHandler(new AcceptingCanalAdmin());
|
||||||
|
// seed intentionally left null
|
||||||
|
|
||||||
|
MockChannel channel = new MockChannel();
|
||||||
|
MockChannelPipeline pipeline = new MockChannelPipeline(channel);
|
||||||
|
channel.pipeline = pipeline;
|
||||||
|
MockChannelHandlerContext ctx = new MockChannelHandlerContext(channel, pipeline);
|
||||||
|
|
||||||
|
MessageEvent event = buildClientAuthEvent("admin", "any-password");
|
||||||
|
|
||||||
|
handler.messageReceived(ctx, event);
|
||||||
|
|
||||||
|
Assert.assertEquals("Expected exactly one write for the error packet", 1, channel.writes.size());
|
||||||
|
Packet response = Packet.parseFrom(channel.writes.get(0));
|
||||||
|
Assert.assertEquals(AdminPacket.PacketType.ACK, response.getType());
|
||||||
|
Ack ack = Ack.parseFrom(response.getBody());
|
||||||
|
Assert.assertTrue("Expected error ack", ack.getCode() != 0);
|
||||||
|
Assert.assertTrue("Channel should be closed when seed is null", channel.closed);
|
||||||
|
Assert.assertEquals("Auth handler must not be removed on failure", 0, pipeline.removedHandlers.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAuthSuccessShouldWriteAckAndRemoveHandlers() throws Exception {
|
||||||
|
// Given a handler with a seed set and an admin that accepts auth
|
||||||
|
ClientAuthenticationHandler handler = new ClientAuthenticationHandler(new AcceptingCanalAdmin());
|
||||||
|
handler.setSeed(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 });
|
||||||
|
|
||||||
|
MockChannel channel = new MockChannel();
|
||||||
|
MockChannelPipeline pipeline = new MockChannelPipeline(channel);
|
||||||
|
channel.pipeline = pipeline;
|
||||||
|
MockChannelHandlerContext ctx = new MockChannelHandlerContext(channel, pipeline);
|
||||||
|
|
||||||
|
MessageEvent event = buildClientAuthEvent("admin", "correct-password");
|
||||||
|
|
||||||
|
handler.messageReceived(ctx, event);
|
||||||
|
|
||||||
|
Assert.assertEquals("Expected exactly one write for the success ack", 1, channel.writes.size());
|
||||||
|
Packet response = Packet.parseFrom(channel.writes.get(0));
|
||||||
|
Assert.assertEquals(AdminPacket.PacketType.ACK, response.getType());
|
||||||
|
Ack ack = Ack.parseFrom(response.getBody());
|
||||||
|
Assert.assertEquals("Expected success ack", 0, ack.getCode());
|
||||||
|
Assert.assertFalse("Channel should NOT be closed on auth success", channel.closed);
|
||||||
|
Assert.assertEquals("Both handshake and auth handlers should be removed", 2, pipeline.removedHandlers.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
private MessageEvent buildClientAuthEvent(String username, String password) {
|
||||||
|
AdminPacket.ClientAuth clientAuth = AdminPacket.ClientAuth.newBuilder()
|
||||||
|
.setUsername(username)
|
||||||
|
.setPassword(ByteString.copyFromUtf8(password))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Packet packet = Packet.newBuilder()
|
||||||
|
.setType(AdminPacket.PacketType.CLIENTAUTHENTICATION)
|
||||||
|
.setVersion(3)
|
||||||
|
.setBody(clientAuth.toByteString())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
byte[] bytes = packet.toByteArray();
|
||||||
|
ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(bytes);
|
||||||
|
return new MockMessageEvent(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
// Simple stub implementations for Netty 3 interfaces used by the tests
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
|
private static class AcceptingCanalAdmin implements CanalAdmin {
|
||||||
|
@Override
|
||||||
|
public boolean auth(String username, String password, byte[] seed) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean check() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean start() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean stop() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean restart() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRunningInstances() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkInstance(String destination) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean startInstance(String destination) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean stopInstance(String destination) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean releaseInstance(String destination) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean restartInstance(String destination) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String listCanalLog() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String canalLog(int lines) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String listInstanceLog(String destination) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String instanceLog(String destination, String fileName, int lines) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class RejectingCanalAdmin implements CanalAdmin {
|
||||||
|
@Override
|
||||||
|
public boolean auth(String username, String password, byte[] seed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean check() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean start() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean stop() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean restart() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRunningInstances() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkInstance(String destination) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean startInstance(String destination) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean stopInstance(String destination) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean releaseInstance(String destination) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean restartInstance(String destination) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String listCanalLog() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String canalLog(int lines) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String listInstanceLog(String destination) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String instanceLog(String destination, String fileName, int lines) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class MockChannelFuture implements ChannelFuture {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Channel getChannel() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDone() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSuccess() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Throwable getCause() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean cancel() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setSuccess() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setFailure(Throwable cause) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setProgress(long amount, long current, long total) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addListener(ChannelFutureListener listener) {
|
||||||
|
try {
|
||||||
|
listener.operationComplete(this);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeListener(ChannelFutureListener listener) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelFuture await() throws InterruptedException {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelFuture awaitUninterruptibly() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean await(long timeoutMillis) throws InterruptedException {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean awaitUninterruptibly(long timeout, TimeUnit unit) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean awaitUninterruptibly(long timeoutMillis) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class MockChannel implements Channel {
|
||||||
|
|
||||||
|
final List<byte[]> writes = new ArrayList<>();
|
||||||
|
boolean closed = false;
|
||||||
|
MockChannelPipeline pipeline;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelFuture write(Object message) {
|
||||||
|
byte[] data = ((ChannelBuffer) message).array();
|
||||||
|
writes.add(data);
|
||||||
|
return new MockChannelFuture();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelFuture write(Object message, SocketAddress remoteAddress) {
|
||||||
|
return write(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelFuture close() {
|
||||||
|
closed = true;
|
||||||
|
return new MockChannelFuture();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelPipeline getPipeline() {
|
||||||
|
return pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getId() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelFactory getFactory() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Channel getParent() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public org.jboss.netty.channel.ChannelConfig getConfig() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOpen() {
|
||||||
|
return !closed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBound() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isConnected() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SocketAddress getLocalAddress() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SocketAddress getRemoteAddress() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelFuture bind(SocketAddress localAddress) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelFuture connect(SocketAddress remoteAddress) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelFuture disconnect() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelFuture unbind() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelFuture getCloseFuture() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getInterestOps() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReadable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWritable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelFuture setInterestOps(int interestOps) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelFuture setReadable(boolean readable) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Channel o) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class MockChannelPipeline implements ChannelPipeline {
|
||||||
|
|
||||||
|
final MockChannel channel;
|
||||||
|
final List<String> removedHandlers = new ArrayList<>();
|
||||||
|
|
||||||
|
MockChannelPipeline(MockChannel channel) {
|
||||||
|
this.channel = channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Channel getChannel() {
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendDownstream(ChannelEvent e) {
|
||||||
|
if (e instanceof MessageEvent) {
|
||||||
|
Object msg = ((MessageEvent) e).getMessage();
|
||||||
|
if (msg instanceof ChannelBuffer) {
|
||||||
|
ChannelBuffer buf = (ChannelBuffer) msg;
|
||||||
|
byte[] data = new byte[buf.readableBytes()];
|
||||||
|
buf.getBytes(buf.readerIndex(), data);
|
||||||
|
// AdminNettyUtils prepends a 4-byte length header; strip it
|
||||||
|
// before storing the protobuf body for easier assertions.
|
||||||
|
byte[] body = new byte[data.length - 4];
|
||||||
|
System.arraycopy(data, 4, body, 0, body.length);
|
||||||
|
channel.writes.add(body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e.getFuture().setSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(ChannelHandler handler) {
|
||||||
|
removedHandlers.add(handler.getClass().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelHandler remove(String name) {
|
||||||
|
removedHandlers.add(name);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends ChannelHandler> T remove(Class<T> handlerType) {
|
||||||
|
removedHandlers.add(handlerType.getName());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unused methods
|
||||||
|
@Override
|
||||||
|
public void addFirst(String name, ChannelHandler handler) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addLast(String name, ChannelHandler handler) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addBefore(String baseName, String name, ChannelHandler handler) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addAfter(String baseName, String name, ChannelHandler handler) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelHandler removeFirst() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelHandler removeLast() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelHandler replace(String oldName, String newName, ChannelHandler newHandler) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends ChannelHandler> T replace(Class<T> oldHandlerType, String newName, ChannelHandler newHandler) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelHandler getFirst() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelHandler getLast() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelHandler get(String name) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends ChannelHandler> T get(Class<T> handlerType) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelHandlerContext getContext(ChannelHandler handler) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelHandlerContext getContext(String name) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelHandlerContext getContext(Class<? extends ChannelHandler> handlerType) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendUpstream(ChannelEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelSink getSink() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void attach(Channel channel, ChannelSink sink) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAttached() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getNames() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, ChannelHandler> toMap() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class MockChannelHandlerContext implements ChannelHandlerContext {
|
||||||
|
|
||||||
|
private final Channel channel;
|
||||||
|
private final ChannelPipeline pipeline;
|
||||||
|
|
||||||
|
MockChannelHandlerContext(Channel channel, ChannelPipeline pipeline) {
|
||||||
|
this.channel = channel;
|
||||||
|
this.pipeline = pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Channel getChannel() {
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelPipeline getPipeline() {
|
||||||
|
return pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelHandler getHandler() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canHandleUpstream() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canHandleDownstream() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendUpstream(ChannelEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendDownstream(ChannelEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getAttachment() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAttachment(Object attachment) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class MockMessageEvent implements MessageEvent {
|
||||||
|
|
||||||
|
private final ChannelBuffer message;
|
||||||
|
|
||||||
|
MockMessageEvent(ChannelBuffer message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SocketAddress getRemoteAddress() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Channel getChannel() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelFuture getFuture() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user