You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by da...@apache.org on 2008/01/22 01:35:40 UTC
svn commit: r614071 - in /db/derby/code/trunk/java:
engine/org/apache/derby/iapi/sql/ engine/org/apache/derby/iapi/sql/conn/
engine/org/apache/derby/impl/sql/ engine/org/apache/derby/impl/sql/compile/
engine/org/apache/derby/impl/sql/conn/ engine/org/a...
Author: dag
Date: Mon Jan 21 16:35:38 2008
New Revision: 614071
URL: http://svn.apache.org/viewvc?rev=614071&view=rev
Log:
DERBY-3327 SQL roles: Implement authorization stack
Patch DERBY-3327-3 which implements the authorization stack for SQL roles.
Modified:
db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/Activation.java
db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/LanguageConnectionContext.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericActivationHolder.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericPreparedStatement.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SpecialFunctionNode.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BaseActivation.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CallStatementResultSet.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/SetRoleConstantAction.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/RolesTest.java
Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/Activation.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/Activation.java?rev=614071&r1=614070&r2=614071&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/Activation.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/Activation.java Mon Jan 21 16:35:38 2008
@@ -585,4 +585,39 @@
this with a real implementation.
*/
public int getMaxDynamicResults();
+
+ /**
+ * Set the current role name of the dynamic call context stemming
+ * from this activation (which must be a stored
+ * procedure/function) call.
+ *
+ * @arg role The name of the current role
+ */
+ public void setNestedCurrentRole(String role);
+
+ /**
+ * Get the current role name of the dynamic call context stemming
+ * from this activation (which must be a stored
+ * procedure/function) call.
+ *
+ * @return The name of the current role
+ */
+ public String getNestedCurrentRole();
+
+ /**
+ * This activation is created in a dynamic call context, remember
+ * its caller's activation.
+ *
+ * @arg a The caller's activation
+ */
+ public void setCallActivation(Activation a);
+
+ /**
+ * This activation is created in a dynamic call context, get its
+ * caller's activation.
+ *
+ * @return The caller's activation
+ */
+ public Activation getCallActivation();
+
}
Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/LanguageConnectionContext.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/LanguageConnectionContext.java?rev=614071&r1=614070&r2=614071&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/LanguageConnectionContext.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/LanguageConnectionContext.java Mon Jan 21 16:35:38 2008
@@ -424,22 +424,6 @@
public String getAuthorizationId();
/**
- * Get the current role authorization identifier
- *
- * @return String the role id
- */
- public String getCurrentRoleId();
-
-
- /**
- * Set the current role
- *
- * @param rd the descriptor of the role to be set to current
- */
- public void setCurrentRole(RoleDescriptor rd);
-
-
- /**
* Get the current default schema for the connection.
*
* @return SchemaDescriptor the current schema
@@ -1048,4 +1032,38 @@
* Close any unused activations in this connection context.
*/
public void closeUnusedActivations() throws StandardException;
+
+ /**
+ * Remember most recent (call stack top) caller's activation when
+ * invoking a method, see CallStatementResultSet#open.
+ */
+ public void pushCaller(Activation a);
+
+ /**
+ * Companion of pushCaller. See usage in CallStatementResultSet#open.
+ */
+ public void popCaller();
+
+ /**
+ * Get most recent (call stack top) caller's activation
+ */
+ public Activation getCaller();
+
+ /**
+ * Set the current role
+ *
+ * @param activation activation of set role statement
+ * @param role the id of the role to be set to current
+ */
+ public void setCurrentRole(Activation a, String role);
+
+ /**
+ * Get the current role authorization identifier of the dynamic
+ * call context associated with this activation.
+ *
+ * @param activation activation of statement needing current role
+ * @return String the role id
+ */
+ public String getCurrentRoleId(Activation a);
+
}
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericActivationHolder.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericActivationHolder.java?rev=614071&r1=614070&r2=614071&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericActivationHolder.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericActivationHolder.java Mon Jan 21 16:35:38 2008
@@ -564,6 +564,23 @@
return ac.getTargetVTI();
}
+ public void setNestedCurrentRole(String role) {
+ ac.setNestedCurrentRole(role);
+ }
+
+ public String getNestedCurrentRole() {
+ return ac.getNestedCurrentRole();
+ }
+
+ public void setCallActivation(Activation a) {
+ ac.setCallActivation(a);
+ }
+
+ public Activation getCallActivation() {
+ return ac.getCallActivation();
+ }
+
+
/* Class implementation */
@@ -667,5 +684,4 @@
public int getMaxDynamicResults() {
return ac.getMaxDynamicResults();
}
-
}
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericPreparedStatement.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericPreparedStatement.java?rev=614071&r1=614070&r2=614071&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericPreparedStatement.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/GenericPreparedStatement.java Mon Jan 21 16:35:38 2008
@@ -240,6 +240,8 @@
// deadlock.
lcc.closeUnusedActivations();
+ ac.setCallActivation(lcc.getCaller());
+
return ac;
}
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SpecialFunctionNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SpecialFunctionNode.java?rev=614071&r1=614070&r2=614071&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SpecialFunctionNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SpecialFunctionNode.java Mon Jan 21 16:35:38 2008
@@ -236,8 +236,15 @@
mb.pushThis();
mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.Activation, "getLanguageConnectionContext",
ClassName.LanguageConnectionContext, 0);
+ int argCount = 0;
- mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, methodName, methodType, 0);
+ if (methodName.equals("getCurrentRoleId")) {
+ acb.pushThisAsActivation(mb);
+ argCount++;
+ }
+
+ mb.callMethod(VMOpcode.INVOKEINTERFACE,
+ (String) null, methodName, methodType, argCount);
String fieldType = getTypeCompiler().interfaceName();
LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, fieldType);
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java?rev=614071&r1=614070&r2=614071&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java Mon Jan 21 16:35:38 2008
@@ -163,6 +163,18 @@
*/
private int queryNestingDepth;
+ /**
+ * 'callers' keeps track of which, if any, stored procedure
+ * activations are active. This helps implement the "authorization
+ * stack" of SQL 2003, vol 2, section 4.34.1.1 and 4.27.3.
+ *
+ * For the top level, the current role is kept here,
+ * cf. 'currentRole'. For dynamic call contexts, the current role
+ * is kept in the activation of the calling statement,
+ * cf. 'getCurrentRoleId'.
+ */
+ private ArrayList callers = new ArrayList(); // used as a stack only
+
protected DataValueFactory dataFactory;
protected LanguageFactory langFactory;
protected TypeCompilerFactory tcf;
@@ -185,7 +197,7 @@
protected Authorizer authorizer;
protected String userName = null; //The name the user connects with.
//May still be quoted.
- protected RoleDescriptor currentRole;
+ protected String currentRole;
protected SchemaDescriptor sd;
// RESOLVE - How do we want to set the default.
@@ -1770,27 +1782,6 @@
/**
- * Get the current role authorization identifier
- *
- * @return String the role id
- */
- public String getCurrentRoleId() {
- return currentRole != null ?
- currentRole.getRoleName() : null;
- }
-
-
- /**
- * Set the current role
- *
- * @param rd the descriptor of the role to be set to current
- */
- public void setCurrentRole(RoleDescriptor rd) {
- this.currentRole = rd;
- }
-
-
- /**
* Get the default schema
*
* @return SchemaDescriptor the default schema
@@ -3082,5 +3073,76 @@
sb.append("), ");
return sb;
+ }
+
+ /**
+ * Remember most recent (call stack top) caller's activation when
+ * invoking a method, see CallStatementResultSet#open.
+ */
+ public void pushCaller(Activation a) {
+ callers.add(a);
+ }
+
+ /**
+ * Companion of pushCaller. See usage in CallStatementResultSet#open.
+ */
+ public void popCaller() {
+ callers.remove(callers.size() - 1);
+ }
+
+
+ /**
+ * Get most recent (call stack top) caller's activation
+ * or null, if not in a call context.
+ */
+ public Activation getCaller() {
+ if (callers.isEmpty()) {
+ return null;
+ } else {
+ return (Activation)callers.get(callers.size() - 1);
+ }
+ }
+
+
+ /**
+ * Set the current role
+ *
+ * @param activation activation of set role statement
+ * @param role the id of the role to be set to current
+ */
+ public void setCurrentRole(Activation a, String role) {
+ Activation caller = a.getCallActivation();
+
+ if (caller != null ) {
+ //inside a stored procedure context
+ caller.setNestedCurrentRole(role);
+ } else {
+ // top level
+ this.currentRole = role;
+ }
+ }
+
+
+ /**
+ * Get the current role authorization identifier of the dynamic
+ * call context associated with this activation.
+ *
+ * @param activation activation of statement needing current role
+ * @return String the role id
+ */
+ public String getCurrentRoleId(Activation a) {
+ Activation caller = a.getCallActivation();
+
+ if (caller != null ) {
+ // Want current role of stored procedure context
+ // Note that it may have returned at this point, but the
+ // activation still keeps track on what the current role
+ // was when we returned.
+ return caller.getNestedCurrentRole();
+ } else {
+ // Top level current role, no stored procedure call
+ // context.
+ return currentRole;
+ }
}
}
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BaseActivation.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BaseActivation.java?rev=614071&r1=614070&r2=614071&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BaseActivation.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BaseActivation.java Mon Jan 21 16:35:38 2008
@@ -140,6 +140,34 @@
private int[] autoGeneratedKeysColumnIndexes ;
private String[] autoGeneratedKeysColumnNames ;
+ // Authorization stack frame, cf. SQL 2003 4.31.1.1 and 4.27.3 is
+ // implemented as follows: Statements at root connection level
+ // (not executed within a stored procedure), maintain the current
+ // role in the lcc. In this case, 'callActivation' is null. If
+ // we are executing SQL inside a stored procedure (nested
+ // connection), then 'callActivation' will be non-null, and we
+ // maintain the current role in the activation of the calling
+ // statement, see 'setNestedCurrentRole'. The current role of a call
+ // context is kept in the field 'nestedCurrentRole'.
+ //
+ // 'callActivation' is set when activation is created (see
+ // GenericPreparedStatement#getActivation based on the top of the
+ // dynamic call stack of activation, see
+ // GenericLanguageConnectionContext#getCaller.
+ //
+ // Corner case: When a dynamic result set references current role,
+ // the value retrieved will always be that of the current role
+ // when the statement is executed (inside), not the current value
+ // when the result set is accessed outside the stored procedure.
+ //
+ // Consequence of this implementation: If more than one nested
+ // connection is used inside a shared procedure, they will share
+ // the current role setting. Since the same dynamic call context
+ // is involved, this seems correct.
+ //
+ private Activation callActivation;
+ private String nestedCurrentRole;
+
//Following is the position of the session table names list in savedObjects in compiler context
//This is updated to be the correct value at cursor generate time if the cursor references any session table names.
//If the cursor does not reference any session table names, this will stay negative
@@ -1310,6 +1338,49 @@
row[resultSetNumber] = null;
}
}
+
+ /**
+ * Set the current role name of the dynamic call context stemming
+ * from this activation (which must be a stored
+ * procedure/function call).
+ *
+ * @arg role The name of the current role
+ */
+ public void setNestedCurrentRole(String role) {
+ nestedCurrentRole = role;
+ }
+
+ /**
+ * Get the current role name of the dynamic call context stemming
+ * from this activation (which must be a stored
+ * procedure/function call).
+ *
+ * @return The name of the current role
+ */
+ public String getNestedCurrentRole() {
+ return nestedCurrentRole;
+ }
+
+ /**
+ * This activation is created in a dynamic call context, remember
+ * its caller's activation.
+ *
+ * @arg a The caller's activation
+ */
+ public void setCallActivation(Activation a) {
+ callActivation = a;
+ }
+
+ /**
+ * This activation is created in a dynamic call context, get its
+ * caller's activation.
+ *
+ * @return The caller's activation
+ */
+ public Activation getCallActivation() {
+ return callActivation;
+ }
+
protected final DataValueDescriptor getColumnFromRow(int rsNumber, int colId)
throws StandardException {
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CallStatementResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CallStatementResultSet.java?rev=614071&r1=614070&r2=614071&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CallStatementResultSet.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CallStatementResultSet.java Mon Jan 21 16:35:38 2008
@@ -28,6 +28,7 @@
import org.apache.derby.iapi.jdbc.ConnectionContext;
import org.apache.derby.iapi.services.loader.GeneratedMethod;
import org.apache.derby.iapi.sql.Activation;
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
/**
* Call a Java procedure. This calls a generated method in the
@@ -71,9 +72,28 @@
public void open() throws StandardException
{
setup();
- methodCall.invoke(activation);
+
+ LanguageConnectionContext lcc =
+ activation.getLanguageConnectionContext();
+
+ // Push the "authorization stack" of SQL 2003, vol 2, section
+ // 4.34.1.1 and 4.27.3.
+ lcc.pushCaller(activation);
+
+ // Copy the current role into top cell of stack. Activations
+ // inside nested connections look to this activation for
+ // keeping its current role rather than rely on what's in lcc
+ // (top level only).
+ activation.setNestedCurrentRole(lcc.getCurrentRoleId(activation));
+
+ try {
+ methodCall.invoke(activation);
+ }
+ finally {
+ activation.getLanguageConnectionContext().popCaller();
+ }
}
-
+
/**
* Need to explicitly close any dynamic result sets.
* <BR>
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/SetRoleConstantAction.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/SetRoleConstantAction.java?rev=614071&r1=614070&r2=614071&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/SetRoleConstantAction.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/SetRoleConstantAction.java Mon Jan 21 16:35:38 2008
@@ -135,15 +135,19 @@
rd = dd.getRoleGrantDescriptor(thisRoleName,
currentAuthId,
dbo);
- if (rd == null &&
- (dd.getRoleGrantDescriptor
- (thisRoleName,
- Authorizer.PUBLIC_AUTHORIZATION_ID,
- dbo) == null)) {
+ if (rd == null) {
+ // or if not, via PUBLIC?
+ rd = dd.getRoleGrantDescriptor
+ (thisRoleName,
+ Authorizer.PUBLIC_AUTHORIZATION_ID,
+ dbo);
- throw StandardException.newException
- (SQLState.ROLE_INVALID_SPECIFICATION_NOT_GRANTED,
- thisRoleName);
+ // Nope, we can't set this role, so throw.
+ if (rd == null) {
+ throw StandardException.newException
+ (SQLState. ROLE_INVALID_SPECIFICATION_NOT_GRANTED,
+ thisRoleName);
+ }
}
}
} finally {
@@ -152,6 +156,6 @@
}
}
- lcc.setCurrentRole(rd);
+ lcc.setCurrentRole(activation, rd != null ? thisRoleName : null);
}
}
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/RolesTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/RolesTest.java?rev=614071&r1=614070&r2=614071&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/RolesTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/RolesTest.java Mon Jan 21 16:35:38 2008
@@ -27,6 +27,7 @@
import java.sql.Statement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
+import java.sql.DriverManager;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.apache.derbyTesting.junit.BaseJDBCTestCase;
@@ -402,9 +403,14 @@
sqlAuthorizationRequired, null , null /* through public */);
doStmt("set role 'FOO'",
sqlAuthorizationRequired, null, null);
+
+ doSetRoleInsideStoredProcedures("FOO");
+
doStmt("set role none",
sqlAuthorizationRequired, null , null);
+
doDynamicSetRole(_conn);
+
doStmt("set role bar",
sqlAuthorizationRequired, null , null /* direct grant */);
doStmt("set role role",
@@ -418,12 +424,14 @@
_conn.commit();
_conn.setAutoCommit(true);
+
+
/*
* CURRENT_ROLE
*/
ResultSet rs = doQuery("values current_role",
sqlAuthorizationRequired, null , null);
- assertCurrentRole(rs, "ROLE", "BAR");
+ assertRoleInRs(rs, "ROLE", "BAR");
/*
* REVOKE role
@@ -477,7 +485,7 @@
doStmt("create function f1() returns int" +
" language java parameter style java" +
" external name 'org.apache.derbyTesting." +
- "functionTests.tests.lang.RolesTest.t1'" +
+ "functionTests.tests.lang.RolesTest.f1'" +
" no sql called on null input",
null, null, null);
doStmt("grant execute on function f1 to admin",
@@ -758,7 +766,7 @@
int rowcnt = pstmt.executeUpdate();
assertEquals(rowcnt, 0, "rowcount from set role ? not 0");
ResultSet rs = doQuery("values current_role", n_a, null , n_a );
- assertCurrentRole(rs, "NONE", n_a);
+ assertRoleInRs(rs, "NONE", n_a);
rs.close();
} catch (SQLException e) {
fail("execute of set role ? failed: [NONE] " + e);
@@ -774,6 +782,60 @@
}
+ /* Test that current role is handled correctly when inside a
+ * stored procedure. The SQL standard requires we have an
+ * "authorization stack", see section 4.34.1.1. This implies that
+ * current role is popped at end of stored procedure.
+ * We test two levels deep.
+ */
+ private void doSetRoleInsideStoredProcedures(String currRole)
+ throws SQLException
+ {
+ if (_authLevel != NO_SQLAUTHORIZATION) {
+ String n_a = null; // auth level not used for this test
+
+ doStmt("create procedure p2(role varchar(255))" +
+ " dynamic result sets 1 language java parameter style java"+
+ " external name 'org.apache.derbyTesting." +
+ "functionTests.tests.lang.RolesTest.p2'" +
+ " modifies sql data",
+ n_a, null, null);
+ doStmt("create function f2(role varchar(255))" +
+ " returns int language java parameter style java" +
+ " external name 'org.apache.derbyTesting." +
+ "functionTests.tests.lang.RolesTest.f2'" +
+ " reads sql data",
+ n_a, null, null);
+ doStmt("call p2('" + currRole + "')",
+ n_a , null , null );
+
+ // Dynamic result set: At what time should CURRENT_ROLE be
+ // evaluated? Logically at the inside, so it should be
+ // "BAR" also when accessed on outside. I think. Anyway,
+ // that's what's implemented: the activation of the call
+ // is still live and holds the current role as it was
+ // inside the nested scope even when the procedure call
+ // has returned.
+ ResultSet prs = _stm.getResultSet();
+ assertRoleInRs(prs, "BAR", "BAR");
+ prs.close();
+
+ // check that role didn't get impacted by change inside p2
+ // too 'BAR':
+ ResultSet rs = doQuery("values current_role",
+ n_a , null , null );
+ assertRoleInRs(rs, currRole, currRole);
+ rs.close();
+
+ rs = doQuery("values f2('" + currRole + "')",
+ n_a , null , null );
+ rs.close();
+
+ doStmt("drop procedure p2", n_a, null, null);
+ doStmt("drop function f2", n_a, null, null);
+ }
+ }
+
private void assertSystableRowCount(String table,
int rcNoAuth,
int rcDbo,
@@ -934,9 +996,9 @@
}
- private void assertCurrentRole(ResultSet rs,
- String dboRole,
- String notDboRole)
+ private void assertRoleInRs(ResultSet rs,
+ String dboRole,
+ String notDboRole)
throws SQLException
{
@@ -944,16 +1006,18 @@
assertNull(rs);
} else {
assertTrue("result set empty", rs.next());
+ String actualRole = rs.getString(1);
if (isDbo()) {
- assertTrue(dboRole.equals(rs.getString(1)));
+ assertTrue("role is " + actualRole + ", expected " + dboRole,
+ dboRole.equals(actualRole));
} else {
- assertTrue(notDboRole.equals(rs.getString(1)));
+ assertTrue("role is " + actualRole + ", expected " + notDboRole,
+ notDboRole.equals(actualRole));
}
// cardinality should be 1
assertFalse("result set not empty", rs.next());
- rs.close();
}
}
@@ -964,6 +1028,22 @@
}
}
+ private static void assertRsSingleStringValue(ResultSet rs,
+ String expectedValue)
+ throws SQLException
+ {
+
+ assertTrue("result set empty", rs.next());
+ String actualValue = rs.getString(1);
+
+ assertTrue("string is " + actualValue + ", expected " + expectedValue,
+ actualValue.equals(expectedValue));
+
+ // cardinality should be 1
+ assertFalse("result set not empty", rs.next());
+ }
+
+
/**
* Utility function used to test auto-drop of grant routine
* permission to a role
@@ -971,6 +1051,160 @@
*/
public static int f1()
{
+ return 1;
+ }
+
+
+ /**
+ * Utility procedure used to test that current role
+ * is stacked correctly according to dynamic scope.
+ */
+ public static void p2(String roleOutside, ResultSet[] rs1)
+ throws SQLException
+ {
+ Connection conn1 = null;
+ Connection conn2 = null;
+
+ try {
+ conn1 = DriverManager.getConnection("jdbc:default:connection");
+ PreparedStatement ps =
+ conn1.prepareStatement("values current_role");
+
+ // check that we inherit role correctly
+ ResultSet rs = ps.executeQuery();
+ assertRsSingleStringValue(rs, roleOutside);
+ rs.close();
+
+ // set the role to something else
+ Statement stm = conn1.createStatement();
+ stm.execute("set role bar");
+ rs = ps.executeQuery();
+
+ // check that role got set
+ assertRsSingleStringValue(rs, "BAR");
+
+ // another nesting level to test authorization stack even more
+ stm.execute(
+ "create procedure calledNestedFromP2(role varchar(255))" +
+ " language java parameter style java" +
+ " external name 'org.apache.derbyTesting." +
+ "functionTests.tests.lang.RolesTest.calledNestedFromP2'" +
+ " modifies sql data");
+ conn1.commit(); // need to be idle
+ stm.execute("call calledNestedFromP2('BAR')");
+
+ rs = ps.executeQuery();
+
+ // check that role didn't get impacted by change inside
+ // calledNestedFromP2 too 'FOO':
+ assertRsSingleStringValue(rs, "BAR");
+ stm.execute("drop procedure calledNestedFromP2");
+
+ // Test that the role is shared by another nested
+ // connection also.
+ conn2 = DriverManager.getConnection("jdbc:default:connection");
+ PreparedStatement ps2 =
+ conn2.prepareStatement("values current_role");
+ ResultSet rs2 = ps2.executeQuery();
+ assertRsSingleStringValue(rs2, "BAR");
+
+ // Pass out CURRENT_ROLE in a dynamic result set.
+ rs = ps.executeQuery();
+ rs1[0] = rs;
+
+ } finally {
+
+ if (conn1 != null) {
+ try {
+ conn1.close();
+ } catch (Exception e) {
+ }
+ }
+
+ if (conn2 != null) {
+ try {
+ conn2.close();
+ } catch (Exception e) {
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Called from p2 so we get to test with a call stack 3 levels
+ * deep.
+ */
+ public static void calledNestedFromP2(String roleOutside)
+ throws SQLException
+ {
+ Connection conn1 = null;
+
+ try {
+ conn1 = DriverManager.getConnection("jdbc:default:connection");
+ PreparedStatement ps =
+ conn1.prepareStatement("values current_role");
+
+ // check that we inherit role correctly
+ ResultSet rs = ps.executeQuery();
+ assertRsSingleStringValue(rs, roleOutside);
+ rs.close();
+
+ // set the role to something else
+ Statement stm = conn1.createStatement();
+ stm.execute("set role foo");
+ rs = ps.executeQuery();
+
+ // check that role got set
+ assertRsSingleStringValue(rs, "FOO");
+
+ } finally {
+ if (conn1 != null) {
+ try {
+ conn1.close();
+ } catch (Exception e) {
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Utility function used to test that current role
+ * is stacked correctly according to scope.
+ */
+ public static int f2(String roleOutside) throws SQLException
+ {
+ Connection conn1 = null;
+
+ try {
+ conn1 = DriverManager.getConnection("jdbc:default:connection");
+ PreparedStatement ps =
+ conn1.prepareStatement("values current_role");
+
+ // check that we inherit role correctly
+ ResultSet rs = ps.executeQuery();
+ assertRsSingleStringValue(rs, roleOutside);
+ rs.close();
+
+ // set the role to something else
+ Statement stm = conn1.createStatement();
+ stm.execute("set role bar");
+ rs = ps.executeQuery();
+
+ // check that role got set
+ assertRsSingleStringValue(rs, "BAR");
+
+ } finally {
+
+ if (conn1 != null) {
+ try {
+ conn1.close();
+ } catch (Exception e) {
+ }
+ }
+
+ }
return 1;
}
}