You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by jb...@apache.org on 2013/09/30 16:28:59 UTC

svn commit: r1527592 - in /karaf/trunk: assemblies/features/framework/src/main/resources/resources/etc/ jaas/boot/src/main/java/org/apache/karaf/jaas/boot/principal/ jaas/command/ jaas/command/src/main/java/org/apache/karaf/jaas/command/ jaas/command/s...

Author: jbonofre
Date: Mon Sep 30 14:28:59 2013
New Revision: 1527592

URL: http://svn.apache.org/r1527592
Log:
[KARAF-2434] Add support for JAAS groups

Added:
    karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/GroupAddCommand.java
    karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/GroupDeleteCommand.java
    karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/GroupRoleAddCommand.java
    karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/GroupRoleDeleteCommand.java
    karaf/trunk/jaas/modules/src/test/java/org/apache/karaf/jaas/modules/properties/PropertiesBackingEngineTest.java
Modified:
    karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/users.properties
    karaf/trunk/jaas/boot/src/main/java/org/apache/karaf/jaas/boot/principal/GroupPrincipal.java
    karaf/trunk/jaas/boot/src/main/java/org/apache/karaf/jaas/boot/principal/RolePolicy.java
    karaf/trunk/jaas/command/pom.xml
    karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/ListUsersCommand.java
    karaf/trunk/jaas/command/src/main/resources/OSGI-INF/blueprint/jaas-command.xml
    karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/BackingEngine.java
    karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCBackingEngine.java
    karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/properties/PropertiesBackingEngine.java
    karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/properties/PropertiesLoginModule.java
    karaf/trunk/jaas/modules/src/test/java/org/apache/karaf/jaas/modules/properties/PropertiesLoginModuleTest.java

Modified: karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/users.properties
URL: http://svn.apache.org/viewvc/karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/users.properties?rev=1527592&r1=1527591&r2=1527592&view=diff
==============================================================================
--- karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/users.properties (original)
+++ karaf/trunk/assemblies/features/framework/src/main/resources/resources/etc/users.properties Mon Sep 30 14:28:59 2013
@@ -27,4 +27,5 @@
 # and modifiable via the JAAS command group. These users reside in a JAAS domain
 # with the name "karaf"..
 #
-karaf=karaf,admin
+karaf = karaf,_g_:admingroup
+_g_\:admingroup = group,admin,manager,viewer

Modified: karaf/trunk/jaas/boot/src/main/java/org/apache/karaf/jaas/boot/principal/GroupPrincipal.java
URL: http://svn.apache.org/viewvc/karaf/trunk/jaas/boot/src/main/java/org/apache/karaf/jaas/boot/principal/GroupPrincipal.java?rev=1527592&r1=1527591&r2=1527592&view=diff
==============================================================================
--- karaf/trunk/jaas/boot/src/main/java/org/apache/karaf/jaas/boot/principal/GroupPrincipal.java (original)
+++ karaf/trunk/jaas/boot/src/main/java/org/apache/karaf/jaas/boot/principal/GroupPrincipal.java Mon Sep 30 14:28:59 2013
@@ -12,43 +12,43 @@
  *  limitations under the License.
  *  under the License.
  */
-
 package org.apache.karaf.jaas.boot.principal;
 
 import java.security.Principal;
-import java.security.acl.Group;
-import java.util.Enumeration;
-import java.util.Hashtable;
 
-public class GroupPrincipal implements Group {
+public class GroupPrincipal implements Principal {
 
     private String name;
-    private Hashtable<String,Principal> members = new Hashtable<String, Principal>();
 
     public GroupPrincipal(String name) {
+        assert name != null;
         this.name = name;
     }
-    
-    public boolean addMember(Principal user) {
-        members.put(user.getName(), user);
-        return true;
-    }
 
-    public boolean removeMember(Principal user) {
-        members.remove(user.getName());
-        return true;
+    public String getName() {
+        return this.name;
     }
 
-    public boolean isMember(Principal member) {
-        return members.contains(member.getName());
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof GroupPrincipal)) return false;
+
+        GroupPrincipal that = (GroupPrincipal) o;
+
+        if (name != null ? !name.equals(that.name) : that.name != null) return false;
+
+        return true;
     }
 
-    public Enumeration<? extends Principal> members() {
-        return members.elements();
+    @Override
+    public int hashCode() {
+        return name != null ? name.hashCode() : 0;
     }
 
-    public String getName() {
-        return name;
+    @Override
+    public String toString() {
+        return "GroupPrincipal[" + name + "]";
     }
 
 }

Modified: karaf/trunk/jaas/boot/src/main/java/org/apache/karaf/jaas/boot/principal/RolePolicy.java
URL: http://svn.apache.org/viewvc/karaf/trunk/jaas/boot/src/main/java/org/apache/karaf/jaas/boot/principal/RolePolicy.java?rev=1527592&r1=1527591&r2=1527592&view=diff
==============================================================================
--- karaf/trunk/jaas/boot/src/main/java/org/apache/karaf/jaas/boot/principal/RolePolicy.java (original)
+++ karaf/trunk/jaas/boot/src/main/java/org/apache/karaf/jaas/boot/principal/RolePolicy.java Mon Sep 30 14:28:59 2013
@@ -12,11 +12,9 @@
  *  limitations under the License.
  *  under the License.
  */
-
 package org.apache.karaf.jaas.boot.principal;
 
 import java.security.Principal;
-import java.security.acl.Group;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.Map;
@@ -36,19 +34,6 @@ public enum RolePolicy {
                 }
             }
         }
-    },
-    GROUP_ROLES("group") {
-        public void handleRoles(Subject subject,Set<Principal> principals,String discriminator) {
-            Group group = new GroupPrincipal(discriminator);
-            for(Principal p:principals) {
-                if(p instanceof RolePrincipal) {
-                    group.addMember(p);
-                } else {
-                    subject.getPrincipals().add(p);
-                }
-            }
-            subject.getPrincipals().add(group);
-        }
     };
 
     private String value;

Modified: karaf/trunk/jaas/command/pom.xml
URL: http://svn.apache.org/viewvc/karaf/trunk/jaas/command/pom.xml?rev=1527592&r1=1527591&r2=1527592&view=diff
==============================================================================
--- karaf/trunk/jaas/command/pom.xml (original)
+++ karaf/trunk/jaas/command/pom.xml Mon Sep 30 14:28:59 2013
@@ -30,7 +30,7 @@
 
     <artifactId>org.apache.karaf.jaas.command</artifactId>
     <packaging>bundle</packaging>
-    <name>Apache Karaf :: Jaas :: Command</name>
+    <name>Apache Karaf :: JAAS :: Command</name>
     <description>This bundle provides Karaf shell commands to manipulate JAAS security framework.</description>
 
     <properties>

Added: karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/GroupAddCommand.java
URL: http://svn.apache.org/viewvc/karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/GroupAddCommand.java?rev=1527592&view=auto
==============================================================================
--- karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/GroupAddCommand.java (added)
+++ karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/GroupAddCommand.java Mon Sep 30 14:28:59 2013
@@ -0,0 +1,58 @@
+/*
+ * 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.karaf.jaas.command;
+
+import org.apache.karaf.jaas.modules.BackingEngine;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+
+@Command(scope = "jaas", name = "group-add", description = "Make an user part of a group")
+public class GroupAddCommand extends JaasCommandSupport {
+
+    @Argument(index = 0, name = "username", description = "Username", required = true, multiValued = false)
+    private String username;
+
+    @Argument(index = 1, name = "group", description = "Group", required = true, multiValued = false)
+    private String group;
+
+    @Override
+    protected Object doExecute(BackingEngine engine) throws Exception {
+        engine.addGroup(username, group);
+        return null;
+    }
+
+    public String getUsername() {
+        return this.username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getGroup() {
+        return this.group;
+    }
+
+    public void setGroup(String group) {
+        this.group = group;
+    }
+
+    @Override
+    public String toString() {
+        return "GroupAddCommand {username='" + username + "', group='" + group + "'}";
+    }
+
+}

Added: karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/GroupDeleteCommand.java
URL: http://svn.apache.org/viewvc/karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/GroupDeleteCommand.java?rev=1527592&view=auto
==============================================================================
--- karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/GroupDeleteCommand.java (added)
+++ karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/GroupDeleteCommand.java Mon Sep 30 14:28:59 2013
@@ -0,0 +1,58 @@
+/*
+ * 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.karaf.jaas.command;
+
+import org.apache.karaf.jaas.modules.BackingEngine;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+
+@Command(scope = "jaas", name = "group-delete", description = "Remove an user from a group")
+public class GroupDeleteCommand extends JaasCommandSupport {
+
+    @Argument(index = 0, name = "username", description = "Username", required = true, multiValued = false)
+    private String username;
+
+    @Argument(index = 1, name = "group", description = "Group", required = true, multiValued = false)
+    private String group;
+
+    @Override
+    protected Object doExecute(BackingEngine engine) throws Exception {
+        engine.deleteGroup(username, group);
+        return null;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getGroup() {
+        return group;
+    }
+
+    public void setGroup(String group) {
+        this.group = group;
+    }
+
+    @Override
+    public String toString() {
+        return "GroupDeleteCommand {username='" + username + "', group='" + group + "'}";
+    }
+
+}

Added: karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/GroupRoleAddCommand.java
URL: http://svn.apache.org/viewvc/karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/GroupRoleAddCommand.java?rev=1527592&view=auto
==============================================================================
--- karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/GroupRoleAddCommand.java (added)
+++ karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/GroupRoleAddCommand.java Mon Sep 30 14:28:59 2013
@@ -0,0 +1,58 @@
+/*
+ * 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.karaf.jaas.command;
+
+import org.apache.karaf.jaas.modules.BackingEngine;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+
+@Command(scope = "jaas", name = "group-role-add", description = "Add a role to a group")
+public class GroupRoleAddCommand extends JaasCommandSupport {
+
+    @Argument(index = 0, name = "group", description = "Group", required = true, multiValued = false)
+    private String group;
+
+    @Argument(index = 1, name = "role", description = "Role", required = true, multiValued = false)
+    private String role;
+
+    @Override
+    protected Object doExecute(BackingEngine engine) throws Exception {
+        engine.addGroupRole(group, role);
+        return null;
+    }
+
+    public String getGroup() {
+        return group;
+    }
+
+    public void setGroup(String group) {
+        this.group = group;
+    }
+
+    public String getRole() {
+        return role;
+    }
+
+    public void setRole(String role) {
+        this.role = role;
+    }
+
+    @Override
+    public String toString() {
+        return "GroupRoleAddCommand {groupname='" + group + "', role='" + role + "'}";
+    }
+
+}

Added: karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/GroupRoleDeleteCommand.java
URL: http://svn.apache.org/viewvc/karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/GroupRoleDeleteCommand.java?rev=1527592&view=auto
==============================================================================
--- karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/GroupRoleDeleteCommand.java (added)
+++ karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/GroupRoleDeleteCommand.java Mon Sep 30 14:28:59 2013
@@ -0,0 +1,58 @@
+/*
+ * 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.karaf.jaas.command;
+
+import org.apache.karaf.jaas.modules.BackingEngine;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+
+@Command(scope = "jaas", name = "group-role-delete", description = "Remove a role from a group")
+public class GroupRoleDeleteCommand extends JaasCommandSupport {
+
+    @Argument(index = 0, name = "group", description = "Group", required = true, multiValued = false)
+    private String group;
+
+    @Argument(index = 1, name = "role", description = "Role", required = true, multiValued = false)
+    private String role;
+
+    @Override
+    protected Object doExecute(BackingEngine engine) throws Exception {
+        engine.deleteGroupRole(group, role);
+        return null;
+    }
+
+    public String getGroup() {
+        return group;
+    }
+
+    public void setGroup(String group) {
+        this.group = group;
+    }
+
+    public String getRole() {
+        return role;
+    }
+
+    public void setRole(String role) {
+        this.role = role;
+    }
+
+    @Override
+    public String toString() {
+        return "GroupRoleDeleteCommand {groupname='" + group + "', role='" + role + "'}";
+    }
+
+}

Modified: karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/ListUsersCommand.java
URL: http://svn.apache.org/viewvc/karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/ListUsersCommand.java?rev=1527592&r1=1527591&r2=1527592&view=diff
==============================================================================
--- karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/ListUsersCommand.java (original)
+++ karaf/trunk/jaas/command/src/main/java/org/apache/karaf/jaas/command/ListUsersCommand.java Mon Sep 30 14:28:59 2013
@@ -15,14 +15,17 @@
  */
 package org.apache.karaf.jaas.command;
 
-import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.jaas.boot.principal.GroupPrincipal;
 import org.apache.karaf.jaas.boot.principal.RolePrincipal;
+import org.apache.karaf.shell.commands.Command;
 import org.apache.karaf.jaas.boot.principal.UserPrincipal;
 import org.apache.karaf.jaas.config.JaasRealm;
 import org.apache.karaf.jaas.modules.BackingEngine;
 import org.apache.karaf.shell.table.ShellTable;
 
 import javax.security.auth.login.AppConfigurationEntry;
+import java.security.Principal;
+import java.util.ArrayList;
 import java.util.List;
 
 @Command(scope = "jaas", name = "user-list", description = "List the users of the selected JAAS realm/login module")
@@ -54,19 +57,20 @@ public class ListUsersCommand extends Ja
 
         ShellTable table = new ShellTable();
         table.column("User Name");
+        table.column("Group");
         table.column("Role");
 
         for (UserPrincipal user : users) {
+            List<String> reportedRoles = new ArrayList<String>();
             String userName = user.getName();
-            List<RolePrincipal> roles = engine.listRoles(user);
 
-            if (roles != null && roles.size() >= 1) {
-                for (RolePrincipal role : roles) {
-                    String roleName = role.getName();
-                    table.addRow().addContent(userName, roleName);
-                }
-            } else {
-                table.addRow().addContent(userName, "");
+            for (GroupPrincipal group : engine.listGroups(user)) {
+                String groupName = group.getName();
+                reportedRoles.addAll(displayRole(engine, userName, groupName, group, table));
+            }
+
+            if (reportedRoles.size() == 0) {
+                table.addRow().addContent(userName, "", "");
             }
 
         }
@@ -76,4 +80,19 @@ public class ListUsersCommand extends Ja
         return null;
     }
 
+    private List<String> displayRole(BackingEngine engine, String userName, String groupName, Principal principal, ShellTable table) {
+        List<String> names = new ArrayList<String>();
+        List<RolePrincipal> roles = engine.listRoles(principal);
+
+        if (roles != null && roles.size() >= 1) {
+            for (RolePrincipal role : roles) {
+                String roleName = role.getName();
+                names.add(roleName);
+                table.addRow().addContent(userName, groupName, roleName);
+            }
+        }
+
+        return names;
+    }
+
 }

Modified: karaf/trunk/jaas/command/src/main/resources/OSGI-INF/blueprint/jaas-command.xml
URL: http://svn.apache.org/viewvc/karaf/trunk/jaas/command/src/main/resources/OSGI-INF/blueprint/jaas-command.xml?rev=1527592&r1=1527591&r2=1527592&view=diff
==============================================================================
--- karaf/trunk/jaas/command/src/main/resources/OSGI-INF/blueprint/jaas-command.xml (original)
+++ karaf/trunk/jaas/command/src/main/resources/OSGI-INF/blueprint/jaas-command.xml Mon Sep 30 14:28:59 2013
@@ -63,6 +63,12 @@
         <command>
             <action class="org.apache.karaf.jaas.command.RoleDeleteCommand"/>
         </command>
+        <command>
+            <action class="org.apache.karaf.jaas.command.GroupAddCommand"/>
+        </command>
+        <command>
+            <action class="org.apache.karaf.jaas.command.GroupDeleteCommand"/>
+        </command>
     </command-bundle>
 
     <!-- JAAS Realms -->

Modified: karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/BackingEngine.java
URL: http://svn.apache.org/viewvc/karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/BackingEngine.java?rev=1527592&r1=1527591&r2=1527592&view=diff
==============================================================================
--- karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/BackingEngine.java (original)
+++ karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/BackingEngine.java Mon Sep 30 14:28:59 2013
@@ -14,14 +14,15 @@
  */
 package org.apache.karaf.jaas.modules;
 
+import java.security.Principal;
 import java.util.List;
 
+import org.apache.karaf.jaas.boot.principal.GroupPrincipal;
 import org.apache.karaf.jaas.boot.principal.RolePrincipal;
 import org.apache.karaf.jaas.boot.principal.UserPrincipal;
 
 public interface BackingEngine {
 
-
     /**
      * Create a new User.
      *
@@ -43,12 +44,37 @@ public interface BackingEngine {
     List<UserPrincipal> listUsers();
 
     /**
-     * List Roles for {@param user}.
+     * List groups that an user is in.
      *
      * @param user
      * @return
      */
-    List<RolePrincipal> listRoles(UserPrincipal user);
+    List<GroupPrincipal> listGroups(UserPrincipal user);
+
+    /**
+     * Add an user to a group.
+     *
+     * @param username
+     * @param group
+     */
+    void addGroup(String username, String group);
+
+    /**
+     * Remove an user from a group.
+     *
+     * @param username
+     * @param group
+     */
+    void deleteGroup(String username, String group);
+
+    /**
+     * List Roles for {@param principal}. This could either be a
+     * {@link UserPrincipal} or a {@link GroupPrincipal}.
+     *
+     * @param principal
+     * @return
+     */
+    List<RolePrincipal> listRoles(Principal principal);
 
     /**
      * Add a role to the user
@@ -66,4 +92,20 @@ public interface BackingEngine {
      */
     void deleteRole(String username, String role);
 
+    /**
+     * Add a role in a group.
+     *
+     * @param group
+     * @param role
+     */
+    void addGroupRole(String group, String role);
+
+    /**
+     * Remove a role from a group.
+     *
+     * @param group
+     * @param role
+     */
+    void deleteGroupRole(String group, String role);
+
 }

Modified: karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCBackingEngine.java
URL: http://svn.apache.org/viewvc/karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCBackingEngine.java?rev=1527592&r1=1527591&r2=1527592&view=diff
==============================================================================
--- karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCBackingEngine.java (original)
+++ karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/jdbc/JDBCBackingEngine.java Mon Sep 30 14:28:59 2013
@@ -13,9 +13,9 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
-
 package org.apache.karaf.jaas.modules.jdbc;
 
+import org.apache.karaf.jaas.boot.principal.GroupPrincipal;
 import org.apache.karaf.jaas.boot.principal.RolePrincipal;
 import org.apache.karaf.jaas.boot.principal.UserPrincipal;
 import org.apache.karaf.jaas.modules.BackingEngine;
@@ -24,11 +24,13 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import javax.sql.DataSource;
+import java.security.Principal;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 public class JDBCBackingEngine implements BackingEngine {
@@ -216,12 +218,12 @@ public class JDBCBackingEngine implement
     }
 
     /**
-     * List the roles of the {@param user}.
+     * List the roles of the {@param principal}.
      *
-     * @param user
+     * @param principal
      * @return
      */
-    public List<RolePrincipal> listRoles(UserPrincipal user) {
+    public List<RolePrincipal> listRoles(Principal principal) {
         List<RolePrincipal> roles = new ArrayList<RolePrincipal>();
 
         Connection connection = null;
@@ -236,7 +238,7 @@ public class JDBCBackingEngine implement
 
                 //Remove from roles
                 listRolesStatement = connection.prepareStatement(selectRolesQuery);
-                listRolesStatement.setString(1, user.getName());
+                listRolesStatement.setString(1, principal.getName());
 
                 rolesResultSet = listRolesStatement.executeQuery();
 
@@ -406,4 +408,34 @@ public class JDBCBackingEngine implement
         this.selectRolesQuery = selectRolesQuery;
     }
 
+    @Override
+    public List<GroupPrincipal> listGroups(UserPrincipal user) {
+        // TODO support of groups has to be added
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void addGroup(String username, String group) {
+        // TODO support of groups has to be added
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void deleteGroup(String username, String group) {
+        // TODO support of groups has to be added
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void addGroupRole(String group, String role) {
+        // TODO support of groups has to be added
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void deleteGroupRole(String group, String role) {
+        // TODO support of groups has to be added
+        throw new UnsupportedOperationException();
+    }
+
 }

Modified: karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/properties/PropertiesBackingEngine.java
URL: http://svn.apache.org/viewvc/karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/properties/PropertiesBackingEngine.java?rev=1527592&r1=1527591&r2=1527592&view=diff
==============================================================================
--- karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/properties/PropertiesBackingEngine.java (original)
+++ karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/properties/PropertiesBackingEngine.java Mon Sep 30 14:28:59 2013
@@ -13,10 +13,10 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
-
 package org.apache.karaf.jaas.modules.properties;
 
 import org.apache.felix.utils.properties.Properties;
+import org.apache.karaf.jaas.boot.principal.GroupPrincipal;
 import org.apache.karaf.jaas.boot.principal.RolePrincipal;
 import org.apache.karaf.jaas.boot.principal.UserPrincipal;
 import org.apache.karaf.jaas.modules.BackingEngine;
@@ -24,14 +24,16 @@ import org.apache.karaf.jaas.modules.enc
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.security.Principal;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Set;
 
 public class PropertiesBackingEngine implements BackingEngine {
 
     private static final transient Logger LOGGER = LoggerFactory.getLogger(PropertiesBackingEngine.class);
 
+    static final String GROUP_PREFIX = "_g_:";
+
     private Properties users;
     private EncryptionSupport encryptionSupport;
 
@@ -49,13 +51,15 @@ public class PropertiesBackingEngine imp
         this.encryptionSupport = encryptionSupport;
     }
 
-    /**
-     * Add a user.
-     *
-     * @param username
-     * @param password
-     */
+    @Override
     public void addUser(String username, String password) {
+        if (username.startsWith(GROUP_PREFIX))
+            throw new IllegalArgumentException("Prefix not permitted: " + GROUP_PREFIX);
+
+        addUserInternal(username, password);
+    }
+
+    private void addUserInternal(String username, String password) {
         String[] infos = null;
         StringBuffer userInfoBuffer = new StringBuffer();
 
@@ -96,12 +100,13 @@ public class PropertiesBackingEngine imp
         }
     }
 
-    /**
-     * Delete a User.
-     *
-     * @param username
-     */
+    @Override
     public void deleteUser(String username) {
+        // delete all its groups first, for garbage collection of the groups
+        for (GroupPrincipal gp : listGroups(username)) {
+            deleteGroup(username, gp.getName());
+        }
+
         users.remove(username);
 
         try {
@@ -111,43 +116,54 @@ public class PropertiesBackingEngine imp
         }
     }
 
-    /**
-     * List Users
-     *
-     * @return
-     */
+    @Override
     public List<UserPrincipal> listUsers() {
         List<UserPrincipal> result = new ArrayList<UserPrincipal>();
 
-        for (String userNames :	(Set<String>) users.keySet()) {
-            UserPrincipal userPrincipal = new UserPrincipal(userNames);
+        for (Object user : users.keySet()) {
+            String userName = (String) user;
+            if (userName.startsWith(GROUP_PREFIX))
+                continue;
+
+            UserPrincipal userPrincipal = new UserPrincipal(userName);
             result.add(userPrincipal);
         }
         return result;
     }
 
-    /**
-     * List the Roles of the {@param user}
-     *
-     * @param user
-     * @return
-     */
-    public List<RolePrincipal> listRoles(UserPrincipal user) {
+    @Override
+    public List<RolePrincipal> listRoles(Principal principal) {
+        String userName = principal.getName();
+        if (principal instanceof  GroupPrincipal) {
+            userName = GROUP_PREFIX + userName;
+        }
+        return listRoles(userName);
+    }
+
+    private List<RolePrincipal> listRoles(String name) {
+
         List<RolePrincipal> result = new ArrayList<RolePrincipal>();
-        String userInfo = (String) users.get(user.getName());
+        String userInfo = (String) users.get(name);
         String[] infos = userInfo.split(",");
         for (int i = 1; i < infos.length; i++) {
-            result.add(new RolePrincipal(infos[i]));
+            String roleName = infos[i];
+            if (roleName.startsWith(GROUP_PREFIX)) {
+                for (RolePrincipal rp : listRoles(roleName)) {
+                    if (!result.contains(rp)) {
+                        result.add(rp);
+                    }
+                }
+            } else {
+                RolePrincipal rp = new RolePrincipal(roleName);
+                if (!result.contains(rp)) {
+                    result.add(rp);
+                }
+            }
         }
         return result;
     }
 
-    /**
-     * Add a role to a User.
-     *
-     * @param username
-     * @param role
-     */
+    @Override
     public void addRole(String username, String role) {
         String userInfos = (String) users.get(username);
         if (userInfos != null) {
@@ -161,12 +177,7 @@ public class PropertiesBackingEngine imp
         }
     }
 
-    /**
-     * Delete a Role form User.
-     *
-     * @param username
-     * @param role
-     */
+    @Override
     public void deleteRole(String username, String role) {
         String[] infos = null;
         StringBuffer userInfoBuffer = new StringBuffer();
@@ -196,4 +207,62 @@ public class PropertiesBackingEngine imp
         }
     }
 
+    @Override
+    public List<GroupPrincipal> listGroups(UserPrincipal user) {
+        String userName = user.getName();
+        return listGroups(userName);
+    }
+
+    private List<GroupPrincipal> listGroups(String userName) {
+        List<GroupPrincipal> result = new ArrayList<GroupPrincipal>();
+        String userInfo = (String) users.get(userName);
+        if (userInfo != null) {
+            String[] infos = userInfo.split(",");
+            for (int i = 1; i < infos.length; i++) {
+                String name = infos[i];
+                if (name.startsWith(GROUP_PREFIX)) {
+                    result.add(new GroupPrincipal(name.substring(GROUP_PREFIX.length())));
+                }
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public void addGroup(String username, String group) {
+        String groupName = GROUP_PREFIX + group;
+        if (users.get(groupName) == null) {
+            addUserInternal(groupName, "group");
+        }
+        addRole(username, groupName);
+    }
+
+    @Override
+    public void deleteGroup(String username, String group) {
+        deleteRole(username, GROUP_PREFIX + group);
+
+        // garbage collection, clean up the groups if needed
+        for (UserPrincipal user : listUsers()) {
+            for (GroupPrincipal g : listGroups(user)) {
+                if (group.equals(g.getName())) {
+                    // there is another user of this group, nothing to clean up
+                    return;
+                }
+            }
+        }
+
+        // nobody is using this group any more, remote it
+        deleteUser(GROUP_PREFIX + group);
+    }
+
+    @Override
+    public void addGroupRole(String group, String role) {
+        addRole(GROUP_PREFIX + group, role);
+    }
+
+    @Override
+    public void deleteGroupRole(String group, String role) {
+        deleteRole(GROUP_PREFIX + group, role);
+    }
+
 }

Modified: karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/properties/PropertiesLoginModule.java
URL: http://svn.apache.org/viewvc/karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/properties/PropertiesLoginModule.java?rev=1527592&r1=1527591&r2=1527592&view=diff
==============================================================================
--- karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/properties/PropertiesLoginModule.java (original)
+++ karaf/trunk/jaas/modules/src/main/java/org/apache/karaf/jaas/modules/properties/PropertiesLoginModule.java Mon Sep 30 14:28:59 2013
@@ -31,6 +31,7 @@ import javax.security.auth.login.FailedL
 import javax.security.auth.login.LoginException;
 
 import org.apache.felix.utils.properties.Properties;
+import org.apache.karaf.jaas.boot.principal.GroupPrincipal;
 import org.apache.karaf.jaas.boot.principal.RolePrincipal;
 import org.apache.karaf.jaas.boot.principal.UserPrincipal;
 import org.apache.karaf.jaas.modules.AbstractKarafLoginModule;
@@ -44,7 +45,7 @@ public class PropertiesLoginModule exten
 
     private static final transient Logger LOGGER = LoggerFactory.getLogger(PropertiesLoginModule.class);
 
-    private static final String USER_FILE = "users";
+    static final String USER_FILE = "users";
 
     private String usersFile;
 
@@ -84,6 +85,11 @@ public class PropertiesLoginModule exten
         }
         // user callback get value
         user = ((NameCallback) callbacks[0]).getName();
+        if (user.startsWith(PropertiesBackingEngine.GROUP_PREFIX)) {
+            // you can't log in under a group name
+            throw new FailedLoginException("login failed");
+        }
+
         // password callback get value
         String password = new String(((PasswordCallback) callbacks[1]).getPassword());
 
@@ -155,7 +161,20 @@ public class PropertiesLoginModule exten
         principals = new HashSet<Principal>();
         principals.add(new UserPrincipal(user));
         for (int i = 1; i < infos.length; i++) {
-            principals.add(new RolePrincipal(infos[i]));
+            if (infos[i].startsWith(PropertiesBackingEngine.GROUP_PREFIX)) {
+                // it's a group reference
+                principals.add(new GroupPrincipal(infos[i].substring(PropertiesBackingEngine.GROUP_PREFIX.length())));
+                String groupInfo = (String) users.get(infos[i]);
+                if (groupInfo != null) {
+                    String[] roles = groupInfo.split(",");
+                    for (int j = 1; j < roles.length; j++) {
+                        principals.add(new RolePrincipal(roles[j]));
+                    }
+                }
+            } else {
+                // it's an user reference
+                principals.add(new RolePrincipal(infos[i]));
+            }
         }
 
         users.clear();

Added: karaf/trunk/jaas/modules/src/test/java/org/apache/karaf/jaas/modules/properties/PropertiesBackingEngineTest.java
URL: http://svn.apache.org/viewvc/karaf/trunk/jaas/modules/src/test/java/org/apache/karaf/jaas/modules/properties/PropertiesBackingEngineTest.java?rev=1527592&view=auto
==============================================================================
--- karaf/trunk/jaas/modules/src/test/java/org/apache/karaf/jaas/modules/properties/PropertiesBackingEngineTest.java (added)
+++ karaf/trunk/jaas/modules/src/test/java/org/apache/karaf/jaas/modules/properties/PropertiesBackingEngineTest.java Mon Sep 30 14:28:59 2013
@@ -0,0 +1,204 @@
+/*
+ * 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.karaf.jaas.modules.properties;
+
+import junit.framework.TestCase;
+import org.apache.felix.utils.properties.Properties;
+import org.apache.karaf.jaas.boot.principal.GroupPrincipal;
+import org.apache.karaf.jaas.boot.principal.RolePrincipal;
+import org.apache.karaf.jaas.boot.principal.UserPrincipal;
+
+import java.io.File;
+import java.io.IOException;
+
+public class PropertiesBackingEngineTest extends TestCase {
+
+    public void testUserRoles() throws IOException {
+        File f = File.createTempFile(getClass().getName(), ".tmp");
+        try {
+            Properties p = new Properties(f);
+
+            PropertiesBackingEngine engine = new PropertiesBackingEngine(p);
+            engine.addUser("a", "aa");
+            assertEquals(1, engine.listUsers().size());
+            UserPrincipal upa = engine.listUsers().iterator().next();
+            assertEquals("a", upa.getName());
+            engine.addUser("b", "bb");
+
+            engine.addRole("a", "role1");
+            engine.addRole("a", "role2");
+            assertEquals(2, engine.listRoles(upa).size());
+
+            boolean foundR1 = false;
+            boolean foundR2 = false;
+            for (RolePrincipal rp : engine.listRoles(upa)) {
+                if ("role1".equals(rp.getName())) {
+                    foundR1 = true;
+                } else if ("role2".equals(rp.getName())) {
+                    foundR2 = true;
+                }
+            }
+            assertTrue(foundR1);
+            assertTrue(foundR2);
+
+            engine.addGroup("a", "g");
+            engine.addGroupRole("g", "role2");
+            engine.addGroupRole("g", "role3");
+            engine.addGroup("b", "g");
+            engine.addGroup("b", "g2");
+            engine.addGroupRole("g2", "role4");
+
+            assertEquals(2, engine.listUsers().size());
+            UserPrincipal upa_1 = null;
+            UserPrincipal upb_1 = null;
+            for (UserPrincipal u : engine.listUsers()) {
+                if ("a".equals(u.getName())) {
+                    upa_1 = u;
+                } else if ("b".equals(u.getName())) {
+                    upb_1 = u;
+                }
+            }
+            assertNotNull(upa_1);
+            assertNotNull(upb_1);
+
+            assertEquals(3, engine.listRoles(upa).size());
+            boolean foundR1_2 = false;
+            boolean foundR2_2 = false;
+            boolean foundR3_2 = false;
+            for (RolePrincipal rp : engine.listRoles(upa)) {
+                if ("role1".equals(rp.getName())) {
+                    foundR1_2 = true;
+                } else if ("role2".equals(rp.getName())) {
+                    foundR2_2 = true;
+                } else if ("role3".equals(rp.getName())) {
+                    foundR3_2 = true;
+                }
+            }
+            assertTrue(foundR1_2);
+            assertTrue(foundR2_2);
+            assertTrue(foundR3_2);
+
+            // check that the loading works
+            PropertiesBackingEngine engine2 = new PropertiesBackingEngine(new Properties(f));
+            assertEquals(2, engine2.listUsers().size());
+            UserPrincipal upa_2 = null;
+            UserPrincipal upb_2 = null;
+            for (UserPrincipal u : engine2.listUsers()) {
+                if ("a".equals(u.getName())) {
+                    upa_2 = u;
+                } else if ("b".equals(u.getName())) {
+                    upb_2 = u;
+                }
+            }
+            assertNotNull(upa_2);
+            assertNotNull(upb_2);
+
+            assertEquals(3, engine2.listRoles(upa_2).size());
+            boolean foundR1_3 = false;
+            boolean foundR2_3 = false;
+            boolean foundR3_3 = false;
+            for (RolePrincipal rp : engine2.listRoles(upa_2)) {
+                if ("role1".equals(rp.getName())) {
+                    foundR1_3 = true;
+                } else if ("role2".equals(rp.getName())) {
+                    foundR2_3 = true;
+                } else if ("role3".equals(rp.getName())) {
+                    foundR3_3 = true;
+                }
+            }
+            assertTrue(foundR1_3);
+            assertTrue(foundR2_3);
+            assertTrue(foundR3_3);
+
+            assertEquals(3, engine2.listRoles(upb_2).size());
+            boolean foundR2_4 = false;
+            boolean foundR3_4 = false;
+            boolean foundR4_4 = false;
+            for (RolePrincipal rp : engine2.listRoles(upb_2)) {
+                if ("role2".equals(rp.getName())) {
+                    foundR2_4 = true;
+                } else if ("role3".equals(rp.getName())) {
+                    foundR3_4 = true;
+                } else if ("role4".equals(rp.getName())) {
+                    foundR4_4 = true;
+                }
+            }
+            assertTrue(foundR2_4);
+            assertTrue(foundR3_4);
+            assertTrue(foundR4_4);
+
+            // removing some stuff
+            UserPrincipal upb = null;
+            for (UserPrincipal up : engine.listUsers()) {
+                if ("b".equals(up.getName())) {
+                    upb = up;
+                }
+            }
+            assertEquals(1, engine.listGroups(upa).size());
+            assertEquals(2, engine.listGroups(upb).size());
+
+            GroupPrincipal gp = engine.listGroups(upa).iterator().next();
+            engine.deleteGroupRole("g", "role2");
+            assertEquals(1, engine.listRoles(gp).size());
+            assertEquals("role3", engine.listRoles(gp).iterator().next().getName());
+
+            // check that the user roles are reported correctly
+            assertEquals("role2 should still be there as it was added to the user directly too", 3, engine.listRoles(upa).size());
+            boolean foundR1_5 = false;
+            boolean foundR2_5 = false;
+            boolean foundR3_5 = false;
+            for (RolePrincipal rp : engine.listRoles(upa)) {
+                if ("role1".equals(rp.getName())) {
+                    foundR1_5 = true;
+                } else if ("role2".equals(rp.getName())) {
+                    foundR2_5 = true;
+                } else if ("role3".equals(rp.getName())) {
+                    foundR3_5 = true;
+                }
+            }
+            assertTrue(foundR1_5);
+            assertTrue(foundR2_5);
+            assertTrue(foundR3_5);
+
+            assertEquals(2, engine.listRoles(upb).size());
+            boolean foundR3_6 = false;
+            boolean foundR4_6 = false;
+            for (RolePrincipal rp : engine.listRoles(upb)) {
+                if ("role3".equals(rp.getName())) {
+                    foundR3_6 = true;
+                } else if ("role4".equals(rp.getName())) {
+                    foundR4_6 = true;
+                }
+            }
+            assertTrue(foundR3_6);
+            assertTrue(foundR4_6);
+
+            engine.deleteGroup("b", "g");
+            engine.deleteGroup("b", "g2");
+            assertEquals(0, engine.listRoles(upb).size());
+
+            engine.deleteUser("b");
+            engine.deleteUser("a");
+            assertEquals("Properties should be empty now", 0, p.size());
+        } finally {
+            if (!f.delete()) {
+                fail("Could not delete temporary file: " + f);
+            }
+        }
+    }
+
+}

Modified: karaf/trunk/jaas/modules/src/test/java/org/apache/karaf/jaas/modules/properties/PropertiesLoginModuleTest.java
URL: http://svn.apache.org/viewvc/karaf/trunk/jaas/modules/src/test/java/org/apache/karaf/jaas/modules/properties/PropertiesLoginModuleTest.java?rev=1527592&r1=1527591&r2=1527592&view=diff
==============================================================================
--- karaf/trunk/jaas/modules/src/test/java/org/apache/karaf/jaas/modules/properties/PropertiesLoginModuleTest.java (original)
+++ karaf/trunk/jaas/modules/src/test/java/org/apache/karaf/jaas/modules/properties/PropertiesLoginModuleTest.java Mon Sep 30 14:28:59 2013
@@ -1,19 +1,246 @@
+/*
+ * 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.karaf.jaas.modules.properties;
 
+import java.io.File;
 import java.io.IOException;
+import java.security.Principal;
 import java.util.HashMap;
 import java.util.Map;
 
 import javax.security.auth.Subject;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.callback.*;
+import javax.security.auth.login.FailedLoginException;
 import javax.security.auth.login.LoginException;
 
 import junit.framework.Assert;
 
+import org.apache.felix.utils.properties.Properties;
+import org.apache.karaf.jaas.boot.principal.GroupPrincipal;
+import org.apache.karaf.jaas.boot.principal.RolePrincipal;
+import org.apache.karaf.jaas.boot.principal.UserPrincipal;
 import org.junit.Test;
 
 public class PropertiesLoginModuleTest {
+
+    @Test
+    public void testBasicLogin() throws Exception {
+        File f = File.createTempFile(getClass().getName(), ".tmp");
+        try {
+            Properties p = new Properties(f);
+            PropertiesBackingEngine pbe = new PropertiesBackingEngine(p);
+            pbe.addUser("abc", "xyz");
+            pbe.addRole("abc", "myrole");
+            pbe.addUser("pqr", "abc");
+
+            PropertiesLoginModule module = new PropertiesLoginModule();
+            Map<String, String> options = new HashMap<String, String>();
+            options.put(PropertiesLoginModule.USER_FILE, f.getAbsolutePath());
+            CallbackHandler cb = new CallbackHandler() {
+                @Override
+                public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+                    for (Callback cb : callbacks) {
+                        if (cb instanceof NameCallback) {
+                            ((NameCallback) cb).setName("abc");
+                        } else if (cb instanceof PasswordCallback) {
+                            ((PasswordCallback) cb).setPassword("xyz".toCharArray());
+                        }
+                    }
+                }
+            };
+            Subject subject = new Subject();
+            module.initialize(subject, cb, null, options);
+
+            Assert.assertEquals("Precondition", 0, subject.getPrincipals().size());
+            Assert.assertTrue(module.login());
+            Assert.assertTrue(module.commit());
+
+            Assert.assertEquals(2, subject.getPrincipals().size());
+
+            boolean foundUser = false;
+            boolean foundRole = false;
+            for (Principal pr : subject.getPrincipals()) {
+                if (pr instanceof UserPrincipal) {
+                    Assert.assertEquals("abc", pr.getName());
+                    foundUser = true;
+                } else if (pr instanceof RolePrincipal) {
+                    Assert.assertEquals("myrole", pr.getName());
+                    foundRole = true;
+                }
+            }
+            Assert.assertTrue(foundUser);
+            Assert.assertTrue(foundRole);
+
+            Assert.assertTrue(module.logout());
+            Assert.assertEquals("Principals should be gone as the user has logged out", 0, subject.getPrincipals().size());
+        } finally {
+            if (!f.delete()) {
+                Assert.fail("Could not delete temporary file: " + f);
+            }
+        }
+    }
+
+    @Test
+    public void testLoginIncorrectPassword() throws Exception {
+        File f = File.createTempFile(getClass().getName(), ".tmp");
+        try {
+            Properties p = new Properties(f);
+            PropertiesBackingEngine pbe = new PropertiesBackingEngine(p);
+            pbe.addUser("abc", "xyz");
+            pbe.addUser("pqr", "abc");
+
+            PropertiesLoginModule module = new PropertiesLoginModule();
+            Map<String, String> options = new HashMap<String, String>();
+            options.put(PropertiesLoginModule.USER_FILE, f.getAbsolutePath());
+            CallbackHandler cb = new CallbackHandler() {
+                @Override
+                public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+                    for (Callback cb : callbacks) {
+                        if (cb instanceof NameCallback) {
+                            ((NameCallback) cb).setName("abc");
+                        } else if (cb instanceof PasswordCallback) {
+                            ((PasswordCallback) cb).setPassword("abc".toCharArray());
+                        }
+                    }
+                }
+            };
+            module.initialize(new Subject(), cb, null, options);
+            try {
+                module.login();
+                Assert.fail("The login should have failed as the passwords didn't match");
+            } catch (FailedLoginException fle) {
+                // good
+            }
+        } finally {
+            if (!f.delete()) {
+                Assert.fail("Could not delete temporary file: " + f);
+            }
+        }
+    }
+
+    @Test
+    public void testLoginWithGroups() throws Exception {
+        File f = File.createTempFile(getClass().getName(), ".tmp");
+        try {
+            Properties p = new Properties(f);
+            PropertiesBackingEngine pbe = new PropertiesBackingEngine(p);
+            pbe.addUser("abc", "xyz");
+            pbe.addRole("abc", "myrole");
+            pbe.addUser("pqr", "abc");
+            pbe.addGroup("pqr", "group1");
+            pbe.addGroupRole("group1", "r1");
+
+            PropertiesLoginModule module = new PropertiesLoginModule();
+            Map<String, String> options = new HashMap<String, String>();
+            options.put(PropertiesLoginModule.USER_FILE, f.getAbsolutePath());
+            CallbackHandler cb = new CallbackHandler() {
+                @Override
+                public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+                    for (Callback cb : callbacks) {
+                        if (cb instanceof NameCallback) {
+                            ((NameCallback) cb).setName("pqr");
+                        } else if (cb instanceof PasswordCallback) {
+                            ((PasswordCallback) cb).setPassword("abc".toCharArray());
+                        }
+                    }
+                }
+            };
+            Subject subject = new Subject();
+            module.initialize(subject, cb, null, options);
+
+            Assert.assertEquals("Precondition", 0, subject.getPrincipals().size());
+            Assert.assertTrue(module.login());
+            Assert.assertTrue(module.commit());
+
+            Assert.assertEquals(3, subject.getPrincipals().size());
+            boolean foundUser = false;
+            boolean foundRole = false;
+            boolean foundGroup = false;
+            for (Principal pr : subject.getPrincipals()) {
+                if (pr instanceof UserPrincipal) {
+                    Assert.assertEquals("pqr", pr.getName());
+                    foundUser = true;
+                } else if (pr instanceof GroupPrincipal) {
+                    Assert.assertEquals("group1", pr.getName());
+                    foundGroup = true;
+                } else if (pr instanceof RolePrincipal) {
+                    Assert.assertEquals("r1", pr.getName());
+                    foundRole = true;
+                }
+            }
+            Assert.assertTrue(foundUser);
+            Assert.assertTrue(foundGroup);
+            Assert.assertTrue(foundRole);
+        } finally {
+            if (!f.delete()) {
+                Assert.fail("Could not delete temporary file: " + f);
+            }
+        }
+    }
+
+    // This is a fairly important test that ensures that you cannot log in under the name of a
+    // group directly.
+    @Test
+    public void testCannotLoginAsGroupDirectly() throws Exception {
+        testCannotLoginAsGroupDirectly("group1");
+        testCannotLoginAsGroupDirectly("_g_:group1");
+        testCannotLoginAsGroupDirectly(PropertiesBackingEngine.GROUP_PREFIX + "group1");
+    }
+
+    private void testCannotLoginAsGroupDirectly(final String name) throws IOException, LoginException {
+        File f = File.createTempFile(getClass().getName(), ".tmp");
+        try {
+            Properties p = new Properties(f);
+            PropertiesBackingEngine pbe = new PropertiesBackingEngine(p);
+            pbe.addUser("abc", "xyz");
+            pbe.addRole("abc", "myrole");
+            pbe.addUser("pqr", "abc");
+            pbe.addGroup("pqr", "group1");
+            pbe.addGroupRole("group1", "r1");
+
+            PropertiesLoginModule module = new PropertiesLoginModule();
+            Map<String, String> options = new HashMap<String, String>();
+            options.put(PropertiesLoginModule.USER_FILE, f.getAbsolutePath());
+            CallbackHandler cb = new CallbackHandler() {
+                @Override
+                public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+                    for (Callback cb : callbacks) {
+                        if (cb instanceof NameCallback) {
+                            ((NameCallback) cb).setName(name);
+                        } else if (cb instanceof PasswordCallback) {
+                            ((PasswordCallback) cb).setPassword("group".toCharArray());
+                        }
+                    }
+                }
+            };
+            module.initialize(new Subject(), cb, null, options);
+            try {
+                module.login();
+                Assert.fail("The login should have failed as you cannot log in under a group name directly");
+            } catch (FailedLoginException fle) {
+                // good
+            }
+        } finally {
+            if (!f.delete()) {
+                Assert.fail("Could not delete temporary file: " + f);
+            }
+        }
+    }
+
     @Test
     public void testNullUsersFile() {
         try {
@@ -42,4 +269,5 @@ public class PropertiesLoginModuleTest {
         module.initialize(sub, handler, null, options);
         module.login();
     }
+
 }