As always, thanks a lot for your work!
Describe the bug
Using the token request param in a WebSocket URL gives an unauthorized response, it seems is not working as intended in the documentation. I am only able to authorize using the Authorization header on the handshake HTTP request using a nodejs websocket client implementation but this is not possible when using the browser WebSocket API.
I think this was the reason the token request param was implemented in this commit by using a request wrapper. But I'm trying to send a token using this param and the AuthenticationFilter it's telling me that the request is unauthorized:
2022-07-15T14:11:23,010+0200 [pulsar-web-56-15] WARN org.apache.pulsar.broker.web.AuthenticationFilter - [127.0.0.1] Failed to authenticate HTTP request: Authentication required
2022-07-15T14:11:23,052+0200 [pulsar-web-56-15] INFO org.eclipse.jetty.server.RequestLog - 127.0.0.1 - - [15/jul./2022:14:11:22 +0200] "GET /ws/v2/consumer/persistent/public/default/test-topic/test-sub HTTP/1.1" 401 606 "-" "-" 64
For me it seems like the AuthenticationFilter is being executed before the request wrapper is applied, or directly not using the wrapped request. I've tried to download and execute the code to test this but its my first time trying to use Pulsar and I don't know still how to do it.
I've found an opened issue about WebSocket token authentication but seems very old compared with the commit that implemented the use of the token request parameter and I'm not sure why it was not closed once implementation was made. I've opened a new one because of that but, of course, feel free to close or manage this issue in the best way.
To Reproduce
To reproduce this, I have set a standalone Pulsar configuration following the steps on https://pulsar.apache.org/ja/docs/standalone/ with version 2.10.1 and modified the standalone.conf in order to set up JWT authentication/authorization checking:
Following are the properties I have modified on standalone.conf file:
# Enable authentication
authenticationEnabled=true
# Authentication 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.MultiRolesTokenAuthorizationProvider
superUserRoles=superuser
brokerClientAuthenticationPlugin=org.apache.pulsar.client.impl.auth.AuthenticationToken
brokerClientAuthenticationParameters={"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJyb2xlcyI6WyJzdXBlcnVzZXIiLCJ0ZXN0Il19.fwFySHYsYES_j4ggOwShLJFsYiLBP9Ng0note_bex8Q"}
tokenSecretKey=data:;base64,dGVzdHNlY3JldFRvb29Mb29vb25nVG9CZVJlbWVtYmVyZWRGb3JUaGVTYWtlT2ZTaW1wbGljaXR5VW5leHBlY3RlZFdoYXRldmVyMQ==
tokenAuthClaim=roles
Then, I've just opened a WebSocket connection against ws://localhost:8080/ws/v2/consumer/persistent/public/default/test-topic/test-sub?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJyb2xlcyI6WyJzdXBlcnVzZXIiXX0.t76ZTaEfMTONmznsi8DAQyJ1dtAcmlw1KVq5BisGEpw and received the unauthorized response.
As seen in a comment in the related issue, I've tested then the WebSocket connection using a nodejs application with the websocket library that allows me to put an Authorization header on the HTTP requests and it worked fine:
#!/usr/bin/env node
console.log('Starting websocket client...');
var WebSocketClient = require('websocket').client;
var client = new WebSocketClient();
client.on('connectFailed', function (error) {
console.log('Connect Error: ' + error.toString());
});
client.on('connect', function (connection) {
console.log('WebSocket Client Connected');
connection.on('error', function (error) {
console.log("Connection Error: " + error.toString());
});
connection.on('close', function () {
console.log('echo-protocol Connection Closed');
});
connection.on('message', function (message) {
console.log('Received message:', message);
});
});
client.connect(
'ws://localhost:8080/ws/v2/consumer/persistent/public/default/test-topic/test-sub',
null,
null,
{
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJyb2xlcyI6WyJzdXBlcnVzZXIiXX0.t76ZTaEfMTONmznsi8DAQyJ1dtAcmlw1KVq5BisGEpw'
}
);
As stated above, seems like the AuthenticationFilter is being executed without the wrapped request and thus is not retrieving the value of the token request param when checking the Authorization header.
Expected behavior
WebSocket connections should be authorized correctly when passing the token request parameter on the connection URL since WebSocket browser implementation does not allow to use custom HTTP headers (and it seems is the common way authorization is implemented, at least until WebSocket browser implementation is evolved to support sending HTTP headers).
Thanks for all your support!
As always, thanks a lot for your work!
Describe the bug
Using the
tokenrequest param in a WebSocket URL gives an unauthorized response, it seems is not working as intended in the documentation. I am only able to authorize using theAuthorizationheader on the handshake HTTP request using a nodejs websocket client implementation but this is not possible when using the browser WebSocket API.I think this was the reason the
tokenrequest param was implemented in this commit by using a request wrapper. But I'm trying to send a token using this param and the AuthenticationFilter it's telling me that the request is unauthorized:For me it seems like the AuthenticationFilter is being executed before the request wrapper is applied, or directly not using the wrapped request. I've tried to download and execute the code to test this but its my first time trying to use Pulsar and I don't know still how to do it.
I've found an opened issue about WebSocket token authentication but seems very old compared with the commit that implemented the use of the
tokenrequest parameter and I'm not sure why it was not closed once implementation was made. I've opened a new one because of that but, of course, feel free to close or manage this issue in the best way.To Reproduce
To reproduce this, I have set a standalone Pulsar configuration following the steps on https://pulsar.apache.org/ja/docs/standalone/ with version
2.10.1and modified thestandalone.confin order to set up JWT authentication/authorization checking:Following are the properties I have modified on
standalone.conffile:Then, I've just opened a WebSocket connection against
ws://localhost:8080/ws/v2/consumer/persistent/public/default/test-topic/test-sub?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJyb2xlcyI6WyJzdXBlcnVzZXIiXX0.t76ZTaEfMTONmznsi8DAQyJ1dtAcmlw1KVq5BisGEpwand received the unauthorized response.As seen in a comment in the related issue, I've tested then the WebSocket connection using a nodejs application with the websocket library that allows me to put an Authorization header on the HTTP requests and it worked fine:
As stated above, seems like the
AuthenticationFilteris being executed without the wrapped request and thus is not retrieving the value of thetokenrequest param when checking theAuthorizationheader.Expected behavior
WebSocket connections should be authorized correctly when passing the
tokenrequest parameter on the connection URL since WebSocket browser implementation does not allow to use custom HTTP headers (and it seems is the common way authorization is implemented, at least until WebSocket browser implementation is evolved to support sending HTTP headers).Thanks for all your support!