From 0b2beeaad590bdc50454bed3431f19d3473fbe2e Mon Sep 17 00:00:00 2001 From: JinwooHwang Date: Thu, 12 Mar 2026 08:48:02 -0400 Subject: [PATCH] Revert "Testcases for Server-Only TLS with Application-Layer Authentication (#7987)" This reverts commit 4e93d2c48296c01cc45e15ca328fd78ead8d9d41. --- .../P2PServerOnlyTLSWithAuthDUnitTest.java | 382 ------------- .../ssl/ServerOnlyTLSWithAuthDUnitTest.java | 513 ------------------ .../ServerOnlyTLSWithAuthNegativeTest.java | 481 ---------------- .../security/templates/TokenAuthInit.java | 68 --- .../junit/rules/ServerOnlyTLSTestFixture.java | 253 --------- 5 files changed, 1697 deletions(-) delete mode 100644 geode-core/src/distributedTest/java/org/apache/geode/cache/ssl/P2PServerOnlyTLSWithAuthDUnitTest.java delete mode 100644 geode-core/src/distributedTest/java/org/apache/geode/cache/ssl/ServerOnlyTLSWithAuthDUnitTest.java delete mode 100644 geode-core/src/distributedTest/java/org/apache/geode/cache/ssl/ServerOnlyTLSWithAuthNegativeTest.java delete mode 100644 geode-junit/src/main/java/org/apache/geode/security/templates/TokenAuthInit.java delete mode 100644 geode-junit/src/main/java/org/apache/geode/test/junit/rules/ServerOnlyTLSTestFixture.java diff --git a/geode-core/src/distributedTest/java/org/apache/geode/cache/ssl/P2PServerOnlyTLSWithAuthDUnitTest.java b/geode-core/src/distributedTest/java/org/apache/geode/cache/ssl/P2PServerOnlyTLSWithAuthDUnitTest.java deleted file mode 100644 index 0424c6bd7998..000000000000 --- a/geode-core/src/distributedTest/java/org/apache/geode/cache/ssl/P2PServerOnlyTLSWithAuthDUnitTest.java +++ /dev/null @@ -1,382 +0,0 @@ -/* - * 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.cache.ssl; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.util.Properties; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import org.apache.geode.cache.RegionShortcut; -import org.apache.geode.security.GemFireSecurityException; -import org.apache.geode.test.dunit.IgnoredException; -import org.apache.geode.test.dunit.rules.ClusterStartupRule; -import org.apache.geode.test.dunit.rules.MemberVM; -import org.apache.geode.test.junit.categories.SecurityTest; -import org.apache.geode.test.junit.rules.ServerOnlyTLSTestFixture; - -/** - * Distributed tests for Peer-to-Peer (P2P) Cache Topology using Server-only TLS with - * Application-Layer Authentication (Approach 3). - * - *

- * This test demonstrates that in a P2P cache configuration (where all members are peers, no - * client/server distinction), Approach 3 works correctly: - *

- * - *

- * Key Difference from Client/Server: In P2P topology, all members are equal peers - * that communicate directly. Each peer presents a server certificate for TLS encryption, but - * authentication happens at the application layer using credentials validated by SecurityManager. - * - *

- * This approach solves the public CA clientAuth EKU sunset problem for P2P topologies by: - *

    - *
  1. Eliminating the need for client certificates entirely
  2. - *
  3. Maintaining full TLS encryption for all transport
  4. - *
  5. Using existing authentication infrastructure (LDAP, database, tokens)
  6. - *
- * - * @see ServerOnlyTLSWithAuthDUnitTest for client/server topology tests - */ -@Category({SecurityTest.class}) -public class P2PServerOnlyTLSWithAuthDUnitTest { - - private static final String REGION_NAME = "testRegion"; - - @Rule - public ClusterStartupRule cluster = new ClusterStartupRule(); - - private ServerOnlyTLSTestFixture fixture; - - @Before - public void setUp() throws Exception { - fixture = new ServerOnlyTLSTestFixture(); - - // Add ignored exceptions for SSL-related cleanup warnings - IgnoredException.addIgnoredException("javax.net.ssl.SSLException"); - IgnoredException.addIgnoredException("java.io.IOException"); - IgnoredException.addIgnoredException("Authentication failed"); - IgnoredException.addIgnoredException("Security check failed"); - } - - /** - * Test basic P2P cluster formation with server-only TLS and application-layer authentication. - * - *

- * Verifies: - *

- */ - @Test - public void testP2PClusterFormationWithServerOnlyTLSAndAppAuth() throws Exception { - // Create certificate stores using fixture - // All peers use the same certificate for TLS (server cert) - CertStores clusterStores = fixture.createClusterStores(); - - // Configure locator with: - // - Server-only TLS (ssl-require-authentication=false) - // - Security manager for application-layer authentication - // - Peer authentication credentials - Properties locatorProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(locatorProps); - fixture.addPeerAuthProperties(locatorProps, "cluster", "cluster"); - - // Start locator - it will authenticate itself when joining - MemberVM locator = cluster.startLocatorVM(0, locatorProps); - int locatorPort = locator.getPort(); - - // Configure first server with same setup - Properties server1Props = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(server1Props); - fixture.addPeerAuthProperties(server1Props, "cluster", "cluster"); - - // Start first server - it joins via application-layer auth, not certificate auth - MemberVM server1 = cluster.startServerVM(1, server1Props, locatorPort); - - // Verify server1 successfully joined the cluster - server1.invoke(() -> { - assertThat(ClusterStartupRule.getCache()).isNotNull(); - assertThat(ClusterStartupRule.getCache().getDistributedSystem().getAllOtherMembers()) - .hasSize(1); // locator - }); - - // Configure second server with same setup - Properties server2Props = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(server2Props); - fixture.addPeerAuthProperties(server2Props, "cluster", "cluster"); - - // Start second server - MemberVM server2 = cluster.startServerVM(2, server2Props, locatorPort); - - // Verify server2 successfully joined and sees all peers - server2.invoke(() -> { - assertThat(ClusterStartupRule.getCache()).isNotNull(); - assertThat(ClusterStartupRule.getCache().getDistributedSystem().getAllOtherMembers()) - .hasSize(2); // locator + server1 - }); - - // Verify all peers see each other (peer-to-peer mesh formed) - server1.invoke(() -> { - assertThat(ClusterStartupRule.getCache().getDistributedSystem().getAllOtherMembers()) - .hasSize(2); // locator + server2 - }); - } - - /** - * Test P2P data replication across encrypted peer connections without certificate authentication. - * - *

- * Verifies: - *

- */ - @Test - public void testP2PDataReplicationOverServerOnlyTLS() throws Exception { - CertStores clusterStores = fixture.createClusterStores(); - - // Configure and start locator - Properties locatorProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(locatorProps); - fixture.addPeerAuthProperties(locatorProps, "cluster", "cluster"); - MemberVM locator = cluster.startLocatorVM(0, locatorProps); - int locatorPort = locator.getPort(); - - // Start server1 with replicated region - Properties server1Props = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(server1Props); - fixture.addPeerAuthProperties(server1Props, "cluster", "cluster"); - MemberVM server1 = cluster.startServerVM(1, server1Props, locatorPort); - - server1.invoke(() -> { - ClusterStartupRule.getCache() - .createRegionFactory(RegionShortcut.REPLICATE) - .create(REGION_NAME); - }); - - // Start server2 with same replicated region - Properties server2Props = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(server2Props); - fixture.addPeerAuthProperties(server2Props, "cluster", "cluster"); - MemberVM server2 = cluster.startServerVM(2, server2Props, locatorPort); - - server2.invoke(() -> { - ClusterStartupRule.getCache() - .createRegionFactory(RegionShortcut.REPLICATE) - .create(REGION_NAME); - }); - - // Put data on server1 - server1.invoke(() -> { - ClusterStartupRule.getCache() - .getRegion(REGION_NAME) - .put("key1", "value1"); - }); - - // Verify data replicated to server2 over TLS-encrypted peer connection - server2.invoke(() -> { - Object value = ClusterStartupRule.getCache() - .getRegion(REGION_NAME) - .get("key1"); - assertThat(value).isEqualTo("value1"); - }); - - // Put data on server2 - server2.invoke(() -> { - ClusterStartupRule.getCache() - .getRegion(REGION_NAME) - .put("key2", "value2"); - }); - - // Verify data replicated to server1 - server1.invoke(() -> { - Object value = ClusterStartupRule.getCache() - .getRegion(REGION_NAME) - .get("key2"); - assertThat(value).isEqualTo("value2"); - }); - } - - /** - * Test that peer with invalid credentials cannot join P2P cluster. - * - *

- * Verifies: - *

- */ - @Test - public void testP2PPeerRejectedWithInvalidCredentials() throws Exception { - // Add ignored exception for authentication failure messages - IgnoredException.addIgnoredException("Authentication FAILED"); - CertStores clusterStores = fixture.createClusterStores(); - - // Configure and start locator - Properties locatorProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(locatorProps); - fixture.addPeerAuthProperties(locatorProps, "cluster", "cluster"); - MemberVM locator = cluster.startLocatorVM(0, locatorProps); - int locatorPort = locator.getPort(); - - // Try to start server with INVALID credentials - Properties serverProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(serverProps); - fixture.addPeerAuthProperties(serverProps, "cluster", "wrongPassword"); // INVALID - - // Server should fail to join due to authentication failure - // Note: Root cause is SecurityException, not GemFireSecurityException - assertThatThrownBy(() -> cluster.startServerVM(1, serverProps, locatorPort)) - .hasRootCauseInstanceOf(SecurityException.class) - .hasStackTraceContaining("invalid username/password"); - } - - /** - * Test that peer without CLUSTER:MANAGE permission cannot join P2P cluster. - * - *

- * Verifies: - *

- */ - @Test - public void testP2PPeerRejectedWithoutClusterManagePermission() throws Exception { - CertStores clusterStores = fixture.createClusterStores(); - - // Configure and start locator - Properties locatorProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(locatorProps); - fixture.addPeerAuthProperties(locatorProps, "cluster", "cluster"); - MemberVM locator = cluster.startLocatorVM(0, locatorProps); - int locatorPort = locator.getPort(); - - // Try to start server with user that has valid credentials but no CLUSTER:MANAGE - // SimpleSecurityManager allows authentication when username == password - // but "data" user does NOT have CLUSTER:MANAGE permission - Properties serverProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(serverProps); - fixture.addPeerAuthProperties(serverProps, "data", "data"); // Valid creds, insufficient perms - - // Server should fail to join due to authorization failure - // Note: Root cause is SecurityException, not GemFireSecurityException - assertThatThrownBy(() -> cluster.startServerVM(1, serverProps, locatorPort)) - .hasRootCauseInstanceOf(SecurityException.class) - .hasStackTraceContaining("not authorized for CLUSTER:MANAGE"); - } - - /** - * Test that peer with no credentials cannot join P2P cluster. - * - *

- * Verifies: - *

- */ - @Test - public void testP2PPeerRejectedWithNoCredentials() throws Exception { - CertStores clusterStores = fixture.createClusterStores(); - - // Configure and start locator - Properties locatorProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(locatorProps); - fixture.addPeerAuthProperties(locatorProps, "cluster", "cluster"); - MemberVM locator = cluster.startLocatorVM(0, locatorProps); - int locatorPort = locator.getPort(); - - // Try to start server WITHOUT any authentication credentials - Properties serverProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(serverProps); - // NO peer auth properties added - missing credentials - - // Server should fail to join due to missing credentials - assertThatThrownBy(() -> cluster.startServerVM(1, serverProps, locatorPort)) - .hasRootCauseInstanceOf(GemFireSecurityException.class); - } - - /** - * Test multiple peers joining with different valid credentials. - * - *

- * Verifies that the cluster supports heterogeneous peer credentials as long as all have - * CLUSTER:MANAGE permission. This demonstrates flexibility in credential management where - * different services/teams can use different credentials. - */ - @Test - public void testMultiplePeersWithDifferentCredentials() throws Exception { - CertStores clusterStores = fixture.createClusterStores(); - - // Start locator with "cluster" credentials - Properties locatorProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(locatorProps); - fixture.addPeerAuthProperties(locatorProps, "cluster", "cluster"); - MemberVM locator = cluster.startLocatorVM(0, locatorProps); - int locatorPort = locator.getPort(); - - // Start server1 with "clusterManage" credentials - // SimpleSecurityManager grants CLUSTER:MANAGE to "cluster" and "clusterManage" users - Properties server1Props = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(server1Props); - fixture.addPeerAuthProperties(server1Props, "clusterManage", "clusterManage"); - MemberVM server1 = cluster.startServerVM(1, server1Props, locatorPort); - - // Start server2 with "cluster" credentials (same as locator) - Properties server2Props = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(server2Props); - fixture.addPeerAuthProperties(server2Props, "cluster", "cluster"); - MemberVM server2 = cluster.startServerVM(2, server2Props, locatorPort); - - // Verify all peers joined successfully - server1.invoke(() -> { - assertThat(ClusterStartupRule.getCache().getDistributedSystem().getAllOtherMembers()) - .hasSize(2); // locator + server2 - }); - - server2.invoke(() -> { - assertThat(ClusterStartupRule.getCache().getDistributedSystem().getAllOtherMembers()) - .hasSize(2); // locator + server1 - }); - } -} diff --git a/geode-core/src/distributedTest/java/org/apache/geode/cache/ssl/ServerOnlyTLSWithAuthDUnitTest.java b/geode-core/src/distributedTest/java/org/apache/geode/cache/ssl/ServerOnlyTLSWithAuthDUnitTest.java deleted file mode 100644 index 04305b0a0f32..000000000000 --- a/geode-core/src/distributedTest/java/org/apache/geode/cache/ssl/ServerOnlyTLSWithAuthDUnitTest.java +++ /dev/null @@ -1,513 +0,0 @@ -/* - * 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.cache.ssl; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import org.apache.geode.cache.Region; -import org.apache.geode.cache.RegionShortcut; -import org.apache.geode.cache.client.ClientCache; -import org.apache.geode.cache.client.ClientCacheFactory; -import org.apache.geode.cache.client.ClientRegionShortcut; -import org.apache.geode.examples.SimpleSecurityManager; -import org.apache.geode.test.dunit.IgnoredException; -import org.apache.geode.test.dunit.rules.ClientVM; -import org.apache.geode.test.dunit.rules.ClusterStartupRule; -import org.apache.geode.test.dunit.rules.MemberVM; -import org.apache.geode.test.junit.categories.SecurityTest; -import org.apache.geode.test.junit.rules.ServerOnlyTLSTestFixture; - -/** - * Distributed tests for Server-only TLS with Alternative Client Authentication. - * - *

- * These tests verify that: - *

- */ -@Category({SecurityTest.class}) -public class ServerOnlyTLSWithAuthDUnitTest { - - private static final String REGION_NAME = "testRegion"; - - @Rule - public ClusterStartupRule cluster = new ClusterStartupRule(); - - private ServerOnlyTLSTestFixture fixture; - - @Before - public void setUp() throws Exception { - fixture = new ServerOnlyTLSTestFixture(); - - // Add ignored exceptions for SSL-related cleanup warnings - IgnoredException.addIgnoredException("javax.net.ssl.SSLException"); - IgnoredException.addIgnoredException("java.io.IOException"); - } - - /** - * Test basic client connection with TLS transport encryption and username/password - * authentication. - * - *

- * Verifies: - *

- */ - @Test - public void testBasicConnectionWithUsernamePassword() throws Exception { - // Create certificates and stores using fixture - // Note: Use createClusterStores() for both locator and server peer SSL communication - CertStores clusterStores = fixture.createClusterStores(); - CertStores clientStores = fixture.createClientStores(); - - // Configure locator with server-only TLS (require-authentication=false) and security manager - Properties locatorProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(locatorProps); - fixture.addPeerAuthProperties(locatorProps, "cluster", "cluster"); - - // Start locator - MemberVM locator = cluster.startLocatorVM(0, locatorProps); - int locatorPort = locator.getPort(); - - // Configure server with server-only TLS and security manager - Properties serverProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(serverProps); - fixture.addPeerAuthProperties(serverProps, "cluster", "cluster"); - serverProps.setProperty("locators", "localhost[" + locatorPort + "]"); - - // Start server - MemberVM server = cluster.startServerVM(1, serverProps, locatorPort); - - // Create region on server - server.invoke(() -> { - ClusterStartupRule.getCache() - .createRegionFactory(RegionShortcut.REPLICATE) - .create(REGION_NAME); - }); - - // Configure client with server-only TLS (truststore only, no keystore) - Properties clientSSLProps = clientStores.propertiesWith("all", false, false); - - // Add authentication properties (username/password) - // SimpleSecurityManager accepts username when username == password - Properties clientAuthProps = fixture.createClientAuthProperties("data", "data"); - clientSSLProps.putAll(clientAuthProps); - - // Connect client - ClientVM client = cluster.startClientVM(2, c -> c - .withProperties(clientSSLProps) - .withLocatorConnection(locatorPort)); - - // Verify client can perform operations - client.invoke(() -> { - ClientCache clientCache = ClusterStartupRule.getClientCache(); - assertThat(clientCache).isNotNull(); - - Region region = clientCache - .createClientRegionFactory(ClientRegionShortcut.PROXY) - .create(REGION_NAME); - - // Perform basic operations - region.put("key1", "value1"); - Object value = region.get("key1"); - assertThat(value).isEqualTo("value1"); - }); - } - - /** - * Test multiple clients connecting with different credentials. - * - *

- * Verifies: - *

- */ - @Test - public void testMultipleClientsWithDifferentCredentials() throws Exception { - // Create certificates and stores - CertStores locatorStores = fixture.createLocatorStores(); - CertStores clusterStores = fixture.createClusterStores(); - CertStores client1Stores = fixture.createClientStores(); - CertStores client2Stores = fixture.createClientStores(); - CertStores client3Stores = fixture.createClientStores(); - - // Start locator - Properties locatorProps = locatorStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(locatorProps); - fixture.addPeerAuthProperties(locatorProps, "cluster", "cluster"); - MemberVM locator = cluster.startLocatorVM(0, locatorProps); - int locatorPort = locator.getPort(); - - // Start server - Properties serverProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(serverProps); - fixture.addPeerAuthProperties(serverProps, "cluster", "cluster"); - serverProps.setProperty("locators", "localhost[" + locatorPort + "]"); - MemberVM server = cluster.startServerVM(1, serverProps, locatorPort); - - // Create region - server.invoke(() -> { - ClusterStartupRule.getCache() - .createRegionFactory(RegionShortcut.REPLICATE) - .create(REGION_NAME); - }); - - // Connect client 1 with user "dataRead" - Properties client1Props = client1Stores.propertiesWith("all", false, false); - client1Props.putAll(fixture.createClientAuthProperties("data", "data")); - ClientVM client1 = cluster.startClientVM(2, c -> c - .withProperties(client1Props) - .withLocatorConnection(locatorPort)); - - // Connect client 2 with user "dataWrite" - Properties client2Props = client2Stores.propertiesWith("all", false, false); - client2Props.putAll(fixture.createClientAuthProperties("dataWrite", "dataWrite")); - ClientVM client2 = cluster.startClientVM(3, c -> c - .withProperties(client2Props) - .withLocatorConnection(locatorPort)); - - // Connect client 3 with user "dataManage" - Properties client3Props = client3Stores.propertiesWith("all", false, false); - client3Props.putAll(fixture.createClientAuthProperties("dataManage", "dataManage")); - ClientVM client3 = cluster.startClientVM(4, c -> c - .withProperties(client3Props) - .withLocatorConnection(locatorPort)); - - // Verify all clients can access region - for (ClientVM client : new ClientVM[] {client1, client2, client3}) { - client.invoke(() -> { - Region region = ClusterStartupRule.getClientCache() - .createClientRegionFactory(ClientRegionShortcut.PROXY) - .create(REGION_NAME); - assertThat(region).isNotNull(); - }); - } - } - - /** - * Test token-based authentication instead of username/password. - * - *

- * Verifies: - *

    - *
  • Clients can authenticate using bearer tokens
  • - *
  • Token authentication works with TLS transport
  • - *
  • No client certificates are required
  • - *
- */ - @Test - public void testTokenBasedAuthentication() throws Exception { - // Create certificates and stores - // Note: Locator and server must use same CertStores for peer SSL communication - CertStores clusterStores = fixture.createClusterStores(); - CertStores clientStores = fixture.createClientStores(); - - // Start locator - Properties locatorProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(locatorProps); - fixture.addPeerAuthProperties(locatorProps, "cluster", "cluster"); - MemberVM locator = cluster.startLocatorVM(0, locatorProps); - int locatorPort = locator.getPort(); - - // Start server - Properties serverProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(serverProps); - fixture.addPeerAuthProperties(serverProps, "cluster", "cluster"); - serverProps.setProperty("locators", "localhost[" + locatorPort + "]"); - MemberVM server = cluster.startServerVM(1, serverProps, locatorPort); - - // Create region - server.invoke(() -> { - ClusterStartupRule.getCache() - .createRegionFactory(RegionShortcut.REPLICATE) - .create(REGION_NAME); - }); - - // Configure client with token authentication - Properties clientProps = clientStores.propertiesWith("all", false, false); - Properties tokenAuthProps = fixture.createClientTokenAuthProperties( - SimpleSecurityManager.VALID_TOKEN); - clientProps.putAll(tokenAuthProps); - - // Connect client - ClientVM client = cluster.startClientVM(2, c -> c - .withProperties(clientProps) - .withLocatorConnection(locatorPort)); - - // Verify client can perform operations - client.invoke(() -> { - Region region = ClusterStartupRule.getClientCache() - .createClientRegionFactory(ClientRegionShortcut.PROXY) - .create(REGION_NAME); - - region.put("tokenKey", "tokenValue"); - assertThat(region.get("tokenKey")).isEqualTo("tokenValue"); - }); - } - - /** - * Test server restart with client reconnection. - * - *

- * Verifies: - *

    - *
  • Client can reconnect after server restart
  • - *
  • TLS session is re-established
  • - *
  • Client re-authenticates successfully
  • - *
- */ - @Test - public void testServerRestartWithClientReconnection() throws Exception { - // Create certificates and stores - // Note: Locator and server must use same CertStores for peer SSL communication - CertStores clusterStores = fixture.createClusterStores(); - CertStores clientStores = fixture.createClientStores(); - - // Start locator - Properties locatorProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(locatorProps); - fixture.addPeerAuthProperties(locatorProps, "cluster", "cluster"); - MemberVM locator = cluster.startLocatorVM(0, locatorProps); - int locatorPort = locator.getPort(); - - // Start server - Properties serverProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(serverProps); - fixture.addPeerAuthProperties(serverProps, "cluster", "cluster"); - serverProps.setProperty("locators", "localhost[" + locatorPort + "]"); - MemberVM server = cluster.startServerVM(1, serverProps, locatorPort); - - // Create region - server.invoke(() -> { - ClusterStartupRule.getCache() - .createRegionFactory(RegionShortcut.REPLICATE) - .create(REGION_NAME); - }); - - // Connect client - Properties clientProps = clientStores.propertiesWith("all", false, false); - clientProps.putAll(fixture.createClientAuthProperties("data", "data")); - ClientVM client = cluster.startClientVM(2, c -> c - .withProperties(clientProps) - .withLocatorConnection(locatorPort)); - - // Verify initial connection - client.invoke(() -> { - Region region = ClusterStartupRule.getClientCache() - .createClientRegionFactory(ClientRegionShortcut.PROXY) - .create(REGION_NAME); - region.put("beforeRestart", "value1"); - }); - - // Stop and restart server - cluster.stop(1); - server = cluster.startServerVM(1, serverProps, locatorPort); - - // Recreate region on restarted server - server.invoke(() -> { - ClusterStartupRule.getCache() - .createRegionFactory(RegionShortcut.REPLICATE) - .create(REGION_NAME); - }); - - // Verify client can reconnect and operate - client.invoke(() -> { - Region region = ClusterStartupRule.getClientCache().getRegion(REGION_NAME); - region.put("afterRestart", "value2"); - assertThat(region.get("afterRestart")).isEqualTo("value2"); - }); - } - - /** - * Test concurrent client operations over TLS. - * - *

- * Verifies: - *

    - *
  • Multiple threads can perform concurrent operations over TLS
  • - *
  • TLS connection handles concurrent load
  • - *
  • Authentication works with concurrent operations
  • - *
- */ - @Test - public void testConcurrentClientConnections() throws Exception { - // Create certificates and stores - // Note: Use createClusterStores() for both locator and server peer SSL communication - CertStores clusterStores = fixture.createClusterStores(); - CertStores clientStores = fixture.createClientStores(); - - // Start locator - Properties locatorProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(locatorProps); - fixture.addPeerAuthProperties(locatorProps, "cluster", "cluster"); - MemberVM locator = cluster.startLocatorVM(0, locatorProps); - int locatorPort = locator.getPort(); - - // Start server - Properties serverProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(serverProps); - fixture.addPeerAuthProperties(serverProps, "cluster", "cluster"); - serverProps.setProperty("locators", "localhost[" + locatorPort + "]"); - MemberVM server = cluster.startServerVM(1, serverProps, locatorPort); - - // Create region - server.invoke(() -> { - ClusterStartupRule.getCache() - .createRegionFactory(RegionShortcut.REPLICATE) - .create(REGION_NAME); - }); - - // Create single client cache with TLS - Properties clientProps = clientStores.propertiesWith("all", false, false); - clientProps.putAll(fixture.createClientAuthProperties("data", "data")); - - ClientCacheFactory factory = new ClientCacheFactory(clientProps) - .addPoolLocator("localhost", locatorPort) - .setPoolSubscriptionEnabled(true); - - try (ClientCache clientCache = factory.create()) { - Region region = clientCache - .createClientRegionFactory(ClientRegionShortcut.PROXY) - .create(REGION_NAME); - - // Perform concurrent operations from multiple threads - int numThreads = 10; - ExecutorService executor = Executors.newFixedThreadPool(numThreads); - CountDownLatch startLatch = new CountDownLatch(1); - CountDownLatch completionLatch = new CountDownLatch(numThreads); - List> futures = new ArrayList<>(); - - for (int i = 0; i < numThreads; i++) { - final int operationId = i; - Future future = executor.submit(() -> { - try { - // Wait for all threads to be ready - startLatch.await(); - - // Perform operation - region.put("key" + operationId, "value" + operationId); - assertThat(region.get("key" + operationId)).isEqualTo("value" + operationId); - - completionLatch.countDown(); - } catch (Exception e) { - throw new RuntimeException("Operation " + operationId + " failed", e); - } - }); - futures.add(future); - } - - // Start all operations simultaneously - startLatch.countDown(); - - // Wait for all operations to complete - boolean completed = completionLatch.await(2, TimeUnit.MINUTES); - - // Check for exceptions first to see what actually failed - for (Future future : futures) { - future.get(); - } - - assertThat(completed).isTrue(); - - executor.shutdown(); - } - } - - /** - * Test region operations with authorization checks. - * - *

- * Verifies: - *

    - *
  • SecurityManager enforces authorization based on principal
  • - *
  • Different users have different permissions
  • - *
  • Authorization works with TLS transport encryption
  • - *
- */ - @Test - public void testRegionOperationsWithAuthorization() throws Exception { - // Create certificates and stores - // Note: Locator and server must use same CertStores for peer SSL communication - CertStores clusterStores = fixture.createClusterStores(); - CertStores clientStores = fixture.createClientStores(); - - // Start locator - Properties locatorProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(locatorProps); - fixture.addPeerAuthProperties(locatorProps, "cluster", "cluster"); - MemberVM locator = cluster.startLocatorVM(0, locatorProps); - int locatorPort = locator.getPort(); - - // Start server - Properties serverProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(serverProps); - fixture.addPeerAuthProperties(serverProps, "cluster", "cluster"); - serverProps.setProperty("locators", "localhost[" + locatorPort + "]"); - MemberVM server = cluster.startServerVM(1, serverProps, locatorPort); - - // Create region - server.invoke(() -> { - ClusterStartupRule.getCache() - .createRegionFactory(RegionShortcut.REPLICATE) - .create(REGION_NAME); - }); - - // Connect client with "data" credentials - // SimpleSecurityManager authorizes based on username prefix matching permission - Properties clientProps = clientStores.propertiesWith("all", false, false); - clientProps.putAll(fixture.createClientAuthProperties("data", "data")); - ClientVM client = cluster.startClientVM(2, c -> c - .withProperties(clientProps) - .withLocatorConnection(locatorPort)); - - // Verify authorized operations succeed - client.invoke(() -> { - Region region = ClusterStartupRule.getClientCache() - .createClientRegionFactory(ClientRegionShortcut.PROXY) - .create(REGION_NAME); - - // User "data" should be authorized for DATA:READ and DATA:WRITE - region.put("authKey", "authValue"); - assertThat(region.get("authKey")).isEqualTo("authValue"); - }); - } -} diff --git a/geode-core/src/distributedTest/java/org/apache/geode/cache/ssl/ServerOnlyTLSWithAuthNegativeTest.java b/geode-core/src/distributedTest/java/org/apache/geode/cache/ssl/ServerOnlyTLSWithAuthNegativeTest.java deleted file mode 100644 index 6c762d214d53..000000000000 --- a/geode-core/src/distributedTest/java/org/apache/geode/cache/ssl/ServerOnlyTLSWithAuthNegativeTest.java +++ /dev/null @@ -1,481 +0,0 @@ -/* - * 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.cache.ssl; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.util.Properties; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import org.apache.geode.cache.Region; -import org.apache.geode.cache.RegionShortcut; -import org.apache.geode.cache.client.ClientCache; -import org.apache.geode.cache.client.ClientRegionShortcut; -import org.apache.geode.cache.client.ServerOperationException; -import org.apache.geode.security.AuthenticationFailedException; -import org.apache.geode.security.AuthenticationRequiredException; -import org.apache.geode.security.NotAuthorizedException; -import org.apache.geode.test.dunit.IgnoredException; -import org.apache.geode.test.dunit.rules.ClientVM; -import org.apache.geode.test.dunit.rules.ClusterStartupRule; -import org.apache.geode.test.dunit.rules.MemberVM; -import org.apache.geode.test.junit.categories.SecurityTest; -import org.apache.geode.test.junit.rules.ServerOnlyTLSTestFixture; - -/** - * Negative tests for Server-only TLS with Alternative Client Authentication. - * - *

- * These tests verify that security violations are properly detected and rejected: - *

    - *
  • Invalid credentials are rejected
  • - *
  • Missing credentials are rejected
  • - *
  • Invalid tokens are rejected
  • - *
  • Unauthorized operations are blocked
  • - *
  • Missing or invalid server certificates are detected
  • - *
- */ -@Category({SecurityTest.class}) -public class ServerOnlyTLSWithAuthNegativeTest { - - private static final String REGION_NAME = "testRegion"; - - @Rule - public ClusterStartupRule cluster = new ClusterStartupRule(); - - private ServerOnlyTLSTestFixture fixture; - - @Before - public void setUp() throws Exception { - fixture = new ServerOnlyTLSTestFixture(); - } - - @org.junit.After - public void tearDown() throws Exception { - // Remove ignored exceptions - IgnoredException.removeAllExpectedExceptions(); - // Give VMs time to fully shut down - Thread.sleep(500); - } - - /** - * Test that clients with invalid credentials are rejected. - * - *

- * Verifies: - *

    - *
  • Wrong password causes authentication failure
  • - *
  • TLS connection is established but authentication fails
  • - *
- */ - @Test - public void testClientWithInvalidCredentialsRejected() throws Exception { - IgnoredException.addIgnoredException(AuthenticationFailedException.class.getName()); - IgnoredException.addIgnoredException("Authentication FAILED"); - IgnoredException.addIgnoredException("ServerOperationException"); - - // Create certificates and stores - // Note: Locator and server must use same CertStores for peer SSL communication - CertStores clusterStores = fixture.createClusterStores(); - CertStores clientStores = fixture.createClientStores(); - - // Start locator - Properties locatorProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(locatorProps); - fixture.addPeerAuthProperties(locatorProps, "cluster", "cluster"); - MemberVM locator = cluster.startLocatorVM(0, locatorProps); - int locatorPort = locator.getPort(); - - // Start server - Properties serverProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(serverProps); - fixture.addPeerAuthProperties(serverProps, "cluster", "cluster"); - serverProps.setProperty("locators", "localhost[" + locatorPort + "]"); - MemberVM server = cluster.startServerVM(1, serverProps, locatorPort); - - // Create region - server.invoke(() -> { - ClusterStartupRule.getCache() - .createRegionFactory(RegionShortcut.REPLICATE) - .create(REGION_NAME); - }); - - // Configure client with WRONG password - Properties clientProps = clientStores.propertiesWith("all", false, false); - clientProps.putAll(fixture.createClientAuthProperties("testUser", "wrongPassword")); - - // Client connection succeeds (TLS is established), but authentication fails on first operation - ClientVM client = cluster.startClientVM(2, c -> c - .withProperties(clientProps) - .withLocatorConnection(locatorPort)); - - // Verify authentication fails when attempting an operation - client.invoke(() -> { - ClientCache clientCache = ClusterStartupRule.getClientCache(); - Region region = clientCache - .createClientRegionFactory(ClientRegionShortcut.PROXY) - .create(REGION_NAME); - - // Authentication should fail on first operation - assertThatThrownBy(() -> region.put("key", "value")) - .isInstanceOf(ServerOperationException.class) - .hasCauseInstanceOf(AuthenticationFailedException.class); - }); - } - - /** - * Test that clients without credentials are rejected. - * - *

- * Verifies: - *

    - *
  • Missing authentication credentials cause connection failure
  • - *
  • TLS connection might establish but authentication is required
  • - *
- */ - @Test - public void testClientWithMissingCredentialsRejected() throws Exception { - IgnoredException.addIgnoredException(AuthenticationFailedException.class.getName()); - IgnoredException.addIgnoredException("Authentication FAILED"); - IgnoredException.addIgnoredException("AuthenticationRequiredException"); - IgnoredException.addIgnoredException("No security credentials are provided"); - IgnoredException.addIgnoredException("ServerOperationException"); - - // Create certificates and stores - // Note: Locator and server must use same CertStores for peer SSL communication - CertStores clusterStores = fixture.createClusterStores(); - CertStores clientStores = fixture.createClientStores(); - - // Start locator - Properties locatorProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(locatorProps); - fixture.addPeerAuthProperties(locatorProps, "cluster", "cluster"); - MemberVM locator = cluster.startLocatorVM(0, locatorProps); - int locatorPort = locator.getPort(); - - // Start server - Properties serverProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(serverProps); - fixture.addPeerAuthProperties(serverProps, "cluster", "cluster"); - serverProps.setProperty("locators", "localhost[" + locatorPort + "]"); - MemberVM server = cluster.startServerVM(1, serverProps, locatorPort); - - // Create region - server.invoke(() -> { - ClusterStartupRule.getCache() - .createRegionFactory(RegionShortcut.REPLICATE) - .create(REGION_NAME); - }); - - // Configure client with TLS but NO authentication credentials - Properties clientProps = clientStores.propertiesWith("all", false, false); - // Do NOT add authentication properties - - // Client connection succeeds (TLS is established), but authentication fails on first operation - ClientVM client = cluster.startClientVM(2, c -> c - .withProperties(clientProps) - .withLocatorConnection(locatorPort)); - - // Verify authentication fails when attempting an operation - client.invoke(() -> { - ClientCache clientCache = ClusterStartupRule.getClientCache(); - Region region = clientCache - .createClientRegionFactory(ClientRegionShortcut.PROXY) - .create(REGION_NAME); - - // Authentication should fail on first operation due to missing credentials - assertThatThrownBy(() -> region.put("key", "value")) - .isInstanceOf(ServerOperationException.class) - .hasCauseInstanceOf(AuthenticationRequiredException.class); - }); - } - - /** - * Test that clients with invalid tokens are rejected. - * - *

- * Verifies: - *

    - *
  • Invalid bearer tokens cause authentication failure
  • - *
  • Token validation is enforced
  • - *
- */ - @Test - public void testClientWithInvalidTokenRejected() throws Exception { - IgnoredException.addIgnoredException(AuthenticationFailedException.class.getName()); - IgnoredException.addIgnoredException("Authentication FAILED"); - IgnoredException.addIgnoredException("Token authentication FAILED"); - IgnoredException.addIgnoredException("ServerOperationException"); - - // Create certificates and stores - // Note: Locator and server must use same CertStores for peer SSL communication - CertStores clusterStores = fixture.createClusterStores(); - CertStores clientStores = fixture.createClientStores(); - - // Start locator - Properties locatorProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(locatorProps); - fixture.addPeerAuthProperties(locatorProps, "cluster", "cluster"); - MemberVM locator = cluster.startLocatorVM(0, locatorProps); - int locatorPort = locator.getPort(); - - // Start server - Properties serverProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(serverProps); - fixture.addPeerAuthProperties(serverProps, "cluster", "cluster"); - serverProps.setProperty("locators", "localhost[" + locatorPort + "]"); - MemberVM server = cluster.startServerVM(1, serverProps, locatorPort); - - // Create region - server.invoke(() -> { - ClusterStartupRule.getCache() - .createRegionFactory(RegionShortcut.REPLICATE) - .create(REGION_NAME); - }); - - // Configure client with INVALID token - Properties clientProps = clientStores.propertiesWith("all", false, false); - clientProps.putAll(fixture.createClientTokenAuthProperties("INVALID_TOKEN")); - - // Client connection succeeds (TLS is established), but authentication fails on first operation - ClientVM client = cluster.startClientVM(2, c -> c - .withProperties(clientProps) - .withLocatorConnection(locatorPort)); - - // Verify authentication fails when attempting an operation - client.invoke(() -> { - ClientCache clientCache = ClusterStartupRule.getClientCache(); - Region region = clientCache - .createClientRegionFactory(ClientRegionShortcut.PROXY) - .create(REGION_NAME); - - // Authentication should fail on first operation due to invalid token - assertThatThrownBy(() -> region.put("key", "value")) - .isInstanceOf(ServerOperationException.class) - .hasCauseInstanceOf(AuthenticationFailedException.class); - }); - } - - /** - * Test that authenticated clients without authorization are blocked from operations. - * - *

- * Verifies: - *

    - *
  • Authentication succeeds
  • - *
  • Unauthorized operations are blocked by SecurityManager
  • - *
- */ - @Test - public void testClientUnauthorizedForOperation() throws Exception { - IgnoredException.addIgnoredException(NotAuthorizedException.class.getName()); - - // Create certificates and stores - // Note: Locator and server must use same CertStores for peer SSL communication - CertStores clusterStores = fixture.createClusterStores(); - CertStores clientStores = fixture.createClientStores(); - - // Start locator - Properties locatorProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(locatorProps); - fixture.addPeerAuthProperties(locatorProps, "cluster", "cluster"); - MemberVM locator = cluster.startLocatorVM(0, locatorProps); - int locatorPort = locator.getPort(); - - // Start server - Properties serverProps = clusterStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(serverProps); - fixture.addPeerAuthProperties(serverProps, "cluster", "cluster"); - serverProps.setProperty("locators", "localhost[" + locatorPort + "]"); - MemberVM server = cluster.startServerVM(1, serverProps, locatorPort); - - // Create region - server.invoke(() -> { - ClusterStartupRule.getCache() - .createRegionFactory(RegionShortcut.REPLICATE) - .create(REGION_NAME); - }); - - // Connect client with credentials that don't match required permissions - // SimpleSecurityManager authorizes based on principal matching permission string prefix - // User "readonly" will NOT be authorized for "DATA:WRITE" operations - Properties clientProps = clientStores.propertiesWith("all", false, false); - clientProps.putAll(fixture.createClientAuthProperties("readonly", "readonly")); - - ClientVM client = cluster.startClientVM(2, c -> c - .withProperties(clientProps) - .withLocatorConnection(locatorPort)); - - // Verify client can connect but unauthorized operations fail - client.invoke(() -> { - Region region = ClusterStartupRule.getClientCache() - .createClientRegionFactory(ClientRegionShortcut.PROXY) - .create(REGION_NAME); - - // This operation should fail due to lack of authorization - assertThatThrownBy(() -> region.put("unauthorizedKey", "value")) - .hasCauseInstanceOf(NotAuthorizedException.class); - }); - } - - /** - * Test that clients reject connections to servers without certificates. - * - *

- * Verifies: - *

    - *
  • TLS handshake fails when server doesn't present certificate
  • - *
  • Client-side verification is enforced
  • - *
- */ - @Test - public void testClientCannotConnectWithoutServerCert() throws Exception { - IgnoredException.addIgnoredException("SSLHandshakeException"); - IgnoredException.addIgnoredException("Server expecting SSL handshake"); - - // This test would require starting a server WITHOUT SSL configuration - // which is complex in a proper test environment. The test verifies the concept - // that mixing SSL and non-SSL components fails. - - // Create locator WITH SSL - CertStores locatorStores = fixture.createLocatorStores(); - - Properties locatorProps = locatorStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(locatorProps); - fixture.addPeerAuthProperties(locatorProps, "cluster", "cluster"); - MemberVM locator = cluster.startLocatorVM(2, locatorProps); - int locatorPort = locator.getPort(); - - // Start server WITHOUT SSL (simulating misconfiguration) - Properties serverProps = new Properties(); - serverProps.setProperty("locators", "localhost[" + locatorPort + "]"); - // No SSL properties - fixture.addSecurityManagerConfig(serverProps); - fixture.addPeerAuthProperties(serverProps, "cluster", "cluster"); - - // Server should fail to join the cluster due to SSL mismatch - assertThatThrownBy(() -> { - cluster.startServerVM(3, serverProps, locatorPort); - }).getCause().getCause().getCause() - .isInstanceOf(javax.net.ssl.SSLHandshakeException.class); - } - - /** - * Test that clients reject servers with invalid or untrusted certificates. - * - *

- * Verifies: - *

    - *
  • Client verifies server certificate against truststore
  • - *
  • Invalid server certificates are rejected
  • - *
  • PKIX path validation is enforced
  • - *
- */ - @Test - public void testClientRejectsServerWithInvalidCert() throws Exception { - IgnoredException.addIgnoredException("SSLHandshakeException"); - IgnoredException.addIgnoredException("path"); - IgnoredException.addIgnoredException("certificate"); - - // Create two separate CAs - CertificateMaterial validCA = fixture.getCA(); - - // Create a separate untrusted CA - CertificateMaterial untrustedCA = new CertificateBuilder() - .commonName("Untrusted-CA") - .isCA() - .generate(); - - // Create locator with valid CA - CertStores locatorStores = fixture.createLocatorStores(); - - Properties locatorProps = locatorStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(locatorProps); - fixture.addPeerAuthProperties(locatorProps, "cluster", "cluster"); - MemberVM locator = cluster.startLocatorVM(0, locatorProps); - int locatorPort = locator.getPort(); - - // Create server with certificate from UNTRUSTED CA - CertificateMaterial untrustedServerCert = new CertificateBuilder() - .commonName("untrusted-server") - .issuedBy(untrustedCA) - .sanDnsName("localhost") - .sanIpAddress("127.0.0.1") - .generate(); - - CertStores untrustedServerStores = CertStores.serverStore(); - untrustedServerStores.withCertificate("server", untrustedServerCert); - untrustedServerStores.trust("untrustedCA", untrustedCA); // Server ONLY trusts untrusted CA, not - // valid CA - - Properties serverProps = untrustedServerStores.propertiesWith("all", false, false); - fixture.addSecurityManagerConfig(serverProps); - fixture.addPeerAuthProperties(serverProps, "cluster", "cluster"); - serverProps.setProperty("locators", "localhost[" + locatorPort + "]"); - serverProps.setProperty("member-timeout", "5000"); // Fail fast if can't join cluster - - // Server might start but cluster communication could fail due to cert mismatch - // OR server might fail to join cluster - // Either way, this demonstrates certificate validation - - // Create client truststore with valid CA only (doesn't trust untrusted CA) - CertStores clientStores = CertStores.clientStore(); - clientStores.trust("ca", validCA); // Client ONLY trusts valid CA - - Properties clientProps = clientStores.propertiesWith("all", false, false); - clientProps.putAll(fixture.createClientAuthProperties("testUser", "testUser")); - - // If server manages to start, client connection should fail due to untrusted certificate - try { - MemberVM server = cluster.startServerVM(1, serverProps, locatorPort); - - server.invoke(() -> { - ClusterStartupRule.getCache() - .createRegionFactory(RegionShortcut.REPLICATE) - .create(REGION_NAME); - }); - - // Client should reject server's untrusted certificate - assertThatThrownBy(() -> { - cluster.startClientVM(2, c -> c - .withProperties(clientProps) - .withLocatorConnection(locatorPort)); - }).satisfiesAnyOf( - e -> assertThat(e).hasMessageContaining("PKIX"), - e -> assertThat(e).hasMessageContaining("certificate"), - e -> assertThat(e).hasMessageContaining("trust")); - } catch (Exception e) { - // Server startup failure due to certificate mismatch is expected - // The cause chain should contain SSL/certificate/handshake errors - Throwable cause = e; - boolean foundSSLError = false; - while (cause != null && !foundSSLError) { - String message = cause.getClass().getName() + ": " + cause.getMessage(); - if (message.contains("SSL") || message.contains("certificate") - || message.contains("handshake")) { - foundSSLError = true; - } - cause = cause.getCause(); - } - assertThat(foundSSLError).as("Should find SSL/certificate/handshake error in cause chain") - .isTrue(); - } - } -} diff --git a/geode-junit/src/main/java/org/apache/geode/security/templates/TokenAuthInit.java b/geode-junit/src/main/java/org/apache/geode/security/templates/TokenAuthInit.java deleted file mode 100644 index a7aa7d3255e7..000000000000 --- a/geode-junit/src/main/java/org/apache/geode/security/templates/TokenAuthInit.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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.security.templates; - -import java.util.Properties; - -import org.apache.geode.LogWriter; -import org.apache.geode.distributed.DistributedMember; -import org.apache.geode.security.AuthInitialize; -import org.apache.geode.security.AuthenticationFailedException; -import org.apache.geode.security.SecurityManager; - -/** - * An {@link AuthInitialize} implementation that obtains a bearer token as credentials from the - * given set of properties. - * - * To use this class the {@code security-client-auth-init} property should be set to the fully - * qualified name of the static {@code create} method viz. - * {@code org.apache.geode.security.templates.TokenAuthInit.create} - */ -public class TokenAuthInit implements AuthInitialize { - - public static final String BEARER_TOKEN = "security-bearer-token"; - - protected LogWriter systemLogWriter; - protected LogWriter securityLogWriter; - - public static AuthInitialize create() { - return new TokenAuthInit(); - } - - @Override - public void init(final LogWriter systemLogWriter, final LogWriter securityLogWriter) - throws AuthenticationFailedException { - this.systemLogWriter = systemLogWriter; - this.securityLogWriter = securityLogWriter; - } - - @Override - public Properties getCredentials(final Properties securityProperties, - final DistributedMember server, final boolean isPeer) throws AuthenticationFailedException { - String token = securityProperties.getProperty(BEARER_TOKEN); - if (token == null) { - throw new AuthenticationFailedException( - "TokenAuthInit: bearer token property [" + BEARER_TOKEN + "] not set."); - } - - Properties securityPropertiesCopy = new Properties(); - // SecurityManager expects TOKEN property - securityPropertiesCopy.setProperty(SecurityManager.TOKEN, token); - return securityPropertiesCopy; - } - - @Override - public void close() {} -} diff --git a/geode-junit/src/main/java/org/apache/geode/test/junit/rules/ServerOnlyTLSTestFixture.java b/geode-junit/src/main/java/org/apache/geode/test/junit/rules/ServerOnlyTLSTestFixture.java deleted file mode 100644 index 20ffc0924d96..000000000000 --- a/geode-junit/src/main/java/org/apache/geode/test/junit/rules/ServerOnlyTLSTestFixture.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * 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.test.junit.rules; - -import java.util.Properties; - -import org.apache.geode.cache.ssl.CertStores; -import org.apache.geode.cache.ssl.CertificateBuilder; -import org.apache.geode.cache.ssl.CertificateMaterial; -import org.apache.geode.examples.SimpleSecurityManager; -import org.apache.geode.security.templates.UserPasswordAuthInit; - -/** - * Test fixture for Server-only TLS with Alternative Client Authentication scenarios. - * - *

- * This fixture creates: - *

    - *
  • A Certificate Authority (CA)
  • - *
  • Server certificates signed by the CA (for locators and servers)
  • - *
  • NO client certificates - clients authenticate via username/password or tokens
  • - *
  • Server/locator keystores with server certificates
  • - *
  • Client truststores with CA certificate (to verify servers)
  • - *
  • Security configuration using SimpleSecurityManager
  • - *
- * - *

- * Key characteristics: - *

    - *
  • ssl-require-authentication=false - servers don't require client certificates
  • - *
  • All transport is TLS-encrypted in both directions
  • - *
  • Clients authenticate using application-layer credentials (username/password or tokens)
  • - *
- */ -public class ServerOnlyTLSTestFixture { - - private static final String CA_CN = "Server-Only-TLS-CA"; - private static final String SERVER_CN = "geode-server"; - private static final String LOCATOR_CN = "geode-locator"; - - private final CertificateMaterial ca; - private final CertificateMaterial serverCertificate; - private final CertificateMaterial locatorCertificate; - - public ServerOnlyTLSTestFixture() throws Exception { - // Create CA - ca = createCA(); - - // Create server and locator certificates (no client certificates needed) - serverCertificate = createServerCertificate(ca); - locatorCertificate = createLocatorCertificate(ca); - } - - /** - * Creates a Certificate Authority for signing server certificates. - */ - private CertificateMaterial createCA() throws Exception { - CertificateBuilder caBuilder = new CertificateBuilder() - .commonName(CA_CN) - .isCA(); - - return caBuilder.generate(); - } - - /** - * Creates a server certificate signed by the CA. - * Includes comprehensive Subject Alternative Names for server verification. - */ - private CertificateMaterial createServerCertificate(CertificateMaterial ca) throws Exception { - CertificateBuilder serverBuilder = new CertificateBuilder() - .commonName(SERVER_CN) - .issuedBy(ca) - .sanDnsName("localhost") - .sanDnsName("server.localdomain") - .sanIpAddress("127.0.0.1") - .sanIpAddress("0.0.0.0"); - - return serverBuilder.generate(); - } - - /** - * Creates a locator certificate signed by the CA. - * Includes comprehensive Subject Alternative Names for locator verification. - */ - private CertificateMaterial createLocatorCertificate(CertificateMaterial ca) throws Exception { - CertificateBuilder locatorBuilder = new CertificateBuilder() - .commonName(LOCATOR_CN) - .issuedBy(ca) - .sanDnsName("localhost") - .sanDnsName("locator.localdomain") - .sanIpAddress("127.0.0.1") - .sanIpAddress("0.0.0.0"); - - return locatorBuilder.generate(); - } - - /** - * Creates and returns server CertStores for server-only TLS. - * - *

- * Server truststore contains the CA certificate to verify peer connections. - *

- * Server keystore contains the server's certificate for presentation to clients. - * - * @return CertStores configured for server with server certificate - */ - public CertStores createServerStores() { - CertStores certStores = CertStores.serverStore(); - certStores.withCertificate("server", serverCertificate); - certStores.trust("ca", ca); - return certStores; - } - - /** - * Creates and returns locator CertStores for server-only TLS. - * - *

- * Locator truststore contains the CA certificate to verify peer connections. - *

- * Locator keystore contains the locator's certificate for presentation to clients and peers. - * - * @return CertStores configured for locator with locator certificate - */ - public CertStores createLocatorStores() { - CertStores certStores = CertStores.locatorStore(); - certStores.withCertificate("locator", locatorCertificate); - certStores.trust("ca", ca); - return certStores; - } - - /** - * Creates and returns cluster CertStores for both locator and server. - * - *

- * For peer SSL communication, both locator and server need compatible certificates. - * This method creates CertStores with the server certificate that works for both. - * The server certificate includes SANs for localhost/127.0.0.1 which work for both roles. - * - * @return CertStores configured with server certificate and CA trust - */ - public CertStores createClusterStores() { - CertStores certStores = CertStores.serverStore(); - // Use server certificate for both locator and server (SANs cover both roles) - certStores.withCertificate("server", serverCertificate); - certStores.trust("ca", ca); - return certStores; - } - - /** - * Creates and returns client CertStores for server-only TLS. - * - *

- * Client truststore contains ONLY the CA certificate to verify server certificates. - *

- * NO keystore is created - clients do not present certificates. - * - * @return CertStores configured for client with only truststore (no client certificate) - */ - public CertStores createClientStores() { - CertStores certStores = CertStores.clientStore(); - // Client only needs truststore with CA to verify servers - certStores.trust("ca", ca); - // NO client keystore - clients don't present certificates - return certStores; - } - - /** - * Adds security manager configuration to properties. - * Uses SimpleSecurityManager for authentication and authorization. - */ - public Properties addSecurityManagerConfig(Properties props) { - props.setProperty("security-manager", SimpleSecurityManager.class.getName()); - return props; - } - - /** - * Adds peer authentication credentials for server/locator-to-locator connections. - * Required when security-manager is enabled. - * - * @param props the properties to add authentication to - * @param username the username for peer authentication - * @param password the password for peer authentication - * @return the properties with peer authentication configured - */ - public Properties addPeerAuthProperties(Properties props, String username, String password) { - props.setProperty("security-username", username); - props.setProperty("security-password", password); - return props; - } - - /** - * Creates client authentication properties with username and password. - * - * @param username the username - * @param password the password - * @return Properties with authentication configuration - */ - public Properties createClientAuthProperties(String username, String password) { - Properties props = new Properties(); - props.setProperty("security-client-auth-init", - UserPasswordAuthInit.class.getName() + ".create"); - props.setProperty(UserPasswordAuthInit.USER_NAME, username); - props.setProperty(UserPasswordAuthInit.PASSWORD, password); - return props; - } - - /** - * Creates client authentication properties with a bearer token. - * - * @param token the bearer token - * @return Properties with token authentication configuration - */ - public Properties createClientTokenAuthProperties(String token) { - Properties props = new Properties(); - props.setProperty("security-client-auth-init", - "org.apache.geode.security.templates.TokenAuthInit.create"); - props.setProperty("security-bearer-token", token); - return props; - } - - /** - * Gets the CA certificate material for testing purposes. - */ - public CertificateMaterial getCA() { - return ca; - } - - /** - * Gets the server certificate material for testing purposes. - */ - public CertificateMaterial getServerCertificate() { - return serverCertificate; - } - - /** - * Gets the locator certificate material for testing purposes. - */ - public CertificateMaterial getLocatorCertificate() { - return locatorCertificate; - } -}