From 51bf98cdc5409fee24ad989e9541c74be76a0151 Mon Sep 17 00:00:00 2001 From: hengyunabc Date: Fri, 5 Mar 2021 17:19:28 +0800 Subject: [PATCH] support username/password in url; websocket support url with parameters. #1655 #1727 --- .../taobao/arthas/common/ArthasConstants.java | 3 ++ .../http/BasicHttpAuthenticatorHandler.java | 35 ++++++++++++++++++- .../term/impl/http/HttpRequestHandler.java | 4 +-- .../impl/http/LocalTtyServerInitializer.java | 6 ++-- .../term/impl/http/TtyServerInitializer.java | 4 +-- .../httptelnet/ProtocolDetectHandler.java | 4 +-- .../arthas/tunnel/server/TunnelServer.java | 4 +-- .../app/configuration/ArthasProperties.java | 4 +-- 8 files changed, 49 insertions(+), 15 deletions(-) diff --git a/common/src/main/java/com/taobao/arthas/common/ArthasConstants.java b/common/src/main/java/com/taobao/arthas/common/ArthasConstants.java index db9a20b74..abed4cf58 100644 --- a/common/src/main/java/com/taobao/arthas/common/ArthasConstants.java +++ b/common/src/main/java/com/taobao/arthas/common/ArthasConstants.java @@ -25,6 +25,7 @@ public class ArthasConstants { public static final int TELNET_PORT = 3658; + public static final String DEFAULT_WEBSOCKET_PATH = "/ws"; public static final int WEBSOCKET_IDLE_SECONDS = 60; /** @@ -35,4 +36,6 @@ public class ArthasConstants { public static final String DEFAULT_USERNAME = "arthas"; public static final String SUBJECT_KEY = "subject"; public static final String AUTH = "auth"; + public static final String USERNAME_KEY = "username"; + public static final String PASSWORD_KEY = "password"; } diff --git a/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/BasicHttpAuthenticatorHandler.java b/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/BasicHttpAuthenticatorHandler.java index b9a6e8b37..b14975cd1 100644 --- a/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/BasicHttpAuthenticatorHandler.java +++ b/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/BasicHttpAuthenticatorHandler.java @@ -1,6 +1,8 @@ package com.taobao.arthas.core.shell.term.impl.http; import java.nio.charset.Charset; +import java.util.List; +import java.util.Map; import javax.security.auth.Subject; @@ -26,6 +28,7 @@ import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpVersion; +import io.netty.handler.codec.http.QueryStringDecoder; import io.netty.util.Attribute; /** @@ -61,9 +64,13 @@ public final class BasicHttpAuthenticatorHandler extends ChannelDuplexHandler { authed = true; } - // 判断请求header里是否带有 username/password if (!authed) { + // 判断请求header里是否带有 username/password BasicPrincipal principal = extractBasicAuthSubject(httpRequest); + if (principal == null) { + // 判断 url里是否有 username/password + principal = extractBasicAuthSubjectFromUrl(httpRequest); + } Subject subject = securityAuthenticator.login(principal); if (subject != null) { authed = true; @@ -103,6 +110,32 @@ public final class BasicHttpAuthenticatorHandler extends ChannelDuplexHandler { super.write(ctx, msg, promise); } + /** + * 从url参数里提取 ?username=hello&password=world + * + * @param request + * @return + */ + protected static BasicPrincipal extractBasicAuthSubjectFromUrl(HttpRequest request) { + QueryStringDecoder queryDecoder = new QueryStringDecoder(request.uri()); + Map> parameters = queryDecoder.parameters(); + + List passwords = parameters.get(ArthasConstants.PASSWORD_KEY); + if (passwords == null || passwords.size() == 0) { + return null; + } + String password = passwords.get(0); + + String username = ArthasConstants.DEFAULT_USERNAME; + List usernames = parameters.get(ArthasConstants.USERNAME_KEY); + if (usernames != null && !usernames.isEmpty()) { + username = usernames.get(0); + } + BasicPrincipal principal = new BasicPrincipal(username, password); + logger.debug("Extracted Basic Auth principal from url: {}", principal); + return principal; + } + /** * Extracts the username and password details from the HTTP basic header * Authorization. diff --git a/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/HttpRequestHandler.java b/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/HttpRequestHandler.java index c2589e90b..43c23d9e8 100644 --- a/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/HttpRequestHandler.java +++ b/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/HttpRequestHandler.java @@ -59,7 +59,8 @@ public class HttpRequestHandler extends SimpleChannelInboundHandler pipeline.addLast(new HttpServerCodec()); pipeline.addLast(new ChunkedWriteHandler()); pipeline.addLast(new HttpObjectAggregator(ArthasConstants.MAX_HTTP_CONTENT_LENGTH)); - pipeline.addLast(workerGroup, "HttpRequestHandler", new HttpRequestHandler("/ws")); - pipeline.addLast(new WebSocketServerProtocolHandler("/ws")); + pipeline.addLast(workerGroup, "HttpRequestHandler", new HttpRequestHandler(ArthasConstants.DEFAULT_WEBSOCKET_PATH)); + pipeline.addLast(new WebSocketServerProtocolHandler(ArthasConstants.DEFAULT_WEBSOCKET_PATH, true)); pipeline.addLast(new IdleStateHandler(0, 0, ArthasConstants.WEBSOCKET_IDLE_SECONDS)); pipeline.addLast(new TtyWebSocketFrameHandler(group, handler)); } diff --git a/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/TtyServerInitializer.java b/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/TtyServerInitializer.java index d6582de68..b130cb8ca 100644 --- a/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/TtyServerInitializer.java +++ b/core/src/main/java/com/taobao/arthas/core/shell/term/impl/http/TtyServerInitializer.java @@ -42,8 +42,8 @@ public class TtyServerInitializer extends ChannelInitializer { pipeline.addLast(new ChunkedWriteHandler()); pipeline.addLast(new HttpObjectAggregator(ArthasConstants.MAX_HTTP_CONTENT_LENGTH)); pipeline.addLast(new BasicHttpAuthenticatorHandler(httpSessionManager)); - pipeline.addLast(workerGroup, "HttpRequestHandler", new HttpRequestHandler("/ws")); - pipeline.addLast(new WebSocketServerProtocolHandler("/ws")); + pipeline.addLast(workerGroup, "HttpRequestHandler", new HttpRequestHandler(ArthasConstants.DEFAULT_WEBSOCKET_PATH)); + pipeline.addLast(new WebSocketServerProtocolHandler(ArthasConstants.DEFAULT_WEBSOCKET_PATH, true)); pipeline.addLast(new IdleStateHandler(0, 0, ArthasConstants.WEBSOCKET_IDLE_SECONDS)); pipeline.addLast(new TtyWebSocketFrameHandler(group, handler)); } diff --git a/core/src/main/java/com/taobao/arthas/core/shell/term/impl/httptelnet/ProtocolDetectHandler.java b/core/src/main/java/com/taobao/arthas/core/shell/term/impl/httptelnet/ProtocolDetectHandler.java index 2b217320b..7525fce12 100644 --- a/core/src/main/java/com/taobao/arthas/core/shell/term/impl/httptelnet/ProtocolDetectHandler.java +++ b/core/src/main/java/com/taobao/arthas/core/shell/term/impl/httptelnet/ProtocolDetectHandler.java @@ -93,8 +93,8 @@ public class ProtocolDetectHandler extends ChannelInboundHandlerAdapter { pipeline.addLast(new ChunkedWriteHandler()); pipeline.addLast(new HttpObjectAggregator(ArthasConstants.MAX_HTTP_CONTENT_LENGTH)); pipeline.addLast(new BasicHttpAuthenticatorHandler(httpSessionManager)); - pipeline.addLast(workerGroup, "HttpRequestHandler", new HttpRequestHandler("/ws")); - pipeline.addLast(new WebSocketServerProtocolHandler("/ws")); + pipeline.addLast(workerGroup, "HttpRequestHandler", new HttpRequestHandler(ArthasConstants.DEFAULT_WEBSOCKET_PATH)); + pipeline.addLast(new WebSocketServerProtocolHandler(ArthasConstants.DEFAULT_WEBSOCKET_PATH, true)); pipeline.addLast(new IdleStateHandler(0, 0, ArthasConstants.WEBSOCKET_IDLE_SECONDS)); pipeline.addLast(new TtyWebSocketFrameHandler(channelGroup, ttyConnectionFactory)); ctx.fireChannelActive(); diff --git a/tunnel-server/src/main/java/com/alibaba/arthas/tunnel/server/TunnelServer.java b/tunnel-server/src/main/java/com/alibaba/arthas/tunnel/server/TunnelServer.java index 9592c4118..ffe3dc72c 100644 --- a/tunnel-server/src/main/java/com/alibaba/arthas/tunnel/server/TunnelServer.java +++ b/tunnel-server/src/main/java/com/alibaba/arthas/tunnel/server/TunnelServer.java @@ -12,6 +12,7 @@ import org.slf4j.LoggerFactory; import com.alibaba.arthas.tunnel.common.SimpleHttpResponse; import com.alibaba.arthas.tunnel.server.cluster.TunnelClusterStore; +import com.taobao.arthas.common.ArthasConstants; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; @@ -33,12 +34,11 @@ import io.netty.util.concurrent.Promise; */ public class TunnelServer { private final static Logger logger = LoggerFactory.getLogger(TunnelServer.class); - public static final String DEFAULT_WEBSOCKET_PATH = "/ws"; private boolean ssl; private String host; private int port; - private String path = DEFAULT_WEBSOCKET_PATH; + private String path = ArthasConstants.DEFAULT_WEBSOCKET_PATH; private Map agentInfoMap = new ConcurrentHashMap(); diff --git a/tunnel-server/src/main/java/com/alibaba/arthas/tunnel/server/app/configuration/ArthasProperties.java b/tunnel-server/src/main/java/com/alibaba/arthas/tunnel/server/app/configuration/ArthasProperties.java index 927328f33..1b59c8cd1 100644 --- a/tunnel-server/src/main/java/com/alibaba/arthas/tunnel/server/app/configuration/ArthasProperties.java +++ b/tunnel-server/src/main/java/com/alibaba/arthas/tunnel/server/app/configuration/ArthasProperties.java @@ -6,8 +6,8 @@ import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; -import com.alibaba.arthas.tunnel.server.TunnelServer; import com.alibaba.arthas.tunnel.server.utils.InetAddressUtil; +import com.taobao.arthas.common.ArthasConstants; /** * @@ -58,7 +58,7 @@ public class ArthasProperties { private String host; private int port; private boolean ssl; - private String path = TunnelServer.DEFAULT_WEBSOCKET_PATH; + private String path = ArthasConstants.DEFAULT_WEBSOCKET_PATH; /** * 客户端连接的地址。也用于保存到redis里,当部署tunnel server集群里需要。不配置则会自动获取