blob: b9adee529debeacef8502a2caef98f65b54968f0 [file] [log] [blame]
/*
* 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.NOTAUTHZ_EXCEPTION;
import static org.apache.geode.security.SecurityTestUtils.NO_EXCEPTION;
import static org.apache.geode.security.SecurityTestUtils.REGION_NAME;
import static org.apache.geode.security.SecurityTestUtils.closeCache;
import static org.apache.geode.security.SecurityTestUtils.createCacheClient;
import static org.apache.geode.security.SecurityTestUtils.createCacheClientForMultiUserMode;
import static org.apache.geode.security.SecurityTestUtils.doMultiUserContainsKeys;
import static org.apache.geode.security.SecurityTestUtils.doMultiUserDestroys;
import static org.apache.geode.security.SecurityTestUtils.doMultiUserFE;
import static org.apache.geode.security.SecurityTestUtils.doMultiUserGetAll;
import static org.apache.geode.security.SecurityTestUtils.doMultiUserGets;
import static org.apache.geode.security.SecurityTestUtils.doMultiUserInvalidates;
import static org.apache.geode.security.SecurityTestUtils.doMultiUserPuts;
import static org.apache.geode.security.SecurityTestUtils.doMultiUserQueries;
import static org.apache.geode.security.SecurityTestUtils.doMultiUserQueryExecute;
import static org.apache.geode.security.SecurityTestUtils.doMultiUserRegionDestroys;
import static org.apache.geode.test.dunit.LogWriterUtils.getLogWriter;
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.SecurityTest;
@Category({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(serverProps, javaProps));
}
}