You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@geode.apache.org by "ASF GitHub Bot (JIRA)" <ji...@apache.org> on 2017/12/06 22:49:00 UTC

[jira] [Commented] (GEODE-4007) Authentication failures/bad handshake should close the socket from the server side

    [ https://issues.apache.org/jira/browse/GEODE-4007?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16281060#comment-16281060 ] 

ASF GitHub Bot commented on GEODE-4007:
---------------------------------------

upthewaterspout closed pull request #1087: GEODE-4007: Authentication/Handshake errors should close the socket
URL: https://github.com/apache/geode/pull/1087
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/geode-client-protocol/src/main/java/org/apache/geode/internal/protocol/operations/OperationHandler.java b/geode-client-protocol/src/main/java/org/apache/geode/internal/protocol/operations/OperationHandler.java
index 841976dd70..dc1fe2ef31 100644
--- a/geode-client-protocol/src/main/java/org/apache/geode/internal/protocol/operations/OperationHandler.java
+++ b/geode-client-protocol/src/main/java/org/apache/geode/internal/protocol/operations/OperationHandler.java
@@ -19,6 +19,7 @@
 import org.apache.geode.internal.protocol.MessageExecutionContext;
 import org.apache.geode.internal.protocol.Result;
 import org.apache.geode.internal.protocol.serialization.SerializationService;
+import org.apache.geode.internal.protocol.state.exception.ConnectionStateException;
 
 /**
  * This interface is implemented by a object capable of handling request types 'Req' and returning
@@ -30,7 +31,11 @@
   /**
    * Decode the message, deserialize contained values using the serialization service, do the work
    * indicated on the provided cache, and return a response.
+   *
+   * @throws ConnectionStateException if the connection is in an invalid state for the operation in
+   *         question.
    */
   Result<Resp, ErrorResp> process(SerializationService serializationService, Req request,
-      MessageExecutionContext messageExecutionContext) throws InvalidExecutionContextException;
+      MessageExecutionContext messageExecutionContext)
+      throws InvalidExecutionContextException, ConnectionStateException;
 }
diff --git a/geode-client-protocol/src/main/java/org/apache/geode/internal/protocol/state/ConnectionShiroAuthorizingStateProcessor.java b/geode-client-protocol/src/main/java/org/apache/geode/internal/protocol/state/ConnectionShiroAuthorizingStateProcessor.java
index cd2c6cca0b..c7c71aa112 100644
--- a/geode-client-protocol/src/main/java/org/apache/geode/internal/protocol/state/ConnectionShiroAuthorizingStateProcessor.java
+++ b/geode-client-protocol/src/main/java/org/apache/geode/internal/protocol/state/ConnectionShiroAuthorizingStateProcessor.java
@@ -21,6 +21,7 @@
 import org.apache.geode.internal.protocol.OperationContext;
 import org.apache.geode.internal.protocol.ProtocolErrorCode;
 import org.apache.geode.internal.protocol.state.exception.ConnectionStateException;
+import org.apache.geode.internal.protocol.state.exception.OperationNotAuthorizedException;
 import org.apache.geode.internal.security.SecurityService;
 import org.apache.geode.security.NotAuthorizedException;
 
@@ -42,7 +43,7 @@ public void validateOperation(MessageExecutionContext messageContext,
       securityService.authorize(operationContext.getAccessPermissionRequired());
     } catch (NotAuthorizedException e) {
       messageContext.getStatistics().incAuthorizationViolations();
-      throw new ConnectionStateException(ProtocolErrorCode.AUTHORIZATION_FAILED,
+      throw new OperationNotAuthorizedException(ProtocolErrorCode.AUTHORIZATION_FAILED,
           "The user is not authorized to complete this operation");
     } finally {
       threadState.restore();
diff --git a/geode-client-protocol/src/main/java/org/apache/geode/internal/protocol/state/ConnectionStateProcessor.java b/geode-client-protocol/src/main/java/org/apache/geode/internal/protocol/state/ConnectionStateProcessor.java
index 321120d2b5..e0d18b3924 100644
--- a/geode-client-protocol/src/main/java/org/apache/geode/internal/protocol/state/ConnectionStateProcessor.java
+++ b/geode-client-protocol/src/main/java/org/apache/geode/internal/protocol/state/ConnectionStateProcessor.java
@@ -58,4 +58,13 @@ default ConnectionHandshakingStateProcessor allowHandshake() throws ConnectionSt
     throw new ConnectionStateException(ProtocolErrorCode.UNSUPPORTED_OPERATION,
         "Requested operation not allowed at this time");
   }
+
+  /**
+   * This indicates whether this state is capable of receiving any more messages
+   *
+   * @return True if the socket should be closed
+   */
+  default boolean socketProcessingIsFinished() {
+    return false;
+  }
 }
diff --git a/geode-client-protocol/src/main/java/org/apache/geode/internal/protocol/state/ConnectionTerminatingStateProcessor.java b/geode-client-protocol/src/main/java/org/apache/geode/internal/protocol/state/ConnectionTerminatingStateProcessor.java
new file mode 100644
index 0000000000..d1b47ecbab
--- /dev/null
+++ b/geode-client-protocol/src/main/java/org/apache/geode/internal/protocol/state/ConnectionTerminatingStateProcessor.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.protocol.state;
+
+import org.apache.geode.internal.protocol.MessageExecutionContext;
+import org.apache.geode.internal.protocol.OperationContext;
+import org.apache.geode.internal.protocol.ProtocolErrorCode;
+import org.apache.geode.internal.protocol.state.exception.ConnectionStateException;
+
+public class ConnectionTerminatingStateProcessor implements ConnectionStateProcessor {
+  @Override
+  public void validateOperation(MessageExecutionContext messageContext,
+      OperationContext operationContext) throws ConnectionStateException {
+    throw new ConnectionStateException(ProtocolErrorCode.GENERIC_FAILURE,
+        "This connection has been marked as terminating.");
+  }
+
+  @Override
+  public boolean socketProcessingIsFinished() {
+    return true;
+  }
+}
diff --git a/geode-client-protocol/src/main/java/org/apache/geode/internal/protocol/security/exception/IncompatibleAuthenticationMechanismsException.java b/geode-client-protocol/src/main/java/org/apache/geode/internal/protocol/state/exception/OperationNotAuthorizedException.java
similarity index 70%
rename from geode-client-protocol/src/main/java/org/apache/geode/internal/protocol/security/exception/IncompatibleAuthenticationMechanismsException.java
rename to geode-client-protocol/src/main/java/org/apache/geode/internal/protocol/state/exception/OperationNotAuthorizedException.java
index e7995223e0..a06002bf69 100644
--- a/geode-client-protocol/src/main/java/org/apache/geode/internal/protocol/security/exception/IncompatibleAuthenticationMechanismsException.java
+++ b/geode-client-protocol/src/main/java/org/apache/geode/internal/protocol/state/exception/OperationNotAuthorizedException.java
@@ -12,12 +12,12 @@
  * or implied. See the License for the specific language governing permissions and limitations under
  * the License.
  */
-package org.apache.geode.internal.protocol.security.exception;
+package org.apache.geode.internal.protocol.state.exception;
 
-import org.apache.geode.security.AuthenticationFailedException;
+import org.apache.geode.internal.protocol.ProtocolErrorCode;
 
-public class IncompatibleAuthenticationMechanismsException extends AuthenticationFailedException {
-  public IncompatibleAuthenticationMechanismsException(String message) {
-    super(message);
+public class OperationNotAuthorizedException extends ConnectionStateException {
+  public OperationNotAuthorizedException(ProtocolErrorCode errorCode, String errorMessage) {
+    super(errorCode, errorMessage);
   }
 }
diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/client/protocol/ClientProtocolProcessor.java b/geode-core/src/main/java/org/apache/geode/internal/cache/client/protocol/ClientProtocolProcessor.java
index e49f16f402..2631ed52af 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/cache/client/protocol/ClientProtocolProcessor.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/cache/client/protocol/ClientProtocolProcessor.java
@@ -42,4 +42,9 @@ void processMessage(InputStream inputStream, OutputStream outputStream)
    */
   @Override
   void close();
+
+  /**
+   * Indicates that the associated connection should be closed
+   */
+  boolean socketProcessingIsFinished();
 }
diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/GenericProtocolServerConnection.java b/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/GenericProtocolServerConnection.java
index 8063bf016e..736c7ad30b 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/GenericProtocolServerConnection.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/GenericProtocolServerConnection.java
@@ -68,6 +68,10 @@ protected void doOneMessage() {
       OutputStream outputStream = socket.getOutputStream();
 
       protocolProcessor.processMessage(inputStream, outputStream);
+
+      if (protocolProcessor.socketProcessingIsFinished()) {
+        this.setFlagProcessMessagesAsFalse();
+      }
     } catch (EOFException e) {
       this.setFlagProcessMessagesAsFalse();
       setClientDisconnectedException(e);
diff --git a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufCachePipeline.java b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufCachePipeline.java
index 647e13eb81..4b88ec48aa 100644
--- a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufCachePipeline.java
+++ b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufCachePipeline.java
@@ -57,4 +57,9 @@ public void processMessage(InputStream inputStream, OutputStream outputStream)
   public void close() {
     this.statistics.clientDisconnected();
   }
+
+  @Override
+  public boolean socketProcessingIsFinished() {
+    return messageExecutionContext.getConnectionStateProcessor().socketProcessingIsFinished();
+  }
 }
diff --git a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufLocatorPipeline.java b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufLocatorPipeline.java
index 3129d59fef..d67897f978 100644
--- a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufLocatorPipeline.java
+++ b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufLocatorPipeline.java
@@ -55,4 +55,10 @@ public void processMessage(InputStream inputStream, OutputStream outputStream)
   public void close() {
     this.statistics.clientDisconnected();
   }
+
+  @Override
+  public boolean socketProcessingIsFinished() {
+    // All locator connections are closed after one message, so this is not used
+    return false;
+  }
 }
diff --git a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufOpsProcessor.java b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufOpsProcessor.java
index ef640278e7..9437c3abe0 100644
--- a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufOpsProcessor.java
+++ b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/ProtobufOpsProcessor.java
@@ -28,7 +28,9 @@
 import org.apache.geode.internal.protocol.protobuf.v1.registry.ProtobufOperationContextRegistry;
 import org.apache.geode.internal.protocol.protobuf.v1.utilities.ProtobufResponseUtilities;
 import org.apache.geode.internal.protocol.serialization.SerializationService;
+import org.apache.geode.internal.protocol.state.ConnectionTerminatingStateProcessor;
 import org.apache.geode.internal.protocol.state.exception.ConnectionStateException;
+import org.apache.geode.internal.protocol.state.exception.OperationNotAuthorizedException;
 
 /**
  * This handles protobuf requests by determining the operation type of the request and dispatching
@@ -59,8 +61,14 @@ public ProtobufOpsProcessor(SerializationService serializationService,
       messageExecutionContext.getConnectionStateProcessor()
           .validateOperation(messageExecutionContext, operationContext);
       result = processOperation(request, messageExecutionContext, requestType, operationContext);
+    } catch (OperationNotAuthorizedException e) {
+      // Don't move to a terminating state for authorization state failures
+      logger.warn(e.getMessage());
+      result = Failure.of(ProtobufResponseUtilities.makeErrorResponse(e));
     } catch (ConnectionStateException e) {
       logger.warn(e.getMessage());
+      messageExecutionContext
+          .setConnectionStateProcessor(new ConnectionTerminatingStateProcessor());
       result = Failure.of(ProtobufResponseUtilities.makeErrorResponse(e));
     }
 
@@ -69,7 +77,8 @@ public ProtobufOpsProcessor(SerializationService serializationService,
   }
 
   private Result processOperation(ClientProtocol.Request request, MessageExecutionContext context,
-      ClientProtocol.Request.RequestAPICase requestType, OperationContext operationContext) {
+      ClientProtocol.Request.RequestAPICase requestType, OperationContext operationContext)
+      throws ConnectionStateException {
     try {
       return operationContext.getOperationHandler().process(serializationService,
           operationContext.getFromRequest().apply(request), context);
diff --git a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/HandshakeRequestOperationHandler.java b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/HandshakeRequestOperationHandler.java
index 1521fc063c..97338e6d8f 100644
--- a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/HandshakeRequestOperationHandler.java
+++ b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/HandshakeRequestOperationHandler.java
@@ -29,6 +29,7 @@
 import org.apache.geode.internal.protocol.serialization.SerializationService;
 import org.apache.geode.internal.protocol.state.ConnectionHandshakingStateProcessor;
 import org.apache.geode.internal.protocol.state.ConnectionStateProcessor;
+import org.apache.geode.internal.protocol.state.ConnectionTerminatingStateProcessor;
 import org.apache.geode.internal.protocol.state.exception.ConnectionStateException;
 
 public class HandshakeRequestOperationHandler implements
@@ -39,20 +40,21 @@
   @Override
   public Result<ConnectionAPI.HandshakeResponse, ClientProtocol.ErrorResponse> process(
       SerializationService serializationService, ConnectionAPI.HandshakeRequest request,
-      MessageExecutionContext messageExecutionContext) throws InvalidExecutionContextException {
+      MessageExecutionContext messageExecutionContext)
+      throws InvalidExecutionContextException, ConnectionStateException {
     ConnectionHandshakingStateProcessor stateProcessor;
 
-    try {
-      stateProcessor = messageExecutionContext.getConnectionStateProcessor().allowHandshake();
-    } catch (ConnectionStateException e) {
-      return Failure.of(ProtobufResponseUtilities.makeErrorResponse(e));
-    }
+    // If handshake not allowed by this state this will throw a ConnectionStateException
+    stateProcessor = messageExecutionContext.getConnectionStateProcessor().allowHandshake();
 
     final boolean handshakeSucceeded =
         validator.isValid(request.getMajorVersion(), request.getMinorVersion());
     if (handshakeSucceeded) {
       ConnectionStateProcessor nextStateProcessor = stateProcessor.handshakeSucceeded();
       messageExecutionContext.setConnectionStateProcessor(nextStateProcessor);
+    } else {
+      messageExecutionContext
+          .setConnectionStateProcessor(new ConnectionTerminatingStateProcessor());
     }
 
     return Success.of(ConnectionAPI.HandshakeResponse.newBuilder()
diff --git a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/security/AuthenticationRequestOperationHandler.java b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/security/AuthenticationRequestOperationHandler.java
index 3decb49f63..727a693685 100644
--- a/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/security/AuthenticationRequestOperationHandler.java
+++ b/geode-protobuf/src/main/java/org/apache/geode/internal/protocol/protobuf/v1/operations/security/AuthenticationRequestOperationHandler.java
@@ -20,19 +20,16 @@
 import org.apache.logging.log4j.Logger;
 
 import org.apache.geode.internal.exception.InvalidExecutionContextException;
-import org.apache.geode.internal.protocol.Failure;
 import org.apache.geode.internal.protocol.MessageExecutionContext;
-import org.apache.geode.internal.protocol.ProtocolErrorCode;
 import org.apache.geode.internal.protocol.Result;
 import org.apache.geode.internal.protocol.Success;
 import org.apache.geode.internal.protocol.operations.OperationHandler;
-import org.apache.geode.internal.protocol.protobuf.v1.BasicTypes;
 import org.apache.geode.internal.protocol.protobuf.v1.ClientProtocol;
 import org.apache.geode.internal.protocol.protobuf.v1.ConnectionAPI;
-import org.apache.geode.internal.protocol.protobuf.v1.utilities.ProtobufResponseUtilities;
-import org.apache.geode.internal.protocol.security.exception.IncompatibleAuthenticationMechanismsException;
 import org.apache.geode.internal.protocol.serialization.SerializationService;
 import org.apache.geode.internal.protocol.state.ConnectionAuthenticatingStateProcessor;
+import org.apache.geode.internal.protocol.state.ConnectionStateProcessor;
+import org.apache.geode.internal.protocol.state.ConnectionTerminatingStateProcessor;
 import org.apache.geode.internal.protocol.state.exception.ConnectionStateException;
 import org.apache.geode.security.AuthenticationFailedException;
 
@@ -43,41 +40,26 @@
   @Override
   public Result<ConnectionAPI.AuthenticationResponse, ClientProtocol.ErrorResponse> process(
       SerializationService serializationService, ConnectionAPI.AuthenticationRequest request,
-      MessageExecutionContext messageExecutionContext) throws InvalidExecutionContextException {
+      MessageExecutionContext messageExecutionContext)
+      throws InvalidExecutionContextException, ConnectionStateException {
     ConnectionAuthenticatingStateProcessor stateProcessor;
 
-    try {
-      stateProcessor = messageExecutionContext.getConnectionStateProcessor().allowAuthentication();
-    } catch (ConnectionStateException e) {
-      return Failure.of(ProtobufResponseUtilities.makeErrorResponse(e));
-    }
+    // If authentication not allowed by this state this will throw a ConnectionStateException
+    stateProcessor = messageExecutionContext.getConnectionStateProcessor().allowAuthentication();
 
     Properties properties = new Properties();
     properties.putAll(request.getCredentialsMap());
 
     try {
-      messageExecutionContext.setConnectionStateProcessor(stateProcessor.authenticate(properties));
+      ConnectionStateProcessor nextState = stateProcessor.authenticate(properties);
+      messageExecutionContext.setConnectionStateProcessor(nextState);
       return Success
           .of(ConnectionAPI.AuthenticationResponse.newBuilder().setAuthenticated(true).build());
-    } catch (IncompatibleAuthenticationMechanismsException e) {
-      return Failure.of(ClientProtocol.ErrorResponse.newBuilder().setError(
-          buildAndLogError(ProtocolErrorCode.UNSUPPORTED_AUTHENTICATION_MODE, e.getMessage(), e))
-          .build());
     } catch (AuthenticationFailedException e) {
+      messageExecutionContext
+          .setConnectionStateProcessor(new ConnectionTerminatingStateProcessor());
       return Success
           .of(ConnectionAPI.AuthenticationResponse.newBuilder().setAuthenticated(false).build());
     }
   }
-
-  private BasicTypes.Error buildAndLogError(ProtocolErrorCode errorCode, String message,
-      Exception ex) {
-    if (ex == null) {
-      logger.warn(message);
-    } else {
-      logger.warn(message, ex);
-    }
-
-    return BasicTypes.Error.newBuilder().setErrorCode(errorCode.codeValue).setMessage(message)
-        .build();
-  }
 }
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/AuthenticationIntegrationTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/AuthenticationIntegrationTest.java
index e10573ac73..c3b6c7364f 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/AuthenticationIntegrationTest.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/AuthenticationIntegrationTest.java
@@ -200,6 +200,7 @@ public void skippingAuthenticationFails() throws Exception {
         errorResponse.getResponse().getResponseAPICase());
     assertEquals(AUTHENTICATION_FAILED.codeValue,
         errorResponse.getResponse().getErrorResponse().getError().getErrorCode());
+    verifyConnectionClosed();
   }
 
   @Test
@@ -246,6 +247,7 @@ public void simpleAuthenticationWithEmptyCreds() throws Exception {
     ConnectionAPI.AuthenticationResponse authenticationResponse =
         parseSimpleAuthenticationResponseFromInput();
     assertFalse(authenticationResponse.getAuthenticated());
+    verifyConnectionClosed();
   }
 
   @Test
@@ -265,6 +267,8 @@ public void simpleAuthenticationWithInvalidCreds() throws Exception {
     ConnectionAPI.AuthenticationResponse authenticationResponse =
         parseSimpleAuthenticationResponseFromInput();
     assertFalse(authenticationResponse.getAuthenticated());
+
+    verifyConnectionClosed();
   }
 
   @Test
@@ -296,6 +300,7 @@ public void legacyClientAuthenticatorSet() throws Exception {
         errorResponse.getResponse().getResponseAPICase());
     assertEquals(UNSUPPORTED_AUTHENTICATION_MODE.codeValue,
         errorResponse.getResponse().getErrorResponse().getError().getErrorCode());
+    verifyConnectionClosed();
   }
 
   @Test
@@ -316,6 +321,18 @@ public void legacyPeerAuthenticatorSet() throws Exception {
         errorResponse.getResponse().getResponseAPICase());
     assertEquals(UNSUPPORTED_AUTHENTICATION_MODE.codeValue,
         errorResponse.getResponse().getErrorResponse().getError().getErrorCode());
+    verifyConnectionClosed();
+  }
+
+  private void verifyConnectionClosed() {
+    Awaitility.await().atMost(10, TimeUnit.SECONDS).until(() -> {
+      try {
+        assertEquals(-1, socket.getInputStream().read()); // EOF implies disconnected.
+        return true;
+      } catch (IOException e) {
+        throw new RuntimeException(e);
+      }
+    });
   }
 
   private void createLegacyAuthCache(String authenticationProperty) {
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/HandshakeIntegrationTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/HandshakeIntegrationTest.java
index b52ed0c6c1..de3038f88d 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/HandshakeIntegrationTest.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/HandshakeIntegrationTest.java
@@ -15,6 +15,7 @@
 package org.apache.geode.internal.protocol.protobuf.v1;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
@@ -40,6 +41,7 @@
 import org.apache.geode.distributed.ConfigurationProperties;
 import org.apache.geode.internal.AvailablePortHelper;
 import org.apache.geode.internal.cache.tier.CommunicationMode;
+import org.apache.geode.internal.protocol.ProtocolErrorCode;
 import org.apache.geode.internal.protocol.protobuf.v1.serializer.ProtobufProtocolSerializer;
 import org.apache.geode.test.junit.categories.IntegrationTest;
 
@@ -122,4 +124,64 @@ public void testInvalidMajorVersionBreaksConnection() throws Exception {
       }
     });
   }
+
+  @Test
+  public void testInvalidMinorVersionBreaksConnectionAfterResponse() throws Exception {
+    outputStream.write(CommunicationMode.ProtobufClientServerProtocol.getModeNumber());
+    outputStream.write(ConnectionAPI.MajorVersions.CURRENT_MAJOR_VERSION_VALUE);
+
+    ClientProtocol.Message.newBuilder()
+        .setRequest(ClientProtocol.Request.newBuilder()
+            .setHandshakeRequest(ConnectionAPI.HandshakeRequest.newBuilder()
+                .setMajorVersion(ConnectionAPI.MajorVersions.CURRENT_MAJOR_VERSION_VALUE)
+                .setMinorVersion(ConnectionAPI.MinorVersions.INVALID_MINOR_VERSION_VALUE)))
+        .build().writeDelimitedTo(outputStream);
+    ClientProtocol.Message handshakeResponse = protobufProtocolSerializer.deserialize(inputStream);
+    assertFalse(handshakeResponse.getResponse().getHandshakeResponse().getHandshakePassed());
+
+    // Verify that connection is closed
+    Awaitility.await().atMost(10, TimeUnit.SECONDS).until(() -> {
+      try {
+        assertEquals(-1, socket.getInputStream().read()); // EOF implies disconnected.
+        return true;
+      } catch (IOException e) {
+        throw new RuntimeException(e);
+      }
+    });
+  }
+
+  @Test
+  public void testUnexpectedHandshakeFailsAndClosesConnection() throws Exception {
+    outputStream.write(CommunicationMode.ProtobufClientServerProtocol.getModeNumber());
+    outputStream.write(ConnectionAPI.MajorVersions.CURRENT_MAJOR_VERSION_VALUE);
+
+    ClientProtocol.Message.newBuilder()
+        .setRequest(ClientProtocol.Request.newBuilder()
+            .setHandshakeRequest(ConnectionAPI.HandshakeRequest.newBuilder()
+                .setMajorVersion(ConnectionAPI.MajorVersions.CURRENT_MAJOR_VERSION_VALUE)
+                .setMinorVersion(ConnectionAPI.MinorVersions.CURRENT_MINOR_VERSION_VALUE)))
+        .build().writeDelimitedTo(outputStream);
+    ClientProtocol.Message handshakeResponse = protobufProtocolSerializer.deserialize(inputStream);
+    assertTrue(handshakeResponse.getResponse().getHandshakeResponse().getHandshakePassed());
+
+    ClientProtocol.Message.newBuilder()
+        .setRequest(ClientProtocol.Request.newBuilder()
+            .setHandshakeRequest(ConnectionAPI.HandshakeRequest.newBuilder()
+                .setMajorVersion(ConnectionAPI.MajorVersions.CURRENT_MAJOR_VERSION_VALUE)
+                .setMinorVersion(ConnectionAPI.MinorVersions.CURRENT_MINOR_VERSION_VALUE)))
+        .build().writeDelimitedTo(outputStream);
+    ClientProtocol.Message failingHandshake = protobufProtocolSerializer.deserialize(inputStream);
+    assertEquals(ProtocolErrorCode.UNSUPPORTED_OPERATION.codeValue,
+        failingHandshake.getResponse().getErrorResponse().getError().getErrorCode());
+
+    // Verify that connection is closed
+    Awaitility.await().atMost(10, TimeUnit.SECONDS).until(() -> {
+      try {
+        assertEquals(-1, socket.getInputStream().read()); // EOF implies disconnected.
+        return true;
+      } catch (IOException e) {
+        throw new RuntimeException(e);
+      }
+    });
+  }
 }
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/acceptance/CacheConnectionTimeoutJUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/acceptance/CacheConnectionTimeoutJUnitTest.java
index da65172112..116a69a4a6 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/acceptance/CacheConnectionTimeoutJUnitTest.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/acceptance/CacheConnectionTimeoutJUnitTest.java
@@ -17,6 +17,7 @@
 
 import static junit.framework.TestCase.assertTrue;
 import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -27,6 +28,7 @@
 
 import org.awaitility.Awaitility;
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -40,9 +42,12 @@
 import org.apache.geode.cache.server.CacheServer;
 import org.apache.geode.distributed.ConfigurationProperties;
 import org.apache.geode.internal.AvailablePortHelper;
+import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.internal.cache.tier.CommunicationMode;
 import org.apache.geode.internal.cache.tier.sockets.ClientHealthMonitor;
 import org.apache.geode.internal.net.SocketCreatorFactory;
+import org.apache.geode.internal.protocol.MessageExecutionContext;
+import org.apache.geode.internal.protocol.Result;
 import org.apache.geode.internal.protocol.protobuf.v1.ClientProtocol;
 import org.apache.geode.internal.protocol.protobuf.v1.ConnectionAPI;
 import org.apache.geode.internal.protocol.protobuf.v1.MessageUtil;
@@ -82,7 +87,6 @@ public void setup() throws Exception {
     cacheFactory.set(ConfigurationProperties.MCAST_PORT, "0");
     cacheFactory.set(ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION, "false");
     cacheFactory.set(ConfigurationProperties.USE_CLUSTER_CONFIGURATION, "false");
-    cacheFactory.setSecurityManager(null);
 
     cache = cacheFactory.create();
 
@@ -149,6 +153,15 @@ public void testUnresponsiveClientsGetDisconnected() throws Exception {
   @Test
   public void testResponsiveClientsStaysConnected() throws Exception {
     ProtobufProtocolSerializer protobufProtocolSerializer = new ProtobufProtocolSerializer();
+
+    ClientProtocol.Message.newBuilder()
+        .setRequest(ClientProtocol.Request.newBuilder()
+            .setHandshakeRequest(ConnectionAPI.HandshakeRequest.newBuilder()
+                .setMajorVersion(ConnectionAPI.MajorVersions.CURRENT_MAJOR_VERSION_VALUE)
+                .setMinorVersion(ConnectionAPI.MinorVersions.CURRENT_MINOR_VERSION_VALUE)))
+        .build().writeDelimitedTo(outputStream);
+    protobufProtocolSerializer.deserialize(socket.getInputStream());
+
     ClientProtocol.Message putMessage =
         MessageUtil.makePutRequestMessage(serializationService, TEST_KEY, TEST_VALUE, TEST_REGION);
 
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetAllRequestOperationHandlerJUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetAllRequestOperationHandlerJUnitTest.java
index c7584386ef..592e8df330 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetAllRequestOperationHandlerJUnitTest.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetAllRequestOperationHandlerJUnitTest.java
@@ -33,7 +33,6 @@
 
 import org.apache.geode.cache.CacheLoaderException;
 import org.apache.geode.cache.Region;
-import org.apache.geode.internal.exception.InvalidExecutionContextException;
 import org.apache.geode.internal.protocol.Result;
 import org.apache.geode.internal.protocol.Success;
 import org.apache.geode.internal.protocol.TestExecutionContext;
@@ -95,8 +94,7 @@ public void processReturnsExpectedValuesForValidKeys() throws Exception {
   }
 
   @Test
-  public void processReturnsNoEntriesForNoKeysRequested() throws UnsupportedEncodingTypeException,
-      CodecNotRegisteredForTypeException, InvalidExecutionContextException {
+  public void processReturnsNoEntriesForNoKeysRequested() throws Exception {
     Result result =
         operationHandler.process(serializationServiceStub, generateTestRequest(false, false),
             TestExecutionContext.getNoAuthCacheExecutionContext(cacheStub));
@@ -129,8 +127,7 @@ public void singeNullKey() throws Exception {
   }
 
   @Test
-  public void multipleKeysWhereOneThrows() throws UnsupportedEncodingTypeException,
-      CodecNotRegisteredForTypeException, InvalidExecutionContextException {
+  public void multipleKeysWhereOneThrows() throws Exception {
     Result result =
         operationHandler.process(serializationServiceStub, generateTestRequest(true, true),
             TestExecutionContext.getNoAuthCacheExecutionContext(cacheStub));
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetAvailableServersOperationHandlerJUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetAvailableServersOperationHandlerJUnitTest.java
index a43c5faab5..61f72d12ba 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetAvailableServersOperationHandlerJUnitTest.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetAvailableServersOperationHandlerJUnitTest.java
@@ -38,6 +38,7 @@
 import org.apache.geode.internal.protocol.protobuf.v1.LocatorAPI;
 import org.apache.geode.internal.protocol.protobuf.v1.LocatorAPI.GetAvailableServersResponse;
 import org.apache.geode.internal.protocol.protobuf.v1.utilities.ProtobufRequestUtilities;
+import org.apache.geode.internal.protocol.state.exception.ConnectionStateException;
 import org.apache.geode.test.junit.categories.UnitTest;
 
 @Category(UnitTest.class)
@@ -81,8 +82,7 @@ public void testServerReturnedFromHandler() throws Exception {
   }
 
   @Test
-  public void testWhenServersFromSnapshotAreNullReturnsEmtpy()
-      throws InvalidExecutionContextException {
+  public void testWhenServersFromSnapshotAreNullReturnsEmtpy() throws Exception {
     when(locatorLoadSnapshot.getServers(any())).thenReturn(null);
 
     LocatorAPI.GetAvailableServersRequest getAvailableServersRequest =
@@ -95,8 +95,7 @@ public void testWhenServersFromSnapshotAreNullReturnsEmtpy()
   }
 
   private Result getOperationHandlerResult(
-      LocatorAPI.GetAvailableServersRequest getAvailableServersRequest)
-      throws InvalidExecutionContextException {
+      LocatorAPI.GetAvailableServersRequest getAvailableServersRequest) throws Exception {
     return operationHandler.process(serializationServiceStub, getAvailableServersRequest,
         TestExecutionContext.getLocatorExecutionContext(internalLocatorMock));
   }
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRegionNamesRequestOperationHandlerJUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRegionNamesRequestOperationHandlerJUnitTest.java
index 0deb3f6b04..4913e4b42d 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRegionNamesRequestOperationHandlerJUnitTest.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/GetRegionNamesRequestOperationHandlerJUnitTest.java
@@ -61,7 +61,7 @@ public void setUp() throws Exception {
   }
 
   @Test
-  public void processReturnsCacheRegions() throws InvalidExecutionContextException {
+  public void processReturnsCacheRegions() throws Exception {
     Result result = operationHandler.process(serializationServiceStub,
         ProtobufRequestUtilities.createGetRegionNamesRequest(),
         getNoAuthCacheExecutionContext(cacheStub));
diff --git a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/HandshakeRequestOperationHandlerJUnitTest.java b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/HandshakeRequestOperationHandlerJUnitTest.java
index 0641e5d196..0baf9bb8ea 100644
--- a/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/HandshakeRequestOperationHandlerJUnitTest.java
+++ b/geode-protobuf/src/test/java/org/apache/geode/internal/protocol/protobuf/v1/operations/HandshakeRequestOperationHandlerJUnitTest.java
@@ -4,6 +4,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.Mockito.mock;
 
 import org.apache.shiro.subject.Subject;
@@ -13,6 +14,7 @@
 
 import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.internal.exception.InvalidExecutionContextException;
+import org.apache.geode.internal.protocol.Failure;
 import org.apache.geode.internal.protocol.MessageExecutionContext;
 import org.apache.geode.internal.protocol.ProtocolErrorCode;
 import org.apache.geode.internal.protocol.Result;
@@ -21,9 +23,11 @@
 import org.apache.geode.internal.protocol.protobuf.v1.ProtobufSerializationService;
 import org.apache.geode.internal.protocol.protobuf.v1.state.ConnectionShiroAuthenticatingStateProcessor;
 import org.apache.geode.internal.protocol.protobuf.v1.state.ProtobufConnectionHandshakeStateProcessor;
+import org.apache.geode.internal.protocol.protobuf.v1.utilities.ProtobufResponseUtilities;
 import org.apache.geode.internal.protocol.serialization.SerializationService;
 import org.apache.geode.internal.protocol.state.ConnectionShiroAuthorizingStateProcessor;
 import org.apache.geode.internal.protocol.state.NoSecurityConnectionStateProcessor;
+import org.apache.geode.internal.protocol.state.exception.ConnectionStateException;
 import org.apache.geode.internal.security.SecurityService;
 import org.apache.geode.test.junit.categories.UnitTest;
 
@@ -85,16 +89,20 @@ public void testInvalidMajorVersionFails() throws Exception {
         new MessageExecutionContext(mock(InternalCache.class), null, handshakeStateProcessor);
 
     verifyHandshakeFails(handshakeRequest, messageExecutionContext);
+  }
 
-    // Also validate the protobuf INVALID_MAJOR_VERSION_VALUE constant fails
-    handshakeRequest =
+  @Test
+  public void testInvalidMajorVersionProtocolConstantFails() throws Exception {
+    ConnectionAPI.HandshakeRequest handshakeRequest =
         generateHandshakeRequest(ConnectionAPI.MajorVersions.INVALID_MAJOR_VERSION_VALUE,
             ConnectionAPI.MinorVersions.CURRENT_MINOR_VERSION_VALUE);
+    MessageExecutionContext messageExecutionContext =
+        new MessageExecutionContext(mock(InternalCache.class), null, handshakeStateProcessor);
     verifyHandshakeFails(handshakeRequest, messageExecutionContext);
   }
 
   private void verifyHandshakeFails(ConnectionAPI.HandshakeRequest handshakeRequest,
-      MessageExecutionContext messageExecutionContext) throws InvalidExecutionContextException {
+      MessageExecutionContext messageExecutionContext) throws Exception {
     Result<ConnectionAPI.HandshakeResponse, ClientProtocol.ErrorResponse> result =
         handshakeHandler.process(serializationService, handshakeRequest, messageExecutionContext);
     ConnectionAPI.HandshakeResponse handshakeResponse = result.getMessage();
@@ -111,11 +119,16 @@ public void testInvalidMinorVersionFails() throws Exception {
         new MessageExecutionContext(mock(InternalCache.class), null, handshakeStateProcessor);
 
     verifyHandshakeFails(handshakeRequest, messageExecutionContext);
+  }
 
-    // Also validate the protobuf INVALID_MINOR_VERSION_VALUE constant fails
-    handshakeRequest =
+  @Test
+  public void testInvalidMinorVersionProtocolConstantFails() throws Exception {
+    ConnectionAPI.HandshakeRequest handshakeRequest =
         generateHandshakeRequest(ConnectionAPI.MajorVersions.CURRENT_MAJOR_VERSION_VALUE,
             ConnectionAPI.MinorVersions.INVALID_MINOR_VERSION_VALUE);
+    MessageExecutionContext messageExecutionContext =
+        new MessageExecutionContext(mock(InternalCache.class), null, handshakeStateProcessor);
+
     verifyHandshakeFails(handshakeRequest, messageExecutionContext);
   }
 
@@ -127,11 +140,12 @@ public void testNoSecurityStateFailsHandshake() throws Exception {
     MessageExecutionContext messageExecutionContext = new MessageExecutionContext(
         mock(InternalCache.class), null, new NoSecurityConnectionStateProcessor());
 
-    Result<ConnectionAPI.HandshakeResponse, ClientProtocol.ErrorResponse> result =
-        handshakeHandler.process(serializationService, handshakeRequest, messageExecutionContext);
-    ClientProtocol.ErrorResponse errorMessage = result.getErrorMessage();
-    assertEquals(ProtocolErrorCode.UNSUPPORTED_OPERATION.codeValue,
-        errorMessage.getError().getErrorCode());
+    try {
+      handshakeHandler.process(serializationService, handshakeRequest, messageExecutionContext);
+      fail("Handshake in non-handshake state should throw exception");
+    } catch (ConnectionStateException ex) {
+      assertEquals(ProtocolErrorCode.UNSUPPORTED_OPERATION, ex.getErrorCode());
+    }
   }
 
   @Test
@@ -143,11 +157,12 @@ public void testAuthenticatingStateFailsHandshake() throws Exception {
         new MessageExecutionContext(mock(InternalCache.class), null,
             new ConnectionShiroAuthenticatingStateProcessor(mock(SecurityService.class)));
 
-    Result<ConnectionAPI.HandshakeResponse, ClientProtocol.ErrorResponse> result =
-        handshakeHandler.process(serializationService, handshakeRequest, messageExecutionContext);
-    ClientProtocol.ErrorResponse errorMessage = result.getErrorMessage();
-    assertEquals(ProtocolErrorCode.UNSUPPORTED_OPERATION.codeValue,
-        errorMessage.getError().getErrorCode());
+    try {
+      handshakeHandler.process(serializationService, handshakeRequest, messageExecutionContext);
+      fail("Handshake in non-handshake state should throw exception");
+    } catch (ConnectionStateException ex) {
+      assertEquals(ProtocolErrorCode.UNSUPPORTED_OPERATION, ex.getErrorCode());
+    }
   }
 
   @Test
@@ -160,11 +175,12 @@ public void testAuthorizingStateFailsHandshake() throws Exception {
             new ConnectionShiroAuthorizingStateProcessor(mock(SecurityService.class),
                 mock(Subject.class)));
 
-    Result<ConnectionAPI.HandshakeResponse, ClientProtocol.ErrorResponse> result =
-        handshakeHandler.process(serializationService, handshakeRequest, messageExecutionContext);
-    ClientProtocol.ErrorResponse errorMessage = result.getErrorMessage();
-    assertEquals(ProtocolErrorCode.UNSUPPORTED_OPERATION.codeValue,
-        errorMessage.getError().getErrorCode());
+    try {
+      handshakeHandler.process(serializationService, handshakeRequest, messageExecutionContext);
+      fail("Handshake in non-handshake state should throw exception");
+    } catch (ConnectionStateException ex) {
+      assertEquals(ProtocolErrorCode.UNSUPPORTED_OPERATION, ex.getErrorCode());
+    }
   }
 
   private ConnectionAPI.HandshakeRequest generateHandshakeRequest(int majorVersion,


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


> Authentication failures/bad handshake should close the socket from the server side
> ----------------------------------------------------------------------------------
>
>                 Key: GEODE-4007
>                 URL: https://issues.apache.org/jira/browse/GEODE-4007
>             Project: Geode
>          Issue Type: Bug
>          Components: client/server
>            Reporter: Brian Rowe
>
> Ensure after failed auth/handshake the server (after sending error response) closes the socket and cleans up.
> While going over the code together, it looks like maybe authentication errors simply leave the socket in a state where it is expecting another authentication request. It might be better to close the socket from the server side for various error conditions like a failed handshake or authentication.



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)