I have file nodes created by File Framework module with taxonomy enabled. So each file node has one term from a certain vocabulary.

My client wants to provide access to only the files defined for certain role(s). So here is my setup:

Roles:
client A
client B
...
client Z

Vocabulary terms for node-type File:
Term 1
Term 2
Term 3
Term 4

I configured tac_lite settings at http://www.example.com/admin/user/access/tac_lite/scheme_1 and gave view access to certain roles for certain terms.

It works like a charm when all the request are made "normally".

The problem occurs on the following step. Some of these files are PDFs and I need to stamp those PDFs with user name and role, etc. For this, I use a custom page and SetaPDF APIs.

Before I integrated tac_lite PDF stamper was working without any problem. But after I set up tac_lite it started giving "access denied" errors:

The code i am using:
(Note; the code below works if the file is a stream not controlled by tac_lite, or a local file on file system. But chokes on streams controlled by tac_lite.)

require_once './includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);

global $user;

/**
 * set the includepath for SetaPDF APIs
 * You have to point to the root directory "SetaPDF"
 */
set_include_path(get_include_path() . PATH_SEPARATOR . realpath(dirname(__FILE__).'/Download'));

// Watermark text
$watermark = "Downloaded by $user->name on date('M j, Y g:ia') from $user->hostname";

// Get file
$download_path = 'http://www.example.com/file/213/view/471';
$varInAnyScope = file_get_contents($download_path);

$newVarInAnyScope = '';

require_once("Tools/StreamWrapper/Php5/VarStream.php");
require_once("Stamper/SetaPDF_Stamper.php");
define('SetaPDF_STAMPER_FONTPATH', 'Stamper/font/');
$stamper =& SetaPDF_Stamper::factory('I');

$stamper->addFile(array(
//    'in'  => 'Any_file_on_the_filesystem.pdf',
      'in'  => VarStream::createReference($varInAnyScope),
      'out' => 'stamped_version.pdf'
));
require_once("Stamper/SetaPDF_Stamp/SetaPDF_TextStamp.php");
$textstamp =& new SetaPDF_TextStamp();
$textstamp->setText($watermark);
$textstamp->setFontFamily('Arial');
$textstamp->setFontSize(-1);
$textstamp->setTextWidth(650);
$textstamp->setAlign('C');
$textstamp->setAlpha(1);
$textstamp->setFontColor(153,153,153);
$textstamp->setRenderingMode(0);
$stamper->setStamp($textstamp,"CM", "all", 0, 0, 60, true);
$stamper->stampit();

Frankly, it took a while for me to figure what was the problem. Because there was only white blank page, no error message, nothing. After trying out several methods like cURL and drupal_http_request I got the error message(s), different errors but all are 403...

Error message from the logs:

Type	php
Date	Thursday, January 7, 2010 - 10:53
User	superadmin
Location	http://www.example.com/demo13.php
Referrer	
Message	file_get_contents(http://www.example.com/file/213/view/471) [<a href='function.file-get-contents'>function.file-get-contents</a>]: failed to open stream: HTTP request failed! HTTP/1.1 403 Forbidden in /var/www/httpdocs/demo13.php on line 26.
Severity	error
Operations	

or

Type	access denied
Date	Thursday, January 7, 2010 - 00:10
User	Visitor
Location	http://www.example.com/file/249/view/533
Referrer	
Message	file/249/view/533
Severity	warning
Operations	

So, I guess tac_lite cannot authenticate user if the call is made by a stream. Is there a way I can accomplish my goal, but still use tac_lite?

p.s. I also tried stream context to add headers for the call but it didn't work either:

  $download_path = 'http://www.example.com/file/213/view/471';

  $uri  = parse_url($download_path);
  $port = isset($uri['port']) ? $uri['port'] : 80;
  $host = $uri['host'] . ($port != 80 ? ':'. $port : '');
  $opts = array(
    'http'=>array(
      'method'=>"GET",
      'header'=>"Host: " . $host . "\r\n" .
                "User-Agent: Drupal (+http://drupal.org/)\r\n" .
                "Content-type: application/pdf"
    )
  );

  $context = stream_context_create($opts);
  
  $varInAnyScope = file_get_contents($download_path, 0, $context);

Comments

Dave Cohen’s picture

Category: bug » support

tac_lite hides nodes based on how they are tagged. It never calls drupal_access_denied() or return an access denied HTTP code.

I think your script should be able to access any URL that an anonymous user can access. Try hitting the same URL from a browser and see what happens. Maybe file framework is calling drupal_access_denied().

osman’s picture

Hi Dave,

The script above was working before I configured tac_lite. Also I can access the same URL on the browser works fine, as normal.

I realized that in the logs that on some of my tests, the user, generating the access denied error is anonymous user even though there is an open session (#1). Somehow it looses the session value or something.

FYI, I tested the same script to call a file from the file system, it works and also keeps the session (see the watermark string).

So, I don't really know what causes this problem. Only thing I know is, it started after setting up tac_lite. I was hoping you could help me finding it out.

On my tests I got different error messages. It may not be calling drupal_access_denied() directly, but somehow it loses the session.

Thanks,

Dave Cohen’s picture

Delete all your browser cookies, then hit the same URL as the script. You should get the same access denied.

osman’s picture

What?

File nodes are only available to certain roles (authenticated users). Anonymous users have no access anyway. I am getting this error when I am authenticated as either one of these roles or user #1.

Are you suggesting tac_lite creates cookies? Otherwise I don't see how it is relevant.

Dave Cohen’s picture

I don't see how your script authenticates itself to Drupal. I think Drupal treats your script as the anonymous user.

osman’s picture

It doesn't do the authentication itself. It uses the existing session:

require_once './includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);

Think about this page is called only after you logged in, found your PDF for downloading and clicked on that link. Right there, this page is called. It uses the existing session information to populate watermark string:

// Watermark text
$watermark = "Downloaded by $user->name on date('M j, Y g:ia') from $user->hostname";

Like I wrote it before, this was working fine before tac_lite, now it's broken.

Dave Cohen’s picture

It seems to me that when

 $download_path = 'http://www.example.com/file/213/view/471';

then file_get_contents() will be hitting the example.com server as an anonymous user. I would try a local file location (no "http://...") or try authenticating to that server.

That said, you seem 100% certain that tac_lite is the cause of the problem. So if you can provide a patch to fix it, or a way to easily reproduce the problem, please let me know.

osman’s picture

The $download_path is full URI of a local file node. And it worked with the way it is before tac_lite.

I'll be look into tac_lite's code to see if I'll be able to create a patch. Meanwhile here's the recipe for duplicating the environment:

Drupal 6.14
Bitcache 6.x-1.0-beta2
File Framework 6.x-1.0-alpha5
Taxonomy Access Control Lite 6.x-1.3

There are other modules installed on my environment, but I don't think any of them related with the modules listed above.
First thing is, before installing tac_lite, make sure Fileframework and its required modules are installed and configured properly. Create a few file nodes have them ready for next step.
Create following roles & users:

Roles:
1. my clients
2. client A
3. client B

Users:
1. user1 (roles: my clients, client A)
2. user2 (roles: my clients, client B)

Create a new vocabulary called "Downloads" and assign to File node-type. (This is not the one you should've already created during Fileframework configuration.) This will be used for tac_lite.

Terms for "Downloads" vocabulary:
Pictures
Movies
Office Docs

Tac_lite configuration:
Scheme 1
----
Scheme name: view only
Permissions: view

Access for anonymous user
Downloads:
<none>

Access for authenticated user
Downloads:
<none>

Access for my clients
Downloads:
<none>

Access for client A
Downloads:
Pictures
Movies

Access for client B
Downloads:
Office Docs

Scheme 1 is the only scheme configured in tac_lite.

Related Permissions (admin/user/permissions):
----
bitcache module
access bitstreams (anonymous user, authenticated user)

node module
access content (anonymous user, authenticated user)

Let me know if this recipe makes sense or you would need more information on the configurations.

Thanks,

Dave Cohen’s picture

Priority: Critical » Normal
Status: Active » Fixed

that doesn't fit the description, "way to easily reproduce the problem."

look, when you call

file_get_contents('http://www.example.com/file/213/view/471');

your script is making an http request to www.example.com. Because that's exactly what you're telling it to do, and it does that as an anonymous user. There's not much mystery here, and no bug.

If I'm right, type http://www.example.com/file/213/view/471 in your browser, as an anonymous user, and you'll get the same result as the script gets. Then, disable tac_lite and repeat the same experiment. The script and the browser should always get the same result.

Status: Fixed » Closed (fixed)

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

Dave Cohen’s picture

Was I right about this?