You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shiro.apache.org by lh...@apache.org on 2011/07/22 22:34:29 UTC

svn commit: r1149728 - in /shiro/trunk/core: pom.xml src/main/java/org/apache/shiro/realm/jdbc/JdbcRealm.java src/test/java/org/apache/shiro/realm/jdbc/ src/test/java/org/apache/shiro/realm/jdbc/JDBCRealmTest.java

Author: lhazlewood
Date: Fri Jul 22 20:34:28 2011
New Revision: 1149728

URL: http://svn.apache.org/viewvc?rev=1149728&view=rev
Log:
SHIRO-277: applied patch

Added:
    shiro/trunk/core/src/test/java/org/apache/shiro/realm/jdbc/
    shiro/trunk/core/src/test/java/org/apache/shiro/realm/jdbc/JDBCRealmTest.java
Modified:
    shiro/trunk/core/pom.xml
    shiro/trunk/core/src/main/java/org/apache/shiro/realm/jdbc/JdbcRealm.java

Modified: shiro/trunk/core/pom.xml
URL: http://svn.apache.org/viewvc/shiro/trunk/core/pom.xml?rev=1149728&r1=1149727&r2=1149728&view=diff
==============================================================================
--- shiro/trunk/core/pom.xml (original)
+++ shiro/trunk/core/pom.xml Fri Jul 22 20:34:28 2011
@@ -100,6 +100,12 @@
                 </exclusion>
             </exclusions>
         </dependency>
+        <!-- JDBC Realm tests: -->
+        <dependency>
+            <groupId>hsqldb</groupId>
+            <artifactId>hsqldb</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
 </project>

Modified: shiro/trunk/core/src/main/java/org/apache/shiro/realm/jdbc/JdbcRealm.java
URL: http://svn.apache.org/viewvc/shiro/trunk/core/src/main/java/org/apache/shiro/realm/jdbc/JdbcRealm.java?rev=1149728&r1=1149727&r2=1149728&view=diff
==============================================================================
--- shiro/trunk/core/src/main/java/org/apache/shiro/realm/jdbc/JdbcRealm.java (original)
+++ shiro/trunk/core/src/main/java/org/apache/shiro/realm/jdbc/JdbcRealm.java Fri Jul 22 20:34:28 2011
@@ -25,6 +25,7 @@ import org.apache.shiro.authz.SimpleAuth
 import org.apache.shiro.config.ConfigurationException;
 import org.apache.shiro.realm.AuthorizingRealm;
 import org.apache.shiro.subject.PrincipalCollection;
+import org.apache.shiro.util.ByteSource;
 import org.apache.shiro.util.JdbcUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -35,7 +36,6 @@ import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.Set;
 
@@ -65,6 +65,11 @@ public class JdbcRealm extends Authorizi
      * The default query used to retrieve account data for the user.
      */
     protected static final String DEFAULT_AUTHENTICATION_QUERY = "select password from users where username = ?";
+    
+    /**
+     * The default query used to retrieve account data for the user when {@link #saltStyle} is COLUMN.
+     */
+    protected static final String DEFAULT_SALTED_AUTHENTICATION_QUERY = "select password, password_salt from users where username = ?";
 
     /**
      * The default query used to retrieve the roles that apply to a user.
@@ -77,6 +82,16 @@ public class JdbcRealm extends Authorizi
     protected static final String DEFAULT_PERMISSIONS_QUERY = "select permission from roles_permissions where role_name = ?";
 
     private static final Logger log = LoggerFactory.getLogger(JdbcRealm.class);
+    
+    /**
+     * Password hash salt configuration. <ul>
+     *   <li>NO_SALT - password hashes are not salted.</li>
+     *   <li>CRYTP - password hashes are stored in in the database unix crypt format.</li>
+     *   <li>COLUMN - salt is in a separate column in the database.</li> 
+     *   <li>EXTERNAL - salt is not stored in the database. {@link #getSaltForUser(String)} will be called
+     *       to get the salt</li></ul>
+     */
+    public enum SaltStyle {NO_SALT, CRYPT, COLUMN, EXTERNAL};
 
     /*--------------------------------------------
     |    I N S T A N C E   V A R I A B L E S    |
@@ -90,6 +105,8 @@ public class JdbcRealm extends Authorizi
     protected String permissionsQuery = DEFAULT_PERMISSIONS_QUERY;
 
     protected boolean permissionsLookupEnabled = false;
+    
+    protected SaltStyle saltStyle = SaltStyle.NO_SALT;
 
     /*--------------------------------------------
     |         C O N S T R U C T O R S           |
@@ -98,7 +115,7 @@ public class JdbcRealm extends Authorizi
     /*--------------------------------------------
     |  A C C E S S O R S / M O D I F I E R S    |
     ============================================*/
-
+    
     /**
      * Sets the datasource that should be used to retrieve connections used by this realm.
      *
@@ -165,6 +182,18 @@ public class JdbcRealm extends Authorizi
     public void setPermissionsLookupEnabled(boolean permissionsLookupEnabled) {
         this.permissionsLookupEnabled = permissionsLookupEnabled;
     }
+    
+    /**
+     * Sets the salt style.  See {@link #saltStyle}.
+     * 
+     * @param saltStyle new SaltStyle to set.
+     */
+    public void setSaltStyle(SaltStyle saltStyle) {
+        this.saltStyle = saltStyle;
+        if (saltStyle == SaltStyle.COLUMN && authenticationQuery.equals(DEFAULT_AUTHENTICATION_QUERY)) {
+            authenticationQuery = DEFAULT_SALTED_AUTHENTICATION_QUERY;
+        }
+    }
 
     /*--------------------------------------------
     |               M E T H O D S               |
@@ -181,17 +210,39 @@ public class JdbcRealm extends Authorizi
         }
 
         Connection conn = null;
-        AuthenticationInfo info = null;
+        SimpleAuthenticationInfo info = null;
         try {
             conn = dataSource.getConnection();
 
-            String password = getPasswordForUser(conn, username);
+            String password = null;
+            String salt = null;
+            switch (saltStyle) {
+            case NO_SALT:
+                password = getPasswordForUser(conn, username)[0];
+                break;
+            case CRYPT:
+                // TODO: separate password and hash from getPasswordForUser[0]
+                throw new ConfigurationException("Not implemented yet");
+                //break;
+            case COLUMN:
+                String[] queryResults = getPasswordForUser(conn, username);
+                password = queryResults[0];
+                salt = queryResults[1];
+                break;
+            case EXTERNAL:
+                password = getPasswordForUser(conn, username)[0];
+                salt = getSaltForUser(username);
+            }
 
             if (password == null) {
                 throw new UnknownAccountException("No account found for user [" + username + "]");
             }
 
-            info = buildAuthenticationInfo(username, password.toCharArray());
+            info = new SimpleAuthenticationInfo(username, password.toCharArray(), getName());
+            
+            if (salt != null) {
+                info.setCredentialsSalt(ByteSource.Util.bytes(salt));
+            }
 
         } catch (SQLException e) {
             final String message = "There was a SQL error while authenticating user [" + username + "]";
@@ -208,15 +259,23 @@ public class JdbcRealm extends Authorizi
         return info;
     }
 
-    protected AuthenticationInfo buildAuthenticationInfo(String username, char[] password) {
-        return new SimpleAuthenticationInfo(username, password, getName());
-    }
-
-    private String getPasswordForUser(Connection conn, String username) throws SQLException {
+    private String[] getPasswordForUser(Connection conn, String username) throws SQLException {
 
+        String[] result;
+        boolean returningSeparatedSalt = false;
+        switch (saltStyle) {
+        case NO_SALT:
+        case CRYPT:
+        case EXTERNAL:
+            result = new String[1];
+            break;
+        default:
+            result = new String[2];
+            returningSeparatedSalt = true;
+        }
+        
         PreparedStatement ps = null;
         ResultSet rs = null;
-        String password = null;
         try {
             ps = conn.prepareStatement(authenticationQuery);
             ps.setString(1, username);
@@ -233,7 +292,10 @@ public class JdbcRealm extends Authorizi
                     throw new AuthenticationException("More than one user row found for user [" + username + "]. Usernames must be unique.");
                 }
 
-                password = rs.getString(1);
+                result[0] = rs.getString(1);
+                if (returningSeparatedSalt) {
+                    result[1] = rs.getString(2);
+                }
 
                 foundResult = true;
             }
@@ -242,7 +304,7 @@ public class JdbcRealm extends Authorizi
             JdbcUtils.closeStatement(ps);
         }
 
-        return password;
+        return result;
     }
 
     /**
@@ -357,5 +419,9 @@ public class JdbcRealm extends Authorizi
 
         return permissions;
     }
+    
+    protected String getSaltForUser(String username) {
+        return username;
+    }
 
 }

Added: shiro/trunk/core/src/test/java/org/apache/shiro/realm/jdbc/JDBCRealmTest.java
URL: http://svn.apache.org/viewvc/shiro/trunk/core/src/test/java/org/apache/shiro/realm/jdbc/JDBCRealmTest.java?rev=1149728&view=auto
==============================================================================
--- shiro/trunk/core/src/test/java/org/apache/shiro/realm/jdbc/JDBCRealmTest.java (added)
+++ shiro/trunk/core/src/test/java/org/apache/shiro/realm/jdbc/JDBCRealmTest.java Fri Jul 22 20:34:28 2011
@@ -0,0 +1,373 @@
+/*
+ * 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.shiro.realm.jdbc;
+
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.IncorrectCredentialsException;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.config.Ini;
+import org.apache.shiro.config.IniSecurityManagerFactory;
+import org.apache.shiro.crypto.hash.Sha256Hash;
+import org.apache.shiro.mgt.DefaultSecurityManager;
+import org.apache.shiro.realm.AuthorizingRealm;
+import org.apache.shiro.subject.Subject;
+import org.apache.shiro.util.JdbcUtils;
+import org.apache.shiro.util.ThreadContext;
+import org.hsqldb.jdbc.jdbcDataSource;
+import org.junit.*;
+import org.junit.rules.TestName;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.HashMap;
+
+
+/**
+ * Test case for JDBCRealm.
+ */
+public class JDBCRealmTest {
+
+    protected DefaultSecurityManager securityManager = null;
+    protected AuthorizingRealm realm;
+    protected final String username = "testUser";
+    protected final String plainTextPassword = "testPassword";
+    protected final String salt = username;  //Default impl of getSaltForUser returns username
+    protected final String testRole = "testRole";
+    protected final String testPermissionString = "testDomain:testTarget:testAction";
+    
+    // Maps keyed on test method name so setup/teardown can manage per test resources
+    protected HashMap<String, JdbcRealm> realmMap = new HashMap<String, JdbcRealm>();
+    protected HashMap<String, DataSource> dsMap = new HashMap<String, DataSource>();
+
+    @Rule 
+    public TestName name = new TestName();
+
+    @Before
+    public void setup() {
+        ThreadContext.remove();
+        Ini config = new Ini();
+        config.setSectionProperty("main", "myRealm", "org.apache.shiro.realm.jdbc.JdbcRealm");
+        config.setSectionProperty("main", "myRealmCredentialsMatcher", "org.apache.shiro.authc.credential.Sha256CredentialsMatcher");
+        config.setSectionProperty("main", "myRealm.credentialsMatcher", "$myRealmCredentialsMatcher");
+        config.setSectionProperty("main", "securityManager.sessionManager.sessionValidationSchedulerEnabled", "false");
+        
+        IniSecurityManagerFactory factory = new IniSecurityManagerFactory(config);
+        securityManager = (DefaultSecurityManager) factory.createInstance();
+        SecurityUtils.setSecurityManager(securityManager);
+        
+        // Create a database and realm for the test
+        createRealm(name.getMethodName()); 
+    }
+
+    @After
+    public void tearDown() {
+        final String testName = name.getMethodName();
+        shutDown(testName);
+        SecurityUtils.setSecurityManager(null);
+        securityManager.destroy();
+        ThreadContext.remove();
+    }
+    
+    @Test
+    public void testUnSaltedSuccess() throws Exception {
+        String testMethodName = name.getMethodName();
+        JdbcRealm realm = realmMap.get(testMethodName);
+        createDefaultSchema(testMethodName, false);
+        realm.setSaltStyle(JdbcRealm.SaltStyle.NO_SALT);
+        
+        Subject.Builder builder = new Subject.Builder(securityManager);
+        Subject currentUser = builder.buildSubject();
+        UsernamePasswordToken token = new UsernamePasswordToken(username, plainTextPassword);
+        currentUser.login(token);
+        currentUser.logout();
+    }
+    
+    @Test
+    public void testUnSaltedWrongPassword() throws Exception {
+        String testMethodName = name.getMethodName();
+        JdbcRealm realm = realmMap.get(testMethodName);
+        createDefaultSchema(testMethodName, false);
+        realm.setSaltStyle(JdbcRealm.SaltStyle.NO_SALT);
+        
+        Subject.Builder builder = new Subject.Builder(securityManager);
+        Subject currentUser = builder.buildSubject();
+        UsernamePasswordToken token = new UsernamePasswordToken(username, "passwrd");
+        try {
+            currentUser.login(token);
+        } catch (IncorrectCredentialsException ex) {
+            // Expected
+        }
+    }
+    
+    @Test
+    public void testUnSaltedMultipleRows() throws Exception {
+        String testMethodName = name.getMethodName();
+        JdbcRealm realm = realmMap.get(testMethodName);
+        createDefaultSchema(testMethodName, false);
+        realm.setSaltStyle(JdbcRealm.SaltStyle.NO_SALT);
+        Connection conn = dsMap.get(testMethodName).getConnection();
+        Statement sql = conn.createStatement();
+        sql.executeUpdate("insert into users values ('" + username + "', 'dupe')");
+        
+        Subject.Builder builder = new Subject.Builder(securityManager);
+        Subject currentUser = builder.buildSubject();
+        UsernamePasswordToken token = new UsernamePasswordToken(username, "passwrd");
+        try {
+            currentUser.login(token);
+        } catch (AuthenticationException ex) {
+            // Expected
+        }
+    }
+    
+    @Test
+    public void testSaltColumnSuccess() throws Exception {
+        String testMethodName = name.getMethodName();
+        JdbcRealm realm = realmMap.get(testMethodName);
+        createSaltColumnSchema(testMethodName);
+        realm.setSaltStyle(JdbcRealm.SaltStyle.COLUMN);
+        
+        Subject.Builder builder = new Subject.Builder(securityManager);
+        Subject currentUser = builder.buildSubject();
+        UsernamePasswordToken token = new UsernamePasswordToken(username, plainTextPassword);
+        currentUser.login(token);
+        currentUser.logout();
+    }
+    
+    @Test
+    public void testSaltColumnWrongPassword() throws Exception {
+        String testMethodName = name.getMethodName();
+        JdbcRealm realm = realmMap.get(testMethodName);
+        createSaltColumnSchema(testMethodName);
+        realm.setSaltStyle(JdbcRealm.SaltStyle.COLUMN);
+        
+        Subject.Builder builder = new Subject.Builder(securityManager);
+        Subject currentUser = builder.buildSubject();
+        UsernamePasswordToken token = new UsernamePasswordToken(username, "passwrd");
+        try {
+            currentUser.login(token);
+        } catch (IncorrectCredentialsException ex) {
+            // Expected
+        }
+    }
+    
+    @Test
+    public void testExternalSuccess() throws Exception {
+        String testMethodName = name.getMethodName();
+        JdbcRealm realm = realmMap.get(testMethodName);
+        createDefaultSchema(testMethodName, true);
+        realm.setSaltStyle(JdbcRealm.SaltStyle.EXTERNAL);
+        
+        Subject.Builder builder = new Subject.Builder(securityManager);
+        Subject currentUser = builder.buildSubject();
+        UsernamePasswordToken token = new UsernamePasswordToken(username, plainTextPassword);
+        currentUser.login(token);
+        currentUser.logout();
+    }
+    
+    @Test
+    public void testExternalWrongPassword() throws Exception {
+        String testMethodName = name.getMethodName();
+        JdbcRealm realm = realmMap.get(testMethodName);
+        createDefaultSchema(testMethodName, true);
+        realm.setSaltStyle(JdbcRealm.SaltStyle.EXTERNAL);
+        
+        Subject.Builder builder = new Subject.Builder(securityManager);
+        Subject currentUser = builder.buildSubject();
+        UsernamePasswordToken token = new UsernamePasswordToken(username, "passwrd");
+        try {
+            currentUser.login(token);
+        } catch (IncorrectCredentialsException ex) {
+            // Expected
+        }
+    }
+    
+    @Test
+    public void testRolePresent() throws Exception {
+        String testMethodName = name.getMethodName();
+        JdbcRealm realm = realmMap.get(testMethodName);
+        createDefaultSchema(testMethodName, false);
+        realm.setSaltStyle(JdbcRealm.SaltStyle.NO_SALT);
+        
+        Subject.Builder builder = new Subject.Builder(securityManager);
+        Subject currentUser = builder.buildSubject();
+        UsernamePasswordToken token = new UsernamePasswordToken(username, plainTextPassword);
+        currentUser.login(token);
+        Assert.assertTrue(currentUser.hasRole(testRole));
+    }
+    
+    @Test
+    public void testRoleNotPresent() throws Exception {
+        String testMethodName = name.getMethodName();
+        JdbcRealm realm = realmMap.get(testMethodName);
+        createDefaultSchema(testMethodName, false);
+        realm.setSaltStyle(JdbcRealm.SaltStyle.NO_SALT);
+        
+        Subject.Builder builder = new Subject.Builder(securityManager);
+        Subject currentUser = builder.buildSubject();
+        UsernamePasswordToken token = new UsernamePasswordToken(username, plainTextPassword);
+        currentUser.login(token);
+        Assert.assertFalse(currentUser.hasRole("Game Overall Director"));
+    }
+    
+    @Test
+    public void testPermissionPresent() throws Exception {
+        String testMethodName = name.getMethodName();
+        JdbcRealm realm = realmMap.get(testMethodName);
+        createDefaultSchema(testMethodName, false);
+        realm.setSaltStyle(JdbcRealm.SaltStyle.NO_SALT);
+        realm.setPermissionsLookupEnabled(true);
+        
+        Subject.Builder builder = new Subject.Builder(securityManager);
+        Subject currentUser = builder.buildSubject();
+        UsernamePasswordToken token = new UsernamePasswordToken(username, plainTextPassword);
+        currentUser.login(token);
+        Assert.assertTrue(currentUser.isPermitted(testPermissionString));
+    }
+    
+    @Test
+    public void testPermissionNotPresent() throws Exception {
+        String testMethodName = name.getMethodName();
+        JdbcRealm realm = realmMap.get(testMethodName);
+        createDefaultSchema(testMethodName, false);
+        realm.setSaltStyle(JdbcRealm.SaltStyle.NO_SALT);
+        realm.setPermissionsLookupEnabled(true);
+        
+        Subject.Builder builder = new Subject.Builder(securityManager);
+        Subject currentUser = builder.buildSubject();
+        UsernamePasswordToken token = new UsernamePasswordToken(username, plainTextPassword);
+        currentUser.login(token);
+        Assert.assertFalse(currentUser.isPermitted("testDomain:testTarget:specialAction"));
+    }
+    
+    /**
+     * Creates a realm for a test method and puts it in the realMap.
+     */
+    protected void createRealm(String testMethodName) {
+        JdbcRealm realm = (JdbcRealm) securityManager.getRealms().iterator().next();
+        realmMap.put(testMethodName, realm);
+    }
+    
+    /**
+     * Shuts down the database and removes the realm from the realm map.
+     */
+    protected void shutDown(String testName) {
+        Connection conn = null;
+        Statement sql = null;
+        DataSource ds = dsMap.get(testName);
+        try {
+            Connection c = ds.getConnection();
+            Statement s = c.createStatement();
+            s.executeUpdate("SHUTDOWN");
+        } catch (SQLException ex) {
+            // ignore
+        } finally {
+            JdbcUtils.closeStatement(sql);
+            JdbcUtils.closeConnection(conn);
+            dsMap.remove(testName);
+            realmMap.remove(testName);
+        }
+    }
+    
+    /**
+     * Creates a test database with the default (no separate salt column) schema, salting with
+     * username if salted is true. Sets the DataSource of the realm associated with the test
+     * to a DataSource connected to the database.  (To prevent concurrency problems when tests
+     * are executed in multithreaded mode, each test method gets its own database.)
+     */
+    protected void createDefaultSchema(String testName, boolean salted) {
+        jdbcDataSource ds = new jdbcDataSource();
+        ds.setDatabase("jdbc:hsqldb:mem:" + name);
+        ds.setUser("SA");
+        ds.setPassword("");
+        Connection conn = null;
+        Statement sql = null;
+        try {
+            conn = ds.getConnection();
+            sql = conn.createStatement();
+            sql.executeUpdate("create table users (username varchar(20), password varchar(20))");
+            Sha256Hash sha256Hash = salted ? new Sha256Hash(plainTextPassword, salt) :
+                new Sha256Hash(plainTextPassword);
+            String password = sha256Hash.toHex();
+            sql.executeUpdate("insert into users values ('" + username + "', '" + password + "')");
+        } catch (SQLException ex) {
+            Assert.fail("Exception creating test database");
+        } finally {
+            JdbcUtils.closeStatement(sql);
+            JdbcUtils.closeConnection(conn);
+        }
+        createRolesAndPermissions(ds);
+        realmMap.get(testName).setDataSource(ds);
+        dsMap.put(testName, ds);
+    }
+    
+    /**
+     * Creates a test database with a separate salt column in the users table. Sets the
+     * DataSource of the realm associated with the test to a DataSource connected to the database.
+     */
+    protected void createSaltColumnSchema(String testName) {
+        jdbcDataSource ds = new jdbcDataSource();
+        ds.setDatabase("jdbc:hsqldb:mem:" + name);
+        ds.setUser("SA");
+        ds.setPassword("");
+        Connection conn = null;
+        Statement sql = null;
+        try {
+            conn = ds.getConnection();
+            sql = conn.createStatement();
+            sql.executeUpdate(
+                    "create table users (username varchar(20), password varchar(20), password_salt varchar(20))");
+            Sha256Hash sha256Hash = new Sha256Hash(plainTextPassword, salt);
+            String password = sha256Hash.toHex();
+            sql.executeUpdate("insert into users values ('" + username + "', '" + password + "', '" + salt + "')");
+        } catch (SQLException ex) {
+            Assert.fail("Exception creating test database");
+        } finally {
+            JdbcUtils.closeStatement(sql);
+            JdbcUtils.closeConnection(conn);
+        }
+        createRolesAndPermissions(ds);
+        realmMap.get(testName).setDataSource(ds);
+        dsMap.put(testName, ds);
+    }
+    
+    /**
+     * Creates and adds test data to user_role and roles_permissions tables.
+     */
+    protected void createRolesAndPermissions(DataSource ds) {
+        Connection conn = null;;
+        Statement sql = null;
+        try {
+            conn = ds.getConnection();
+            sql = conn.createStatement();
+            sql.executeUpdate("create table user_roles (username varchar(20), role_name varchar(20))");
+            sql.executeUpdate("insert into user_roles values ('" + username + "', '" + testRole + "')");
+            sql.executeUpdate("create table roles_permissions (role_name varchar(20), permission varchar(40))");
+            sql.executeUpdate(
+                    "insert into roles_permissions values ('" + testRole + "', '" + testPermissionString + "')");
+        } catch (SQLException ex) {
+            Assert.fail("Exception adding test role and permission");
+        } finally {
+            JdbcUtils.closeStatement(sql);
+            JdbcUtils.closeConnection(conn);
+        }
+    }
+}