This is an automated email from the ASF dual-hosted git repository. eolivelli pushed a commit to branch branch-2.7 in repository https://gitbox.apache.org/repos/asf/pulsar.git
The following commit(s) were added to refs/heads/branch-2.7 by this push: new 16387e2 [WebSocket Client] WebSocket url token param value optimization (#10187) 16387e2 is described below commit 16387e2f8dd35eefa3ce24b06a3d2d1138b9532a Author: ran <gaoran...@126.com> AuthorDate: Fri Apr 16 01:47:24 2021 +0800 [WebSocket Client] WebSocket url token param value optimization (#10187) * Remove the `Bearer ` prefix requirement for the token param value of the WebSocket url. * add mock request test (cherry picked from commit 3e5fbcea4c424302cfd258d1238d2135eca2a555) --- .../WebSocketHttpServletRequestWrapper.java | 8 +- .../WebSocketHttpServletRequestWrapperTest.java | 85 ++++++++++++++ pulsar-websocket/src/test/resources/my-public.key | Bin 0 -> 294 bytes pulsar-websocket/src/test/resources/websocket.conf | 127 +++++++++++++++++++++ 4 files changed, 218 insertions(+), 2 deletions(-) diff --git a/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/WebSocketHttpServletRequestWrapper.java b/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/WebSocketHttpServletRequestWrapper.java index 29602a8..22cf7d1 100644 --- a/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/WebSocketHttpServletRequestWrapper.java +++ b/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/WebSocketHttpServletRequestWrapper.java @@ -22,13 +22,13 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import org.eclipse.jetty.websocket.servlet.UpgradeHttpServletRequest; - /** * WebSocket HttpServletRequest wrapper. */ public class WebSocketHttpServletRequestWrapper extends HttpServletRequestWrapper { final static String HTTP_HEADER_NAME = "Authorization"; + final static String HTTP_HEADER_VALUE_PREFIX = "Bearer "; final static String TOKEN = "token"; public WebSocketHttpServletRequestWrapper(HttpServletRequest request) { @@ -41,7 +41,11 @@ public class WebSocketHttpServletRequestWrapper extends HttpServletRequestWrappe // query param `token` to transport the auth token for the browser javascript WebSocket client. if (name.equals(HTTP_HEADER_NAME) && !((UpgradeHttpServletRequest) this.getRequest()).getHeaders().containsKey(HTTP_HEADER_NAME)) { - return getRequest().getParameter(TOKEN); + String token = getRequest().getParameter(TOKEN); + if (token != null && !token.startsWith(HTTP_HEADER_VALUE_PREFIX)) { + return HTTP_HEADER_VALUE_PREFIX + token; + } + return token; } return super.getHeader(name); } diff --git a/pulsar-websocket/src/test/java/org/apache/pulsar/websocket/WebSocketHttpServletRequestWrapperTest.java b/pulsar-websocket/src/test/java/org/apache/pulsar/websocket/WebSocketHttpServletRequestWrapperTest.java new file mode 100644 index 0000000..52bee3f --- /dev/null +++ b/pulsar-websocket/src/test/java/org/apache/pulsar/websocket/WebSocketHttpServletRequestWrapperTest.java @@ -0,0 +1,85 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.pulsar.websocket; + +import org.apache.pulsar.common.configuration.PulsarConfigurationLoader; +import org.apache.pulsar.websocket.service.WebSocketProxyConfiguration; +import org.eclipse.jetty.websocket.servlet.UpgradeHttpServletRequest; +import org.junit.Assert; +import org.mockito.Mockito; +import org.testng.annotations.Test; + +/** + * WebSocketHttpServletRequestWrapper test. + */ +public class WebSocketHttpServletRequestWrapperTest { + + private final static String TOKEN = "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ0ZXN0LXVzZXIifQ.U387jG" + + "-gmpEXNmTjbnnnk24jCXnfy7OTiQhhhOdXPgV2wEvZYr83KRSmH54wJQr4V2FCWIFb_6mBc_" + + "E2acpfpfBOTTzrtietfhd6wE5uOP2NXaLpy_kUDsE3ZQGKPEsn18cWQUw54GAzS1oRcG9TnoqSCSFFGabvo" + + "FTiOMHoBQ3ZHO3TqAGqlJlRF5ZXMkRtQ9vwbPC-mlwIfRrRIJfK5_ijPRkpgFSEvAwp0rX6roz08SyTj_" + + "d4UNT96nsEL6sRNTpZMQ0qNj2_LMKFnwF3O_xe43-Uen3TllkAzhNd9Z6qIxyJyFbaFyWAVgiAfoFWQD0v4EmV96ZzKZvv3CbGjw"; + private final static String BEARER_TOKEN = WebSocketHttpServletRequestWrapper.HTTP_HEADER_VALUE_PREFIX + TOKEN; + + @Test + public void testTokenParamWithBearerPrefix() { + UpgradeHttpServletRequest httpServletRequest = Mockito.mock(UpgradeHttpServletRequest.class); + Mockito.when(httpServletRequest.getParameter(WebSocketHttpServletRequestWrapper.TOKEN)) + .thenReturn(BEARER_TOKEN); + + WebSocketHttpServletRequestWrapper webSocketHttpServletRequestWrapper = + new WebSocketHttpServletRequestWrapper(httpServletRequest); + Assert.assertEquals(BEARER_TOKEN, + webSocketHttpServletRequestWrapper.getHeader(WebSocketHttpServletRequestWrapper.HTTP_HEADER_NAME)); + } + + @Test + public void testTokenParamWithOutBearerPrefix() { + UpgradeHttpServletRequest httpServletRequest = Mockito.mock(UpgradeHttpServletRequest.class); + Mockito.when(httpServletRequest.getParameter(WebSocketHttpServletRequestWrapper.TOKEN)) + .thenReturn(TOKEN); + + WebSocketHttpServletRequestWrapper webSocketHttpServletRequestWrapper = + new WebSocketHttpServletRequestWrapper(httpServletRequest); + Assert.assertEquals(BEARER_TOKEN, + webSocketHttpServletRequestWrapper.getHeader(WebSocketHttpServletRequestWrapper.HTTP_HEADER_NAME)); + } + + @Test + public void mockRequestTest() throws Exception { + WebSocketProxyConfiguration config = PulsarConfigurationLoader.create( + this.getClass().getClassLoader().getResource("websocket.conf").getFile(), + WebSocketProxyConfiguration.class); + String publicKeyPath = this.getClass().getClassLoader().getResource("my-public.key").getFile(); + config.getProperties().setProperty("tokenPublicKey", publicKeyPath); + WebSocketService service = new WebSocketService(config); + service.start(); + + UpgradeHttpServletRequest httpServletRequest = Mockito.mock(UpgradeHttpServletRequest.class); + Mockito.when(httpServletRequest.getRemoteAddr()).thenReturn("localhost"); + Mockito.when(httpServletRequest.getRemotePort()).thenReturn(8080); + Mockito.when(httpServletRequest.getParameter(WebSocketHttpServletRequestWrapper.TOKEN)) + .thenReturn(TOKEN); + WebSocketHttpServletRequestWrapper webSocketHttpServletRequestWrapper = + new WebSocketHttpServletRequestWrapper(httpServletRequest); + + Assert.assertEquals("test-user", service.getAuthenticationService().authenticateHttpRequest(webSocketHttpServletRequestWrapper)); + } + +} diff --git a/pulsar-websocket/src/test/resources/my-public.key b/pulsar-websocket/src/test/resources/my-public.key new file mode 100644 index 0000000..43ca81e Binary files /dev/null and b/pulsar-websocket/src/test/resources/my-public.key differ diff --git a/pulsar-websocket/src/test/resources/websocket.conf b/pulsar-websocket/src/test/resources/websocket.conf new file mode 100644 index 0000000..3d62926 --- /dev/null +++ b/pulsar-websocket/src/test/resources/websocket.conf @@ -0,0 +1,127 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +### --- Web Socket proxy settings --- ### + +# Configuration Store connection string +configurationStoreServers=memory://127.0.0.1:2181 + +# Zookeeper session timeout in milliseconds +zooKeeperSessionTimeoutMillis=30000 +# ZooKeeper cache expiry time in seconds +zooKeeperCacheExpirySeconds=300 + +# Pulsar cluster url to connect to broker (optional if configurationStoreServers present) +serviceUrl=localhost:6650 +serviceUrlTls= +brokerServiceUrl= +brokerServiceUrlTls= + +# Port to use to server HTTP request +webServicePort=8080 +# Port to use to server HTTPS request +webServicePortTls= + +# Path for the file used to determine the rotation status for the proxy-instance when responding +# to service discovery health checks +statusFilePath= + +# Hostname or IP address the service binds on, default is 0.0.0.0. +bindAddress=0.0.0.0 + +# Name of the pulsar cluster to connect to +clusterName=standalone + +# Number of IO threads in Pulsar Client used in WebSocket proxy +webSocketNumIoThreads=8 + +# Number of threads to use in HTTP server. Default is Runtime.getRuntime().availableProcessors() +numHttpServerThreads= + +# Number of connections per Broker in Pulsar Client used in WebSocket proxy +webSocketConnectionsPerBroker=8 + +# Time in milliseconds that idle WebSocket session times out +webSocketSessionIdleTimeoutMillis=300000 + +# The maximum size of a text message during parsing in WebSocket proxy +webSocketMaxTextFrameSize=1048576 + +### --- Authentication --- ### + +# Enable authentication +authenticationEnabled=true + +# Autentication provider name list, which is comma separated list of class names +authenticationProviders=org.apache.pulsar.broker.authentication.AuthenticationProviderToken + +# Enforce authorization +authorizationEnabled=true + +# Authorization provider fully qualified class-name +authorizationProvider=org.apache.pulsar.broker.authorization.PulsarAuthorizationProvider + +# Allow wildcard matching in authorization +# (wildcard matching only applicable if wildcard-char: +# * presents at first or last position eg: *.pulsar.service, pulsar.service.*) +authorizationAllowWildcardsMatching=false + +# Role names that are treated as "super-user", meaning they will be able to do all admin +# operations and publish/consume from all topics +superUserRoles=test-user + +tokenPublicKey=./my-public.key + +# Authentication settings of the proxy itself. Used to connect to brokers +brokerClientTlsEnabled=false +brokerClientAuthenticationPlugin= +brokerClientAuthenticationParameters= +brokerClientTrustCertsFilePath= + +# When this parameter is not empty, unauthenticated users perform as anonymousUserRole +anonymousUserRole= + +### --- TLS --- ### + +# Deprecated - use webServicePortTls and brokerClientTlsEnabled instead +tlsEnabled=false + +# Accept untrusted TLS certificate from client +tlsAllowInsecureConnection=false + +# Path for the TLS certificate file +tlsCertificateFilePath= + +# Path for the TLS private key file +tlsKeyFilePath= + +# Path for the trusted TLS certificate file +tlsTrustCertsFilePath= + +# Specify whether Client certificates are required for TLS +# Reject the Connection if the Client Certificate is not trusted. +tlsRequireTrustedClientCertOnConnect=false + +# Tls cert refresh duration in seconds (set 0 to check on every new connection) +tlsCertRefreshCheckDurationSec=300 + +### --- Deprecated config variables --- ### + +# Deprecated. Use configurationStoreServers +globalZookeeperServers=