You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by tu...@apache.org on 2015/08/27 14:27:18 UTC
[2/6] incubator-geode git commit: GEODE-77 : Integrated Security Code
Merge Review board url : https://reviews.apache.org/r/37209/
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d511979e/gemfire-core/src/main/java/com/gemstone/gemfire/security/TokenService.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/security/TokenService.java b/gemfire-core/src/main/java/com/gemstone/gemfire/security/TokenService.java
new file mode 100644
index 0000000..4a397ba
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/security/TokenService.java
@@ -0,0 +1,60 @@
+/**
+ *
+ */
+package com.gemstone.gemfire.security;
+
+import java.security.Principal;
+
+/**
+ * This interface provides APIs to generate and validate tokens for Geode REST
+ * clients.
+ * <p>
+ * A single instance of the implementing class per cache will created by Geode
+ * and these methods will be invoked on that same instance. Synchronization, if
+ * any, needs to be handled by the implementation itself.
+ */
+public interface TokenService {
+
+ /**
+ * Generates an unique token for the given principal. Geode REST service keeps
+ * track of each token and its associated client and only validates this token
+ * for each subsequent request from the same REST client, thus eliminating the
+ * need to explicitly authenticate it every time.
+ *
+ * <p>
+ * If a REST client sends its credentials in its subsequent requests, instead
+ * of the issued token, the Geode REST service treats it as a new client's
+ * request and issues a new token for it.
+ *
+ * @param principal
+ * the principal which the token is to be generated for.
+ * @return the generated token for the given principal.
+ */
+ public String generateToken(Principal principal);
+
+ /**
+ * Verifies that the provided token is a valid one for the provided principal.
+ * Optionally, it may replace this token by returning a new one. Thus, a new
+ * token is exchanged for each request from the client.
+ *
+ * <p>
+ * The REST client must send this returned token in its next request instead
+ * of the credentials. The method throws appropriate authentication exception
+ * if the token is not valid.
+ * <p>
+ * The implementation may expire the tokens after regular interval so as to
+ * minimise its possible misuse.
+ *
+ * @param token
+ * the token to be validated. This is the token the client had
+ * received in the previous response from the Geode REST service and
+ * has sent it back in its current request to the Geode REST service.
+ * @param principal
+ * the principal associated with the given token.
+ * @return the validated token. The implementation may also issue a new token
+ * replacing earlier one for the client.
+ */
+ public String validateToken(String token, Principal principal)
+ throws AuthenticationRequiredException, AuthenticationFailedException;
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d511979e/gemfire-core/src/test/java/com/gemstone/gemfire/internal/cache/extension/mock/MockExtensionCommands.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/cache/extension/mock/MockExtensionCommands.java b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/cache/extension/mock/MockExtensionCommands.java
index 89644f0..5e1f26d 100644
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/cache/extension/mock/MockExtensionCommands.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/cache/extension/mock/MockExtensionCommands.java
@@ -30,6 +30,9 @@ import com.gemstone.gemfire.management.internal.cli.result.ResultBuilder;
import com.gemstone.gemfire.management.internal.cli.result.TabularResultData;
import com.gemstone.gemfire.management.internal.configuration.SharedConfigurationWriter;
import com.gemstone.gemfire.management.internal.configuration.domain.XmlEntity;
+import com.gemstone.gemfire.management.internal.security.Resource;
+import com.gemstone.gemfire.management.internal.security.ResourceConstants;
+import com.gemstone.gemfire.management.internal.security.ResourceOperation;
/**
* Mock Extension gfsh commands.
@@ -70,6 +73,7 @@ public class MockExtensionCommands implements CommandMarker {
*/
@CliCommand(value = CREATE_MOCK_REGION_EXTENSION)
@CliMetaData(writesToSharedConfiguration = true)
+ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
public Result createMockRegionExtension(@CliOption(key = OPTION_REGION_NAME, mandatory = true) final String regionName,
@CliOption(key = OPTION_VALUE, mandatory = true) final String value) {
return executeFunctionOnAllMembersTabulateResultPersist(CreateMockRegionExtensionFunction.INSTANCE, true,
@@ -90,6 +94,7 @@ public class MockExtensionCommands implements CommandMarker {
*/
@CliCommand(value = ALTER_MOCK_REGION_EXTENSION)
@CliMetaData(writesToSharedConfiguration = true)
+ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
public Result alterMockRegionExtension(@CliOption(key = OPTION_REGION_NAME, mandatory = true) final String regionName,
@CliOption(key = OPTION_VALUE, mandatory = true) final String value) {
return executeFunctionOnAllMembersTabulateResultPersist(AlterMockRegionExtensionFunction.INSTANCE, true,
@@ -108,6 +113,7 @@ public class MockExtensionCommands implements CommandMarker {
*/
@CliCommand(value = DESTROY_MOCK_REGION_EXTENSION)
@CliMetaData(writesToSharedConfiguration = true)
+ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
public Result destroyMockRegionExtension(@CliOption(key = OPTION_REGION_NAME, mandatory = true) final String regionName) {
return executeFunctionOnAllMembersTabulateResultPersist(DestroyMockRegionExtensionFunction.INSTANCE, true,
DestroyMockRegionExtensionFunction.toArgs(regionName));
@@ -124,6 +130,7 @@ public class MockExtensionCommands implements CommandMarker {
*/
@CliCommand(value = CREATE_MOCK_CACHE_EXTENSION)
@CliMetaData(writesToSharedConfiguration = true)
+ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
public Result createMockCacheExtension(@CliOption(key = OPTION_VALUE, mandatory = true) final String value) {
return executeFunctionOnAllMembersTabulateResultPersist(CreateMockCacheExtensionFunction.INSTANCE, true, CreateMockCacheExtensionFunction.toArgs(value));
}
@@ -138,6 +145,7 @@ public class MockExtensionCommands implements CommandMarker {
* @since 8.1
*/
@CliCommand(value = ALTER_MOCK_CACHE_EXTENSION)
+ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
@CliMetaData(writesToSharedConfiguration = true)
public Result alterMockCacheExtension(@CliOption(key = OPTION_VALUE, mandatory = true) final String value) {
return executeFunctionOnAllMembersTabulateResultPersist(AlterMockCacheExtensionFunction.INSTANCE, true, AlterMockCacheExtensionFunction.toArgs(value));
@@ -150,6 +158,7 @@ public class MockExtensionCommands implements CommandMarker {
* @since 8.1
*/
@CliCommand(value = DESTROY_MOCK_CACHE_EXTENSION)
+ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
@CliMetaData(writesToSharedConfiguration = true)
public Result destroyMockCacheExtension() {
return executeFunctionOnAllMembersTabulateResultPersist(DestroyMockCacheExtensionFunction.INSTANCE, false);
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d511979e/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/cli/CommandManagerJUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/cli/CommandManagerJUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/cli/CommandManagerJUnitTest.java
index ab9333d..dea9d92 100644
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/cli/CommandManagerJUnitTest.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/cli/CommandManagerJUnitTest.java
@@ -37,8 +37,12 @@ import com.gemstone.gemfire.management.internal.cli.parser.Argument;
import com.gemstone.gemfire.management.internal.cli.parser.AvailabilityTarget;
import com.gemstone.gemfire.management.internal.cli.parser.CommandTarget;
import com.gemstone.gemfire.management.internal.cli.parser.Option;
+import com.gemstone.gemfire.management.internal.security.Resource;
+import com.gemstone.gemfire.management.internal.security.ResourceConstants;
+import com.gemstone.gemfire.management.internal.security.ResourceOperation;
import com.gemstone.gemfire.test.junit.categories.UnitTest;
+
/**
* CommandManagerTest - Includes tests to check the CommandManager functions
*
@@ -220,6 +224,7 @@ public class CommandManagerJUnitTest {
static public class Commands implements CommandMarker {
@CliCommand(value = { COMMAND1_NAME, COMMAND1_NAME_ALIAS }, help = COMMAND1_HELP)
@CliMetaData(shellOnly = true, relatedTopic = { "relatedTopicOfCommand1" })
+ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
public static String command1(
@CliArgument(name = ARGUMENT1_NAME, argumentContext = ARGUMENT1_CONTEXT, help = ARGUMENT1_HELP, mandatory = true)
String argument1,
@@ -235,11 +240,13 @@ public class CommandManagerJUnitTest {
}
@CliCommand(value = { COMMAND2_NAME })
+ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
public static String command2() {
return null;
}
@CliCommand(value = { "testParamConcat" })
+ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
public static Result testParamConcat(
@CliOption(key = { "string" })
String string,
@@ -256,6 +263,7 @@ public class CommandManagerJUnitTest {
}
@CliCommand(value = { "testMultiWordArg" })
+ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
public static Result testMultiWordArg(@CliArgument(name = "arg1")
String arg1, @CliArgument(name = "arg2")
String arg2) {
@@ -306,6 +314,7 @@ public class CommandManagerJUnitTest {
public static class MockPluginCommand implements CommandMarker {
@CliCommand(value = "mock plugin command")
+ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
public Result mockPluginCommand() {
return null;
}
@@ -313,6 +322,7 @@ public class CommandManagerJUnitTest {
public static class MockPluginCommandUnlisted implements CommandMarker {
@CliCommand(value = "mock plugin command unlisted")
+ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
public Result mockPluginCommandUnlisted() {
return null;
}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d511979e/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/cli/GfshParserJUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/cli/GfshParserJUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/cli/GfshParserJUnitTest.java
index 126bb88..4a0a431 100644
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/cli/GfshParserJUnitTest.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/cli/GfshParserJUnitTest.java
@@ -38,6 +38,9 @@ import com.gemstone.gemfire.management.internal.cli.converters.StringListConvert
import com.gemstone.gemfire.management.internal.cli.i18n.CliStrings;
import com.gemstone.gemfire.management.internal.cli.parser.SyntaxConstants;
import com.gemstone.gemfire.management.internal.cli.result.ResultBuilder;
+import com.gemstone.gemfire.management.internal.security.Resource;
+import com.gemstone.gemfire.management.internal.security.ResourceConstants;
+import com.gemstone.gemfire.management.internal.security.ResourceOperation;
import com.gemstone.gemfire.test.junit.categories.UnitTest;
/**
@@ -1042,6 +1045,7 @@ public class GfshParserJUnitTest {
static class Commands implements CommandMarker {
@CliCommand(value = { COMMAND1_NAME, COMMAND1_NAME_ALIAS }, help = COMMAND1_HELP)
+ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
public static String command1(
@CliArgument(name = ARGUMENT1_NAME, argumentContext = ARGUMENT1_CONTEXT, help = ARGUMENT1_HELP, mandatory = true)
String argument1,
@@ -1057,11 +1061,13 @@ public class GfshParserJUnitTest {
}
@CliCommand(value = { COMMAND2_NAME })
+ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
public static String command2() {
return null;
}
@CliCommand(value = { "testParamConcat" })
+ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
public static Result testParamConcat(
@CliOption(key = { "string" }) String string,
@CliOption(key = { "stringArray" }) @CliMetaData(valueSeparator = ",") String[] stringArray,
@@ -1072,6 +1078,7 @@ public class GfshParserJUnitTest {
}
@CliCommand(value = { "testMultiWordArg" })
+ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
public static Result testMultiWordArg(
@CliArgument(name = "arg1" ) String arg1,
@CliArgument(name = "arg2" ) String arg2) {
@@ -1128,17 +1135,18 @@ public class GfshParserJUnitTest {
static final String C2_MSG_AVAILABLE = C2_NAME + " is available.";
@CliCommand(value = { C1_NAME })
+ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
public Result command1() {
return ResultBuilder.createInfoResult(C1_MSG_AVAILABLE);
}
@CliCommand(value = { C2_NAME })
+ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
public Result command2() {
return ResultBuilder.createInfoResult(C2_MSG_AVAILABLE);
}
- @CliAvailabilityIndicator(C1_NAME)
- @CliMetaData.AvailabilityMetadata(availabilityDescription=C1_MSG_UNAVAILABLE)
+ @CliAvailabilityIndicator(C1_NAME)
public boolean isCommand1Available() {
return Boolean.getBoolean(C1_PROP);
}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d511979e/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/cli/shell/GfshExecutionStrategyJUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/cli/shell/GfshExecutionStrategyJUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/cli/shell/GfshExecutionStrategyJUnitTest.java
index 44aef44..659b407 100644
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/cli/shell/GfshExecutionStrategyJUnitTest.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/cli/shell/GfshExecutionStrategyJUnitTest.java
@@ -29,6 +29,9 @@ import com.gemstone.gemfire.management.internal.cli.result.ResultBuilder;
import com.gemstone.gemfire.management.internal.cli.shell.Gfsh;
import com.gemstone.gemfire.management.internal.cli.shell.GfshConfig;
import com.gemstone.gemfire.management.internal.cli.shell.GfshExecutionStrategy;
+import com.gemstone.gemfire.management.internal.security.Resource;
+import com.gemstone.gemfire.management.internal.security.ResourceConstants;
+import com.gemstone.gemfire.management.internal.security.ResourceOperation;
import com.gemstone.gemfire.test.junit.categories.UnitTest;
/**
@@ -92,17 +95,20 @@ public class GfshExecutionStrategyJUnitTest {
@CliCommand(value = { COMMAND1_NAME, COMMAND1_NAME_ALIAS }, help = COMMAND1_HELP)
@CliMetaData(shellOnly = true )
+ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
public static Result command1() {
return ResultBuilder.createInfoResult(COMMAND1_SUCESS);
}
@CliCommand(value = { COMMAND2_NAME })
@CliMetaData(shellOnly = false )
+ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
public static Result command2() {
return ResultBuilder.createInfoResult(COMMAND2_SUCESS);
}
@CliCommand(value = { "testParamConcat" })
+ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
public static Result testParamConcat(
@CliOption(key = { "string" })
String string,
@@ -119,6 +125,7 @@ public class GfshExecutionStrategyJUnitTest {
}
@CliCommand(value = { "testMultiWordArg" })
+ @ResourceOperation(resource = Resource.DISTRIBUTED_SYSTEM, operation= ResourceConstants.LIST_DS)
public static Result testMultiWordArg(@CliArgument(name = "arg1")
String arg1, @CliArgument(name = "arg2")
String arg2) {
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d511979e/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/security/JSONAuthCodeTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/security/JSONAuthCodeTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/security/JSONAuthCodeTest.java
index 384493b..fa9a292 100644
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/security/JSONAuthCodeTest.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/security/JSONAuthCodeTest.java
@@ -173,7 +173,7 @@ public class JSONAuthCodeTest extends TestCase {
}
private void checkAccessControlMBean() throws Exception {
- ObjectName name = new ObjectName(ManagementInterceptor.OBJECT_NAME_ACCESSCONTROL);
+ ObjectName name = new ObjectName(ResourceConstants.OBJECT_NAME_ACCESSCONTROL);
MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
Set<ObjectName> names = platformMBeanServer.queryNames(name, null);
assertFalse(names.isEmpty());
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d511979e/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/security/ResourceOperationJUnit.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/security/ResourceOperationJUnit.java b/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/security/ResourceOperationJUnit.java
index f061240..b88b56c 100644
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/security/ResourceOperationJUnit.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/management/internal/security/ResourceOperationJUnit.java
@@ -2,26 +2,37 @@ package com.gemstone.gemfire.management.internal.security;
import java.io.IOException;
import java.io.Serializable;
+import java.lang.annotation.Annotation;
import java.net.MalformedURLException;
import java.security.Principal;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.management.Attribute;
+import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.JMX;
import javax.management.MBeanException;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
+import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
+
+
import org.junit.experimental.categories.Category;
+
import junit.framework.TestCase;
import com.gemstone.gemfire.LogWriter;
@@ -33,10 +44,15 @@ import com.gemstone.gemfire.distributed.DistributedMember;
import com.gemstone.gemfire.distributed.DistributedSystem;
import com.gemstone.gemfire.distributed.internal.DistributionConfig;
import com.gemstone.gemfire.internal.AvailablePort;
+import com.gemstone.gemfire.internal.AvailablePortHelper;
import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
+import com.gemstone.gemfire.internal.logging.LogService;
import com.gemstone.gemfire.management.DistributedSystemMXBean;
import com.gemstone.gemfire.management.MemberMXBean;
import com.gemstone.gemfire.management.internal.MBeanJMXAdapter;
+import com.gemstone.gemfire.management.internal.cli.CommandManager;
+import com.gemstone.gemfire.management.internal.cli.parser.CommandTarget;
+import com.gemstone.gemfire.management.internal.cli.parser.GfshMethodTarget;
import com.gemstone.gemfire.management.internal.security.ResourceOperationContext.ResourceOperationCode;
import com.gemstone.gemfire.security.AccessControl;
import com.gemstone.gemfire.security.AuthenticationFailedException;
@@ -46,246 +62,457 @@ import com.gemstone.gemfire.test.junit.categories.UnitTest;
@Category(UnitTest.class)
public class ResourceOperationJUnit extends TestCase {
-
- public static class TestUsernamePrincipal implements Principal,
- Serializable {
-
- private final String userName;
-
- public TestUsernamePrincipal(String userName) {
- this.userName = userName;
- }
-
- public String getName() {
- return this.userName;
- }
-
- @Override
- public String toString() {
- return this.userName;
- }
-
- }
-
- public static class TestAuthenticator implements Authenticator {
-
- @Override
- public void close() {
-
- }
-
- @Override
- public void init(Properties securityProps, LogWriter systemLogger,
- LogWriter securityLogger) throws AuthenticationFailedException {
-
- }
-
- @Override
- public Principal authenticate(Properties props, DistributedMember member)
- throws AuthenticationFailedException {
- String user = props.getProperty(ManagementInterceptor.USER_NAME);
- String pwd = props.getProperty(ManagementInterceptor.PASSWORD);
- if (user!=null && !user.equals(pwd) && !"".equals(user))
- throw new AuthenticationFailedException(
- "Wrong username/password");
- System.out.println("Authentication successful!! for " + user);
- return new TestUsernamePrincipal(user);
- }
-
- }
-
- public static class TestAccessControl implements AccessControl {
-
- private Principal principal=null;
- @Override
- public void close() {
-
- }
-
- @Override
- public void init(Principal principal, DistributedMember remoteMember,
- Cache cache) throws NotAuthorizedException {
- this.principal = principal;
- }
-
- @Override
- public boolean authorizeOperation(String regionName,
- OperationContext context) {
- if(principal.getName().equals("tushark")) {
- ResourceOperationCode authorizedOps[] = {
- ResourceOperationCode.LIST_DS,
- ResourceOperationCode.READ_DS,
- ResourceOperationCode.CHANGE_ALERT_LEVEL_DS,
- ResourceOperationCode.LOCATE_ENTRY_REGION
- };
-
- System.out.println("Context received " + context);
-
- //if(context instanceof JMXOperationContext) {
- ResourceOperationContext ctx = (ResourceOperationContext)context;
- System.out.println("Checking for code " + ctx.getResourceOperationCode());
- boolean found = false;
- for(ResourceOperationCode code : authorizedOps) {
- if(ctx.getResourceOperationCode().equals(code)){
- found =true;
- System.out.println("found code " + code.toString());
- break;
- }
- }
- if(found)
- return true;
- System.out.println("Did not find code " + ctx.getResourceOperationCode());
- return false;
- //}
- }
- return false;
- }
-
- }
-
- public void testJMXOperationContext() {
- System.setProperty("resource-auth-accessor", "com.gemstone.gemfire.management.internal.security.ResourceOperationJUnit$TestAccessControl");
- System.setProperty("resource-authenticator", "com.gemstone.gemfire.management.internal.security.ResourceOperationJUnit$TestAuthenticator");
- GemFireCacheImpl cache = null;
- DistributedSystem ds = null;
- Properties pr = new Properties();
- pr.put("name", "testJMXOperationContext");
- pr.put(DistributionConfig.JMX_MANAGER_NAME, "true");
- pr.put(DistributionConfig.JMX_MANAGER_START_NAME, "true");
- int port = AvailablePort.getRandomAvailablePort(AvailablePort.SOCKET);
- pr.put(DistributionConfig.JMX_MANAGER_PORT_NAME, String.valueOf(port));
- pr.put(DistributionConfig.HTTP_SERVICE_PORT_NAME, "0");
- ds = getSystem(pr);
- cache = (GemFireCacheImpl) CacheFactory.create(ds);
- ObjectName name = MBeanJMXAdapter.getDistributedSystemName();
-
- String[] methods = {
- "listCacheServerObjectNames",
- "viewRemoteClusterStatus",
- "getTotalHeapSize",
- "setQueryCollectionsDepth",
- "getQueryCollectionsDepth",
- "changeAlertLevel",
- "backupAllMembers",
- "revokeMissingDiskStores",
- "shutDownAllMembers",
- "queryData",
- "queryDataForCompressedResult",
- "setQueryResultSetLimit",
- };
-
- ResourceOperationCode expectedCodes[] = {
- ResourceOperationCode.LIST_DS,
- ResourceOperationCode.LIST_DS,
- ResourceOperationCode.READ_DS,
- ResourceOperationCode.QUERYDATA_DS,
- ResourceOperationCode.READ_DS,
- ResourceOperationCode.CHANGE_ALERT_LEVEL_DS,
- ResourceOperationCode.BACKUP_DS,
- ResourceOperationCode.REMOVE_DISKSTORE_DS,
- ResourceOperationCode.SHUTDOWN_DS,
- ResourceOperationCode.QUERYDATA_DS,
- ResourceOperationCode.QUERYDATA_DS,
- ResourceOperationCode.QUERYDATA_DS
- };
-
- for(int i=0;i<methods.length;i++) {
- String methodName = methods[i];
- JMXOperationContext context = new JMXOperationContext(name, methodName);
- assertEquals(expectedCodes[i],
- context.getResourceOperationCode());
- assertEquals(OperationCode.RESOURCE, context.getOperationCode());
- }
-
- JMXConnector cs = getGemfireMBeanServer(port, "tushark", "tushark");;
- MBeanServerConnection mbeanServer =null;
- try {
- mbeanServer = cs.getMBeanServerConnection();
- mbeanServer.invoke(MBeanJMXAdapter.getDistributedSystemName(), "listCacheServerObjectNames", null, null);
- String oldLevel = (String)mbeanServer.getAttribute(MBeanJMXAdapter.getDistributedSystemName(), "AlertLevel");
- System.out.println("Old Level = " + oldLevel);
- mbeanServer.invoke(MBeanJMXAdapter.getDistributedSystemName(), "changeAlertLevel", new Object[]{"WARNING"},new String[]{
- String.class.getCanonicalName()
- });
- String newLevel = (String)mbeanServer.getAttribute(MBeanJMXAdapter.getDistributedSystemName(), "AlertLevel");
- System.out.println("New Level = " + newLevel);
-
-
- //Checking accessControlMXBean
- System.out.println("Checking access via AccessControlMbean");
- ResourceOperationCode authorizedOps[] = {
- ResourceOperationCode.LIST_DS,
- ResourceOperationCode.READ_DS,
- ResourceOperationCode.CHANGE_ALERT_LEVEL_DS,
- ResourceOperationCode.LOCATE_ENTRY_REGION
- };
- ObjectName accControlON = new ObjectName(ManagementInterceptor.OBJECT_NAME_ACCESSCONTROL);
- for(ResourceOperationCode c : authorizedOps) {
- boolean result = (Boolean) mbeanServer.invoke(accControlON, "authorize"
- , new Object[]{ResourceOperationCode.CHANGE_ALERT_LEVEL_DS.toString()}
- , new String[]{String.class.getCanonicalName()});
- assertTrue(result);
- }
-
- boolean result = (Boolean) mbeanServer.invoke(accControlON, "authorize"
- , new Object[]{ResourceOperationCode.ADMIN_DS.toString()}
- , new String[]{String.class.getCanonicalName()});
- assertFalse(result);
-
- } catch (InstanceNotFoundException e1) {
- e1.printStackTrace();
- fail("Error while invoking JMXRMI " + e1.getMessage());
- } catch (MBeanException e1) {
- e1.printStackTrace();
- fail("Error while invoking JMXRMI " + e1.getMessage());
- } catch (ReflectionException e1) {
- fail("Error while invoking JMXRMI " + e1.getMessage());
- } catch (IOException e1) {
- fail("Error while invoking JMXRMI " + e1.getMessage());
- } catch (AttributeNotFoundException e) {
- fail("Error while invoking JMXRMI" + e.getMessage());
- } catch (MalformedObjectNameException e) {
- fail("Error while invoking JMXRMI" + e.getMessage());
+
+ public static class TestUsernamePrincipal implements Principal,
+ Serializable {
+
+ private final String userName;
+
+ public TestUsernamePrincipal(String userName) {
+ this.userName = userName;
+ }
+
+ public String getName() {
+ return this.userName;
+ }
+
+ @Override
+ public String toString() {
+ return this.userName;
+ }
+
+ }
+
+ public static class TestAuthenticator implements Authenticator {
+
+ @Override
+ public void close() {
+
+ }
+
+ @Override
+ public void init(Properties securityProps, LogWriter systemLogger,
+ LogWriter securityLogger) throws AuthenticationFailedException {
+
+ }
+
+ @Override
+ public Principal authenticate(Properties props, DistributedMember member)
+ throws AuthenticationFailedException {
+ String mysecret = props.getProperty("GoTSecret");
+ props.list(System.out);
+ if (mysecret == null) {
+ String user = props.getProperty(ResourceConstants.USER_NAME);
+ String pwd = props.getProperty(ResourceConstants.PASSWORD);
+ if (user != null && !user.equals(pwd) && !"".equals(user))
+ throw new AuthenticationFailedException("Wrong username/password");
+ System.out.println("Authentication successful!! for " + user);
+ return new TestUsernamePrincipal(user);
+ } else {
+ if (mysecret.equals("JohnSnowIsIceAndFire")) {
+ System.out.println("Authentication successful!! for IronThrone");
+ return new TestUsernamePrincipal("IronThrone");
+ } else
+ throw new AuthenticationFailedException("Wrong username/password");
+ }
+ }
+
+ public static Authenticator create() {
+ return new TestAuthenticator();
+ }
+
+ }
+
+ public static class TestAccessControl implements AccessControl {
+
+ private Principal principal=null;
+ public static AtomicInteger preCallsTL = new AtomicInteger(0);
+ public static AtomicInteger postCallsTL = new AtomicInteger(0);
+
+ public static boolean failPostOpIntentionally = false;
+
+ public static AccessControl create(){
+ return new TestAccessControl();
+ }
+
+ static {
+ resetCallsCounter();
+ }
+
+ public static void resetCallsCounter() {
+ preCallsTL.set(0);
+ postCallsTL.set(0);
+ }
+
+ @Override
+ public void close() {
+
+ }
+
+ @Override
+ public void init(Principal principal, DistributedMember remoteMember,
+ Cache cache) throws NotAuthorizedException {
+ this.principal = principal;
+ }
+
+ private void increaseCount(OperationContext context) {
+ if (!(context instanceof AccessControlContext)) {
+ if (context.isPostOperation()) {
+ postCallsTL.incrementAndGet();
+ System.out.println("Context Received " + context + " isPostOp=" + context.isPostOperation() + " calls="
+ + postCallsTL.get());
+ } else {
+ preCallsTL.incrementAndGet();
+ System.out.println("Context Received " + context + " isPreOp=" + context.isPostOperation() + " calls="
+ + preCallsTL.get());
+ }
+ }
+ }
+
+ @Override
+ public boolean authorizeOperation(String regionName,
+ OperationContext context) {
+
+ if(context.isPostOperation() && failPostOpIntentionally) {
+ System.out.println("Failing AuthZ since failPostOpIntentionally=true");
+ return false;
+ }
+
+ if(principal.getName().equals("tushark") || principal.getName().equals("IronThrone")) {
+ ResourceOperationCode authorizedOps[] = {
+ ResourceOperationCode.LIST_DS,
+ ResourceOperationCode.CHANGE_ALERT_LEVEL,
+ ResourceOperationCode.LOCATE_ENTRY,
+ ResourceOperationCode.QUERY
+ };
+
+ LogService.getLogger().info("Context received " + context);
+ ResourceOperationContext ctx = (ResourceOperationContext) context;
+ LogService.getLogger().info("Checking for code " + ctx.getResourceOperationCode());
+ boolean found = false;
+ for (ResourceOperationCode code : authorizedOps) {
+ if (ctx.getResourceOperationCode().equals(code)) {
+ found = true;
+ LogService.getLogger().info("found code " + code.toString());
+ break;
+ }
+ }
+ if (found) {
+ increaseCount(context);
+ return true;
+ }
+ LogService.getLogger().info("Did not find code " + ctx.getResourceOperationCode());
+ return false;
+ }
+ return false;
+ }
+
+ }
+
+ public void testJMXOperationContext() {
+ TestAccessControl.resetCallsCounter();
+ GemFireCacheImpl cache = null;
+ DistributedSystem ds = null;
+ Properties pr = new Properties();
+ pr.put("name", "testJMXOperationContext");
+ pr.put(DistributionConfig.JMX_MANAGER_NAME, "true");
+ pr.put(DistributionConfig.JMX_MANAGER_START_NAME, "true");
+ int port = AvailablePort.getRandomAvailablePort(AvailablePort.SOCKET);
+ pr.put(DistributionConfig.JMX_MANAGER_PORT_NAME, String.valueOf(port));
+ pr.put(DistributionConfig.HTTP_SERVICE_PORT_NAME, "0");
+
+ pr.put(DistributionConfig.SECURITY_CLIENT_AUTHENTICATOR_NAME, "com.gemstone.gemfire.management.internal.security.ResourceOperationJUnit$TestAuthenticator.create");
+ pr.put(DistributionConfig.SECURITY_CLIENT_ACCESSOR_NAME, "com.gemstone.gemfire.management.internal.security.ResourceOperationJUnit$TestAccessControl.create");
+ pr.put(DistributionConfig.SECURITY_CLIENT_ACCESSOR_PP_NAME, "com.gemstone.gemfire.management.internal.security.ResourceOperationJUnit$TestAccessControl.create");
+
+ ds = getSystem(pr);
+ cache = (GemFireCacheImpl) CacheFactory.create(ds);
+ ObjectName name = MBeanJMXAdapter.getDistributedSystemName();
+
+ String[] methods = {
+ "listCacheServerObjectNames",
+ "viewRemoteClusterStatus",
+ "getTotalHeapSize",
+ "setQueryCollectionsDepth",
+ "getQueryCollectionsDepth",
+ "changeAlertLevel",
+ "backupAllMembers",
+ "revokeMissingDiskStores",
+ "shutDownAllMembers",
+ "queryData",
+ "queryDataForCompressedResult",
+ "setQueryResultSetLimit",
+ };
+
+ ResourceOperationCode expectedCodes[] = {
+ ResourceOperationCode.LIST_DS,
+ ResourceOperationCode.LIST_DS,
+ ResourceOperationCode.LIST_DS,
+ ResourceOperationCode.QUERY,
+ ResourceOperationCode.LIST_DS,
+ ResourceOperationCode.CHANGE_ALERT_LEVEL,
+ ResourceOperationCode.BACKUP_MEMBERS,
+ ResourceOperationCode.REVOKE_MISSING_DISKSTORE,
+ ResourceOperationCode.SHUTDOWN,
+ ResourceOperationCode.QUERY,
+ ResourceOperationCode.QUERY,
+ ResourceOperationCode.QUERY
+ };
+
+ for(int i=0;i<methods.length;i++) {
+ String methodName = methods[i];
+ JMXOperationContext context = new JMXOperationContext(name, methodName);
+ assertEquals(expectedCodes[i],
+ context.getResourceOperationCode());
+ assertEquals(OperationCode.RESOURCE, context.getOperationCode());
+ }
+
+ JMXConnector cs = getGemfireMBeanServer(port, "tushark", "tushark");;
+ MBeanServerConnection mbeanServer =null;
+ int totalCalls=-1;
+ try {
+ mbeanServer = cs.getMBeanServerConnection();
+ mbeanServer.invoke(MBeanJMXAdapter.getDistributedSystemName(), "listCacheServerObjectNames", null, null);
+ String oldLevel = (String)mbeanServer.getAttribute(MBeanJMXAdapter.getDistributedSystemName(), "AlertLevel");
+ System.out.println("Old Level = " + oldLevel);
+ mbeanServer.invoke(MBeanJMXAdapter.getDistributedSystemName(), "changeAlertLevel", new Object[]{"WARNING"},new String[]{
+ String.class.getCanonicalName()
+ });
+ String newLevel = (String)mbeanServer.getAttribute(MBeanJMXAdapter.getDistributedSystemName(), "AlertLevel");
+ System.out.println("New Level = " + newLevel);
+
+
+ //totalCalls = 1 for listCacheServerObjectNames + changeAlertLevel + 2 for AlertLevel attr
+ totalCalls = 2 + 2 ;
+ totalCalls += checkGetAttributesAndSetAttributes(mbeanServer);
+ assertEquals(totalCalls, (int)TestAccessControl.preCallsTL.get());
+ assertEquals(totalCalls, (int)TestAccessControl.postCallsTL.get());
+ checkAcceeControlMXBean(mbeanServer);
+
+ } catch (InstanceNotFoundException e1) {
+ e1.printStackTrace();
+ fail("Error while invoking JMXRMI " + e1.getMessage());
+ } catch (MBeanException e1) {
+ e1.printStackTrace();
+ fail("Error while invoking JMXRMI " + e1.getMessage());
+ } catch (ReflectionException e1) {
+ fail("Error while invoking JMXRMI " + e1.getMessage());
+ } catch (IOException e1) {
+ fail("Error while invoking JMXRMI " + e1.getMessage());
+ } catch (AttributeNotFoundException e) {
+ fail("Error while invoking JMXRMI" + e.getMessage());
+ } catch (MalformedObjectNameException e) {
+ fail("Error while invoking JMXRMI" + e.getMessage());
+ }
+
+ try {
+ mbeanServer.invoke(MBeanJMXAdapter.getDistributedSystemName(),
+ "backupAllMembers",
+ new Object[]{"targetPath","baseLinePath"},
+ new String[]{String.class.getCanonicalName(), String.class.getCanonicalName()});
+ fail("Should not be authorized for backupAllMembers");
+ } catch (SecurityException e) {
+ //expected
+ } catch(Exception e){
+ e.printStackTrace();
+ fail("Unexpected exception : " + e.getMessage());
}
-
- try {
- mbeanServer.invoke(MBeanJMXAdapter.getDistributedSystemName(),
- "backupAllMembers",
- new Object[]{"targetPath","baseLinePath"},
- new String[]{String.class.getCanonicalName(), String.class.getCanonicalName()});
- fail("Should not be authorized for backupAllMembers");
- } catch (SecurityException e) {
- //expected
- } catch(Exception e){
- e.printStackTrace();
- fail("Unexpected exception : " + e.getMessage());
- }
-
- try {
- mbeanServer.invoke(MBeanJMXAdapter.getDistributedSystemName(),
- "shutDownAllMembers",null,null);
- fail("Should not be authorized for shutDownAllMembers");
- } catch (SecurityException e) {
- //expected
- } catch(Exception e){
- fail("Unexpected exception : " + e.getMessage());
- }
-
- checkCLIContext(mbeanServer);
-
- try {
- cs.close();
- } catch (IOException e) {
- fail("Unexpected exception : " + e.getMessage());
- }
-
-
-
-
- cache.close();
- ds.disconnect();
- }
-
+
+ try {
+ mbeanServer.invoke(MBeanJMXAdapter.getDistributedSystemName(),
+ "shutDownAllMembers",null,null);
+ fail("Should not be authorized for shutDownAllMembers");
+ } catch (SecurityException e) {
+ //expected
+ } catch(Exception e){
+ fail("Unexpected exception : " + e.getMessage());
+ }
+
+ //2 unsuccessful calls
+ assertEquals(totalCalls, (int)TestAccessControl.preCallsTL.get());
+ assertEquals(totalCalls, (int)TestAccessControl.postCallsTL.get());
+
+ checkCLIContext(mbeanServer);totalCalls += 2;
+ assertEquals(totalCalls, (int)TestAccessControl.preCallsTL.get());
+ assertEquals(totalCalls, (int)TestAccessControl.postCallsTL.get());
+
+ //Simulate a condition where accessControl return false during postOpAuthZ
+ TestAccessControl.failPostOpIntentionally = true;
+ for(int i=1;i<=3;i++) {
+ try {
+ mbeanServer.invoke(MBeanJMXAdapter.getDistributedSystemName(), "changeAlertLevel", new Object[] { "WARNING" },
+ new String[] { String.class.getCanonicalName() });
+ } catch (InstanceNotFoundException e) {
+ fail("Unexpected exception : " + e.getMessage());
+ } catch (MBeanException e) {
+ fail("Unexpected exception : " + e.getMessage());
+ } catch (ReflectionException e) {
+ fail("Unexpected exception : " + e.getMessage());
+ } catch (IOException e) {
+ fail("Unexpected exception : " + e.getMessage());
+ } catch (SecurityException e) {
+ //expected
+ assertEquals(totalCalls+i, (int)TestAccessControl.preCallsTL.get());
+ assertEquals(totalCalls, (int)TestAccessControl.postCallsTL.get());
+ }
+ }
+ TestAccessControl.failPostOpIntentionally = false;
+ try {
+ cs.close();
+ } catch (IOException e) {
+ fail("Unexpected exception : " + e.getMessage());
+ }
+
+ cache.close();
+ ds.disconnect();
+ }
+
+ private int checkGetAttributesAndSetAttributes(MBeanServerConnection mbeanServer) throws InstanceNotFoundException, ReflectionException, IOException {
+ AttributeList list = mbeanServer.getAttributes(MBeanJMXAdapter.getDistributedSystemName(),
+ new String[]{"TotalHeapSize","TotalRegionEntryCount","TotalRegionCount","TotalMissCount"});
+ assertNotNull(list);
+ assertEquals(4,list.size());
+ list = new AttributeList();
+ list.add(new Attribute("QueryResultSetLimit", 1000));
+ list.add(new Attribute("QueryCollectionsDepth",1000));
+ list = mbeanServer.setAttributes(MBeanJMXAdapter.getDistributedSystemName(),list);
+ assertNotNull(list);
+ assertEquals(2,list.size());
+ return 3;
+ }
+
+ public void testOnlyAuthenticatorNoAuthorization() {
+ TestAccessControl.resetCallsCounter();
+ GemFireCacheImpl cache = null;
+ DistributedSystem ds = null;
+ Properties pr = new Properties();
+ pr.put("name", "testJMXOperationContext");
+ pr.put(DistributionConfig.JMX_MANAGER_NAME, "true");
+ pr.put(DistributionConfig.JMX_MANAGER_START_NAME, "true");
+ int port = AvailablePortHelper.getRandomAvailableTCPPort();
+ pr.put(DistributionConfig.JMX_MANAGER_PORT_NAME, String.valueOf(port));
+ pr.put(DistributionConfig.HTTP_SERVICE_PORT_NAME, "0");
+ pr.put(DistributionConfig.SECURITY_CLIENT_AUTHENTICATOR_NAME, "com.gemstone.gemfire.management.internal.security.ResourceOperationJUnit$TestAuthenticator.create");
+ ds = getSystem(pr);
+ cache = (GemFireCacheImpl) CacheFactory.create(ds);
+ JMXConnector cs = getGemfireMBeanServer(port, "tushark", "tushark");;
+ MBeanServerConnection mbeanServer =null;
+ try {
+ mbeanServer = cs.getMBeanServerConnection();
+ mbeanServer.invoke(MBeanJMXAdapter.getDistributedSystemName(), "listCacheServerObjectNames", null, null);
+ String oldLevel = (String)mbeanServer.getAttribute(MBeanJMXAdapter.getDistributedSystemName(), "AlertLevel");
+ System.out.println("Old Level = " + oldLevel);
+ mbeanServer.invoke(MBeanJMXAdapter.getDistributedSystemName(), "changeAlertLevel", new Object[]{"WARNING"},new String[]{
+ String.class.getCanonicalName()
+ });
+ String newLevel = (String)mbeanServer.getAttribute(MBeanJMXAdapter.getDistributedSystemName(), "AlertLevel");
+ System.out.println("New Level = " + newLevel);
+ //totalCalls = 0 since not AccessControl is invoked
+ assertEquals(0, (int)TestAccessControl.preCallsTL.get());
+ assertEquals(0, (int)TestAccessControl.postCallsTL.get());
+ } catch (InstanceNotFoundException e1) {
+ e1.printStackTrace();
+ fail("Error while invoking JMXRMI " + e1.getMessage());
+ } catch (MBeanException e1) {
+ e1.printStackTrace();
+ fail("Error while invoking JMXRMI " + e1.getMessage());
+ } catch (ReflectionException e1) {
+ fail("Error while invoking JMXRMI " + e1.getMessage());
+ } catch (IOException e1) {
+ fail("Error while invoking JMXRMI " + e1.getMessage());
+ } catch (AttributeNotFoundException e) {
+ fail("Error while invoking JMXRMI" + e.getMessage());
+ }
+ cache.close();
+ ds.disconnect();
+ }
+
+ public void testAuthenticationUsingPropertiesBag(){
+ TestAccessControl.resetCallsCounter();
+ GemFireCacheImpl cache = null;
+ DistributedSystem ds = null;
+ Properties pr = new Properties();
+ pr.put("name", "testJMXOperationContext");
+ pr.put(DistributionConfig.JMX_MANAGER_NAME, "true");
+ pr.put(DistributionConfig.JMX_MANAGER_START_NAME, "true");
+ int port = AvailablePortHelper.getRandomAvailableTCPPort();
+ pr.put(DistributionConfig.JMX_MANAGER_PORT_NAME, String.valueOf(port));
+ pr.put(DistributionConfig.HTTP_SERVICE_PORT_NAME, "0");
+ pr.put(DistributionConfig.SECURITY_CLIENT_AUTHENTICATOR_NAME, "com.gemstone.gemfire.management.internal.security.ResourceOperationJUnit$TestAuthenticator.create");
+ pr.put(DistributionConfig.SECURITY_CLIENT_ACCESSOR_NAME, "com.gemstone.gemfire.management.internal.security.ResourceOperationJUnit$TestAccessControl.create");
+ pr.put(DistributionConfig.SECURITY_CLIENT_ACCESSOR_PP_NAME, "com.gemstone.gemfire.management.internal.security.ResourceOperationJUnit$TestAccessControl.create");
+ ds = getSystem(pr);
+ cache = (GemFireCacheImpl) CacheFactory.create(ds);
+
+ Properties userProperties = new Properties();
+ userProperties.put("GoTSecret", "JohnSnowIsIceAndFire");
+ JMXConnector cs = getGemfireMBeanServer(port, userProperties);
+ MBeanServerConnection mbeanServer =null;
+ try {
+ mbeanServer = cs.getMBeanServerConnection();
+ String oldLevel = (String)mbeanServer.getAttribute(MBeanJMXAdapter.getDistributedSystemName(), "AlertLevel");
+ System.out.println("Old Level = " + oldLevel);
+ cs.close();
+ } catch (InstanceNotFoundException e1) {
+ e1.printStackTrace();
+ fail("Error while invoking JMXRMI " + e1.getMessage());
+ } catch (MBeanException e1) {
+ e1.printStackTrace();
+ fail("Error while invoking JMXRMI " + e1.getMessage());
+ } catch (ReflectionException e1) {
+ fail("Error while invoking JMXRMI " + e1.getMessage());
+ } catch (IOException e1) {
+ fail("Error while invoking JMXRMI " + e1.getMessage());
+ } catch (AttributeNotFoundException e) {
+ fail("Error while invoking JMXRMI" + e.getMessage());
+ }
+
+ try {
+ userProperties = new Properties();
+ userProperties.put("GoTSecret", "JoffreyIsRightfulKing");
+ cs = getGemfireMBeanServer(port, userProperties);
+ fail("Authentication should fail");
+ } catch (AuthenticationFailedException e) {
+ //expected
+ } catch (SecurityException e) {
+ //expected
+ } catch(Exception e){
+ e.printStackTrace();
+ fail("Unexpected error " + e.getMessage());
+ }
+ cache.close();
+ ds.disconnect();
+ }
+
+ private void checkAcceeControlMXBean(MBeanServerConnection mbeanServer) throws MalformedObjectNameException,
+ InstanceNotFoundException, MBeanException, ReflectionException, IOException {
+ // Checking accessControlMXBean
+ System.out.println("Checking access via AccessControlMbean");
+ ResourceOperationCode authorizedOps[] = { ResourceOperationCode.LIST_DS, ResourceOperationCode.LIST_DS,
+ ResourceOperationCode.CHANGE_ALERT_LEVEL, ResourceOperationCode.LOCATE_ENTRY };
+ ObjectName accControlON = new ObjectName(ResourceConstants.OBJECT_NAME_ACCESSCONTROL);
+ for (ResourceOperationCode c : authorizedOps) {
+ boolean result = (Boolean) mbeanServer.invoke(accControlON, "authorize",
+ new Object[] { c.toString() },
+ new String[] { String.class.getCanonicalName() });
+ assertTrue(result);
+ }
+
+ //check accessControlMBean is hidden from generic listing
+ Set<ObjectInstance> instanceSet = mbeanServer.queryMBeans(null, null);
+ for(ObjectInstance oi : instanceSet) {
+ if(oi.getObjectName().equals(accControlON))
+ fail("Found AccessControl Mbean in queryMbeans");
+ }
+
+ Set<ObjectName> onSet = mbeanServer.queryNames(null, null);
+ for(ObjectName on : onSet) {
+ if(on.equals(accControlON))
+ fail("Found AccessControl Mbean in queryNames");
+ }
+
+ }
+
private void checkCLIContext(MBeanServerConnection mbeanServer) {
DistributedSystemMXBean proxy = JMX.newMXBeanProxy(mbeanServer, MBeanJMXAdapter.getDistributedSystemName(),
DistributedSystemMXBean.class);
@@ -298,81 +525,198 @@ public class ResourceOperationJUnit extends TestCase {
System.out.println("Result = " + result);
} catch (Exception e) {
System.out.println("Excpetion e " + e.getMessage());
- e.printStackTrace();
+ fail(e.getMessage());
+ }
+ }
+
+ public void testAllCommandsAreAnnotated() {
+ GemFireCacheImpl cache = null;
+ DistributedSystem ds = null;
+ Properties pr = new Properties();
+ pr.put("name", "testJMXOperationContext");
+ pr.put(DistributionConfig.JMX_MANAGER_NAME, "true");
+ pr.put(DistributionConfig.JMX_MANAGER_START_NAME, "true");
+ int port = AvailablePortHelper.getRandomAvailableTCPPort();
+ pr.put(DistributionConfig.JMX_MANAGER_PORT_NAME, String.valueOf(port));
+ pr.put(DistributionConfig.HTTP_SERVICE_PORT_NAME, "0");
+ pr.put(DistributionConfig.SECURITY_CLIENT_AUTHENTICATOR_NAME, "com.gemstone.gemfire.management.internal.security.ResourceOperationJUnit$TestAuthenticator.create");
+ pr.put(DistributionConfig.SECURITY_CLIENT_ACCESSOR_NAME, "com.gemstone.gemfire.management.internal.security.ResourceOperationJUnit$TestAccessControl.create");
+ pr.put(DistributionConfig.SECURITY_CLIENT_ACCESSOR_PP_NAME, "com.gemstone.gemfire.management.internal.security.ResourceOperationJUnit$TestAccessControl.create");
+ ds = getSystem(pr);
+ cache = (GemFireCacheImpl) CacheFactory.create(ds);
+
+ CommandManager manager = CommandManager.getExisting();
+ List<String> notFoundList = new ArrayList<String>();
+ Map<String,CommandTarget> map = manager.getCommands();
+ for(Map.Entry<String,CommandTarget> entry : map.entrySet()) {
+ String commandName = entry.getKey();
+ CommandTarget target = entry.getValue();
+ GfshMethodTarget methodTarget = target.getGfshMethodTarget();
+ boolean found=false;
+ Annotation ans[] = methodTarget.getMethod().getDeclaredAnnotations();
+ for(Annotation an : ans){
+ if(an instanceof ResourceOperation) {
+ String opcode= ((ResourceOperation) an).operation();
+ LogService.getLogger().info("For command " + commandName + " OpCode="+ opcode);
+ found = true;
+ }
+ }
+ if(!found)
+ notFoundList.add(commandName);
+ }
+ System.out.println("Command without any annotation " + notFoundList);
+ assertEquals(0,notFoundList.size());
+ cache.close();
+ ds.disconnect();
+ }
+
+ public void testCLIOperationContext() {
+ GemFireCacheImpl cache = null;
+ DistributedSystem ds = null;
+ Properties pr = new Properties();
+ pr.put("name", "testJMXOperationContext");
+ pr.put(DistributionConfig.JMX_MANAGER_NAME, "true");
+ pr.put(DistributionConfig.JMX_MANAGER_START_NAME, "true");
+ int port = AvailablePort.getRandomAvailablePort(AvailablePort.SOCKET);
+ pr.put(DistributionConfig.JMX_MANAGER_PORT_NAME, String.valueOf(port));
+ pr.put(DistributionConfig.HTTP_SERVICE_PORT_NAME, "0");
+ pr.put(DistributionConfig.SECURITY_CLIENT_AUTHENTICATOR_NAME, "com.gemstone.gemfire.management.internal.security.ResourceOperationJUnit$TestAuthenticator.create");
+ pr.put(DistributionConfig.SECURITY_CLIENT_ACCESSOR_NAME, "com.gemstone.gemfire.management.internal.security.ResourceOperationJUnit$TestAccessControl.create");
+ pr.put(DistributionConfig.SECURITY_CLIENT_ACCESSOR_PP_NAME, "com.gemstone.gemfire.management.internal.security.ResourceOperationJUnit$TestAccessControl.create");
+ ds = getSystem(pr);
+ cache = (GemFireCacheImpl) CacheFactory.create(ds);
+
+ String[] commands = {
+ "export data --region=value --file=value --member=value",
+ "import data --region=value --file=value --member=value",
+ "rebalance",
+ "get --key=k1 --region=/region1",
+ "put --key=k1 --value=v1 --region=/region1",
+ "locate entry --key=k1 --region=/region1",
+ "query --query=\"select * from /region1\"",
+ "remove --key=k1 --region=/region1",
+ "remove --region=/region1 --all=true", //region clear
+ "create region --name=r1 --type=REPLICATE",
+ "destroy region --name=/r1",
+ "execute function --id=func1",
+ "close durable-cq --durable-client-id=value --durable-cq-name=value"
+ //"stop cq"
+ //"removeall",
+ //"get durable cqs",
+ };
+
+ ResourceOperationCode expectedResourceCodes[] = {
+ ResourceOperationCode.EXPORT_DATA,
+ ResourceOperationCode.IMPORT_DATA,
+ ResourceOperationCode.REBALANCE,
+ ResourceOperationCode.GET,
+ ResourceOperationCode.PUT,
+ ResourceOperationCode.LOCATE_ENTRY,
+ ResourceOperationCode.QUERY,
+ ResourceOperationCode.REMOVE,
+ ResourceOperationCode.REMOVE,
+ ResourceOperationCode.CREATE_REGION,
+ ResourceOperationCode.DESTROY_REGION,
+ ResourceOperationCode.EXECUTE_FUNCTION,
+ ResourceOperationCode.CLOSE_DURABLE_CQ,
+ };
+
+ OperationCode expectedOpCodes[] = {
+ OperationCode.RESOURCE,
+ OperationCode.RESOURCE,
+ OperationCode.RESOURCE,
+ OperationCode.GET,
+ OperationCode.PUT,
+ OperationCode.GET,
+ OperationCode.QUERY,
+ OperationCode.DESTROY,
+ OperationCode.REMOVEALL,
+ OperationCode.REGION_CREATE,
+ OperationCode.REGION_DESTROY,
+ OperationCode.EXECUTE_FUNCTION,
+ OperationCode.CLOSE_CQ,
+ };
+
+ for(int i=0;i<commands.length;i++){
+ CLIOperationContext ctx = new CLIOperationContext(commands[i]);
+ System.out.println("Context " + ctx);
+ assertEquals(expectedResourceCodes[i],ctx.getResourceOperationCode());
+ assertEquals(expectedOpCodes[i],ctx.getOperationCode());
+ }
+
+ cache.close();
+ ds.disconnect();
+ }
+
+ public void testResourceOpCodeAllowedOp() {
+ assertTrue(ResourceOperationCode.ADMIN.allowedOp(ResourceOperationCode.LIST_DS));
+ assertTrue(ResourceOperationCode.DATA_READ.allowedOp(ResourceOperationCode.LIST_DS));
+ assertTrue(ResourceOperationCode.DATA_WRITE.allowedOp(ResourceOperationCode.LIST_DS));
+ assertTrue(ResourceOperationCode.MONITOR.allowedOp(ResourceOperationCode.LIST_DS));
+
+ assertTrue(ResourceOperationCode.MONITOR.allowedOp(ResourceOperationCode.DATA_READ));
+ assertTrue(ResourceOperationCode.DATA_WRITE.allowedOp(ResourceOperationCode.DATA_READ));
+ assertTrue(ResourceOperationCode.ADMIN.allowedOp(ResourceOperationCode.DATA_READ));
+
+ assertTrue(ResourceOperationCode.MONITOR.allowedOp(ResourceOperationCode.PULSE_DASHBOARD));
+ assertTrue(ResourceOperationCode.DATA_WRITE.allowedOp(ResourceOperationCode.PULSE_DASHBOARD));
+ assertTrue(ResourceOperationCode.ADMIN.allowedOp(ResourceOperationCode.PULSE_DASHBOARD));
+
+ assertFalse(ResourceOperationCode.PULSE_DASHBOARD.allowedOp(ResourceOperationCode.BECOME_LOCK_GRANTOR));
+ assertTrue(ResourceOperationCode.PULSE_DASHBOARD.allowedOp(ResourceOperationCode.PULSE_DASHBOARD));
+
+ assertTrue(ResourceOperationCode.ADMIN.allowedOp(ResourceOperationCode.SHUTDOWN));
+ assertFalse(ResourceOperationCode.DATA_READ.allowedOp(ResourceOperationCode.SHUTDOWN));
+ assertFalse(ResourceOperationCode.DATA_WRITE.allowedOp(ResourceOperationCode.SHUTDOWN));
+ assertFalse(ResourceOperationCode.MONITOR.allowedOp(ResourceOperationCode.SHUTDOWN));
+
+ assertTrue(ResourceOperationCode.ADMIN.allowedOp(ResourceOperationCode.BECOME_LOCK_GRANTOR));
+ assertFalse(ResourceOperationCode.DATA_READ.allowedOp(ResourceOperationCode.BECOME_LOCK_GRANTOR));
+ assertTrue(ResourceOperationCode.DATA_WRITE.allowedOp(ResourceOperationCode.BECOME_LOCK_GRANTOR));
+ assertFalse(ResourceOperationCode.MONITOR.allowedOp(ResourceOperationCode.BECOME_LOCK_GRANTOR));
+
+ assertTrue(ResourceOperationCode.ADMIN.allowedOp(ResourceOperationCode.EXPORT_STACKTRACE));
+ assertFalse(ResourceOperationCode.DATA_READ.allowedOp(ResourceOperationCode.EXPORT_STACKTRACE));
+ assertFalse(ResourceOperationCode.DATA_WRITE.allowedOp(ResourceOperationCode.EXPORT_STACKTRACE));
+ assertTrue(ResourceOperationCode.MONITOR.allowedOp(ResourceOperationCode.EXPORT_STACKTRACE));
+ }
+
+ private JMXConnector getGemfireMBeanServer(int port, Properties pr) {
+ return _getGemfireMBeanServer(port, pr);
+ }
+
+ private JMXConnector getGemfireMBeanServer(int port, String user, String pwd) {
+ String[] creds = null;
+ if(user!=null)
+ creds = new String[]{ user, pwd };
+ return _getGemfireMBeanServer(port, creds);
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ private JMXConnector _getGemfireMBeanServer(int port, Object creds) {
+ JMXServiceURL url;
+ try {
+ url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:" + port + "/jmxrmi");
+ if (creds != null) {
+ Map env = new HashMap();
+ env.put(JMXConnector.CREDENTIALS, creds);
+ JMXConnector jmxc = JMXConnectorFactory.connect(url, env);
+ return jmxc;
+ } else {
+ JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
+ return jmxc;
+ }
+ } catch (MalformedURLException e) {
+ fail("Error connecting to port=" + port + " " + e.getMessage());
+ } catch (IOException e) {
+ fail("Error connecting to port=" + port + " " + e.getMessage());
}
+ return null;
}
- public void testCLIOperationContext() {
- System.setProperty("resource-auth-accessor", "com.gemstone.gemfire.management.internal.security.ResourceOperationJUnit$TestAccessControl");
- System.setProperty("resource-authenticator", "com.gemstone.gemfire.management.internal.security.ResourceOperationJUnit$TestAuthenticator");
- GemFireCacheImpl cache = null;
- DistributedSystem ds = null;
- Properties pr = new Properties();
- pr.put("name", "testJMXOperationContext");
- pr.put(DistributionConfig.JMX_MANAGER_NAME, "true");
- pr.put(DistributionConfig.JMX_MANAGER_START_NAME, "true");
- int port = AvailablePort.getRandomAvailablePort(AvailablePort.SOCKET);
- pr.put(DistributionConfig.JMX_MANAGER_PORT_NAME, String.valueOf(port));
- pr.put(DistributionConfig.HTTP_SERVICE_PORT_NAME, "0");
- ds = getSystem(pr);
- cache = (GemFireCacheImpl) CacheFactory.create(ds);
-
- String[] commands = {
- "put --key=k1 --value=v1 --region=/region1",
- "locate entry --key=k1 --region=/region1",
- "query --query=\"select * from /region1\"",
- "export data --region=value --file=value --member=value",
- "import data --region=value --file=value --member=value",
- "rebalance"
- };
-
- ResourceOperationCode expectedCodes[] = {
- ResourceOperationCode.PUT_REGION,
- ResourceOperationCode.LOCATE_ENTRY_REGION,
- ResourceOperationCode.QUERYDATA_DS,
- ResourceOperationCode.EXPORT_DATA_REGION,
- ResourceOperationCode.IMPORT_DATA_REGION,
- ResourceOperationCode.REBALANCE_DS
- };
-
- for(int i=0;i<commands.length;i++){
- CLIOperationContext ctx = new CLIOperationContext(commands[i]);
- System.out.println("Context " + ctx);
- assertEquals(expectedCodes[i],ctx.getResourceOperationCode());
- }
-
- cache.close();
- ds.disconnect();
- }
-
-
-
- private JMXConnector getGemfireMBeanServer(int port, String user, String pwd) {
- JMXServiceURL url;
- try {
- url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:"+ port +"/jmxrmi");
- if(user!=null){
- Map env = new HashMap();
- String[] creds = {user, pwd};
- env.put(JMXConnector.CREDENTIALS, creds);
- JMXConnector jmxc = JMXConnectorFactory.connect(url,env);
- return jmxc;
- } else {
- JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
- return jmxc;
- }
- } catch (MalformedURLException e) {
- fail("Error connecting to port=" + port + " " + e.getMessage());
- } catch (IOException e) {
- fail("Error connecting to port=" + port + " " + e.getMessage());
- }
- return null;
- }
-
-
-
- private static DistributedSystem getSystem(Properties properties) {
- return DistributedSystem.connect(properties);
- }
+ private static DistributedSystem getSystem(Properties properties) {
+ return DistributedSystem.connect(properties);
+ }
}
+
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d511979e/gemfire-core/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestTestUtils.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestTestUtils.java b/gemfire-core/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestTestUtils.java
index d2499fe..78210bd 100644
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestTestUtils.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/rest/internal/web/controllers/RestTestUtils.java
@@ -11,12 +11,14 @@ import java.net.URI;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
+
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
@@ -98,4 +100,12 @@ public class RestTestUtils {
return UriComponentsBuilder.fromUri(baseUrl).pathSegment(pathSegments)
.build().toUri();
}
+
+ public static String createRestURL(String baseURL, Object requestPart) {
+ if(StringUtils.isEmpty(requestPart)) {
+ return baseURL + RestTestUtils.GEMFIRE_REST_API_CONTEXT + RestTestUtils.GEMFIRE_REST_API_VERSION;
+ }else {
+ return baseURL + RestTestUtils.GEMFIRE_REST_API_CONTEXT + RestTestUtils.GEMFIRE_REST_API_VERSION + requestPart;
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d511979e/gemfire-web-api/src/main/java/com/gemstone/gemfire/rest/internal/web/controllers/AbstractBaseController.java
----------------------------------------------------------------------
diff --git a/gemfire-web-api/src/main/java/com/gemstone/gemfire/rest/internal/web/controllers/AbstractBaseController.java b/gemfire-web-api/src/main/java/com/gemstone/gemfire/rest/internal/web/controllers/AbstractBaseController.java
index feed8c7..2a44403 100644
--- a/gemfire-web-api/src/main/java/com/gemstone/gemfire/rest/internal/web/controllers/AbstractBaseController.java
+++ b/gemfire-web-api/src/main/java/com/gemstone/gemfire/rest/internal/web/controllers/AbstractBaseController.java
@@ -68,6 +68,7 @@ import com.gemstone.gemfire.rest.internal.web.exception.GemfireRestException;
import com.gemstone.gemfire.rest.internal.web.exception.MalformedJsonException;
import com.gemstone.gemfire.rest.internal.web.exception.RegionNotFoundException;
import com.gemstone.gemfire.rest.internal.web.exception.ResourceNotFoundException;
+import com.gemstone.gemfire.rest.internal.web.security.RestRequestFilter;
import com.gemstone.gemfire.rest.internal.web.util.ArrayUtils;
import com.gemstone.gemfire.rest.internal.web.util.IdentifiableUtils;
import com.gemstone.gemfire.rest.internal.web.util.JSONUtils;
@@ -96,6 +97,7 @@ public abstract class AbstractBaseController {
protected static final String UTF_8 = "UTF-8";
protected static final String DEFAULT_ENCODING = UTF_8;
private static final AtomicLong ID_SEQUENCE = new AtomicLong(0l);
+ protected static final String AUTH_TOKEN_HEADER = "security-gfrest-authtoken";
//private Cache cache = GemFireCacheImpl.getExisting(null);
@@ -184,13 +186,13 @@ public abstract class AbstractBaseController {
}
}
- public ResponseEntity<String> processQueryResponse (Object queryResult, String queryId) throws JSONException {
+ public ResponseEntity<String> processQueryResponse (Object queryResult, String queryId, HttpHeaders headers) throws JSONException {
if(queryResult instanceof Collection<?>){
Collection<Object> result = (Collection<Object>) queryResult;
String queryResultAsJson = JSONUtils.convertCollectionToJson(result);
- final HttpHeaders headers = new HttpHeaders();
- headers.setLocation(toUri("queries", queryId));
+ headers.setLocation(toUri("queries", queryId));
+
return new ResponseEntity<String>(queryResultAsJson, headers, HttpStatus.OK);
}else {
throw new GemfireRestException("Server has encountered error while generating query result into restful format(JSON)!");
@@ -680,7 +682,7 @@ public abstract class AbstractBaseController {
}
}
- public ResponseEntity<String> updateSingleKey(final String region, final String key, final String json, final String opValue){
+ public ResponseEntity<String> updateSingleKey(final String region, final String key, final String json, final String opValue, HttpHeaders headers){
final JSONTypes jsonType = validateJsonAndFindType(json);
@@ -707,13 +709,12 @@ public abstract class AbstractBaseController {
}
}
- final HttpHeaders headers = new HttpHeaders();
headers.setLocation(toUri(region, key));
return new ResponseEntity<String>(existingValue, headers, (existingValue == null ? HttpStatus.OK : HttpStatus.CONFLICT));
}
- public ResponseEntity<String> updateMultipleKeys(final String region, final String[] keys, final String json){
+ public ResponseEntity<String> updateMultipleKeys(final String region, final String[] keys, final String json, HttpHeaders headers){
JSONArray jsonArr = null;
try {
@@ -743,8 +744,7 @@ public abstract class AbstractBaseController {
if(!CollectionUtils.isEmpty(map)){
putPdxValues(region, map);
}
-
- HttpHeaders headers = new HttpHeaders();
+
headers.setLocation(toUri(region, StringUtils.arrayToCommaDelimitedString(keys)));
return new ResponseEntity<String>(headers, HttpStatus.OK);
}
@@ -829,4 +829,22 @@ public abstract class AbstractBaseController {
targetedMembers.add(c.getDistributedSystem().getDistributedMember());
return targetedMembers;
}
+
+ protected void setAuthTokenHeader(HttpHeaders headers) {
+ Map<String, Object> envMap = (Map<String, Object>)RestRequestFilter.getEnvironment();
+ boolean isSecurityEnabled = (boolean) envMap.get("isSecurityEnabled");
+
+ if(isSecurityEnabled == false)
+ return;
+
+ headers.set(AUTH_TOKEN_HEADER,(String)envMap.get("authToken"));
+
+ }
+
+ protected String getAuthToken(){
+ Map<String, Object> envMap = (Map<String, Object>)RestRequestFilter.getEnvironment();
+ return (String)envMap.get("authToken");
+ }
+
}
+
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d511979e/gemfire-web-api/src/main/java/com/gemstone/gemfire/rest/internal/web/controllers/BaseControllerAdvice.java
----------------------------------------------------------------------
diff --git a/gemfire-web-api/src/main/java/com/gemstone/gemfire/rest/internal/web/controllers/BaseControllerAdvice.java b/gemfire-web-api/src/main/java/com/gemstone/gemfire/rest/internal/web/controllers/BaseControllerAdvice.java
index 5ae88bc..d862448 100644
--- a/gemfire-web-api/src/main/java/com/gemstone/gemfire/rest/internal/web/controllers/BaseControllerAdvice.java
+++ b/gemfire-web-api/src/main/java/com/gemstone/gemfire/rest/internal/web/controllers/BaseControllerAdvice.java
@@ -25,6 +25,9 @@ import com.gemstone.gemfire.rest.internal.web.exception.GemfireRestException;
import com.gemstone.gemfire.rest.internal.web.exception.MalformedJsonException;
import com.gemstone.gemfire.rest.internal.web.exception.RegionNotFoundException;
import com.gemstone.gemfire.rest.internal.web.exception.ResourceNotFoundException;
+import com.gemstone.gemfire.security.AuthenticationFailedException;
+import com.gemstone.gemfire.security.AuthenticationRequiredException;
+import com.gemstone.gemfire.security.NotAuthorizedException;
/**
* The CrudControllerAdvice class handles exception thrown while serving the REST request
@@ -33,7 +36,7 @@ import com.gemstone.gemfire.rest.internal.web.exception.ResourceNotFoundExceptio
* @since 8.0
*/
-@ControllerAdvice
+//@ControllerAdvice
@SuppressWarnings("unused")
public class BaseControllerAdvice extends AbstractBaseController{
@@ -134,5 +137,42 @@ public class BaseControllerAdvice extends AbstractBaseController{
return convertErrorAsJson(cause.getMessage());
}
+ /**
+ * Handles NotAuthorizedException, occurring when REST service encounters unAuthorized access.
+ * <p/>
+ * @param e the RuntimeException thrown when request is not authorized to perform the operation.
+ * @return the String message from the RuntimeException.
+ */
+ @ExceptionHandler({ NotAuthorizedException.class })
+ @ResponseBody
+ @ResponseStatus(HttpStatus.UNAUTHORIZED)
+ public String handleException(final NotAuthorizedException e) {
+ return convertErrorAsJson(e.getMessage());
+ }
+
+ /**
+ * Handles AuthenticationFailedException, occurring when REST service can not authenticate the request.
+ * <p/>
+ * @param e the RuntimeException thrown when request is not authenticated to perform the operation.
+ * @return the String message from the RuntimeException.
+ */
+ @ExceptionHandler({ AuthenticationFailedException.class })
+ @ResponseBody
+ @ResponseStatus(HttpStatus.FORBIDDEN)
+ public String handleException(final AuthenticationFailedException e) {
+ return convertErrorAsJson(e.getMessage());
+ }
+
+ /**
+ * Handles AuthenticationRequiredException, occurring when REST service can not find the security credentials i nthe request.
+ * <p/>
+ * @param e the RuntimeException thrown when request does not contains security credentials for authentication.
+ * @return the String message from the RuntimeException.
+ */
+ @ExceptionHandler({ AuthenticationRequiredException.class })
+ @ResponseBody
+ @ResponseStatus(HttpStatus.FORBIDDEN)
+ public String handleException(final AuthenticationRequiredException e) {
+ return convertErrorAsJson(e.getMessage());
+ }
}
-
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d511979e/gemfire-web-api/src/main/java/com/gemstone/gemfire/rest/internal/web/controllers/CommonCrudController.java
----------------------------------------------------------------------
diff --git a/gemfire-web-api/src/main/java/com/gemstone/gemfire/rest/internal/web/controllers/CommonCrudController.java b/gemfire-web-api/src/main/java/com/gemstone/gemfire/rest/internal/web/controllers/CommonCrudController.java
index ef52347..fb7d16d 100644
--- a/gemfire-web-api/src/main/java/com/gemstone/gemfire/rest/internal/web/controllers/CommonCrudController.java
+++ b/gemfire-web-api/src/main/java/com/gemstone/gemfire/rest/internal/web/controllers/CommonCrudController.java
@@ -27,12 +27,17 @@ import com.gemstone.gemfire.cache.execute.Execution;
import com.gemstone.gemfire.cache.execute.FunctionException;
import com.gemstone.gemfire.cache.execute.FunctionService;
import com.gemstone.gemfire.cache.execute.ResultCollector;
+import com.gemstone.gemfire.cache.operations.OperationContext.OperationCode;
import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
import com.gemstone.gemfire.internal.logging.LogService;
+import com.gemstone.gemfire.internal.security.AuthorizeRequest;
import com.gemstone.gemfire.internal.util.ArrayUtils;
import com.gemstone.gemfire.rest.internal.web.controllers.support.RestServersResultCollector;
import com.gemstone.gemfire.rest.internal.web.exception.GemfireRestException;
+import com.gemstone.gemfire.rest.internal.web.security.AuthorizationProvider;
+import com.gemstone.gemfire.rest.internal.web.security.RestRequestFilter;
import com.gemstone.gemfire.rest.internal.web.util.JSONUtils;
+import com.gemstone.gemfire.security.NotAuthorizedException;
import org.json.JSONException;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiResponse;
@@ -71,10 +76,23 @@ public abstract class CommonCrudController extends AbstractBaseController {
logger.debug("Listing all resources (Regions) in GemFire...");
}
- final Set<Region<?, ?>> regions = getCache().rootRegions();
- String listRegionsAsJson = JSONUtils.formulateJsonForListRegions(regions, "regions");
final HttpHeaders headers = new HttpHeaders();
headers.setLocation(toUri());
+
+ //Do request(Pre) authorization if security is enabled.
+ if(AuthorizationProvider.isSecurityEnabled()){
+ setAuthTokenHeader(headers);
+ AuthorizationProvider.init();
+ try{
+ AuthorizationProvider.listRegionsAuthorize(OperationCode.LIST, true, "LIST_REGIONS");
+ }catch(NotAuthorizedException nae){
+ return new ResponseEntity<String>(headers, HttpStatus.UNAUTHORIZED);
+ }
+ }
+
+ final Set<Region<?, ?>> regions = getCache().rootRegions();
+ String listRegionsAsJson = JSONUtils.formulateJsonForListRegions(regions, "regions");
+
return new ResponseEntity<String>(listRegionsAsJson, headers, HttpStatus.OK);
}
@@ -98,16 +116,35 @@ public abstract class CommonCrudController extends AbstractBaseController {
public ResponseEntity<?> keys(@PathVariable("region") String region){
if(logger.isDebugEnabled()){
- logger.debug("Reading all Keys in Region ({})...", region);
+ logger.debug("Listing all Keys in Region ({})...", region);
}
region = decode(region);
-
- Object[] keys = getKeys(region, null);
-
- String listKeysAsJson = JSONUtils.formulateJsonForListKeys(keys, "keys");
final HttpHeaders headers = new HttpHeaders();
headers.setLocation(toUri(region, "keys"));
+
+ //Request(Pre) authorization if security is enabled.
+ if(AuthorizationProvider.isSecurityEnabled()){
+ setAuthTokenHeader(headers);
+ AuthorizationProvider.init();
+ try{
+ AuthorizationProvider.keySetAuthorize(region);
+ }catch(NotAuthorizedException nae) {
+ return new ResponseEntity<String>(headers, HttpStatus.UNAUTHORIZED);
+ }
+ }
+
+ Set<Object> keys = getRegion(region).keySet();
+
+ //Post authorization
+ if(AuthorizationProvider.isSecurityEnabled()){
+ try{
+ AuthorizationProvider.keySetAuthorizePP(region, keys);
+ }catch(NotAuthorizedException nae) {
+ return new ResponseEntity<String>(headers, HttpStatus.UNAUTHORIZED);
+ }
+ }
+ String listKeysAsJson = JSONUtils.formulateJsonForListKeys(keys.toArray(), "keys");
return new ResponseEntity<String>(listKeysAsJson, headers, HttpStatus.OK);
}
@@ -136,9 +173,21 @@ public abstract class CommonCrudController extends AbstractBaseController {
}
region = decode(region);
+ final HttpHeaders headers = new HttpHeaders();
+
+ //Do request(Pre) authorization if security is enabled.
+ if(AuthorizationProvider.isSecurityEnabled()){
+ setAuthTokenHeader(headers);
+ AuthorizationProvider.init();
+ try{
+ AuthorizationProvider.deleteAuthorize(region, keys, null);
+ }catch(NotAuthorizedException nae) {
+ return new ResponseEntity<String>(headers, HttpStatus.UNAUTHORIZED);
+ }
+ }
deleteValues(region, (Object[])keys);
- return new ResponseEntity<Object>(HttpStatus.OK);
+ return new ResponseEntity<Object>(headers, HttpStatus.OK);
}
/**
@@ -164,9 +213,21 @@ public abstract class CommonCrudController extends AbstractBaseController {
}
region = decode(region);
+ final HttpHeaders headers = new HttpHeaders();
+
+ //Do request(Pre) authorization if security is enabled.
+ if(AuthorizationProvider.isSecurityEnabled()){
+ setAuthTokenHeader(headers);
+ AuthorizationProvider.init();
+ try{
+ AuthorizationProvider.deleteAllAuthorize(region, null);
+ }catch(NotAuthorizedException nae) {
+ return new ResponseEntity<String>(headers, HttpStatus.UNAUTHORIZED);
+ }
+ }
deleteValues(region);
- return new ResponseEntity<Object>(HttpStatus.OK);
+ return new ResponseEntity<Object>(headers, HttpStatus.OK);
}
@RequestMapping(method = { RequestMethod.GET, RequestMethod.HEAD }, value = "/ping")
@@ -180,6 +241,7 @@ public abstract class CommonCrudController extends AbstractBaseController {
@ApiResponse( code = 500, message = "if GemFire throws an error or exception" )
} )
public ResponseEntity<?> ping() {
+ // Request Authorization not required.
return new ResponseEntity<Object>(HttpStatus.OK);
}
@@ -194,12 +256,13 @@ public abstract class CommonCrudController extends AbstractBaseController {
@ApiResponse( code = 500, message = "if GemFire throws an error or exception" )
} )
public ResponseEntity<?> servers() {
+ //Request Authorization not required.
Execution function = null;
if(logger.isDebugEnabled()){
logger.debug("Executing function to get REST enabled gemfire nodes in the DS!");
}
-
+
try {
function = FunctionService.onMembers(getAllMembersInDS());
} catch(FunctionException fe) {
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d511979e/gemfire-web-api/src/main/java/com/gemstone/gemfire/rest/internal/web/controllers/FunctionAccessController.java
----------------------------------------------------------------------
diff --git a/gemfire-web-api/src/main/java/com/gemstone/gemfire/rest/internal/web/controllers/FunctionAccessController.java b/gemfire-web-api/src/main/java/com/gemstone/gemfire/rest/internal/web/controllers/FunctionAccessController.java
index 45d6f66..09acbcd 100644
--- a/gemfire-web-api/src/main/java/com/gemstone/gemfire/rest/internal/web/controllers/FunctionAccessController.java
+++ b/gemfire-web-api/src/main/java/com/gemstone/gemfire/rest/internal/web/controllers/FunctionAccessController.java
@@ -33,10 +33,16 @@ import com.gemstone.gemfire.cache.execute.Function;
import com.gemstone.gemfire.cache.execute.FunctionException;
import com.gemstone.gemfire.cache.execute.FunctionService;
import com.gemstone.gemfire.cache.execute.ResultCollector;
+import com.gemstone.gemfire.cache.operations.ExecuteFunctionOperationContext;
+import com.gemstone.gemfire.cache.operations.OperationContext.OperationCode;
import com.gemstone.gemfire.internal.logging.LogService;
+import com.gemstone.gemfire.management.internal.RestAgent;
import com.gemstone.gemfire.rest.internal.web.exception.GemfireRestException;
+import com.gemstone.gemfire.rest.internal.web.security.AuthorizationProvider;
+import com.gemstone.gemfire.rest.internal.web.security.FunctionExecutionPostAuthzRC;
import com.gemstone.gemfire.rest.internal.web.util.ArrayUtils;
import com.gemstone.gemfire.rest.internal.web.util.JSONUtils;
+import com.gemstone.gemfire.security.NotAuthorizedException;
import org.json.JSONException;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
@@ -93,10 +99,22 @@ public class FunctionAccessController extends AbstractBaseController {
logger.debug("Listing all registered Functions in GemFire...");
}
- final Map<String, Function> registeredFunctions = FunctionService.getRegisteredFunctions();
- String listFunctionsAsJson = JSONUtils.formulateJsonForListFunctionsCall(registeredFunctions.keySet());
final HttpHeaders headers = new HttpHeaders();
headers.setLocation(toUri("functions"));
+
+ //Do request(Pre) authorization if security is enabled.
+ if(AuthorizationProvider.isSecurityEnabled()){
+ setAuthTokenHeader(headers);
+ AuthorizationProvider.init();
+ try{
+ AuthorizationProvider.listFunctionsAuthorize(OperationCode.LIST, true, "LIST_FUNCTIONS");
+ }catch(NotAuthorizedException nae) {
+ return new ResponseEntity<String>(HttpStatus.UNAUTHORIZED);
+ }
+ }
+
+ final Map<String, Function> registeredFunctions = FunctionService.getRegisteredFunctions();
+ String listFunctionsAsJson = JSONUtils.formulateJsonForListFunctionsCall(registeredFunctions.keySet());
return new ResponseEntity<String>(listFunctionsAsJson, headers, HttpStatus.OK);
}
@@ -133,6 +151,27 @@ public class FunctionAccessController extends AbstractBaseController {
Execution function = null;
functionId = decode(functionId);
+ boolean isOptimizedForWrite = FunctionService.getFunction(functionId).optimizeForWrite();
+ Object[] args = null;
+ final HttpHeaders headers = new HttpHeaders();
+
+ if(argsInBody != null)
+ {
+ args = jsonToObjectArray(argsInBody);
+ }
+
+ //Request(Pre) authorization if security is enabled.
+ ExecuteFunctionOperationContext fContext = null;
+ if(AuthorizationProvider.isSecurityEnabled()){
+ setAuthTokenHeader(headers);
+ AuthorizationProvider.init();
+ try{
+ fContext = AuthorizationProvider.executeFunctionAuthorize(functionId, region, null, args, isOptimizedForWrite);
+ }catch(NotAuthorizedException nae) {
+ return new ResponseEntity<String>(headers, HttpStatus.UNAUTHORIZED);
+ }
+ }
+
if (StringUtils.hasText(region)) {
if(logger.isDebugEnabled()){
logger.debug("Executing Function ({}) with arguments ({}) on Region ({})...", functionId,
@@ -181,23 +220,32 @@ public class FunctionAccessController extends AbstractBaseController {
throw new GemfireRestException("Disributed system does not contain any valid data node to run the specified function!", fe);
}
}
-
+
final ResultCollector<?, ?> results;
try {
- if(argsInBody != null)
- {
- Object[] args = jsonToObjectArray(argsInBody);
-
- //execute function with specified arguments
- if(args.length == 1){
+ //Post Authorization if security is enabled.
+ if(AuthorizationProvider.isSecurityEnabled() && RestAgent.getAuthorizeRequestPP(getAuthToken()) != null) {
+ if (fContext == null){
+ fContext = new ExecuteFunctionOperationContext(functionId, region, null, args, isOptimizedForWrite, true);
+ }
+ if(args != null && args.length == 1){
+ results = function.withArgs(args[0]).withCollector(new FunctionExecutionPostAuthzRC(fContext)).execute(functionId);
+ }else if (args != null && args.length > 1) {
+ results = function.withArgs(args).withCollector(new FunctionExecutionPostAuthzRC(fContext)).execute(functionId);
+ }else {
+ //execute function with no args
+ results = function.withCollector(new FunctionExecutionPostAuthzRC(fContext)).execute(functionId);
+ }
+ }else {
+ if(args != null && args.length == 1){
results = function.withArgs(args[0]).execute(functionId);
- } else {
+ }else if (args != null && args.length > 1) {
results = function.withArgs(args).execute(functionId);
+ }else {
+ //execute function with no args
+ results = function.execute(functionId);
}
- }else {
- //execute function with no args
- results = function.execute(functionId);
}
} catch(ClassCastException cce){
throw new GemfireRestException("Key is of an inappropriate type for this region!", cce);
@@ -215,7 +263,6 @@ public class FunctionAccessController extends AbstractBaseController {
Object functionResult = results.getResult();
if(functionResult instanceof List<?>) {
- final HttpHeaders headers = new HttpHeaders();
headers.setLocation(toUri("functions", functionId));
try {