Writing a Basic LTI Tool Provider

This program is a demonstration of a simple functioning Basic LTI Tool Provider.

Setup

There are several steps for setup.

You are now set up, lets run the tool.

Running the Tool

To run the tool, we must use the fake IMS Basic LTI Consumer (i.e. the fake LMS).

The Program Structure

The basic flow of Basic LTI is that the LMS launches the tool with a number of POST parameters that are signed OAuth (www.oauth.net). Here is some sample parameters:

auth_version = 1.0
oauth_nonce = 6e92873834fb08b403971ddebab49e72
oauth_timestamp = 1267007863
oauth_consumer_key = 12345
resource_link_id = 120988f929-274612
resource_link_title = Weekly Blog
user_id = 292832126
roles = Instructor
lis_person_name_full = Jane Q. Public
lis_person_contact_email_primary = user@school.edu
context_id = 456434513
context_label = SI182
oauth_signature = pY6Fsej3ak+nr35FWySmmwIfazs=

If you look at the code in ads.php you can see the bit that intercepts this data and provisions the session and a variable called $context.

require_once '../ims-blti/blti.php';
require_once("db.php");
$context = new BLTI(array('table' => 'blti_keys'));
if ( $context->complete ) exit();
if ( ! $context->valid ) {
    print "Could not establish context: ".$context->message."\n";
    exit();
}
In this code, we import the Basic LTI code, set up the database connection, and establish the context. If you look at BLTI, it checks to see if this is a launch message by looking at the post parameters - if it is a launch, BLTI verifies the secret and sets up the context and stores the context in the PHP session. If the message is a normal (non-launch) message the context is restored from the session.

The context contains the information from the launch that can be used to identify the currently "logged-in" user and course so your application can support more than one school, course, and user as follows:

Data Base Structure

This is some sample data from the blti_keys table:

mysql> select id, oauth_consumer_key, secret, name from blti_keys;
+----+--------------------+--------+---------------+
| id | oauth_consumer_key | secret | name          |
+----+--------------------+--------+---------------+
| 32 | 12345              | secret | A Testing Key |
| 31 | admin              | secret | Adminitrator  |
+----+--------------------+--------+---------------+
And here is sample data from the ads table:
mysql> select id, course_key,user_key,title from ads;
+----+----------------------------+----------------------------+-----------------------+
| id | course_key                 | user_key                   | title                 |
+----+----------------------------+----------------------------+-----------------------+
|  6 | 12345:456434513            | 12345:292832126            | A Totally Sweet Title |
|  7 | 12345:456434513            | 12345:292832126            | Another Awesome Title |
|  8 | lmsng.school.edu:456434513 | lmsng.school.edu:292832126 | A TITLE               |
+----+----------------------------+----------------------------+-----------------------+
You will notice that in this simeple example, I have not normalized things like the users and course information. You will want to do a better job of modelling this information and using JOINs to reconstruct this information.

Authorization Strategy

A key to any multi-tenancy application is to show the correct data for the correct user/course/role combination. You can use a combination of the course_key, user_key, and whether the user is an instructor to create a simple Authorization mechanism using only SQL.

For example when the application is about to edit an advertisement using the following URL:

http://localhost/~csev/php-simple/adlist/ads.php?action=edit&id=7
It retrieves the old data using the following query is you are an instructor:
SELECT * FROM ads WHERE id='7' AND course_key='12345:456434513
And if you are a Learner (i.e. not an Instructor) the query is
SELECT * FROM ads WHERE id='7' AND course_key='12345:456434513 and user_key = '12345:292832126'
Using this technique, instructors can edit any ad, while students can only edit ads that belong to them.

If you look at the code that lists the ads, the following code decides if the Edit button is to be shown:

<php
if ( $context->isInstructor() || $row['user_key'] == $context->getUserKey() ) {
?>
     <a title="Edit" href="<self?>?action=edit&id=<row[id]?>">edit<a>
     <a title="Delete" href="<self?>?action=delete&id=<row[id]?>">delete<a>
<php
}
?>
The Edit button is always displayed if you are the instructor or if you are a student and the ad belongs to you.

Needed Improvements