diff --git a/includes/islandora_authtokens.inc b/includes/islandora_authtokens.inc new file mode 100644 index 00000000..d691a739 --- /dev/null +++ b/includes/islandora_authtokens.inc @@ -0,0 +1,95 @@ +uid . $pid . $dsid . $time); + +/* 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); + 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, + 'uid' => $user->uid, + 'pid' => $pid, + 'dsid' => $dsid, + 'time' => $time, + )) + ->execute(); + 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(); + $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('pid', $pid, '=') + ->condition('dsid', $dsid, '=') + ->condition('time', $time, '<=') + ->condition('time', $time-TOKEN_TIMEOUT, '>') + ->execute() + ->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('pid', $pid, '=') + ->condition('dsid', $dsid, '=') + ->execute(); + //** **// + + if ($result) { + return $result[0]; + } + else { + return FALSE; + } +} + 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"); +} 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() { ); } - - - -