Browse Source

Merge pull request #235 from jonathangreen/7.x-test-tokens

7.x test tokens
pull/233/merge
Jonathan Green 12 years ago
parent
commit
fe12defee4
  1. 2
      includes/IslandoraTuque.inc
  2. 16
      includes/islandora_authtokens.inc
  3. 2
      islandora.info
  4. 110
      islandora.module
  5. BIN
      tests/fixtures/bug.jp2
  6. 192979
      tests/fixtures/testfixture_10001.xml
  7. 94
      tests/islandora_authtokens.test
  8. 36
      tests/islandora_web_test_case.inc
  9. 4
      tests/test_config.ini

2
includes/IslandoraTuque.inc

@ -64,7 +64,7 @@ class IslandoraTuque {
global $user; global $user;
} }
if (!isset($user) || $user->uid == 0) { if ($user->uid == 0) {
$user_string = 'anonymous'; $user_string = 'anonymous';
$pass_string = 'anonymous'; $pass_string = 'anonymous';
} }

16
includes/islandora_authtokens.inc

@ -23,7 +23,9 @@ define('TOKEN_TIMEOUT', 300);
* Defaults to 1. * Defaults to 1.
* The number of uses the token should be used for. There are * The number of uses the token should be used for. There are
* times when this should be greater than 1: ie. Djatoka needs * times when this should be greater than 1: ie. Djatoka needs
* to make two calls. * to make two calls. This is the number of times it can be called
* from different php sessions, not in the run of a program. (it is
* statically cached).
* *
* @return string * @return string
* The generated authentication token. * The generated authentication token.
@ -68,6 +70,12 @@ function islandora_get_object_token($pid, $dsid, $uses = 1) {
* FALSE otherwise * FALSE otherwise
*/ */
function islandora_validate_object_token($pid, $dsid, $token) { function islandora_validate_object_token($pid, $dsid, $token) {
static $accounts = array();
if(!empty($accounts[$pid][$dsid][$token])) {
return $accounts[$pid][$dsid][$token];
}
// Check for database token. // Check for database token.
$time = time(); $time = time();
$query = db_select('islandora_authtokens', 'tokens'); $query = db_select('islandora_authtokens', 'tokens');
@ -104,11 +112,13 @@ function islandora_validate_object_token($pid, $dsid, $token) {
->execute(); ->execute();
} }
unset($result[0]->remaining_uses); unset($result[0]->remaining_uses);
return $result[0]; $accounts[$pid][$dsid][$token] = $result[0];
} }
else { else {
return FALSE; $accounts[$pid][$dsid][$token] = FALSE;
} }
return $accounts[$pid][$dsid][$token];
} }
/** /**

2
islandora.info

@ -10,4 +10,6 @@ files[] = includes/MimeDetect.inc
files[] = includes/DublinCore.inc files[] = includes/DublinCore.inc
files[] = includes/IslandoraTuque.inc files[] = includes/IslandoraTuque.inc
files[] = includes/IslandoraTuqueWrapper.inc files[] = includes/IslandoraTuqueWrapper.inc
files[] = tests/islandora_web_test_case.inc
files[] = tests/islandora_authtokens.test
php = 5.3 php = 5.3

110
islandora.module

@ -26,13 +26,13 @@
define('DS_COMP_STREAM', 'DS-COMPOSITE-MODEL'); define('DS_COMP_STREAM', 'DS-COMPOSITE-MODEL');
// Permissions // Permissions
define('FEDORA_VIEW', 'view fedora repository'); define('FEDORA_VIEW_OBJECTS', 'view fedora repository objects');
define('FEDORA_MANAGE_DATASTREAMS', 'view fedora repository datastreams');
define('FEDORA_METADATA_EDIT', 'edit fedora metadata'); define('FEDORA_METADATA_EDIT', 'edit fedora metadata');
define('FEDORA_ADD_DS', 'add fedora datastreams'); define('FEDORA_ADD_DS', 'add fedora datastreams');
define('FEDORA_INGEST', 'ingest fedora objects'); define('FEDORA_INGEST', 'ingest fedora objects');
define('FEDORA_PURGE', 'delete fedora objects and datastreams'); define('FEDORA_PURGE', 'delete fedora objects and datastreams');
define('FEDORA_MANAGE_PROPERTIES', 'manage object properties'); define('FEDORA_MANAGE_PROPERTIES', 'manage object properties');
define('FEDORA_MANAGE', 'manage fedora items');
// Hooks // Hooks
define('ISLANDORA_VIEW_HOOK', 'islandora_view_object'); define('ISLANDORA_VIEW_HOOK', 'islandora_view_object');
@ -82,7 +82,7 @@ function islandora_menu() {
'title' => 'Islandora Repository', 'title' => 'Islandora Repository',
'page callback' => 'islandora_view_default_object', 'page callback' => 'islandora_view_default_object',
'type' => MENU_NORMAL_ITEM, 'type' => MENU_NORMAL_ITEM,
'access arguments' => array(FEDORA_VIEW), 'access arguments' => array(FEDORA_VIEW_OBJECTS),
); );
$items['islandora/object/%islandora_object'] = array( $items['islandora/object/%islandora_object'] = array(
'title' => 'Repository', 'title' => 'Repository',
@ -90,7 +90,7 @@ function islandora_menu() {
'page arguments' => array(2), 'page arguments' => array(2),
'type' => MENU_NORMAL_ITEM, 'type' => MENU_NORMAL_ITEM,
'access callback' => 'islandora_object_access_callback', 'access callback' => 'islandora_object_access_callback',
'access arguments' => array(FEDORA_VIEW, 2), 'access arguments' => array(FEDORA_VIEW_OBJECTS, 2),
); );
$items['islandora/object/%islandora_object/view'] = array( $items['islandora/object/%islandora_object/view'] = array(
'title' => 'View', 'title' => 'View',
@ -107,8 +107,8 @@ function islandora_menu() {
'page callback' => 'islandora_edit_object', 'page callback' => 'islandora_edit_object',
'page arguments' => array(2), 'page arguments' => array(2),
'type' => MENU_LOCAL_TASK, 'type' => MENU_LOCAL_TASK,
'access callback' => 'islandora_object_access_callback', 'access callback' => 'islandora_object_manage_access_callback',
'access arguments' => array(FEDORA_MANAGE, 2), 'access arguments' => array(array(FEDORA_MANAGE_DATASTREAMS, FEDORA_MANAGE_PROPERTIES, FEDORA_ADD_DS), 2),
); );
$items['islandora/object/%islandora_object/manage/datastreams'] = array( $items['islandora/object/%islandora_object/manage/datastreams'] = array(
'title' => 'Datastreams', 'title' => 'Datastreams',
@ -158,13 +158,15 @@ function islandora_menu() {
'type' => MENU_CALLBACK, 'type' => MENU_CALLBACK,
'file' => 'includes/datastream.inc', 'file' => 'includes/datastream.inc',
'access callback' => 'islandora_object_datastream_access_callback', 'access callback' => 'islandora_object_datastream_access_callback',
'access arguments' => array(FEDORA_VIEW, 2, 4), 'access arguments' => array(FEDORA_VIEW_OBJECTS, 2, 4),
'load arguments' => array(2), 'load arguments' => array(2),
); );
// This menu item uses token authentication in islandora_tokened_object. // This menu item uses token authentication in islandora_tokened_object.
$items['islandora/object/%islandora_tokened_object/datastream/%islandora_tokened_datastream/view'] = array( $items['islandora/object/%islandora_tokened_object/datastream/%islandora_tokened_datastream/view'] = array(
'title' => 'View datastream', 'title' => 'View datastream',
'load arguments' => array('%map'), 'load arguments' => array('%map'),
'access callback' => 'islandora_object_datastream_tokened_access_callback',
'access arguments' => array(FEDORA_VIEW_OBJECTS, 2, 4),
'type' => MENU_DEFAULT_LOCAL_TASK, 'type' => MENU_DEFAULT_LOCAL_TASK,
); );
$items['islandora/object/%islandora_object/datastream/%islandora_datastream/download'] = array( $items['islandora/object/%islandora_object/datastream/%islandora_datastream/download'] = array(
@ -174,7 +176,7 @@ function islandora_menu() {
'type' => MENU_CALLBACK, 'type' => MENU_CALLBACK,
'file' => 'includes/datastream.inc', 'file' => 'includes/datastream.inc',
'access callback' => 'islandora_object_datastream_access_callback', 'access callback' => 'islandora_object_datastream_access_callback',
'access arguments' => array(FEDORA_VIEW, 2, 4), 'access arguments' => array(FEDORA_VIEW_OBJECTS, 2, 4),
'load arguments' => array(2), 'load arguments' => array(2),
); );
$items['islandora/object/%islandora_object/datastream/%islandora_datastream/edit'] = array( $items['islandora/object/%islandora_object/datastream/%islandora_datastream/edit'] = array(
@ -248,9 +250,13 @@ function islandora_theme() {
*/ */
function islandora_permission() { function islandora_permission() {
return array( return array(
FEDORA_VIEW => array( FEDORA_VIEW_OBJECTS => array(
'title' => t('View repository objects and datastreams'), 'title' => t('View repository objects'),
'description' => t('View objects in the repository and their associated datastreams. Note: Fedora XACML security policies may override this permission.') 'description' => t('View objects in the repository. Note: Fedora XACML security policies may override this permission.')
),
FEDORA_MANAGE_DATASTREAMS => array(
'title' => t('Manage repository object datastreams'),
'description' => t('Manage datastreams of objects in the repository. Note: Fedora XACML security policies may override this permission.')
), ),
FEDORA_ADD_DS => array( FEDORA_ADD_DS => array(
'title' => t('Add datastreams to repository objects'), 'title' => t('Add datastreams to repository objects'),
@ -272,10 +278,6 @@ function islandora_permission() {
'title' => t('Manage object properties'), 'title' => t('Manage object properties'),
'description' => t('Modify object labels, owner IDs, and states.') 'description' => t('Modify object labels, owner IDs, and states.')
), ),
FEDORA_MANAGE => array(
'title' => t('View object management tabs'),
'description' => t('View tabs that provide object management functions.')
)
); );
} }
@ -303,7 +305,7 @@ function islandora_forms($form_id) {
* page not found errors. * page not found errors.
* *
* @param string $perm * @param string $perm
* The user permission to test for. * User permission to test for.
* @param FedoraObject $object * @param FedoraObject $object
* The object to test, if NULL given the object doesn't exist or is * The object to test, if NULL given the object doesn't exist or is
* inaccessible. * inaccessible.
@ -340,13 +342,76 @@ function islandora_object_access_callback($perm, $object = NULL) {
* @param FedoraDatastream $datastream * @param FedoraDatastream $datastream
* The datastream to test, if NULL given the datastream doesn't exist * The datastream to test, if NULL given the datastream doesn't exist
* or is inaccessible. * or is inaccessible.
* @param StdObject $account
* The account to test permissions as or NULL for current user.
* *
* @return boolean * @return boolean
* TRUE if the user is allowed to access this object, FALSE otherwise. * TRUE if the user is allowed to access this object, FALSE otherwise.
*/ */
function islandora_object_datastream_access_callback($perm, $object = NULL, $datastream = NULL) { function islandora_object_datastream_access_callback($perm, $object = NULL, $datastream = NULL, $account = NULL) {
module_load_include('inc', 'islandora', 'includes/utilities'); module_load_include('inc', 'islandora', 'includes/utilities');
return user_access($perm) && is_object($object) && islandora_namespace_accessible($object->id) && is_object($datastream); return user_access($perm, $account) && is_object($object) && islandora_namespace_accessible($object->id) && is_object($datastream);
}
/**
* Checks whether the user can access the given object and datastream with
* the given permission. This function will validate and use a token if one
* is provided in the _GET array.
*
* Checks for object existance, accessiblitly, namespace permissions,
* and user permissions
*
* @see islandora_object_datastream_tokened_access_callback()
*/
function islandora_object_datastream_tokened_access_callback($perm, $object = NULL, $datastream = NULL) {
module_load_include('inc', 'islandora', 'includes/utilities');
$token_account = NULL;
$token = filter_input(INPUT_GET, 'token', FILTER_SANITIZE_STRING);
if ($token) {
$user = islandora_validate_object_token($object->id, $datastream->id, $token);
if ($user) {
$token_account = user_load($user->uid);
}
}
return islandora_object_datastream_access_callback($perm, $object, $datastream, $token_account);
}
/**
* Checks whether the user can access the given object's manage tab
* with the given array of permissions.
*
* Checks for object existance, accessiblitly, namespace permissions,
* and user permissions
*
* @see islandora_object_load() To find potential solutions to enable
* page not found errors.
*
* @param array $perms
* Array of user permission to test for.
* @param FedoraObject $object
* The object to test, if NULL given the object doesn't exist or is
* inaccessible.
*
* @return boolean
* TRUE if the user is allowed to access this object, FALSE otherwise.
*/
function islandora_object_manage_access_callback($perms, $object = NULL) {
module_load_include('inc', 'islandora', 'includes/utilities');
if (!$object && !islandora_describe_repository()) {
islandora_display_repository_inaccessible_message();
return FALSE;
}
$has_access = FALSE;
for ($i = 0; $i < count($perms) && !$has_access; $i++) {
$has_access = $has_access || user_access($perms[$i]);
}
return $has_access && is_object($object) && islandora_namespace_accessible($object->id);
} }
/** /**
@ -466,6 +531,12 @@ function islandora_default_islandora_view_object($object) {
* Just a wrapper around fetchings the IslandoraTuque object, with some very * Just a wrapper around fetchings the IslandoraTuque object, with some very
* basic error logging. * basic error logging.
* *
* @param $user
* The user to connect as.
*
* @param $url
* The URL to connect to.
*
* @return IslandoraTuque * @return IslandoraTuque
* A IslandoraTuque instance * A IslandoraTuque instance
*/ */
@ -545,7 +616,8 @@ function islandora_tokened_object_load($object_id, $map) {
if ($token) { if ($token) {
module_load_include('inc', 'islandora', 'includes/islandora_authtokens'); module_load_include('inc', 'islandora', 'includes/islandora_authtokens');
$token_user = islandora_validate_object_token($object_id, $map[4], $token); $token_user = islandora_validate_object_token($object_id, $map[4], $token);
islandora_get_tuque_connection($user = $token_user); $token_user = $token_user ? user_load($token_user->uid) : NULL;
islandora_get_tuque_connection($token_user);
} }
} }
return islandora_object_load($object_id); return islandora_object_load($object_id);

BIN
tests/fixtures/bug.jp2 vendored

Binary file not shown.

192979
tests/fixtures/testfixture_10001.xml vendored

File diff suppressed because it is too large Load Diff

94
tests/islandora_authtokens.test

@ -0,0 +1,94 @@
<?php
class IslandoraAuthtokensTestCase extends IslandoraWebTestCase {
public static function getInfo() {
return array(
'name' => 'Islandora Authorization Tokens',
'description' => 'Ensure the correct functionality of the tokens to pass authorization to Djatoka in Islandora.',
'group' => 'Islandora',
);
}
public function setUp() {
parent::setUp(array('islandora'));
}
public function testRedeemInvalidToken() {
module_load_include('inc', 'islandora', 'includes/islandora_authtokens');
// get a token
$token = islandora_get_object_token('test:pid', 'woot', 1);
$this->assertTrue($token, 'Token was generated correctly.', 'Unit Tests');
// redeem a token that doesn't exist with real pid and dsid
$account = islandora_validate_object_token('test:pid', 'woot', 'foo');
$this->assertFalse($account, 'Redeeming an token that doesn\'t exist returns FALSE', 'Unit Tests');
}
public function testRedeemValidToken() {
module_load_include('inc', 'islandora', 'includes/islandora_authtokens');
// change the current user
global $user;
$user_backup = $user;
$test_account = $this->drupalCreateUser();
$user = $test_account;
$token = islandora_get_object_token('test:pid', 'woot', 1);
// logout again
$user = $user_backup;
$token_account = islandora_validate_object_token('test:pid', 'woot', $token);
$this->assertEqual($token_account->uid, $test_account->uid, 'UID from token is correct', 'Unit Tests');
$this->assertEqual($token_account->pass, $test_account->pass, 'Pass from token is correct', 'Unit Tests');
$this->assertEqual($token_account->name, $test_account->name, 'Name from token is correct', 'Unit Tests');
}
public function testTokenedViewDatastreamWithoutXacml() {
// ingest the fixture
$fixture_path = drupal_get_path('module', 'islandora') . '/tests/fixtures/bug.jp2';
$tuque = islandora_get_tuque_connection();
$newpid = "{$this->randomName()}:{$this->randomName()}";
$fixture_object = $tuque->repository->constructObject($newpid);
$fixture_datastream = $fixture_object->constructDatastream('JP2');
$fixture_datastream->setContentFromFile($fixture_path, TRUE);
$fixture_object->ingestDatastream($fixture_datastream);
$tuque->repository->ingestObject($fixture_object);
$this->drupalGet("islandora/object/{$newpid}/datastream/JP2/view");
$this->assertResponse(403, 'Page not found as anonymous');
$account = $this->drupalCreateUser(array(FEDORA_VIEW_OBJECTS));
$this->drupalLogin($account);
$this->drupalGet("islandora/object/{$newpid}/datastream/JP2/view");
$this->assertResponse(200, 'Page loaded as the authorized user');
// do some voodoo to get a token as the user we are connecting as
// to do this we need to change the user we are logged in as
module_load_include('inc', 'islandora', 'includes/islandora_authtokens');
global $user;
$backup = $user;
$user = $account;
$token = islandora_get_object_token($newpid, 'JP2', 1);
$user = $backup;
$this->drupalLogout();
$this->drupalGet("islandora/object/{$newpid}/datastream/JP2/view", array('query' => array('token' => $token)));
$this->assertResponse(200, 'Page loaded with the token');
$this->drupalGet("islandora/object/{$newpid}/datastream/JP2/view", array('query' => array('token' => $token)));
$this->assertResponse(403, 'Token is unable to be reused');
// delete fixture object
$tuque->repository->purgeObject($newpid);
}
public function testTokenedViewDatastreamWithXacml() {
// we need to add this test.
}
}

36
tests/islandora_web_test_case.inc

@ -0,0 +1,36 @@
<?php
class IslandoraWebTestCase extends DrupalWebTestCase {
public function setUp() {
$args = func_get_args();
call_user_func_array(array('parent', 'setUp'), $args);
$islandora_path = drupal_get_path('module', 'islandora');
$this->config_info = parse_ini_file("$islandora_path/tests/test_config.ini");
$connection_info = Database::getConnectionInfo('default');
$this->original_drupal_fiter = file_get_contents($this->config_info['filter_drupal_file']);
$drupal_filter_dom = new DomDocument();
$drupal_filter_dom->loadXML($this->original_drupal_fiter);
$drupal_filter_xpath = new DOMXPath($drupal_filter_dom);
$server = $connection_info['default']['host'];
$dbname = $connection_info['default']['database'];
$user = $connection_info['default']['username'];
$password = $connection_info['default']['password'];
$port = $connection_info['default']['port'] ? $connection_info['default']['port'] : '3306';
$prefix = $connection_info['default']['prefix']['default'];
$results = $drupal_filter_xpath->query("/FilterDrupal_Connection/connection[@server='$server' and @dbname='$dbname' and @user='$user' and @password='$password' and @port='$port']/sql");
$results->item(0)->nodeValue = "SELECT DISTINCT u.uid AS userid, u.name AS Name, u.pass AS Pass, r.name AS Role FROM ({$prefix}users u LEFT JOIN {$prefix}users_roles ON u.uid={$prefix}users_roles.uid) LEFT JOIN {$prefix}role r ON r.rid={$prefix}users_roles.rid WHERE u.name=? AND u.pass=?;";
file_put_contents($this->config_info['filter_drupal_file'], $drupal_filter_dom->saveXML());
}
public function tearDown() {
file_put_contents($this->config_info['filter_drupal_file'], $this->original_drupal_fiter);
parent::tearDown();
}
}

4
tests/test_config.ini

@ -0,0 +1,4 @@
[fedora]
filter_drupal_file = "/usr/local/fedora/server/config/filter-drupal.xml"
admin_user = "fedoraAdmin"
admin_pass = "fedoraAdmin"
Loading…
Cancel
Save