Lembre-se de que as integrações não estão incluídas nos pacotes básicos de licenciamento. Eles devem ser adquiridos separadamente como AddOns. Para obter mais informações, visite nosso site: https://www.teamviewer.com/pt-br/integracoes/
Com a API REACH, o TeamViewer oferece uma API para integração em soluções RMM ou MDM, que permite o início de sessões de controle remoto assistidas e não supervisionadas.
Este documento busca explicar os conceitos fundamentais por trás da API REACH, bem como disponibilizar instruções e orientações para a integração da API em uma solução de gerenciamento.
Para tanto, o documento está estruturado em diferentes seções que trazem informações sobre os diferentes tópicos.
O primeiro capítulo explica a abordagem conceitual básica e traz uma visão geral de por que certos mecanismos de segurança foram aplicados.
Em seguida, uma implementação exemplar é explicada com base no código-fonte de um exemplo de integração, também conhecido como VendorExampleApp, que foi desenvolvido pela TeamViewer.
No capítulo final, são descritos detalhes sobre a implementação da integração no Android.
_____
📌Lembrete: Todos os exemplos de código neste artigo foram publicados sob a licença MIT:
Copyright (c) 2018 TeamViewer GmbH
A permissão é concedida, gratuitamente, a qualquer pessoa que obtenha uma cópia deste software e arquivos de documentação associados (o "Software"), para manusear o Software sem restrições, incluindo, sem limitações, os direitos de usar, copiar, modificar, mesclar , publicar, distribuir, sublicenciar e/ou vender cópias do Software e permitir que as pessoas a quem o Software é fornecido o façam, sujeito às seguintes condições:
O aviso de direitos autorais acima e este aviso de permissão devem ser incluídos em todas as cópias ou partes substanciais do Software.
O SOFTWARE É FORNECIDO "NO ESTADO EM QUE SE ENCONTRA", SEM QUALQUER TIPO DE GARANTIA, EXPRESSA OU IMPLÍCITA, INCLUINDO, MAS NÃO SE LIMITANDO ÀS GARANTIAS DE COMERCIALIZAÇÃO, ADEQUAÇÃO A UM DETERMINADO FIM E NÃO VIOLAÇÃO. EM NENHUMA HIPÓTESE OS AUTORES OU TITULARES DOS DIREITOS AUTORAIS SERÃO RESPONSÁVEIS POR QUALQUER RECLAMAÇÃO, DANOS OU OUTRA RESPONSABILIDADE, SEJA EM UMA AÇÃO DE CONTRATO, DELITO OU DE OUTRA FORMA, DECORRENTE DE, FORA DE OU EM CONEXÃO COM O SOFTWARE OU O USO OU OUTRAS NEGOCIAÇÕES NO PROGRAMAS.
Ao reutilizar ou redistribuir o software, respeite todas as licenças do software incluído de terceiros, se aplicável.
_____
Os conceitos por trás da API REACH, no final, são divididos em três casos de uso:
A implementação é usada para trocar chaves de criptografia entre um dispositivo e a solução de gerenciamento. Essas chaves de criptografia são usadas nas fases de controle e cancelamento de registro e garantem que toda a comunicação com um dispositivo seja segura.
O diagrama explica o fluxo de registro:
O Management Solution Agent (MSA) é um componente que deve ser executado no dispositivo. Este agente deve ter direitos administrativos no dispositivo e recuperar os dados necessários para concluir a fase de implementação com sucesso.
Para iniciar a distribuição, o MSA lê um arquivo especial (etapa 1) que é escrito no início do cliente TeamViewer e após cada solicitação de implementação bem ou malsucedida para este cliente TeamViewer.
📌Lembrete: A etapa 1 pode ser diferente para cada plataforma. A abordagem de arquivo se aplica apenas às plataformas Windows e macOS. No entanto, os dados fornecidos para a implementação são os mesmos para todas as plataformas. Para especificações do Android, consulte o capítulo Android.
Este arquivo contém a RolloutKey (ROK é válida para uma solicitação e usado para descriptografar a resposta da API), um identificador exclusivo global (GUID), bem como o RemotecontrolID do dispositivo (ID do TeamViewer).
Com o RemotecontrolID e o GUID dos dados de distribuição e um conjunto de permissões, uma chamada de API (POST/oem/devices/ createdevicekey) é feita para criar uma nova chave de dispositivo (etapa 3).
Esta chamada de API está iniciando a comunicação do back-end do TeamViewer com o cliente TeamViewer de destino.
Se os dados forem válidos, o cliente TeamViewer está criando um par de chaves para futuras sessões de controle remoto.
O cliente TeamViewer está criptografando a chave privada (= DeviceKey) do par de chaves recém-criado com o RolloutKey e o envia junto com um identificador para este par de chaves, bem como um token de desativação como uma resposta à chamada API, passando pelo backend do TeamViewer (etapa 4).
A solução de gerenciamento deve usar a RolloutKey obtido anteriormente para descriptografar a DeviceKey. Para simplificar o processo de descriptografia, a DeviceKey é criptografada usando o formato PEM padrão.
A DeviceKey e a DeviceKeyID são usadas durante a fase de controle, enquanto o token de desativação é necessário para cancelar o registro de uma DeviceKey.
📌Lembrete: A DeviceKey descriptografada, o DeviceKeyID e o token de desativação devem ser armazenados com segurança no lado da solução de gerenciamento.
Com a primeira etapa concluída, a partir de agora é possível iniciar as sessões de controle remoto para o dispositivo cadastrado. Para iniciar uma sessão de controle remoto, o seguinte processo se aplica:
O controle remoto só é possível após o registro bem-sucedido de um dispositivo, pois a DeviceKey e a DeviceKeyID são necessárias para iniciar uma sessão de controle remoto.
A primeira etapa é uma chamada WebAPI (POST / oem / devices / requestcontrol) com os parâmetros RemotecontrolID, DeviceKeyID e o tipo de controle. Esses parâmetros serão repassados ao cliente alvo, que está verificando se a DeviceKey possui as permissões de controle solicitadas na chamada da API.
Após a verificação bem-sucedida da solicitação, o cliente TeamViewer alvo gera um segredo temporário para uso único (uma mensagem de autenticação de método em hash, HMAC) que é comparável a uma senha de sessão.
A HMAC é calculada com base nos dados recebidos por meio da solicitação de controle e outros dados (Nonce de destino, DeviceSecret) que são gerados pelo cliente TeamViewer.
Depois de calcular a HMAC, o cliente criptografa a DeviceSecret com a DeviceKey que foi especificado na chamada de API através da DeviceKeyID.
O DeviceSecret é retornado como parâmetro de resposta de chamada API EncryptedDeviceSecret junto com o nonce de destino e um modelo de URL de um URL de protocolo TeamViewer ("teamviewerapi://") que inclui o espaço reservado YOURMASTERSECRET.
A implementação do ISV deve descriptografar o EncryptedDeviceSecret com o DeviceKey e calcular a HMAC com base no segredo do dispositivo descriptografado, o nonce de destino e as outras informações enviadas na chamada de API de controle de solicitação.
Assim que a HMAC é calculada, o espaço reservado YOURMASTERSECRET deve ser substituído pela HMAC para construir um URL de protocolo TeamViewer válido.
O URL completo contendo a HMAC deve ser apresentado ao cliente TeamViewer de origem para iniciar uma conexão.
Isso pode acontecer por meio de um navegador ou como parâmetro de linha de comando (o protocolo TeamViewer é registrado com o sistema operacional quando o TeamViewer é instalado e associado ao aplicativo TeamViewer).
O cliente TeamViewer de origem agora está usando as informações no URL, incluindo a HMAC, para estabelecer uma conexão com o cliente de destino.
No caso de uma DeviceKey não ser mais usada, a DeviceKey pode ter seu registro cancelado. O diagrama mostra o princípio básico:
Para cancelar o registro de uma chave de dispositivo, a chamada de API da Web DELETE/oem/devices/unregister é usada.
Para uma execução bem-sucedida, é necessário que a DeviceKeyID identifique a chave correta, a RemotecontrolID do dispositivo, bem como o token de desativação que também foi emitido na resposta de chamada da API POST/oem/devices/createdevicekey durante a fase de implementação.
Essas informações serão então processadas pelo cliente TeamViewer no dispositivo.
Se as informações na API corresponderem às informações do cliente, a parte local do par de chaves criado na fase de implementação será excluída e uma confirmação será retornada através da da WbeAPI.
A partir desse momento, nenhuma outra sessão de controle remoto poderá ser estabelecida usando esta DeviceKey.
Para seguir este guia e realizar a integração, algumas informações são necessárias ao longo das diferentes fases da integração, que são
A ID do fornecedor foi fornecida por um representante TeamViewer ao ISV.
A conta do locatário pode então ser criada com um token de script da conta do fornecedor com permissões de gerenciamento do locatário.
Por exemplo, você poderia usar uma ferramenta como o Postman para emitir as chamadas da WebAPI.
Por fim, é necessário um token de script da conta do locatário que tenha permissões para criar chaves de dispositivo, solicitar controle e excluir chaves de dispositivo.
Por favor, consulte https://www.teamviewer.com/en/for-developers/#create-script-section para obter instruções sobre como criar um token de script.
Para o exemplo de integração, os exemplos de código fornecidos usam as seguintes tecnologias e bibliotecas:
Para Android, as seguintes informações são necessárias adicionalmente:
O AppKey é a assinatura do MSA no dispositivo Android, a AppKeyID é usada junto com a ID da conta como um índice. Ambos os valores são retornados com a resposta da chamada da WebAPI para registrar a chave do aplicativo no console web.
Dica: Esteja ciente de que todos os valores usados durante a explicação devem ser substituídos por seus valores concretos.
O diagrama a seguir oferece uma breve visão geral das partes do lado do fornecedor onde a integração deve ser feita.
A chamada de API pode ser feita com qualquer classe de cliente HTTP.
A pré-condição para esta chamada da API da Web é ler as informações do arquivo de distribuição que é escrito pelo cliente TeamViewer.
Este arquivo pode ser lido em plataformas Windows e macOS com direitos de administrador.
Em dispositivos Android, um registro do aplicativo MSA é necessário antes de tentar acessar os dados de implementação. Isso é descrito separadamente no capítulo Integração do Android abaixo.
Para nosso exemplo aqui, nos referimos ao código, pois ele também é fornecido no
VendorExampleApp, disponível no código-fonte. Primeiro, você tem que criar o corpo JSON, que pode, por exemplo, acontecer usando uma classe de dados, como a seguinte criação exemplar de tal classe de dados.
Esteja ciente de que as informações para RemotecontrolID e RequestID se originam do arquivo de implementação:
Criação do corpo da solicitação
var createDeviceKeyRequest = new CreateDeviceKeyRequest { key_permissions = "unattended", remotecontrol_id = "r124124124", request_id = "{8c4fa1a7-9d1c-41e9-be17-70e95c289080}", tenant_id = "t0001" };
Com essa classe de dados criada e preenchida com informações, a chamada WepAPI pode ser emitida, especificando o URL e o método, preenchendo o cabeçalho da solicitação HTTP com as informações de autenticação necessárias e, em seguida, anexe o corpo JSON contendo a classe de dados serializada acima.
Para adicionar a autorização ao cabeçalho HTTP, um token de script de aplicativo deve ser criado através do Console de Gerenciamento do TeamViewer.
Deve-se ter certeza de que esse token de script possui as permissões corretas para executar as chamadas da WebAPI.
Essas permissões só podem ser concedidas para esse token de script se a conta que possuir o token de script for um locatário.
Veja um exemplo de código na caixa a seguir, emitindo a chamada, analisando a resposta e retornando a classe de dados de serializada contendo os valores de resposta. Este código de exemplo é obtido do aplicativo do fornecedor.
Solicitar DeviceSecretKey
HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(apiUrl + "/api/v1/oem/devices/createdevicekey"); webReq.Method = "POST"; webReq.ContentType = "application/json"; webReq.Headers.Add("Authorization", "Bearer "+accessToken); using (var streamWriter = new StreamWriter(webReq.GetRequestStream())) { var createSecretKeyRequestJson = JsonConvert.SerializeObject(createDeivceKeyRequest); streamWriter.Write(createDeviceKeyRequestJson); streamWriter.Flush(); streamWriter.Close(); } var httpResponse = (HttpWebResponse) await webReq.GetResponseAsync(); if (httpResponse == null) { throw new InvalidDataException("No response received"); } var responseStream = httpResponse.GetResponseStream(); if (responseStream == null) { throw new InvalidDataException("No response stream received."); } using (var streamReader = new StreamReader(responseStream)) { var result = streamReader.ReadToEnd(); return JsonConvert.DeserializeObject<CreateDeviceKeyResponse>(result); }
Com a resposta da API, agora você possui a DeviceKey criptografada.
Para decodificar o DeviceKey criptografado que está no formato PEM, escolhemos aqui BouncyCastle como uma biblioteca porque torna muito mais fácil.
BouncyCastle também está disponível para Java. Mas deve haver muitas bibliotecas para cada linguagem, podendo trabalhar com arquivos PEM.
O algoritmo de criptografia é declarado diretamente no arquivo PEM que você obtém da solicitação da API.
Exemplo:
"-----BEGIN RSA PRIVATE KEY-----\nProc-Type: 4,ENCRYPTED\nDEK-Info: AES-256-CBC,309AA16\n-----END RSA PRIVATE KEY-----\n"
Por questões de segurança, RECOMENDAMOS ALTAMENTE que você use uma biblioteca para lidar com o trabalho, porque as bibliotecas geralmente vêm com a capacidade de identificar automaticamente o algoritmo correto.
No caso de um problema de segurança com o próprio algoritmo, podemos e iremos alterá-lo.
Nenhuma mudança será necessária no lado do ISV se uma biblioteca apropriada for usada, enquanto uma implementação manual nunca seria tão flexível.
Usando o Bouncy Castle, a descriptografia da chave PEM se resume a um código, como no exemplo a seguir.
Por razões de simplicidade, armazenamos o deviceKey como uma string de formato PEM descriptografada, pois isso pode ser manipulado pela biblioteca BouncyCastle e pode ser armazenado como uma string.
Descriptografar chave PEM
TextReader textReader = new StringReader(encryptedDeviceKey); PemReader pemReader = new PemReader(textReader, new PasswordFinder(password)); object deviceKeyObject = pemReader.ReadObject(); AsymmetricCipherKeyPair rsaPrivatekey = (AsymmetricCipherKeyPair)deviceKeyObject; TextWriter tw = new StringWriter(); var pemWriter = new PemWriter(tw); pemWriter.WriteObject(rsaPrivatekey.Private); pemWriter.Writer.Flush(); string deviceKey = tw.ToString(); return deviceKey;
Importante: após esta etapa é que você deve armazenar a DeviceKey, junto com a DeviceKeyID e A RemotecontrolID, que foi retornada na resposta da chamada WebAPI, no contexto de sua solução de gerenciamento.
Além disso, você precisa manter o token de desativação que eventualmente será necessário para cancelar o registro de uma DeviceKey novamente.
Com os dados da fase anterior, a DeviceKey e a DeviceKeyID, pode ser estabelecida uma sessão de controle remoto com o dispositivo registrado.
É importante que, durante a solicitação de controle remoto você use o mesmo tipo de controle para o qual solicitou permissões durante a fase de implementação.
Novamente, no início, uma instância de classe de dados é primeiro preenchida com as informações necessárias para a chamada da WebAPI.
Classe de dados de controle de solicitação
var requestControlRequest = new RequestControlRequest() { control_type = "attended", device_key_id = "{114fa1a7-abab-41e9-be17-70e95c289080}", remotecontrol_id = "r124124124", tenant_id = "t0001", tenant_nonce = "243dd78d07324ab7befa41390d08d35f" };
Com essa instância de dados em posição, a chamada da API da Web pode ser emitida como no código C# a seguir.
Novamente, primeiro o URL é adicionado, em seguida, o cabeçalho de autorização HTTP com o token de script e, finalmente, a instância da classe de dados desserializado como um corpo JSON.
Depois que a solicitação retornar com uma resposta, os dados podem ser desserializado em uma instância de classe de dados própria, que fornece o modelo para o link do TeamViewer.
Este link será então preenchido com uma Mensagem de Autenticação de Método com Hash (HMAC).
Chamada de controle remoto
HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(apiUrl + "/api/v1/oem/devices/requestcontrol"); webReq.Method = "POST"; webReq.ContentType = "application/json"; webReq.Headers.Add("Authorization", "Bearer " + accessToken); using (var streamWriter = new StreamWriter(webReq.GetRequestStream())) { var requestControlRequestJson = JsonConvert.SerializeObject(requestControlRequest); streamWriter.Write(requestControlRequestJson); streamWriter.Flush(); streamWriter.Close(); } var httpResponse = (HttpWebResponse)(await webReq.GetResponseAsync()); if (httpResponse == null) { throw new InvalidDataException("No response received"); } var responseStream = httpResponse.GetResponseStream(); if (responseStream == null) { throw new InvalidDataException("No response stream received."); } using (var streamReader = new StreamReader(responseStream)) { var result = streamReader.ReadToEnd(); return JsonConvert.DeserializeObject<RequestControlResponse>(result); }
Como a resposta da API retorna apenas um modelo de link, o link deve ser preenchido com a HMAC.
O segredo para criar a HMAC é retornado criptografado na resposta da API, portanto, a primeira etapa é descriptografar o segredo.
A chave para a des-criptografia é a DeviceKey que foi recebida com a resposta da API durante a fase de implementação.
Como a DeviceKey é armazenada como uma string formatada por PEM, a primeira parte do código converte essa string em uma estrutura adequada para o BouncyCastle (a variável do tipo "AsymmetricCipherKeyPair”).
Descriptografar PreMasterSecret
using (var reader = new StringReader(DeviceKey)) { //Convert to right format var bytesToDecrypt = encryptedDeviceSecret.FromBase64SafeUrl(); //--------DESCRIPTOGRAFAR COM DISPOSITIVO PEM KEY-------------// AsymmetricCipherKeyPair keyPair = (AsymmetricCipherKeyPair) new PemReader(reader).ReadObject(); var decryptEngine = new OaepEncoding(new RsaEngine()); decryptEngine.Init(false, keyPair.Private); var decryptedDeviceSecret = decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length); }
Com o DeviceSecret descriptografado, A TenantID, A RemotecontrolID do destino e os nonces do destino e do locatário, o HMAC pode ser criado como no exemplo a seguir, que novamente é implementado usando a biblioteca de segurança BouncyCastle.
Gerar Mastersecret
//---------Valores HMAC a serem hash, recombinados em uma string ------------// var hashVerifier = $"{tenantNonce}{targetNonce}{tenantId.Substring(1)}{remotecontrolId.Substring(1)}"; HMACSHA512 hmacsha512 = new HMACSHA512(decryptedDeviceSecret); byte[] hashmessage = hmacsha512.ComputeHash(Encoding.UTF8.GetBytes(hashVerifier)); var masterSecret = hashmessage.ToBase64SafeUrl();
O resultado é colocado no modelo de link do TeamViewer em vez da string YOURMASTERSECRET.
Com essa string concluída, a sessão de controle remoto pode ser estabelecida abrindo o link no navegador da Internet de um sistema que tenha um cliente TeamViewer Enterprise instalado ou passando este link para a linha de comando de uma chamada para o TeamViewer.exe
A chamada de dispositivo de cancelamento de registro requer os seguintes parâmetros para executar com êxito o cancelamento de registro:
Como nas fases anteriores, uma instância de classe de dados para esta chamada específica deve ser criada, preenchida com os dados concretos para a próxima chamada para a WebAPI:
Criação de estrutura de dados
var unregisterDeviceRequest = new UnregisterDeviceRequest { tenant_id = "t0001", remotecontrol_id = "r124124124", device_key_id = "{114fa1a7-abab-41e9-be17-70e95c289080}", decommission_token = _mState.LastDecommissionToken };
Novamente, como já mostrado anteriormente, o mesmo padrão de implementação é seguido, adicionando a URL de chamada WebAPI, adicionando o método, o token de script do aplicativo ao cabeçalho de autorização HTTP e, eventualmente, anexando o conteúdo serializado da classe de dados criada anteriormente no formato JSON.
Cancelando o registro
HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(apiUrl + "/api/v1/oem/devices/unregister"); webReq.Method = "DELETE"; webReq.ContentType = "application/json"; webReq.Headers.Add("Authorization", "Bearer " + accessToken); using (var streamWriter = new StreamWriter(webReq.GetRequestStream())) { var unregisterDeviceRequestJson = JsonConvert.SerializeObject(unregisterDeviceRequest); streamWriter.Write(unregisterDeviceRequestJson); streamWriter.Flush(); streamWriter.Close(); } var httpResponse = (HttpWebResponse)await webReq.GetResponseAsync(); if (httpResponse == null) { throw new InvalidDataException("No response received"); } var responseStream = httpResponse.GetResponseStream(); if (responseStream == null) { throw new InvalidDataException("No response stream received."); } using (var streamReader = new StreamReader(responseStream)) { var result = streamReader.ReadToEnd(); return; }
Neste caso, o resultado retornado não conterá dados.
O sucesso da operação só pode ser verificado verificando o valor de retorno que deve ser 204 (consulte também valores de retorno comuns de HTTP).
Devido a restrições de plataforma no Android (não há a separação de privilégios administrativos adequada), a implementação é diferente de outras plataformas. Uma verificação do MSA precisa ser realizada antes que ele possa se comunicar com o aplicativo TeamViewer Android e a RolloutKey é obtida de forma diferente.
O hash SHA-256 da chave de assinatura do MSA (referido como AppKey daqui em diante) deve ser registrado no TeamViewer como uma string hexadecimal usando a chamada WebAPI POST "/oem/appregistrations".
Esta etapa de registro é necessária apenas uma vez por AppKey e pode ser realizada com qualquer cliente REST como o Postman.
A comunicação entre o aplicativo TeamViewer e o MSA usa a interface nativa do Android Binder (https://developer.android.com/reference/android/os/Binder.html) conforme descrito pelos arquivos AIDL que você recebeu ao se registrar na REACH API.
Antes de qualquer outra chamada, o método verify precisa ser chamado. O método de verificação requer a AccountID da conta usada para registrar a MSA AppKey e a KeyID retornada durante o registro. Se a verificação for bem-sucedida, você pode chamar qualquer um dos métodos do serviço Binder. Caso contrário, uma SecurityException será lançada.
A principal diferença no Android, exceto o registro do aplicativo, é a forma como a RolloutKey é obtida. O arquivo que contém os dados de distribuição é gravado no armazenamento privado do aplicativo do app TeamViewer. Só é possível ler essas informações para o aplicativo TeamViewer. Por esse motivo, o aplicativo MSA deve solicitar os dados de implementação através da interface do Binder. Depois de obter os dados de implementação com sucesso, usando o método requestPreKeyData na interface do Binder, você pode proceder da mesma forma descrita no capítulo Implementação de um dispositivo para a REACH API