You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by je...@apache.org on 2016/02/25 21:27:18 UTC
[30/50] [abbrv] incubator-geode git commit: Merge branch 'develop'
into feature/GEODE-17
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5c01d5f4/geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/AccessControlMXBean.java
----------------------------------------------------------------------
diff --cc geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/AccessControlMXBean.java
index 0000000,68c3d64..144b90a
mode 000000,100644..100644
--- a/geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/AccessControlMXBean.java
+++ b/geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/AccessControlMXBean.java
@@@ -1,0 -1,23 +1,29 @@@
+ /*
+ * 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 com.gemstone.gemfire.management.internal.security;
+
++/**
++ * Interface for AccessControlMBean
++ * @author tushark
++ * @since 9.0
++ */
+ public interface AccessControlMXBean {
+
++ @ResourceOperation(resource=Resource.MEMBER, operation=ResourceConstants.LIST_DS)
+ public boolean authorize(String role);
+
+ }
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5c01d5f4/geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/CLIOperationContext.java
----------------------------------------------------------------------
diff --cc geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/CLIOperationContext.java
index 0000000,4007d09..8999875
mode 000000,100644..100644
--- a/geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/CLIOperationContext.java
+++ b/geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/CLIOperationContext.java
@@@ -1,0 -1,138 +1,186 @@@
+ /*
+ * 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 com.gemstone.gemfire.management.internal.security;
+
+ import java.lang.annotation.Annotation;
+ import java.lang.reflect.Method;
+ import java.util.HashMap;
+ import java.util.Map;
+
+ import org.springframework.shell.event.ParseResult;
+
-import com.gemstone.gemfire.internal.logging.LogService;
++import com.gemstone.gemfire.GemFireConfigException;
+ import com.gemstone.gemfire.management.cli.CommandProcessingException;
+ import com.gemstone.gemfire.management.internal.cli.CommandManager;
+ import com.gemstone.gemfire.management.internal.cli.GfshParseResult;
+ import com.gemstone.gemfire.management.internal.cli.GfshParser;
++import com.gemstone.gemfire.management.internal.cli.i18n.CliStrings;
+ import com.gemstone.gemfire.management.internal.cli.parser.CommandTarget;
++import static com.gemstone.gemfire.management.internal.security.ResourceConstants.*;
+
-
++/**
++ * It represents command being executed and all passed options and option-values.
++ * ResourceOpCode returned by CLIOperationContext is retrieved from ResourceOperation
++ * annotation on the target command
++ *
++ * @author tushark
++ * @since 9.0
++ */
+ public class CLIOperationContext extends ResourceOperationContext {
-
- private OperationCode code = OperationCode.RESOURCE;
- private ResourceOperationCode resourceCode = null;
- private Map<String,String> commandOptions = null;
-
- private static Map<String,ResourceOperationCode> commandToCodeMapping = new HashMap<String,ResourceOperationCode>();
- private static CommandManager commandManager = null;
- private static GfshParser parser = null;
-
- public CLIOperationContext(String commandString) throws CommandProcessingException, IllegalStateException{
- code = OperationCode.RESOURCE;
- GfshParseResult parseResult = (GfshParseResult) parseCommand(commandString);
- this.commandOptions = parseResult.getParamValueStrings();
- this.resourceCode = findResourceCode(parseResult.getCommandName()); //need to add this to ParseResult
- }
-
- private static ParseResult parseCommand(String commentLessLine) throws CommandProcessingException, IllegalStateException {
++
++ private OperationCode code = OperationCode.RESOURCE;
++ private ResourceOperationCode resourceCode = null;
++ private Map<String,String> commandOptions = null;
++
++ private static Map<String,ResourceOperationCode> commandToCodeMapping = new HashMap<String,ResourceOperationCode>();
++ private static CommandManager commandManager = null;
++ private static GfshParser parser = null;
++
++ public CLIOperationContext(String commandString) throws CommandProcessingException, IllegalStateException{
++ GfshParseResult parseResult = (GfshParseResult) parseCommand(commandString);
++ this.commandOptions = parseResult.getParamValueStrings();
++ this.resourceCode = findResourceCode(parseResult.getCommandName());
++ this.code = findOperationCode(parseResult.getCommandName());
++ }
++
++ /**
++ * This method returns OperationCode for command. Some commands perform data
++ * operations, for such commands OperationCode returned is not RESOURCE but
++ * corresponding data operation as defined in OperationCode
++ *
++ * @param commandName
++ * @return OperationCode
++ */
++ private OperationCode findOperationCode(String commandName) {
++
++ if(CliStrings.GET.equals(commandName) || CliStrings.LOCATE_ENTRY.equals(commandName))
++ return OperationCode.GET;
++
++ if(CliStrings.PUT.equals(commandName))
++ return OperationCode.PUT;
++
++ if(CliStrings.QUERY.equals(commandName))
++ return OperationCode.QUERY;
++
++ if (CliStrings.REMOVE.equals(commandName)) {
++ if (commandOptions.containsKey(CliStrings.REMOVE__ALL)
++ && "true".equals(commandOptions.get(CliStrings.REMOVE__ALL))) {
++ return OperationCode.REMOVEALL;
++ } else
++ return OperationCode.DESTROY;
++ }
++
++ if(CliStrings.CLOSE_DURABLE_CQS.equals(commandName)) {
++ return OperationCode.CLOSE_CQ;
++ }
++
++ if(CliStrings.CREATE_REGION.equals(commandName)) {
++ return OperationCode.REGION_CREATE;
++ }
++
++ if(CliStrings.DESTROY_REGION.equals(commandName)) {
++ return OperationCode.REGION_DESTROY;
++ }
++
++ if(CliStrings.EXECUTE_FUNCTION.equals(commandName)) {
++ return OperationCode.EXECUTE_FUNCTION;
++ }
++
++ //"stop cq"
++ //"removeall",
++ //"get durable cqs",
++ return OperationCode.RESOURCE;
++ }
++
++ private static ParseResult parseCommand(String commentLessLine) throws CommandProcessingException, IllegalStateException {
+ if (commentLessLine != null) {
+ return parser.parse(commentLessLine);
+ }
+ throw new IllegalStateException("Command String should not be null.");
+ }
-
- public static void registerCommand(CommandManager cmdManager, Method method, CommandTarget commandTarget){
- //Save command manager instance and create a local parser for parsing the commands
- if(commandManager==null){
- commandManager = cmdManager;
- parser = new GfshParser(cmdManager);
- }
-
- boolean found=false;
- Annotation ans[] = method.getDeclaredAnnotations();
- for(Annotation an : ans){
- if(an instanceof ResourceOperation) {
- cache(commandTarget.getCommandName(),(ResourceOperation)an);
- found=true;
- }
- }
- if(!found)
- cache(commandTarget.getCommandName(),null);
- }
++
++ public static void registerCommand(CommandManager cmdManager, Method method, CommandTarget commandTarget){
++ if(commandManager==null){
++ commandManager = cmdManager;
++ parser = new GfshParser(cmdManager);
++ }
++
++ boolean found=false;
++ Annotation ans[] = method.getDeclaredAnnotations();
++ for(Annotation an : ans){
++ if(an instanceof ResourceOperation) {
++ cache(commandTarget.getCommandName(),(ResourceOperation)an);
++ found=true;
++ }
++ }
++ if(!found)
++ cache(commandTarget.getCommandName(),null);
++ }
++
++ private static void cache(String commandName, ResourceOperation op) {
++ ResourceOperationCode resourceOpCode = null;
++
++ if (op != null) {
++ String opString = op.operation();
++ if (opString != null)
++ resourceOpCode = ResourceOperationCode.parse(opString);
++ }
++
++ if(resourceOpCode==null){
++ if (commandName.startsWith(GETTER_DESCRIBE) || commandName.startsWith(GETTER_LIST)
++ || commandName.startsWith(GETTER_STATUS)) {
++ resourceOpCode = ResourceOperationCode.LIST_DS;
++ }
++ }
++
++
++ if(resourceOpCode!=null) {
++ commandToCodeMapping.put(commandName, resourceOpCode);
++ } else {
++ throw new GemFireConfigException(
++ "Error while configuring authorization for gfsh commands. No opCode defined for command " + commandName);
+
- private static void cache(String commandName, ResourceOperation op) {
- ResourceOperationCode code = null;
-
- if (op != null) {
- String opString = op.operation();
- if (opString != null)
- code = ResourceOperationCode.parse(opString);
- }
-
- if(code==null){
- if(commandName.startsWith("describe") || commandName.startsWith("list") || commandName.startsWith("status")
- || commandName.startsWith("show")){
- code = ResourceOperationCode.LIST_DS;
- }
- }
-
- //TODO : Have map according to each resources
- //TODO : How to save information for retrieving command Option map or region and serverGroup
-
- Resource targetedResource = null;
- if(op!=null){
- targetedResource = op.resource();
- } else {
- targetedResource = Resource.DISTRIBUTED_SYSTEM;
- //TODO : Add other resource and mbeans
- }
-
-
- LogService.getLogger().trace("#RegisterCommandSecurity : " + commandName + " code " + code + " op="+op);
-
- if(code!=null) {
- commandToCodeMapping.put(commandName, code);
- }
-
- }
++ }
++
++ }
+
- public Map<String, String> getCommandOptions() {
- return commandOptions;
- }
++ public Map<String, String> getCommandOptions() {
++ return commandOptions;
++ }
+
- private static ResourceOperationCode findResourceCode(String commandName) {
- return commandToCodeMapping.get(commandName);
- }
++ private static ResourceOperationCode findResourceCode(String commandName) {
++ return commandToCodeMapping.get(commandName);
++ }
+
+
- @Override
- public OperationCode getOperationCode() {
- return code;
- }
++ @Override
++ public OperationCode getOperationCode() {
++ return code;
++ }
+
- @Override
- public ResourceOperationCode getResourceOperationCode() {
- return resourceCode;
- }
-
-
- public String toString(){
- String str;
- str = "CLIOperationContext(resourceCode=" + resourceCode + ") options=" + commandOptions+")";
- return str;
- }
++ @Override
++ public ResourceOperationCode getResourceOperationCode() {
++ return resourceCode;
++ }
++
++
++ public String toString(){
++ String str;
++ str = "CLIOperationContext(resourceCode=" + resourceCode + ") options=" + commandOptions+")";
++ return str;
++ }
+ }
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5c01d5f4/geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/JMXOperationContext.java
----------------------------------------------------------------------
diff --cc geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/JMXOperationContext.java
index 0000000,225555f..1363efc
mode 000000,100644..100644
--- a/geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/JMXOperationContext.java
+++ b/geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/JMXOperationContext.java
@@@ -1,0 -1,177 +1,262 @@@
+ /*
+ * 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 com.gemstone.gemfire.management.internal.security;
+
+ import java.io.IOException;
+ import java.lang.annotation.Annotation;
+ import java.lang.reflect.Method;
+ import java.util.HashMap;
+ import java.util.Map;
+
+ import javax.management.ObjectName;
+
+ import com.gemstone.gemfire.GemFireConfigException;
++import com.gemstone.gemfire.internal.logging.LogService;
++import com.gemstone.gemfire.management.AsyncEventQueueMXBean;
++import com.gemstone.gemfire.management.CacheServerMXBean;
++import com.gemstone.gemfire.management.DiskStoreMXBean;
++import com.gemstone.gemfire.management.DistributedLockServiceMXBean;
++import com.gemstone.gemfire.management.DistributedRegionMXBean;
+ import com.gemstone.gemfire.management.DistributedSystemMXBean;
++import com.gemstone.gemfire.management.GatewayReceiverMXBean;
++import com.gemstone.gemfire.management.GatewaySenderMXBean;
++import com.gemstone.gemfire.management.LocatorMXBean;
++import com.gemstone.gemfire.management.LockServiceMXBean;
++import com.gemstone.gemfire.management.ManagerMXBean;
++import com.gemstone.gemfire.management.MemberMXBean;
++import com.gemstone.gemfire.management.RegionMXBean;
+ import com.gemstone.gemfire.management.internal.MBeanJMXAdapter;
+ import com.gemstone.gemfire.management.internal.cli.util.ClasspathScanLoadHelper;
++import static com.gemstone.gemfire.management.internal.security.ResourceConstants.*;
+
-
++/**
++ * It describes current JMX MBean Method call and its parameters.
++ * OpCode returned by JMXOperationContext is retrieved from ResourceOperation annotation
++ * on the target methodName
++ *
++ * @author tushark
++ * @since 9.0
++ *
++ */
+ public class JMXOperationContext extends ResourceOperationContext {
-
- private OperationCode code = OperationCode.RESOURCE;
- private ResourceOperationCode resourceCode = null;
-
- private static Map<String,ResourceOperationCode> cacheDSResourceOps = null;
- private static Map<String,ResourceOperationCode> cacheMemberResourceOps = null;
- private static Map<String,ResourceOperationCode> cacheRegionResourceOps = null;
- private static Map<String,ResourceOperationCode> cacheDiskStoreResourceOps = null;
-
- static {
- //cache all resource annotations
- readJMXAnnotations();
-
- }
++
++
++ private OperationCode code = OperationCode.RESOURCE;
++ private ResourceOperationCode resourceCode = null;
++ private ObjectName name;
++ private String methodName;
++
++ private static Map<Class<?>,Map<String,ResourceOperationCode>> cachedResourceOpsMapping = new HashMap<Class<?>,Map<String,ResourceOperationCode>>();
++ private static Map<String,ResourceOperationCode> distributedSystemMXBeanResourceOps = new HashMap<String,ResourceOperationCode>();
++ private static Map<String,ResourceOperationCode> diskStoreMXBeanResourceOps = new HashMap<String,ResourceOperationCode>();
++ private static Map<String,ResourceOperationCode> cacheServerMXBeanResourceOps = new HashMap<String,ResourceOperationCode>();
++ private static Map<String,ResourceOperationCode> gatewayReceiverMXBeanResourceOps = new HashMap<String,ResourceOperationCode>();
++ private static Map<String,ResourceOperationCode> gatewaySenderMXBeanResourceOps = new HashMap<String,ResourceOperationCode>();
++ private static Map<String,ResourceOperationCode> lockServiceMXBeanResourceOps = new HashMap<String,ResourceOperationCode>();
++ private static Map<String,ResourceOperationCode> managerMXBeanResourceOps = new HashMap<String,ResourceOperationCode>();
++ private static Map<String,ResourceOperationCode> memberMXBeanResourceOps = new HashMap<String,ResourceOperationCode>();
++ private static Map<String,ResourceOperationCode> regionMXBeanResourceOps = new HashMap<String,ResourceOperationCode>();
++ private static Map<String,ResourceOperationCode> locatorMXBeanResourceOps = new HashMap<String,ResourceOperationCode>();
++ private static Map<String,ResourceOperationCode> distributedLockServiceMXBeanResourceOps = new HashMap<String,ResourceOperationCode>();
++ private static Map<String,ResourceOperationCode> distributedRegionMXBeanResourceOps = new HashMap<String,ResourceOperationCode>();
++ private static Map<String,ResourceOperationCode> asyncEventQueueMXBeanResourceOps = new HashMap<String,ResourceOperationCode>();
++ private static Map<String,ResourceOperationCode> accessControlMXBeanResourceOps = new HashMap<String,ResourceOperationCode>();
+
- private static void readJMXAnnotations() {
- try {
- Class[] klassList = ClasspathScanLoadHelper.getClasses("com.gemstone.gemfire.management");
- for(Class klass : klassList) {
- if(klass.getName().endsWith("MXBean")) {
- Method[] methods = klass.getMethods();
- for(Method method : methods) {
- String name = method.getName();
- //ResourceOperation op = method.getDeclaredAnnotations();(ResourceOperation.class);
- boolean found=false;
- Annotation ans[] = method.getDeclaredAnnotations();
- for(Annotation an : ans){
- if(an instanceof ResourceOperation) {
- cache(klass,name,(ResourceOperation)an);
- found=true;
- }
- }
- if(!found)
- cache(klass,name,null);
- }
- //TODO : Log all cached operations
- }
- }
- } catch (ClassNotFoundException e) {
- throw new GemFireConfigException(
- "Error while configuring authorization for jmx - ", e);
- } catch (IOException e) {
- throw new GemFireConfigException(
- "Error while configuring authorization for jmx - ", e);
- }
-
- }
-
- private static void cache(Class klass, String name, ResourceOperation op) {
- ResourceOperationCode code = null;
-
- if (op != null) {
- String opString = op.operation();
- if (opString != null)
- code = ResourceOperationCode.parse(opString);
- }
-
- if(code==null){
- if(name.startsWith("list") || name.startsWith("fetch") || name.startsWith("view")
- || name.startsWith("show")){
- code = ResourceOperationCode.LIST_DS;
- } else if (name.startsWith("get")){
- code = ResourceOperationCode.READ_DS;
- } else if (name.startsWith("is")){
- code = ResourceOperationCode.READ_DS;
- } else if (name.startsWith("set")){
- code = ResourceOperationCode.SET_DS;
- }
- }
-
- /*
- System.out.println("Klass " + klass + " mname : " + name);
- if (code != null)
- System.out.println("ResourceOperation code=" + code);
- else
- System.out.println("ResourceOperation is null");*/
-
- Resource targetedResource = null;
-
- if(op!=null){
- targetedResource = op.resource();
- } else {
- if(klass.equals(DistributedSystemMXBean.class)) {
- targetedResource = Resource.DISTRIBUTED_SYSTEM;
- }
- //TODO : Add other resource and mbeans
- }
-
- /* Comment for timebeing to avoid falling for other methods
- if(!isGetterSetter(name) && code==null){
- throw new GemFireConfigException(
- "Error while configuring authorization for jmx. No authorization defined for "
- + klass.getCanonicalName() + " method " + name);
- }*/
- if(targetedResource!=null) {
- switch (targetedResource) {
- case DISTRIBUTED_SYSTEM:
- if (code != null){
- if(cacheDSResourceOps==null)
- cacheDSResourceOps = new HashMap<String,ResourceOperationCode>();
- cacheDSResourceOps.put(name, code);
- }
- break;
- }
- }
- }
++
++ static {
++ readJMXAnnotations();
++ }
+
- private static boolean isGetterSetter(String name) {
- if(name.startsWith("is") || name.startsWith("get") || name.startsWith("set") || name.startsWith("fetch")
- || name.startsWith("list") || name.startsWith("view") || name.startsWith("show") )
- return true;
- else return false;
- }
++ private static void readJMXAnnotations() {
++
++ cachedResourceOpsMapping.put(DistributedSystemMXBean.class, distributedSystemMXBeanResourceOps);
++ cachedResourceOpsMapping.put(DiskStoreMXBean.class, diskStoreMXBeanResourceOps);
++ cachedResourceOpsMapping.put(CacheServerMXBean.class, cacheServerMXBeanResourceOps);
++ cachedResourceOpsMapping.put(GatewayReceiverMXBean.class, gatewayReceiverMXBeanResourceOps);
++ cachedResourceOpsMapping.put(GatewaySenderMXBean.class, gatewaySenderMXBeanResourceOps);
++ cachedResourceOpsMapping.put(LockServiceMXBean.class, lockServiceMXBeanResourceOps);
++ cachedResourceOpsMapping.put(ManagerMXBean.class, managerMXBeanResourceOps);
++ cachedResourceOpsMapping.put(MemberMXBean.class, memberMXBeanResourceOps);
++ cachedResourceOpsMapping.put(RegionMXBean.class, regionMXBeanResourceOps);
++ cachedResourceOpsMapping.put(LocatorMXBean.class, locatorMXBeanResourceOps);
++ cachedResourceOpsMapping.put(DistributedLockServiceMXBean.class, distributedLockServiceMXBeanResourceOps);
++ cachedResourceOpsMapping.put(DistributedRegionMXBean.class, distributedRegionMXBeanResourceOps);
++ cachedResourceOpsMapping.put(AsyncEventQueueMXBean.class, asyncEventQueueMXBeanResourceOps);
++ cachedResourceOpsMapping.put(AccessControlMXBean.class, accessControlMXBeanResourceOps);
++
++ try {
++ Class<?>[] klassList = ClasspathScanLoadHelper.getClasses(MANAGEMENT_PACKAGE);
++ for(Class<?> klass : klassList) {
++ if(klass.getName().endsWith("MXBean")) {
++ Method[] methods = klass.getMethods();
++ for(Method method : methods) {
++ String name = method.getName();
++ boolean found=false;
++ Annotation ans[] = method.getDeclaredAnnotations();
++ for(Annotation an : ans){
++ if(an instanceof ResourceOperation) {
++ cache(klass,name,(ResourceOperation)an);
++ found=true;
++ }
++ }
++ if(!found)
++ cache(klass,name,null);
++ }
++ }
++ }
++ } catch (ClassNotFoundException e) {
++ throw new GemFireConfigException(
++ "Error while configuring authorization for jmx - ", e);
++ } catch (IOException e) {
++ throw new GemFireConfigException(
++ "Error while configuring authorization for jmx - ", e);
++ }
++
++ }
++
++ private static void cache(Class<?> klass, String name, ResourceOperation op) {
++ ResourceOperationCode code = null;
++
++ if (op != null) {
++ String opString = op.operation();
++ if (opString != null)
++ code = ResourceOperationCode.parse(opString);
++ }
++
++ if(code==null && isGetterSetter(name)){
++ code = ResourceOperationCode.LIST_DS;
++ }
++
++
++ if (code == null && cachedResourceOpsMapping.keySet().contains(klass) && !isGetterSetter(name)) {
++ throw new GemFireConfigException("Error while configuring authorization for jmx. No opCode defined for "
++ + klass.getCanonicalName() + " method " + name);
++ }
++
++ final Map<String,ResourceOperationCode> resourceOpsMap = cachedResourceOpsMapping.get(klass);
++ if(resourceOpsMap==null) {
++ if (cachedResourceOpsMapping.keySet().contains(klass))
++ throw new GemFireConfigException("Unknown MBean " + klass.getCanonicalName());
++ else {
++ LogService.getLogger().warn("Unsecured mbean " + klass);
++ }
++ }
++ else {
++ resourceOpsMap.put(name, code);
++ }
++ }
+
- public JMXOperationContext(ObjectName name , String methodName){
- code = OperationCode.RESOURCE;
- if(name.equals(MBeanJMXAdapter.getDistributedSystemName())){
- resourceCode = cacheDSResourceOps.get(methodName);
- }
- }
-
++ public static boolean isGetterSetter(String name) {
++ if(name.startsWith(GETTER_IS) || name.startsWith(GETTER_GET) || name.startsWith(GETTER_FETCH)
++ || name.startsWith(GETTER_LIST) || name.startsWith(GETTER_VIEW) || name.startsWith(GETTER_SHOW) || name.startsWith(GETTER_HAS))
++ return true;
++ else return false;
++ }
+
- @Override
- public OperationCode getOperationCode() {
- return code;
- }
++ public JMXOperationContext(ObjectName name , String methodName){
++ code = OperationCode.RESOURCE;
++ Class<?> klass = getMbeanClass(name);
++ Map<String,ResourceOperationCode> resourceOpsMap = cachedResourceOpsMapping.get(klass);
++ resourceCode = resourceOpsMap.get(methodName);
++ this.methodName = methodName;
++ this.name = name;
++
++ //If getAttr is not found try for isAttr ie. boolean getter
++ if(resourceCode==null) {
++ if(this.methodName.startsWith(GET_PREFIX)) {
++ String methodNameBooleanGetter = GET_IS_PREFIX + this.methodName.substring(GET_PREFIX.length());
++ if(resourceOpsMap.containsKey(methodNameBooleanGetter)){
++ resourceCode = resourceOpsMap.get(methodNameBooleanGetter);
++ this.methodName = methodNameBooleanGetter;
++ }
++ }
++ }
++
++ //If resourceCode is still null most likely its wrong method name so just allow it pass
++ if(resourceCode==null) {
++ resourceCode = ResourceOperationCode.LIST_DS;
++ }
++ }
++
+
- @Override
- public ResourceOperationCode getResourceOperationCode() {
- return resourceCode;
- }
++
+
- public static Map<String, ResourceOperationCode> getCacheDSResourceOps() {
- return cacheDSResourceOps;
- }
++ private Class<?> getMbeanClass(ObjectName name) {
++ if (name.equals(MBeanJMXAdapter.getDistributedSystemName()))
++ return DistributedSystemMXBean.class;
++ else {
++ String service = name.getKeyProperty(MBEAN_KEY_SERVICE);
++ String mbeanType = name.getKeyProperty(MBEAN_KEY_TYPE);
+
- public static void setCacheDSResourceOps(
- Map<String, ResourceOperationCode> cacheDSResourceOps) {
- JMXOperationContext.cacheDSResourceOps = cacheDSResourceOps;
- }
-
-
++ if (MBEAN_TYPE_DISTRIBUTED.equals(mbeanType)) {
++ if (MBEAN_SERVICE_SYSTEM.equals(service)) {
++ return DistributedSystemMXBean.class;
++ } else if (MBEAN_SERVICE_REGION.equals(service)) {
++ return DistributedRegionMXBean.class;
++ } else if (MBEAN_SERVICE_LOCKSERVICE.equals(service)) {
++ return DistributedLockServiceMXBean.class;
++ } else {
++ throw new RuntimeException("Unknown mbean type " + name);
++ }
++ } else if (MBEAN_TYPE_MEMBER.equals(mbeanType)) {
++ if (service == null) {
++ return MemberMXBean.class;
++ } else {
++ if (MBEAN_SERVICE_MANAGER.equals(service)) {
++ return ManagerMXBean.class;
++ } else if (MBEAN_SERVICE_CACHESERVER.equals(service)) {
++ return CacheServerMXBean.class;
++ } else if (MBEAN_SERVICE_REGION.equals(service)) {
++ return RegionMXBean.class;
++ } else if (MBEAN_SERVICE_LOCKSERVICE.equals(service)) {
++ return LockServiceMXBean.class;
++ } else if (MBEAN_SERVICE_DISKSTORE.equals(service)) {
++ return DiskStoreMXBean.class;
++ } else if (MBEAN_SERVICE_GATEWAY_RECEIVER.equals(service)) {
++ return GatewayReceiverMXBean.class;
++ } else if (MBEAN_SERVICE_GATEWAY_SENDER.equals(service)) {
++ return GatewaySenderMXBean.class;
++ } else if (MBEAN_SERVICE_ASYNCEVENTQUEUE.equals(service)) {
++ return AsyncEventQueueMXBean.class;
++ } else if (MBEAN_SERVICE_LOCATOR.equals(service)) {
++ return LocatorMXBean.class;
++ } else {
++ throw new RuntimeException("Unknown mbean type " + name);
++ }
++ }
++ } else {
++ throw new RuntimeException("Unknown mbean type " + name);
++ }
++ }
++ }
++
++ @Override
++ public OperationCode getOperationCode() {
++ return code;
++ }
++
++ @Override
++ public ResourceOperationCode getResourceOperationCode() {
++ return resourceCode;
++ }
++
++ public String toString(){
++ return "JMXOpCtx(on="+name+",method="+methodName+")";
++ }
+
+ }
++
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5c01d5f4/geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/JSONAuthorization.java
----------------------------------------------------------------------
diff --cc geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/JSONAuthorization.java
index 0000000,ef98575..5455818
mode 000000,100644..100644
--- a/geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/JSONAuthorization.java
+++ b/geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/JSONAuthorization.java
@@@ -1,0 -1,308 +1,292 @@@
-/*
- * 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 com.gemstone.gemfire.management.internal.security;
+
+ import java.io.File;
+ import java.io.FileReader;
+ import java.io.IOException;
+ import java.security.Principal;
+ import java.util.HashMap;
+ import java.util.HashSet;
+ import java.util.Map;
+ import java.util.Properties;
+ import java.util.Set;
+
+ import javax.management.remote.JMXPrincipal;
+
+ import org.json.JSONArray;
+ import org.json.JSONException;
+ import org.json.JSONObject;
+
+ import com.gemstone.gemfire.GemFireConfigException;
+ import com.gemstone.gemfire.LogWriter;
+ import com.gemstone.gemfire.cache.Cache;
+ import com.gemstone.gemfire.cache.operations.OperationContext;
+ import com.gemstone.gemfire.distributed.DistributedMember;
+ import com.gemstone.gemfire.internal.logging.LogService;
+ import com.gemstone.gemfire.management.internal.security.ResourceOperationContext.ResourceOperationCode;
+ import com.gemstone.gemfire.security.AccessControl;
+ import com.gemstone.gemfire.security.AuthenticationFailedException;
+ import com.gemstone.gemfire.security.Authenticator;
+ import com.gemstone.gemfire.security.NotAuthorizedException;
+
+ public class JSONAuthorization implements AccessControl, Authenticator {
+
+ public static class Role{
+ String[] permissions;
+ String name;
+ String regionName;
+ String serverGroup;
+ }
+
+ public static class User{
+ String name;
+ Role[] roles;
+ String pwd;
+ }
+
+ private static Map<String,User> acl = null;
+
+ public static JSONAuthorization create() throws IOException, JSONException {
+ if(acl==null){
+ readSecurityDescriptor(readDefault());
+ }
+ return new JSONAuthorization();
+ }
+
+ public JSONAuthorization() {
+ if (acl == null) {
+ try {
+ readSecurityDescriptor(readDefault());
+ } catch (IOException e) {
+ throw new GemFireConfigException("Error creating JSONAuth", e);
+ } catch (JSONException e) {
+ throw new GemFireConfigException("Error creating JSONAuth", e);
+ }
+ }
+ }
+
+ public static Set<ResourceOperationCode> getAuthorizedOps(User user, ResourceOperationContext context) {
+ Set<ResourceOperationCode> codeList = new HashSet<ResourceOperationCode>();
+ for(Role role : user.roles) {
+ for (String perm : role.permissions) {
+ ResourceOperationCode code = ResourceOperationCode.parse(perm);
+ if (role.regionName == null && role.serverGroup == null) {
+ addPermissions(code, codeList);
+ } else if (role.regionName != null) {
+ LogService.getLogger().info("This role requires region=" + role.regionName);
+ if (context instanceof CLIOperationContext) {
+ CLIOperationContext cliContext = (CLIOperationContext) context;
+ String region = cliContext.getCommandOptions().get("region");
+ if (region != null && region.equals(role.regionName)) {
+ addPermissions(code, codeList);
+ } else {
+ LogService.getLogger().info("Not adding permission " + code + " since region=" + region + " does not match");
+ }
+ }
+ }
+ // Same to be implemented for ServerGroup
+ }
+ }
+ LogService.getLogger().info("Final set of permisions " + codeList);
+ return codeList;
+ }
+
+ private static void addPermissions(ResourceOperationCode code, Set<ResourceOperationCode> codeList) {
+ if(code!=null) {
+ if(code.getChildren()==null)
+ codeList.add(code);
+ else {
+ for(ResourceOperationCode c : code.getChildren()){
+ codeList.add(c);
+ }
+ }
+ }
+ }
+
+ private static String readDefault() throws IOException, JSONException {
+ String str = System.getProperty(ResourceConstants.RESORUCE_SEC_DESCRIPTOR, ResourceConstants.RESORUCE_DEFAULT_SEC_DESCRIPTOR);
+ File file = new File(str);
+ FileReader reader = new FileReader(file);
+ char[] buffer = new char[(int) file.length()];
+ reader.read(buffer);
+ String json = new String(buffer);
+ reader.close();
+ return json;
+ }
+
+ public JSONAuthorization(String json) throws IOException, JSONException{
+ readSecurityDescriptor(json);
+ }
+
+
+ private static void readSecurityDescriptor(String json) throws IOException, JSONException {
+ JSONObject jsonBean = new JSONObject(json);
+ acl = new HashMap<String,User>();
+ Map<String,Role> roleMap = readRoles(jsonBean);
+ readUsers(acl,jsonBean,roleMap);
+ }
+
+ private static void readUsers(Map<String, User> acl, JSONObject jsonBean,
+ Map<String, Role> roleMap) throws JSONException {
+ JSONArray array = jsonBean.getJSONArray("users");
+ for(int i=0;i<array.length();i++){
+ JSONObject obj = array.getJSONObject(i);
+ User user = new User();
+ user.name = obj.getString("name");
+ if(obj.has("password"))
+ user.pwd = obj.getString("password");
+ else
+ user.pwd = user.name;
+
+ JSONArray ops = obj.getJSONArray("roles");
+ user.roles = new Role[ops.length()];
+ for(int j=0;j<ops.length();j++){
+ String roleName = ops.getString(j);
+ user.roles[j] = roleMap.get(roleName);
+ if(user.roles[j]==null){
+ throw new RuntimeException("Role not present " + roleName);
+ }
+ }
+ acl.put(user.name, user);
+ }
+ }
+
+ private static Map<String, Role> readRoles(JSONObject jsonBean) throws JSONException {
+ Map<String,Role> roleMap = new HashMap<String,Role>();
+ JSONArray array = jsonBean.getJSONArray("roles");
+ for(int i=0;i<array.length();i++){
+ JSONObject obj = array.getJSONObject(i);
+ Role role = new Role();
+ role.name = obj.getString("name");
+
+ if(obj.has("operationsAllowed")){
+ JSONArray ops = obj.getJSONArray("operationsAllowed");
+ role.permissions = new String[ops.length()];
+ for(int j=0;j<ops.length();j++){
+ role.permissions[j] = ops.getString(j);
+ }
+ }else {
+ if (!obj.has("inherit"))
+ throw new RuntimeException(
+ "Role "
+ + role.name
+ + " does not have any permission neither it inherits any parent role");
+ }
+
+ roleMap.put(role.name,role);
+
+ if(obj.has("region")){
+ role.regionName = obj.getString("region");
+ }
+
+ if(obj.has("serverGroup")){
+ role.serverGroup = obj.getString("serverGroup");
+ }
+ }
+
+ for(int i=0;i<array.length();i++){
+ JSONObject obj = array.getJSONObject(i);
+ String name = obj.getString("name");
+ Role role = roleMap.get(name);
+ if (role == null) {
+ throw new RuntimeException("Role not present "
+ + role);
+ }
+ if(obj.has("inherit")){
+ JSONArray parentRoles = obj.getJSONArray("inherit");
+ for (int m = 0; m < parentRoles.length(); m++) {
+ String parentRoleName = parentRoles.getString(m);
+ Role parentRole = roleMap.get(parentRoleName);
+ if (parentRole == null) {
+ throw new RuntimeException("Role not present "
+ + parentRoleName);
+ }
+ int oldLenth=0;
+ if(role.permissions!=null)
+ oldLenth = role.permissions.length;
+ int newLength = oldLenth + parentRole.permissions.length;
+ String[] str = new String[newLength];
+ int k = 0;
+ if(role.permissions!=null) {
+ for (; k < role.permissions.length; k++) {
+ str[k] = role.permissions[k];
+ }
+ }
+
+ for (int l = 0; l < parentRole.permissions.length; l++) {
+ str[k + l] = parentRole.permissions[l];
+ }
+ role.permissions = str;
+ }
+ }
+
+ }
+ return roleMap;
+ }
+
+ public static Map<String, User> getAcl() {
+ return acl;
+ }
+
+ private Principal principal=null;
+
+ @Override
+ public void close() {
+
+ }
+
+ @Override
+ public boolean authorizeOperation(String arg0, OperationContext context) {
+
+ if(principal!=null) {
+ User user = acl.get(principal.getName());
+ if(user!=null) {
+ LogService.getLogger().info("Context received " + context);
+ ResourceOperationContext ctx = (ResourceOperationContext)context;
+ LogService.getLogger().info("Checking for code " + ctx.getResourceOperationCode());
+
+ //TODO : This is for un-annotated commands
+ if(ctx.getResourceOperationCode()==null)
+ return true;
+
+ boolean found = false;
+ for(ResourceOperationCode code : getAuthorizedOps(user, (ResourceOperationContext) context)) {
+ if(ctx.getResourceOperationCode().equals(code)){
+ found =true;
+ LogService.getLogger().info("found code " + code.toString());
+ break;
+ }
+ }
+ if(found)
+ return true;
+ LogService.getLogger().info("Did not find code " + ctx.getResourceOperationCode());
+ return false;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void init(Principal principal, DistributedMember arg1, Cache arg2) throws NotAuthorizedException {
+ this.principal = principal;
+ }
+
+ @Override
+ public Principal authenticate(Properties props, DistributedMember arg1) throws AuthenticationFailedException {
- String user = props.getProperty(ManagementInterceptor.USER_NAME);
- String pwd = props.getProperty(ManagementInterceptor.PASSWORD);
++ String user = props.getProperty(ResourceConstants.USER_NAME);
++ String pwd = props.getProperty(ResourceConstants.PASSWORD);
+ User userObj = acl.get(user);
+ if(userObj==null)
+ throw new AuthenticationFailedException("Wrong username/password");
+ LogService.getLogger().info("User="+user + " pwd="+pwd);
+ if (user!=null && !userObj.pwd.equals(pwd) && !"".equals(user))
+ throw new AuthenticationFailedException("Wrong username/password");
+ LogService.getLogger().info("Authentication successful!! for " + user);
+ return new JMXPrincipal(user);
+ }
+
+ @Override
+ public void init(Properties arg0, LogWriter arg1, LogWriter arg2) throws AuthenticationFailedException {
+
+ }
+
+ }
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5c01d5f4/geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/MBeanServerWrapper.java
----------------------------------------------------------------------
diff --cc geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/MBeanServerWrapper.java
index 0000000,d85920c..0a79634
mode 000000,100644..100644
--- a/geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/MBeanServerWrapper.java
+++ b/geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/MBeanServerWrapper.java
@@@ -1,0 -1,286 +1,343 @@@
+ /*
+ * 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 com.gemstone.gemfire.management.internal.security;
+
+ import java.io.ObjectInputStream;
++import java.util.HashSet;
+ import java.util.Set;
+
+ import javax.management.Attribute;
+ import javax.management.AttributeList;
+ import javax.management.AttributeNotFoundException;
+ import javax.management.InstanceAlreadyExistsException;
+ import javax.management.InstanceNotFoundException;
+ import javax.management.IntrospectionException;
+ import javax.management.InvalidAttributeValueException;
+ import javax.management.ListenerNotFoundException;
+ import javax.management.MBeanException;
+ import javax.management.MBeanInfo;
+ import javax.management.MBeanRegistrationException;
+ import javax.management.MBeanServer;
+ import javax.management.NotCompliantMBeanException;
+ import javax.management.NotificationFilter;
+ import javax.management.NotificationListener;
+ import javax.management.ObjectInstance;
+ import javax.management.ObjectName;
+ import javax.management.OperationsException;
+ import javax.management.QueryExp;
+ import javax.management.ReflectionException;
+ import javax.management.loading.ClassLoaderRepository;
+ import javax.management.remote.MBeanServerForwarder;
-
++import static com.gemstone.gemfire.management.internal.security.ResourceConstants.*;
++
++/**
++ * This class intercepts all MBean requests for GemFire MBeans and passed it to
++ * ManagementInterceptor for authorization
++ *
++ *
++ * @author tushark
++ * @since 9.0
++ *
++ */
+ public class MBeanServerWrapper implements MBeanServerForwarder {
+
+ private MBeanServer mbs;
+ private ManagementInterceptor interceptor;
+
+ public MBeanServerWrapper(ManagementInterceptor interceptor){
+ this.interceptor = interceptor;
+ }
+
- private void doAuthorization(ObjectName name, String methodName, Object[] methodParams){
- interceptor.authorize(name,methodName, methodParams);
++ private ResourceOperationContext doAuthorization(ObjectName name, String methodName, Object[] methodParams){
++ return interceptor.authorize(name,methodName, methodParams);
++ }
++
++ private void doAuthorizationPost(ObjectName name, String methodName, ResourceOperationContext context, Object result){
++ interceptor.postAuthorize(name,methodName,context,result);
+ }
+
+ @Override
+ public ObjectInstance createMBean(String className, ObjectName name) throws ReflectionException,
+ InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException {
- doAuthorization(name, "createMBean", new Object[]{name});
- return mbs.createMBean(className, name);
++ ResourceOperationContext ctx = doAuthorization(name, CREATE_MBEAN, new Object[]{name});
++ ObjectInstance result = mbs.createMBean(className, name);
++ doAuthorizationPost(name, CREATE_MBEAN, ctx, result);
++ return result;
+ }
+
+ @Override
+ public ObjectInstance createMBean(String className, ObjectName name, ObjectName loaderName)
+ throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException,
+ NotCompliantMBeanException, InstanceNotFoundException {
- doAuthorization(name, "createMBean", new Object[]{name});
- return mbs.createMBean(className, name, loaderName);
++ ResourceOperationContext ctx = doAuthorization(name, CREATE_MBEAN, new Object[]{name});
++ ObjectInstance result = mbs.createMBean(className, name, loaderName);
++ doAuthorizationPost(name, CREATE_MBEAN, ctx, result);
++ return result;
+ }
+
+ @Override
+ public ObjectInstance createMBean(String className, ObjectName name, Object[] params, String[] signature)
+ throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException,
+ NotCompliantMBeanException {
- doAuthorization(name, "createMBean", new Object[]{name, params});
- return mbs.createMBean(className,name,params,signature);
++ ResourceOperationContext ctx = doAuthorization(name, CREATE_MBEAN, new Object[]{name, params});
++ ObjectInstance result = mbs.createMBean(className,name,params,signature);
++ doAuthorizationPost(name, CREATE_MBEAN, ctx, result);
++ return result;
+ }
+
+ @Override
+ public ObjectInstance createMBean(String className, ObjectName name, ObjectName loaderName, Object[] params,
+ String[] signature) throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException,
+ MBeanException, NotCompliantMBeanException, InstanceNotFoundException {
- doAuthorization(name, "createMBean", new Object[]{name});
- return mbs.createMBean(className, name, loaderName, params, signature);
++ ResourceOperationContext ctx = doAuthorization(name, CREATE_MBEAN, new Object[]{name});
++ ObjectInstance result = mbs.createMBean(className, name, loaderName, params, signature);
++ doAuthorizationPost(name, CREATE_MBEAN, ctx, result);
++ return result;
+ }
+
+ @Override
+ public ObjectInstance registerMBean(Object object, ObjectName name) throws InstanceAlreadyExistsException,
+ MBeanRegistrationException, NotCompliantMBeanException {
- doAuthorization(name, "registerMBean", new Object[]{name});
- return mbs.registerMBean(object, name);
++ ResourceOperationContext ctx = doAuthorization(name, REGISTER_MBEAN, new Object[]{name});
++ ObjectInstance result = mbs.registerMBean(object, name);
++ doAuthorizationPost(name, REGISTER_MBEAN, ctx, result);
++ return result;
+ }
+
+ @Override
+ public void unregisterMBean(ObjectName name) throws InstanceNotFoundException, MBeanRegistrationException {
- doAuthorization(name, "registerMBean", new Object[]{});
++ ResourceOperationContext ctx = doAuthorization(name, UNREGISTER_MBEAN, new Object[]{});
+ mbs.unregisterMBean(name);
++ doAuthorizationPost(name, UNREGISTER_MBEAN, ctx, null);
+ }
+
+ @Override
+ public ObjectInstance getObjectInstance(ObjectName name) throws InstanceNotFoundException {
+ return mbs.getObjectInstance(name);
+ }
+
+ @Override
+ public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
- return mbs.queryMBeans(name, query);
++ return filterAccessControlMBeanInstance(mbs.queryMBeans(name, query));
++ }
++
++ private Set<ObjectInstance> filterAccessControlMBeanInstance(Set<ObjectInstance> queryMBeans) {
++ Set<ObjectInstance> set = new HashSet<ObjectInstance>();
++ for(ObjectInstance oi : queryMBeans) {
++ if(!oi.getObjectName().equals(interceptor.getAccessControlMBeanON())){
++ set.add(oi);
++ }
++ }
++ return set;
+ }
+
+ @Override
- public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
- return mbs.queryNames(name, query);
++ public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
++ return filterAccessControlMBean(mbs.queryNames(name, query));
++ }
++
++ private Set<ObjectName> filterAccessControlMBean(Set<ObjectName> queryNames) {
++ Set<ObjectName> set = new HashSet<ObjectName>();
++ for(ObjectName oi : queryNames) {
++ if(!oi.equals(interceptor.getAccessControlMBeanON())){
++ set.add(oi);
++ }
++ }
++ return set;
+ }
+
+ @Override
+ public boolean isRegistered(ObjectName name) {
+ return mbs.isRegistered(name);
+ }
+
+ @Override
+ public Integer getMBeanCount() {
+ return mbs.getMBeanCount();
+ }
+
+ @Override
+ public Object getAttribute(ObjectName name, String attribute) throws MBeanException, AttributeNotFoundException,
+ InstanceNotFoundException, ReflectionException {
- doAuthorization(name, "getAttribute", new Object[]{attribute});
- return mbs.getAttribute(name, attribute);
++ ResourceOperationContext ctx = doAuthorization(name, GET_ATTRIBUTE, new Object[]{attribute});
++ Object result = mbs.getAttribute(name, attribute);
++ doAuthorizationPost(name, GET_ATTRIBUTE, ctx, result);
++ return result;
+ }
+
+ @Override
+ public AttributeList getAttributes(ObjectName name, String[] attributes) throws InstanceNotFoundException,
+ ReflectionException {
- doAuthorization(name, "getAttributes", new Object[]{attributes});
- return mbs.getAttributes(name, attributes);
++ ResourceOperationContext ctx = doAuthorization(name, GET_ATTRIBUTES, new Object[]{attributes});
++ AttributeList result = mbs.getAttributes(name, attributes);
++ doAuthorizationPost(name,GET_ATTRIBUTES, ctx, result);
++ return result;
+ }
+
+ @Override
+ public void setAttribute(ObjectName name, Attribute attribute) throws InstanceNotFoundException,
+ AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException {
- doAuthorization(name, "setAttribute", new Object[]{attribute});
++ ResourceOperationContext ctx = doAuthorization(name, SET_ATTRIBUTE, new Object[]{attribute});
+ mbs.setAttribute(name, attribute);
++ doAuthorizationPost(name, SET_ATTRIBUTE, ctx, null);
+ }
+
+ @Override
+ public AttributeList setAttributes(ObjectName name, AttributeList attributes) throws InstanceNotFoundException,
+ ReflectionException {
- doAuthorization(name, "setAttributes", new Object[]{attributes});
- return mbs.setAttributes(name, attributes);
++ ResourceOperationContext ctx = doAuthorization(name, SET_ATTRIBUTES, new Object[]{attributes});
++ AttributeList result = mbs.setAttributes(name, attributes);
++ doAuthorizationPost(name, SET_ATTRIBUTES, ctx, result);
++ return result;
+ }
+
+ @Override
+ public Object invoke(ObjectName name, String operationName, Object[] params, String[] signature)
+ throws InstanceNotFoundException, MBeanException, ReflectionException {
- doAuthorization(name, operationName, new Object[]{params, signature});
- return mbs.invoke(name, operationName, params, signature);
++ ResourceOperationContext ctx = doAuthorization(name, operationName, new Object[]{params, signature});
++ Object result = mbs.invoke(name, operationName, params, signature);
++ doAuthorizationPost(name, operationName, ctx, result);
++ return result;
+ }
+
+ @Override
+ public String getDefaultDomain() {
+ return mbs.getDefaultDomain();
+ }
+
+ @Override
+ public String[] getDomains() {
+ return mbs.getDomains();
+ }
+
+ @Override
+ public void addNotificationListener(ObjectName name, NotificationListener listener, NotificationFilter filter,
+ Object handback) throws InstanceNotFoundException {
+ mbs.addNotificationListener(name, listener, filter, handback);
+ }
+
+ @Override
+ public void addNotificationListener(ObjectName name, ObjectName listener, NotificationFilter filter, Object handback)
+ throws InstanceNotFoundException {
+ mbs.addNotificationListener(name, listener, filter, handback);
+ }
+
+ @Override
+ public void removeNotificationListener(ObjectName name, ObjectName listener) throws InstanceNotFoundException,
+ ListenerNotFoundException {
+ mbs.removeNotificationListener(name, listener);
+ }
+
+ @Override
+ public void removeNotificationListener(ObjectName name, ObjectName listener, NotificationFilter filter,
+ Object handback) throws InstanceNotFoundException, ListenerNotFoundException {
+ mbs.removeNotificationListener(name, listener, filter, handback);
+
+ }
+
+ @Override
+ public void removeNotificationListener(ObjectName name, NotificationListener listener)
+ throws InstanceNotFoundException, ListenerNotFoundException {
+ mbs.removeNotificationListener(name, listener);
+ }
+
+ @Override
+ public void removeNotificationListener(ObjectName name, NotificationListener listener, NotificationFilter filter,
+ Object handback) throws InstanceNotFoundException, ListenerNotFoundException {
+ mbs.removeNotificationListener(name, listener, filter, handback);
+ }
+
+ @Override
+ public MBeanInfo getMBeanInfo(ObjectName name) throws InstanceNotFoundException, IntrospectionException,
+ ReflectionException {
+ return mbs.getMBeanInfo(name);
+ }
+
+ @Override
+ public boolean isInstanceOf(ObjectName name, String className) throws InstanceNotFoundException {
+ return mbs.isInstanceOf(name, className);
+ }
+
+ @Override
+ public Object instantiate(String className) throws ReflectionException, MBeanException {
+ return mbs.instantiate(className);
+ }
+
+ @Override
+ public Object instantiate(String className, ObjectName loaderName) throws ReflectionException, MBeanException,
+ InstanceNotFoundException {
+ return mbs.instantiate(className, loaderName);
+ }
+
+ @Override
+ public Object instantiate(String className, Object[] params, String[] signature) throws ReflectionException,
+ MBeanException {
+ return mbs.instantiate(className, params, signature);
+ }
+
+ @Override
+ public Object instantiate(String className, ObjectName loaderName, Object[] params, String[] signature)
+ throws ReflectionException, MBeanException, InstanceNotFoundException {
+ return mbs.instantiate(className, params, signature);
+ }
+
++ @SuppressWarnings("deprecation")
+ @Override
+ public ObjectInputStream deserialize(ObjectName name, byte[] data) throws InstanceNotFoundException,
+ OperationsException {
+ return mbs.deserialize(name, data);
+ }
+
+ @Override
+ public ObjectInputStream deserialize(String className, byte[] data) throws OperationsException, ReflectionException {
+ return deserialize(className, data);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public ObjectInputStream deserialize(String className, ObjectName loaderName, byte[] data)
+ throws InstanceNotFoundException, OperationsException, ReflectionException {
+ return mbs.deserialize(className, loaderName, data);
+ }
+
+ @Override
+ public ClassLoader getClassLoaderFor(ObjectName mbeanName) throws InstanceNotFoundException {
+ return mbs.getClassLoaderFor(mbeanName);
+ }
+
+ @Override
+ public ClassLoader getClassLoader(ObjectName loaderName) throws InstanceNotFoundException {
+ return mbs.getClassLoader(loaderName);
+ }
+
+ @Override
+ public ClassLoaderRepository getClassLoaderRepository() {
+ return mbs.getClassLoaderRepository();
+ }
+
+ @Override
+ public MBeanServer getMBeanServer() {
+ return mbs;
+ }
+
+ @Override
+ public void setMBeanServer(MBeanServer mbs) {
+ this.mbs = mbs;
+ }
+
+ }
++
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5c01d5f4/geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/ManagementInterceptor.java
----------------------------------------------------------------------
diff --cc geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/ManagementInterceptor.java
index 0000000,c4e7dc5..aa5d194
mode 000000,100644..100644
--- a/geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/ManagementInterceptor.java
+++ b/geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/ManagementInterceptor.java
@@@ -1,0 -1,271 +1,385 @@@
+ /*
+ * 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 com.gemstone.gemfire.management.internal.security;
+
++import static com.gemstone.gemfire.management.internal.security.ResourceConstants.ACCESS_DENIED_MESSAGE;
++import static com.gemstone.gemfire.management.internal.security.ResourceConstants.GET_ATTRIBUTE;
++import static com.gemstone.gemfire.management.internal.security.ResourceConstants.GET_ATTRIBUTES;
++import static com.gemstone.gemfire.management.internal.security.ResourceConstants.GET_PREFIX;
++import static com.gemstone.gemfire.management.internal.security.ResourceConstants.PASSWORD;
++import static com.gemstone.gemfire.management.internal.security.ResourceConstants.PROCESS_COMMAND;
++import static com.gemstone.gemfire.management.internal.security.ResourceConstants.SET_ATTRIBUTE;
++import static com.gemstone.gemfire.management.internal.security.ResourceConstants.SET_ATTRIBUTES;
++import static com.gemstone.gemfire.management.internal.security.ResourceConstants.SET_PREFIX;
++import static com.gemstone.gemfire.management.internal.security.ResourceConstants.USER_NAME;
++import static com.gemstone.gemfire.management.internal.security.ResourceConstants.WRONGE_CREDENTIALS_MESSAGE;
++
+ import java.lang.management.ManagementFactory;
++import java.lang.reflect.Method;
+ import java.security.AccessControlContext;
+ import java.security.AccessController;
+ import java.security.Principal;
+ import java.util.Collections;
++import java.util.List;
++import java.util.Map.Entry;
+ import java.util.Properties;
+ import java.util.Set;
++import java.util.concurrent.ConcurrentHashMap;
++import java.util.concurrent.ConcurrentMap;
+
++import javax.management.Attribute;
++import javax.management.AttributeList;
+ import javax.management.InstanceAlreadyExistsException;
+ import javax.management.MBeanRegistrationException;
+ import javax.management.MBeanServer;
+ import javax.management.MalformedObjectNameException;
+ import javax.management.NotCompliantMBeanException;
+ import javax.management.ObjectName;
+ import javax.management.remote.JMXAuthenticator;
+ import javax.management.remote.JMXPrincipal;
+ import javax.management.remote.MBeanServerForwarder;
+ import javax.security.auth.Subject;
+
+ import org.apache.logging.log4j.Logger;
+
+ import com.gemstone.gemfire.GemFireConfigException;
-import com.gemstone.gemfire.internal.logging.LogService;
++import com.gemstone.gemfire.cache.Cache;
++import com.gemstone.gemfire.distributed.DistributedSystem;
++import com.gemstone.gemfire.distributed.internal.DistributionConfig;
++import com.gemstone.gemfire.internal.ClassLoadUtil;
++import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
++import com.gemstone.gemfire.internal.lang.StringUtils;
++import com.gemstone.gemfire.internal.logging.InternalLogWriter;
++import com.gemstone.gemfire.management.internal.ManagementConstants;
+ import com.gemstone.gemfire.security.AccessControl;
++import com.gemstone.gemfire.security.AuthenticationFailedException;
+ import com.gemstone.gemfire.security.Authenticator;
+
-@SuppressWarnings("rawtypes")
++/**
++ *
++ * ManagementInterceptor is central go-to place for all M&M Clients Authentication and Authorization
++ * requests
++ *
++ * @author tushark
++ * @since 9.0
++ *
++ */
+ public class ManagementInterceptor implements JMXAuthenticator {
+
- public static final String USER_NAME = "security-username";
- public static final String PASSWORD = "security-password";
- public static final String OBJECT_NAME_ACCESSCONTROL = "GemFire:service=AccessControl,type=Distributed";
- private MBeanServerWrapper mBeanServerForwarder;
- private Logger logger;
++ // FIXME: Merged from GEODE-17. Are they necessary?
++ public static final String USER_NAME = "security-username";
++ public static final String PASSWORD = "security-password";
++ public static final String OBJECT_NAME_ACCESSCONTROL = "GemFire:service=AccessControl,type=Distributed";
+
- public ManagementInterceptor(Logger logger) {
- this.logger = logger;
- this.mBeanServerForwarder = new MBeanServerWrapper(this);
- registerAccessContorlMbean();
- LogService.getLogger().info("Starting management interceptor");
- }
++ private MBeanServerWrapper mBeanServerForwarder;
++ private Logger logger;
++ private ObjectName accessControlMBeanON;
++ private Cache cache;
++ private String authzFactoryName;
++ private String postAuthzFactoryName;
++ private String authenticatorFactoryName;
++ private ConcurrentMap<Principal, AccessControl> cachedAuthZCallback;
++ private ConcurrentMap<Principal, AccessControl> cachedPostAuthZCallback;
++
++ public ManagementInterceptor(Cache gemFireCacheImpl, Logger logger) {
++ this.cache = gemFireCacheImpl;
++ this.logger = logger;
++ this.mBeanServerForwarder = new MBeanServerWrapper(this);
++ DistributedSystem system = cache.getDistributedSystem();
++ Properties sysProps = system.getProperties();
++ this.authzFactoryName = sysProps.getProperty(DistributionConfig.SECURITY_CLIENT_ACCESSOR_NAME);
++ this.postAuthzFactoryName = sysProps.getProperty(DistributionConfig.SECURITY_CLIENT_ACCESSOR_PP_NAME);
++ this.authenticatorFactoryName = sysProps.getProperty(DistributionConfig.SECURITY_CLIENT_AUTHENTICATOR_NAME);
++ this.cachedAuthZCallback = new ConcurrentHashMap<Principal, AccessControl>();
++ this.cachedPostAuthZCallback = new ConcurrentHashMap<Principal, AccessControl>();
++ registerAccessContorlMbean();
++ logger.info("Started Management interceptor on JMX connector");
++ }
+
- private void registerAccessContorlMbean() {
++ /**
++ * This method registers an AccessControlMBean which allows any remote JMX Client (for example Pulse) to check for
++ * access allowed for given Operation Code.
++ */
++ private void registerAccessContorlMbean() {
+ try {
- com.gemstone.gemfire.management.internal.security.AccessControl acc = new com.gemstone.gemfire.management.internal.security.AccessControl(this);
- ObjectName name = new ObjectName(OBJECT_NAME_ACCESSCONTROL);
++ com.gemstone.gemfire.management.internal.security.AccessControl acc = new com.gemstone.gemfire.management.internal.security.AccessControl(
++ this);
++ accessControlMBeanON = new ObjectName(ResourceConstants.OBJECT_NAME_ACCESSCONTROL);
+ MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
- Set<ObjectName> names = platformMBeanServer.queryNames(name, null);
- if(names.isEmpty()) {
++ Set<ObjectName> names = platformMBeanServer.queryNames(accessControlMBeanON, null);
++ if (names.isEmpty()) {
+ try {
- platformMBeanServer.registerMBean(acc, name);
- logger.info("Registered AccessContorlMBean on " + name);
++ platformMBeanServer.registerMBean(acc, accessControlMBeanON);
++ logger.info("Registered AccessContorlMBean on " + accessControlMBeanON);
+ } catch (InstanceAlreadyExistsException e) {
- throw new GemFireConfigException("Error while configuring accesscontrol for jmx resource",e);
++ throw new GemFireConfigException("Error while configuring accesscontrol for jmx resource", e);
+ } catch (MBeanRegistrationException e) {
- throw new GemFireConfigException("Error while configuring accesscontrol for jmx resource",e);
++ throw new GemFireConfigException("Error while configuring accesscontrol for jmx resource", e);
+ } catch (NotCompliantMBeanException e) {
- throw new GemFireConfigException("Error while configuring accesscontrol for jmx resource",e);
++ throw new GemFireConfigException("Error while configuring accesscontrol for jmx resource", e);
+ }
+ }
- } catch (MalformedObjectNameException e) {
- e.printStackTrace();
++ } catch (MalformedObjectNameException e) {
++ throw new GemFireConfigException("Error while configuring accesscontrol for jmx resource", e);
+ }
+ }
+
++ /**
++ * Delegates authentication to GemFire Authenticator
++ *
++ * @throws SecurityException
++ * if authentication fails
++ */
+ @Override
- public Subject authenticate(Object credentials) {
- String username = null, password = null;
- if (!(credentials instanceof String[])) {
- // Special case for null so we get a more informative message
- if (credentials == null) {
- // throw new SecurityException("Credentials required");
- username = "empty";
- password = "emptypwd";
- }
- // throw new SecurityException("Credentials should be String[]");
- username = "empty";
- password = "emptypwd";
-
- //TODO ***** Remove empty stuff
-
- } else {
- final String[] aCredentials = (String[]) credentials;
- username = (String) aCredentials[0];
- password = (String) aCredentials[1];
- }
++ public Subject authenticate(Object credentials) {
++ String username = null, password = null;
++ Properties pr = new Properties();
++ if (credentials instanceof String[]) {
++ final String[] aCredentials = (String[]) credentials;
++ username = (String) aCredentials[0];
++ password = (String) aCredentials[1];
++ pr.put(USER_NAME, username);
++ pr.put(PASSWORD, password);
++ } else if (credentials instanceof Properties) {
++ pr = (Properties) credentials;
++ } else {
++ throw new SecurityException(WRONGE_CREDENTIALS_MESSAGE);
++ }
++
++ try {
++ Principal principal = getAuthenticator(cache.getDistributedSystem().getSecurityProperties()).authenticate(pr,
++ cache.getDistributedSystem().getDistributedMember());
++ return new Subject(true, Collections.singleton(new JMXPrincipal(principal.getName())), Collections.EMPTY_SET,
++ Collections.EMPTY_SET);
++ } catch (AuthenticationFailedException e) {
++ //wrap inside Security exception. AuthenticationFailedException is gemfire class
++ //which generic JMX client can't serialize
++ throw new SecurityException("Authentication Failed " + e.getMessage());
++ }
++
++ }
+
- Properties pr = new Properties();
- pr.put(USER_NAME, username);
- pr.put(PASSWORD, password);
- getAuthenticator(pr).authenticate(pr, null);
- return new Subject(true, Collections.singleton(new JMXPrincipal(username)), Collections.EMPTY_SET,
- Collections.EMPTY_SET);
- }
++ /**
++ * Builds ResourceOperationContext for the given JMX MBean Request for delegates Authorization to
++ * gemfire AccessControl plugin with context as parameter
++ *
++ *
++ * @param name
++ * @param methodName
++ * @param params
++ *
++ * @throws SecurityException
++ * if access is not granted
++ */
++ public ResourceOperationContext authorize(ObjectName name, final String methodName, Object[] params) {
++
++ if (StringUtils.isBlank(authzFactoryName)){
++ return com.gemstone.gemfire.management.internal.security.AccessControlContext.ACCESS_GRANTED_CONTEXT;
++ }
+
- @SuppressWarnings("unchecked")
- public void authorize(ObjectName name, final String methodName, Object[] params) {
-
- try {
- ObjectName accessControlMBean = new ObjectName(OBJECT_NAME_ACCESSCONTROL);
- if (name.equals(accessControlMBean)) {
- logger.info("Granting access to accessContorlMXBean.. name="+name);
- return;
- }
- } catch (MalformedObjectNameException e) {
- // TODO Auto-generated catch block
- // e.printStackTrace();
++ if (name.equals(accessControlMBeanON)) {
++ return com.gemstone.gemfire.management.internal.security.AccessControlContext.ACCESS_GRANTED_CONTEXT;
+ }
-
-
- //Only apply for gemfire domain
- String domain = name.getDomain();
- if(!"GemFire".equals(domain))
- return;
-
- // Retrieve Subject from current AccessControlContext
- AccessControlContext acc = AccessController.getContext();
- Subject subject = Subject.getSubject(acc);
- // Allow operations performed locally on behalf of the connector server
- // itself
- if (subject == null) {
- return;
- }
+
- // Restrict access to "createMBean" and "unregisterMBean" to any user
- if (methodName.equals("createMBean")
- || methodName.equals("unregisterMBean")) {
- throw new SecurityException("Access denied");
- }
++ if (!ManagementConstants.OBJECTNAME__DEFAULTDOMAIN.equals(name.getDomain()))
++ return com.gemstone.gemfire.management.internal.security.AccessControlContext.ACCESS_GRANTED_CONTEXT;
+
- // Retrieve JMXPrincipal from Subject
- Set<JMXPrincipal> principals = subject
- .getPrincipals(JMXPrincipal.class);
- Set<Object> pubCredentials = subject.getPublicCredentials();
-
- /*System.out.println("JMXPrincipal " + principals);
- System.out.println("Principals " + subject.getPrincipals());
- System.out.println("PubCredentials " + subject.getPublicCredentials());*/
- //add condition -> check if accessor is configured
- if (principals == null || principals.isEmpty()
- /*|| pubCredentials.size() < 1 */) {
- throw new SecurityException("Access denied");
- }
-
- Principal principal = principals.iterator().next();
-
- //Give read access globally : TODO : Need to change this to map to proper getter
- LogService.getLogger().info("Name=" + name + " methodName=" + methodName + " principal="+ principal.getName());
- if("getAttribute".equals(methodName) || "getAttributes".equals(methodName))
- return;
-
- //TODO : if method=getAttributes params is directly availalbe
- //TODO : if method is operation then params is array array[0] = actual params, array[1]= signature
-
- ResourceOperationContext resourceContext = buildContext(name,methodName, params);
- boolean authorized = getAccessControl(principal).authorizeOperation(null, resourceContext);
- LogService.getLogger().info("Name=" + name + " methodName=" + methodName
- + " result="+authorized + " principal="+ principal.getName());
- if(!authorized)
- throw new SecurityException("Access denied");
- }
++ AccessControlContext acc = AccessController.getContext();
++ Subject subject = Subject.getSubject(acc);
++
++ // Allow operations performed locally on behalf of the connector server itself
++ if (subject == null) {
++ return com.gemstone.gemfire.management.internal.security.AccessControlContext.ACCESS_GRANTED_CONTEXT;
++ }
+
- public MBeanServerForwarder getMBeanServerForwarder() {
- return mBeanServerForwarder;
- }
++ if (methodName.equals(ResourceConstants.CREATE_MBEAN) || methodName.equals(ResourceConstants.UNREGISTER_MBEAN)) {
++ throw new SecurityException(ACCESS_DENIED_MESSAGE);
++ }
+
- private static Class accessControlKlass = null;
-
- public AccessControl getAccessControl(Principal principal) {
- if(accessControlKlass==null) {
- String authorizeKlass = System.getProperty(ResourceConstants.RESORUCE_AUTH_ACCESSOR);
- try {
- accessControlKlass = Class.forName(authorizeKlass);
- } catch (ClassNotFoundException e) {
- logger.error(e);
- throw new GemFireConfigException("Error while configuring accesscontrol for jmx resource",e);
- }
- }
-
- try {
- AccessControl accessControl = (AccessControl) accessControlKlass.newInstance();
- accessControl.init(principal, null, null); //TODO pass proper params
- LogService.getLogger().info("Returning resource accessControl");
- return accessControl;
- } catch (InstantiationException e) {
- logger.error(e);
- throw new GemFireConfigException("Error while configuring accesscontrol for jmx resource",e);
- } catch (IllegalAccessException e) {
- logger.error(e);
- throw new GemFireConfigException("Error while configuring accesscontrol for jmx resource",e);
- }
- }
++ Set<JMXPrincipal> principals = subject.getPrincipals(JMXPrincipal.class);
+
- private static Class authenticatorClass = null;
- private Authenticator getAuthenticator(Properties pr) {
- if(authenticatorClass==null) {
- String authenticatorKlass = System.getProperty(ResourceConstants.RESORUCE_AUTHENTICATOR);
- try {
- authenticatorClass = Class.forName(authenticatorKlass);
- } catch (ClassNotFoundException e) {
- logger.error(e);
- throw new GemFireConfigException("Error while configuring accesscontrol for jmx resource",e);
- }
- }
-
- try {
- Authenticator authenticator = (Authenticator) authenticatorClass.newInstance();
- authenticator.init(pr, null, null); //TODO pass proper params
- LogService.getLogger().info("Returning resource authenticator " + authenticator);
- return authenticator;
- } catch (InstantiationException e) {
- logger.error(e);
- throw new GemFireConfigException("Error while configuring accesscontrol for jmx resource",e);
- } catch (IllegalAccessException e) {
- logger.error(e);
- throw new GemFireConfigException("Error while configuring accesscontrol for jmx resource",e);
- }
- }
++ if (principals == null || principals.isEmpty()) {
++ throw new SecurityException(ACCESS_DENIED_MESSAGE);
++ }
+
- private ResourceOperationContext buildContext(ObjectName name, String methodName, Object[] params) {
- if (params != null) {
- LogService.getLogger().info("Params length=" + params.length);
- for (int i = 0; i < params.length; i++) {
- LogService.getLogger().info("Params[" + i + "] is " + arrayString(params[i]));
++ Principal principal = principals.iterator().next();
++
++
++ if (logger.isDebugEnabled()) {
++ logger.debug("Name=" + name + " methodName=" + methodName + " principal=" + principal.getName());
++ }
++
++ AccessControl accessControl = getAccessControl(principal, false);
++ String method = methodName;
++ if (methodName.equals(GET_ATTRIBUTE)) {
++ method = GET_PREFIX + (String) params[0];
++ } else if(methodName.equals(GET_ATTRIBUTES)) {
++ //Pass to first attribute getter
++ String[] attrs = (String[]) params[0];
++ method = GET_PREFIX + attrs[0];
++ } else if(methodName.equals(SET_ATTRIBUTE)) {
++ Attribute attribute = (Attribute) params[0];
++ method = SET_PREFIX + attribute.getName();
++ }
++
++ if (methodName.equals(SET_ATTRIBUTES)) {
++ AttributeList attrList = (AttributeList) params[0];
++ List<Attribute> list = attrList.asList();
++ ResourceOperationContext setterContext = null;
++ SetAttributesOperationContext resourceContext = new SetAttributesOperationContext();
++ for(int i=0;i<list.size();i++) {
++ Attribute attribute = list.get(i);
++ String setter = SET_PREFIX + attribute.getName();
++ setterContext = buildContext(name,setter,null);
++ boolean authorized = accessControl.authorizeOperation(null, setterContext);
++ if (logger.isDebugEnabled()) {
++ logger.debug("Name=" + name + " methodName=" + methodName + " result=" + authorized + " principal="
++ + principal.getName());
++ }
++ if (!authorized)
++ throw new SecurityException(ACCESS_DENIED_MESSAGE);
++ else
++ resourceContext.addAttribute(attribute.getName(), setterContext);
++ }
++ return resourceContext;
++ } else {
++ ResourceOperationContext resourceContext = buildContext(name, method, params);
++ boolean authorized = accessControl.authorizeOperation(null, resourceContext);
++ if (logger.isDebugEnabled()) {
++ logger.debug("Name=" + name + " methodName=" + methodName + " result=" + authorized + " principal="
++ + principal.getName());
++ }
++
++ if (!authorized)
++ throw new SecurityException(ACCESS_DENIED_MESSAGE);
++ return resourceContext;
++ }
++ }
++
++ public MBeanServerForwarder getMBeanServerForwarder() {
++ return mBeanServerForwarder;
++ }
++
++ public AccessControl getAccessControl(Principal principal, boolean isPost) {
++ if (!isPost) {
++ if (cachedAuthZCallback.containsKey(principal)) {
++ return cachedAuthZCallback.get(principal);
++ } else if (!StringUtils.isBlank(authzFactoryName)) {
++ try {
++ Method authzMethod = ClassLoadUtil.methodFromName(authzFactoryName);
++ AccessControl authzCallback = (AccessControl) authzMethod.invoke(null, (Object[]) null);
++ authzCallback.init(principal, null, cache);
++ cachedAuthZCallback.put(principal, authzCallback);
++ return authzCallback;
++ } catch (Exception ex) {
++ throw new AuthenticationFailedException(
++ LocalizedStrings.HandShake_FAILED_TO_ACQUIRE_AUTHENTICATOR_OBJECT.toLocalizedString(), ex);
++ }
++ }
++ } else {
++ if (cachedPostAuthZCallback.containsKey(principal)) {
++ return cachedPostAuthZCallback.get(principal);
++ } else if (!StringUtils.isBlank(postAuthzFactoryName)) {
++ try {
++ Method authzMethod = ClassLoadUtil.methodFromName(postAuthzFactoryName);
++ AccessControl postAuthzCallback = (AccessControl) authzMethod.invoke(null, (Object[]) null);
++ postAuthzCallback.init(principal, null, cache);
++ cachedPostAuthZCallback.put(principal, postAuthzCallback);
++ return postAuthzCallback;
++ } catch (Exception ex) {
++ throw new AuthenticationFailedException(
++ LocalizedStrings.HandShake_FAILED_TO_ACQUIRE_AUTHENTICATOR_OBJECT.toLocalizedString(), ex);
++ }
+ }
+ }
++ return null;
++ }
+
++ private Authenticator getAuthenticator(Properties gfSecurityProperties) throws AuthenticationFailedException {
++ Authenticator auth;
++ try {
++ Method instanceGetter = ClassLoadUtil.methodFromName(this.authenticatorFactoryName);
++ auth = (Authenticator) instanceGetter.invoke(null, (Object[]) null);
++ } catch (Exception ex) {
++ throw new AuthenticationFailedException(
++ LocalizedStrings.HandShake_FAILED_TO_ACQUIRE_AUTHENTICATOR_OBJECT.toLocalizedString(), ex);
++ }
++ if (auth == null) {
++ throw new AuthenticationFailedException(
++ LocalizedStrings.HandShake_AUTHENTICATOR_INSTANCE_COULD_NOT_BE_OBTAINED.toLocalizedString());
++ }
++ auth.init(gfSecurityProperties,(InternalLogWriter) this.cache.getLogger(), (InternalLogWriter) this.cache.getSecurityLogger());
++ return auth;
++ }
++
++ private ResourceOperationContext buildContext(ObjectName name, String methodName, Object[] params) {
+ String service = name.getKeyProperty("service");
- // only member mbean does not have service KeyProperty
- if (service == null && "processCommand".equals(methodName)) {
++ if (service == null && PROCESS_COMMAND.equals(methodName)) {
+ Object[] array = (Object[]) params[0];
+ String command = (String) array[0];
- CLIOperationContext context = new CLIOperationContext(command);
- LogService.getLogger().info("Returning CLIContext for " + methodName);
++ CLIOperationContext context = new CLIOperationContext(command);
+ return context;
- } else {
++ } else {
+ ResourceOperationContext context = new JMXOperationContext(name, methodName);
- LogService.getLogger().info("Returning JMXOperationContext for " + methodName);
+ return context;
+ }
+ }
+
- private String arrayString(Object object) {
- StringBuilder sb = new StringBuilder();
- if (object instanceof Object[]) {
- Object[] array = (Object[]) object;
- for (Object a : array)
- sb.append(a).append(" ");
++ public ObjectName getAccessControlMBeanON() {
++ return accessControlMBeanON;
++ }
++
++ public void postAuthorize(ObjectName name, final String methodName, ResourceOperationContext context, Object result) {
++
++ if (StringUtils.isBlank(postAuthzFactoryName)){
++ return ;
++ }
++
++ context.setPostOperationResult(result);
++
++ if (context.equals(com.gemstone.gemfire.management.internal.security.AccessControlContext.ACCESS_GRANTED_CONTEXT))
++ return;
++
++ AccessControlContext acc = AccessController.getContext();
++ Subject subject = Subject.getSubject(acc);
++ Set<JMXPrincipal> principals = subject.getPrincipals(JMXPrincipal.class);
++ if (principals == null || principals.isEmpty()) {
++ throw new SecurityException(ACCESS_DENIED_MESSAGE);
++ }
++ Principal principal = principals.iterator().next();
++ AccessControl accessControl = getAccessControl(principal, true);
++ if (context instanceof SetAttributesOperationContext) {
++ SetAttributesOperationContext setterContext = (SetAttributesOperationContext) context;
++ for (Entry<String, ResourceOperationContext> e : setterContext.getAttributesContextMap().entrySet()) {
++ //TODO : Retrieve proper values from AttributeList and set to its jmxContext
++ e.getValue().setPostOperationResult(result);
++ boolean authorized = accessControl.authorizeOperation(null, e.getValue());
++ if (!authorized)
++ throw new SecurityException(ACCESS_DENIED_MESSAGE);
++ }
++ } else {
++ boolean authorized = accessControl.authorizeOperation(null, context);
++ if (logger.isDebugEnabled()) {
++ logger.debug("postAuthorize: Name=" + name + " methodName=" + methodName + " result=" + authorized
++ + " principal=" + principal.getName());
++ }
++ if (!authorized)
++ throw new SecurityException(ACCESS_DENIED_MESSAGE);
+ }
- return sb.toString();
+ }
+
+ }
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5c01d5f4/geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/Resource.java
----------------------------------------------------------------------
diff --cc geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/Resource.java
index 0000000,5a47c07..d6252d5
mode 000000,100644..100644
--- a/geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/Resource.java
+++ b/geode-core/src/main/java/com/gemstone/gemfire/management/internal/security/Resource.java
@@@ -1,0 -1,26 +1,33 @@@
+ /*
+ * 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 com.gemstone.gemfire.management.internal.security;
+
++/**
++ *
++ * @author tushark
++ *
++ * @since 9.0
++ */
+ public enum Resource {
+ DISTRIBUTED_SYSTEM,
+ MEMBER,
+ REGION,
+ DISKSTORE,
+ GATEWAY_SENDER,
- GATEWAT_LISTENER,
++ GATEWAY_RECEIVER,
+ }
++