db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From d..@apache.org
Subject svn commit: r688900 [1/2] - in /db/derby/code/trunk/java: engine/org/apache/derby/iapi/sql/dictionary/ engine/org/apache/derby/impl/sql/execute/ testing/org/apache/derbyTesting/functionTests/tests/lang/
Date Mon, 25 Aug 2008 22:11:35 GMT
Author: dag
Date: Mon Aug 25 15:11:35 2008
New Revision: 688900

URL: http://svn.apache.org/viewvc?rev=688900&view=rev
Log:
DERBY-3223 SQL roles: make use of privileges granted to roles in actual privilege checking

Patch derby-3223-revocation-logic-5, which adds revocation logic for roles.

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/ConstraintDescriptor.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/StatementColumnPermission.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/StatementRoutinePermission.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/StatementTablePermission.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/TriggerDescriptor.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/ViewDescriptor.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DDLConstantAction.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DropRoleConstantAction.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/RevokeRoleConstantAction.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/RolesConferredPrivilegesTest.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/ConstraintDescriptor.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/ConstraintDescriptor.java?rev=688900&r1=688899&r2=688900&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/ConstraintDescriptor.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/ConstraintDescriptor.java
Mon Aug 25 15:11:35 2008
@@ -556,7 +556,9 @@
 			//types SELECT, UPDATE, DELETE, INSERT, REFERENCES, TRIGGER), we  
 			//don't do anything here. Later in makeInvalid method, we make  
 			//the ConstraintDescriptor drop itself. 
+			//Ditto for role grant conferring a privilege.
 		    case DependencyManager.REVOKE_PRIVILEGE:
+		    case DependencyManager.REVOKE_ROLE:
 		    case DependencyManager.INTERNAL_RECOMPILE_REQUEST:
 				break;
 
@@ -600,14 +602,22 @@
 		*  REVOKE_PRIVILEGE are the only valid actions
 		*/
 
-		//Let's handle REVOKE_PRIVILEGE first
-		if (action == DependencyManager.REVOKE_PRIVILEGE) 
+		//Let's handle REVOKE_PRIVILEGE and REVOKE_ROLE first
+		if (action == DependencyManager.REVOKE_PRIVILEGE ||
+			action == DependencyManager.REVOKE_ROLE)
 		{
 			//At this point (Derby 10.2), only a FOREIGN KEY key constraint can
 			//depend on a privilege. None of the other constraint types 
 			//can be dependent on a privilege becuse those constraint types
 			//can not reference a table/routine.
 			ConglomerateDescriptor newBackingConglomCD = drop(lcc, true);
+
+			lcc.getLastActivation().addWarning(
+				StandardException.newWarning(
+					SQLState.LANG_CONSTRAINT_DROPPED,
+					getConstraintName(),
+					getTableDescriptor().getName()));
+
 			if (newBackingConglomCD != null)
 			{
 				/* Since foreign keys can never be unique, and since

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/StatementColumnPermission.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/StatementColumnPermission.java?rev=688900&r1=688899&r2=688900&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/StatementColumnPermission.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/StatementColumnPermission.java
Mon Aug 25 15:11:35 2008
@@ -28,6 +28,7 @@
 import org.apache.derby.iapi.services.io.FormatableBitSet;
 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
 import org.apache.derby.iapi.sql.Activation;
+import org.apache.derby.iapi.sql.execute.ExecPreparedStatement;
 
 /**
  * This class describes a column permission used (required) by a statement.
@@ -92,9 +93,10 @@
 		throws StandardException
 	{
 		DataDictionary dd = lcc.getDataDictionary();
+		ExecPreparedStatement ps = activation.getPreparedStatement();
 
 		if (hasPermissionOnTable(lcc, activation,
-									 authorizationId, forGrant)) {
+									 authorizationId, forGrant, ps)) {
 			return;
 		}
 
@@ -121,11 +123,11 @@
 
 		FormatableBitSet unresolvedColumns = (FormatableBitSet)columns.clone();
 
-		for( int i = unresolvedColumns.anySetBit();
+		for (int i = unresolvedColumns.anySetBit();
 			 i >= 0;
 			 i = unresolvedColumns.anySetBit(i)) {
 
-			if( permittedColumns != null && permittedColumns.get(i)) {
+			if (permittedColumns != null && permittedColumns.get(i)) {
 				// column i (zero-based here) accounted for:
 				unresolvedColumns.clear(i);
 			}
@@ -205,7 +207,24 @@
 					td.getSchemaName(),
 					td.getName());
 			}
+		} else {
+			// We found and successfully applied a role to resolve the
+			// remaining required permissions.
+			//
+			// So add a dependency on the role (qua provider), so that
+			// if role is no longer available to the current user
+			// (e.g. grant to user is revoked, role is dropped,
+			// another role has been set), or it is impacted by
+			// revoked permissions or other roles granted to it, we
+			// are able to invalidate the the ps.
+			//
+			// FIXME: Rather invalidate Activation so other
+			// sessions sharing the same ps are not impacted!!
+			dd.getDependencyManager().
+				addDependency(ps, dd.getRoleDefinitionDescriptor(role),
+							  lcc.getContextManager());
 		}
+
 	} // end of check
 
 	/**
@@ -297,6 +316,65 @@
 	}
 
 	/**
+	 * Returns false if the current role is necessary to cover
+	 * the necessary permission(s).
+	 * @param authid authentication id of the current user
+	 * @param dd data dictionary
+	 *
+	 * @return false if the current role is required
+	 */
+	public boolean allColumnsCoveredByUserOrPUBLIC(String authid,
+												   DataDictionary dd)
+			throws StandardException {
+
+		ColPermsDescriptor colsPermsDesc =
+			dd.getColumnPermissions(tableUUID, privType, false, authid);
+		FormatableBitSet permittedColumns = colsPermsDesc.getColumns();
+		FormatableBitSet unresolvedColumns = (FormatableBitSet)columns.clone();
+		boolean result = true;
+
+		if (permittedColumns != null) { // else none at user level
+			for(int i = unresolvedColumns.anySetBit();
+				i >= 0;
+				i = unresolvedColumns.anySetBit(i)) {
+
+				if(permittedColumns.get(i)) {
+					unresolvedColumns.clear(i);
+				}
+			}
+		}
+
+
+		if (unresolvedColumns.anySetBit() >= 0) {
+			colsPermsDesc =
+				dd.getColumnPermissions(
+					tableUUID, privType, false,
+					Authorizer.PUBLIC_AUTHORIZATION_ID);
+			permittedColumns = colsPermsDesc.getColumns();
+
+			if (permittedColumns != null) { // else none at public level
+				for(int i = unresolvedColumns.anySetBit();
+					i >= 0;
+					i = unresolvedColumns.anySetBit(i)) {
+
+					if(permittedColumns.get(i)) {
+						unresolvedColumns.clear(i);
+					}
+				}
+			}
+
+			if (unresolvedColumns.anySetBit() >= 0) {
+				// even after trying all grants to user and public there
+				// are unresolved columns so role must have been used.
+				result = false;
+			}
+		}
+
+		return result;
+	}
+
+
+	/**
 	 * Given the set of yet unresolved column permissions, try to use
 	 * the supplied role r to resolve them. After this is done, return
 	 * the set of columns still unresolved. If the role is used for

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/StatementRoutinePermission.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/StatementRoutinePermission.java?rev=688900&r1=688899&r2=688900&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/StatementRoutinePermission.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/StatementRoutinePermission.java
Mon Aug 25 15:11:35 2008
@@ -29,6 +29,7 @@
 import org.apache.derby.iapi.sql.dictionary.RoutinePermsDescriptor;
 import org.apache.derby.iapi.store.access.TransactionController;
 import org.apache.derby.iapi.sql.Activation;
+import org.apache.derby.iapi.sql.execute.ExecPreparedStatement;
 
 /**
  * This class describes a routine execute permission
@@ -64,6 +65,7 @@
 	{
 		DataDictionary dd = lcc.getDataDictionary();
 		TransactionController tc = lcc.getTransactionExecute();
+		ExecPreparedStatement ps = activation.getPreparedStatement();
 		
 		RoutinePermsDescriptor perms = dd.getRoutinePermissions( routineUUID, authorizationId);
 		if( perms == null || ! perms.getHasExecutePermission())
@@ -76,7 +78,7 @@
 
 		boolean resolved = false;
 
-		// Since permission does not exists for the current user or PUBLIC,
+		// Since no permission exists for the current user or PUBLIC,
 		// check if a permission exists for the current role (if set).
 		String role = lcc.getCurrentRoleId(activation);
 
@@ -84,7 +86,7 @@
 
 			// Check that role is still granted to current user or
 			// to PUBLIC: A revoked role which is current for this
-			// session, is lazily set to none when it is attempted
+			// session, is lazily set to none when it is attemped
 			// used.
 			String dbo = dd.getAuthorizationDatabaseOwner();
 			RoleGrantDescriptor rd = dd.getRoleGrantDescriptor
@@ -127,6 +129,20 @@
 					}
 				}
 			}
+
+			if (resolved /* using a role*/) {
+				// Also add a dependency on the role (qua provider),
+				// so that if role is no longer available to the
+				// current user (e.g. grant is revoked, role is
+				// dropped, another role has been set), we are able to
+				// invalidate the the ps.
+				//
+				// FIXME: Rather invalidate Activation so other
+				// sessions sharing the same ps are not impacted!!
+				dd.getDependencyManager().
+					addDependency(ps, dd.getRoleDefinitionDescriptor(role),
+								  lcc.getContextManager());
+			}
 		}
 
 		if (!resolved) {

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/StatementTablePermission.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/StatementTablePermission.java?rev=688900&r1=688899&r2=688900&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/StatementTablePermission.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/StatementTablePermission.java
Mon Aug 25 15:11:35 2008
@@ -27,6 +27,7 @@
 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
 import org.apache.derby.iapi.reference.SQLState;
 import org.apache.derby.iapi.sql.Activation;
+import org.apache.derby.iapi.sql.execute.ExecPreparedStatement;
 
 /**
  * This class describes a table permission required by a statement.
@@ -113,9 +114,10 @@
 		throws StandardException
 	{
 		DataDictionary dd = lcc.getDataDictionary();
+		ExecPreparedStatement ps = activation.getPreparedStatement();
 
 		if (!hasPermissionOnTable(lcc, activation,
-									  authorizationId, forGrant)) {
+									  authorizationId, forGrant, ps)) {
 			TableDescriptor td = getTableDescriptor( dd);
 			throw StandardException.newException( forGrant ? SQLState.AUTH_NO_TABLE_PERMISSION_FOR_GRANT
 												  : SQLState.AUTH_NO_TABLE_PERMISSION,
@@ -134,14 +136,23 @@
 		return td;
 	} // end of getTableDescriptor
 
-	/*
+	/**
 	 * Check if current session has permission on the table (current user,
-	 * PUBLIC or role).
+	 * PUBLIC or role) and, if applicable, register a dependency of ps on the
+	 * current role.
+	 *
+	 * @param lcc the current language connection context
+	 * @param activation the activation of ps
+	 * @param authorizationId the id of the current user
+	 * @param forGrant true if FOR GRANT is required
+	 * @param ps the prepared statement for which we are checking necessary
+	 *        privileges
 	 */
 	protected boolean hasPermissionOnTable(LanguageConnectionContext lcc,
 										   Activation activation,
 										   String authorizationId,
-										   boolean forGrant)
+										   boolean forGrant,
+										   ExecPreparedStatement ps)
 		throws StandardException
 	{
 		DataDictionary dd = lcc.getDataDictionary();
@@ -200,6 +211,21 @@
 						result = oneAuthHasPermissionOnTable
 							(dd, r, forGrant);
 					}
+
+					if (result) {
+						// Also add a dependency on the role (qua provider),
+						// so that if role is no longer available to the
+						// current user (e.g. grant is revoked, role is
+						// dropped, another role has been set), we are able to
+						// invalidate the the ps.
+						//
+						// FIXME: Rather invalidate Activation so other
+						// sessions sharing the same ps are not impacted!!
+						dd.getDependencyManager().
+							addDependency(ps,
+										  dd.getRoleDefinitionDescriptor(role),
+										  lcc.getContextManager());
+					}
 				}
 			}
 		}

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/TriggerDescriptor.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/TriggerDescriptor.java?rev=688900&r1=688899&r2=688900&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/TriggerDescriptor.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/TriggerDescriptor.java
Mon Aug 25 15:11:35 2008
@@ -702,8 +702,15 @@
 			// When REVOKE_PRIVILEGE gets sent (this happens for privilege 
 			// types SELECT, UPDATE, DELETE, INSERT, REFERENCES, TRIGGER), we  
 			// make the TriggerDescriptor drop itself. 
+			// Ditto for revoking a role conferring a privilege.
 			case DependencyManager.REVOKE_PRIVILEGE:
+			case DependencyManager.REVOKE_ROLE:
                 drop(lcc);
+
+				lcc.getLastActivation().addWarning(
+					StandardException.newWarning(
+						SQLState.LANG_TRIGGER_DROPPED,
+						this.getObjectName() ));
 				break;
 
 			default:
@@ -717,7 +724,6 @@
         DataDictionary dd = getDataDictionary();
         DependencyManager dm = getDataDictionary().getDependencyManager();
         TransactionController tc = lcc.getTransactionExecute();
-
         dm.invalidateFor(this, DependencyManager.DROP_TRIGGER, lcc);
 
         // Drop the trigger

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/ViewDescriptor.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/ViewDescriptor.java?rev=688900&r1=688899&r2=688900&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/ViewDescriptor.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/ViewDescriptor.java
Mon Aug 25 15:11:35 2008
@@ -274,6 +274,12 @@
 			//the ViewDescriptor drop itself. 
 		    case DependencyManager.REVOKE_PRIVILEGE:
 
+			// When a role grant is revoked, any a view dependent on priviliges
+			// obtained through that role grant will dropped. We don't do
+			// anything here. Later in makeInvalid method, we make the
+			// ViewDescriptor drop itself.
+			case DependencyManager.REVOKE_ROLE:
+
 				// When REVOKE_PRIVILEGE gets sent to a
 				// TablePermsDescriptor we must also send
 				// INTERNAL_RECOMPILE_REQUEST to its Dependents which
@@ -352,6 +358,7 @@
 			//make the ViewDescriptor drop itself. 
 		    case DependencyManager.REVOKE_PRIVILEGE:
 		    case DependencyManager.DROP_COLUMN:
+		    case DependencyManager.REVOKE_ROLE:
 				drop(lcc, 
 						getDataDictionary().getTableDescriptor(uuid).getSchemaDescriptor(),
 						getDataDictionary().getTableDescriptor(uuid));

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DDLConstantAction.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DDLConstantAction.java?rev=688900&r1=688899&r2=688900&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DDLConstantAction.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DDLConstantAction.java
Mon Aug 25 15:11:35 2008
@@ -27,8 +27,6 @@
 import org.apache.derby.catalog.UUID;
 import org.apache.derby.iapi.error.StandardException;
 import org.apache.derby.iapi.reference.SQLState;
-import org.apache.derby.iapi.reference.Property;
-import org.apache.derby.iapi.services.property.PropertyUtil;
 import org.apache.derby.iapi.services.sanity.SanityManager;
 import org.apache.derby.iapi.sql.Activation;
 import org.apache.derby.iapi.sql.conn.Authorizer;
@@ -39,15 +37,19 @@
 import org.apache.derby.iapi.sql.dictionary.ColPermsDescriptor;
 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
 import org.apache.derby.iapi.sql.dictionary.PermissionsDescriptor;
+import org.apache.derby.iapi.sql.dictionary.RoleGrantDescriptor;
 import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
 import org.apache.derby.iapi.sql.dictionary.StatementColumnPermission;
 import org.apache.derby.iapi.sql.dictionary.StatementPermission;
-import org.apache.derby.iapi.sql.dictionary.StatementRoutinePermission;
 import org.apache.derby.iapi.sql.dictionary.StatementSchemaPermission;
+import org.apache.derby.iapi.sql.dictionary.StatementRolePermission;
+import org.apache.derby.iapi.sql.dictionary.StatementRoutinePermission;
 import org.apache.derby.iapi.sql.dictionary.StatementTablePermission;
+import org.apache.derby.iapi.sql.dictionary.RoleClosureIterator;
 import org.apache.derby.iapi.sql.execute.ConstantAction;
 import org.apache.derby.iapi.store.access.ConglomerateController;
 import org.apache.derby.iapi.store.access.TransactionController;
+import org.apache.derby.iapi.services.sanity.SanityManager;
 
 /**
  * Abstract class that has actions that are across
@@ -282,6 +284,9 @@
 	 *  statement. Because of these differences between constraints and views
 	 *  (and triggers), there are 2 different methods in this class to save
 	 *  their privileges in the dependency system.
+	 *
+	 *  For each required privilege, we now register a dependency on a role if
+	 *  that role was required to find an applicable privilege.
 	 *   
 	 *  @param activation The execution environment for this constant action.
 	 *  @param dependent Make this object depend on required privileges
@@ -300,17 +305,21 @@
 		LanguageConnectionContext lcc = activation.getLanguageConnectionContext();
 		DataDictionary dd = lcc.getDataDictionary();
 		DependencyManager dm = dd.getDependencyManager();
-		
+		String dbo = dd.getAuthorizationDatabaseOwner();
+		String authId = lcc.getAuthorizationId();
+		SettableBoolean roleDepAdded = new SettableBoolean();
+
 		//If the Database Owner is creating this constraint, then no need to 
 		//collect any privilege dependencies because the Database Owner can   
 		//access any objects without any restrictions
 		if (!(lcc.getAuthorizationId().equals(dd.getAuthorizationDatabaseOwner())))
 		{
 			PermissionsDescriptor permDesc;
-			// Now, it is time to add into dependency system, constraint's
-			// dependency on REFERENCES or, if it is a CHECK constraint, any
-			// EXECUTE privileges. If the REFERENCES is revoked from the
-			// constraint owner, the constraint will get dropped automatically.
+			// Now, it is time to add into dependency system the FOREIGN
+			// constraint's dependency on REFERENCES privilege, or, if it is a
+			// CHECK constraint, any EXECUTE privileges. If the REFERENCES is
+			// revoked from the constraint owner, the constraint will get
+			// dropped automatically.
 			List requiredPermissionsList = activation.getPreparedStatement().getRequiredPermissionsList();
 
 			if (requiredPermissionsList != null && ! requiredPermissionsList.isEmpty())
@@ -336,7 +345,8 @@
 						//privilege in the required privileges list
 						if (!statementTablePermission.getTableUUID().equals(refTableUUID))
 							continue;
-					} else if (statPerm instanceof StatementSchemaPermission) { 
+					} else if (statPerm instanceof StatementSchemaPermission
+						    || statPerm instanceof StatementRolePermission) {
 						continue;
 					} else {
 						if (SanityManager.DEBUG) {
@@ -363,18 +373,45 @@
 					// individual column levels. In addition, individual column
 					// REFERENCES privilege could be available at the user
 					// level, PUBLIC or role level.  EXECUTE privilege could be
-					// available at the user or PUBLIC level.
+					// available at the user level, PUBLIC or role level.
 					permDesc = statPerm.getPermissionDescriptor(lcc.getAuthorizationId(), dd);				
 					if (permDesc == null) 
 					{
-						//No REFERENCES privilege exists for given 
-						//authorizer at table or column level.
-						//REFERENCES privilege has to exist at at PUBLIC level
+						// No privilege exists for given user. The privilege
+						// has to exist at at PUBLIC level....
+
 						permDesc = statPerm.getPermissionDescriptor(Authorizer.PUBLIC_AUTHORIZATION_ID, dd);
-						if (permDesc != null &&
-							!(permDesc.checkOwner(lcc.getAuthorizationId())))
-							dm.addDependency(dependent, permDesc, lcc.getContextManager());
-					} else 
+						// .... or at the role level. Additionally, for column
+						// level privileges, even if *some* were available at
+						// the PUBLIC level others may be still be missing,
+						// hence the call in the test below to
+						// allColumnsCoveredByUserOrPUBLIC.
+						boolean roleUsed = false;
+
+						if (permDesc == null ||
+							((permDesc instanceof ColPermsDescriptor) &&
+									 !(((StatementColumnPermission)statPerm).
+										   allColumnsCoveredByUserOrPUBLIC
+										   (lcc.getAuthorizationId(), dd)))) {
+							roleUsed = true;
+							permDesc = findRoleUsage(activation, statPerm);
+						}
+
+						// If the user accessing the object is the owner of
+						// that object, then no privilege tracking is needed
+						// for the owner.
+						if (!(permDesc.checkOwner(lcc.getAuthorizationId()))) {
+							dm.addDependency(dependent, permDesc,
+											 lcc.getContextManager());
+
+							if (roleUsed) {
+								// We had to rely on role, so track that
+								// dependency, too.
+								trackRoleDependency
+									(activation, dependent, roleDepAdded);
+							}
+						}
+					} else
 						//if the object on which permission is required is owned by the
 						//same user as the current user, then no need to keep that
 						//object's privilege dependency in the dependency system
@@ -383,37 +420,166 @@
 						dm.addDependency(dependent, permDesc, lcc.getContextManager());
 						if (permDesc instanceof ColPermsDescriptor)
 						{
-							//The if statement above means we found a
-							//REFERENCES privilege at column level for
-							//the given authorizer. If this privilege
-							//doesn't cover all the column , then there 
-							//has to exisit REFERENCES for the remaining
-							//columns at PUBLIC level. Get that permission
-							//descriptor and save it in dependency system
-							StatementColumnPermission statementColumnPermission = (StatementColumnPermission)
statPerm;
-							permDesc = statementColumnPermission.getPUBLIClevelColPermsDescriptor(lcc.getAuthorizationId(),
dd);
+							// The if statement above means we found a
+							// REFERENCES privilege at column level for the
+							// given authorizer. If this privilege doesn't
+							// cover all the column , then there has to exisit
+							// REFERENCES for the remaining columns at PUBLIC
+							// level or at role level.  Get that permission
+							// descriptor and save it in dependency system
+							StatementColumnPermission
+								statementColumnPermission = (
+									StatementColumnPermission)statPerm;
+							permDesc = statementColumnPermission.
+								getPUBLIClevelColPermsDescriptor
+								   (lcc.getAuthorizationId(), dd);
 							//Following if checks if some column level privileges
 							//exist only at public level. If so, then the public
 							//level column privilege dependency is added
 							//into the dependency system
-							if (permDesc != null)
-								dm.addDependency(dependent, permDesc, lcc.getContextManager());	           					
										
+							if (permDesc != null &&
+									permDesc.getObjectID() != null) {
+								// User did not have all required column
+								// permissions and at least one column is
+								// covered by PUBLIC.
+								dm.addDependency(dependent, permDesc,
+												 lcc.getContextManager());
+							}
+							// Possibly, the current role has also been relied
+							// upon.
+							if (!statementColumnPermission.
+									allColumnsCoveredByUserOrPUBLIC
+									    (lcc.getAuthorizationId(), dd)) {
+								// Role has been relied upon, so register a
+								// dependency.
+								trackRoleDependency
+									(activation, dependent, roleDepAdded);
+							}
 						}
 					}
 
-					if (statPerm instanceof StatementTablePermission) {
+					if (!(statPerm instanceof StatementRoutinePermission)) {
 						//We have found the REFERENCES privilege for all the
 						//columns in foreign key constraint and we don't
 						//need to go through the rest of the privileges
 						//for this sql statement.
 						break;
+					} else {
+						// For EXECUTE privilege there may be several functions
+						// referenced in the constraint, so continue looking.
 					}
 				}
 			}
 		}
 		
 	}	
-	
+
+
+	/**
+	 * We have determined that the statement permission described by statPerm
+	 * is not granted to the current user nor to PUBLIC, so it must be granted
+	 * to the current role or one of the roles inherited by the current
+	 * role. Find the relevant permission descriptor and return it.
+	 *
+	 * @return the permission descriptor that yielded the privilege
+	 */
+	private static PermissionsDescriptor findRoleUsage
+		(Activation activation,
+		 StatementPermission statPerm) throws StandardException {
+
+		LanguageConnectionContext lcc =
+			activation.getLanguageConnectionContext();
+		DataDictionary dd = lcc.getDataDictionary();
+		RoleGrantDescriptor rootGrant = null;
+		String role = lcc.getCurrentRoleId(activation);
+		String dbo = dd.getAuthorizationDatabaseOwner();
+		String authId = lcc.getAuthorizationId();
+		PermissionsDescriptor permDesc = null;
+
+		if (SanityManager.DEBUG) {
+			SanityManager.ASSERT(
+				role != null,
+				"Unexpected: current role is not set");
+		}
+
+		// determine how we got to be able use this role
+		rootGrant =
+			dd.getRoleGrantDescriptor(role, authId, dbo);
+
+		if (rootGrant == null) {
+			rootGrant = dd.getRoleGrantDescriptor(
+				role,
+				Authorizer.PUBLIC_AUTHORIZATION_ID,
+				dbo);
+		}
+
+		// If not found in current role, get transitive
+		// closure of roles granted to current role and
+		// iterate over it to see if permission has
+		// been granted to any of the roles the current
+		// role inherits.
+		RoleClosureIterator rci =
+			dd.createRoleClosureIterator
+			(activation.getTransactionController(),
+			 role, true /* inverse relation*/);
+
+		String graphGrant;
+		while (permDesc == null &&
+			   (graphGrant = rci.next()) != null) {
+			permDesc =
+				statPerm.getPermissionDescriptor
+				(graphGrant, dd);
+		}
+
+		if (SanityManager.DEBUG) {
+			SanityManager.ASSERT(
+				permDesc != null,
+				"Unexpected: Permission needs to be found via role");
+		}
+
+		return permDesc;
+	}
+
+
+	/**
+	 * The statement permission needed for dependent has been found to rely on
+	 * the current role. If not already done, register the dependency so that
+	 * if the current role (or any of the roles it inherits) is revoked (or
+	 * dropped), we can invalidate dependent.
+	 *
+	 * @param activation the current activation
+	 * @param dependent the view, constraint or trigger that is dependent on the
+	 *        current role for some privilege.
+	 * @param roleDepAdded keeps track of whether a dependeny on the
+	 *        current role has aleady been registered.
+	 */
+	private static void trackRoleDependency(Activation activation,
+											Dependent dependent,
+											SettableBoolean roleDepAdded)
+			throws StandardException {
+
+		// We only register the dependency once, lest
+		// we get duplicates in SYSDEPENDS (duplicates
+		// are not healthy..invalidating more than once
+		// fails for triggers at least).
+		if (!roleDepAdded.get()) {
+			LanguageConnectionContext lcc =
+				activation.getLanguageConnectionContext();
+			DataDictionary dd = lcc.getDataDictionary();
+			DependencyManager dm = dd.getDependencyManager();
+
+			String role =
+				lcc.getCurrentRoleId(activation);
+			RoleGrantDescriptor rgd =
+				dd.getRoleDefinitionDescriptor(role);
+
+			dm.addDependency
+				(dependent, rgd,
+				 lcc.getContextManager());
+			roleDepAdded.set(true);
+		}
+	}
+
 	/**
 	 *	This method saves dependencies of views and triggers on privileges in  
 	 *  the dependency system. It gets called by CreateViewConstantAction
@@ -437,7 +603,10 @@
 	 *  to identify right privileges for right constraints for a given sql
 	 *  statement. Because of these differences between constraints and views
 	 *  (and triggers), there are 2 different methods in this class to save
-	 *  their privileges in the dependency system.  
+	 *  their privileges in the dependency system.
+	 *
+	 *  For each required privilege, we now register of a dependency on a role
+	 *  if that role was required to find an applicable privilege.
 	 *
 	 *  @param activation The execution environment for this constant action.
 	 *  @param dependent Make this object depend on required privileges
@@ -451,11 +620,14 @@
 		LanguageConnectionContext lcc = activation.getLanguageConnectionContext();
 		DataDictionary dd = lcc.getDataDictionary();
 		DependencyManager dm = dd.getDependencyManager();
-		
-		//If the Database Owner is creating this view/triiger, then no need to  
-		//collect any privilege dependencies because the Database Owner can  
-		//access any objects without any restrictions
-		if (!(lcc.getAuthorizationId().equals(dd.getAuthorizationDatabaseOwner())))
+		String dbo = dd.getAuthorizationDatabaseOwner();
+		String authId = lcc.getAuthorizationId();
+		SettableBoolean roleDepAdded = new SettableBoolean();
+
+		// If the Database Owner is creating this view/trigger, then no need to
+		// collect any privilege dependencies because the Database Owner can
+		// access any objects without any restrictions.
+		if (!authId.equals(dbo))
 		{
 			PermissionsDescriptor permDesc;
 			List requiredPermissionsList = activation.getPreparedStatement().getRequiredPermissionsList();
@@ -470,22 +642,55 @@
 					//But we don't need to add schema permission to list of 
 					//permissions that the object is dependent on once it is 
 					//created.
-					if (statPerm instanceof StatementSchemaPermission)
+					//Also, StatementRolePermission should not occur here.
+					if (statPerm instanceof StatementSchemaPermission ||
+						statPerm instanceof StatementRolePermission) {
+
+						if (SanityManager.DEBUG) {
+							if (statPerm instanceof StatementRolePermission) {
+								SanityManager.THROWASSERT(
+									"Unexpected StatementRolePermission");
+							}
+						}
+
 						continue;
+					}
+
 					//See if we can find the required privilege for given authorizer?
 					permDesc = statPerm.getPermissionDescriptor(lcc.getAuthorizationId(), dd);				
 					if (permDesc == null)//privilege not found for given authorizer 
 					{
 						//The if condition above means that required privilege does 
 						//not exist at the user level. The privilege has to exist at 
-						//PUBLIC level.
-						permDesc = statPerm.getPermissionDescriptor(Authorizer.PUBLIC_AUTHORIZATION_ID, dd);
+						//PUBLIC level... ,
+						permDesc = statPerm.getPermissionDescriptor(
+							Authorizer.PUBLIC_AUTHORIZATION_ID, dd);
+
+						boolean roleUsed = false;
+
+						// .. or at role level
+						if (permDesc == null ||
+								((permDesc instanceof ColPermsDescriptor) &&
+									 !(((StatementColumnPermission)statPerm).
+									 allColumnsCoveredByUserOrPUBLIC
+										   (lcc.getAuthorizationId(), dd)))) {
+							roleUsed = true;
+							permDesc = findRoleUsage(activation, statPerm);
+						}
+
 						//If the user accessing the object is the owner of that 
 						//object, then no privilege tracking is needed for the
 						//owner.
-						if (permDesc != null &&
-							!(permDesc.checkOwner(lcc.getAuthorizationId())))
+						if (!(permDesc.checkOwner(lcc.getAuthorizationId()))) {
 							dm.addDependency(dependent, permDesc, lcc.getContextManager());
+
+							// We had to rely on role, so track that
+							// dependency, too.
+							if (roleUsed) {
+								trackRoleDependency
+									(activation, dependent, roleDepAdded);
+							}
+						}
 						continue;
 					}
 					//if the object on which permission is required is owned by the
@@ -519,15 +724,30 @@
 							permDesc = statementColumnPermission.getPUBLIClevelColPermsDescriptor(lcc.getAuthorizationId(),
dd);
 							//Following if checks if some column level privileges
 							//exist only at public level. If so, then the public
-							//level column privilege dependency of view is added
-							//into dependency system.
-							if (permDesc != null)
-								dm.addDependency(dependent, permDesc, lcc.getContextManager());	           					
	
+							//level column privilege, if any, dependency of
+							//view is added into dependency system.
+
+							if (permDesc != null &&
+									permDesc.getObjectID() != null) {
+								// User did not have all required column
+								// permissions and at least one column is
+								// covered by PUBLIC.
+								dm.addDependency(dependent, permDesc,
+												 lcc.getContextManager());
+							} // else nothing found for PUBLIC..
+
+							// Has the the current role has also been relied
+							// upon?
+							if (!statementColumnPermission.
+									allColumnsCoveredByUserOrPUBLIC
+									    (lcc.getAuthorizationId(), dd)) {
+								trackRoleDependency
+									(activation, dependent, roleDepAdded);
+							}
 						}
 					}
 				}
 			}
-			
 		}
 	}
 
@@ -543,5 +763,24 @@
 		}
 		return false;
 	}
+
+	/**
+	 * Mutable Boolean wrapper, initially false
+	 */
+	private class SettableBoolean {
+		boolean value;
+
+		SettableBoolean() {
+			value = false;
+		}
+
+		void set(boolean b) {
+			value = b;
+		}
+
+		boolean get() {
+			return value;
+		}
+	}
 }
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DropRoleConstantAction.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DropRoleConstantAction.java?rev=688900&r1=688899&r2=688900&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DropRoleConstantAction.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DropRoleConstantAction.java
Mon Aug 25 15:11:35 2008
@@ -21,13 +21,13 @@
 
 package org.apache.derby.impl.sql.execute;
 
-import org.apache.derby.iapi.sql.execute.ConstantAction;
-
 import org.apache.derby.iapi.error.StandardException;
 import org.apache.derby.iapi.sql.Activation;
 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
+import org.apache.derby.iapi.sql.depend.DependencyManager;
 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
 import org.apache.derby.iapi.sql.dictionary.RoleGrantDescriptor;
+import org.apache.derby.iapi.sql.dictionary.RoleClosureIterator;
 import org.apache.derby.shared.common.reference.SQLState;
 import org.apache.derby.iapi.store.access.TransactionController;
 
@@ -74,11 +74,9 @@
 
 
     /**
-     *  This is the guts of the Execution-time logic for DROP ROLE.
-     *
-     *  @see ConstantAction#executeConstantAction
+     * This is the guts of the Execution-time logic for DROP ROLE.
      *
-     * @exception StandardException     Thrown on failure
+     * @see org.apache.derby.iapi.sql.execute.ConstantAction#executeConstantAction
      */
     public void executeConstantAction( Activation activation )
         throws StandardException
@@ -106,6 +104,30 @@
                 SQLState.ROLE_INVALID_SPECIFICATION, roleName);
         }
 
+        // When a role is dropped, for every role in its grantee closure, we
+        // call two invalidate actions.  REVOKE_ROLE and
+        // INTERNAL_RECOMPILE_REQUEST.  The latter is used to force
+        // recompilation of dependent prepared statements, the former to drop
+        // dependent objects (constraints, triggers and views).  Note that
+        // until DERBY-1632 is fixed, we risk dropping objects not really
+        // dependent on this role, but one some other role just because it
+        // inherits from this one. See also RevokeRoleConstantAction.
+        RoleClosureIterator rci =
+            dd.createRoleClosureIterator
+            (activation.getTransactionController(),
+             roleName, false);
+
+        String role;
+        while ((role = rci.next()) != null) {
+            RoleGrantDescriptor r = dd.getRoleDefinitionDescriptor(role);
+
+            dd.getDependencyManager().invalidateFor
+                (r, DependencyManager.REVOKE_ROLE, lcc);
+
+            dd.getDependencyManager().invalidateFor
+                (r, DependencyManager.INTERNAL_RECOMPILE_REQUEST, lcc);
+        }
+
         rdDef.drop(lcc);
 
         /*

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/RevokeRoleConstantAction.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/RevokeRoleConstantAction.java?rev=688900&r1=688899&r2=688900&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/RevokeRoleConstantAction.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/RevokeRoleConstantAction.java
Mon Aug 25 15:11:35 2008
@@ -21,16 +21,16 @@
 
 package org.apache.derby.impl.sql.execute;
 
-import org.apache.derby.iapi.sql.execute.ConstantAction;
-
 import java.util.Iterator;
 import java.util.List;
 import org.apache.derby.iapi.error.StandardException;
 import org.apache.derby.iapi.sql.Activation;
 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
+import org.apache.derby.iapi.sql.depend.DependencyManager;
 import org.apache.derby.iapi.sql.conn.Authorizer;
 import org.apache.derby.iapi.sql.dictionary.RoleGrantDescriptor;
 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
+import org.apache.derby.iapi.sql.dictionary.RoleClosureIterator;
 import org.apache.derby.iapi.store.access.TransactionController;
 import org.apache.derby.shared.common.reference.SQLState;
 import org.apache.derby.iapi.services.sanity.SanityManager;
@@ -63,11 +63,9 @@
     // INTERFACE METHODS
 
     /**
-     *  This is the guts of the Execution-time logic for REVOKE role.
-     *
-     *  @see ConstantAction#executeConstantAction
+     * This is the guts of the Execution-time logic for REVOKE role.
      *
-     * @exception StandardException     Thrown on failure
+     * @see org.apache.derby.iapi.sql.execute.ConstantAction#executeConstantAction
      */
     public void executeConstantAction(Activation activation)
             throws StandardException {
@@ -146,15 +144,33 @@
                             SanityManager.NOTREACHED();
                         }
 
-                        // do some invalidation
-
-                        rd.drop(lcc);
-                        rd.setWithAdminOption(false);
-                        dd.addDescriptor(rd,
-                                         null,  // parent
-                                         DataDictionary.SYSROLES_CATALOG_NUM,
-                                         false, // no duplicatesAllowed
-                                         tc);
+                        // Do invalidation.
+                        //
+                        // RoleClosureIterator rci =
+                        //     dd.createRoleClosureIterator
+                        //     (activation.getTransactionController(),
+                        //      role, false);
+                        //
+                        // String r;
+                        // while ((r = rci.next()) != null) {
+                        //   rdDef = dd.getRoleDefinitionDescriptor(r);
+                        //
+                        //   dd.getDependencyManager().invalidateFor
+                        //       (rdDef, DependencyManager.REVOKE_ROLE, lcc);
+                        //
+                        //   dd.getDependencyManager().invalidateFor
+                        //       (rdDef,
+                        //        DependencyManager.INTERNAL_RECOMPILE_REQUEST,
+                        //        lcc);
+                        // }
+                        //
+                        // rd.drop(lcc);
+                        // rd.setWithAdminOption(false);
+                        // dd.addDescriptor(rd,
+                        //                  null,  // parent
+                        //                  DataDictionary.SYSROLES_CATALOG_NUM,
+                        //                  false, // no duplicatesAllowed
+                        //                  tc);
                     } else {
                         activation.addWarning
                             (StandardException.newWarning
@@ -162,9 +178,37 @@
                               role, grantee));
                     }
                 } else if (rd != null) {
-                    // normal revoke of role from grantee
+                    // Normal revoke of role from grantee.
                     //
+                    // When a role is revoked, for every role in its grantee
+                    // closure, we call two invalidate actions.  REVOKE_ROLE
+                    // and INTERNAL_RECOMPILE_REQUEST.  The latter is used to
+                    // force recompilation of dependent prepared statements,
+                    // the former to drop dependent objects (constraints,
+                    // triggers and views).  Note that until DERBY-1632 is
+                    // fixed, we risk dropping objects not really dependent on
+                    // this role, but one some other role just because it
+                    // inherits from this one.
+                    RoleClosureIterator rci =
+                        dd.createRoleClosureIterator
+                        (activation.getTransactionController(),
+                         role, false);
+
+                    String r;
+                    while ((r = rci.next()) != null) {
+                        rdDef = dd.getRoleDefinitionDescriptor(r);
+
+                        dd.getDependencyManager().invalidateFor
+                            (rdDef, DependencyManager.REVOKE_ROLE, lcc);
+
+                        dd.getDependencyManager().invalidateFor
+                            (rdDef,
+                             DependencyManager.INTERNAL_RECOMPILE_REQUEST,
+                             lcc);
+                    }
+
                     rd.drop(lcc);
+
                 } else {
                     activation.addWarning
                         (StandardException.newWarning

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=688900&r1=688899&r2=688900&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 Aug 25 15:11:35 2008
@@ -28,9 +28,8 @@
 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
 import org.apache.derby.iapi.sql.ParameterValueSet;
 import org.apache.derby.iapi.sql.StatementType;
-import org.apache.derby.iapi.sql.conn.Authorizer;
+import org.apache.derby.iapi.sql.depend.DependencyManager;
 import org.apache.derby.iapi.types.DataValueDescriptor;
-import org.apache.derby.iapi.reference.Limits;
 import org.apache.derby.iapi.error.StandardException;
 import org.apache.derby.iapi.sql.Activation;
 import org.apache.derby.iapi.reference.SQLState;
@@ -120,8 +119,21 @@
 
         RoleGrantDescriptor rdDef = null;
 
-        if (thisRoleName != null) {
-            try {
+        try {
+            String oldRole = lcc.getCurrentRoleId(activation);
+
+            if (oldRole != null && !oldRole.equals(thisRoleName)) {
+                rdDef = dd.getRoleDefinitionDescriptor(oldRole);
+
+                if (rdDef != null) {
+                    dd.getDependencyManager().invalidateFor(
+                        rdDef,
+                        DependencyManager.INTERNAL_RECOMPILE_REQUEST,
+                        lcc);
+                } // else: old role else no longer exists, so ignore.
+            }
+
+            if (thisRoleName != null) {
                 rdDef = dd.getRoleDefinitionDescriptor(thisRoleName);
 
                 // SQL 2003, section 18.3, General rule 4:
@@ -135,10 +147,10 @@
                               (SQLState. ROLE_INVALID_SPECIFICATION_NOT_GRANTED,
                                thisRoleName);
                 }
-            } finally {
-                // reading above changes idle state, so reestablish it
-                lcc.userCommit();
             }
+        } finally {
+            // reading above changes idle state, so reestablish it
+            lcc.userCommit();
         }
 
         lcc.setCurrentRole(activation, rdDef != null ? thisRoleName : null);



Mime
View raw message