From 6de1708def257130eca7f9e29ee41be8a28562ef Mon Sep 17 00:00:00 2001 From: =?utf8?q?Felix=20D=C3=B6rre?= Date: Thu, 11 Sep 2014 22:31:48 +0200 Subject: [PATCH] ADD: user group management (with testcase) --- src/org/cacert/gigi/dbObjects/Group.java | 57 ++++++++++ src/org/cacert/gigi/dbObjects/User.java | 46 ++++++++ .../cacert/gigi/TestUserGroupMembership.java | 102 ++++++++++++++++++ 3 files changed, 205 insertions(+) create mode 100644 src/org/cacert/gigi/dbObjects/Group.java create mode 100644 tests/org/cacert/gigi/TestUserGroupMembership.java diff --git a/src/org/cacert/gigi/dbObjects/Group.java b/src/org/cacert/gigi/dbObjects/Group.java new file mode 100644 index 00000000..bdce278d --- /dev/null +++ b/src/org/cacert/gigi/dbObjects/Group.java @@ -0,0 +1,57 @@ +package org.cacert.gigi.dbObjects; + +import java.util.HashMap; + +public class Group { + + private static HashMap cache = new HashMap<>(); + + private final String dbName; + + private Group(String name) { + dbName = name; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((dbName == null) ? 0 : dbName.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Group other = (Group) obj; + if (dbName == null) { + if (other.dbName != null) { + return false; + } + } else if ( !dbName.equals(other.dbName)) { + return false; + } + return true; + } + + public static synchronized Group getByString(String name) { + Group g = cache.get(name); + if (g == null) { + g = new Group(name); + cache.put(name, g); + } + return g; + } + + public String getDatabaseName() { + return dbName; + } +} diff --git a/src/org/cacert/gigi/dbObjects/User.java b/src/org/cacert/gigi/dbObjects/User.java index bc927fa9..c07db48c 100644 --- a/src/org/cacert/gigi/dbObjects/User.java +++ b/src/org/cacert/gigi/dbObjects/User.java @@ -5,7 +5,10 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Calendar; +import java.util.Collections; +import java.util.HashSet; import java.util.Locale; +import java.util.Set; import org.cacert.gigi.GigiApiException; import org.cacert.gigi.database.DatabaseConnection; @@ -28,6 +31,8 @@ public class User implements IdCachable { private Locale locale; + private Set groups = new HashSet<>(); + private User(int id) { this.id = id; updateName(id); @@ -50,6 +55,13 @@ public class User implements IdCachable { } } rs.close(); + PreparedStatement psg = DatabaseConnection.getInstance().prepare("SELECT permission FROM user_groups WHERE user=? AND deleted is NULL"); + psg.setInt(1, id); + ResultSet rs2 = psg.executeQuery(); + while (rs2.next()) { + groups.add(Group.getByString(rs2.getString(1))); + } + rs2.close(); } catch (SQLException e) { e.printStackTrace(); } @@ -504,6 +516,40 @@ public class User implements IdCachable { update.executeUpdate(); } + public boolean isInGroup(Group g) { + return groups.contains(g); + } + + public Set getGroups() { + return Collections.unmodifiableSet(groups); + } + + public void grantGroup(User granter, Group toGrant) throws GigiApiException { + groups.add(toGrant); + try { + PreparedStatement ps = DatabaseConnection.getInstance().prepare("INSERT INTO user_groups SET user=?, permission=?, grantedby=?"); + ps.setInt(1, getId()); + ps.setString(2, toGrant.getDatabaseName()); + ps.setInt(3, granter.getId()); + ps.execute(); + } catch (SQLException e) { + throw new GigiApiException(e); + } + } + + public void revokeGroup(User revoker, Group toRevoke) throws GigiApiException { + groups.remove(toRevoke); + try { + PreparedStatement ps = DatabaseConnection.getInstance().prepare("UPDATE user_groups SET deleted=CURRENT_TIMESTAMP, revokedby=? WHERE deleted is NULL AND permission=? AND user=?"); + ps.setInt(1, revoker.getId()); + ps.setString(2, toRevoke.getDatabaseName()); + ps.setInt(3, getId()); + ps.execute(); + } catch (SQLException e) { + throw new GigiApiException(e); + } + } + private static ObjectCache myCache = new ObjectCache<>(); public static synchronized User getById(int id) { diff --git a/tests/org/cacert/gigi/TestUserGroupMembership.java b/tests/org/cacert/gigi/TestUserGroupMembership.java new file mode 100644 index 00000000..fa670721 --- /dev/null +++ b/tests/org/cacert/gigi/TestUserGroupMembership.java @@ -0,0 +1,102 @@ +package org.cacert.gigi; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; + +import org.cacert.gigi.database.DatabaseConnection; +import org.cacert.gigi.dbObjects.Group; +import org.cacert.gigi.dbObjects.ObjectCache; +import org.cacert.gigi.dbObjects.User; +import org.cacert.gigi.testUtils.ManagedTest; +import org.junit.Test; + +public class TestUserGroupMembership extends ManagedTest { + + private final Group ttpGroup = Group.getByString("ttp-assuer"); + + private final Group supporter = Group.getByString("supporter"); + + @Test + public void testAddObject() throws GigiApiException, SQLException { + User u = User.getById(createVerifiedUser("fname", "lname", createUniqueName() + "@example.org", TEST_PASSWORD)); + + User granter = User.getById(createVerifiedUser("grFname", "lname", createUniqueName() + "@example.org", TEST_PASSWORD)); + assertBehavesEmpty(u); + + u.grantGroup(granter, ttpGroup); + assertBehavesTtpGroup(u); + + ObjectCache.clearAllCaches(); + User u2 = User.getById(u.getId()); + + assertThat(u2, is(not(sameInstance(u)))); + assertBehavesTtpGroup(u2); + + ResultSet rs = fetchGroupRowsFor(u); + + assertTrue(rs.next()); + assertEquals(0, rs.getInt("revokedby")); + assertEquals(granter.getId(), rs.getInt("grantedby")); + assertEquals(ttpGroup.getDatabaseName(), rs.getString("permission")); + + assertNull(rs.getDate("deleted")); + assertNotNull(rs.getDate("granted")); + + assertFalse(rs.next()); + } + + @Test + public void testRemoveObject() throws GigiApiException, SQLException { + User u = User.getById(createVerifiedUser("fname", "lname", createUniqueName() + "@example.org", TEST_PASSWORD)); + + User granter = User.getById(createVerifiedUser("grFname", "lname", createUniqueName() + "@example.org", TEST_PASSWORD)); + + assertBehavesEmpty(u); + u.grantGroup(granter, ttpGroup); + assertBehavesTtpGroup(u); + u.revokeGroup(granter, ttpGroup); + assertBehavesEmpty(u); + + ObjectCache.clearAllCaches(); + User u2 = User.getById(u.getId()); + assertThat(u2, is(not(sameInstance(u)))); + assertBehavesEmpty(u); + + ResultSet rs = fetchGroupRowsFor(u); + assertTrue(rs.next()); + assertEquals(granter.getId(), rs.getInt("revokedby")); + assertEquals(granter.getId(), rs.getInt("grantedby")); + assertEquals(ttpGroup.getDatabaseName(), rs.getString("permission")); + + assertNotNull(rs.getDate("deleted")); + assertNotNull(rs.getDate("granted")); + + assertFalse(rs.next()); + } + + private ResultSet fetchGroupRowsFor(User u) throws SQLException { + PreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT * FROM user_groups WHERE user=?"); + ps.setInt(1, u.getId()); + ResultSet rs = ps.executeQuery(); + return rs; + } + + private void assertBehavesEmpty(User u) { + assertEquals(Collections.emptySet(), u.getGroups()); + assertFalse(u.isInGroup(ttpGroup)); + assertFalse(u.isInGroup(supporter)); + } + + private void assertBehavesTtpGroup(User u) { + assertEquals(new HashSet<>(Arrays.asList(ttpGroup)), u.getGroups()); + assertTrue(u.isInGroup(ttpGroup)); + assertFalse(u.isInGroup(supporter)); + } +} -- 2.39.2