You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by no...@apache.org on 2015/08/11 16:28:50 UTC

svn commit: r1695308 - in /lucene/dev/trunk/solr: core/src/java/org/apache/solr/handler/admin/ core/src/java/org/apache/solr/security/ core/src/java/org/apache/solr/util/ core/src/test/org/apache/solr/handler/admin/ core/src/test/org/apache/solr/securi...

Author: noble
Date: Tue Aug 11 14:28:50 2015
New Revision: 1695308

URL: http://svn.apache.org/r1695308
Log:
SOLR-7838: changed the permissions froma map to an array so that order is obvious

Modified:
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/security/RuleBasedAuthorizationPlugin.java
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CommandOperation.java
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/admin/SecurityConfHandlerTest.java
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/security/TestRuleBasedAuthorizationPlugin.java
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/util/TestUtils.java
    lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/common/util/Utils.java

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java?rev=1695308&r1=1695307&r2=1695308&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java Tue Aug 11 14:28:50 2015
@@ -18,6 +18,7 @@ package org.apache.solr.handler.admin;
  */
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -141,9 +142,14 @@ public class SecurityConfHandler extends
   }
 
   public static Map<String, Object> getMapValue(Map<String, Object> lookupMap, String key) {
-    Map<String, Object> roleMap = (Map<String, Object>) lookupMap.get(key);
-    if (roleMap == null) lookupMap.put(key, roleMap = new LinkedHashMap<>());
-    return roleMap;
+    Map<String, Object> m = (Map<String, Object>) lookupMap.get(key);
+    if (m == null) lookupMap.put(key, m = new LinkedHashMap<>());
+    return m;
+  }
+  public static List getListValue(Map<String, Object> lookupMap, String key) {
+    List l = (List) lookupMap.get(key);
+    if (l == null) lookupMap.put(key, l= new ArrayList());
+    return l;
   }
 
   @Override

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/security/RuleBasedAuthorizationPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/security/RuleBasedAuthorizationPlugin.java?rev=1695308&r1=1695307&r2=1695308&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/security/RuleBasedAuthorizationPlugin.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/security/RuleBasedAuthorizationPlugin.java Tue Aug 11 14:28:50 2015
@@ -39,6 +39,8 @@ import org.apache.solr.util.CommandOpera
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static java.util.Collections.singleton;
+import static org.apache.solr.handler.admin.SecurityConfHandler.getListValue;
 import static org.apache.solr.handler.admin.SecurityConfHandler.getMapValue;
 import static org.apache.solr.common.params.CommonParams.NAME;
 import static org.apache.solr.common.util.Utils.getDeepCopy;
@@ -86,12 +88,15 @@ public class RuleBasedAuthorizationPlugi
   @Override
   public AuthorizationResponse authorize(AuthorizationContext context) {
     List<AuthorizationContext.CollectionRequest> collectionRequests = context.getCollectionRequests();
-    if (collectionRequests != null) {
-      for (AuthorizationContext.CollectionRequest collreq : collectionRequests) {
-        //check permissions for each collection
-        MatchStatus flag = checkCollPerm(mapping.get(collreq.collectionName), context);
-        if (flag != MatchStatus.NO_PERMISSIONS_FOUND) return flag.rsp;
-      }
+    if (collectionRequests.isEmpty()) {
+      MatchStatus flag = checkCollPerm(mapping.get(""), context);
+      return flag.rsp;
+    }
+
+    for (AuthorizationContext.CollectionRequest collreq : collectionRequests) {
+      //check permissions for each collection
+      MatchStatus flag = checkCollPerm(mapping.get(collreq.collectionName), context);
+      if (flag != MatchStatus.NO_PERMISSIONS_FOUND) return flag.rsp;
     }
     //check global permissions.
     MatchStatus flag = checkCollPerm(mapping.get(null), context);
@@ -160,12 +165,11 @@ public class RuleBasedAuthorizationPlugi
       String roleName = (String) e.getKey();
       usersVsRoles.put(roleName, readValueAsSet(map, roleName));
     }
-    map = getMapValue(initInfo, "permissions");
-    for (Object o : map.entrySet()) {
-      Map.Entry e = (Map.Entry) o;
+    List<Map> perms = getListValue(initInfo, "permissions");
+    for (Map o : perms) {
       Permission p;
       try {
-        p = Permission.load((String) e.getKey(), (Map) e.getValue());
+        p = Permission.load(o);
       } catch (Exception exp) {
         log.error("Invalid permission ", exp);
         continue;
@@ -175,8 +179,8 @@ public class RuleBasedAuthorizationPlugi
     }
   }
 
+  //this is to do optimized lookup of permissions for a given collection/path
   private void add2Mapping(Permission permission) {
-    //this is to do optimized lookup of permissions for a given collection/path
     for (String c : permission.collections) {
       WildCardSupportMap m = mapping.get(c);
       if (m == null) mapping.put(c, m = new WildCardSupportMap());
@@ -186,7 +190,6 @@ public class RuleBasedAuthorizationPlugi
         perms.add(permission);
       }
     }
-
   }
 
   /**
@@ -199,7 +202,14 @@ public class RuleBasedAuthorizationPlugi
   static Set<String> readValueAsSet(Map m, String key) {
     Set<String> result = new HashSet<>();
     Object val = m.get(key);
-    if (val == null) return null;
+    if (val == null) {
+      if("collection".equals(key)){
+        //for collection collection: null means a core admin/ collection admin request
+        // otherwise it means a request where collection name is ignored
+        return m.containsKey(key) ?  singleton("") : singleton(null);
+      }
+      return null;
+    }
     if (val instanceof Collection) {
       Collection list = (Collection) val;
       for (Object o : list) result.add(String.valueOf(o));
@@ -223,13 +233,15 @@ public class RuleBasedAuthorizationPlugi
     private Permission() {
     }
 
-    static Permission load(String name, Map m) {
+    static Permission load(Map m) {
       Permission p = new Permission();
+      String name = (String) m.get(NAME);
       if (!m.containsKey("role")) throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "role not specified");
       p.role = readValueAsSet(m, "role");
       if (well_known_permissions.containsKey(name)) {
         HashSet<String> disAllowed = new HashSet<>(knownKeys);
-        disAllowed.remove("role");
+        disAllowed.remove("role");//these are the only
+        disAllowed.remove(NAME);//allowed keys for well-known permissions
         for (String s : disAllowed) {
           if (m.containsKey(s))
             throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, s + " is not a valid key for the permission : " + name);
@@ -245,7 +257,7 @@ public class RuleBasedAuthorizationPlugi
       return p;
     }
 
-    static final Set<String> knownKeys = ImmutableSet.of("collection", "role", "params", "path", "method");
+    static final Set<String> knownKeys = ImmutableSet.of("collection", "role", "params", "path", "method", NAME);
   }
 
   enum MatchStatus {
@@ -275,7 +287,7 @@ public class RuleBasedAuthorizationPlugi
       }
       return set;
     }
-    return set == null ? Collections.singleton(null) : set;
+    return set == null ? singleton(null) : set;
   }
 
   @Override
@@ -328,36 +340,53 @@ public class RuleBasedAuthorizationPlugi
         Map<String, Object> dataMap = op.getDataMap();
         if (op.hasError()) return null;
         dataMap = getDeepCopy(dataMap, 3);
-        dataMap.remove(NAME);
         String before = (String) dataMap.remove("before");
         for (String key : dataMap.keySet()) {
           if (!Permission.knownKeys.contains(key)) op.addError("Unknown key, " + key);
         }
         try {
-          Permission.load(name, dataMap);
+          Permission.load(dataMap);
         } catch (Exception e) {
           op.addError(e.getMessage());
           return null;
         }
-        Map<String, Object> permissions = getMapValue(latestConf, "permissions");
-        if (before == null) {
-          permissions.put(name, dataMap);
-        } else {
-          Map<String, Object> permissionsCopy = new LinkedHashMap<>();
-          for (Map.Entry<String, Object> e : permissions.entrySet()) {
-            if (e.getKey().equals(before)) permissionsCopy.put(name, dataMap);
-            permissionsCopy.put(e.getKey(), e.getValue());
-          }
-          if (!permissionsCopy.containsKey(name)) {
-            op.addError("Invalid 'before' :" + before);
-            return null;
+        List<Map> permissions = getListValue(latestConf, "permissions");
+        List<Map> permissionsCopy = new ArrayList<>();
+        boolean added = false;
+        for (Map e : permissions) {
+          Object n = e.get(NAME);
+          if (n.equals(before) || n.equals(name)) {
+            added = true;
+            permissionsCopy.add(dataMap);
           }
-          latestConf.put("permissions", permissionsCopy);
+          if (!n.equals(name)) permissionsCopy.add(e);
         }
-
+        if (!added && before != null) {
+          op.addError("Invalid 'before' :" + before);
+          return null;
+        }
+        if (!added) permissionsCopy.add(dataMap);
+        latestConf.put("permissions", permissionsCopy);
         return latestConf;
       }
     },
+    UPDATE_PERMISSION("update-permission") {
+      @Override
+      public Map<String, Object> edit(Map<String, Object> latestConf, CommandOperation op) {
+        String name = op.getStr(NAME);
+        if (op.hasError()) return null;
+        for (Map permission : (List<Map>) getListValue(latestConf, "permissions")) {
+          if (name.equals(permission.get(NAME))) {
+            LinkedHashMap copy = new LinkedHashMap<>(permission);
+            copy.putAll(op.getDataMap());
+            op.setCommandData(copy);
+            return SET_PERMISSION.edit(latestConf, op);
+          }
+        }
+        op.addError("No such permission " + name);
+        return null;
+      }
+    },
     DELETE_PERMISSION("delete-permission") {
       @Override
       public Map<String, Object> edit(Map<String, Object> latestConf, CommandOperation op) {
@@ -366,13 +395,23 @@ public class RuleBasedAuthorizationPlugi
           op.addError("Invalid command");
           return null;
         }
-        Map<String, Object> p = getMapValue(latestConf, "permissions");
-        for (String s : names) {
-          if (p.remove(s) == null) {
-            op.addError("Unknown permission : " + s);
-            return null;
+        names = new ArrayList<>(names);
+        List<Map> copy = new ArrayList<>();
+        List<Map> p = getListValue(latestConf, "permissions");
+        for (Map map : p) {
+          Object n = map.get(NAME);
+          if (names.contains(n)) {
+            names.remove(n);
+            continue;
+          } else {
+            copy.add(map);
           }
         }
+        if (!names.isEmpty()) {
+          op.addError("Unknown permission name(s) " + names);
+          return null;
+        }
+        latestConf.put("permissions", copy);
         return latestConf;
       }
     };
@@ -397,16 +436,20 @@ public class RuleBasedAuthorizationPlugi
           "    { " +
           "    security-edit :{" +
           "      path:['/admin/authentication','/admin/authorization']," +
+          "      collection:null," +
           "      method:POST }," +
           "    security-read :{" +
           "      path:['/admin/authentication','/admin/authorization']," +
-          "      method:GET }," +
+          "      collection:null," +
+          "      method:GET}," +
           "    schema-edit :{" +
           "      method:POST," +
           "      path:'/schema/*'}," +
           "    collection-admin-edit :{" +
+              "  collection:null," +
           "      path:'/admin/collections'}," +
           "    collection-admin-read :{" +
+          "      collection:null," +
           "      path:'/admin/collections'}," +
           "    schema-read :{" +
           "      method:GET," +

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CommandOperation.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CommandOperation.java?rev=1695308&r1=1695307&r2=1695308&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CommandOperation.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CommandOperation.java Tue Aug 11 14:28:50 2015
@@ -59,6 +59,9 @@ public class CommandOperation {
     Object o = getMapVal(key);
     return o == null ? def : String.valueOf(o);
   }
+  public void setCommandData(Object o){
+    commandData = o;
+  }
 
   public Map<String,Object> getDataMap() {
     if (commandData instanceof Map) {

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/admin/SecurityConfHandlerTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/admin/SecurityConfHandlerTest.java?rev=1695308&r1=1695307&r2=1695308&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/admin/SecurityConfHandlerTest.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/admin/SecurityConfHandlerTest.java Tue Aug 11 14:28:50 2015
@@ -97,13 +97,56 @@ public class SecurityConfHandlerTest ext
     List tomRoles = (List) userRoles.get("tom");
     assertTrue(tomRoles.contains("admin"));
     assertTrue(tomRoles.contains("dev"));
-    Map permissions = (Map) authzconf.get("permissions");
+    List<Map> permissions = (List<Map>) authzconf.get("permissions");
     assertEquals(2, permissions.size());
-    for (Object p : permissions.entrySet()) {
-      Map.Entry e = (Map.Entry) p;
-      assertEquals("some-permission", e.getKey());
+    for (Map p : permissions) {
+      assertEquals("some-permission", p.get("name"));
       break;
     }
+
+
+    command = "{\n" +
+        "'set-permission':{'name': 'security-edit',\n" +
+        "                  'role': ['admin','dev']\n" +
+        "                  }}";
+    req = new LocalSolrQueryRequest(null, new ModifiableSolrParams());
+    req.getContext().put("httpMethod","POST");
+    req.getContext().put("path","/admin/authorization");
+    o = new ContentStreamBase.ByteArrayStream(command.getBytes(StandardCharsets.UTF_8),"");
+    req.setContentStreams(Collections.singletonList(o));
+    rsp = new SolrQueryResponse();
+    handler.handleRequestBody(req, rsp);
+    authzconf = (Map) ((ConfigData) handler.m.get("/security.json")).data.get("authorization");
+    permissions = (List<Map>) authzconf.get("permissions");
+
+    Map p = permissions.get(1);
+    assertEquals("security-edit", p.get("name"));
+    List rol = (List) p.get("role");
+    assertEquals( "admin", rol.get(0));
+    assertEquals( "dev", rol.get(1));
+
+    command = "{\n" +
+        "'update-permission':{'name': 'some-permission',\n" +
+        "                  'role': ['guest','admin']\n" +
+        "                  }}";
+    req = new LocalSolrQueryRequest(null, new ModifiableSolrParams());
+    req.getContext().put("httpMethod","POST");
+    req.getContext().put("path","/admin/authorization");
+    o = new ContentStreamBase.ByteArrayStream(command.getBytes(StandardCharsets.UTF_8),"");
+    req.setContentStreams(Collections.singletonList(o));
+    rsp = new SolrQueryResponse();
+    handler.handleRequestBody(req, rsp);
+    authzconf = (Map) ((ConfigData) handler.m.get("/security.json")).data.get("authorization");
+    permissions = (List<Map>) authzconf.get("permissions");
+
+    p = permissions.get(0);
+    assertEquals("some-permission", p.get("name"));
+    rol = (List) p.get("role");
+    assertEquals( "guest", rol.get(0));
+    assertEquals( "admin", rol.get(1));
+
+
+
     command = "{\n" +
         "'delete-permission': 'some-permission',\n" +
         "'set-user-role':{'tom':null}\n" +
@@ -119,12 +162,15 @@ public class SecurityConfHandlerTest ext
     authzconf = (Map) ((ConfigData) handler.m.get("/security.json")).data.get("authorization");
     userRoles = (Map) authzconf.get("user-role");
     assertEquals(0, userRoles.size());
-    permissions = (Map) authzconf.get("permissions");
+    permissions = (List<Map>) authzconf.get("permissions");
     assertEquals(1, permissions.size());
-    assertNull(permissions.get("some-permission"));
+
+    for (Map permission : permissions) {
+      assertFalse("some-permission".equals(permission.get("name")));
+    }
     command = "{\n" +
         "'set-permission':{'name': 'security-edit',\n" +
-        "                  'method':'POST',"+ // security edit is a well-known permission , only role attribute should be provided
+        "                  'method':'POST',"+ // -ve test security edit is a well-known permission , only role attribute should be provided
         "                  'role': 'admin'\n" +
         "                  }}";
     req = new LocalSolrQueryRequest(null, new ModifiableSolrParams());
@@ -136,7 +182,6 @@ public class SecurityConfHandlerTest ext
     handler.handleRequestBody(req, rsp);
     List l = (List) ((Map) ((List)rsp.getValues().get("errorMessages")).get(0)).get("errorMessages");
     assertEquals(1, l.size());
-
   }
 
 

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java?rev=1695308&r1=1695307&r2=1695308&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java Tue Aug 11 14:28:50 2015
@@ -131,7 +131,7 @@ public class BasicAuthIntegrationTest ex
     r = cl.execute(httpPost);
     assertEquals(200, r.getStatusLine().getStatusCode());
 
-    verifySecurityStatus(cl, baseUrl+"/admin/authorization", "authorization/permissions/x-update/collection", "x", 20);
+    verifySecurityStatus(cl, baseUrl+"/admin/authorization", "authorization/permissions[1]/collection", "x", 20);
 
   }
 
@@ -206,5 +206,5 @@ public class BasicAuthIntegrationTest ex
       "  'authorization':{\n" +
       "    'class':'solr.RuleBasedAuthorizationPlugin',\n" +
       "    'user-role':{'solr':'admin'},\n" +
-      "    'permissions':{'security-edit':{'role':'admin'}}}}";
+      "    'permissions':[{'name':'security-edit','role':'admin'}]}}";
 }

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/security/TestRuleBasedAuthorizationPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/security/TestRuleBasedAuthorizationPlugin.java?rev=1695308&r1=1695307&r2=1695308&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/security/TestRuleBasedAuthorizationPlugin.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/security/TestRuleBasedAuthorizationPlugin.java Tue Aug 11 14:28:50 2015
@@ -19,6 +19,7 @@ package org.apache.solr.security;
 
 import java.nio.charset.StandardCharsets;
 import java.security.Principal;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.List;
@@ -44,21 +45,18 @@ public class TestRuleBasedAuthorizationP
         "    joe: [user]," +
         "    noble:[dev,user]" +
         "  }," +
-        "  permissions : {" +
-        "    schema-edit :{" +
-        "      role:admin" +
-        "    }," +
-        "    collection-admin-read :{" +
-        "      role:null" +
-        "    }," +
-        "    collection-admin-edit :{" +
-        "      role:admin" +
-        "    }," +
-        "    mycoll_update: {" +
+        "  permissions : [" +
+        "    {name:'schema-edit'," +
+        "     role:admin}," +
+        "    {name:'collection-admin-read'," +
+        "    role:null}," +
+        "    {name:collection-admin-edit ," +
+        "    role:admin}," +
+        "    {name:mycoll_update," +
         "      collection:mycoll," +
         "      path:'/update/*'," +
         "      role:[dev,admin]" +
-        "    }}}" ;
+        "    }]}" ;
     Map initConfig = (Map) Utils.fromJSON(jsonRules.getBytes(StandardCharsets.UTF_8));
 
     RuleBasedAuthorizationPlugin plugin= new RuleBasedAuthorizationPlugin();
@@ -97,6 +95,7 @@ public class TestRuleBasedAuthorizationP
     assertEquals(FORBIDDEN,authResp.statusCode);
 
     values.put("resource","/admin/collections");
+    values.put("collectionRequests",new ArrayList<>());
     values.put("params", new MapSolrParams(Collections.singletonMap("action", "LIST")));
     values.put("httpMethod","GET");
     authResp = plugin.authorize(context);

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/util/TestUtils.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/util/TestUtils.java?rev=1695308&r1=1695307&r2=1695308&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/util/TestUtils.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/util/TestUtils.java Tue Aug 11 14:28:50 2015
@@ -26,6 +26,7 @@ import java.util.Map;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.common.util.SimpleOrderedMap;
 import org.apache.solr.common.util.StrUtils;
+import org.apache.solr.common.util.Utils;
 import org.junit.Assert;
 
 /**
@@ -154,4 +155,26 @@ public class TestUtils extends SolrTestC
     assertEquals( num, NumberUtils.SortableStr2long(sortable, 0, sortable.length() ) );
     assertEquals( Long.toString(num), NumberUtils.SortableStr2long(sortable) );
   }
+  
+  public void testUtilsJSPath(){
+    
+    String json = "{\n" +
+        "  'authorization':{\n" +
+        "    'class':'solr.RuleBasedAuthorizationPlugin',\n" +
+        "    'user-role':{\n" +
+        "      'solr':'admin',\n" +
+        "      'harry':'admin'},\n" +
+        "    'permissions':[{\n" +
+        "        'name':'security-edit',\n" +
+        "        'role':'admin'},\n" +
+        "      {\n" +
+        "        'name':'x-update',\n" +
+        "        'collection':'x',\n" +
+        "        'path':'/update/*',\n" +
+        "        'role':'dev'}],\n" +
+        "    '':{'v':4}}}";
+    Map m = (Map) Utils.fromJSONString(json);
+    assertEquals("x-update", Utils.getObjectByPath(m,false, "authorization/permissions[1]/name"));
+    
+  }
 }

Modified: lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/common/util/Utils.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/common/util/Utils.java?rev=1695308&r1=1695307&r2=1695308&view=diff
==============================================================================
--- lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/common/util/Utils.java (original)
+++ lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/common/util/Utils.java Tue Aug 11 14:28:50 2015
@@ -30,6 +30,8 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import org.apache.solr.common.SolrException;
 import org.noggit.CharArr;
@@ -121,16 +123,37 @@ public class Utils {
     }
   }
 
+  public static Object getObjectByPath(Map root, boolean onlyPrimitive, String hierarchy) {
+    return getObjectByPath(root, onlyPrimitive, StrUtils.splitSmart(hierarchy, '/'));
+  }
+
   public static Object getObjectByPath(Map root, boolean onlyPrimitive, List<String> hierarchy) {
     Map obj = root;
     for (int i = 0; i < hierarchy.size(); i++) {
+      int idx = -1;
       String s = hierarchy.get(i);
+      if (s.endsWith("]")) {
+        Matcher matcher = ARRAY_ELEMENT_INDEX.matcher(s);
+        if (matcher.find()) {
+          s = matcher.group(1);
+          idx = Integer.parseInt(matcher.group(2));
+        }
+      }
       if (i < hierarchy.size() - 1) {
-        if (!(obj.get(s) instanceof Map)) return null;
-        obj = (Map) obj.get(s);
-        if (obj == null) return null;
+        Object o = obj.get(s);
+        if (o == null) return null;
+        if (idx > -1) {
+          List l = (List) o;
+          o = idx < l.size() ? l.get(idx) : null;
+        }
+        if (!(o instanceof Map)) return null;
+        obj = (Map) o;
       } else {
         Object val = obj.get(s);
+        if (idx > -1) {
+          List l = (List) val;
+          val = idx < l.size() ? l.get(idx) : null;
+        }
         if (onlyPrimitive && val instanceof Map) {
           return null;
         }
@@ -140,4 +163,7 @@ public class Utils {
 
     return false;
   }
+
+  public static final Pattern ARRAY_ELEMENT_INDEX = Pattern
+      .compile("(\\S*?)\\[(\\d+)\\]");
 }