You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2013/11/15 09:59:06 UTC

[2/2] git commit: ISIS-586: allow ldap realm to load perm/role mappings from ini file.

ISIS-586: allow ldap realm to load perm/role mappings from ini file.

also updates to the quickstart app (for archetype)


Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/ad16b962
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/ad16b962
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/ad16b962

Branch: refs/heads/master
Commit: ad16b962928715e343369b00d8a42cd12c9bd79b
Parents: c611e49
Author: Dan Haywood <da...@apache.org>
Authored: Fri Nov 15 08:43:17 2013 +0000
Committer: Dan Haywood <da...@apache.org>
Committed: Fri Nov 15 08:43:17 2013 +0000

----------------------------------------------------------------------
 .../isis/security/shiro/IsisLdapRealm.java      | 107 +++++++++++++++++--
 .../permrolemapper/PermissionToRoleMapper.java  |  26 +++++
 .../PermissionToRoleMapperFromIni.java          |  52 +++++++++
 .../PermissionToRoleMapperFromString.java       |  39 +++++++
 .../shiro/IsisPermissionTest_typicalUsage.java  |   7 ++
 .../PermissionToRoleMapperFromIniTest.java      |  45 ++++++++
 .../PermissionToRoleMapperFromStringTest.java   |  45 ++++++++
 .../isis/security/shiro/permrolemapper/my.ini   |  26 +++++
 .../webapp/src/main/resources/webapp/realm1.ini |  68 ++++++++++++
 .../webapp/src/main/resources/webapp/realm2.ini |  66 ++++++++++++
 .../webapp/src/main/webapp/WEB-INF/shiro.ini    |  76 +++++++------
 11 files changed, 512 insertions(+), 45 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/ad16b962/component/security/shiro/src/main/java/org/apache/isis/security/shiro/IsisLdapRealm.java
----------------------------------------------------------------------
diff --git a/component/security/shiro/src/main/java/org/apache/isis/security/shiro/IsisLdapRealm.java b/component/security/shiro/src/main/java/org/apache/isis/security/shiro/IsisLdapRealm.java
index 21e88c5..7ea1022 100644
--- a/component/security/shiro/src/main/java/org/apache/isis/security/shiro/IsisLdapRealm.java
+++ b/component/security/shiro/src/main/java/org/apache/isis/security/shiro/IsisLdapRealm.java
@@ -31,12 +31,18 @@ import javax.naming.directory.SearchControls;
 import javax.naming.directory.SearchResult;
 import javax.naming.ldap.LdapContext;
 
+import org.apache.isis.security.shiro.permrolemapper.PermissionToRoleMapper;
+import org.apache.isis.security.shiro.permrolemapper.PermissionToRoleMapperFromIni;
+import org.apache.isis.security.shiro.permrolemapper.PermissionToRoleMapperFromString;
 import org.apache.isis.security.shiro.util.Util;
+
 import org.apache.shiro.authz.AuthorizationInfo;
 import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.config.Ini;
 import org.apache.shiro.realm.ldap.JndiLdapRealm;
 import org.apache.shiro.realm.ldap.LdapContextFactory;
 import org.apache.shiro.realm.ldap.LdapUtils;
+import org.apache.shiro.realm.text.IniRealm;
 import org.apache.shiro.subject.PrincipalCollection;
 import org.apache.shiro.util.StringUtils;
 
@@ -74,14 +80,42 @@ import com.google.common.collect.Sets;
  *    GLOBAL_ADMIN: admin_role,\
  *    DEMOS: self-install_role
  * 
+ * securityManager.realms = $ldapRealm
+ * </pre>
+ * 
+ * <p>
+ * The permissions for each role can be specified using the
+ * {@link #setResourcePath(String)} to an 'ini' file with a [roles] section, eg:
+ * 
+ * <pre>
+ * ldapRealm.resourcePath=classpath:webapp/myroles.ini
+ * </pre>
+ *
+ * <p>
+ * where <tt>myroles.ini</tt> is in <tt>src/main/resources/webapp</tt>, and takes the form:
+ * 
+ * <pre>
+ * [roles]
+ * user_role = *:ToDoItemsJdo:*:*,\
+ *             *:ToDoItem:*:*
+ * self-install_role = *:ToDoItemsFixturesService:install:*
+ * admin_role = *
+ * </pre>
+ * 
+ * <p>
+ * This 'ini' file can then be referenced by other realms (if multiple realm are configured
+ * with the Shiro security manager). 
+ * 
+ * <p>
+ * Alternatively, permissions can be set directly using {@link #setPermissionsByRole(String)},
+ * where the string is the same information, formatted thus:
+ * 
+ * <re>
  * ldapRealm.permissionsByRole=\
  *    user_role = *:ToDoItemsJdo:*:*,\
  *                *:ToDoItem:*:*; \
  *    self-install_role = *:ToDoItemsFixturesService:install:* ; \
  *    admin_role = *
- * 
- * securityManager.realms = $ldapRealm
- * 
  * </pre>
  */
 public class IsisLdapRealm extends JndiLdapRealm {
@@ -99,8 +133,9 @@ public class IsisLdapRealm extends JndiLdapRealm {
     private String uniqueMemberAttributeValueSuffix;
     
     private final Map<String,String> rolesByGroup = Maps.newLinkedHashMap();
-    private final Map<String,List<String>> permissionsByRole = Maps.newLinkedHashMap();
     
+    private PermissionToRoleMapper permissionToRoleMapper;
+
     public IsisLdapRealm() {
         setGroupObjectClass("groupOfUniqueNames");
         setUniqueMemberAttribute("uniqueMember");
@@ -185,7 +220,7 @@ public class IsisLdapRealm extends JndiLdapRealm {
     private Set<String> permsFor(Set<String> roleNames) {
         Set<String> perms = Sets.newLinkedHashSet(); // preserve order
         for(String role: roleNames) {
-            List<String> permsForRole = permissionsByRole.get(role);
+            List<String> permsForRole = getPermissionsByRole().get(role);
             if(permsForRole != null) {
                 perms.addAll(permsForRole);
             }
@@ -228,7 +263,67 @@ public class IsisLdapRealm extends JndiLdapRealm {
         this.rolesByGroup.putAll(rolesByGroup);
     }
 
+    /**
+     * Retrieves permissions by role set using either
+     * {@link #setPermissionsByRole(String)} or {@link #setResourcePath(String)}.
+     */
+    private Map<String,List<String>> getPermissionsByRole() {
+        if(permissionToRoleMapper == null) {
+            throw new IllegalStateException("Permissions by role not yet set.");
+        } 
+        return permissionToRoleMapper.getPermissionsByRole();
+    }
+    
+    /**
+     * <pre>
+     * ldapRealm.resourcePath=classpath:webapp/myroles.ini
+     * </pre>
+     *
+     * <p>
+     * where <tt>myroles.ini</tt> is in <tt>src/main/resources/webapp</tt>, and takes the form:
+     * 
+     * <pre>
+     * [roles]
+     * user_role = *:ToDoItemsJdo:*:*,\
+     *             *:ToDoItem:*:*
+     * self-install_role = *:ToDoItemsFixturesService:install:*
+     * admin_role = *
+     * </pre>
+     * 
+     * <p>
+     * This 'ini' file can then be referenced by other realms (if multiple realm are configured
+     * with the Shiro security manager). 
+     * 
+     * @see #setResourcePath(String)
+     */
+    public void setResourcePath(String resourcePath) {
+        if(permissionToRoleMapper != null) {
+            throw new IllegalStateException("Permissions already set, " + permissionToRoleMapper.getClass().getName());
+        } 
+        final Ini ini = Ini.fromResourcePath(resourcePath);
+        this.permissionToRoleMapper = new PermissionToRoleMapperFromIni(ini);
+    }
+
+    /**
+     * Specify permissions for each role using a formatted string.
+     *
+     * <pre>
+     * ldapRealm.permissionsByRole=\
+     *    user_role = *:ToDoItemsJdo:*:*,\
+     *                *:ToDoItem:*:*; \
+     *    self-install_role = *:ToDoItemsFixturesService:install:* ; \
+     *    admin_role = *
+     * </pre>
+     * 
+     * @see #setResourcePath(String)
+     */
+    @Deprecated
     public void setPermissionsByRole(String permissionsByRoleStr) {
-        permissionsByRole.putAll(Util.parse(permissionsByRoleStr));
+        if(permissionToRoleMapper != null) {
+            throw new IllegalStateException("Permissions already set, " + permissionToRoleMapper.getClass().getName());
+        } 
+        this.permissionToRoleMapper = new PermissionToRoleMapperFromString(permissionsByRoleStr);
     }
+
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/ad16b962/component/security/shiro/src/main/java/org/apache/isis/security/shiro/permrolemapper/PermissionToRoleMapper.java
----------------------------------------------------------------------
diff --git a/component/security/shiro/src/main/java/org/apache/isis/security/shiro/permrolemapper/PermissionToRoleMapper.java b/component/security/shiro/src/main/java/org/apache/isis/security/shiro/permrolemapper/PermissionToRoleMapper.java
new file mode 100644
index 0000000..02006d0
--- /dev/null
+++ b/component/security/shiro/src/main/java/org/apache/isis/security/shiro/permrolemapper/PermissionToRoleMapper.java
@@ -0,0 +1,26 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.isis.security.shiro.permrolemapper;
+
+import java.util.List;
+import java.util.Map;
+
+public interface PermissionToRoleMapper {
+
+    Map<String, List<String>> getPermissionsByRole();
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/ad16b962/component/security/shiro/src/main/java/org/apache/isis/security/shiro/permrolemapper/PermissionToRoleMapperFromIni.java
----------------------------------------------------------------------
diff --git a/component/security/shiro/src/main/java/org/apache/isis/security/shiro/permrolemapper/PermissionToRoleMapperFromIni.java b/component/security/shiro/src/main/java/org/apache/isis/security/shiro/permrolemapper/PermissionToRoleMapperFromIni.java
new file mode 100644
index 0000000..954632d
--- /dev/null
+++ b/component/security/shiro/src/main/java/org/apache/isis/security/shiro/permrolemapper/PermissionToRoleMapperFromIni.java
@@ -0,0 +1,52 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.isis.security.shiro.permrolemapper;
+
+import java.util.List;
+import java.util.Map;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Maps.EntryTransformer;
+
+import org.apache.shiro.config.Ini;
+import org.apache.shiro.realm.text.IniRealm;
+import org.apache.shiro.util.PermissionUtils;
+
+public class PermissionToRoleMapperFromIni implements PermissionToRoleMapper {
+
+    private final Map<String, List<String>> permissionsByRole;
+
+    /**
+     * Using the same logic as in {@link IniRealm}.
+     */
+    public PermissionToRoleMapperFromIni(Ini ini) {
+        Map<String,String> section = ini.getSection(IniRealm.ROLES_SECTION_NAME);
+        this.permissionsByRole = Maps.transformEntries(section, new EntryTransformer<String,String,List<String>>() {
+            
+            @Override
+            public List<String> transformEntry(String key, String value) {
+                return Lists.newArrayList(PermissionUtils.toPermissionStrings(value));
+            }
+        });
+    }
+
+    @Override
+    public Map<String, List<String>> getPermissionsByRole() {
+        return permissionsByRole;
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/ad16b962/component/security/shiro/src/main/java/org/apache/isis/security/shiro/permrolemapper/PermissionToRoleMapperFromString.java
----------------------------------------------------------------------
diff --git a/component/security/shiro/src/main/java/org/apache/isis/security/shiro/permrolemapper/PermissionToRoleMapperFromString.java b/component/security/shiro/src/main/java/org/apache/isis/security/shiro/permrolemapper/PermissionToRoleMapperFromString.java
new file mode 100644
index 0000000..6475df0
--- /dev/null
+++ b/component/security/shiro/src/main/java/org/apache/isis/security/shiro/permrolemapper/PermissionToRoleMapperFromString.java
@@ -0,0 +1,39 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.isis.security.shiro.permrolemapper;
+
+import java.util.List;
+import java.util.Map;
+
+import com.google.common.collect.Maps;
+
+import org.apache.isis.security.shiro.util.Util;
+
+public class PermissionToRoleMapperFromString implements PermissionToRoleMapper {
+
+    private final Map<String,List<String>> permissionsByRole = Maps.newLinkedHashMap();
+
+    public PermissionToRoleMapperFromString(String permissionsByRoleStr) {
+        permissionsByRole.putAll(Util.parse(permissionsByRoleStr));
+    }
+
+    @Override
+    public Map<String, List<String>> getPermissionsByRole() {
+        return permissionsByRole;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/ad16b962/component/security/shiro/src/test/java/org/apache/isis/security/shiro/IsisPermissionTest_typicalUsage.java
----------------------------------------------------------------------
diff --git a/component/security/shiro/src/test/java/org/apache/isis/security/shiro/IsisPermissionTest_typicalUsage.java b/component/security/shiro/src/test/java/org/apache/isis/security/shiro/IsisPermissionTest_typicalUsage.java
index f32ccd6..0593e3e 100644
--- a/component/security/shiro/src/test/java/org/apache/isis/security/shiro/IsisPermissionTest_typicalUsage.java
+++ b/component/security/shiro/src/test/java/org/apache/isis/security/shiro/IsisPermissionTest_typicalUsage.java
@@ -58,6 +58,9 @@ public class IsisPermissionTest_typicalUsage {
         assertThat(viewCustomerChangeAddress, permittedBy("com.mycompany.myapp:Customer:changeAddress:*"));
         assertThat(viewCustomerChangeAddress, permittedBy("com.mycompany.myapp:Customer:*:r"));
         assertThat(viewCustomerChangeAddress, permittedBy("com.mycompany.myapp:*:*:r"));
+        assertThat(viewCustomerChangeAddress, permittedBy("com.mycompany.myapp:*:*"));
+        assertThat(viewCustomerChangeAddress, permittedBy("com.mycompany.myapp:*"));
+        assertThat(viewCustomerChangeAddress, permittedBy("com.mycompany.myapp"));
         assertThat(viewCustomerChangeAddress, permittedBy("*:*:*:r"));
         assertThat(viewCustomerChangeAddress, permittedBy("*:*:*:*"));
         assertThat(viewCustomerChangeAddress, permittedBy("*:*:*"));
@@ -65,10 +68,14 @@ public class IsisPermissionTest_typicalUsage {
         assertThat(viewCustomerChangeAddress, permittedBy("*"));
         assertThat(viewCustomerChangeAddress, permittedBy("*:Customer:*:r"));
 
+
         assertThat(useCustomerChangeAddress, permittedBy("com.mycompany.myapp:Customer:changeAddress:w"));
         assertThat(useCustomerChangeAddress, permittedBy("com.mycompany.myapp:Customer:changeAddress:*"));
 
         // and these are some counterexamples
+        assertThat(viewCustomerChangeAddress, not(permittedBy("com.mycompany"))); // packages are NOT recursive
+        assertThat(viewCustomerChangeAddress, not(permittedBy("com.mycompany.*"))); // can't use regex wildcards for packages either
+        
         assertThat(viewCustomerChangeAddress, not(permittedBy("com.mycompany.myapp:Customer:changeAddress:w")));
         assertThat(useCustomerChangeAddress, not(permittedBy("com.mycompany.myapp:Customer:changeAddress:r")));
 

http://git-wip-us.apache.org/repos/asf/isis/blob/ad16b962/component/security/shiro/src/test/java/org/apache/isis/security/shiro/permrolemapper/PermissionToRoleMapperFromIniTest.java
----------------------------------------------------------------------
diff --git a/component/security/shiro/src/test/java/org/apache/isis/security/shiro/permrolemapper/PermissionToRoleMapperFromIniTest.java b/component/security/shiro/src/test/java/org/apache/isis/security/shiro/permrolemapper/PermissionToRoleMapperFromIniTest.java
new file mode 100644
index 0000000..4752912
--- /dev/null
+++ b/component/security/shiro/src/test/java/org/apache/isis/security/shiro/permrolemapper/PermissionToRoleMapperFromIniTest.java
@@ -0,0 +1,45 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.isis.security.shiro.permrolemapper;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.util.List;
+import java.util.Map;
+
+import com.google.common.collect.Lists;
+
+import org.apache.shiro.config.Ini;
+import org.junit.Test;
+
+public class PermissionToRoleMapperFromIniTest {
+
+    @Test
+    public void test() {
+        final Ini ini = Ini.fromResourcePath("classpath:org/apache/isis/security/shiro/permrolemapper/my.ini");
+        final Map<String, List<String>> permissionsByRole = 
+                new PermissionToRoleMapperFromIni(ini).getPermissionsByRole();
+        
+        assertThat(permissionsByRole.get("role1"), is(equalTo((List<String>)Lists.newArrayList("foo","bar"))));
+        assertThat(permissionsByRole.get("role2"), is(equalTo((List<String>)Lists.newArrayList("fiz:x","bip:bop:*"))));
+        assertThat(permissionsByRole.get("role3"), is(equalTo((List<String>)Lists.newArrayList("*"))));
+        assertThat(permissionsByRole.size(), is(3));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/ad16b962/component/security/shiro/src/test/java/org/apache/isis/security/shiro/permrolemapper/PermissionToRoleMapperFromStringTest.java
----------------------------------------------------------------------
diff --git a/component/security/shiro/src/test/java/org/apache/isis/security/shiro/permrolemapper/PermissionToRoleMapperFromStringTest.java b/component/security/shiro/src/test/java/org/apache/isis/security/shiro/permrolemapper/PermissionToRoleMapperFromStringTest.java
new file mode 100644
index 0000000..1cf4927
--- /dev/null
+++ b/component/security/shiro/src/test/java/org/apache/isis/security/shiro/permrolemapper/PermissionToRoleMapperFromStringTest.java
@@ -0,0 +1,45 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.isis.security.shiro.permrolemapper;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.util.List;
+import java.util.Map;
+
+import com.google.common.collect.Lists;
+
+import org.junit.Test;
+
+public class PermissionToRoleMapperFromStringTest {
+
+    @Test
+    public void test() {
+        final Map<String, List<String>> permissionsByRole = new PermissionToRoleMapperFromString(
+                "role1 = foo,bar;"
+                + "role2 = fiz:x,bip:bop:* ;"
+                + "role3 = *").getPermissionsByRole();
+        
+        assertThat(permissionsByRole.get("role1"), is(equalTo((List<String>)Lists.newArrayList("foo","bar"))));
+        assertThat(permissionsByRole.get("role2"), is(equalTo((List<String>)Lists.newArrayList("fiz:x","bip:bop:*"))));
+        assertThat(permissionsByRole.get("role3"), is(equalTo((List<String>)Lists.newArrayList("*"))));
+        assertThat(permissionsByRole.size(), is(3));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/ad16b962/component/security/shiro/src/test/resources/org/apache/isis/security/shiro/permrolemapper/my.ini
----------------------------------------------------------------------
diff --git a/component/security/shiro/src/test/resources/org/apache/isis/security/shiro/permrolemapper/my.ini b/component/security/shiro/src/test/resources/org/apache/isis/security/shiro/permrolemapper/my.ini
new file mode 100644
index 0000000..958ade9
--- /dev/null
+++ b/component/security/shiro/src/test/resources/org/apache/isis/security/shiro/permrolemapper/my.ini
@@ -0,0 +1,26 @@
+#
+# 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.
+#
+
+[roles]
+
+role1 = foo,\
+        bar
+role2 = fiz:x,\
+        bip:bop:* 
+role3 = * 

http://git-wip-us.apache.org/repos/asf/isis/blob/ad16b962/example/application/quickstart_wicket_restful_jdo/webapp/src/main/resources/webapp/realm1.ini
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/webapp/src/main/resources/webapp/realm1.ini b/example/application/quickstart_wicket_restful_jdo/webapp/src/main/resources/webapp/realm1.ini
new file mode 100644
index 0000000..3a98d2a
--- /dev/null
+++ b/example/application/quickstart_wicket_restful_jdo/webapp/src/main/resources/webapp/realm1.ini
@@ -0,0 +1,68 @@
+#
+# 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.
+#
+
+
+# -----------------------------------------------------------------------------
+# Users and their assigned roles
+#
+# Each line conforms to the format defined in the
+# org.apache.shiro.realm.text.TextConfigurationRealm#setUserDefinitions JavaDoc
+# -----------------------------------------------------------------------------
+
+[users]
+# user = password, role1, role2, role3, ...
+
+#
+# realm1 configures sven, dick and bob only.  Additional logins are configured in realm2
+#
+
+sven = pass, admin_role
+dick = pass, user_role, analysis_role, self-install_role
+bob  = pass, user_role, self-install_role
+
+
+
+# -----------------------------------------------------------------------------
+# Roles with assigned permissions
+# 
+# Each line conforms to the format defined in the
+# org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc
+# -----------------------------------------------------------------------------
+
+[roles]
+# role = perm1, perm2, perm3, ...
+# perm in format: packageName:className:memberName:r,w
+
+#
+# the role/perm mappings for realm1 and realm2 are "coincidentally" the same.
+# But if using the IsisLdapRealm, it could be pointed at an ini file such as this in 
+# order to share role/perm mappings.
+#
+
+
+# configuring iniRealm to use Shiro's built-in WildcardPermissions
+user_role = *:ToDoItems:*:*,\
+            *:ToDoItem:*:*,\
+            *:ToDoAppDashboard:*:*
+analysis_role = *:ToDoItemAnalysis:*:*,\
+            *:ToDoItemsByCategoryViewModel:*:*,\
+            *:ToDoItemsByDateRangeViewModel:*:*
+self-install_role = *:ToDoItemsFixturesService:install:*
+admin_role = *
+

http://git-wip-us.apache.org/repos/asf/isis/blob/ad16b962/example/application/quickstart_wicket_restful_jdo/webapp/src/main/resources/webapp/realm2.ini
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/webapp/src/main/resources/webapp/realm2.ini b/example/application/quickstart_wicket_restful_jdo/webapp/src/main/resources/webapp/realm2.ini
new file mode 100644
index 0000000..5bae28b
--- /dev/null
+++ b/example/application/quickstart_wicket_restful_jdo/webapp/src/main/resources/webapp/realm2.ini
@@ -0,0 +1,66 @@
+#
+# 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.
+#
+
+
+# -----------------------------------------------------------------------------
+# Users and their assigned roles
+#
+# Each line conforms to the format defined in the
+# org.apache.shiro.realm.text.TextConfigurationRealm#setUserDefinitions JavaDoc
+# -----------------------------------------------------------------------------
+
+[users]
+# user = password, role1, role2, role3, ...
+
+#
+# realm2 configures joe and guest only.  Additional logins are configured in realm1
+#
+
+joe  = pass, user_role, self-install_role
+guest = guest, user_role
+
+
+
+# -----------------------------------------------------------------------------
+# Roles with assigned permissions
+# 
+# Each line conforms to the format defined in the
+# org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc
+# -----------------------------------------------------------------------------
+
+[roles]
+# role = perm1, perm2, perm3, ...
+# perm in format: packageName:className:memberName:r,w
+
+#
+# the role/perm mappings for realm1 and realm2 are "coincidentally" the same.
+# But if using the IsisLdapRealm, it could be pointed at an ini file such as this in 
+# order to share role/perm mappings.
+#
+
+# configuring iniRealm to use Shiro's built-in WildcardPermissions
+user_role = *:ToDoItems:*:*,\
+            *:ToDoItem:*:*,\
+            *:ToDoAppDashboard:*:*
+analysis_role = *:ToDoItemAnalysis:*:*,\
+            *:ToDoItemsByCategoryViewModel:*:*,\
+            *:ToDoItemsByDateRangeViewModel:*:*
+self-install_role = *:ToDoItemsFixturesService:install:*
+admin_role = *
+

http://git-wip-us.apache.org/repos/asf/isis/blob/ad16b962/example/application/quickstart_wicket_restful_jdo/webapp/src/main/webapp/WEB-INF/shiro.ini
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/webapp/src/main/webapp/WEB-INF/shiro.ini b/example/application/quickstart_wicket_restful_jdo/webapp/src/main/webapp/WEB-INF/shiro.ini
index edf1a2b..41ee3f4 100644
--- a/example/application/quickstart_wicket_restful_jdo/webapp/src/main/webapp/WEB-INF/shiro.ini
+++ b/example/application/quickstart_wicket_restful_jdo/webapp/src/main/webapp/WEB-INF/shiro.ini
@@ -19,6 +19,24 @@
 
 [main]
 
+#######
+# configure a couple of iniRealms
+# (nb: not possible for their .ini files to live in WEB-INF, because Shiro does not
+# provide a mechanism to load resources from that location)
+#######
+
+realm1 = org.apache.shiro.realm.text.IniRealm
+realm1.resourcePath=classpath:webapp/realm1.ini
+
+realm2 = org.apache.shiro.realm.text.IniRealm
+realm2.resourcePath=classpath:webapp/realm2.ini
+
+
+
+#######
+# configure an ldap-based realm
+#######
+
 contextFactory = org.apache.isis.security.shiro.IsisLdapContextFactory
 contextFactory.url = ldap://localhost:10389
 contextFactory.authenticationMechanism = CRAM-MD5
@@ -42,56 +60,36 @@ ldapRealm.uniqueMemberAttributeValueTemplate = uid={0}
 #    GLOBAL_ADMIN: admin_role,\
 #    DEMOS: self-install_role
 
-ldapRealm.permissionsByRole=\
-   user_role = *:ToDoItemsJdo:*:*,\
-               *:ToDoItem:*:*; \
-   self-install_role = *:ToDoItemsFixturesService:install:* ; \
-   admin_role = *
+# configuring ldapRealm role/perm mappings
+# (use same as realm1)
+ldapRealm.resourcePath=classpath:webapp/realm1.ini
 
-# to use ldap...
-# (see docs for details of how to setup users/groups in Apache Directory Studio).
-#securityManager.realms = $ldapRealm
 
-# to use .ini file
-securityManager.realms = $iniRealm
+#######
+# configure security manager to use realm(s)
+#######
 
+# authenticate/authorize first with realm1, then realm2
+securityManager.realms = $realm1,$realm2
 
 
-# -----------------------------------------------------------------------------
-# Users and their assigned roles
-#
-# Each line conforms to the format defined in the
-# org.apache.shiro.realm.text.TextConfigurationRealm#setUserDefinitions JavaDoc
-# -----------------------------------------------------------------------------
-
-[users]
-# user = password, role1, role2, role3, ...
+# or to use ldap with realm1 as a backup...
+# (see docs for details of how to setup users/groups in Apache Directory Studio).
+#securityManager.realms = $ldapRealm,$realm1
 
 
-sven = pass, admin_role
-dick = pass, user_role, analysis_role, self-install_role
-bob  = pass, user_role, self-install_role
-joe  = pass, user_role, self-install_role
-guest = guest, user_role
+# or to just use this .ini file...
+# (would require [users] and [roles] to be set up)
+#securityManager.realms = $iniRealm
 
 
 
 # -----------------------------------------------------------------------------
-# Roles with assigned permissions
-# 
-# Each line conforms to the format defined in the
-# org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc
+# Users and their assigned roles
 # -----------------------------------------------------------------------------
 
+[users]
+# unused (assuming  not configured $iniRealm)
+
 [roles]
-# role = perm1, perm2, perm3, ...
-# perm in format: packageName:className:memberName:r,w
-
-user_role = *:ToDoItems:*:*,\
-            *:ToDoItem:*:*
-analysis_role = *:ToDoItemAnalysis:*:*,\
-            *:ToDoItemsByCategoryViewModel:*:*,\
-            *:ToDoItemsByDateRangeViewModel:*:*,\
-            *:ToDoAppDashboard:*:*
-self-install_role = *:ToDoItemsFixturesService:install:*
-admin_role = *
+# unused (assuming not configured $iniRealm)