Skip to content

Learning Tools Interoperability

O que é?

A Interoperabilidade das ferramentas de aprendizagem é uma iniciativa gerenciada pelo IMS Global Learning Consortium que integra perfeitamente os aplicativos de aprendizagem usados pelos instrutores nos cursos. Inclui um protocolo padrão para estabelecer um relacionamento de confiança entre o provedor da ferramenta e o Sistema de Gerenciamento de Aprendizagem, para que alunos e professores possam ter uma experiência perfeita e integrada ao usar a ferramenta no contexto do curso. Para saber mais, consulte o artigo sobre LTI do IMS Global Learning..

Hub Educacional - Integração com o Padrão LTI 1.0

A integração ao Hub Educacional permite que usuários de diversas escolas possam acessar suas ferramentas educacionais parceiras a partir de uma plataforma centralizada, com um único acesso - Single Sign On (SSO). O Hub obtém essa funcionalidade através da implementação da funcionalidade de Inicialização do padrão LTI (LTI Launch). A ferramenta deve implementar um endpoint POST seguro por OAuth1 para receber requisições de inicialização. Quando um usuário do sistema solicita a inicialização de uma aplicação, o Hub constrói, e assina uma mensagem LTI, que é enviada para o endpoint de inicialização da aplicação. Após as validações necessárias, a ferramenta deve exibir os recursos para o usuário.

Este documento servirá como apresentação do padrão de integração e como um guia de implementação.

Para a escrita deste documento e implementação do parão LTI, o time do Hub Educacional utilizou o documentação da Especificação e Guia Implementação LTI 1 oficial disponibilizado pela IMS Global Learning Consortium.

Além disso o guia de Melhores práticas LTI e também a página Inicialização Básica LTI: Parâmetros do POST podem auxiliar no processo de implementação.

Conteúdo

Integração da Ferramenta ao Hub Educacional

Dados do aplicativo

Após a confirmação do cadastro da Edtech, o respectivo responsável deve cadastrar sua ferramenta no Hub em área reservada [Em desenvolvimento]. A Edtech poderá adicionar uma ou mais ferramentas. Para ter sua ferramenta integrada, a Edtech deve compartilhar algumas informações básicas mínimas sobre a aplicação. As informações mínimas são as seguintes:

Título: Título/Nome da ferramenta exibido no card da galeria. \ Descrição Curta: Descrição da ferramenta exibida no card da galeria. \ Logo: Imagem exibida no card da galeria. \ Descrição Longa: Texto apresentado no detalhamento da ferramenta. \ Site: URL para site da Edtech ou da ferramenta.

Dados da inicialização LTI

LTI utiliza OAuth1 como framework de segurança para validar as requisições de inicialização. A Edtech deverá cadastrar o Hub Educacional como cliente OAuth1 na sua aplicação e informar ao Hub as credenciais OAuth necessárias para que a comunicação LTI. As informações são as seguintes:

Id do cliente (client id/oauth_consumer_key): Identificação do Cliente OAuth gerada pela ferramenta (servidor OAuth1) e utilizada pelo Hub para identificação das mensagens. \ Segredo Compartilhado (shared_secret): Uma chave secreta, informada pela ferramenta (servidor OAuth) utilizada para assinar a mensagem LTI. \ LTI Launch Endpoint: O endereço da interface de inicialização LTI. Deve atender as especificações básicas da LTI v1.0, apresentadas nesse documento na seção Endpoint de inicialização LTI - POST /launch (Implementação).

Padrão LTI 1.0

LTI é um padrão criado pela IMS Global Learning Consortium para atender a demanda de integração de aplicações ou funcionalidades de terceiros a sistemas, usualmente sistemas de gestão escolar. A funcionalidade mais utilizada do LTI, e talvez a principal delas, é a inicialização LTI ou LTI Launch, que permite que uma ferramenta seja inicializada de forma segura a partir de uma outra plataforma. Esse é o padrão utilizado para que o Hub inicialize as ferramentas educacionais integradas.

Para segurança da comunicação entre a plataforma e a ferramenta, LTI utiliza o padrão OAuth1. Uma ferramenta LTI deve disponibilizar um

Terminologias

Consumidor de Ferramentas (Tool Consumer) ou Plataforma: É usualmente um Sistemas de Gestão Escolar, entretanto pode ser qualquer sistema que consuma uma ferramenta ou uma funcionalidade de uma aplicação de terceiro. Ex.: Hub Educacional. \ Provedor de Ferramentas (Tool Provider): Aplicativo ou Ferramenta que provê uma funcionalidade, usualmente uma ferramenta educacional. Ex: Ferramenta de ensino da Edtech. \ Chave do cliente (consumer key): Chave utilizada para identificação do cliente na requisição OAuth1. \ Segredo Compartilhado (shared secret): Na comunicação LTI, o Hub utiliza o segredo compartilhado para assinar a mensagem de inicialização, do outro lado, a ferramenta utiliza o segredo para validar a assinatura da mensagem. \ Contexto (context): Uma aplicação educacional pode ser composta por vários recursos como turmas, aulas, avaliações, por exemplo, em que o utilizador (aluno, professor, gestor, etc) pode ter acesso. Quando um desses recursos é instanciado, ou apresentado para o usuário, entende-se que este é o contexto em que o recurso da ferramenta está sendo utilização. Em outras palavras, o contexto indica em que recurso a ferramenta deverá ser inicializada. \ Identificador de Recurso (resource link id): É o link ou identificação do contexto da inicialização do recurso da aplicação, em outras palavras, é o campo que identifica a inicialização. Para cada recurso da aplicação podem haver multiplos identificadores de recurso associados, entretanto, cada identificador deve ser tratado de forma única, por exemplo, se uma ferramenta disponibiliza um recurso de bate-papo, cada identificador do recurso seria uma sala diferente.

Requisição de Inicialização LTI

Para que a ferramenta seja inicializada a partir do Hub, o Hub constrói e assina uma mensagem LTI,

  • Hub cria, assina e envia o pacote de inicialização é enviada através do navegador do usuário via HTTP POST.
  • Dados são passados através dos parâmetros da requisição POST.
  • Parâmetros podem incluir dados sobre contexto da inicialização, identificação do usuário, papel do usuário, entre outros.
  • Conexão é assegurada pelo padrão OAuth1 por nonce, timestamp e assinatura.

Segurança (OAuth1)

LTI 1.0 é construído sobre o padrão de segurança OAuth1 para verificação da autenticidade da mensagem de inicialização LTI. Como segue a definição, a comunicação OAuth1 no endpoint de inicialização necessita que o Hub seja identificado como cliente OAuth1 da ferramenta, para isso a ferramenta deve cadastrar o Hub em seu servidor OAuth1 e informar ao Hub os dados gerados, client id e shared secret, o Hub usa essas informações para assinar a mensagem LTI. OAuth1 é um padrão de segurança amplamente conhecido e utilizado, como o foco deste documento não é entrar em detalhes do padrão OAuth1, acesse https://oauth.net/1/ para mais informações. Consulte também as documentações LTI.

Endpoint de inicialização LTI - POST /launch (Implementação)

Especificações

O endpoint de inicialização LTI deve ser implementado pela ferramenta seguindo as especificações do padrão LTI encontradas no documentos da Especificação e Guia Implementação LTI 1. O endpoint básico tem atende as seguintes configurações:

  • Endpoint HTTP com suporte ao método POST
  • Endpoint deve verificar assinatura OAuth1
  • Função deve validar os parâmetros LTI recebidos via formulário, Content-Type: application/x-www-form-urlencoded.

Parâmetros básicos obrigatórios:

LTI A requisição é construída, assinada e enviada pelo Hub. O padrão LTI prevê os seguintes atributos como obrigatórios para a mensagem básica. Esses campos identificam o tipo da mensagem, a versão do protocolo e o recurso solicitado, além da identificação do requisitante através dos atributos OAuth, entretanto, muitos outros atributos podem ser passados, como identificação do usuário, pepel do usuário no sistema e outros. Abaixo está descrito a lista de parâmetros básicos para a mensagem LTI 1.0, para uma lista contendo os parâmetros recomendados e opcionais, consulte: https://www.eduappcenter.com/docs/basics/post_parameters

LTI \ lti_message_type: valor deve ser basic-lti-launch-request \ lti_version: valor obrigatório LTI-1p0 \ resource_link_id: a identificação do recurso configurada pelas instituições é enviada nesse campo.

OAuth1 \ oauth_consumer_key: Identificador OAuth1 do Hub na ferramenta. \ oauth_signature_method: Método usado para a assinatura. Hub utiliza HMAC-SHA1 para assinatura. \ oauth_timestamp: Horário atual Unix da consumidora (Plataforma Hub). \ oauth_nonce: Um valor único para a requisição. \ oauth_version: Deve ter valor 1.0. \ oauth_signature: Assinatura da mensagem gerada com o segredo compartilhado. \ oauth_callback: Endereço de retorno da ferramenta, que é o site a ser acessado ao sair da ferramenta. Esse campo não é utilizado no padrão LTI, entretanto Hub irá enviar o endereço da sua homepage apenas para ficar de acordo com o padrão OAuth1.

Recebendo uma Requisição de Inicialização LTI

\ lti_message_type: valor deve ser basic-lti-launch-request \ lti_version: valor obrigatório LTI-1p0 \ resource_link_id: a identificação do recurso configurada pelas instituições é enviada nesse campo.

Exibição dos recursos após Inicialização LTI válida

Após verificação, se a mensagem de inicialização for validada, a ferramenta deve retornar os recursos solicitados para o usuário. A forma de apresentação dos recursos varia de aplicação para aplicação. É muito provável que sua aplicação tenha sua própria gestão de usuários e autenticação, neste caso você deve implementar todas as etapas necessárias para a exibição final do recurso para o aluno ou usuário, por exemplo: * Levantamento de sessão do usuário * Instanciamento da aula/prova/curso * Etc

Usualmente, os recursos são retornados em forma de página HTML com aula, curso, ou outro recurso, para utilização do usuário.

Implementações

Alguns exemplos de ferramenta estão disponíveis. Entre em contato com o time do Hub Educacional.

Hub Educacional - Exemplo de Ferramenta LTI (Node)

Implementação (Provedor de Ferramenta LTI)

A implementação desse projeto deve como diretrizes os seguintes documentos: Guia de implementação LTI, Melhores práticas LTI e o auxílio de Inicialização Básica LTI: Parâmetros do POST. Use esses documentos como referência para sua aplicação.

Esse exemplo foi escrito em Node + Express para prover o endpoint de inicialização LTI (POST /launch) utilizando a biblioteca ims-lti para verificação LTI e OAuth1. Abaixo seguem os tópicos que serão abordados:

  • Implementação (Provedor de Ferramenta LTI)
  • Verificação OAuth1 e validação da mensagem de inicialização LTI 1.0
  • Instalação
  • Executando o app (Provedor de Ferramenta LTI)
  • Biblioteca ims-lti

Estrutura do projeto

Essa é a árvore de arquivos desse projeto:

1
2
3
4
5
6
.
├── app.js
├── ltiTool.js
├── package.json
├── package-lock.json
└── README.md
O arquivo app.js é o código da nossa aplicação Express, aqui está um código bem simples que define o endpoint de inicialização LTI (POST /launch) para a função LTI1p0BasicLaunch() do arquivo ltiTool.js que trata da verificação da mensagem básica LTI de inicialização. A função LTI1p0BasicLaunch() utiliza a biblioteca ims-lti para realizar a verificação OAuth1 e as validações da mensagem LTI. No arquivo ltiTool.js está definido também o o objeto EmulatedClientDB = {} que irá emular uma base de dados de clientes OAuth1. Note que em uma aplicação real é muito provável que essa base de clientes seja um RDBMS ou um banco de dados NoSQL. No próximo item será explicado o processo e verificação OAuth1 e LTI.

Verificação OAuth1 e validação da mensagem de inicialização LTI 1.0

No arquivo ltiTool.js você verifica a definição do endpoint e da função LTI1p0BasicLaunch(). Essa função implementa to tratamento da verificação e validação da mensagem de inicialização LTI 1.0 feita pela biblioteca ims-lti.

O código abaixo mostra uma implementação simplificada, porém funcional, da validação e verificação da mensagem LTI recebida (A seguir será explicado o passo a passo das partes mais importantes dessa função):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// Mensagem Básica de Inicialização LTI 1.0
// Tratamento da Requisição
function LTI1p0BasicLaunch (req, res) {
  // Recupera client_secret pelo id do cliente(oauth_consumer_key)
  let client_id = req.body["oauth_consumer_key"];
  if (client_id) {
    let client_secret = EmulatedClientDB[client_id];

    // Após encontrar os dados do cliente
    // É instanciado um objeto lti.Provider com os dados do cliente
    const provider = new lti.Provider(client_id, client_secret);

    // lti.Provider.valid_request() realiza a validação tanto da assinatura OAuth1
    // quanto dos parâmetros LTI da mensagem
    provider.valid_request(req, (err, is_valid) => {
      let response;
      // Caso a validação falhe, retorna erro com o motivo.
      if (err) {
        console.log('error:', err);
        response = {
          ...err,
          body: req.body
        }
        res.send(response, 401);
      }
      // Caso a mensagem seja válida, retorna sucesso para o cliente.
      if (is_valid) {
        console.log('is valid:', is_valid);
        response = {
          message: 'Passou! Mostrar recurso privado!',
          body: req.body
        }
        res.send(response);
      }
      });
  }
  // Código modificado para simplificação
}

Em resumo, a função LTI1p0BasicLaunch() realiza os seguintes passos:

1
2
3
4
5
1. Recupera client_secret a partir do id do cliente.
2. Instancia um objeto lti.Provider com os dados do cliente (client_id, client_secret).
3. Valida a mensagem com provider.valid_request. Se válido (OAuth1 Ok e Mensagem LTI Ok),
 a. Prepara o recurso autenticado e retorna para o usuário/Retorna Sucesso.
 b. Caso contrário, não exibir recurso privado para o requisitante/Retorna Falha.

Neste código simplificado, caso a mensagem LTI seja verificada, o recurso mostrado é apenas Passou! Mostrar recurso privado! com código 200, ou uma mensagem de erro com código 401 caso contrário. No código implementado algumas informações extras são apresentadas, como os parâmetros lidos e mensagens de erros mais explicativas para facilitar testes, mas seguem o mesmo padrão apresentado aqui.

IMPORTANTE Fique ciente, entretanto, que a forma de apresentação dos recursos privados varia de aplicação para aplicação e que esse é somente um exemplo. É muito provável que sua aplicação tenha sua própria gestão de usuários e autenticação, neste caso você deve implementar todas as etapas necessárias para a exibição final do recurso para o aluno ou usuário, como levantamento de sessão do usuário, alocação de recursos, redirecionamentos de páginas necessários, etc.

Instalação

Antes de testar instale os requisitos:

1
$ npm install

Executando o app (Provedor de Ferramenta LTI)

Na raiz do projeto:

1
$ npm start
ou,
1
$ node app

Biblioteca ims-lti

LTI 1.0 é construído sobre o padrão de segurança OAuth1 para autorização e autenticação. Nesse exemplo é utilizada a biblioteca ims-lti que já implementa uma verificação de assinatura OAuth1, além da validação LTI. Caso sua aplicação já tenha sido construída sobre OAuth1, analise se pode reaproveitar a base de dados para clientes OAuth e caso queira realizar somente as validações LTI, pode começar verificando a implementação da biblioteca. Caso sua aplicação seja ou será escrita em outro framework, apenas adapte o provider.valid_request para seu produto.

Hub Educacional - Exemplo de Ferramenta LTI (Python)

Implementação (Provedor de Ferramenta LTI)

A implementação desse projeto deve como diretrizes os seguintes documentos: Guia de implementação LTI, Melhores práticas LTI e o auxílio de Inicialização Básica LTI: Parâmetros do POST. Use esses documentos como referência para sua aplicação.

Esse exemplo foi escrito em Python + Flask para prover o endpoint de inicialização LTI (POST /launch) utilizando a biblioteca Authlib como servidor OAuth1. Abaixo seguem os tópicos que serão abordados:

  • Estrutura do Projeto
    • Implementação (Provedor de Ferramenta LTI)
    • Verificação OAuth1 e validação da mensagem de inicialização LTI 1.0
    • Detalhes adicionais
  • Instalação
  • Executando o app (Provedor de Ferramenta LTI)
  • OAuth1 Server (Authlib)

Estrutura do projeto

Essa é a árvore de arquivos desse projeto:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
.
├── README.md
├── requirements.txt
└── src
    ├── app.py
    ├── lti1p0
       ├── errors.py
       ├── __init__.py
       └── provider.py
    ├── templates
       └── message_params.html
    └── utils
        ├── cache.py
        └── oauth1_server.py

No diretório src, o arquivo app.py é o código da nossa aplicação Flask, aqui está definido o endpoint de inicialização LTI (POST /launch) na função launch() e onde é realizada a verificação OAuth1 e as validações da mensagem LTI de inicialização. Na próximo item será explicado o processo e verificação OAuth1 e LTI.

No diretório lti1p0 estão os códigos relacionados ao LTI 1.0. No arquivo provider.py está a implementação das validações de inicialização básica do LTI 1.0. No arquivo errors.py econtram-se algumas de erros relacionados ao protocolo.

Em utils estão os arquivos oauth1_server.py e cache.py relativos ao servidor OAuth1.

O arquivo templates/message_params.html é o template html utilizado nesse exemplo para exemplificar um recurso e exibir o estado da solicitação de inicialização.

Verificação OAuth1 e validação da mensagem de inicialização LTI 1.0

No arquivo app.py você verifica a definição do endpoint e da função launch(). Nessa função é implementada a funcionalidade mais importante desse projeto: Verificação e validação da mensagem de inicialização LTI 1.0.

O código abaixo mostra uma implementação simplificada, porém funcional, da validação e verificação da mensagem LTI recebida (A seguir será explicado o passo a passo das partes mais importantes dessa função):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
## Código modificado para simplificação
@app.route('/launch', methods=['POST'])
def launch():
    verified = False
    try:
        # Valida requisição OAuth1
        oauth1_request = server.create_oauth1_request(request)
        server.validate_temporary_credentials_request(oauth1_request)

        # Verifica pacote de inicialização básica LTI 1.0
        launch = LTILaunchForm(request.form)
        LTILaunchForm.validate_lti_launch(launch)

        verified = True
    except (OAuth1Error, LTIError) as error:
        # Tratamento de erro
        pass

    # Prepara o recurso e a resposta da requisição
    if verified:
        # Se verificado, prepara o recurso para retornar ao usuário
        response = 'Passou! Mostrar recurso privado!'
        status_code = 200
    else:
        # Caso contrário, prepara mensagem de erro
        response = 'Autenticação falhou!'
        status_code = 401

    # Retorna resposta
    return response, status_code

Em resumo, a função launch() realiza os seguintes passos:

1
2
3
4
5
1. Verifica se a requisição OAuth1 é válida (cliente válido - hub -, assinatura válida, timestamp, nonce, etc)
2. Verifica se a requisição é uma mensagem LTI válida (lti_message_type=basic-lti-launch-request, lti_version=LTI-1p0, resource_link_id presente, etc).
3. Se válido (OAuth1 Ok e Mensagem LTI Ok),
 a. Prepara o recurso autenticado e retorna para o usuário.
 b. Caso contrário, não exibir recurso privado para o requisitante.

A validação OAuth1 é realizada nas seguintes linhas:

1
2
3
# Valida requisição OAuth1
oauth1_request = server.create_oauth1_request(request)
server.validate_temporary_credentials_request(oauth1_request)
Aqui oauth1_request = server.create_oauth1_request(request) traduz a requisição recebida pelo Flask para o formato entendido pela biblioteca Authlib. Em server.validate_temporary_credentials_request(oauth1_request) faz as validações OAuth1 (cliente válido, timestamp, nonce, assinatura, etc). Caso alguma das verificações falhe, uma exceção é disparada indicando erro na verificação OAuth. Caso nenhuma exceção seja disparada, o código continua para a validação do pacote LTI.

A validação da mensagem LTI ocorre nas seguintes linhas:

1
2
3
# Verifica pacote de inicialização básica LTI 1.0
launch = LTILaunchForm(request.form)
LTILaunchForm.validate_lti_launch(launch)

A linha launch = LTILaunchForm(request.form) realiza uma transformação do formulário da requisição Flask para um formato entendido pela biblioteca LTI implementada. LTILaunchForm aceita basicamente qualquer fomato que seja transformado nativamente em um dicionário como dict(request_form). A linha LTILaunchForm.validate_lti_launch(launch) realiza as validações da mensagem LTI, basicamente lti_message_type=basic-lti-launch-request, lti_version=LTI-1p0 e resource_link_id presente. Você pode checar a implementação de LTILaunchForm.validate_lti_launch() em lti1p0/provider.py para as verificações realizadas ou customizar sua própria verificação. Caso alguma das validações falhem uma exceção é disparada indicando erro na validação LTI. Caso nenhum erro durante a validação LTI ocorra o código continua configurando o estado da variável verified para True e segue para a preparação e retorno dos recursos.

Neste código simplificado, caso a mensagem LTI seja verificada, o recurso mostrado é apenas Passou! Mostrar recurso privado! com código 200, e Autenticação falhou! com código 401 caso contrário. No código implementado algumas informações extras são apresentadas, como os parâmetros lidos e mensagens de erros mais explicativas para facilitar testes, mas seguem o mesmo padrão apresentado aqui.

IMPORTANTE Fique ciente, entretanto, que a forma de apresentação dos recursos privados varia de aplicação para aplicação e que esse é somente um exemplo. É muito provável que sua aplicação tenha sua própria gestão de usuários e autenticação, neste caso você deve implementar todas as etapas necessárias para a exibição final do recurso para o aluno ou usuário, como levantamento de sessão do usuário, alocação de recursos, redirecionamentos de páginas necessários, etc.

Detalhes adicionais

Como segue a definição, a comunicação OAuth no endpoint de inicialização necessita que o Hub seja identificado como cliente OAuth1 do servidor. Em app.py, adicionamos o Hub como cliente do servidor no seguinte trecho do código:

1
2
3
4
5
6
7
8
9
# Create Hub Educacional Client Example
hub_client_example = Client(
    client_id='hub.educacional.com',
    client_secret='secret',
)

# Persist Hub client to Client Database
db.session.add(hub_client_example)
db.session.commit()

Essa adição foi realizada apenas para exemplo e pode variar de acordo com o servidor OAuth implementado. Você pode adicionar outros clientes da mesma forma para testes se desejar.

Instalação

Antes de testar instale os requisitos:

1
2
3
$ python --version
Python 3.7.4
$ pip install -r requirements.txt

Executando o app (Provedor de Ferramenta LTI)

Unix:

1
2
$ export FLASK_APP=src/app.py
$ flask run
ou apenas,
1
2
$ cd src
$ flask run

Windows CMD:

1
2
> set FLASK_APP=src/app.py
> flask run

Windows PowerShell:

1
2
> $env:FLASK_APP = src/app.py
> flask run

OAuth1 Server (Authlib)

LTI 1.0 é construído sobre o padrão de segurança OAuth1 para autorização e autenticação. Nesse exemplo é utilizada a biblioteca Authlib. O código do servidor OAuth1 foi retirado do próprio repositório da biblioteca.

Arquivo do servidor: authlib/tests/flask/test_oauth1/oauth1_server.py (e035dc9)

IMPORTANTE: Caso sua aplicação seja ou será escrita em outro framework, cheque a documentação da Authlib para verificar se seu framework é suportado, e os códigos de test do repositório para adaptação. Caso você já tenha seu sevidor OAuth1 configurado ou pretenda usar outra biblioteca OAuth, adicione apenas as validações LTI em um endpoint com verificação OAuth de acordo com sua implementação e seguindo as documentações LTI acima. Para outras linguagens e bibliotecas, verifique OAuth.net.