-
Notifications
You must be signed in to change notification settings - Fork 69
[Bug] OAuth2 authentication failed #184
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
It seems to be caused by the packaging style. It's very similar to this issue: apache/pulsar-client-node#281 I did some experiements with the Python client. Given the following similar Python script. #!/bin/env python3
import pulsar
pulsar_url = "pulsar+ssl://test-auth.sndev.snio.cloud:6651"
pulsar_oauth_params = '''{
"issuer_url": "https://auth.streamnative.cloud/",
"private_key": "YOUR-KEY-FILE-PATH",
"audience": "urn:sn:pulsar:sndev:test-auth"
}'''
pulsar_topic = "persistent://public/default/my-topic"
if __name__ == "__main__":
client = pulsar.Client(
pulsar_url,
authentication=pulsar.AuthenticationOauth2(pulsar_oauth_params),
)
producer = client.create_producer(topic=pulsar_topic)
producer.send(f"hello".encode('utf-8'))
producer.close()
client.close() I tried two ways to install the Python wheel (on Ubuntu 20.04). 1. [OK] Build from source.git clone [email protected]:apache/pulsar-client-python.git -b v3.1.0-candidate-1
git submodule update --init
cmake -B build
cmake --build build
cp build/lib_pulsar.so .
python3 ./setup.py bdist_wheel
sudo pip3 install dist/pulsar_client-3.1.0a1-cp38-cp38-linux_x86_64.whl --force-reinstall The output:
We can see the handshake succeeded and the client connected to the proxy 2. [FAILED] Install the existing wheelcurl -O -L https://dist.apache.org/repos/dist/dev/pulsar/pulsar-client-python-3.1.0-candidate-1/linux-glibc-x86_64/pulsar_client-3.1.0a1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
sudo pip3 install dist/pulsar_client-3.1.0a1-cp38-cp38-linux_x86_64.whl --force-reinstall The output:
ConclusionThe cause might be apache/pulsar#16064, which is related to a CVE. We need to document the workround or change the way to build the client library. |
Updated: Building the C++ client from source works. I think the main reason is the
I think the key point is the libcurl and OpenSSL dependencies. I'm still investigating and testing it. |
The root cause is that the OAuth2 client credential flow does not configure any CA cert for verification. TL; DR, just see the following workaround section. WorkaroundJust take Ubuntu 20.04 for example, whose default CA file is C++ client: pass the CA cert path to ClientConfiguration config;
config.setTlsTrustCertsFilePath("/etc/ssl/certs/ca-certificates.crt")
Client client(serviceUrl, config); Python and Node.js clients: though they also have the related configs to set the CA cert path, it does not work actually. (See the following section for detailed explanation). You have to copy the CA cert file to the specific path, which is determined by your system. # All Python wheels for Linux use /etc/pki/tls/certs/ca-bundle.crt as the path of the CA cert
sudo mkdir -p /etc/pki/tls/certs
sudo cp /etc/ssl/certs/ca-certificates.crt /etc/pki/tls/certs/ca-bundle.crt AnalysisFrom https://curl.se/docs/sslcerts.html we can see
Before Pulsar C++ client 3.0.0, the OAuth2 client credential flow didn't verify the peer, which leads to the CVE-2022-33684. Then apache/pulsar#16064 fixes it by enabling the option to verify the peer. However, the libcurl dependency is built from source and linked statically by:
When it's built from source, the default path of the CA cert is detected automatically and determined by the OS. e.g. the Python wheels for Linux are built on The only workaround for Python and Node.js clients on Linux is copying your CA cert file into that path. The C++ client can work by configuring How to reproduceCreate an account on StreamNative cloud to get the client id and client secret. You can switch to your own vendor if you have an Pulsar service with OAuth2 authentication enabled. TlsOauth2Example.cc #include <pulsar/Client.h>
using namespace pulsar;
int main(int argc, char *argv[]) {
std::string params = R"({
"issuer_url": "https://auth.streamnative.cloud/", // St
"client_id": "<your-client-id>",
"client_secret": "<your-client-secret>",
"audience": "<your-audience>"})";
ClientConfiguration config;
config.setAuth(AuthOauth2::create(params));
// NOTE: here we use a customized CA cert path
config.setTlsTrustCertsFilePath("/app/ca-certificates.crt");
Client client("pulsar+ssl://<your-host>:<your-port>", config);
Producer producer;
auto result = client.createProducer("persistent://public/default/my-topic", producer);
if (result != ResultOk) {
std::cerr << "Failed to create producer: " << result << std::endl;
return 1;
}
client.close();
return 0;
} Start a docker container: docker run -v $PWD:/app -it ubuntu:20.04 /bin/bash Run the following commands inside the container: cd /app
apt update -y
apt install -y curl g++
curl -O -L https://archive.apache.org/dist/pulsar/pulsar-client-cpp-3.1.1/deb-x86_64/apache-pulsar-client-dev.deb
curl -O -L https://archive.apache.org/dist/pulsar/pulsar-client-cpp-3.1.1/deb-x86_64/apache-pulsar-client.deb
apt install ./apache-pulsar-client*.deb
# NOTE: move the CA file from the default path to /app
mv /etc/ssl/certs/ca-certificates.crt .
g++ TlsOauth2Example.cc -std=c++11 -lpulsar
./a.out You will see the following output:
If you removed the
That's because the for TLS connection, the C++ client reads the CA cert file from the config: pulsar-client-cpp/lib/ClientConnection.cc Lines 205 to 209 in 0631e36
SolutionWe should use the pulsar-client-cpp/lib/HTTPLookupService.cc Lines 260 to 262 in 0631e36
I will push a PR soon. |
…2 flow Fixes apache#184 ### Modifications Add a `AuthenticationDataProvider` implementation `InitialAuthData`, which holds the CA cert path. Then, in `AuthOauth2::getAuthData`, retrieve the path and pass it to the `ClientCredentialFlow` for HTTP requests performed by libcurl. This solution is API and ABI compatible. ### Verifications It's hard to add the test in CI because we need an OAuth2 server configured with the CA configured. Follow the **How to reproduce** section in apache#184 (comment) to reproduce this issue. Apply this patch and build the `libpulsar.so` with `LINK_STATIC=ON`, then copy the `libpulsar.so` into the docker container (under `/app/lib`). Run `./a.out` directly, you will still see the `AuthenticationError`. However, if you added the path of `libpulsar.so` to the `LD_LIBRARY_PATH`: ```bash export LD_LIBRARY_PATH=/app/lib ./a.out ``` No error will happen. You can also replace the `/lib/libpulsar.so` with the `libpulsar.so` built from source.
…2 flow Fixes apache#184 ### Modifications Add a `AuthenticationDataProvider` implementation `InitialAuthData`, which holds the CA cert path. Then, in `AuthOauth2::getAuthData`, retrieve the path and pass it to the `ClientCredentialFlow` for HTTP requests performed by libcurl. This solution is API and ABI compatible. ### Verifications It's hard to add the test in CI because we need an OAuth2 server configured with the CA configured. Follow the **How to reproduce** section in apache#184 (comment) to reproduce this issue. Apply this patch and build the `libpulsar.so` with `LINK_STATIC=ON`, then copy the `libpulsar.so` into the docker container (under `/app/lib`). Run `./a.out` directly, you will still see the `AuthenticationError`. However, if you added the path of `libpulsar.so` to the `LD_LIBRARY_PATH`: ```bash export LD_LIBRARY_PATH=/app/lib ./a.out ``` No error will happen. You can also replace the `/lib/libpulsar.so` with the `libpulsar.so` built from source. (cherry picked from commit d7eb539)
Nice catch! Node.js 1.8.0 oauth2 auth failed is the same as this.
I checked cross-compile logs on the macOS system, and the I'll use your PR to verify if this can be fixed. |
It can solve this problem by configuring |
Search before asking
Version
Minimal reproduce step
Set up an account on StreamNative cloud, create the topic
my-topic
in advance and grant the produce permission. The following example usestest-auth
instance under thesndev
organization, replaceYOUR-KEY-FILE-PATH
to the path of the credential file.What did you expect to see?
It should succeed
What did you see instead?
Ubuntu:
Windows:
Anything else?
No response
Are you willing to submit a PR?
The text was updated successfully, but these errors were encountered: