If as an admin user I create a Node which is not yet published, then using a CCK Node Reference field in another Node make a reference to the first Node and publish the referring Node, An anonymous user will be able to view the second Node and see the link, but then will get access denied when they try to follow it. I believe that if the CCK Node Reference points to a Node the current user isn't allowed to see, then they shouldn't be able to see the reference link at all.

CommentFileSizeAuthor
#5 nodereference_viewaccess.patch1.78 KBnaught101

Comments

CaptainFold’s picture

Has there been any progress on this issue? We are experiencing this problem as well and would like a resolution.

Thanks.

CaptainFold’s picture

I have made the following change to the nodereference.module file.

function theme_nodereference_formatter_full_teaser($element) {
global $user; //added
static $recursion_queue = array();
$output = '';
if (!empty($element['#item']['nid']) && is_numeric($element['#item']['nid'])) {
$node = $element['#node'];
$field = content_fields($element['#field_name'], $element['#type_name']);
// If no 'referencing node' is set, we are starting a new 'reference thread'
if (!isset($node->referencing_node)) {
$recursion_queue = array();
}
$recursion_queue[] = $node->nid;
if (in_array($element['#item']['nid'], $recursion_queue)) {
// Prevent infinite recursion caused by reference cycles:
// if the node has already been rendered earlier in this 'thread',
// we fall back to 'default' (node title) formatter.
return theme('nodereference_formatter_default', $element);
}
if ($referenced_node = node_load($element['#item']['nid'])) {
$referenced_node->referencing_node = $node;
$referenced_node->referencing_field = $field;
_nodereference_titles($element['#item']['nid'], $referenced_node->title);

//Added this to check status of referenced node - only display if published, user viewing is the author, and if user is user 1
if ($referenced_node->status == 1 || $user->uid == $referenced_node->uid || $user->uid == 1) {
$output = node_view($referenced_node, $element['#formatter'] == 'teaser');
}
else {
$output = '';
}
}
}
return $output;
}

The logic above could also be added to the formatter plain and formatter default functions.

Does anyone see a problem with this code? Let me know what you think.

CaptainFold’s picture

Even better and probably more appropriate and proper Drupal code:

//Added this to check status of referenced node - only display if published, user viewing is the author, and if user is user 1
if (node_access ('view', $referenced_node)) {
$output = node_view($referenced_node, $element['#formatter'] == 'teaser');
}

mki’s picture

Title: node reference still visible to user even though resulting node is not » Node reference doesn't respect access rights
Version: 6.x-2.1 » 6.x-2.x-dev
naught101’s picture

Priority: Normal » Critical
Status: Active » Needs review
StatusFileSize
new1.78 KB

I haven't tested this, but this is basically CaptainFold's solution in a patch, and including all three formatters.

I reckon that because of the full teaser formatter showing potentially sensitive content, this is critical.

liquid06’s picture

Patch in #5 seems to solve this issue.

kris digital’s picture

Hi,

I am using node references with the Services Module and I would need to filter the references on node_load... It works with the node referrer module, any chance to achieve this with the node references module??

naught101’s picture

@year2036: try the patch in #5, if that works, please change the status to "reviewed and tested by the community"

kris digital’s picture

I tried the patch as you suggested, but it can't and does not work, because the Services gives back the node after load. The patch is more a theming thing and it may be enough, because you get an access denied when following the link, but that is not the case with Services module in the version I use.

What I can't figure out at the moment: At what point are the referenced nids inserted into the node? There is no load hook in the module File...

kris digital’s picture

this is how I solved it...

/**
 * Implementation of hook_nodeapi().
 */
function nodereference_nodeapi($node, $op) {
switch ($op) {
	case 'load':
		$cid = "content:$node->nid:";
		db_query("DELETE FROM {cache_content} WHERE cid LIKE '%s%%'", $cid);
		$type = content_types($node->type);
		foreach ($type['fields'] as $field) {
	        if ($field['type'] == 'nodereference') {
	          $node_field = isset($node->$field['field_name']) ? $node->$field['field_name'] : array();
			  
				$values =& $node->$field['field_name'];
	          
			  foreach ($node_field as $delta => $item) {	
	   				$ref_node = node_load($item['nid']);
	
 					if(!node_access('view', $ref_node)) $values[$delta] = array();
	          }
			
				//sort elements continously
				$count = 0;
				foreach ($values as $delta => $item) {
						$values[$count] = $item;
		                                $count++;
		           }
	        }
	      }
	break;
  }
}

you can also put it in a seperate module, if you are also using with Services Module...

karens’s picture

Status: Needs review » Fixed

Just committed a fix for access control on nodereference that handles it in a different way.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

webservant316’s picture

this fix seems essential for most. curiously for my use case I would like to be able to display a node reference teaser even if the user doesn't have permission to view the full node. I am looking through the code to see how this might be possible. I have created a new issue post here - http://drupal.org/node/1587484

webservant316’s picture

my problem solved with this one line hack/addition. added this line to 349 of nodereference.module

function theme_nodereference_formatter_full_teaser($element) {
  static $recursion_queue = array();
  $output = '';
+  if ( stripos($element['#field_name'],"grant") != FALSE ) { $element['#item']['safe']['nid'] = $element['#item']['nid']; } // allow view of node reference without perms if 'grant' in cck field name
  if (!empty($element['#item']['safe']['nid'])) {
    $nid = $element['#item']['safe']['nid'];

Perhaps this feature could be added in a better way.