|
80 | 80 | import org.apache.pulsar.broker.ServiceConfiguration;
|
81 | 81 | import org.apache.pulsar.broker.TransactionMetadataStoreService;
|
82 | 82 | import org.apache.pulsar.broker.auth.MockAuthenticationProvider;
|
| 83 | +import org.apache.pulsar.broker.auth.MockMultiStageAuthenticationProvider; |
83 | 84 | import org.apache.pulsar.broker.authentication.AuthenticationDataSource;
|
84 | 85 | import org.apache.pulsar.broker.authentication.AuthenticationProvider;
|
85 | 86 | import org.apache.pulsar.broker.authentication.AuthenticationService;
|
|
103 | 104 | import org.apache.pulsar.common.api.proto.CommandAck.AckType;
|
104 | 105 | import org.apache.pulsar.common.api.proto.CommandAddPartitionToTxnResponse;
|
105 | 106 | import org.apache.pulsar.common.api.proto.CommandAddSubscriptionToTxnResponse;
|
| 107 | +import org.apache.pulsar.common.api.proto.CommandAuthChallenge; |
106 | 108 | import org.apache.pulsar.common.api.proto.CommandAuthResponse;
|
107 | 109 | import org.apache.pulsar.common.api.proto.CommandCloseProducer;
|
108 | 110 | import org.apache.pulsar.common.api.proto.CommandConnected;
|
@@ -490,11 +492,84 @@ public void testConnectCommandWithAuthenticationNegative() throws Exception {
|
490 | 492 | ByteBuf clientCommand = Commands.newConnect("none", "", null);
|
491 | 493 | channel.writeInbound(clientCommand);
|
492 | 494 |
|
493 |
| - assertEquals(serverCnx.getState(), State.Start); |
| 495 | + assertEquals(serverCnx.getState(), State.Failed); |
494 | 496 | assertTrue(getResponse() instanceof CommandError);
|
495 | 497 | channel.finish();
|
496 | 498 | }
|
497 | 499 |
|
| 500 | + @Test(timeOut = 30000) |
| 501 | + public void testConnectCommandWithFailingOriginalAuthData() throws Exception { |
| 502 | + AuthenticationService authenticationService = mock(AuthenticationService.class); |
| 503 | + AuthenticationProvider authenticationProvider = new MockAuthenticationProvider(); |
| 504 | + String authMethodName = authenticationProvider.getAuthMethodName(); |
| 505 | + |
| 506 | + when(brokerService.getAuthenticationService()).thenReturn(authenticationService); |
| 507 | + when(authenticationService.getAuthenticationProvider(authMethodName)).thenReturn(authenticationProvider); |
| 508 | + svcConfig.setAuthenticationEnabled(true); |
| 509 | + svcConfig.setAuthenticateOriginalAuthData(true); |
| 510 | + svcConfig.setProxyRoles(Collections.singleton("proxy")); |
| 511 | + |
| 512 | + resetChannel(); |
| 513 | + assertTrue(channel.isActive()); |
| 514 | + assertEquals(serverCnx.getState(), State.Start); |
| 515 | + |
| 516 | + ByteBuf clientCommand = Commands.newConnect(authMethodName, "pass.proxy", 1,null, |
| 517 | + null, "client", "fail", authMethodName); |
| 518 | + channel.writeInbound(clientCommand); |
| 519 | + |
| 520 | + // We currently expect two responses because the originalAuthData is verified after sending |
| 521 | + // a successful response to the proxy. Because this is a synchronous operation, there is currently |
| 522 | + // no risk. It would be better to fix this. See https://github.com/apache/pulsar/issues/19311. |
| 523 | + Object response1 = getResponse(); |
| 524 | + assertTrue(response1 instanceof CommandConnected); |
| 525 | + Object response2 = getResponse(); |
| 526 | + assertTrue(response2 instanceof CommandError); |
| 527 | + assertEquals(((CommandError) response2).getMessage(), "Unable to authenticate"); |
| 528 | + assertEquals(serverCnx.getState(), State.Failed); |
| 529 | + assertFalse(serverCnx.isActive()); |
| 530 | + channel.finish(); |
| 531 | + } |
| 532 | + |
| 533 | + @Test(timeOut = 30000) |
| 534 | + public void testAuthResponseWithFailingAuthData() throws Exception { |
| 535 | + AuthenticationService authenticationService = mock(AuthenticationService.class); |
| 536 | + AuthenticationProvider authenticationProvider = new MockMultiStageAuthenticationProvider(); |
| 537 | + String authMethodName = authenticationProvider.getAuthMethodName(); |
| 538 | + |
| 539 | + when(brokerService.getAuthenticationService()).thenReturn(authenticationService); |
| 540 | + when(authenticationService.getAuthenticationProvider(authMethodName)).thenReturn(authenticationProvider); |
| 541 | + svcConfig.setAuthenticationEnabled(true); |
| 542 | + |
| 543 | + resetChannel(); |
| 544 | + assertTrue(channel.isActive()); |
| 545 | + assertEquals(serverCnx.getState(), State.Start); |
| 546 | + |
| 547 | + // Trigger connect command to result in AuthChallenge |
| 548 | + ByteBuf clientCommand = Commands.newConnect(authMethodName, "challenge.client", "1"); |
| 549 | + channel.writeInbound(clientCommand); |
| 550 | + |
| 551 | + Object challenge1 = getResponse(); |
| 552 | + assertTrue(challenge1 instanceof CommandAuthChallenge); |
| 553 | + |
| 554 | + // Trigger another AuthChallenge to verify that code path continues to challenge |
| 555 | + ByteBuf authResponse1 = Commands.newAuthResponse(authMethodName, AuthData.of("challenge.client".getBytes()), 1, "1"); |
| 556 | + channel.writeInbound(authResponse1); |
| 557 | + |
| 558 | + Object challenge2 = getResponse(); |
| 559 | + assertTrue(challenge2 instanceof CommandAuthChallenge); |
| 560 | + |
| 561 | + // Trigger failure |
| 562 | + ByteBuf authResponse2 = Commands.newAuthResponse(authMethodName, AuthData.of("fail.client".getBytes()), 1, "1"); |
| 563 | + channel.writeInbound(authResponse2); |
| 564 | + |
| 565 | + Object response3 = getResponse(); |
| 566 | + assertTrue(response3 instanceof CommandError); |
| 567 | + assertEquals(((CommandError) response3).getMessage(), "Unable to authenticate"); |
| 568 | + assertEquals(serverCnx.getState(), State.Failed); |
| 569 | + assertFalse(serverCnx.isActive()); |
| 570 | + channel.finish(); |
| 571 | + } |
| 572 | + |
498 | 573 | @Test(timeOut = 30000)
|
499 | 574 | public void testProducerCommand() throws Exception {
|
500 | 575 | resetChannel();
|
|
0 commit comments