DonalEvans commented on a change in pull request #6835:
URL: https://github.com/apache/geode/pull/6835#discussion_r708699303
##########
File path:
geode-core/src/distributedTest/java/org/apache/geode/management/internal/security/MultiUserAuthenticationDUnitTest.java
##########
@@ -100,4 +112,65 @@ public void multiAuthenticatedView() throws Exception {
cache.close();
}
}
+
+ @Test
+ public void multiUserCQ() throws Exception {
+ int locatorPort = locator.getPort();
+ ClientCache cache = client.withCacheSetup(f ->
f.setPoolSubscriptionEnabled(true)
+ .setPoolMultiuserAuthentication(true)
+ .addPoolLocator("localhost", locatorPort))
+ .createCache();
+
+ // both are able to read data
+ RegionService regionService1 = client.createAuthenticatedView("data",
"data");
+ RegionService regionService2 = client.createAuthenticatedView("dataRead",
"dataRead");
+
+ EventsCqListner listener1 =
createAndExecuteCQ(regionService1.getQueryService(), "cq1",
+ "select * from /region r where r.length<=2");
+ EventsCqListner listener2 =
createAndExecuteCQ(regionService2.getQueryService(), "cq2",
+ "select * from /region r where r.length>=2");
+
+ // put 4 data in the region
Review comment:
This comment is incorrect; only three entries are put into the region.
##########
File path:
geode-core/src/distributedTest/java/org/apache/geode/management/internal/security/MultiUserAuthenticationDUnitTest.java
##########
@@ -100,4 +112,65 @@ public void multiAuthenticatedView() throws Exception {
cache.close();
}
}
+
+ @Test
+ public void multiUserCQ() throws Exception {
+ int locatorPort = locator.getPort();
+ ClientCache cache = client.withCacheSetup(f ->
f.setPoolSubscriptionEnabled(true)
Review comment:
This variable is never used, so this line could just be
`client.withCacheSetup(f -> f.setPoolSubscriptionEnabled(true)`
##########
File path:
geode-junit/src/main/java/org/apache/geode/test/version/VersionManager.java
##########
@@ -143,6 +143,14 @@ public String getInstall(String version) {
return unmodifiableList(testVersions);
}
+ public List<String> getVersionsLaterThanAndEqualTo(String version) {
+ checkForLoadFailure();
+ List<String> result = new ArrayList<>(testVersions);
+ result.removeIf(s -> TestVersion.compare(s, version) < 0);
+ result.add(CURRENT_VERSION);
Review comment:
This method may return unexpected results if the `version` passed to it
is greater than `CURRENT_VERSION`, since, from the method name, we would not
expect any versions to be returned in that situation.
##########
File path:
geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/command/PutUserCredentials.java
##########
@@ -39,45 +39,44 @@ public void cmdExecute(final Message clientMessage, final
ServerConnection serve
throws IOException, ClassNotFoundException, InterruptedException {
boolean isSecureMode = clientMessage.isSecureMode();
- // if (!isSecureMode)
- // client has not send secuirty header, need to send exception and log
this in security (file)
-
- if (isSecureMode) {
-
- int numberOfParts = clientMessage.getNumberOfParts();
+ if (!isSecureMode) {
+ // client has not send secuirty header, need to send exception and log
this in security (file)
Review comment:
Typo here, should be "security". Also, the comment makes it seem like an
exception should be sent and something should be logged here.
##########
File path:
geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/CacheClientProxyTest.java
##########
@@ -0,0 +1,123 @@
+/*
+ *
+ * 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.cache.tier.sockets;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.net.InetAddress;
+import java.net.Socket;
+
+import org.apache.shiro.subject.Subject;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.geode.StatisticsFactory;
+import org.apache.geode.internal.cache.Conflatable;
+import org.apache.geode.internal.cache.InternalCache;
+import
org.apache.geode.internal.cache.tier.sockets.CacheClientProxy.CacheClientProxyStatsFactory;
+import
org.apache.geode.internal.cache.tier.sockets.CacheClientProxy.MessageDispatcherFactory;
+import org.apache.geode.internal.security.SecurityService;
+import org.apache.geode.internal.serialization.KnownVersion;
+import org.apache.geode.internal.statistics.StatisticsClock;
+
+public class CacheClientProxyTest {
+ private CacheClientProxy proxy;
+ private CacheClientNotifier notifier;
+ private Socket socket;
+ private ClientProxyMembershipID id;
+ private KnownVersion version;
+ private SecurityService securityService;
+ private Subject subject;
+ private StatisticsClock clock;
+ private InternalCache cache;
+ private StatisticsFactory statsFactory;
+ private CacheClientProxyStatsFactory proxyStatsFactory;
+ private MessageDispatcherFactory dispatcherFactory;
+ private InetAddress inetAddress;
+ private CacheServerStats stats;
+
+ @Before
+ public void before() throws Exception {
+ notifier = mock(CacheClientNotifier.class);
+ stats = mock(CacheServerStats.class);
+ socket = mock(Socket.class);
+ inetAddress = mock(InetAddress.class);
+ when(socket.getInetAddress()).thenReturn(inetAddress);
+ when(notifier.getAcceptorStats()).thenReturn(stats);
+ id = mock(ClientProxyMembershipID.class);
+ version = KnownVersion.TEST_VERSION;
+ securityService = mock(SecurityService.class);
+ subject = mock(Subject.class);
+ clock = mock(StatisticsClock.class);
+ cache = mock(InternalCache.class);
+ statsFactory = mock(StatisticsFactory.class);
+ proxyStatsFactory = mock(CacheClientProxyStatsFactory.class);
+ dispatcherFactory = mock(MessageDispatcherFactory.class);
+ }
+
+ @Test
+ public void noExceptionWhenGettingSubjectForCQWhenSubjectIsNotNull() {
+ proxy = spy(new CacheClientProxy(cache, notifier, socket, id, true, (byte)
1, version, 1L, true,
+ securityService, subject, clock, statsFactory, proxyStatsFactory,
dispatcherFactory));
+ proxy.getSubject("cq");
+ }
+
+ @Test
+ public void noExceptionWhenGettingSubjectForCQWhenSubjectIsNull() {
+ proxy = spy(new CacheClientProxy(cache, notifier, socket, id, true, (byte)
1, version, 1L, true,
+ securityService, null, clock, statsFactory, proxyStatsFactory,
dispatcherFactory));
+ proxy.getSubject("cq");
+ }
+
+ @Test
+ public void deliverMessageWhenSubjectIsNotNull() throws Exception {
Review comment:
`Exception` is not thrown from this method, nor from the one below.
##########
File path:
geode-core/src/distributedTest/java/org/apache/geode/management/internal/security/MultiUserAuthenticationDUnitTest.java
##########
@@ -100,4 +112,65 @@ public void multiAuthenticatedView() throws Exception {
cache.close();
}
}
+
+ @Test
+ public void multiUserCQ() throws Exception {
+ int locatorPort = locator.getPort();
+ ClientCache cache = client.withCacheSetup(f ->
f.setPoolSubscriptionEnabled(true)
+ .setPoolMultiuserAuthentication(true)
+ .addPoolLocator("localhost", locatorPort))
+ .createCache();
+
+ // both are able to read data
+ RegionService regionService1 = client.createAuthenticatedView("data",
"data");
+ RegionService regionService2 = client.createAuthenticatedView("dataRead",
"dataRead");
+
+ EventsCqListner listener1 =
createAndExecuteCQ(regionService1.getQueryService(), "cq1",
+ "select * from /region r where r.length<=2");
+ EventsCqListner listener2 =
createAndExecuteCQ(regionService2.getQueryService(), "cq2",
+ "select * from /region r where r.length>=2");
+
+ // put 4 data in the region
+ gfsh.executeAndAssertThat("put --region=region --key=1 --value=1");
+ gfsh.executeAndAssertThat("put --region=region --key=11 --value=11");
+ gfsh.executeAndAssertThat("put --region=region --key=111 --value=111");
+
+ await().untilAsserted(
+ () -> assertThat(listener1.getKeys())
+ .containsExactly("1", "11"));
+
+ // user1Service listener will eventually get these events
Review comment:
This comment is unclear in what it's referring to, as there's nothing
called "user1Service" in this test. Could it be reworded?
##########
File path:
geode-core/src/main/java/org/apache/geode/cache/client/internal/AuthenticateUserOp.java
##########
@@ -87,31 +101,13 @@ private AuthenticateUserOp() {
}
static class AuthenticateUserOpImpl extends AbstractOp {
-
+ private static final Logger logger = LogService.getLogger();
Review comment:
This logger is never used in this class and can probably be removed.
##########
File path:
geode-core/src/distributedTest/java/org/apache/geode/management/internal/security/MultiUserAuthenticationDUnitTest.java
##########
@@ -100,4 +112,65 @@ public void multiAuthenticatedView() throws Exception {
cache.close();
}
}
+
+ @Test
+ public void multiUserCQ() throws Exception {
Review comment:
Would it make sense to have additional test cases where both users don't
have the same/equivalent permissions?
##########
File path:
geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/CacheClientUpdater.java
##########
@@ -1763,6 +1767,18 @@ private void processMessages() {
}
}
+ private void handleAuthenticate(Message clientMessage) {
+ // if client is in multi-user mode, the CacheClientUpdator (at this point)
Review comment:
Typo here, should be "CacheClientUpdater"
##########
File path:
geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/OldClientSupportService.java
##########
@@ -18,13 +18,16 @@
import java.io.DataInput;
import java.io.DataOutput;
+import org.apache.geode.annotations.Immutable;
import org.apache.geode.internal.cache.CacheService;
import org.apache.geode.internal.serialization.KnownVersion;
/**
* Support for old GemFire clients
*/
public interface OldClientSupportService extends CacheService {
+ @Immutable
+ KnownVersion RE_AUTHENTICATION_START_VERSION = KnownVersion.GEODE_1_15_0;
Review comment:
Would it make more sense to keep this constant in the
`ClientReAuthenticateMessage` class or some other class specifically related to
re-authentication?
##########
File path:
geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/ClientReAuthenticateMessage.java
##########
@@ -0,0 +1,104 @@
+/*
+ * 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.cache.tier.sockets;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+import org.apache.geode.internal.cache.EventID;
+import org.apache.geode.internal.cache.tier.MessageType;
+import org.apache.geode.internal.serialization.DeserializationContext;
+import org.apache.geode.internal.serialization.KnownVersion;
+import org.apache.geode.internal.serialization.SerializationContext;
+
+public class ClientReAuthenticateMessage implements ClientMessage {
+
+ /**
+ * This {@code ClientMessage}'s {@code EventID}
+ */
+ private final EventID eventId;
+
+ public ClientReAuthenticateMessage() {
+ this(new EventID());
+ }
+
+ public ClientReAuthenticateMessage(EventID eventId) {
+ this.eventId = eventId;
+ }
+
+ @Override
+ public Message getMessage(CacheClientProxy proxy, boolean notify) throws
IOException {
Review comment:
`IOException` is never thrown from this method.
##########
File path:
geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/command/PutUserCredentials.java
##########
@@ -39,45 +39,44 @@ public void cmdExecute(final Message clientMessage, final
ServerConnection serve
throws IOException, ClassNotFoundException, InterruptedException {
boolean isSecureMode = clientMessage.isSecureMode();
- // if (!isSecureMode)
- // client has not send secuirty header, need to send exception and log
this in security (file)
-
- if (isSecureMode) {
-
- int numberOfParts = clientMessage.getNumberOfParts();
+ if (!isSecureMode) {
+ // client has not send secuirty header, need to send exception and log
this in security (file)
+ return;
+ }
- if (numberOfParts == 1) {
- // need to get credentials
- try {
- serverConnection.setAsTrue(REQUIRES_RESPONSE);
- byte[] uniqueId = serverConnection.setCredentials(clientMessage);
- writeResponse(uniqueId, null, clientMessage, false,
serverConnection);
- } catch (GemFireSecurityException gfse) {
- if (serverConnection.getSecurityLogWriter().warningEnabled()) {
- serverConnection.getSecurityLogWriter().warning(String.format("%s",
- serverConnection.getName() + ": Security exception: " +
gfse.toString()
- + (gfse.getCause() != null ? ", caused by: " +
gfse.getCause().toString()
- : "")));
- }
- writeException(clientMessage, gfse, false, serverConnection);
- } catch (Exception ex) {
- if (serverConnection.getLogWriter().warningEnabled()) {
- serverConnection.getLogWriter().warning(
- String.format("An exception was thrown for client [%s]. %s",
- serverConnection.getProxyID(), ""),
- ex);
- }
- writeException(clientMessage, ex, false, serverConnection);
- } finally {
- serverConnection.setAsTrue(RESPONDED);
- }
+ int numberOfParts = clientMessage.getNumberOfParts();
+ if (numberOfParts != 1) {
+ // need to throw exception
Review comment:
This comment makes it seem that an exception should be thrown.
##########
File path:
geode-core/src/main/java/org/apache/geode/cache/client/internal/AbstractOp.java
##########
@@ -166,6 +166,8 @@ protected void processSecureBytes(Connection cnx, Message
message) throws Except
}
/**
+ * return true if this operation needs to be authenticated first
Review comment:
Could this be moved to a `@return` statement in the javadoc to make it
more visible?
##########
File path:
geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/CacheClientUpdater.java
##########
@@ -1763,6 +1767,18 @@ private void processMessages() {
}
}
+ private void handleAuthenticate(Message clientMessage) {
Review comment:
The `clientMessage` is never used in this method, so can probably be
removed from the signature.
##########
File path:
geode-core/src/main/java/org/apache/geode/cache/client/internal/AuthenticateUserOp.java
##########
@@ -123,67 +119,89 @@ private AuthenticateUserOp() {
super(MessageType.USER_CREDENTIAL_MESSAGE, 1);
securityProperties = securityProps;
needsServerLocation = needsServer;
-
getMessage().setMessageHasSecurePartFlag();
}
@Override
- protected void sendMessage(Connection cnx) throws Exception {
- HeapDataOutputStream hdos = new
HeapDataOutputStream(KnownVersion.CURRENT);
- byte[] secureBytes;
- hdos.writeLong(cnx.getConnectionID());
- if (securityProperties != null) {
- DistributedMember server = new
InternalDistributedMember(cnx.getSocket().getInetAddress(),
- cnx.getSocket().getPort(), false);
- DistributedSystem sys =
InternalDistributedSystem.getConnectedInstance();
- String authInitMethod =
sys.getProperties().getProperty(SECURITY_CLIENT_AUTH_INIT);
-
- Properties credentials = Handshake.getCredentials(authInitMethod,
securityProperties,
- server, false, sys.getLogWriter(), sys.getSecurityLogWriter());
- byte[] credentialBytes;
- try (HeapDataOutputStream heapdos = new
HeapDataOutputStream(KnownVersion.CURRENT)) {
- DataSerializer.writeProperties(credentials, heapdos);
- credentialBytes = ((ConnectionImpl)
cnx).encryptBytes(heapdos.toByteArray());
- }
- getMessage().addBytesPart(credentialBytes);
+ protected void sendMessage(Connection connection) throws Exception {
+ if (securityProperties == null) {
+ securityProperties = getConnectedSystem().getSecurityProperties();
}
- try {
- secureBytes = ((ConnectionImpl) cnx).encryptBytes(hdos.toByteArray());
- } finally {
- hdos.close();
+ byte[] credentialBytes = getCredentialBytes(connection,
securityProperties);
+ getMessage().addBytesPart(credentialBytes);
+
+ try (HeapDataOutputStream hdos = new HeapDataOutputStream(16,
KnownVersion.CURRENT)) {
+ hdos.writeLong(connection.getConnectionID());
+ hdos.writeLong(getUserId(connection));
+ getMessage().setSecurePart(((ConnectionImpl)
connection).encryptBytes(hdos.toByteArray()));
}
- getMessage().setSecurePart(secureBytes);
getMessage().send(false);
}
+ protected long getUserId(Connection connection) {
+ // single user mode
+ if (UserAttributes.userAttributes.get() == null) {
+ return connection.getServer().getUserId();
+ }
+ // multi user mode
+ Long id =
UserAttributes.userAttributes.get().getServerToId().get(connection.getServer());
+ if (id == null) {
+ return -1L;
+ }
+ return id;
+ }
+
+ protected InternalDistributedSystem getConnectedSystem() {
+ return InternalDistributedSystem.getConnectedInstance();
+ }
+
+ protected byte[] getCredentialBytes(Connection connection, Properties
securityProperties)
+ throws Exception {
+ InternalDistributedSystem system = getConnectedSystem();
Review comment:
Could this variable be renamed to prevent confusion between the internal
distributed system and `java.lang.System`, which also has a `getProperties()`
method?
##########
File path:
geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/ServerConnection.java
##########
@@ -894,6 +876,50 @@ void doNormalMessage() {
}
}
+ ThreadState bindSubject(Command command) {
+ if (!securityService.isIntegratedSecurity()) {
+ return null;
+ }
+
+ if (communicationMode.isWAN()) {
+ return null;
+ }
+
+ if (command instanceof PutUserCredentials) {
+ return null;
+ }
+
+ if (isInternalMessage(requestMessage,
allowInternalMessagesWithoutCredentials)) {
+ return null;
+ }
+
+ long uniqueId = getUniqueId();
+ String messageType =
MessageType.getString(requestMessage.getMessageType());
+ if (uniqueId == 0 || uniqueId == -1) {
+ logger.debug("No unique ID yet. {}, {}", messageType, getName());
Review comment:
Should this (and the other `logger.debug()` call below) be wrapped with
`if (LogService.isDebugEnabled())`?
##########
File path:
geode-core/src/main/java/org/apache/geode/internal/cache/tier/sockets/MessageDispatcher.java
##########
@@ -609,7 +707,18 @@ protected boolean dispatchMessage(ClientMessage
clientMessage) throws IOExceptio
return isDispatched;
}
- private void sendMessage(Message message) throws IOException {
+ @NotNull
+ private ResourcePermission getResourcePermission(ClientUpdateMessage
message) {
+ String regionName = message.getRegionName();
+ Object key = message.getKeyOfInterest();
+ ResourcePermission permission = new
ResourcePermission(ResourcePermission.Resource.DATA,
+ ResourcePermission.Operation.READ,
+ regionName, key == null ? null : key.toString());
+ return permission;
Review comment:
This can be simplified to just
```
return new ResourcePermission(ResourcePermission.Resource.DATA,
ResourcePermission.Operation.READ, regionName, key == null ? null :
key.toString());
```
##########
File path:
geode-core/src/distributedTest/java/org/apache/geode/management/internal/security/MultiUserAuthenticationDUnitTest.java
##########
@@ -100,4 +112,65 @@ public void multiAuthenticatedView() throws Exception {
cache.close();
}
}
+
+ @Test
+ public void multiUserCQ() throws Exception {
+ int locatorPort = locator.getPort();
+ ClientCache cache = client.withCacheSetup(f ->
f.setPoolSubscriptionEnabled(true)
+ .setPoolMultiuserAuthentication(true)
+ .addPoolLocator("localhost", locatorPort))
+ .createCache();
+
+ // both are able to read data
+ RegionService regionService1 = client.createAuthenticatedView("data",
"data");
+ RegionService regionService2 = client.createAuthenticatedView("dataRead",
"dataRead");
+
+ EventsCqListner listener1 =
createAndExecuteCQ(regionService1.getQueryService(), "cq1",
+ "select * from /region r where r.length<=2");
+ EventsCqListner listener2 =
createAndExecuteCQ(regionService2.getQueryService(), "cq2",
+ "select * from /region r where r.length>=2");
+
+ // put 4 data in the region
+ gfsh.executeAndAssertThat("put --region=region --key=1 --value=1");
+ gfsh.executeAndAssertThat("put --region=region --key=11 --value=11");
+ gfsh.executeAndAssertThat("put --region=region --key=111 --value=111");
+
+ await().untilAsserted(
+ () -> assertThat(listener1.getKeys())
+ .containsExactly("1", "11"));
+
+ // user1Service listener will eventually get these events
+ await().untilAsserted(
+ () -> assertThat(listener2.getKeys())
+ .containsExactly("11", "111"));
+
+ }
+
+ private static EventsCqListner createAndExecuteCQ(QueryService queryService,
String cqName,
+ String query)
+ throws CqExistsException, CqException, RegionNotFoundException {
+ CqAttributesFactory cqaf = new CqAttributesFactory();
+ EventsCqListner listenter = new EventsCqListner();
Review comment:
Typo in this variable name, it should be `listener`.
##########
File path:
geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/CacheClientProxyTest.java
##########
@@ -0,0 +1,123 @@
+/*
+ *
+ * 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.cache.tier.sockets;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.net.InetAddress;
+import java.net.Socket;
+
+import org.apache.shiro.subject.Subject;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.geode.StatisticsFactory;
+import org.apache.geode.internal.cache.Conflatable;
+import org.apache.geode.internal.cache.InternalCache;
+import
org.apache.geode.internal.cache.tier.sockets.CacheClientProxy.CacheClientProxyStatsFactory;
+import
org.apache.geode.internal.cache.tier.sockets.CacheClientProxy.MessageDispatcherFactory;
+import org.apache.geode.internal.security.SecurityService;
+import org.apache.geode.internal.serialization.KnownVersion;
+import org.apache.geode.internal.statistics.StatisticsClock;
+
+public class CacheClientProxyTest {
+ private CacheClientProxy proxy;
+ private CacheClientNotifier notifier;
+ private Socket socket;
+ private ClientProxyMembershipID id;
+ private KnownVersion version;
+ private SecurityService securityService;
+ private Subject subject;
+ private StatisticsClock clock;
+ private InternalCache cache;
+ private StatisticsFactory statsFactory;
+ private CacheClientProxyStatsFactory proxyStatsFactory;
+ private MessageDispatcherFactory dispatcherFactory;
+ private InetAddress inetAddress;
+ private CacheServerStats stats;
Review comment:
These fields can be converted to local variables in `before()`.
##########
File path:
geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/MessageDispatcherTest.java
##########
@@ -0,0 +1,167 @@
+/*
+ *
+ * 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.cache.tier.sockets;
+
+import static
org.apache.geode.internal.lang.SystemPropertyHelper.RE_AUTHENTICATE_WAIT_TIME;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.apache.shiro.subject.Subject;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.geode.CancelCriterion;
+import org.apache.geode.internal.cache.EventID;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.internal.cache.ha.HARegionQueue;
+import org.apache.geode.internal.cache.ha.HARegionQueueStats;
+import
org.apache.geode.internal.cache.tier.sockets.ClientUpdateMessageImpl.CqNameToOp;
+import org.apache.geode.internal.security.SecurityService;
+import org.apache.geode.internal.serialization.KnownVersion;
+import org.apache.geode.security.AuthenticationExpiredException;
+import org.apache.geode.security.ResourcePermission;
+
+public class MessageDispatcherTest {
+ private MessageDispatcher dispatcher;
+ private CacheClientProxy proxy;
+ private ClientUpdateMessage message;
+ private InternalCache cache;
+ private SecurityService securityService;
+ private Subject subject;
+ private CacheClientNotifier notifier;
+ private ClientProxyMembershipID proxyId;
+ private HARegionQueue messageQueue;
+ private HARegionQueueStats queueStats;
+ private CancelCriterion cancelCriterion;
+ private CacheClientProxyStats proxyStats;
Review comment:
`cache`, `notifier`, `proxyId`, `queueStats`, `cancelCriterion` and
`proxyStats` can all be converted to local variables in the `before()` method.
##########
File path:
geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/MessageDispatcherTest.java
##########
@@ -0,0 +1,167 @@
+/*
+ *
+ * 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.cache.tier.sockets;
+
+import static
org.apache.geode.internal.lang.SystemPropertyHelper.RE_AUTHENTICATE_WAIT_TIME;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.apache.shiro.subject.Subject;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.geode.CancelCriterion;
+import org.apache.geode.internal.cache.EventID;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.internal.cache.ha.HARegionQueue;
+import org.apache.geode.internal.cache.ha.HARegionQueueStats;
+import
org.apache.geode.internal.cache.tier.sockets.ClientUpdateMessageImpl.CqNameToOp;
+import org.apache.geode.internal.security.SecurityService;
+import org.apache.geode.internal.serialization.KnownVersion;
+import org.apache.geode.security.AuthenticationExpiredException;
+import org.apache.geode.security.ResourcePermission;
+
+public class MessageDispatcherTest {
+ private MessageDispatcher dispatcher;
+ private CacheClientProxy proxy;
+ private ClientUpdateMessage message;
+ private InternalCache cache;
+ private SecurityService securityService;
+ private Subject subject;
+ private CacheClientNotifier notifier;
+ private ClientProxyMembershipID proxyId;
+ private HARegionQueue messageQueue;
+ private HARegionQueueStats queueStats;
+ private CancelCriterion cancelCriterion;
+ private CacheClientProxyStats proxyStats;
+ private EventID eventID;
+
+ @Before
+ public void before() throws Exception {
+ proxy = mock(CacheClientProxy.class);
+ message = mock(ClientUpdateMessageImpl.class);
+ cache = mock(InternalCache.class);
+ subject = mock(Subject.class);
+ securityService = mock(SecurityService.class);
+ notifier = mock(CacheClientNotifier.class);
+ proxyId = mock(ClientProxyMembershipID.class);
+ messageQueue = mock(HARegionQueue.class);
+ queueStats = mock(HARegionQueueStats.class);
+ cancelCriterion = mock(CancelCriterion.class);
+ proxyStats = mock(CacheClientProxyStats.class);
+ eventID = mock(EventID.class);
+ when(messageQueue.getStatistics()).thenReturn(queueStats);
+ when(cache.getSecurityService()).thenReturn(securityService);
+ when(proxy.getCache()).thenReturn(cache);
+ when(cache.getCancelCriterion()).thenReturn(cancelCriterion);
+ when(proxy.getCacheClientNotifier()).thenReturn(notifier);
+ when(proxy.getProxyID()).thenReturn(proxyId);;
Review comment:
Extra semicolon here.
##########
File path:
geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/ServerConnectionTest.java
##########
@@ -124,4 +146,97 @@ public void nonSecureShouldThrow() {
.isExactlyInstanceOf(AuthenticationRequiredException.class)
.hasMessage("No security credentials are provided");
}
+
+ @Test
+ public void bindSubjectDoesNothingIfNotIntegratedService() throws Exception {
Review comment:
`Exception` is never thrown from any of the tests added in this class.
##########
File path:
geode-core/src/upgradeTest/java/org/apache/geode/security/AuthExpirationDUnitTest.java
##########
@@ -70,15 +84,70 @@
.withSecurityManager(ExpirableSecurityManager.class)
.withRegion(RegionShortcut.REPLICATE, "region");
+
+ private ClientVM clientVM;
+
@Test
- public void
clientShouldReAuthenticateWhenCredentialExpiredAndOperationSucceed()
- throws Exception {
+ public void clientWithNoUserRefreshWillNotSucceed() throws Exception {
int serverPort = server.getPort();
ClientVM clientVM = lsRule.startClientVM(0, clientVersion,
c -> c.withProperty(SECURITY_CLIENT_AUTH_INIT,
UpdatableUserAuthInitialize.class.getName())
.withPoolSubscription(true)
.withServerConnection(serverPort));
+ clientVM.invoke(() -> {
+ UpdatableUserAuthInitialize.setUser("user1");
+ ClientCache clientCache = ClusterStartupRule.getClientCache();
+ ClientRegionFactory<Object, Object> clientRegionFactory =
+ clientCache.createClientRegionFactory(ClientRegionShortcut.PROXY);
+ Region<Object, Object> region = clientRegionFactory.create("region");
+ region.put(0, "value0");
+ });
+
+ // expire the current user
+ ExpirableSecurityManager securityManager = getSecurityManager();
+ securityManager.addExpiredUser("user1");
+
+ // if client, even after getting AuthExpiredExpiration, still sends in
+ // old credentials, the operation will fail (we only try re-authenticate
once)
+ // this test makes sure no lingering old credentials will allow the
operations to succeed.
+ clientVM.invoke(() -> {
+ ClientCache clientCache = ClusterStartupRule.getClientCache();
+ Region<Object, Object> region = clientCache.getRegion("region");
+ doPutAndExpectFailure(region, 100);
+ });
+
+ Region<Object, Object> region = server.getCache().getRegion("/region");
+ assertThat(region.size()).isEqualTo(1);
+ Map<String, List<String>> authorizedOps =
securityManager.getAuthorizedOps();
+ Map<String, List<String>> unAuthorizedOps =
securityManager.getUnAuthorizedOps();
+ assertThat(authorizedOps.keySet().size()).isEqualTo(1);
+
assertThat(authorizedOps.get("user1")).asList().containsExactly("DATA:WRITE:region:0");
+ assertThat(unAuthorizedOps.keySet().size()).isEqualTo(1);
+ }
+
+ private static void doPutAndExpectFailure(Region<Object, Object> region, int
times) {
+ for (int i = 1; i < times; i++) {
+ try {
+ region.put(1, "value1");
+ fail("Exception expected");
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(ServerOperationException.class);
+
assertThat(e.getCause()).isInstanceOfAny(AuthenticationFailedException.class,
+ AuthenticationRequiredException.class);
+ }
Review comment:
This can be simplified to:
```
assertThatThrownBy(() -> region.put(1, "value1"))
.isInstanceOf(ServerOperationException.class)
.getCause().isInstanceOfAny(AuthenticationFailedException.class,
AuthenticationRequiredException.class);
```
##########
File path:
geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/ServerConnectionTest.java
##########
@@ -57,25 +67,37 @@
private AcceptorImpl acceptor;
private Message requestMessage;
private ServerSideHandshake handshake;
+ private SecurityService securityService;
private ServerConnection serverConnection;
+ private Command command;
+ private InetAddress inetAddress;
+ private Socket socket;
+ private InternalCacheForClientAccess cache;
+ private CachedRegionHelper cachedRegionHelper;
+ private InternalDistributedSystem internalDistributedSystem;
+ private DistributionManager distributionManager;
+ private ThreadsMonitoring threadsMonitoring;
Review comment:
`inetAddress`, `internalDistributedSystem`, `distributionManager` and
`threadsMonitoring` can all be converted to local variables in `setUp()`.
##########
File path:
geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/ClientUserAuthsTest.java
##########
@@ -0,0 +1,84 @@
+/*
+ *
+ * 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.cache.tier.sockets;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.apache.shiro.subject.Subject;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ClientUserAuthsTest {
+ private ClientUserAuths auth;
+ private Subject subject1;
+ private Subject subject2;
+
+ @Before
+ public void before() throws Exception {
+ subject1 = mock(Subject.class);
+ subject2 = mock(Subject.class);
+ when(subject1.getPrincipal()).thenReturn("user1");
+ when(subject2.getPrincipal()).thenReturn("user2");
+ auth = spy(new ClientUserAuths(0));
+ doReturn(123L).when(auth).getNextID();
+ }
+
+ @Test
+ public void putSubjectWithNegativeOneWillProduceNewId() throws Exception {
Review comment:
`Exception` is never thrown from any of the test methods in this class.
##########
File path:
geode-core/src/upgradeTest/java/org/apache/geode/security/AuthExpirationDUnitTest.java
##########
@@ -56,7 +70,7 @@
@Parameterized.Parameters(name = "{0}")
public static Collection<String> data() {
// only test the current version and the latest released version
Review comment:
This comment is inaccurate, as once we're on version 1.16.0, this test
will use versions 1.14.0, 1.15.0 and 1.16.0. A more accurate comment would be
"only test versions greater than or equal to 1.14.0"
--
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: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]