? 000-seven-form-css-sanity.patch
? 690828-block-ahah_0.patch
? 732542-system-goto-action-D7.patch
? 735528-states-or.patch
? 823428-entity-uri-34.patch
? 846296-file-download.patch
? 846296-file-download2.patch
? 890716-file-settings.patch
? 920614-node-access-new-column.patch
? 920614-node-access-tests.patch
? 920614-node-access-unpublished-documentation.patch
? 920614-node-access-with-test.patch
? 920614-node-access.patch
? file_download_access6.patch
? test.patch
? sites/default/files
? sites/default/private
Index: modules/node/node.api.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.api.php,v
retrieving revision 1.74
diff -u -p -r1.74 node.api.php
--- modules/node/node.api.php	25 Sep 2010 18:01:28 -0000	1.74
+++ modules/node/node.api.php	28 Sep 2010 14:27:07 -0000
@@ -138,7 +138,10 @@
  * an array of the list IDs that this user is a member of.
  *
  * A node access module may implement as many realms as necessary to
- * properly define the access privileges for the nodes.
+ * properly define the access privileges for the nodes. Note that the system
+ * makes no distinction between published and unpublished nodes. It is the
+ * module's responsibility to provide appropriate realms to limit access to
+ * unpublished content.
  *
  * @param $account
  *   The user object whose grants are requested.
@@ -169,6 +172,12 @@ function hook_node_grants($account, $op)
  * interested, it must respond with an array of permissions arrays for that
  * node.
  *
+ * Node access grants apply regardless of the published or unpublished status
+ * of the node. Implementations must make sure not to grant access to
+ * unpublished nodes if they don't want to change the standard access control
+ * behavior. Your module may need to create a separate access realm to handle
+ * access to unpublished nodes.
+ *
  * Note that the grant values in the return value from your hook must be
  * integers and not boolean TRUE and FALSE.
  *
@@ -177,7 +186,9 @@ function hook_node_grants($account, $op)
  *   hook_node_grants().
  * - 'gid': A 'grant ID' from hook_node_grants().
  * - 'grant_view': If set to 1 a user that has been identified as a member
- *   of this gid within this realm can view this node.
+ *   of this gid within this realm can view this node. This should usually be
+ *   set to $node->status. Failure to do so may expose unpublished content
+ *   to some users.
  * - 'grant_update': If set to 1 a user that has been identified as a member
  *   of this gid within this realm can edit this node.
  * - 'grant_delete': If set to 1 a user that has been identified as a member
@@ -187,6 +198,35 @@ function hook_node_grants($account, $op)
  *   priority will not be written. If there is any doubt, it is best to
  *   leave this 0.
  *
+ *
+ * When an implementation is interested in a node but want to deny access to
+ * everyone, it may return a "deny all" grant:
+ *
+ * @code
+ * $grants[] = array(
+ *   'realm' => 'all',
+ *   'gid' => 0,
+ *   'grant_view' => 0,
+ *   'grant_update' => 0,
+ *   'grant_delete' => 0,
+ *   'priority' => 1,
+ * );
+ * @endcode
+ *
+ * Setting the priority should cancel out other grants. In the case of a
+ * conflict between modules, it is safer to use hook_node_access_records_alter()
+ * to return only the deny grant.
+ *
+ * Note: a deny all grant is not written to the database; denies are implicit.
+ *
+ * @see node_access_write_grants()
+ *
+ * @param $node
+ *   The node that has just been saved.
+ *
+ * @return
+ *   An array of grants as defined above.
+ *
  * @ingroup node_access
  */
 function hook_node_access_records($node) {
@@ -194,17 +234,22 @@ function hook_node_access_records($node)
   // treated just like any other node and we completely ignore it.
   if ($node->private) {
     $grants = array();
-    $grants[] = array(
-      'realm' => 'example',
-      'gid' => 1,
-      'grant_view' => 1,
-      'grant_update' => 0,
-      'grant_delete' => 0,
-      'priority' => 0,
-    );
-
+    // Only published nodes should be viewable to all users. If we allow access
+    // blindly here, then all users could view an unpublished node.
+    if ($node->status) {
+      $grants[] = array(
+        'realm' => 'example',
+        'gid' => 1,
+        'grant_view' => 1,
+        'grant_update' => 0,
+        'grant_delete' => 0,
+        'priority' => 0,
+      );
+    }
     // For the example_author array, the GID is equivalent to a UID, which
-    // means there are many many groups of just 1 user.
+    // means there are many groups of just 1 user.
+    // Note that an author can always view his or her nodes, even if they
+    // have status unpublished.
     $grants[] = array(
       'realm' => 'example_author',
       'gid' => $node->uid,
@@ -213,6 +258,7 @@ function hook_node_access_records($node)
       'grant_delete' => 1,
       'priority' => 0,
     );
+
     return $grants;
   }
 }
@@ -234,6 +280,8 @@ function hook_node_access_records($node)
  * user must have one or more matching permissions in order to complete the
  * requested operation.
  *
+ * A module may deny all access to a node by setting $grants to an empty array.
+ *
  * @see hook_node_grants()
  * @see hook_node_grants_alter()
  *
@@ -277,6 +325,8 @@ function hook_node_access_records_alter(
  * The resulting grants are then checked against the records stored in the
  * {node_access} table to determine if the operation may be completed.
  *
+ * A module may deny all access to a user by setting $grants to an empty array.
+ *
  * @see hook_node_access_records()
  * @see hook_node_access_records_alter()
  *
Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.1302
diff -u -p -r1.1302 node.module
--- modules/node/node.module	24 Sep 2010 00:37:43 -0000	1.1302
+++ modules/node/node.module	28 Sep 2010 14:27:10 -0000
@@ -3156,8 +3156,8 @@ function node_access_acquire_grants($nod
   $grants = module_invoke_all('node_access_records', $node);
   // Let modules alter the grants.
   drupal_alter('node_access_records', $grants, $node);
-  // If no grants are set, then use the default grant.
-  if (empty($grants)) {
+  // If no grants are set and the node is published, then use the default grant.
+  if (empty($grants) && !empty($node->status)) {
     $grants[] = array('realm' => 'all', 'gid' => 0, 'grant_view' => 1, 'grant_update' => 0, 'grant_delete' => 0);
   }
   else {
@@ -3206,7 +3206,7 @@ function node_access_write_grants($node,
   }
 
   // Only perform work when node_access modules are active.
-  if (count(module_implements('node_grants'))) {
+  if (!empty($grants) && count(module_implements('node_grants'))) {
     $query = db_insert('node_access')->fields(array('nid', 'realm', 'gid', 'grant_view', 'grant_update', 'grant_delete'));
     foreach ($grants as $grant) {
       if ($realm && $realm != $grant['realm']) {
Index: modules/node/node.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.test,v
retrieving revision 1.95
diff -u -p -r1.95 node.test
--- modules/node/node.test	17 Sep 2010 14:53:21 -0000	1.95
+++ modules/node/node.test	28 Sep 2010 14:27:13 -0000
@@ -770,7 +770,7 @@ class NodeRSSContentTestCase extends Dru
 
 /**
  * Test case to verify basic node_access functionality.
- * @todo Cover hook_access in a separate test class.
+ * @todo Cover hook_node_access in a separate test class.
  * hook_node_access_records is covered in another test class.
  */
 class NodeAccessUnitTest extends DrupalWebTestCase {
@@ -821,6 +821,9 @@ class NodeAccessUnitTest extends DrupalW
     $node3 = $this->drupalCreateNode(array('status' => 0, 'uid' => $web_user3->uid));
     $this->assertNodeAccess(array('view' => FALSE), $node3, $web_user3);
 
+    // User cannot create content without permission.
+    $this->assertNodeAccess(array('create' => FALSE), 'page', $web_user3);
+
     // User can 'view own unpublished content', but another user cannot.
     $web_user4 = $this->drupalCreateUser(array('access content', 'view own unpublished content'));
     $web_user5 = $this->drupalCreateUser(array('access content', 'view own unpublished content'));
@@ -830,7 +833,6 @@ class NodeAccessUnitTest extends DrupalW
 
     // Tests the default access provided for a published node.
     $node5 = $this->drupalCreateNode();
-    $this->assertNodeAccess(array('create' => FALSE), 'page', $web_user3);
     $this->assertNodeAccess(array('view' => TRUE, 'update' => FALSE, 'delete' => FALSE), $node5, $web_user3);
   }
 }
@@ -909,6 +911,12 @@ class NodeAccessRecordsUnitTest extends 
       drupal_alter('node_grants', $altered_grants, $web_user, $op);
       $this->assertNotEqual($grants, $altered_grants, t('Altered the %op grant for a user.', array('%op' => $op)));
     }
+
+    // Check that core does not grant access to an unpublished node when an
+    // empty $grants array is returned.
+    $node6 = $this->drupalCreateNode(array('status' => 0, 'disable_node_access' => TRUE));
+    $records = db_query('SELECT realm, gid FROM {node_access} WHERE nid = :nid', array(':nid' => $node6->nid))->fetchAll();
+    $this->assertEqual(count($records), 0, t('Returned no records for unpublished node.'));
   }
 }
 
Index: modules/node/tests/node_test.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/tests/node_test.module,v
retrieving revision 1.11
diff -u -p -r1.11 node_test.module
--- modules/node/tests/node_test.module	20 Apr 2010 09:30:21 -0000	1.11
+++ modules/node/tests/node_test.module	28 Sep 2010 14:27:13 -0000
@@ -52,6 +52,10 @@ function node_test_node_grants($account,
  * Implements hook_node_access_records().
  */
 function node_test_node_access_records($node) {
+  // Return nothing when testing for empty responses.
+  if (!empty($node->disable_node_access)) {
+    return;
+  }
   $grants = array();
   if ($node->type == 'article') {
     // Create grant in arbitrary article_realm for article nodes.
