Skip to content

Conversation

@michaeljmarshall
Copy link
Member

@michaeljmarshall michaeljmarshall commented Feb 17, 2023

Motivation

I broke the Pulsar Proxy with #19455 because that PR requires that when X-Original-Principal is supplied, the auth role must be a proxy role. This is not always the case for proxied admin requests. This PR seeks to fix that incorrect assumption by changing the way verification is done for the roles. Specifically, when the two roles are the same and they are not a proxy role, we will consider it a valid combination.

Note that there is no inefficiency in this solution because When the authenticatedPrincipal is not a proxy role, that is the only role that is authenticated. Note also that we do not let the binary protocol authenticate this way, and that is consistent with the way the pulsar proxy forwards authentication data.

Currently, we do the following when authentication is enabled in the proxy:

  1. Authenticate the client's http request and put the resulting role in the X-Original-Principal header for the call to the broker.

    String user = (String) clientRequest.getAttribute(AuthenticationFilter.AuthenticatedRoleAttributeName);
    if (user != null) {
    proxyRequest.header(ORIGINAL_PRINCIPAL_HEADER, user);
    }

  2. Copy the Authorization header into the broker's http request:

    String authorization = oldRequest.getHeaders().get(HttpHeader.AUTHORIZATION);
    Request newRequest = super.copyRequest(oldRequest, newURI);
    if (authorization != null) {
    newRequest.header(HttpHeader.AUTHORIZATION, authorization);
    }

  3. Configure the proxy's http client to use client TLS authentication (when configured):

    AuthenticationDataProvider authData = auth.getAuthData();
    if (authData.hasDataForTls()) {
    sslCtx = SecurityUtility.createSslContext(
    config.isTlsAllowInsecureConnection(),
    trustCertificates,
    authData.getTlsCertificates(),
    authData.getTlsPrivateKey(),
    config.getBrokerClientSslProvider()
    );

The problem with #19455 is that it assumes the proxy supplies its own authentication data. However, that only happens when using TLS authentication. Otherwise, the proxy forwards the client's authentication data in the Authorization header. As such, calls will fail because the X-Original-Principal header supplied without using a proxy role.

Modifications

  • Consider the authenticatedPrincipal and the originalPrincipal a valid pair when they are equal and are not a proxyRole for http requests.

Alternative Solutions

I initially proposed that we only add the X-Original-Principal when we are using the proxy's authentication (see the first commit). I decided this solution is not ideal because it doesn't solve the problem, it doesn't make the brokers backwards compatible, and there isn't actually any inefficiency in passing the role as a header.

Verifying this change

When cherry-picking #19455 to branch-2.9, I discovered that PackagesOpsWithAuthTest#testPackagesOps was consistently failing because of the way the proxy supplies authentication data when proxying http requests. That test was removed by #12771, which explains why I didn't catch the error sooner. This PR includes a test that fails without this change.

Note that the primary issue must be that we didn't have any tests doing authentication forwarding through the proxy. Now we will have both relevant tests where the proxy is and is not authenticating.

Does this pull request potentially affect one of the following parts:

This is not a breaking change.

Documentation

  • doc-required

Matching PR in forked repository

PR in forked repository: michaeljmarshall#31

@michaeljmarshall michaeljmarshall added area/proxy area/admin doc-required Your PR changes impact docs and you will update later. labels Feb 17, 2023
@michaeljmarshall michaeljmarshall added this to the 3.0.0 milestone Feb 17, 2023
@michaeljmarshall michaeljmarshall self-assigned this Feb 17, 2023
@michaeljmarshall michaeljmarshall changed the title [fix][proxy] Only add X-Original-Principal when necessary [fix][broker] Allow proxy to pass same role as authRole and originalRole Feb 18, 2023
@michaeljmarshall michaeljmarshall changed the title [fix][broker] Allow proxy to pass same role as authRole and originalRole [fix][broker] Allow proxy to pass same role for authRole and originalRole Feb 18, 2023
Copy link
Contributor

@nicoloboschi nicoloboschi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@michaeljmarshall
Copy link
Member Author

/pulsarbot rerun-failure-checks

Copy link
Member

@mattisonchao mattisonchao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@michaeljmarshall
Copy link
Member Author

The flaky proxy test is fixed by #19594

@michaeljmarshall michaeljmarshall merged commit d4be954 into apache:master Feb 22, 2023
michaeljmarshall added a commit that referenced this pull request Feb 22, 2023
…Role (#19557)

I broke the Pulsar Proxy with #19455 because that PR requires that when `X-Original-Principal` is supplied, the auth role must be a proxy role. This is not always the case for proxied admin requests. This PR seeks to fix that incorrect assumption by changing the way verification is done for the roles. Specifically, when the two roles are the same and they are not a proxy role, we will consider it a valid combination.

Note that there is no inefficiency in this solution because When the `authenticatedPrincipal` is not a proxy role, that is the only role that is authenticated. Note also that we do not let the binary protocol authenticate this way, and that is consistent with the way the pulsar proxy forwards authentication data.

Currently, we do the following when authentication is enabled in the proxy:

1. Authenticate the client's http request and put the resulting role in the `X-Original-Principal` header for the call to the broker.
https://github.com/apache/pulsar/blob/38555851359f9cfc172650c387a58c5a03809e97/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/AdminProxyHandler.java#L370-L373

2. Copy the `Authorization` header into the broker's http request:
https://github.com/apache/pulsar/blob/38555851359f9cfc172650c387a58c5a03809e97/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/AdminProxyHandler.java#L232-L236

3. Configure the proxy's http client to use client TLS authentication (when configured):
https://github.com/apache/pulsar/blob/38555851359f9cfc172650c387a58c5a03809e97/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/AdminProxyHandler.java#L269-L277

The problem with #19455 is that it assumes the proxy supplies its own authentication data. However, that only happens when using TLS authentication. Otherwise, the proxy forwards the client's authentication data in the `Authorization` header. As such, calls will fail because the `X-Original-Principal` header supplied without using a proxy role.

* Consider the `authenticatedPrincipal` and the `originalPrincipal` a valid pair when they are equal and are not a `proxyRole` for http requests.

I initially proposed that we only add the `X-Original-Principal` when we are using the proxy's authentication (see the first commit). I decided this solution is not ideal because it doesn't solve the problem, it doesn't make the brokers backwards compatible, and there isn't actually any inefficiency in passing the role as a header.

When cherry-picking #19455 to branch-2.9, I discovered that `PackagesOpsWithAuthTest#testPackagesOps` was consistently failing because of the way the proxy supplies authentication data when proxying http requests. That test was removed by #12771, which explains why I didn't catch the error sooner. This PR includes a test that fails  without this change.

Note that the primary issue must be that we didn't have any tests doing authentication forwarding through the proxy. Now we will have both relevant tests where the proxy is and is not authenticating.

This is not a breaking change.

- [x] `doc-required`

PR in forked repository: michaeljmarshall#31

(cherry picked from commit d4be954)
@michaeljmarshall michaeljmarshall deleted the fix-proxy-http-auth-headers branch February 22, 2023 21:31
michaeljmarshall added a commit that referenced this pull request Feb 22, 2023
…Role (#19557)

I broke the Pulsar Proxy with #19455 because that PR requires that when `X-Original-Principal` is supplied, the auth role must be a proxy role. This is not always the case for proxied admin requests. This PR seeks to fix that incorrect assumption by changing the way verification is done for the roles. Specifically, when the two roles are the same and they are not a proxy role, we will consider it a valid combination.

Note that there is no inefficiency in this solution because When the `authenticatedPrincipal` is not a proxy role, that is the only role that is authenticated. Note also that we do not let the binary protocol authenticate this way, and that is consistent with the way the pulsar proxy forwards authentication data.

Currently, we do the following when authentication is enabled in the proxy:

1. Authenticate the client's http request and put the resulting role in the `X-Original-Principal` header for the call to the broker.
https://github.com/apache/pulsar/blob/38555851359f9cfc172650c387a58c5a03809e97/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/AdminProxyHandler.java#L370-L373

2. Copy the `Authorization` header into the broker's http request:
https://github.com/apache/pulsar/blob/38555851359f9cfc172650c387a58c5a03809e97/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/AdminProxyHandler.java#L232-L236

3. Configure the proxy's http client to use client TLS authentication (when configured):
https://github.com/apache/pulsar/blob/38555851359f9cfc172650c387a58c5a03809e97/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/AdminProxyHandler.java#L269-L277

The problem with #19455 is that it assumes the proxy supplies its own authentication data. However, that only happens when using TLS authentication. Otherwise, the proxy forwards the client's authentication data in the `Authorization` header. As such, calls will fail because the `X-Original-Principal` header supplied without using a proxy role.

* Consider the `authenticatedPrincipal` and the `originalPrincipal` a valid pair when they are equal and are not a `proxyRole` for http requests.

I initially proposed that we only add the `X-Original-Principal` when we are using the proxy's authentication (see the first commit). I decided this solution is not ideal because it doesn't solve the problem, it doesn't make the brokers backwards compatible, and there isn't actually any inefficiency in passing the role as a header.

When cherry-picking #19455 to branch-2.9, I discovered that `PackagesOpsWithAuthTest#testPackagesOps` was consistently failing because of the way the proxy supplies authentication data when proxying http requests. That test was removed by #12771, which explains why I didn't catch the error sooner. This PR includes a test that fails  without this change.

Note that the primary issue must be that we didn't have any tests doing authentication forwarding through the proxy. Now we will have both relevant tests where the proxy is and is not authenticating.

This is not a breaking change.

- [x] `doc-required`

PR in forked repository: michaeljmarshall#31

(cherry picked from commit d4be954)
(cherry picked from commit 5f5551d)
michaeljmarshall added a commit to michaeljmarshall/pulsar that referenced this pull request Feb 22, 2023
…Role (apache#19557)

I broke the Pulsar Proxy with apache#19455 because that PR requires that when `X-Original-Principal` is supplied, the auth role must be a proxy role. This is not always the case for proxied admin requests. This PR seeks to fix that incorrect assumption by changing the way verification is done for the roles. Specifically, when the two roles are the same and they are not a proxy role, we will consider it a valid combination.

Note that there is no inefficiency in this solution because When the `authenticatedPrincipal` is not a proxy role, that is the only role that is authenticated. Note also that we do not let the binary protocol authenticate this way, and that is consistent with the way the pulsar proxy forwards authentication data.

Currently, we do the following when authentication is enabled in the proxy:

1. Authenticate the client's http request and put the resulting role in the `X-Original-Principal` header for the call to the broker.
https://github.com/apache/pulsar/blob/38555851359f9cfc172650c387a58c5a03809e97/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/AdminProxyHandler.java#L370-L373

2. Copy the `Authorization` header into the broker's http request:
https://github.com/apache/pulsar/blob/38555851359f9cfc172650c387a58c5a03809e97/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/AdminProxyHandler.java#L232-L236

3. Configure the proxy's http client to use client TLS authentication (when configured):
https://github.com/apache/pulsar/blob/38555851359f9cfc172650c387a58c5a03809e97/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/AdminProxyHandler.java#L269-L277

The problem with apache#19455 is that it assumes the proxy supplies its own authentication data. However, that only happens when using TLS authentication. Otherwise, the proxy forwards the client's authentication data in the `Authorization` header. As such, calls will fail because the `X-Original-Principal` header supplied without using a proxy role.

* Consider the `authenticatedPrincipal` and the `originalPrincipal` a valid pair when they are equal and are not a `proxyRole` for http requests.

I initially proposed that we only add the `X-Original-Principal` when we are using the proxy's authentication (see the first commit). I decided this solution is not ideal because it doesn't solve the problem, it doesn't make the brokers backwards compatible, and there isn't actually any inefficiency in passing the role as a header.

When cherry-picking apache#19455 to branch-2.9, I discovered that `PackagesOpsWithAuthTest#testPackagesOps` was consistently failing because of the way the proxy supplies authentication data when proxying http requests. That test was removed by apache#12771, which explains why I didn't catch the error sooner. This PR includes a test that fails  without this change.

Note that the primary issue must be that we didn't have any tests doing authentication forwarding through the proxy. Now we will have both relevant tests where the proxy is and is not authenticating.

This is not a breaking change.

- [x] `doc-required`

PR in forked repository: #31

(cherry picked from commit d4be954)
(cherry picked from commit 5f5551d)
(cherry picked from commit 4da2487)
michaeljmarshall added a commit to datastax/pulsar that referenced this pull request Feb 23, 2023
…Role (apache#19557)

I broke the Pulsar Proxy with apache#19455 because that PR requires that when `X-Original-Principal` is supplied, the auth role must be a proxy role. This is not always the case for proxied admin requests. This PR seeks to fix that incorrect assumption by changing the way verification is done for the roles. Specifically, when the two roles are the same and they are not a proxy role, we will consider it a valid combination.

Note that there is no inefficiency in this solution because When the `authenticatedPrincipal` is not a proxy role, that is the only role that is authenticated. Note also that we do not let the binary protocol authenticate this way, and that is consistent with the way the pulsar proxy forwards authentication data.

Currently, we do the following when authentication is enabled in the proxy:

1. Authenticate the client's http request and put the resulting role in the `X-Original-Principal` header for the call to the broker.
https://github.com/apache/pulsar/blob/38555851359f9cfc172650c387a58c5a03809e97/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/AdminProxyHandler.java#L370-L373

2. Copy the `Authorization` header into the broker's http request:
https://github.com/apache/pulsar/blob/38555851359f9cfc172650c387a58c5a03809e97/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/AdminProxyHandler.java#L232-L236

3. Configure the proxy's http client to use client TLS authentication (when configured):
https://github.com/apache/pulsar/blob/38555851359f9cfc172650c387a58c5a03809e97/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/AdminProxyHandler.java#L269-L277

The problem with apache#19455 is that it assumes the proxy supplies its own authentication data. However, that only happens when using TLS authentication. Otherwise, the proxy forwards the client's authentication data in the `Authorization` header. As such, calls will fail because the `X-Original-Principal` header supplied without using a proxy role.

* Consider the `authenticatedPrincipal` and the `originalPrincipal` a valid pair when they are equal and are not a `proxyRole` for http requests.

I initially proposed that we only add the `X-Original-Principal` when we are using the proxy's authentication (see the first commit). I decided this solution is not ideal because it doesn't solve the problem, it doesn't make the brokers backwards compatible, and there isn't actually any inefficiency in passing the role as a header.

When cherry-picking apache#19455 to branch-2.9, I discovered that `PackagesOpsWithAuthTest#testPackagesOps` was consistently failing because of the way the proxy supplies authentication data when proxying http requests. That test was removed by apache#12771, which explains why I didn't catch the error sooner. This PR includes a test that fails  without this change.

Note that the primary issue must be that we didn't have any tests doing authentication forwarding through the proxy. Now we will have both relevant tests where the proxy is and is not authenticating.

This is not a breaking change.

- [x] `doc-required`

PR in forked repository: michaeljmarshall#31

(cherry picked from commit d4be954)
(cherry picked from commit 5f5551d)
(cherry picked from commit 4da2487)
michaeljmarshall added a commit to michaeljmarshall/pulsar that referenced this pull request Feb 23, 2023
…Role (apache#19557)

I broke the Pulsar Proxy with apache#19455 because that PR requires that when `X-Original-Principal` is supplied, the auth role must be a proxy role. This is not always the case for proxied admin requests. This PR seeks to fix that incorrect assumption by changing the way verification is done for the roles. Specifically, when the two roles are the same and they are not a proxy role, we will consider it a valid combination.

Note that there is no inefficiency in this solution because When the `authenticatedPrincipal` is not a proxy role, that is the only role that is authenticated. Note also that we do not let the binary protocol authenticate this way, and that is consistent with the way the pulsar proxy forwards authentication data.

Currently, we do the following when authentication is enabled in the proxy:

1. Authenticate the client's http request and put the resulting role in the `X-Original-Principal` header for the call to the broker.
https://github.com/apache/pulsar/blob/38555851359f9cfc172650c387a58c5a03809e97/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/AdminProxyHandler.java#L370-L373

2. Copy the `Authorization` header into the broker's http request:
https://github.com/apache/pulsar/blob/38555851359f9cfc172650c387a58c5a03809e97/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/AdminProxyHandler.java#L232-L236

3. Configure the proxy's http client to use client TLS authentication (when configured):
https://github.com/apache/pulsar/blob/38555851359f9cfc172650c387a58c5a03809e97/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/AdminProxyHandler.java#L269-L277

The problem with apache#19455 is that it assumes the proxy supplies its own authentication data. However, that only happens when using TLS authentication. Otherwise, the proxy forwards the client's authentication data in the `Authorization` header. As such, calls will fail because the `X-Original-Principal` header supplied without using a proxy role.

* Consider the `authenticatedPrincipal` and the `originalPrincipal` a valid pair when they are equal and are not a `proxyRole` for http requests.

I initially proposed that we only add the `X-Original-Principal` when we are using the proxy's authentication (see the first commit). I decided this solution is not ideal because it doesn't solve the problem, it doesn't make the brokers backwards compatible, and there isn't actually any inefficiency in passing the role as a header.

When cherry-picking apache#19455 to branch-2.9, I discovered that `PackagesOpsWithAuthTest#testPackagesOps` was consistently failing because of the way the proxy supplies authentication data when proxying http requests. That test was removed by apache#12771, which explains why I didn't catch the error sooner. This PR includes a test that fails  without this change.

Note that the primary issue must be that we didn't have any tests doing authentication forwarding through the proxy. Now we will have both relevant tests where the proxy is and is not authenticating.

This is not a breaking change.

- [x] `doc-required`

PR in forked repository: #31

(cherry picked from commit d4be954)
(cherry picked from commit 5f5551d)
(cherry picked from commit 4da2487)
(cherry picked from commit dc09681)
michaeljmarshall added a commit to michaeljmarshall/pulsar that referenced this pull request Feb 23, 2023
…Role (apache#19557)

I broke the Pulsar Proxy with apache#19455 because that PR requires that when `X-Original-Principal` is supplied, the auth role must be a proxy role. This is not always the case for proxied admin requests. This PR seeks to fix that incorrect assumption by changing the way verification is done for the roles. Specifically, when the two roles are the same and they are not a proxy role, we will consider it a valid combination.

Note that there is no inefficiency in this solution because When the `authenticatedPrincipal` is not a proxy role, that is the only role that is authenticated. Note also that we do not let the binary protocol authenticate this way, and that is consistent with the way the pulsar proxy forwards authentication data.

Currently, we do the following when authentication is enabled in the proxy:

1. Authenticate the client's http request and put the resulting role in the `X-Original-Principal` header for the call to the broker.
https://github.com/apache/pulsar/blob/38555851359f9cfc172650c387a58c5a03809e97/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/AdminProxyHandler.java#L370-L373

2. Copy the `Authorization` header into the broker's http request:
https://github.com/apache/pulsar/blob/38555851359f9cfc172650c387a58c5a03809e97/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/AdminProxyHandler.java#L232-L236

3. Configure the proxy's http client to use client TLS authentication (when configured):
https://github.com/apache/pulsar/blob/38555851359f9cfc172650c387a58c5a03809e97/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/AdminProxyHandler.java#L269-L277

The problem with apache#19455 is that it assumes the proxy supplies its own authentication data. However, that only happens when using TLS authentication. Otherwise, the proxy forwards the client's authentication data in the `Authorization` header. As such, calls will fail because the `X-Original-Principal` header supplied without using a proxy role.

* Consider the `authenticatedPrincipal` and the `originalPrincipal` a valid pair when they are equal and are not a `proxyRole` for http requests.

I initially proposed that we only add the `X-Original-Principal` when we are using the proxy's authentication (see the first commit). I decided this solution is not ideal because it doesn't solve the problem, it doesn't make the brokers backwards compatible, and there isn't actually any inefficiency in passing the role as a header.

When cherry-picking apache#19455 to branch-2.9, I discovered that `PackagesOpsWithAuthTest#testPackagesOps` was consistently failing because of the way the proxy supplies authentication data when proxying http requests. That test was removed by apache#12771, which explains why I didn't catch the error sooner. This PR includes a test that fails  without this change.

Note that the primary issue must be that we didn't have any tests doing authentication forwarding through the proxy. Now we will have both relevant tests where the proxy is and is not authenticating.

This is not a breaking change.

- [x] `doc-required`

PR in forked repository: #31

(cherry picked from commit d4be954)
(cherry picked from commit 5f5551d)
(cherry picked from commit 4da2487)
(cherry picked from commit dc09681)
@momo-jun
Copy link
Contributor

Hi @michaeljmarshall , I'm checking in to follow up with the doc updates. Did you have any plans to update the docs?

hangc0276 added a commit to hangc0276/pulsar that referenced this pull request Mar 15, 2023
hangc0276 added a commit to hangc0276/pulsar that referenced this pull request Mar 15, 2023
@michaeljmarshall michaeljmarshall added doc-complete Your PR changes impact docs and the related docs have been already added. and removed doc-required Your PR changes impact docs and you will update later. labels Apr 20, 2023
@michaeljmarshall
Copy link
Member Author

After reviewing this, I realize now that the only place I needed to add docs was in the Javadocs. We don't document the HTTP proxy to broker interactions on our website, so nothing needs to be updated there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/admin area/broker area/proxy cherry-picked/branch-2.8 Archived: 2.8 is end of life cherry-picked/branch-2.9 Archived: 2.9 is end of life cherry-picked/branch-2.10 cherry-picked/branch-2.11 doc-complete Your PR changes impact docs and the related docs have been already added. release/2.8.5 release/2.9.5 release/2.10.4 release/2.11.1 type/bug The PR fixed a bug or issue reported a bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants