Skip to content

Conversation

@nodece
Copy link
Member

@nodece nodece commented Feb 2, 2023

Motivation

When anonymousUserRole is configured, and auth method is none, the broker only stores the authRole, ignores store the original authentication data and role forwarded by the proxy, see

if (authenticationProvider == null) {
authRole = getBrokerService().getAuthenticationService().getAnonymousUserRole()
.orElseThrow(() ->
new AuthenticationException("No anonymous role, and no authentication provider configured"));
completeConnect(clientProtocolVersion, clientVersion, enableSubscriptionPatternEvaluation);
return;
}

We have to store the forwarded authentication data and role, the data from CommandConnect#getOriginalAuthData, and the role from CommandConnect#getOriginalPrincipal.

Modifications

  • Add checkAndStoreOriginalAuthDataForwardedByProxy method to check and store the original authentication
  • When using anonymous role, we also check and store the original authentication

Verifying this change

  • Make sure that the change passes the CI checks.

Added ProxyAnonymousRoleTest test.

Documentation

  • doc
  • doc-required
  • doc-not-needed
  • doc-complete

@github-actions github-actions bot added the doc-not-needed Your PR changes do not impact docs label Feb 2, 2023
@nodece nodece self-assigned this Feb 2, 2023
@nodece nodece added area/authn and removed doc-not-needed Your PR changes do not impact docs labels Feb 2, 2023
@github-actions github-actions bot added the doc-not-needed Your PR changes do not impact docs label Feb 2, 2023
import org.testng.annotations.Test;

@Slf4j
public class ProxyAnonymousRoleTest extends ProducerConsumerBase {
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add a test group.

conf.getProperties().setProperty("tokenSecretKey", "data:;base64," + Base64.getEncoder().encodeToString(SECRET_KEY.getEncoded()));

Set<String> superUserRoles = new HashSet<>();
superUserRoles.add(ANONYMOUS_ROLE);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it required?

Copy link
Member Author

Choose a reason for hiding this comment

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

This means the proxy is a superuser. Without this config, the proxy has no permission to communicate.

Comment on lines 140 to 144
private void createAdminClient() throws Exception {
admin = spy(PulsarAdmin.builder().serviceHttpUrl(brokerUrl.toString())
.authentication(AuthenticationFactory.token(ADMIN_TOKEN)).build());
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The admin client will not work with proxy for this case?

Copy link
Member Author

Choose a reason for hiding this comment

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

Any address will do.

Copy link
Member

@michaeljmarshall michaeljmarshall left a comment

Choose a reason for hiding this comment

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

I don't think we should let the proxy authenticate using an anonymous role. I started work in #19270 to propose that we make stricter requirements so that when a connection is started by a proxy, the authRole must be a proxy role (we know because the command has the originalPrincipal and maybe the originalAuthData). That work is only a draft because of some edge cases that will be resolved by #19409.

I propose that we consider a proxy connecting as the anonymous role as a misconfiguration.

@codelipenghui
Copy link
Contributor

codelipenghui commented Feb 6, 2023

I don't think we should let the proxy authenticate using an anonymous role. I started work in #19270 to propose that we make stricter requirements so that when a connection is started by a proxy, the authRole must be a proxy role (we know because the command has the originalPrincipal and maybe the originalAuthData). That work is only a draft because of some edge cases that will be resolved by #19409.

I propose that we consider a proxy connecting as the anonymous role as a misconfiguration.

Sound good to me.

@nodece
Copy link
Member Author

nodece commented Feb 6, 2023

I don't think we should let the proxy authenticate using an anonymous role.

@michaeljmarshall I also agree with this. But I think there is a bug here, when the proxy is an anonymous user, we don't care about storing the original role and original authentication data, so this PR is used to fix this.

#19270 is validating the auth role and proxy role to avoid the auth role as the proxy role, the two PR have different goal.

@nodece nodece changed the title [fix][authentication] Check the original auth when using anonymous role [fix][authentication] Store the original auth when using anonymous role Feb 7, 2023
@nodece nodece force-pushed the anonymous-role-and-original-auth branch from 45eb7e9 to 057703a Compare February 7, 2023 07:38
Copy link
Member

@michaeljmarshall michaeljmarshall left a comment

Choose a reason for hiding this comment

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

I'd like to discuss taking a different direction. I think we should fail the connection if the proxy connects without a valid authMethod. My proposal is in the comments.

@@ -971,6 +973,7 @@ protected void handleConnect(CommandConnect connect) {
authRole = getBrokerService().getAuthenticationService().getAnonymousUserRole()
Copy link
Member

Choose a reason for hiding this comment

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

Why not just add the following before the call to get the anonymous role? I think this would correctly handle the issue of a proxy authenticating as the anonymous role.

if (connect.hasOriginalPrincipal() || connect.hasOriginalAuthData()) {
    throw new AuthenticationException("Proxy cannot authenticate as the anonymous role.");
}

Copy link
Member Author

Choose a reason for hiding this comment

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

This means that the proxy cannot use the anonymous role to connect to the broker, I don't think this is correct.

Usually, the proxy always enable the authentication feature, but we also should consider a case that the proxy doesn't enable the authentication feature.

Copy link
Member

Choose a reason for hiding this comment

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

This means that the proxy cannot use the anonymous role to connect to the broker

Yes, this is the design I am proposing we move towards. That is why I said this earlier in this PR:

I propose that we consider a proxy connecting as the anonymous role as a misconfiguration.

Usually, the proxy always enable the authentication feature, but we also should consider a case that the proxy doesn't enable the authentication feature.

In this case, the broker wouldn't enable authentication either. In the admin API, we only look for the original principal when the authRole is in the proxyRoles set. Given that the proxy has to have at least as much permission as the originalPrincipal, I do not see what the point of authentication would be if the anonymous role is also a proxy role.

Copy link
Member Author

Choose a reason for hiding this comment

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

Your idea is very true, we also recommend enabling authentication anywhere.

We have a case in which we don't want to check the proxy authentication in the broker, only check the original authentication. Would you have any idea?

Right now, we set up anonymousUserRole, but we cannot get the original authentication, because of the broker jumped to completeConnect method, there is misses storing the original authentication.

Copy link
Member

Choose a reason for hiding this comment

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

We have a case in which we don't want to check the proxy authentication in the broker, only check the original authentication. Would you have any idea?

That context helps a lot, thanks! Is it possible to add a configuration to the proxy so that it forwards the original authentication data as the authData part of the Connect command? The broker wouldn't necessarily know the connection is from the proxy, but I think this should be fine.

I think this discussion probably relates to #19332. I have been thinking that our authentication state integration between proxy and broker is very complicated and doesn't appear to be working in all cases (see also #19291).

It seems like we could always drop the proxy auth data in cases where the authentication data can be forwarded.

Copy link
Member Author

Choose a reason for hiding this comment

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

Sounds good, we need to improve the proxy codebase to find a workaround, this is going to take some time.

authRole = getBrokerService().getAuthenticationService().getAnonymousUserRole()
.orElseThrow(() ->
new AuthenticationException("No anonymous role, and no authentication provider configured"));
checkAndStoreOriginalAuthDataForwardedByProxy(connect);
Copy link
Member

Choose a reason for hiding this comment

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

My concern with this solution is that it lets a proxy connect as the anonymous role, and I don't think that will work correctly. Note that we do not use the anonymousRole for the originalPrincipal, so it seems to me that the anonymousRole is only meant for direct broker access.

Copy link
Member Author

@nodece nodece Feb 8, 2023

Choose a reason for hiding this comment

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

Right.

}

@Test
public void testAuthorizationWithProxyAsAnonymousRoleWithOriginalRole() throws Exception {
Copy link
Member

Choose a reason for hiding this comment

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

If we do go with my proposed restriction, it might be helpful to use the ServerCnxTest class to validate how the Connect command behaves. If you look through the commit history on that file, you'll see that I've added several authentication related tests that allow for low level manipulation of the protocol without much need for mocking.

@github-actions
Copy link

The pr had no activity for 30 days, mark with Stale label.

@github-actions github-actions bot added the Stale label Mar 11, 2023
@nodece nodece closed this Jul 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/authn doc-not-needed Your PR changes do not impact docs Stale

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants