PIP-292: Enforce token expiration time in the Websockets plugin

Background knowledge

This pip is about the websockets plugin of apache pulsar.

Motivation

When a client connects via Websockets and uses a token as authentication mechanism, the validity of the token is only checked when the connection is established. When the expiry time of the token has passed, the client remains connected.

This is insecure, and makes the websocket implementation unsuitable for a use case where the enforcement of the token expiry time is important.

Goals

In Scope

This feature is already supported by the ‘regular’ pulsar broker. (Only not by the websocket plugin)

The goal is to make token authentication via websockets more secure. And to reduce the difference between a pulsar connection and a websocket connection.

Out of Scope

It is out of scope to integrate the websocket plugin with the ‘regular’ pulsar broker. (Even though I believe that is what should happen)

High Level Design

The implementation should be identical to the implementation that already exists with the ‘regular’ pulsar broker. This is:

On successful connect: periodically start a task to check the validity of the used authentication. If a token is expired, a request is sent to the client to provide a new token. If the client does not provide a new token the connection will be closed.

Detailed Design

Design & Implementation Details

The design is fully based on the implementation in de Pulsar broker. To summarize:

Extend the onWebsocketConnect function to periodically check the validitity of the supplied AuthenticationData, with the logic as already implemented in the ServerCnx class

Furthermore, the authenticationData used to perform the initial authentication (which includes the token) needs to remain available for the function above to check periodically. Therefore, some of the authentication logic needs to be placed in the AbstractWebSocketHandler class. Or an extension needs to be made on the AuthenticationService to expose this.

Fully working code has already been created (as a starting point).

Public-facing Changes

Clients connected with websockets and authenticated with a token can expect to receive the following message: {"type":"AUTH_CHALLENGE","authChallenge":{"challenge":{"authMethodName":"token","authData":"token"},"protocolVersion":0}}

Existing websocket clients might interpret this message as a regular message, and not as a Command message. This could break existing implementations which use expired tokens.

Websocket clients are intended to reply with: {"type": "AUTH_RESPONSE", "authResponse": {"clientVersion": "v0", "protocolVersion": 0, "response": {"authMethodName": "token", "authData": "[TOKEN]"}}}

Existing websocket clients will simply be disconnected in case they do not reply. A reconnect with a new token will suffice to reestablish a connection.

Public API

NA

Binary protocol

NA

Configuration

The already existing variable ‘AuthenticationRefreshCheckSeconds’ is used.

CLI

NA

Metrics

NA

Monitoring

NA

Security Considerations

The client has the ability to update the authentication data after a websocket connection has been established. It is technically possible to use a different authentication mechanism than the initial mechanism. However, it is expected that this does not pose any security risks.

Backward & Forward Compatibility

Revert

No changes to the websocket client need to be made to use a previous version of the websocket broker.

Upgrade

Websocket clients need to handle incoming messages containing ‘“type”:“AUTH_CHALLENGE”’ as a command. And respond with a new token in a ‘“type”:“AUTH_RESPONSE”’ command.

Alternatives

NA

General Notes

Links