| /* |
| * 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.ignite.internal.encryption; |
| |
| import org.apache.ignite.IgniteCache; |
| import org.apache.ignite.IgniteCheckedException; |
| import org.apache.ignite.cluster.ClusterState; |
| import org.apache.ignite.configuration.CacheConfiguration; |
| import org.apache.ignite.configuration.IgniteConfiguration; |
| import org.apache.ignite.internal.IgniteEx; |
| import org.apache.ignite.internal.util.IgniteUtils; |
| import org.apache.ignite.spi.IgniteSpiException; |
| import org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionSpi; |
| import org.apache.ignite.testframework.GridTestUtils; |
| import org.junit.Test; |
| |
| import static org.apache.ignite.testframework.GridTestUtils.assertThrowsWithCause; |
| |
| /** |
| */ |
| public class EncryptedCacheNodeJoinTest extends AbstractEncryptionTest { |
| /** */ |
| private static final String GRID_2 = "grid-2"; |
| |
| /** */ |
| private static final String GRID_3 = "grid-3"; |
| |
| /** */ |
| private static final String GRID_4 = "grid-4"; |
| |
| /** */ |
| private static final String GRID_5 = "grid-5"; |
| |
| /** */ |
| private static final String GRID_6 = "grid-6"; |
| |
| /** */ |
| private static final String GRID_7 = "grid-7"; |
| |
| /** */ |
| public static final String CLIENT = "client"; |
| |
| /** */ |
| private boolean configureCache; |
| |
| /** */ |
| private static final String KEYSTORE_PATH_2 = |
| IgniteUtils.resolveIgnitePath("modules/core/src/test/resources/other_tde_keystore.jks").getAbsolutePath(); |
| |
| /** {@inheritDoc} */ |
| @Override protected void beforeTestsStarted() throws Exception { |
| cleanPersistenceDir(); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override protected void afterTest() throws Exception { |
| stopAllGrids(); |
| |
| cleanPersistenceDir(); |
| |
| configureCache = false; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override protected IgniteConfiguration getConfiguration(String grid) throws Exception { |
| IgniteConfiguration cfg = super.getConfiguration(grid); |
| |
| cfg.setConsistentId(grid); |
| |
| if (grid.equals(GRID_0) || |
| grid.equals(GRID_2) || |
| grid.equals(GRID_3) || |
| grid.equals(GRID_4) || |
| grid.equals(GRID_5) || |
| grid.equals(GRID_6) || |
| grid.equals(GRID_7)) { |
| KeystoreEncryptionSpi encSpi = new KeystoreEncryptionSpi(); |
| |
| encSpi.setKeyStorePath(grid.equals(GRID_2) ? KEYSTORE_PATH_2 : KEYSTORE_PATH); |
| encSpi.setKeyStorePassword(KEYSTORE_PASSWORD.toCharArray()); |
| |
| cfg.setEncryptionSpi(encSpi); |
| } |
| else |
| cfg.setEncryptionSpi(null); |
| |
| if (configureCache) |
| cfg.setCacheConfiguration(cacheConfiguration(grid)); |
| |
| return cfg; |
| } |
| |
| /** */ |
| protected CacheConfiguration cacheConfiguration(String gridName) { |
| CacheConfiguration ccfg = defaultCacheConfiguration(); |
| |
| ccfg.setName(cacheName()); |
| |
| if (gridName.startsWith(CLIENT) || |
| gridName.equals(GRID_0) || |
| gridName.equals(GRID_6) || |
| gridName.equals(GRID_7)) |
| ccfg.setEncryptionEnabled(true); |
| |
| return ccfg; |
| } |
| |
| /** */ |
| @Test |
| public void testNodeCantJoinWithoutEncryptionSpi() throws Exception { |
| startGrid(GRID_0); |
| |
| assertThrowsWithCause(() -> { |
| try { |
| startGrid(GRID_1); |
| } |
| catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| }, IgniteCheckedException.class); |
| } |
| |
| /** */ |
| @Test |
| public void testNodeCantJoinWithDifferentKeyStore() throws Exception { |
| startGrid(GRID_0); |
| |
| assertThrowsWithCause(() -> { |
| try { |
| startGrid(GRID_2); |
| } |
| catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| }, IgniteCheckedException.class); |
| } |
| |
| /** */ |
| @Test |
| public void testNodeCanJoin() throws Exception { |
| startGrid(GRID_0); |
| |
| startGrid(GRID_3).cluster().active(true); |
| } |
| |
| /** */ |
| @Test |
| public void testNodeCantJoinWithDifferentCacheKeys() throws Exception { |
| IgniteEx grid0 = startGrid(GRID_0); |
| startGrid(GRID_3); |
| |
| grid0.cluster().active(true); |
| |
| stopGrid(GRID_3, false); |
| |
| createEncryptedCache(grid0, null, cacheName(), null, false); |
| |
| stopGrid(GRID_0, false); |
| IgniteEx grid3 = startGrid(GRID_3); |
| |
| grid3.cluster().active(true); |
| |
| createEncryptedCache(grid3, null, cacheName(), null, false); |
| |
| assertThrowsWithCause(() -> { |
| try { |
| startGrid(GRID_0); |
| } |
| catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| }, IgniteCheckedException.class); |
| } |
| |
| /** */ |
| @Test |
| public void testThirdNodeCanJoin() throws Exception { |
| IgniteEx grid0 = startGrid(GRID_0); |
| |
| IgniteEx grid3 = startGrid(GRID_3); |
| |
| grid3.cluster().active(true); |
| |
| createEncryptedCache(grid0, grid3, cacheName(), null); |
| |
| checkEncryptedCaches(grid0, grid3); |
| |
| IgniteEx grid4 = startGrid(GRID_4); |
| |
| awaitPartitionMapExchange(); |
| |
| checkEncryptedCaches(grid0, grid4); |
| } |
| |
| /** */ |
| @Test |
| public void testClientNodeJoin() throws Exception { |
| IgniteEx grid0 = startGrid(GRID_0); |
| |
| IgniteEx grid3 = startGrid(GRID_3); |
| |
| grid3.cluster().active(true); |
| |
| IgniteEx client = startClientGrid(CLIENT); |
| |
| createEncryptedCache(client, grid0, cacheName(), null); |
| } |
| |
| /** */ |
| @Test |
| public void testClientNodeJoinActiveClusterWithNewStaticCacheConfig() throws Exception { |
| checkNodeJoinWithStaticCacheConfig(true, true, true); |
| } |
| |
| /** */ |
| @Test |
| public void testClientNodeJoinActiveClusterWithExistingStaticCacheConfig() throws Exception { |
| checkNodeJoinWithStaticCacheConfig(true, true, false); |
| } |
| |
| /** */ |
| @Test |
| public void testClientNodeJoinInactiveClusterWithNewStaticCacheConfig() throws Exception { |
| checkNodeJoinWithStaticCacheConfig(true, false, true); |
| } |
| |
| /** */ |
| @Test |
| public void testClientNodeJoinInactiveClusterWithExistingStaticCacheConfig() throws Exception { |
| checkNodeJoinWithStaticCacheConfig(true, false, false); |
| } |
| |
| /** */ |
| @Test |
| public void testServerNodeJoinActiveClusterWithNewStaticCacheConfig() throws Exception { |
| checkNodeJoinWithStaticCacheConfig(false, true, true); |
| } |
| |
| /** */ |
| @Test |
| public void testServerNodeJoinInactiveClusterWithNewStaticCacheConfig() throws Exception { |
| checkNodeJoinWithStaticCacheConfig(false, false, true); |
| } |
| |
| /** |
| * @param client {@code True} to test client node join, {@code False} to test server node join. |
| * @param activateBeforeJoin {@code True} to activate the server before joining the client node. |
| * @param newCfg {@code True} to configure cache on the last joined node. {@code False} to configure on all nodes. |
| */ |
| private void checkNodeJoinWithStaticCacheConfig( |
| boolean client, |
| boolean activateBeforeJoin, |
| boolean newCfg |
| ) throws Exception { |
| if (!newCfg) |
| configureCache = true; |
| |
| startGrid(GRID_0); |
| startGrid(GRID_6); |
| |
| IgniteEx client1 = startClientGrid("client1"); |
| |
| if (newCfg) |
| configureCache = true; |
| |
| if (activateBeforeJoin) |
| grid(GRID_0).cluster().state(ClusterState.ACTIVE); |
| |
| if (client && newCfg) { |
| String expErrMsg = "Joining node has encrypted caches which are not presented on the cluster, " + |
| "encrypted caches configured on client node cannot be started when such node joins " + |
| "the cluster, these caches can be started manually (dynamically) after node joined" + |
| "[caches=" + cacheName() + ']'; |
| |
| GridTestUtils.assertThrowsAnyCause(log, () -> startClientGrid(CLIENT), IgniteSpiException.class, expErrMsg); |
| |
| return; |
| } |
| |
| IgniteEx node = client ? startClientGrid(CLIENT) : startGrid(GRID_7); |
| |
| if (!activateBeforeJoin) |
| grid(GRID_0).cluster().state(ClusterState.ACTIVE); |
| |
| awaitPartitionMapExchange(); |
| |
| IgniteCache<Object, Object> cache = node.cache(cacheName()); |
| |
| assertNotNull(cache); |
| |
| for (long i = 0; i < 100; i++) |
| cache.put(i, String.valueOf(i)); |
| |
| checkEncryptedCaches(grid(GRID_0), grid(GRID_6)); |
| checkEncryptedCaches(grid(GRID_0), client1); |
| checkData(client1); |
| |
| if (client) { |
| checkEncryptedCaches(grid(GRID_0), grid(CLIENT)); |
| checkData(grid(CLIENT)); |
| } |
| else |
| checkEncryptedCaches(grid(GRID_7), grid(GRID_0)); |
| } |
| |
| /** */ |
| @Test |
| public void testNodeCantJoinWithSameNameButNotEncCache() throws Exception { |
| configureCache = true; |
| |
| IgniteEx grid0 = startGrid(GRID_0); |
| |
| grid0.cluster().active(true); |
| |
| assertThrowsWithCause(() -> { |
| try { |
| startGrid(GRID_5); |
| } |
| catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| }, IgniteCheckedException.class); |
| } |
| |
| /** */ |
| @Test |
| public void testNodeCantJoinWithSameNameButEncCache() throws Exception { |
| configureCache = true; |
| |
| IgniteEx grid0 = startGrid(GRID_5); |
| |
| grid0.cluster().active(true); |
| |
| assertThrowsWithCause(() -> { |
| try { |
| startGrid(GRID_0); |
| } |
| catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| }, IgniteCheckedException.class); |
| } |
| } |