/* * 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; import static org.apache.geode.security.SecurityTestUtils.*; import static org.apache.geode.test.dunit.LogWriterUtils.*; import java.util.Iterator; import java.util.Properties; import org.junit.Test; import org.junit.experimental.categories.Category; import org.apache.geode.cache.Region; import org.apache.geode.cache.execute.Function; import org.apache.geode.cache.operations.OperationContext.OperationCode; import org.apache.geode.internal.cache.GemFireCacheImpl; import org.apache.geode.internal.cache.execute.PRClientServerTestBase; import org.apache.geode.internal.cache.functions.TestFunction; import org.apache.geode.security.generator.AuthzCredentialGenerator; import org.apache.geode.security.generator.CredentialGenerator; import org.apache.geode.test.dunit.VM; import org.apache.geode.test.junit.categories.DistributedTest; import org.apache.geode.test.junit.categories.SecurityTest; @Category({DistributedTest.class, SecurityTest.class}) public class ClientMultiUserAuthzDUnitTest extends ClientAuthorizationTestCase { @Override public final void preTearDownClientAuthorizationTestBase() throws Exception { closeCache(); } /** * Tests with one user authorized to do puts/gets/containsKey/destroys and another not authorized * for the same. */ @Test public void testOps1() throws Exception { for (Iterator<AuthzCredentialGenerator> iter = getDummyGeneratorCombos().iterator(); iter .hasNext();) { AuthzCredentialGenerator gen = iter.next(); CredentialGenerator cGen = gen.getCredentialGenerator(); Properties extraAuthProps = cGen.getSystemProperties(); Properties javaProps = cGen.getJavaProperties(); Properties extraAuthzProps = gen.getSystemProperties(); String authenticator = cGen.getAuthenticator(); String authInit = cGen.getAuthInit(); String accessor = gen.getAuthorizationCallback(); getLogWriter().info("testOps1: Using authinit: " + authInit); getLogWriter().info("testOps1: Using authenticator: " + authenticator); getLogWriter().info("testOps1: Using accessor: " + accessor); // Start servers with all required properties Properties serverProps = buildProperties(authenticator, accessor, false, extraAuthProps, extraAuthzProps); int port1 = createCacheServerOnVM(server1, javaProps, serverProps); int port2 = createCacheServerOnVM(server2, javaProps, serverProps); if (!prepareClientsForOps(gen, cGen, new OperationCode[] {OperationCode.PUT, OperationCode.PUT}, new OperationCode[] {OperationCode.GET, OperationCode.GET}, javaProps, authInit, port1, port2)) { continue; } verifyPutsGets(); if (!prepareClientsForOps(gen, cGen, new OperationCode[] {OperationCode.PUT, OperationCode.CONTAINS_KEY}, new OperationCode[] {OperationCode.DESTROY, OperationCode.DESTROY}, javaProps, authInit, port1, port2)) { continue; } verifyContainsKeyDestroys(); if (!prepareClientsForOps(gen, cGen, new OperationCode[] {OperationCode.PUT, OperationCode.CONTAINS_KEY}, new OperationCode[] {OperationCode.INVALIDATE, OperationCode.INVALIDATE}, javaProps, authInit, port1, port2)) { continue; } verifyContainsKeyInvalidates(); if (!prepareClientsForOps(gen, cGen, new OperationCode[] {OperationCode.GET, OperationCode.GET}, new OperationCode[] {OperationCode.REGION_DESTROY, OperationCode.REGION_DESTROY}, javaProps, authInit, port1, port2)) { continue; } verifyGetAllInTX(); verifyGetAllRegionDestroys(); } } /** * Test query/function execute */ @Test public void testOps2() throws Exception { AuthzCredentialGenerator gen = getXmlAuthzGenerator(); CredentialGenerator cGen = gen.getCredentialGenerator(); Properties extraAuthProps = cGen.getSystemProperties(); Properties javaProps = cGen.getJavaProperties(); Properties extraAuthzProps = gen.getSystemProperties(); String authenticator = cGen.getAuthenticator(); String authInit = cGen.getAuthInit(); String accessor = gen.getAuthorizationCallback(); getLogWriter().info("testOps2: Using authinit: " + authInit); getLogWriter().info("testOps2: Using authenticator: " + authenticator); getLogWriter().info("testOps2: Using accessor: " + accessor); // Start servers with all required properties Properties serverProps = buildProperties(authenticator, accessor, false, extraAuthProps, extraAuthzProps); int port1 = createCacheServerOnVM(server1, javaProps, serverProps); int port2 = createCacheServerOnVM(server2, javaProps, serverProps); // Start client1 with valid/invalid QUERY credentials Properties[] client1Credentials = new Properties[] { gen.getAllowedCredentials(new OperationCode[] {OperationCode.PUT, OperationCode.QUERY}, new String[] {regionName}, 1), gen.getDisallowedCredentials(new OperationCode[] {OperationCode.PUT, OperationCode.QUERY}, new String[] {regionName}, 1)}; javaProps = cGen.getJavaProperties(); getLogWriter().info("testOps2: For first client credentials: " + client1Credentials[0] + "\n" + client1Credentials[1]); final Properties finalJavaProps = javaProps; client1.invoke(() -> createCacheClientForMultiUserMode(2, authInit, client1Credentials, finalJavaProps, new int[] {port1, port2}, -1, false, NO_EXCEPTION)); // Start client2 with valid/invalid EXECUTE_FUNCTION credentials Properties[] client2Credentials = new Properties[] { gen.getAllowedCredentials(new OperationCode[] {OperationCode.EXECUTE_FUNCTION}, new String[] {regionName}, 2), gen.getDisallowedCredentials(new OperationCode[] {OperationCode.EXECUTE_FUNCTION}, new String[] {regionName}, 9)}; javaProps = cGen.getJavaProperties(); getLogWriter().info("testOps2: For second client credentials: " + client2Credentials[0] + "\n" + client2Credentials[1]); final Properties finalJavaProps2 = javaProps; client2.invoke(() -> createCacheClientForMultiUserMode(2, authInit, client2Credentials, finalJavaProps2, new int[] {port1, port2}, -1, false, NO_EXCEPTION)); Function function = new TestFunction(true, TestFunction.TEST_FUNCTION1); server1.invoke(() -> PRClientServerTestBase.registerFunction(function)); server2.invoke(() -> PRClientServerTestBase.registerFunction(function)); // Perform some put operations before verifying queries client1.invoke(() -> doMultiUserPuts(4, 2, new int[] {NO_EXCEPTION, NOTAUTHZ_EXCEPTION})); client1.invoke(() -> doMultiUserQueries(2, new int[] {NO_EXCEPTION, NOTAUTHZ_EXCEPTION}, 4)); client1 .invoke(() -> doMultiUserQueryExecute(2, new int[] {NO_EXCEPTION, NOTAUTHZ_EXCEPTION}, 4)); // Verify that the FE succeeds/fails client2.invoke( () -> doMultiUserFE(2, function, new int[] {NO_EXCEPTION, NOTAUTHZ_EXCEPTION}, false)); // Failover server1.invoke(() -> closeCache()); Thread.sleep(2000); client1.invoke(() -> doMultiUserPuts(4, 2, new int[] {NO_EXCEPTION, NOTAUTHZ_EXCEPTION})); client1.invoke(() -> doMultiUserQueries(2, new int[] {NO_EXCEPTION, NOTAUTHZ_EXCEPTION}, 4)); client1 .invoke(() -> doMultiUserQueryExecute(2, new int[] {NO_EXCEPTION, NOTAUTHZ_EXCEPTION}, 4)); // Verify that the FE succeeds/fails client2.invoke( () -> doMultiUserFE(2, function, new int[] {NO_EXCEPTION, NOTAUTHZ_EXCEPTION}, true)); } @Test public void testOpsWithClientsInDifferentModes() throws Exception { for (Iterator<AuthzCredentialGenerator> iter = getDummyGeneratorCombos().iterator(); iter .hasNext();) { AuthzCredentialGenerator gen = iter.next(); CredentialGenerator cGen = gen.getCredentialGenerator(); Properties extraAuthProps = cGen.getSystemProperties(); Properties javaProps = cGen.getJavaProperties(); Properties extraAuthzProps = gen.getSystemProperties(); String authenticator = cGen.getAuthenticator(); String authInit = cGen.getAuthInit(); String accessor = gen.getAuthorizationCallback(); getLogWriter().info("testOpsWithClientsInDifferentModes: Using authinit: " + authInit); getLogWriter() .info("testOpsWithClientsInDifferentModes: Using authenticator: " + authenticator); getLogWriter().info("testOpsWithClientsInDifferentModes: Using accessor: " + accessor); // Start servers with all required properties Properties serverProps = buildProperties(authenticator, accessor, false, extraAuthProps, extraAuthzProps); int port1 = createCacheServerOnVM(server1, javaProps, serverProps); int port2 = createCacheServerOnVM(server2, javaProps, serverProps); if (!prepareClientsForOps(gen, cGen, new OperationCode[] {OperationCode.PUT, OperationCode.PUT}, new OperationCode[] {OperationCode.GET, OperationCode.GET}, javaProps, authInit, port1, port2, false, true)) { continue; } verifyPutsGets(false, true); if (!prepareClientsForOps(gen, cGen, new OperationCode[] {OperationCode.PUT, OperationCode.CONTAINS_KEY}, new OperationCode[] {OperationCode.DESTROY, OperationCode.DESTROY}, javaProps, authInit, port1, port2, false, false)) { continue; } verifyContainsKeyDestroys(false, false); } } private boolean prepareClientsForOps(final AuthzCredentialGenerator gen, final CredentialGenerator cGen, final OperationCode[] client1OpCodes, final OperationCode[] client2OpCodes, final Properties javaProps, final String authInit, final int port1, final int port2) { return prepareClientsForOps(gen, cGen, client1OpCodes, client2OpCodes, javaProps, authInit, port1, port2, true /* both clients in multiuser mode */, false /* unused */); } private boolean prepareClientsForOps(final AuthzCredentialGenerator gen, final CredentialGenerator cGen, final OperationCode[] client1OpCodes, final OperationCode[] client2OpCodes, Properties javaProps, final String authInit, final int port1, final int port2, final boolean bothClientsInMultiuserMode, final boolean allowOp) { // Start client1 with valid/invalid client1OpCodes credentials Properties[] client1Credentials = new Properties[] {gen.getAllowedCredentials(client1OpCodes, new String[] {regionName}, 1), gen.getDisallowedCredentials(new OperationCode[] {client1OpCodes[1]}, new String[] {regionName}, 1)}; if (client1Credentials[0] == null || client1Credentials[0].size() == 0) { getLogWriter().info("testOps1: Unable to obtain valid credentials with " + client1OpCodes[0].toString() + " permission; skipping this combination."); return false; } if (client1Credentials[1] == null || client1Credentials[1].size() == 0) { getLogWriter().info("testOps1: Unable to obtain valid credentials with no " + client1OpCodes[0].toString() + " permission; skipping this combination."); return false; } javaProps = cGen.getJavaProperties(); getLogWriter().info("testOps1: For first client credentials: " + client1Credentials[0] + "\n" + client1Credentials[1]); final Properties finalJavaProps = javaProps; client1.invoke(() -> createCacheClientForMultiUserMode(2, authInit, client1Credentials, finalJavaProps, new int[] {port1, port2}, -1, false, NO_EXCEPTION)); // Start client2 with valid/invalid client2OpCodes credentials Properties[] client2Credentials = new Properties[] {gen.getAllowedCredentials(client2OpCodes, new String[] {regionName}, 2), gen.getDisallowedCredentials(client2OpCodes, new String[] {regionName}, 9)}; if (client2Credentials[0] == null || client2Credentials[0].size() == 0) { getLogWriter().info("testOps1: Unable to obtain valid credentials with " + client2OpCodes[0].toString() + " permission; skipping this combination."); return false; } if (client2Credentials[1] == null || client2Credentials[1].size() == 0) { getLogWriter().info("testOps1: Unable to obtain valid credentials with no " + client2OpCodes[0].toString() + " permission; skipping this combination."); return false; } javaProps = cGen.getJavaProperties(); getLogWriter().info("testOps1: For second client credentials: " + client2Credentials[0] + "\n" + client2Credentials[1]); if (bothClientsInMultiuserMode) { final Properties finalJavaProps2 = javaProps; client2.invoke(() -> createCacheClientForMultiUserMode(2, authInit, client2Credentials, finalJavaProps2, new int[] {port1, port2}, -1, false, NO_EXCEPTION)); } else { int credentialsIndex = allowOp ? 0 : 1; final Properties finalJavaProps2 = javaProps; client2.invoke(() -> createCacheClient(authInit, client2Credentials[credentialsIndex], finalJavaProps2, new int[] {port1, port2}, -1, false, false, NO_EXCEPTION)); } return true; } private void verifyPutsGets() throws Exception { verifyPutsGets(true, false /* unused */); } private void verifyPutsGets(final boolean isMultiuser, final boolean opAllowed) throws Exception { // Perform some put operations from client1 client1.invoke(() -> doMultiUserPuts(2, 2, new int[] {NO_EXCEPTION, NOTAUTHZ_EXCEPTION})); // Verify that the gets succeed/fail if (isMultiuser) { client2.invoke(() -> doMultiUserGets(2, 2, new int[] {NO_EXCEPTION, NOTAUTHZ_EXCEPTION})); } else { int expectedResult = (opAllowed) ? NO_EXCEPTION : NOTAUTHZ_EXCEPTION; client2.invoke(() -> doMultiUserGets(1, 1, new int[] {expectedResult})); } } private void verifyContainsKeyDestroys() throws Exception { verifyContainsKeyDestroys(true, false /* unused */); } private void verifyContainsKeyDestroys(final boolean isMultiUser, final boolean opAllowed) throws Exception { // Do puts before verifying containsKey client1.invoke(() -> doMultiUserPuts(2, 2, new int[] {NO_EXCEPTION, NO_EXCEPTION})); client1.invoke(() -> doMultiUserContainsKeys(1, 2, new int[] {NO_EXCEPTION, NOTAUTHZ_EXCEPTION}, new boolean[] {true, false})); // Verify that the destroys succeed/fail if (isMultiUser) { client2.invoke(() -> doMultiUserDestroys(2, 2, new int[] {NO_EXCEPTION, NOTAUTHZ_EXCEPTION})); } else { int expectedResult = (opAllowed) ? NO_EXCEPTION : NOTAUTHZ_EXCEPTION; client2.invoke(() -> doMultiUserDestroys(1, 1, new int[] {expectedResult})); } } private void verifyContainsKeyInvalidates() throws Exception { verifyContainsKeyInvalidates(true, false /* unused */); } private void verifyContainsKeyInvalidates(final boolean isMultiUser, final boolean opAllowed) throws Exception { // Do puts before verifying containsKey client1.invoke(() -> doMultiUserPuts(2, 2, new int[] {NO_EXCEPTION, NO_EXCEPTION})); client1.invoke(() -> doMultiUserContainsKeys(1, 2, new int[] {NO_EXCEPTION, NOTAUTHZ_EXCEPTION}, new boolean[] {true, false})); // Verify that the invalidates succeed/fail if (isMultiUser) { client2 .invoke(() -> doMultiUserInvalidates(2, 2, new int[] {NO_EXCEPTION, NOTAUTHZ_EXCEPTION})); } else { int expectedResult = (opAllowed) ? NO_EXCEPTION : NOTAUTHZ_EXCEPTION; client2.invoke(() -> doMultiUserInvalidates(1, 1, new int[] {expectedResult})); } } private void verifyGetAllInTX() { server1.invoke(() -> doPuts()); client1.invoke( () -> doMultiUserGetAll(2, new int[] {NO_EXCEPTION, NOTAUTHZ_EXCEPTION}, true/* use TX */)); } private void verifyGetAllRegionDestroys() { server1.invoke(() -> doPuts()); client1.invoke(() -> doMultiUserGetAll(2, new int[] {NO_EXCEPTION, NOTAUTHZ_EXCEPTION})); // Verify that the region destroys succeed/fail client2 .invoke(() -> doMultiUserRegionDestroys(2, new int[] {NO_EXCEPTION, NOTAUTHZ_EXCEPTION})); } private void doPuts() { Region region = GemFireCacheImpl.getInstance().getRegion(REGION_NAME); region.put("key1", "value1"); region.put("key2", "value2"); } private int createCacheServerOnVM(final VM server, final Properties javaProps, final Properties serverProps) { return server.invoke(() -> ClientAuthorizationTestCase.createCacheServer(getLocatorPort(), serverProps, javaProps)); } }