Communication with the remote Application

Accessing the application

The extension system for Applications in itslearning uses its own system for providing SSO between itslearning and the remote web application.

Whenever a user creates a new application's instance in the course, itslearning passes data as a regular HTTP URI query string. The request is made to the add instance page, which URL is specified during registration of the application. The request can look as follows:

Raw HTTP request for creating an application instance
GET https://myitslearningextension.net/Add.aspx?Accessibility=False&allowedhtmlcodelevel=Everything&ApiSessionId=n0hsmdawswebjt2fqtap4n55&ContextRole=Administrator&CustomerId=14&email=testing%40hotmail.com&Encoding=utf8&FirstName=Admin&Language=en-GB&LastName=Admin&LearningObjectId=100947&LearningObjectInstanceId=110989&Locale=en-GB&mobile=%2b4798884148&OlsonTimeZoneId=Europe%2fOslo&Permissions=Read%2c+Participate%2c+Modify&ReadOnly=False&Role=Staff&synckey=adminSyncKey&Use12HTimeFormat=False&UserId=9&WindowsTimeZoneId=Central+European+Standard+Time&Timestamp=2014-01-16T15%3a18%3a07&Signature=ed57b0d15f35f81e6eef82b792685b41 HTTP/1.1

Likewise, when we open once created application's instance, there's another request sent, this time to the view page of the application. The query string is similar to the previous one:

Raw HTTP request for viewing the content of the application instance.
GET https://myitslearningextension.net/View.aspx?Accessibility=False&allowedhtmlcodelevel=Everything&ApiSessionId=n0hsmdawswebjt2fqtap4n55&ContextRole=Administrator&CustomerId=14&email=testing%40hotmail.com&Encoding=utf8&FirstName=Admin&Language=en-GB&LastName=Admin&LearningObjectId=100947&LearningObjectInstanceId=110989&Locale=en-GB&mobile=%2b4798884148&OlsonTimeZoneId=Europe%2fOslo&Permissions=Read%2c+Participate%2c+Modify&ReadOnly=False&Role=Staff&synckey=adminSyncKey&Use12HTimeFormat=False&UserId=9&WindowsTimeZoneId=Central+European+Standard+Time&Timestamp=2014-01-16T15:20:11&Signature=0051e5d979c5100b0c5333b766c32e18 HTTP/1.1

Query string parameters passed from itslearning to the application:

Parameter name

Sample value

Explanation

ApiSessionId

fjaklsajj23rfaaallcvj

Session id that must be used for communicating with itslearning rest api (used as part of Authorization header)

LearningObjectId

14345521

Numeric unique id of the learning object

LearningObjectInstanceId

15677744

numeric learning object instance id, identifies a unique use of the learning object (e.g. in a course)

UserId

556660

Numeric unique id for current user. No relation to PersonId from Plugins.

WindowsTimeZoneId

GMT Standard Time

Id of timezone that can be used in .net framework: TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById(windowsTimeZoneId)

OlsonTimeZoneId

Europe/London

Id of timezone on Olson format

FirstName

Bent Audun

First name of current user

LastName

Hesvik

Last name of current user

Locale

en-GB

Culture name that specifies e.g. date time format. RFC 1766 standard in the format "<languagecode2>-<country/regioncode2>") like used by Microsoft.NET Framework, seehttp://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo(vs.71).aspx

Language

en-GB

Culture name for current user's language. RFC 1766 standard in the format "<languagecode2>-<country/regioncode2>") like used by Microsoft.NET Framework, see http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo(vs.71).aspx

Use12hTimeFormat

False

True/False. True if user expects 12 hour format for times (7:00 PM) or False when user expects 24 hour time format (19:00).

Accessibility

False

True/False, if user has checked the accessibility setting in itslearning

Permissions

Read, Participate, 
Evaluate, Modify, ModifyInstance

Permissions user has to this particular learning object instance. Comma separated string.
Read - user is allowed to view the learning object
Participate (only avaliable for Learning Activity) - user is allowed to participate on learning object (e.g. submit answer)
Evaluate (only avaliable for Learning Activity) - user is allowed to evaluate (e.g. assess answers, view reports etc)
Modify - user is allowed to modify the learning object
ModifyInstance - Only applicable for applications that support sharing. User should be allowed to edit instance content stored in your application and also e.g. update deadline stored in itslearning (use rest api method). If your application supports sharing - the user will not have Modify permission when accessing an instance that is connected to a library "master" instance, even though user is author. Shared content must be edited from the library – and then Modify permission will be sent.

If "Read, Participate" is sent from itslearning, it means that the user can view learning object and e.g. submit answer, but should not be allowed to edit learning object or e.g. assess answers.

ContextRole

Admin

The role of the user in the current context (course). One of Admin, Instructor, Member, Learner

CustomerId

353

The customer the user request is coming from. Integer.

Role

Learner

The role that the user has in itslearning. Can be one of Staff, Learner, Guest. This parameter should not be used as a permission system, but rather to for example prevent Learner's from seeing parts of the application that you'd only like Staff users to see.

TimeStamp

2009-06-20T21:30:22

Time stamp in UTC

allowedhtmlcodelevel

The level of HTML the user is allowed to use.

HighlyRestricted (Only some basic tags are allowed)

Restricted (More tags are restricted)

LessRestricted (Some tags are restricted)

Everything (Everything is allowed)

ReadOnly

False

True/False. Can be send in specific cases to indicate a readonly state should be used e.g. preview option.

iscommonaddpageused

True

If "True" itslearning's common AddPage used. If "False" itslearning's common AddPage wasn't used. If application can't use itslearning's common AddPage, parameter won't be present.

Signature

A signature created from all of the above parameters and shared secret.

The signature is calculated by alphabetically ordering the query string parameters by their name [a-z] and creating an MD5 hash of it. The parameter values are URL encoded before signing (using the C# .NET method HttpUtility.UrlEncode(parameter.Value, Encoding.UTF8. ). A parameter called "SharedSecret" is included which holds the shared secret (Only for computing the signature. It is not sent in the query string.)

Example code to validate signature:

/// <summary>
/// Checks if the request signature is valid and the request is not expired.
/// </summary>
/// <param name="queryString"></param>
/// <param name="sharedSecret"></param>
/// <param name="requestLifetimeInMinutes"></param>
/// <param name="parameters"></param>
internal static void ValidateQueryString(string queryString, string sharedSecret, int requestLifetimeInMinutes, NameValueCollection parameters)
{
if (string.IsNullOrEmpty(queryString)) throw new ArgumentNullException("queryString");
if (string.IsNullOrEmpty(sharedSecret)) throw new ArgumentNullException("sharedSecret");
if (parameters == null) throw new ArgumentNullException("parameters");
// Check if timestamp is correct and within acceptable range
string timestampString = parameters["Timestamp"];
if (string.IsNullOrEmpty(timestampString))
{
throw new SecurityAccessDeniedException("Timestamp is not specified.");
}
DateTime timestamp;
if (
!DateTime.TryParse(timestampString, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal,
out timestamp))
{
throw new SecurityAccessDeniedException(
"Query string has an invalid timestamp(check that UTC time is passed and that server time is correct)");
}
timestamp = timestamp.ToUniversalTime();
if (timestamp < DateTime.UtcNow.AddMinutes(-requestLifetimeInMinutes) ||
timestamp > DateTime.UtcNow.AddMinutes(requestLifetimeInMinutes))
{
throw new SecurityAccessDeniedException(
"Query string has an invalid timestamp(check that UTC time is passed and that server time is correct)");
}
// Check signature
string signature = parameters["Signature"];
if (string.IsNullOrEmpty(signature))
{
throw new SecurityAccessDeniedException("Signature is not specified.");
}
// Remove signature from the querystring
queryString = HttpUtility.UrlDecode(queryString);
string queryStringWithoutSignature =
queryString.Replace(string.Format("&Signature={0}", signature), string.Empty);
if (ComputeHash(queryStringWithoutSignature + sharedSecret) != signature)
{
throw new SecurityAccessDeniedException("Signature is invalid.");
}
}
 
/// <summary>
/// Calculates MD5 of the string.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
internal static string ComputeHash(string input)
{
var md5Hasher = new MD5CryptoServiceProvider();
byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));
var sb = new StringBuilder();
// Loop through each byte of the hashed data and format each one as a hexadecimal string.
for (int i = 0; i < data.Length; i++)
{
sb.Append(data[i].ToString("x2"));
}
return sb.ToString();
}

The following parameters are extended data:

Extended data will only be passed as query string parameters if the app has been approved by a site admin to receive such data.

email

Person email address.

mobile

Person mobile phone.

synckey

Person synchronization key.

custom1id

Custom field 1 name used on the site .

custom1

Custom field 1 value for the person.

custom2id

Custom field 2 name used on the site.

custom2

Custom field 2 value for the person.

custom3id

Custom field 3 name used on the site.

custom3

Custom field 3 value for the person.

custom4id

Custom field 4 name used on the site.

custom4

Custom field 4 value for the person.

custom5id

Custom field 5 name used on the site.

custom5

Custom field 5 value for the person.

Deleting a remote instance of the application

Deletion workflow

When an application instance is permanently deleted from itslearning, the URL which is registered as "Delete instance URL" is called.

Your application needs to handle the call by marking the LearningObjectInstance and/or LearningObject as deleted and send the response with code "OK" (200).

If the delete operation takes a long time (delete files, communicate with external systems, etc.), you can only mark your instance as deleted and delete asynchronously.

If the application experiences any difficulties when deleting or marking an instance as deleted, it can return an error and write a problem description into a response. If this is the case, a request will be sent again.

Query string parameters passed on deletion:

Here's sample HTTP request from itslearning to the application sent upon deleting:

Raw HTTP request for deleting the application instance.
GET https://myitslearningextension.net:2080/Delete.ashx?LearningObjectId=5&LearningObjectInstanceId=32&SafeToDeleteLearningObject=True&Timestamp=2014-01-17T13:08:36&Signature=af06dbc4aebfbc9461c5b8bc03696df4 HTTP/1.1
Host: myitslearningextension.net:2080
Connection: Keep-Alive

The parameters explained:

Parameter name

Sample value

Explanation

LearningObjectId

14345521

Numeric unique id of the learning object

LearningObjectInstanceId

15677744

Numeric learning object instance id, identifies a unique use of the learning object (e.g. in a course)

SafeToDeleteLearningObject

True

Use this parameter to identify if it is safe to delete shared content. It is set to True when the last learning object instance is deleted, which indicates that it is now safe to delete the learning object.

This means if a test is shared between several courses, the parameter will be False when one instance is deleted from one of the course. This means you can only delete test results for that particular instance, but not test content (description, questions) or results from other instances. Only when the test is deleted from the last course will this be set to True, which means it's safe to delete all content and data on your side. See more details about this below.

TimeStamp

2009-06-20T21:30:22

Time stamp in UTC

Signature

A signature created from all of the above parameters and shared secret

Deleting shared instances

If your application supports sharing, your learning objects can have multiple instances. For example, you have a test, which is shared with several courses, which means you have a multiple number of learning object instances per learning object. It can be so that not all instances are deleted, so an application needs to determine, if a learning object needs to be deleted or not.

For such purposes there is a parameter called "SafeToDeleteLearningObject". This parameter is transferred through the SSO between itslearning and the application and shows if it’s safe to delete the learning object itself (which means all learning object instances are already deleted). Applications, that don’t support sharing, are always receiving SafeToDeleteLearningObject=True, because there's always one learning object instance per learning object.

Example 1 (Single learning object):

Instance in itslearning and application:
LearningObjectId=1530
LearningObjectInstanceId=9975

The delete request URL: http://mydomain.com/yourapplication/deleteinstance.ashx?LearningObjectId=1530&LearningObjectInstanceId=9975&SafeToDeleteLearningObject=True
The application can easily delete the learning object and its instance.

Example 2 (Shared learning object):

Instance in library:
LearningObjectId=2250
LearningObjectInstanceId=8130

Shared instance 1 in course:
LearningObjectId=2250
LearningObjectInstanceId=8255

Shared instance 2 in course:
LearningObjectId=2250
LearningObjectInstanceId=8512
Instance 2 has been deleted from itslearning.

The delete request URL will be: http://mydomain.com/yourapplication/deleteinstance.ashx?LearningObjectId=2250& LearningObjectInstanceId=8512& SafeToDeleteLearningObject=False

The application should delete all the data connected to the learning object instance 8512, but keep the learning object itself (LearningObjectId=2250) as well as remaining learning object instances 8130 and 8255

Some tips on how to implement delete functionality

  • Check the signature in the same way as with add and view instance pages to make sure the delete request comes from itslearning.

  • Do not try to delete everything in synchronous mode. If the delete operation takes a long time (more than several seconds), itslearning will reset the connection and try to send the delete request once more. A good way is to mark the existing learning object and/or learning object instance for deletion and send the "OK" response. The deletion itself can be done asynchronously.

  • Return error responses when you need the delete request to be sent once more (e.g. the application is unable to mark object/instance for deletion). If you receive a request to delete an already deleted learning object/instance, just do nothing and return the "OK" response.