Tin Can Integration Walkthrough
Concepts
Security and the Tin Can API
Each statement that comes into the Tin Can web service is evaluated for access rights before proceeding. The first thing that's determined is the "Asserter". The Asserter is essentially a combination of an Actor and a set of permissions. The Actor here is the person/system that is acting as the authority for the Tin Can statement being processed. When statements are being written, this Actor actually shows up as the authoritative source in the statement.
Tin Can security is fully customizable through new SCORM Engine Integration methods. If using basic authentication you will likely want to implement:
Actor TinCanGetAuthorityFromBasicAuth(TCAPIContext context, String username, String password);
The default implementation will only accept one username/password which has full authority. This username/password is defined by your SCORMEngineSettings.config entry named "TinCanRootAccount". This config entry has both the name and password separated by a colon. Ex: "joeadmin:mypass".
If using OAuth we already have a good default implementation so you probably won’t override this, at least initially..
What a particular user can do is defined by the Integration method TinCanGetPermissions().
We have defaults for the root user, a person(actor) and an application(actor). However, by overriding this integration method you can have fine-grained control to all permissions.
Auth
Authentication can be handled in Tin Can via Basic Auth or OAuth and is a necessity if you wish to handle Tin Can Statements from an activity not launched by your LMS. Going forward it's expected LMSs will want to track learning happening in places they were never able to track before. An example might be a learner's interactions with a forum inside the LMS. In order to record those interactions as statements in the LRS you will need to have some authentication set up. Integration methods are provided to allow you to tie both of these concepts into your existing system. An example scenario would be allowing a user's Single Sign On credentials to authenticate against your system, through the integration method. This will allow them to use those same credentials for LRS access as they use for other parts of the system. Additionally, you may want to provide special accounts to Activity Providers (like the forum software) so that you can always verify who is making the statement.
Permissions
You'll want to consider what permission level each individual account should have. The default permissions level allows customization across two primary areas:
- Statement Writing: By default a user is able to send any statement (About any Actor) and that user will be recorded as the Authority for that statement. The Authority is the person making the claim.
- Statement Reading: By default a user is able to ready any statement in which they appear. This includes as the Actor, Authority, Group member, instructor, etc.
Additionally, there is a Root permissions level. This level is what you'll want to use for third party applications you want to have the ability to both read and write any statements to or from the LMS. While it's unlikely you'll apply this permissions level to many, if any, third parties we've made the option available for your own systems.
Reporting
Understanding how you want to handle reporting on Tin Can data requires you to understand how you want to use Tin Can. For our customers that will be only using Tin Can content created as traditional courses launched by an LMS you don't need to do anything special. We will aggregate the data from those statements and send it to you via the same RollupRegistration Method we always have. The caveat with this approach is that this approach will focus entirely on the result object within the statement. This means we'll report on completion, success, score, and time as reflected in the result object and we will not depend on the verb for any meaning.
For people looking to record results data for Tin Can content not launched by the LMS you'll want to copy the statements out to a separate location via our TinCanStatementsStored Integration Method for in depth analysis.
If you just want to get the big 4 data (Pass, Completion, Score, Time), for those things we provide an extension to the Tin Can API to allow you to pull that aggregate data directly from the SCORM Engine. You can read more about this in the Tin Can /results API documentation
Content Auth
When we talk about Content Authorization and its relationship to Tin Can we're actually talking about the Tin Can addendum launch spec. The short version is that some Activity Providers may be launched, or initiated, by an LMS but end up taking place outside of the browser where handling content authorization for the content's resources becomes tricky. The easiest example would be a course that launched in a browser, detected it was on a mobile device, and then redirected to a mobile app. The mobile app needs to download the various resources inside the package such as images and videos. For most LMSs these resources are protected by a cookie, or some other authorization scheme, and the authorization mechanic is available to the browser. Once we've left the confines of the browser we have no way to pass cookies to something like a mobile application, and we wouldn't want to.
What we do pass, however, is the endpoint and credentials for accessing the LRS. With that data, and the full implementation of the spec referenced above, we're able to use the Tin Can endpoint as a way to proxy content files to the mobile application. This means that your content is still protected by your authentication scheme but can be made available to people with valid LRS credentials while they take your course.
Multi-Tenant
To make multi-tenant setups work correctly with Tin Can you'll want to use a different Tin Can API endpoint for each of your tenants. The SCORM Engine makes this easy to do. The SCORM Engine is prepared to parse out any value that appears between the Tin Can API and the method name being called and present that to the Integration layer as a way to distinguish which tenant is accessing the system and creating the correct external configuration object.
an example might be:
http://example.com/ScormEngine/TCAPI/examplecompany/statements
When accessing the resource above "examplecompany" will be passed to TinCanPostProcessContext where the Integration layer should convert the string "examplecompany" to both a unique value that can be used internally to fill the appId variable in the context object as well as a valid External configuration object. This value can then be used in all other integration methods where tenancy will be important. Internally, the SCORM Engine will use the concept of "AppId" as a way to track tenancy amongst the various Tin Can tables. Externally, you'll continue to use the External Configuration object to represent the data your system uses to determine individual tenants.
Some optional Tin Can extensions, such as the /results API, will require implementation of the integration method TinCanGetMultiTenantContexts. TinCanPostProcessContext can be used to construct this list of contexts, using the list of Tin Can API endpoints. This will be used to perform background processing using all of the possible ExternalConfiguration Obejcts your system depends on to inspect and transform the data for each of your customers/connection strings.
Config
In order to use Tin Can successfully in Engine, you’ll need to do a few things:
SystemHomepageUrl: Set a value for SystemHomepageUrl in SCORMEngineSettings.config. This is basically a way for actors created implicitly through LMS-style launches of Tin Can content to have a base URL. Typically, it will be your core service URL.
TinCanBasicAccounts: Set a value for TinCanBasicAccounts in SCORMEngineSettings.config. A non-public LRS must have some minimum level of authentication. Tin Can requires basic HTTP authentication and OAuth implementations in the LRS. Engine supports both. Engine also gives you a very lightweight mechanism to configure credentials for common HTTP auth accounts. An example use case is the built in Statement Viewer in the console dashboard. This tool requires at least one read only account be defined to authenticate with the endpoint. Similarly, the OAuth management page requires a root account be defined.
You can read the lengthy comment for this value in the SCORMEngineSettings.config that came with your Engine release for more information. More than likely, you can copy the default from the new config into your existing config and uncomment it, and it should work. That should be enough to get you up and running with Tin Can in console. If your setup is multi-tenant and you want an endpoint per, say, ClientId, then we might have a little more work to do.
ConvertTinCanFromScormRealtime: If you’d like to enable SCORM to Tin Can conversion for all registrations as they happen, set ConvertTinCanFromScormRealtime to true in your config. These statements will be piped through the relevant Tin Can Integration methods and can be interacted with from there.
ConvertTinCanFromScormHistorical: If you’d like to retroactively convert old SCORM registrations to Tin Can statements, set ConvertTinCanFromScormHistorical to true in your config.
Key Integration Methods
- TinCanBuildContext //multi tenant set appID
public TCAPIContext TinCanBuildContext(TinCanVersion version, ExternalConfiguration cfg, boolean isLaunchLink) throws Exception { MyExternalConfiguration myConfig = (MyExternalConfiguration)cfg); TCAPIContext ctx = super.TinCanBuildContext(version, cfg, isLaunchLink); ctx.setAppId(myConfig.TenantID); ctx.setSandbox(false); ctx.setOriginalAppId(myConfig.TenantID); return ctx; }
- TinCanPostProcessContext //multi tenant
public TCAPIContext TinCanPostProcessContext(TCAPIContext ctx, Map requestParameters, String extraEndpointInfo) throws Exception{ String tenantID = extraEndpointInfo; MyExternalConfiguration myConfig = (MyExternalConfiguration)ctx.getExternalConfiguration(); myConfig.TenantID = tenantID; ctx.setAppId(myConfig.TenantID); ctx.setSandbox(false); ctx.setOriginalAppId(myConfig.TenantID); return ctx; }
- TinCanStatementsStored
- TinCanAllowStatements
- TinCanGetAuthorityFromBasicAuth
- TinCanGetAuthorityFromOAuthCredentials
- TinCanGetPermissions
- TinCanHandleContentRequest
- CustomizeConvertedScormStatements
- TinCanGetMultiTenantContexts
Tin Can->SCORM Parity Reports
SCORM Parity Reports are an extension of the Tin Can API created by Rustici Software.
All Calls will return 40X if not authorized
Following are GET requests. Only GET will be supported at this time.
TCAPI/Report/results
This call requires Actor, Activity, or both. Sending neither will return nothing.
Returns 200 ok if successful returns code for not found if not found
Parameter | Required | Format | Description |
---|---|---|---|
agent | Optional | JSON | Represents the Actor object we're requesting data for. This will be passed to the integration layers GetPerson call first |
activity | Optional | String | Represents a particular Activity ID you'd like results for |
Example
Endpoint: http://example.com/TCAPI/Report/results
Request Body:
agent:{
"name": "Generic Example",
"account": {
"homePage": "http://example.com/ScormEngineInterface/",
"name": "gexample"
},
"objectType": "Agent"
}
Response JSON:
{
"results": [
{
"date": "2013-11-11T16:05:06.000Z",
"result": {
"score": {
"raw": 0.93
},
"success": true,
"completion": true,
"duration": "PT55S"
},
"actor": {
"name": "Generic Example",
"account": {
"homePage": "http://example.com/ScormEngineInterface/",
"name": "gexample"
},
"objectType": "Agent"
},
"activity": {
"id": "http://example.com/ScormEngineInterface/3",
"definition": {
"name": {
"en-US": "Golf Explained - Run-time Basic Calls"
}
},
"objectType": "Activity"
}
}
],
"more": "/TCAPI/results?continueToken=6FD79067CD90FBD9453E2D9F16F988EC8BBB2F11tincan/default/activities/1.0.x/6B1B0FB819C861F744536967883DCA7D79EA387C"
}
TCAPI/Report/activities
Returns 200 ok if successful
If No Actor is Sent all Activities will be returned
Parameter | Required | Format | Description |
---|---|---|---|
agent | Optional | JSON | Represents the Actor object we're requesting data for. This will be passed to the integration layers GetPerson call first |
Example
Endpoint: http://example.com/TCAPI/Report/activities
Response JSON:
{
"results": [
{
"objectType": "Activity",
"id": "http://example.org/GolfBasics",
"definition": {
"name": {
"en-US": "Golf Explained - Basics"
}
}
},
{
"objectType": "Activity",
"id": "http://example.org/GolfAdvanced",
"definition": {
"name": {
"en-US": "Golf Explained - Advanced Techniques
}
}
}
]
}
TCAPI/Report/actors
Returns 200 ok if successful returns code for not found if not found
If no Activity is sent all Actors will be returned. This does not include child activities or sub activities part of a group.
Parameter | Required | Format | Description |
---|---|---|---|
activity | Optional | String | Represents a particular Actor ID you'd like results for |
Example
Endpoint: http://example.com/TCAPI/Report/actors
Response JSON:
{
"results": [
{
"objectType": "Agent",
"name": "Learner One",
"account": {
"homePage": "http://example.org/",
"name": "lone"
}
},
{
"objectType": "Agent",
"name": "Learner Two",
"account": {
"homePage": "http://example.org/",
"name": "ltwo"
}
},
{
"objectType": "Agent",
"name": "Learner Three",
"account": {
"homePage": "http://example.org/",
"name": "lthree"
}
}
]
}
Tin Can Statement Forwarding
Statement Forwarding provides the means to automatically forward statements sent from one LRS to another. Applications include:
- Forwarding for users who wish to have their statements stored in their own Personal Data Lockers
- Replicating production data in a sandbox LRS
SCORMEngineSettings
Properties relevant to Statement Forwarding:
TinCanStatementForwardSleepTime
- In milliseconds, specifies how long the statement forwarding thread should sleep before polling the source LRSs for forwarding.TinCanStatementForwardMaxBackoffHours
- Upon failing to forward statements to a destination LRS, the statement forwarding will wait an exponentially increasing backoff before attempting a retry. This sets the maximum threshold for that backoff.TinCanStatementForwardStmtBatchSize
- Limit for gathering batches of statements for fowarding.TinCanStatementForwardWebTimeout
- Timeout (in milliseconds) for the HTTP requests gathering and posting the Tin Can statements.
Integration
For security, generate unique credentials for source and target Learning Record Stores
In order to configure statement forwarding, call ScormEngineManager::AddTinCanForwardingPath(ExternalConfiguration, StatementForwardingPair)
to add paths for forwarding between a source and destination LRS. StatementForwardingPair is a construct containing the following members
Member | Type | Description |
---|---|---|
SourceUrl | string | Contains the endpoint url/query for the source LRS. |
SourceCredentials | Credentials | Contains the credentials for accessing the source LRS |
DestinationUrl | string | Contains the endpoint url for the destination LRS. |
DestinationCredentials | Credentials | Credentials for the destination LRS. |
Id | string | Unique ID for this statement forwarding pair. |
The call will return the unique ID for the statement forwarding. Save this ID for future management of this statement forwarding pair and passing to ScormEngineManager::UpdateTinCanForwardingPath()
and ScormEngineManager::DeleteTinCanForwardingPath()
.