Hi all.

I'd like to propose a change to JDBCRealm to allow a little more flexibility
in the layout of one's users and roles tables.  The current implementation
(1.20) assumes the roles table will have a column with the same name and
meaning as the username column in the users table.  In general, I like to
avoid using a column with domain meaning as a primary or foreign key.  In
particular, doing so makes it difficult to allow a user to change his or her
username because that change would then ripple through the db to any other
place that uses username as a key, such as the roles table.  Instead, my
change requires the specification of two additional attributes in
server.xml's Realm element when using a JDBCRealm, userPrimaryKeyCol and
userForeignKeyCol, but frees one from having to track and propagate username
changes.  userPrimaryKeyCol is whatever column contains the unique (at least
within the user table) identifier of a user; userForeignKeyCol is the column
in the roles table that joins to that column.  Applications built on the
existing implementation of JDBCRealm can continue without a database
reorganization.  They simply have to specify userPrimaryKeyCol and
userForeignKeyCol as having the same value as userNameCol.

I tested my changes using Tomcat 4.0.1 and PostgreSQL 7.1.x.  I first
changed my server.xml to explicitly state that the username column was to be
used to join the users and roles tables.  Things worked as expected.  Then I
changed the layout of my db to use different join columns.  Again, things
worked as expected.  Though Tomcat 4.0.1 comes with JDBCRealm 1.19, I didn't
have any trouble compiling and running my changes based on 1.20.  It appears
the only difference between 1.19 and 1.20 is the addition of accessors in
the newer version.

I generated the patchfile with "diff -u <version 1.20> <my version based on
1.20>."


thanks

john gregg
TechArch Consulting Group
Minneapolis, MN


--- JDBCRealm.java.orig Mon Mar  4 17:26:27 2002
+++ JDBCRealm.java      Mon Mar  4 16:25:22 2002
@@ -179,6 +179,18 @@
 
 
     /**
+     * The column in userRoleTable that joins it to userTable.
+     */
+    protected String userForeignKeyCol = null;
+
+
+    /**
+     * The column in userTable that joins it to userRoleTable.
+     */
+    protected String userPrimaryKeyCol = null;
+
+
+    /**
      * The string manager for this package.
      */
     protected static final StringManager sm =
@@ -297,6 +309,40 @@
     }
 
     /**
+     * Returns the column in the user table that joins to the user role table.
+     *
+     */
+    public String getUserPrimaryKeyCol() {
+        return userPrimaryKeyCol;
+    }
+
+    /**
+     * Sets the column in the user table that joins to the user role table.
+     *
+     * @param userPrimaryKeyCol The column name
+     */
+    public void setUserPrimaryKeyCol( String userPrimaryKeyCol ) {
+        this.userPrimaryKeyCol = userPrimaryKeyCol;
+    }
+
+    /**
+     * Returns the column in the user role table that joins to the user table.
+     *
+     */
+    public String getUserForeignKeyCol() {
+        return userForeignKeyCol;
+    }
+
+    /**
+     * Sets the column in the user role table that joins to the user table.
+     *
+     * @param userForeignKeyCol The column name
+     */
+    public void setUserForeignKeyCol( String userForeignKeyCol ) {
+        this.userForeignKeyCol = userForeignKeyCol;
+    }
+
+    /**
      * Return the column in the user table that holds the user's credentials.
      *
      */
@@ -441,10 +487,12 @@
 
         // Look up the user's credentials
         String dbCredentials = null;
+        String userPrimaryKey = null;
         PreparedStatement stmt = credentials(dbConnection, username);
         ResultSet rs = stmt.executeQuery();
         while (rs.next()) {
             dbCredentials = rs.getString(1).trim();
+            userPrimaryKey = rs.getString(2).trim();
         }
         rs.close();
         if (dbCredentials == null) {
@@ -472,7 +520,7 @@
 
         // Accumulate the user's roles
         ArrayList list = new ArrayList();
-        stmt = roles(dbConnection, username);
+        stmt = roles(dbConnection, userPrimaryKey);
         rs = stmt.executeQuery();
         while (rs.next()) {
             list.add(rs.getString(1).trim());
@@ -540,6 +588,8 @@
         if (preparedCredentials == null) {
             StringBuffer sb = new StringBuffer("SELECT ");
             sb.append(userCredCol);
+            sb.append(", ");
+            sb.append(userPrimaryKeyCol);
             sb.append(" FROM ");
             sb.append(userTable);
             sb.append(" WHERE ");
@@ -634,14 +684,14 @@
 
     /**
      * Return a PreparedStatement configured to perform the SELECT required
-     * to retrieve user roles for the specified username.
+     * to retrieve user roles for the specified user primary key.
      *
      * @param dbConnection The database connection to be used
-     * @param username Username for which roles should be retrieved
+     * @param userPrimaryKey Primary key of user for whom roles should be retrieved
      *
      * @exception SQLException if a database error occurs
      */
-    protected PreparedStatement roles(Connection dbConnection, String username)
+    protected PreparedStatement roles(Connection dbConnection, String userPrimaryKey)
         throws SQLException {
 
         if (preparedRoles == null) {
@@ -649,14 +699,27 @@
             sb.append(roleNameCol);
             sb.append(" FROM ");
             sb.append(userRoleTable);
+            sb.append(", ");
+            sb.append(userTable);
             sb.append(" WHERE ");
-            sb.append(userNameCol);
+            sb.append(userRoleTable);
+            sb.append(".");
+            sb.append(userForeignKeyCol);
+            sb.append(" = ");
+            sb.append(userTable);
+            sb.append(".");
+            sb.append(userPrimaryKeyCol);
+            sb.append(" AND ");
+            sb.append(userRoleTable);
+            sb.append(".");
+            sb.append(userForeignKeyCol);
             sb.append(" = ?");
+
             preparedRoles =
                 dbConnection.prepareStatement(sb.toString());
         }
 
-        preparedRoles.setString(1, username);
+        preparedRoles.setString(1, userPrimaryKey);
         return (preparedRoles);
 
     }

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to