From 117394893824b950f8a8e78fe9cf20b185458f93 Mon Sep 17 00:00:00 2001 From: Jason MacWilliams Date: Thu, 22 Nov 2012 14:09:32 -0400 Subject: [PATCH 1/5] added schema for authentication tokens table --- islandora.install | 67 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/islandora.install b/islandora.install index c44c6418..630b8293 100644 --- a/islandora.install +++ b/islandora.install @@ -25,4 +25,69 @@ function islandora_uninstall() { module_load_include('inc', 'islandora', 'includes/solution_packs'); // uninstall callback islandora_install_solution_pack('islandora', 'uninstall'); -} \ No newline at end of file +} + +/** + * Implements hook_schema(). + * + * @return array + */ +function islandora_schema() { + $schema['islandora_authtokens'] = array( + 'description' => 'The hub for all islandora authentication tokens', + 'fields' => array( + 'id' => array( + 'description' => 'key', + 'type' => 'serial', + 'unsigned' => TRUE, + 'not null' => TRUE, + ), + 'token' => array( + 'description' => 'a unique identifier for this token', + 'type' => 'varchar', + 'length' => 64, + ), + 'uid' => array( + 'description' => 'the user id that requested this token', + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + ), + 'time' => array( + 'description' => 'when this token was created', + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + ), + 'pid' => array( + 'description' => 'the pid of the object this token unlocks', + 'type' => 'varchar', + 'length' => 128, + 'not null' => TRUE, + ), + 'dsid' => array( + 'description' => 'the datasteram id of the object this token unlocks', + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + ), + ), + 'unique keys' => array( + 'id' => array('id'), + ), + 'primary key' => array('id'), + ); + return $schema; +} + +/** + * Implements hook_update_N(). + * + * Add the required table for handling authtokens. + * This is the first instance that has this table. + */ +function islandora_update_7002(&$sandbox) { + drupal_install_schema('islandora'); + $t = get_t(); + return $t("Islandora database updates complete"); +} From 8610dc0313949920f1d4487a9b7104f2ddbc5d97 Mon Sep 17 00:00:00 2001 From: Jason MacWilliams Date: Thu, 22 Nov 2012 14:09:43 -0400 Subject: [PATCH 2/5] added handlers for creating and validating tokens --- includes/islandora_authtokens.inc | 52 +++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 includes/islandora_authtokens.inc diff --git a/includes/islandora_authtokens.inc b/includes/islandora_authtokens.inc new file mode 100644 index 00000000..b938b9d8 --- /dev/null +++ b/includes/islandora_authtokens.inc @@ -0,0 +1,52 @@ +uid . $pid . $dsid . $time); + + $id = db_insert("islandora_authtokens") + ->fields(array( + 'token' => $token, + 'uid' => $user->uid, + 'pid' => $pid, + 'dsid' => $dsid, + 'time' => $time, + )) + ->execute(); + return $token; +} + +function islandora_validate_object_token($pid, $dsid, $token) { + global $user; + // check for database token + $time = time(); + $result = db_select("islandora_authtokens", "id") + ->fields("id") + ->condition('token', $token, '=') + ->condition('uid', $user->uid, '=') + ->condition('pid', $pid, '=') + ->condition('dsid', $dsid, '=') + ->condition('time', $time, '<=') + ->condition('time', $time-TOKEN_TIMEOUT, '>') + ->execute() + ->rowCount(); + + //** this is for one-time use tokens **// + // remove the authtoken (if it exists) so it can't be used again + db_delete("islandora_authtokens") + ->condition('token', $token, '=') + ->condition('uid', $user->uid, '=') + ->condition('pid', $pid, '=') + ->condition('dsid', $dsid, '=') + ->execute(); + +// print_r($result); + return $result > 0; +} From 4d7e7e67bcd8a2ef82dfae1d8f0eb22f2a8e194b Mon Sep 17 00:00:00 2001 From: Jason MacWilliams Date: Thu, 22 Nov 2012 14:59:32 -0400 Subject: [PATCH 3/5] added tuque object to test if request is authorized before creating token --- includes/islandora_authtokens.inc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/includes/islandora_authtokens.inc b/includes/islandora_authtokens.inc index b938b9d8..c7393674 100644 --- a/includes/islandora_authtokens.inc +++ b/includes/islandora_authtokens.inc @@ -11,6 +11,19 @@ function islandora_get_object_token($pid, $dsid) { $time = time(); $token = hash("sha256", $user->uid . $pid . $dsid . $time); + //** check if this request is allowed **// + module_load_include("inc", "islandora", "includes/tuque"); + // test if this is a valid request + $validator = new IslandoraTuque($user); + try { + $result = $validator->connection->getRequest("objects/$pid/datastreams/$dsid/content", true); + } + catch (RepositoryException $rx) { + //print_r("authentication failed"); + return FALSE; + } + //** **// + $id = db_insert("islandora_authtokens") ->fields(array( 'token' => $token, @@ -46,6 +59,7 @@ function islandora_validate_object_token($pid, $dsid, $token) { ->condition('pid', $pid, '=') ->condition('dsid', $dsid, '=') ->execute(); + //** **// // print_r($result); return $result > 0; From 6683c3c70564b5c80760b55250a0e3fa89ddeab5 Mon Sep 17 00:00:00 2001 From: Jason MacWilliams Date: Tue, 27 Nov 2012 10:49:57 -0400 Subject: [PATCH 4/5] added function documentation --- includes/islandora_authtokens.inc | 47 +++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/includes/islandora_authtokens.inc b/includes/islandora_authtokens.inc index c7393674..d691a739 100644 --- a/includes/islandora_authtokens.inc +++ b/includes/islandora_authtokens.inc @@ -4,14 +4,24 @@ * @file */ +// Token lifespan: after this duration the token expires. define('TOKEN_TIMEOUT', 30000); +/** + * Request islandora to construct an object/datastream authentication token. + * This token can later be turned in for access to the requested object or + * datastream. + * @param string $pid + * @param string $dsid + * @return The generated authentication token. + */ function islandora_get_object_token($pid, $dsid) { global $user; $time = time(); $token = hash("sha256", $user->uid . $pid . $dsid . $time); - //** check if this request is allowed **// +/* optional block to check if this request is allowed +// CURRENTLY DISABLED module_load_include("inc", "islandora", "includes/tuque"); // test if this is a valid request $validator = new IslandoraTuque($user); @@ -22,7 +32,7 @@ function islandora_get_object_token($pid, $dsid) { //print_r("authentication failed"); return FALSE; } - //** **// +*/ $id = db_insert("islandora_authtokens") ->fields(array( @@ -36,31 +46,50 @@ function islandora_get_object_token($pid, $dsid) { return $token; } +/** + * Submit a token to islandora for authentication. Supply islandora with the + * token and the object/datastream it is for and you will receive access if + * authentication passes. Tokens can only be redeemed in a short window after + * their creation. + * @param string $pid + * The pid of the object to retrieve. + * @param string @dsid + * The datastream id to retrieve. + * @param string $token + * The registered token that allows access to this object. + * @return The user credentials for access if the token validation passes, + * FALSE otherwise + */ function islandora_validate_object_token($pid, $dsid, $token) { global $user; // check for database token $time = time(); - $result = db_select("islandora_authtokens", "id") - ->fields("id") + $query = db_select('islandora_authtokens', 'tokens'); + $query->join('users', 'u', 'tokens.uid = u.uid'); + $result = $query + ->fields('u', array('uid', 'name', 'pass')) ->condition('token', $token, '=') - ->condition('uid', $user->uid, '=') ->condition('pid', $pid, '=') ->condition('dsid', $dsid, '=') ->condition('time', $time, '<=') ->condition('time', $time-TOKEN_TIMEOUT, '>') ->execute() - ->rowCount(); + ->fetchAll(); //** this is for one-time use tokens **// // remove the authtoken (if it exists) so it can't be used again db_delete("islandora_authtokens") ->condition('token', $token, '=') - ->condition('uid', $user->uid, '=') ->condition('pid', $pid, '=') ->condition('dsid', $dsid, '=') ->execute(); //** **// -// print_r($result); - return $result > 0; + if ($result) { + return $result[0]; + } + else { + return FALSE; + } } + From a0044658e157543679ff59566f0906c75fa1b332 Mon Sep 17 00:00:00 2001 From: Jason MacWilliams Date: Tue, 27 Nov 2012 10:52:04 -0400 Subject: [PATCH 5/5] disabled test hooks, updated documentation --- islandora.module | 82 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 75 insertions(+), 7 deletions(-) diff --git a/islandora.module b/islandora.module index c12b034b..04185161 100644 --- a/islandora.module +++ b/islandora.module @@ -164,8 +164,11 @@ function islandora_menu() { 'access arguments' => array(2, FEDORA_ADD_DS) ); - $items['islandora/object/%islandora_object/datastream/%'] = array( + // this menu item has been modified to use a tokened version of islandora_object_load + // added load arguments to pass both pid and dsid to loader + $items['islandora/object/%islandora_tokened_object/datastream/%'] = array( 'title' => 'View datastream', + 'load arguments' => array(4), 'page callback' => 'islandora_view_datastream', 'page arguments' => array(2, 4), 'type' => MENU_CALLBACK, @@ -174,7 +177,8 @@ function islandora_menu() { 'access arguments' => array(2, FEDORA_VIEW), ); - $items['islandora/object/%islandora_object/datastream/%/view'] = array( + // this menu item has been modified to use a tokened version of islandora_object_load + $items['islandora/object/%islandora_tokened_object/datastream/%/view'] = array( 'title' => 'View datastream', 'type' => MENU_DEFAULT_LOCAL_TASK, ); @@ -208,7 +212,25 @@ function islandora_menu() { 'access callback' => 'islandora_access_callback', 'access arguments' => array(2, FEDORA_PURGE), ); +/* +// These are two test hooks that can be used to create and validate authentication tokens +// They are for debug purposes only and are currently disabled + $items['admin/islandora/get_object_token'] = array( + 'title' => 'Object Token', + 'page callback' => 'islandora_get_object_token', + 'access callback' => TRUE, + 'file' => 'includes/islandora_authtokens.inc', + 'type' => MENU_CALLBACK, + ); + $items['admin/islandora/validate_object_token'] = array( + 'title' => 'Validate Object Token', + 'page callback' => 'islandora_validate_object_token', + 'access callback' => TRUE, + 'file' => 'includes/islandora_authtokens.inc', + 'type' => MENU_CALLBACK, + ); +*/ return $items; } @@ -420,7 +442,6 @@ function islandora_view_object($fedora_object = NULL) { module_load_include('inc', 'islandora', 'includes/utilities'); global $user; - if (!$fedora_object) { return drupal_not_found(); } @@ -498,6 +519,57 @@ function islandora_object_load($object_id) { } } +/** + * A helper function to get a connection and return an object using a token for authentication. + * + * @param string $object_id + * @param string $datastream_id + * @return FedoraObject + */ +function islandora_tokened_object_load($object_id, $datastream_id) { + if (in_array('token', $_GET)) { + $token = $_GET['token']; + } + else { + $token = NULL; + } + + if ($token) { + module_load_include('inc', 'islandora', 'includes/islandora_authtokens'); + $tokenUser = islandora_validate_object_token($object_id, $datastream_id, $token); + + if ($tokenUser) { +// The following block is the same as the islandora_object_load function +// and we can probably just update the islandora_tuque static object and call +// islandora_object_load so we don't have to duplicate the function code + module_load_include('inc', 'islandora', 'includes/tuque'); + $islandora_tuque = &drupal_static(__FUNCTION__); + + if (!$islandora_tuque) { + $islandora_tuque = new IslandoraTuque($tokenUser); + } + + if (IslandoraTuque::exists()) { + try { + $fedora_object = $islandora_tuque->repository->getObject($object_id); + } catch (Exception $e) { + return NULL; + } + + drupal_alter('islandora_object', $fedora_object); + return $fedora_object; + } + else { + IslandoraTuque::getError(); + return NULL; + } +// + } + } + // By default, if no token is found, use original load function + return islandora_object_load($object_id); +} + /** * A helper function to get a connection and purge an object * @@ -634,7 +706,3 @@ function islandora_islandora_required_objects() { ); } - - - -