tabish121 commented on code in PR #5822:
URL: https://github.com/apache/activemq-artemis/pull/5822#discussion_r2193561268


##########
artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/AMQPBrokerConnection.java:
##########
@@ -1204,42 +1208,95 @@ public static boolean isApplicable(final 
NettyConnection connection) {
       }
    }
 
+   private static class XOAuth2SASLMechanism implements ClientSASL {
+
+      private final String userName;
+      private final String token;
+
+      public XOAuth2SASLMechanism(String userName, String token) {
+         this.userName = userName;
+         this.token = token;
+      }
+
+      @Override
+      public String getName() {
+         return XOAUTH2;
+      }
+
+      @Override
+      public byte[] getInitialResponse() {
+         String response = String.format("user=%s\u0001auth=Bearer 
%s\u0001\u0001", userName, token);
+         return response.getBytes(StandardCharsets.UTF_8);
+      }
+
+      @Override
+      public byte[] getResponse(byte[] challenge) {
+         return EMPTY;
+      }
+
+      public static boolean isApplicable(final String username, final String 
password) {
+         return StringUtils.isNoneEmpty(username, password);
+      }
+   }
+
    private static final class SaslFactory implements ClientSASLFactory {
 
       private final NettyConnection connection;
       private final AMQPBrokerConnectConfiguration brokerConnectConfiguration;
+      private final String[] availableSaslMechanisms;
 
-      SaslFactory(NettyConnection connection, AMQPBrokerConnectConfiguration 
brokerConnectConfiguration) {
+      SaslFactory(NettyConnection connection, AMQPBrokerConnectConfiguration 
brokerConnectConfiguration, String[] availableSaslMechanisms) {
          this.connection = connection;
          this.brokerConnectConfiguration = brokerConnectConfiguration;
+         this.availableSaslMechanisms = availableSaslMechanisms;
       }
 
       @Override
-      public ClientSASL chooseMechanism(String[] offeredMechanims) {
-         List<String> availableMechanisms = offeredMechanims == null ? 
Collections.emptyList() : Arrays.asList(offeredMechanims);
+      public ClientSASL chooseMechanism(String[] offeredMechanisms) {
+         Set<String> acceptedMechanisms = 
getAcceptedMechanisms(offeredMechanisms, availableSaslMechanisms);
 
-         if (availableMechanisms.contains(EXTERNAL) && 
ExternalSASLMechanism.isApplicable(connection)) {
+         if (acceptedMechanisms.contains(EXTERNAL) && 
ExternalSASLMechanism.isApplicable(connection)) {
             return new ExternalSASLMechanism();
          }
+
          if (SCRAMClientSASL.isApplicable(brokerConnectConfiguration.getUser(),
                                           
brokerConnectConfiguration.getPassword())) {
             for (SCRAM scram : SCRAM.values()) {
-               if (availableMechanisms.contains(scram.getName())) {
+               if (acceptedMechanisms.contains(scram.getName())) {
                   return new SCRAMClientSASL(scram, 
brokerConnectConfiguration.getUser(),
                                              
brokerConnectConfiguration.getPassword());
                }
             }
          }
-         if (availableMechanisms.contains(PLAIN) && 
PlainSASLMechanism.isApplicable(brokerConnectConfiguration.getUser(), 
brokerConnectConfiguration.getPassword())) {
+
+         if (acceptedMechanisms.contains(PLAIN) && 
PlainSASLMechanism.isApplicable(brokerConnectConfiguration.getUser(), 
brokerConnectConfiguration.getPassword())) {
             return new 
PlainSASLMechanism(brokerConnectConfiguration.getUser(), 
brokerConnectConfiguration.getPassword());
          }
 
-         if (availableMechanisms.contains(ANONYMOUS)) {
+         if (acceptedMechanisms.contains(XOAUTH2) && 
XOAuth2SASLMechanism.isApplicable(brokerConnectConfiguration.getUser(), 
brokerConnectConfiguration.getPassword())) {
+            return new 
XOAuth2SASLMechanism(brokerConnectConfiguration.getUser(), 
brokerConnectConfiguration.getPassword());
+         }
+
+         if (acceptedMechanisms.contains(ANONYMOUS)) {
             return new AnonymousSASLMechanism();
          }
 
          return null;
       }
+
+      private Set<String> getAcceptedMechanisms(String[] 
offeredSaslMechanisms, String[] availableSaslMechanisms) {
+         Set<String> offeredSaslMechanismsSet = offeredSaslMechanisms == null 
? Set.of() : new HashSet<>(Arrays.asList(offeredSaslMechanisms));
+         Set<String> availableSaslMechanismsSet = availableSaslMechanisms == 
null ? Set.of() : new HashSet<>(Arrays.asList(availableSaslMechanisms));

Review Comment:
   This could be refactored to not allocate the enabled set of mechanisms 
unless the array is non-null and not empty as it would be most of the time.  It 
also wouldn't be necessary to create yet another Set for the result if instead 
of `Set.of()` for the offered set you used Collections.emptySet() which will 
just no-op on retainAll as it is treated as empty.



##########
artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/protocol/amqp/connect/AMQPBrokerConnection.java:
##########
@@ -1204,42 +1208,95 @@ public static boolean isApplicable(final 
NettyConnection connection) {
       }
    }
 
+   private static class XOAuth2SASLMechanism implements ClientSASL {
+
+      private final String userName;
+      private final String token;
+
+      public XOAuth2SASLMechanism(String userName, String token) {
+         this.userName = userName;
+         this.token = token;
+      }
+
+      @Override
+      public String getName() {
+         return XOAUTH2;
+      }
+
+      @Override
+      public byte[] getInitialResponse() {
+         String response = String.format("user=%s\u0001auth=Bearer 
%s\u0001\u0001", userName, token);
+         return response.getBytes(StandardCharsets.UTF_8);
+      }
+
+      @Override
+      public byte[] getResponse(byte[] challenge) {
+         return EMPTY;
+      }
+
+      public static boolean isApplicable(final String username, final String 
password) {
+         return StringUtils.isNoneEmpty(username, password);
+      }
+   }
+
    private static final class SaslFactory implements ClientSASLFactory {
 
       private final NettyConnection connection;
       private final AMQPBrokerConnectConfiguration brokerConnectConfiguration;
+      private final String[] availableSaslMechanisms;
 
-      SaslFactory(NettyConnection connection, AMQPBrokerConnectConfiguration 
brokerConnectConfiguration) {
+      SaslFactory(NettyConnection connection, AMQPBrokerConnectConfiguration 
brokerConnectConfiguration, String[] availableSaslMechanisms) {
          this.connection = connection;
          this.brokerConnectConfiguration = brokerConnectConfiguration;
+         this.availableSaslMechanisms = availableSaslMechanisms;
       }
 
       @Override
-      public ClientSASL chooseMechanism(String[] offeredMechanims) {
-         List<String> availableMechanisms = offeredMechanims == null ? 
Collections.emptyList() : Arrays.asList(offeredMechanims);
+      public ClientSASL chooseMechanism(String[] offeredMechanisms) {
+         Set<String> acceptedMechanisms = 
getAcceptedMechanisms(offeredMechanisms, availableSaslMechanisms);
 
-         if (availableMechanisms.contains(EXTERNAL) && 
ExternalSASLMechanism.isApplicable(connection)) {
+         if (acceptedMechanisms.contains(EXTERNAL) && 
ExternalSASLMechanism.isApplicable(connection)) {
             return new ExternalSASLMechanism();
          }
+
          if (SCRAMClientSASL.isApplicable(brokerConnectConfiguration.getUser(),
                                           
brokerConnectConfiguration.getPassword())) {
             for (SCRAM scram : SCRAM.values()) {
-               if (availableMechanisms.contains(scram.getName())) {
+               if (acceptedMechanisms.contains(scram.getName())) {
                   return new SCRAMClientSASL(scram, 
brokerConnectConfiguration.getUser(),
                                              
brokerConnectConfiguration.getPassword());
                }
             }
          }
-         if (availableMechanisms.contains(PLAIN) && 
PlainSASLMechanism.isApplicable(brokerConnectConfiguration.getUser(), 
brokerConnectConfiguration.getPassword())) {
+
+         if (acceptedMechanisms.contains(PLAIN) && 
PlainSASLMechanism.isApplicable(brokerConnectConfiguration.getUser(), 
brokerConnectConfiguration.getPassword())) {
             return new 
PlainSASLMechanism(brokerConnectConfiguration.getUser(), 
brokerConnectConfiguration.getPassword());
          }
 
-         if (availableMechanisms.contains(ANONYMOUS)) {
+         if (acceptedMechanisms.contains(XOAUTH2) && 
XOAuth2SASLMechanism.isApplicable(brokerConnectConfiguration.getUser(), 
brokerConnectConfiguration.getPassword())) {
+            return new 
XOAuth2SASLMechanism(brokerConnectConfiguration.getUser(), 
brokerConnectConfiguration.getPassword());
+         }
+
+         if (acceptedMechanisms.contains(ANONYMOUS)) {
             return new AnonymousSASLMechanism();
          }
 
          return null;
       }
+
+      private Set<String> getAcceptedMechanisms(String[] 
offeredSaslMechanisms, String[] availableSaslMechanisms) {

Review Comment:
   As Dom pointed out above using enabledMechanisms probably makes it more 
clear what's being filtered for in the offered set.



##########
tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/amqp/connect/AMQPConnectSaslTest.java:
##########
@@ -115,6 +117,81 @@ public void testConnectsWithPlain() throws Exception {
       }
    }
 
+   @Test
+   @Timeout(20)
+   public void testConnectsWithXOauth2() throws Exception {
+      try (ProtonTestServer peer = new ProtonTestServer()) {
+         peer.expectSaslXOauth2Connect(USER, PASSWD);
+         peer.expectOpen().respond();
+         peer.expectBegin().respond();
+         peer.start();
+
+         final URI remoteURI = peer.getServerURI();
+         logger.debug("Connect test started, peer listening on: {}", 
remoteURI);
+
+         AMQPBrokerConnectConfiguration amqpConnection =
+             new AMQPBrokerConnectConfiguration(getTestName(), 
"tcp://localhost:" + remoteURI.getPort() + "?saslMechanisms=" + XOAUTH2);
+         amqpConnection.setReconnectAttempts(0);// No reconnects
+         amqpConnection.setUser(USER);
+         amqpConnection.setPassword(PASSWD);
+
+         server.getConfiguration().addAMQPConnection(amqpConnection);
+         server.start();
+
+         peer.waitForScriptToComplete(5, TimeUnit.SECONDS);
+      }
+   }
+
+   @Test
+   @Timeout(20)
+   public void testConnectsWithXOauth2WithoutUserAndPassword() throws 
Exception {

Review Comment:
   suggest name change to 
`testXOAuth2NotSelectedWhenUserAndPasswordNotProvided` to better describe the 
test



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: gitbox-unsubscr...@activemq.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: gitbox-unsubscr...@activemq.apache.org
For additional commands, e-mail: gitbox-h...@activemq.apache.org
For further information, visit: https://activemq.apache.org/contact


Reply via email to