Best practices, tips and tricks

Best practices

Validate request parameters

itslearning will send a request to your application with parameters like ApiSessionId, UserId and Permissions. It is very important that you validate these parameters by comparing the Signature in the request with a signature you create from the given parameters and the SharedSecret. You should only accept the request if the signature in the request matches the signature you create. The signature is an MD5 hash of a string created from the concatenation of the application key, the shared secret, the session ID and the session timestamp. An example can be found in the SDK sample application (the SampleCommunicationHelper.ComputeHash function).

For for more information about verifying the signature, see the separate section further down on this page.

Filter input from user

Input from users (request parameters, form fields etc) must be filtered before you output it in a page or use it in code (look out for XSS and sql injections).

Use HTTPS

To keep data secure and to avoid Internet Explorer prompting the users about "viewing insecure content" you should serve your extension (including images) on a secure connection. If you don't, you risk IE users inadvertently choosing that they do not wish to load insecure content and thus won't be able to see parts of you extension.

Date and time

If you need to display date and time information, you should always display this in the user's time zone, use the parameter OlsonTimeZoneId or WindowsTimeZoneId. If you need to store date and time it is good practice to store this in UTC. E.g. deadlines are important to display correctly with the user's timezone taken into account.

Internationalization

Use the the Locale parameter sent from itslearning to set format for date time, numbers (decimal separator) etc, and use the Language parameter to display texts in user's preferred language (if you support it).

Session expiration

itslearning applications should handle session expiration. One option is to set session timeout to big value (for IIS 6.0 the maximum session timeout is 1440 minutes).

Another (better) solution is to keep session alive while user has an application page open. To do this you can make AJAX calls to a WebService every 10 minutes (if session timeout is set to 20 minutes). If an error occurs you can try to reduce the interval between the Web-service calls.

Example in javascript with jQuery:

$(document).ready(function() {setInterval(keepSessionAlive, 10*60);});function keepSessionAlive() {$.ajax({ type: "GET",url: "/Services/MyService.asmx/KeepAlive",error: function() { setTimeout(keepSessionAlive, 1*60); }});}

Problem with cookies in Internet Explorer (session expires)

Applications are executing in a FRAME which has some limitations. Internet Explorer blocks third party cookies by default so there might be a problem when using session state in the application.

A workaround might be to add a P3P header:

On each page, you could put:

<meta http-equiv="P3P" content='CP="CAO PSA OUR"'/>

or in Global.asax:

protected void Application_BeginRequest(object sender, EventArgs e){ HttpContext.Current.Response.AddHeader("p3p", "CP="CAO PSA OUR"");}

"P3P version 1.0 is a protocol designed to inform Web users about the data-collection practices of Web sites". Please take half a minute to read about the purpose of P3P and then what to include in your P3P header.

Safari also blocks third party cookies by default. Safari users must manually allow third party cookies in their browsers.

Use Session carefully

The same user may have several windows open in a browser window, to different instances. This means that you must not store parameters received in the URL (LearningObjectInstanceId, LearningObjectId) in Session.

Tips and howtos

How to access extended data

If you are developing extensions that should only be available for your own itslearning site, follow these steps:

  • In itslearning, go to Home > Administration > Manage apps > Extended data

  • Choose your Application, Plug-in or Module extension in the list and click Permit

images/download/attachments/10518887/ExtendedData2.png

If you are developing extensions that you want to make available for all itslearning customers or in selected countries, please send a mail to apps@itslearning.com.

Verifying the signature parameter

The request from itslearning to the extension contains a signature that can (should) be used to verify the authenticity of the message.

Calculating the signature for modules or plugins

Here's a sample scenario, that describes the process of verifying the signature. First, itslearning calls the extension:

A request from itslearning to a plugin
GET http://www.myitslextension.com:902/?itsl_auth=%7b%22TimeStamp%22%3a%222014-01-05T16%3a20%3a19%22%2c%22Country%22%3a%22NO%22%2c%22CustomerId%22%3a%221%22%2c%22EditReference%22%3a%22%22%2c%22EducationalLevel%22%3a%22Higher%22%2c%22FirstName%22%3a%22Admin%22%2c%22Language%22%3a%22en-US%22%2c%22LastName%22%3a%22Admin%22%2c%22OAuthToken%22%3a%2230093542-3827-4b61-b49a-f4914ffa8649%22%2c%22OAuthTokenSecret%22%3a%22822680ad-a438-4672-a009-e6e584a14f31%22%2c%22PersonId%22%3a%221%22%2c%22PostTo%22%3a%22https%3a%5c%2f%5c%2fwww.itslearning.com%5c%2feditor%5c%2fInsertPluginContentHtml.aspx%3fExtensionId%3d5006%26EditorClientInstanceId%3dctl00_ContentPlaceHolder_Description_DescriptionEditorCKEditor_ctl00%22%2c%22Role%22%3a%22Staff%22%7d&itsl_sign=7a52cb190b9d20db1f7f19d1946fc439 HTTP/1.1

Then, the contents of itsl_auth are URL-decoded:

Decoded contents of itsl_auth parameter
{"TimeStamp":"2014-01-05T16:20:19","Country":"NO","CustomerId":"1","EditReference":"","EducationalLevel":"Higher","FirstName":"Admin","Language":"en-US","LastName":"Admin","OAuthToken":"30093542-3827-4b61-b49a-f4914ffa8649","OAuthTokenSecret":"822680ad-a438-4672-a009-e6e584a14f31","PersonId":"1","PostTo":"https:\/\/www.itslearning.com\/editor\/InsertPluginContentHtml.aspx?ExtensionId=5006&EditorClientInstanceId=ctl00_ContentPlaceHolder_Description_DescriptionEditorCKEditor_ctl00","Role":"Staff"}

We assume, that the extension's shared secret is set to

Extension's shared secret used in the example
96002924-z56a-2369-z99z-5afdtt413ad9

Then, the base string for computing the signature is created, by concatenating contents of itsl_auth parameter and extension's shared secret:

{"TimeStamp":"2014-01-05T16:20:19","Country":"NO","CustomerId":"1","EditReference":"","EducationalLevel":"Higher","FirstName":"Admin","Language":"en-US","LastName":"Admin","OAuthToken":"30093542-3827-4b61-b49a-f4914ffa8649","OAuthTokenSecret":"822680ad-a438-4672-a009-e6e584a14f31","PersonId":"1","PostTo":"https:\/\/www.itslearning.com\/editor\/InsertPluginContentHtml.aspx?ExtensionId=5006&EditorClientInstanceId=ctl00_ContentPlaceHolder_Description_DescriptionEditorCKEditor_ctl00","Role":"Staff"}96002924-z56a-2369-z99z-5afdtt413ad9

Next, the MD5 hash is computed for the base string:

7a52cb190b9d20db1f7f19d1946fc439

Then, the MD5 hash is compared to the signatured, placed in itsl_sign parameter in the incoming request.

itsl_sign=7a52cb190b9d20db1f7f19d1946fc439

Since both values are equal, the signature is correct. It means that the request has not been tampered with and it comes from itslearning. That's because only itslearning and the extension itself know the value of the shared secret that is used to generate the incoming signature. The next step is to check if the request has not been repeated by a potential attacker. In order to do that, an arbitrary request expiration time should be introduced. After verifying the signature, the current date and time should be compared to the request's timestamp. If the difference does not exceed the expiration time, the request should be considered valid.

Calculating the signature for applications

The process of calculating the signature for applications is identical as for plugins or modules. The only difference is the base string. Instead of using contents of itsl_auth parameter, the base string is determined from the entire request URL:

https://www.myitslextension.com:3100/ViewRegistration.aspx?Accessibility=False&allowedhtmlcodelevel=LessRestricted&ApiSessionId=rundhq45ase1yne212uqpu55&ContextRole=Learner&CustomerId=1&email=johnsmith%40abc.com&Encoding=utf8&FirstName=Admin&Language=en-US&LastName=Admin&LearningObjectId=218&LearningObjectInstanceId=1216&Locale=nb-NO&OlsonTimeZoneId=Europe%2fOslo&Permissions=Read%2c+Participate%2c+Evaluate%2c+Modify&ReadOnly=False&Role=Staff&synckey=TheSyncKey&Use12HTimeFormat=False&UserId=2&Version=LatestOrDraft&WindowsTimeZoneId=Central+European+Standard+Time&Timestamp=2014-01-06T11:08:12&Signature=c2f593d119ade74d6077775a561eb7da

Then, the signature is removed:

https://www.myitslextension.com:3100/ViewRegistration.aspx?Accessibility=False&allowedhtmlcodelevel=LessRestricted&ApiSessionId=rundhq45ase1yne212uqpu55&ContextRole=Learner&CustomerId=1&email=johnsmith%40abc.com&Encoding=utf8&FirstName=Admin&Language=en-US&LastName=Admin&LearningObjectId=218&LearningObjectInstanceId=1216&Locale=nb-NO&OlsonTimeZoneId=Europe%2fOslo&Permissions=Read%2c+Participate%2c+Evaluate%2c+Modify&ReadOnly=False&Role=Staff&synckey=TheSyncKey&Use12HTimeFormat=False&UserId=2&Version=LatestOrDraft&WindowsTimeZoneId=Central+European+Standard+Time&Timestamp=2014-01-06T11:08:12

And the value is URL-decoded:

https://www.myitslextension.com:3100/ViewRegistration.aspx?Accessibility=False&allowedhtmlcodelevel=LessRestricted&ApiSessionId=rundhq45ase1yne212uqpu55&ContextRole=Learner&CustomerId=1&email=johnsmith@abc.com&Encoding=utf8&FirstName=Admin&Language=en-US&LastName=Admin&LearningObjectId=218&LearningObjectInstanceId=1216&Locale=nb-NO&OlsonTimeZoneId=Europe/Oslo&Permissions=Read, Participate, Evaluate, Modify&ReadOnly=False&Role=Staff&synckey=TheSyncKey&Use12HTimeFormat=False&UserId=2&Version=LatestOrDraft&WindowsTimeZoneId=Central European Standard Time&Timestamp=2014-01-06T11:08:12

Finally, the application's shared secret is appended to the string:

https://www.myitslextension.com:3100/ViewRegistration.aspx?Accessibility=False&allowedhtmlcodelevel=LessRestricted&ApiSessionId=rundhq45ase1yne212uqpu55&ContextRole=Learner&CustomerId=1&email=johnsmith@abc.com&Encoding=utf8&FirstName=Admin&Language=en-US&LastName=Admin&LearningObjectId=218&LearningObjectInstanceId=1216&Locale=nb-NO&OlsonTimeZoneId=Europe/Oslo&Permissions=Read, Participate, Evaluate, Modify&ReadOnly=False&Role=Staff&synckey=TheSyncKey&Use12HTimeFormat=False&UserId=2&Version=LatestOrDraft&WindowsTimeZoneId=Central European Standard Time&Timestamp=2014-01-06T11:08:1296002924-z56a-2369-z99z-5afdtt413ad9

The rest of the process is the same as for plugins and modules.

Sample code

To simplify the entire process for you, we have provided the code used to generate this signature below:

Below is example code for C#:

// take the raw json string and just append sharedsecret so it becomes "{json string}sharedSecret"
string itslAuthWithSharedSecret = string.Format(CultureInfo.InvariantCulture, "{0}{1}", itslAuthParamValuesJson, plugin.SharedSecret);
/* Below are the methods that compute the MD5 hash used in the signature (fromItslearning.Platform.RestApi.Sdk.Common.CryptographyHelper ).
Notice "encoding.GetBytes(input)". This interprets 'input' as the given encoding before getting the bytes representing the string. For ASCII characters the bytes are the same for UTF-8 and latin-1/Windows Codepage 1252 which are common encodings to use. When input contains non-ascii characters however different encodings will yield different bytes and thus different hashes which in turn will fail the signature validation. Again the encoding for validating the signature is UTF-8.
*/
 
public static string ComputeHash(string input)
{
    return ComputeHash(input, Encoding.UTF8);
}
   
[Obsolete("Use ComputeHash(string) for UTF-8")]
public static string ComputeHash(string input, Encoding encoding)
{
    var md5Hasher = new MD5CryptoServiceProvider();
    byte[] data = md5Hasher.ComputeHash(encoding.GetBytes(input));
    var sb = new StringBuilder();
 
    // Loop through each byte of the hashed data and format each one as a two digit hexadecimal string.
    for (int i = 0; i < data.Length; i++)
    {
    sb.Append(data[i].ToString("x2"));
    }
 
    return sb.ToString();
}

You need to interpret the characters in the URL as UTF-8 before verifying the signature (with SSOv2). This does not apply to legacy extensions using SSOv1

If you don't do this the signature will fail if non-ASCII characters are sent in the query string to your plugin.
E.g. for people with Norwegian special characters "æøå" in their names.

Troubleshooting

Manage menus

Page Administration > Manage apps > Manage menus > Add module

Problem

Possible reason

Administration > Manage apps > Manage menus tab is not visible

  1. Customer setting "Enable modules" is not turned on

  2. Profile setting "itslearning app management" is disabled

I have added a Module to the Developer portal, but I cannot see the Module when I browse the app library.

  1. Module has not been reviewed and made available by the Extension manager. When the Module has status ‘Draft’ or ‘In review’, it will only be visible for the user adding it to the developer portal

I have added a Module the the Manage apps > Add app page, but the Module does not appear in the location I have specified.

  1. Because menu contents are cached, there might be a delay before the module becomes visible. It should not take longer than 10 minutes

  2. You are logged on with a user who does NOT belong to the user group(s) the Module should be accessible to.

  3. You are logged on with a user who does NOT belong the the hierarchy the Module should be visible for.

Launching Modules

Problem

Possible reason

I get error message 'You are not authorized to view this page' when I try to launch a Module.

  1. Check if Module is set up in Developer portal to be available for all countries. If not, the country code for the itslearning site where you try to launch the Module must be part of the countries specified for the Module (in Developer portal)

  2. User trying to launch the Module does not have valid license.

Default availability for extensions

Page Administration > Manage apps > Default availability> Add application/Add plugin

Problem

Possible reason

Administration > Manage apps > Default availability tab is not visible

  1. Customer setting "Enable default availability for applications and plugins" is not turned on.

  2. Profile setting "itslearning app management" is disabled

I have added an application/plugin to the Developer portal, but I cannot see the application/plugin when I browse the app library.

  1. Application/plugin has not been reviewed and made available by the Extension manager. When the applicataion/plugin has status ‘Draft’ or ‘In review’, it will only be visible for the user adding it to the developer portal

I have added an application to the Manage apps > Default availability >Add application, but the application does not appear in the location I have specified.

  1. Because contents are cached, there might be a delay before the application becomes visible. It should not take longer than 10 minutes

  2. You are logged on with a user who does NOT belong to the user group(s) the applicaton should be accessible to.

  3. You are logged on with a user who does NOT belong the the hierarchy the application should be visible for.

  4. You are in a Course where the course is NOT connected to the hierarchy the appliation has been setup for (See Course > Settings > Course properties and feature)

  5. You are in the Library, but the application is NOT made sharable (setting 'Sharing supported' needs to be enable when you add applicaton to develope portal)

  6. User has manually removed the applicaton from the location. The application will then also be removed from all other location. User will then need to Browse app library to include the application again. Once removed or added manually will overwrite the Default availability settings.

I have added an plugin to the Manage apps > Default availability >Add plugin, but the plugin does not appear in the location I have specified.

  1. Because contents are cached, there might be a delay before the application becomes visible. It should not take longer than 10 minutes

  2. You are logged on with a user who does NOT belong to the user group(s) the plugin should be accessible to.

  3. You are logged on with a user who does NOT belong the the hierarchy the plugin should be visible for.

  4. You are in assignment /new assignment app or Test 2.0/Test 3.0. Here the Rich text editor might have problems recognising which hierarchy you are in - so it might fallback to the setup for the root hierarchy.

  5. User has manually removed the plugin from the location. The application will then also be removed from all other location. User will then need to Browse app library to include the plugin again. Once removed or added manualy will overwrite the Default availability settings.

Launching Applications/Plugins

Problem

Possible reason

I get error message 'You are not authorized to view this page' when I try to launch a Module.

  1. Check if application/plugin is set up in Developer portal to be available for all countries. If not, the country code for the itslearning site where you try to launch the application/plugin must be part of the countries specified for the application/plugin (in Developer portal).

  2. Check if application/plugin is set up in Developer portal to be available for all customers. If not, the customer/site where you try to launch the application/plugin from must be part of the countries specified for the application/plugin (in Developer portal).

  3. User trying to launch the application/plugin does not have valid license.