Skip to end of metadata
Go to start of metadata

CORBA

O que são valuetypes em CORBA?

De acordo com a especificação de CORBA do site da OMG valuetypes são (em tradução livre):

Um valuetype (tipo por valor) é uma entidade que compartilha características de interfaces e de structs. É uma descrição de um conjunto de operações que um cliente pode requisitar e de um estado que é acessível ao cliente (remoto). As instâncias de um valuetype são sempre de implementações locais (seja no cliente ou no servidor). Um valuetype pode herdar de outros valuetypes ou mesmo de múltiplas interfaces.

 

Desenvolvendo Serviços

Como utilizar os mecanismos de observação de logins e ofertas no OpenBus 2.0?


Os exemplos dessa questão estão em C# mas nas outras linguagens os caminhos para os arquivos dentro do pacote do OpenBus SDK são semelhantes.

No OpenBus 2.0 há uma funcionalidade de observação tanto de ofertas como de logins. Pode ser realmente interessante usar para tornar o código mais resiliente. Para utilizar isso no SDK C# há os seguintes passos:

  1. É preciso obter a referência para as duas facetas do barramento que fornecem tal funcionalidade. O acesso a essas referências é facilitado pelo SDK do OpenBus. Ambas estão armazenadas através do , exemplos:

    OpenBusContext context = ORBInitializer.Context;
    context.LoginRegistry.subscribeObserver(...);
    context.OfferRegistry.subscribeObserver(...); 
  2. É preciso estudar esse mecanismo de observação através das assinaturas dos métodos com calma. Há três possibilidades: 
    1. observação de logins via LoginRegistry
    2. observação do registro de ofertas (de qualquer oferta nova que for inserida)

    3. observação de uma oferta específica
  3. Para lidar com o item 2.c e poder (por exemplo) perceber que uma oferta específica (oriunda de uma busca) foi removida (para por exemplo fazer nova busca) é preciso fazer um context.OfferRegistry.findServices antes. Então, no ServiceOfferDesc você pode usar o campo ref e então cadastrar um observador para aquela oferta específica. Você poderá ser notificado em caso de mudança das propriedades e remoção da oferta. Exemplo de código: 

    serviceOfferDesc.@ref.subscribeObserver(...);

A IDL do barramento é a única documentação sobre essa parte:

  1. O guia de referência dela (em html) está na pasta doc\core-idl dentro do .zip do OpenBus SDK C# 2.0.1.0.
  2. Os arquivos em si estão em idl\v2_0\access_control.idl e idl\v2_0\offer_registry.idl.

Quais são as propriedades automaticamente definidas no ato do registro de uma oferta de serviço ?

Segue abaixo a lista das propriedades automaticamente preenchidas pelo barramento no ato do registro da oferta do serviço. Não é possível sobreescrever esses valores no ato do registro, ou seja, utilizando o segundo parâmetro do método registerService do OfferRegistry disponível do SDK. Esse parâmetro existe para a definição de propriedades particulares de cada serviço, conhecidas como propriedades customizadas.

  • openbus.offer.id: Identificador único da oferta. Este identificador é gerado automaticamente no ato da oferta e muda a cada nova oferta.
  • openbus.offer.login: Identificador do login com que a oferta foi registrada. Este identificador é gerado automaticamente no ato do login e muda a cada novo login.
  • openbus.offer.entity: Identificador da entidade que registrou a oferta. Este identificador é governado pelos administradores do barramento e é gerado manualmente.
  • openbus.offer.timestamp: Número indicando o momento do registro da oferta.
  • openbus.offer.year: Ano em que a oferta foi registrada.
  • openbus.offer.month: Número do mês em que a oferta foi registrada.
  • openbus.offer.day: Dia do mês que a oferta foi registrada.
  • openbus.offer.hour: Hora do dia em que a oferta foi registrada.
  • openbus.offer.minute: Minuto do dia em que a oferta foi registrada.
  • openbus.offer.second: Segundo do dia em que a oferta foi registrada.
  • openbus.component.name: Nome do componente SCS que implementa o serviço.
  • openbus.component.version.major: Versão maior do componente SCS que implementa o serviço.
  • openbus.component.version.minor: Versão menor do componente SCS que implementa o serviço.
  • openbus.component.version.patch: Versão de correção do componente SCS que implementa o serviço.
  • openbus.component.facet: Nome de faceta oferecida pelo componente SCS que implementa o serviço.
  • openbus.component.interface: RepID da interface implementada pela faceta do component SCS que implementa o serviço.

Para saber quais valores usar, utilize a ferramenta BusExplorer 1.1.1 (acessível por Documentação > Core - seção Ferramentas). Através dela você pode ir até a aba Ofertas e buscar a oferta de uma aplicação e então descobrir os valores.

Quais as possíveis causas da exceção NO_PERMISSION ?

A exceção NO_PERMISSION é uma exceção em tempo de execução que é definida na especificação de CORBA. No protocolo do OpenBus essa exceção é usada também para representar situações onde não é possível utilizar um serviço remoto. Para diferenciar as várias situações em que um NO_PERMISSION é lançada, a especificação de CORBA recomenda usar o número de minor code. O valor decimal de um minor code é obtido a partir de um vmcid (usado como offset). O número vmcid em hexadecimal usado no protocolo do OpenBus é 0x42555000 (em decimal 1112887296).

Outros valores de vmcid que não 0x42555000 indicam que a origem do NO_PERMISSION não tem como causa o uso do protocolo do OpenBus, nesse caso pode ser uma exceção lançada pela camada CORBA mais básica. Nesses casos consulte a especificação CORBA em http://www.omg.org/spec/CORBA/3.1/.

Segue a lista de minor codes organizados em duas categorias: uma dos usados em exceções emitidas pelo protocolo do OpenBus e outra dos usados em exceções emitidas pela biblioteca do OpenBus.

  • Os minor codes relacionados ao protocolo em geral não devem vazar até a aplicação. São eles:
NomeValorvmcidminorDescrição
InvalidCredentialCode11128880640x42555000768chamada feita com credencial inválida
InvalidChainCode11128880650x42555000769cadeia de chamadas inválida
InvalidLoginCode11128880660x42555000770login inválido
UnverifiedLoginCode11128880670x42555000771serviço remoto não pôde verificar o login
UnknownBusCode11128880680x42555000772serviço remoto está em outro barramento
InvalidPublicKeyCode11128880690x42555000773serviço remoto informou chave pública inválida
NoCredential11128880700x42555000774chamada feita sem credencial
  • Já os minor codes relacionados a biblioteca do OpenBus em geral vazam até a aplicação. São eles:
 NomeValor vmcid minor Descrição 
InvalidTargetCode11128883160x425550001020serviço remoto com login inválido
UnavailableBusCode11128883170x425550001021serviço remoto sem acesso ao barramento
InvalidRemoteCode11128883180x425550001022serviço remoto não respeita o protocolo
NoLoginCode11128883190x425550001023conexão atual não está logada

O que significa a exceção NO_PERMISSION com minorcode 0 durante a comunicação com sistemas SDK 1.5 ?

Ao fazer uma chamada para um serviço OpenBus SDK 1.5 ele pode lançar um NO_PERMISSION em várias situações. Uma delas é a situação que estamos interessados e que refere-se ao fato de termos perdido o login enquanto nos comunicamos com o serviço. As causas para a invalidação do login podem ser diversas: desde uma falha na thread de renovação de login quanto o logout forçado que um administrador tenha feito.

A solução definitiva para o problema não é factível, passaria por oferecer uma correção para todos OpenBus SDK 1.5. Algo que é custoso e tentamos evitar. Entretanto existe uma heurística que ameniza o problema.

Um exemplo de código de catch em C# para fazer o teste enquanto o OpenBus SDK não evolui:

// ATENÇÃO para os namespaces usados neste exemplo de código..
// using tecgraf.openbus;
// using tecgraf.openbus.core.v2_0.services;
// using tecgraf.openbus.core.v2_0.services.access_control;
// using tecgraf.openbus.core.v2_0.services.offer_registry;
  catch (NO_PERMISSION e)
    {
      // ATENÇÃO: o objeto conn refere-se à conexão com barramento, disponível na API básica do OpenBus SDK
      if (e.Minor == 0)
      {
        // Tentativa de identificar se o NO_PERMISSION foi causado pelo login ter sido invalidado
        if (ORBInitializer.Context.LoginRegistry.getLoginValidity(conn.Login.Value.id) == 0)
        {
          Logger.Debug("O login " + conn.Login.Value.id + " foi invalidado durante a " +
            "comunicação com um sistema legado (OpenBus SDK 1.5). A chamada precisará ser refeita.");
        }
        // Existem outras situações que pode ocorrer NO_PERMISSION com minor 0
        else
        {
          Logger.Error("Erro inesperado com exceção NO_PERMISSION minor code 0 durante comunicação com serviço.");
          throw;
        }
      }
    } 

O fato de testarmos a comunicação da referência remota LoginRegistry no método getLoginValidity causará uma comunicação com o barramento e assim caso realmente o login tenha sido invalidado, o SDK 2.0 da sua aplicação saberá identificar e finalmente se recuperar inclusive chamando a callback de InvalidLogin, caso você a esteja utilziando. Porém, infelizmente como isso hoje tem que ser tratado em nível de aplicação, você precisará de uma solução própria para refazer a chamada original (se isso for importante para seu sistema).

Vale lembrar que esse NO_PERMISSION com código 0 só acontecerá na comunicação com um serviço que ainda use o SDK 1.5.

O que significa a exceção CORBA.INTERNAL com a mensagem Any de chave única de requestId vazia ?

A exceção CORBA.INTERNAL pode ser lançada pela biblioteca do OpenBus SDK em situações não-esperadas, ou seja, situações que não deveriam acontecer e que representam ausência de funcionalidade ou limitação da implementação da biblioteca OpenBus SDK.

Essa exceção tipicamente acontece na primeira chamada de um cliente a um servidor que ofereça serviço no barramento. Um exemplo dessa exceção é:

org.omg.CORBA.INTERNAL: Any de chave única de requestId está vazia!  vmcid: 0x0  minor code: 0  completed: No
        at tecgraf.openbus.core.ClientRequestInterceptorImpl.getRequestUniqueId(ClientRequestInterceptorImpl.java:547)
        at tecgraf.openbus.core.ClientRequestInterceptorImpl.receive_exception(ClientRequestInterceptorImpl.java:428)
        at org.jacorb.orb.portableInterceptor.ClientInterceptorIterator.invoke(ClientInterceptorIterator.java:138)
        at org.jacorb.orb.portableInterceptor.AbstractInterceptorIterator.iterate(AbstractInterceptorIterator.java:66)
        at org.jacorb.orb.portableInterceptor.ClientInterceptorIterator.iterate(ClientInterceptorIterator.java:87)
        at org.jacorb.orb.portableInterceptor.DefaultClientInterceptorHandler.invokeInterceptors(DefaultClientInterceptorHandler.java:331)
        at org.jacorb.orb.portableInterceptor.DefaultClientInterceptorHandler.handle_receive_exception(DefaultClientInterceptorHandler.java:264)
        at org.jacorb.orb.portableInterceptor.DefaultClientInterceptorHandler.handle_receive_exception(DefaultClientInterceptorHandler.java:234)
        at org.jacorb.orb.Delegate.servant_preinvoke(Delegate.java:2890)
        at org.jacorb.orb.Delegate.non_existent(Delegate.java:2130)
        at org.omg.CORBA.portable.ObjectImpl._non_existent(ObjectImpl.java:155)
        at br.com.petrobras.ep.openspirit.common.DataServiceFinder.find(DataServiceFinder.java:70)
        at br.com.petrobras.ep.openspirit.common.DataServiceHelper.getDataServiceSource(DataServiceHelper.java:405)
        at br.com.petrobras.ep.openspirit.common.DataServiceHelper.getDataDescription(DataServiceHelper.java:109)
        at br.com.petrobras.ep.openspirit.services.navigation.core.impl.OpenSpiritNavigationHDataService.initSeismicVolume2D(OpenSpiritNavigationHDataService.java:607)
        at br.com.petrobras.ep.openspirit.services.navigation.core.impl.OpenSpiritNavigationHDataService.copyData2DVolume(OpenSpiritNavigationHDataService.java:526)
        at br.com.petrobras.ep.openspirit.services.navigation.core.impl.OpenSpiritNavigationHDataService.copyDataFrom(OpenSpiritNavigationHDataService.java:443)
        at br.com.petrobras.ep.openspirit.services.navigation.test.CopyDataTest.testCopy2DVolumeFromMULTISegyToGF(CopyDataTest.java:406)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at junit.framework.TestCase.runTest(TestCase.java:176)
        at junit.framework.TestCase.runBare(TestCase.java:141)
        at junit.framework.TestResult$1.protect(TestResult.java:122)
        at junit.framework.TestResult.runProtected(TestResult.java:142)
        at junit.framework.TestResult.run(TestResult.java:125)
        at junit.framework.TestCase.run(TestCase.java:129)
        at junit.framework.TestSuite.runTest(TestSuite.java:255)
        at junit.framework.TestSuite.run(TestSuite.java:250)
        at junit.framework.TestSuite.runTest(TestSuite.java:255)
        at junit.framework.TestSuite.run(TestSuite.java:250)
        at junit.extensions.TestDecorator.basicRun(TestDecorator.java:23)
        at junit.extensions.TestSetup$1.protect(TestSetup.java:23)
        at junit.framework.TestResult.runProtected(TestResult.java:142)
        at junit.extensions.TestSetup.run(TestSetup.java:27)
        at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:84)
        at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
        at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
        at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
        at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
        at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
        at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
        at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75) 

Essa stacktrace já nos oferece uma pista importante na análise do problema: mostra o uso de uma infraestrutura de testes unitários baseadas em JUnit. A explicação da mensagem Any de chave única de requestId está vazia é que trata-se de uma requisição que não está seguindo o protocolo OpenBus 2.0 ou a chamada não chegou da camada de rede ou chegou sem a estrutura correta.

Causa: O erro que o desenvolvedor cometeu neste exemplo foi instanciar um cliente e um servidor no mesmo processo usando a mesma instância de ORB. Isso não é suportado pela API do OpenBus SDK 2.0.1.

Solução: É possível criar uma instância de um Assistant para autenticar como cliente e outra instância para autenticar como servidor (através de chave privada), mas será preciso criar instâncias distintas de ORB a utilizar em cada um dessas instâncias de Assistant, por exemplo. Caso se use o Assistant, é possível especificar qual instância de ORB a usar através do AssistantParams.

Quando se utiliza o mesmo ORB, em Java (no caso do JacORB) não é garantido que a camada de rede seja utilizada, portanto a requisição não é serializada conforme o protocolo e assim a requisição não contém toda a estrutura necessária.

Quais as possíveis causas da exceção java.security.InvalidKeyException?

java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
 at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:217)

 at java.security.KeyFactory.generatePrivate(KeyFactory.java:372)
 
at tecgraf.openbus.security.Cryptography.readKeyFromBytes(Cryptography.java:238)
 at tecgraf.openbus.core.OpenBusPrivateKey.createPrivateKeyFromBytes(OpenBusPrivateKey.java:42)
 at tecgraf.openbus.core.OpenBusPrivateKey.createPrivateKeyFromFile(OpenBusPrivateKey.java:61)
 ...
Caused by: java.security.InvalidKeyException: invalid key format

 at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:330)

 at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:356)

 at sun.security.rsa.RSAPrivateCrtKeyImpl.<init>(RSAPrivateCrtKeyImpl.java:91)
 at sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(RSAPrivateCrtKeyImpl.java:75)
 at sun.security.rsa.RSAKeyFactory.generatePrivate(RSAKeyFactory.java:316)
 at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:213)
 ...
  • Causa: como a exceção indica na mensagem "invalid key format", está tentando ser usada uma chave privada para conectar ao barramento que está em formato inválido. Isso é comum durante a migração do SDK 1.5 para o SDK 2.0. A partir do SDK 2.0, a API passou a utilizar uma chave privada serializada no formato DER do OpenSSL ao invés do formato PEM que era usado até então no SDK 1.5.


    Solução: Será preciso converter a chave privada de PEM para DER

O que significam as exceções de MissingCertificate e AccessDenied quando tento conectar por chave privada?

Há duas situações comum dos desenvolvedores terem essas exceções: a primeira vez que usam o barramento e após esquecer as configurações que eram usadas em algum momento do passado. Por isso é importante esclarecer essas exceções.

  • MissingCertificate: Essa exceção significa que não há certificado cadastrado para o nome de entidade que o sistema está usando ao conectar no OpenBus. O nome da entidade é governado pelo OpenBus e é necessário entrar em contato com o administrador da sua instância de OpenBus para que ele cadastre um nome de entidade e o certificado (chave pública) para que um sistema autentique com uma chave privada. Se seu sistema já possui um nome de entidade e você continua tendo essa exceção, deve ser um erro de configuração do seu sistema, verifique que no ato do loginByCertificate você está usando o nome de entidade correto.
  • AccessDenied (com mensagem: erro ao descriptografar desafio): Essa exceção significa que a entidade existe no barramento mas a chave privada usada na autenticação não confere com o certificado cadastrado no barramento. O certificado do sistema é governado pelo OpenBus e o certificado cadastrado é antigo e não foi gerado a partir da mesma chave privada que você está usando na autenticação. Portanto, será preciso entrar em contato com o administrador da sua instância do OpenBus para pedir uma atualização do certificado relativo à entidade que você está usando.

Em C#, como manter ativo um serviço CORBA no servidor IIS?

O uso mais comum do servidor IIS é para hospedar aplicações ASP.NET Web Services. Usando as abstrações do ASP.NET Web Services o framework decidirá sobre o ciclo de vida do serviço e desta forma pode desativá-lo caso não haja alguma requisição HTTP por um período de tempo.

Por isso não é recomendado implementar um serviço para o OpenBus usando o OpenBus SDK C# como um ASP.NET Web Service.

Para entender as diferenças entre como expor um serviço como um ASP.NET Web Service ou um .NET Remoting recomendamos a leitura: https://msdn.microsoft.com/en-us/library/ms978420.aspx. É importante notar duas características:

  • Todo serviço implementado com o OpenBus SDK C# usa o IIOP.NET;
  • O IIOP.NET é um binding para .NET Remoting e na prática define apenas as regras de serialização/desserialização de chamadas através do IIOP sobre o protocolo TCP.

É possível escrever um serviço CORBA (que use o OpenBus SDK C#) que aproveite a infraestrutura do IIS (facilitações de deployment e gerência -- start e stop) e que sempre esteja ativo independente das requisições HTTP. Para isso basta que o Application Pool esteja com o StartMode configurado como AlwaysRunning. Mais detalhes em: http://weblog.west-wind.com/posts/2013/Oct/02/Use-IIS-Application-Initialization-for-keeping-ASPNET-Apps-alive

Em um cenário típico, recomendamos o uso de um pool de aplicações específico para os serviços baseados no OpenBus SDK C# em separado do pool de aplicações ASP.NET Web, por organização e para diminuir a chance de uma indisponibilidade em um serviço de um tipo interfira no outro.

Chaves Privadas e Certificados Públicos

O que mudou no formato das chaves privadas entre o OpenBus SDK 1.5 e o OpenBus SDK 2.0?

As chaves privadas só se diferenciam pelo formato de serialização. Até a versão 1.5 do OpenBus SDK, utiliza-se o formato PEM (textual) para serializar as chaves privadas de 2048 bits encapsuladas como PKCS8 (sem encriptação). A partir da versão 2.0 do OpenBus SDK passou-se a utilizar a serialização DER (binário) para as chaves privadas de 2048 bits encapsuladas como PKCS8 (sem encriptação).

O formato de serialização dos certificados sempre foi DER (binário) e não mudou. Os certificados são emitidos conforme o padrão X509.

Como converter uma chave privada PKCS#8 do formato PEM para o formato DER?

openssl pkcs8 -topk8 -nocrypt -inform PEM -in <arquivo de chave privada PEM.key> -outform DER -out <arquivo de chave privada DER.key>

Como converter uma chave privada PKCS#8 do formato DER para o formato PEM?

openssl pkcs8 -topk8 -nocrypt -inform DER -in <arquivo de chave privada DER.key> -outform PEM -out <arquivo de chave privada PEM.key>

Como gerar um certificado a partir de uma chave privadas PKCS#8 no formato DER?

openssl req -days <validade do certificado em dias> -new -x509 -key <arquivo de chave privada DER.key> -keyform DER -out <arquivo de certificado DER.crt> -outform DER

Em C#, como converter uma chave privada do tipo RSACryptoServiceProvider para o array de bytes esperado por algumas versões do SDK, utilizando a biblioteca BouncyCastle?

O SDK C# 2.0 do OpenBus utiliza a biblioteca BouncyCastle como solução para a API de criptografia. Portanto se sua aplicação usa o tipo RSACryptoServiceProvider precisa passar a chave privada como um array de bytes diretamente no login por chave privada da conexão.

A biblioteca do BouncyCastle tem funções utilitárias para auxiliar nessa tarefa:

RSACryptoServiceProvider rsa = ...;
AsymmetricCipherKeyPair pair = DotNetUtilities.GetKeyPair(rsa);
byte[] keyBytes = PrivateKeyInfoFactory.CreatePrivateKeyInfo(pair.Private).ToAsn1Object().GetEncoded();

Em Java, como utilizar um chaveiro JKS para autenticar no OpenBus?

É muito comum o uso de um Java Key Store para armazenar chaves privadas e públicas em Java. O OpenBus SDK Java precisa apenas do objeto da classe RSAPrivateKey e ela pode ser obtida a partir de um JKS. Exemplo:

  String privateKeyFile = ... // path para seu arquivo .jks
  String keyStorePassword = ... // senha do seu arquivo .jks (caso tenha definido uma senha)
  String keyPassword = ... // senha da sua chave privada armazenada dentro do .jks (caso tenha definido uma outra senha exclusiva para sua chave privada)
  String alias = ... // apelido do seu par de chaves como foi salvo dentro do .jks

  KeyStore ks = KeyStore.getInstance("jks");
  ks.load(new FileInputStream(privateKeyFile), keyStorePassword.toCharArray());
  Key key = ks.getKey(alias, keyPassword .toCharArray());
  RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) key; 
  ...
  connection.loginByCertificate(entity, rsaPrivateKey); // autenticação por chave privada na API do OpenBus SDK Java

Como converter um certificado X509 no formato DER para o formato PEM?

openssl x509 -in <arquivo de certificado DER.crt> -inform DER -out <arquivo de certificado PEM.crt> -outform PEM

Como analisar o conteúdo de um certificado X509 de uma forma textual?

openssl x509 -text -inform DER -in <arquivo de certificado.crt>

Como gerar um chaveiro JKS a partir de um par de chaves?

Para gerar um chaveiro JKS será preciso ter o par de chaves codificados em PEM (formato textual) já que o comando openssl pkcs12 não trabalha com as variações em DER. Portanto, se sua chave privada e seu certificado estiverem codificados em DER (formato binário) será preciso convertê-los conforme: Como converter chave privada DER para PEMComo converter certificado X509 DER para PEM.

Inicialmente, é preciso criar um arquivo no padrão pkcs12 (tipicamente com extensão p12 ou pfx) a partir do par de chaves (ambos codificados em PEM):

openssl pkcs12 -export -out cert_and_key.p12 -inkey privateKey.key -in certificate.crt

Esse comando pede uma senha que será usada para encriptar o arquivo.

Posteriormente, crie o chaveiro. Exemplo:

keytool -importkeystore -destkeystore my-keystore.jks -srckeystore cert-and-key.p12 -srcstoretype PKCS12 -srcstorepass <password> -alias 1

Importante: No campo <password>, deve ser usada a mesma senha que é usada na criação do arquivo pkcs12.

Caso já exista um chaveiro JKS, o comando é o mesmo acima, sendo que no lugar de my-keystore.jks deve ser usado o nome do arquivo do chaveiro pré-existente.

Como faço para inserir um certificado público em um chaveiro?

keytool -import -trustcacerts -file certificate.crt -alias foo -keystore my-keystore.jks

Neste caso, o certificado será configurado como um certificado confiável. Esse comando é tipicamente usado para inserir o certificado da CA que emitiu a chave pública do certificado da aplicação.

O campo alias funciona como um identificador do certificado dentro do chaveiro (importante pois serve como referência na substituição, atualização e remoção das chaves).

Como analisar o conteúdo de um chaveiro JKS?

keytool -list -v -keystore my-keystore.jks

Qual é a causa da exceção "WARNING Unable to create ServerSocketFactory : Unable to find keystore file my-keystore.jks"?

Causa: Nesse caso, o chaveiro indicado no arquivo de propriedades do jacorb (ou na linha de comando) não foi encontrado.

Solução: Verifique se o arquivo encontra-se no build path (eclipse), classpath ou se o caminho/nome estão corretos.

O que causa a exceção "WARNING Unable to create ServerSocketFactory : Cannot recover key"?

Causa: O mais provável é que a senha do chaveiro esteja diferente da senha da chave privada, ou seja, a senha usada para criar o arquivo pkcs12 com o par de chaves não é a mesma utilizada na criação/leitura do chaveiro.

Solução: Recrie o arquivo pkcs12 com a mesma senha do chaveiro e reinsira o conteúdo do arquivo no chaveiro (usando o mesmo alias para sobreescrever o par de chaves), ou então recrie o chaveiro usando a mesma senha usada para criar o arquivo pkcs12.

OpenSSL

Qual versão do OpenSSL é preciso usar?

É preciso usar a versão 1.0.0 (ou superior) do OpenSSL.

Estou no Windows, existe OpenSSL para Windows?

Sim, existe. Neste caso você precisa instalar o binário do OpenSSL:

Como encontrar o comando OpenSSL em uma instalação do OpenBus?

O OpenSSL NÃO É MAIS distribuído como parte do pacote do OpenBus Core.

Logs do OpenBus Core

Que tipo de situações não-planejadas podem acontecer?

Haver um erro na infraestrutura como falta de espaço em disco, falha nos pontos de montagem do NFS, indisponibilidade da rede, LDAP irresponsivo ou lento nas autenticações de usuário/senha.

Erros na camada da aplicação eventualmente reportados por usuários como "não estou conseguindo mais autenticar" tipicamente precisam ser analisados entrando camada a camada.

  • Exemplos:
    • Os erros LDAP aparecem nos logs em longas linhas, pois refletem as tentativas combinadas de autenticações em replicadores de domínio (pois estão configurados vários servidores e vários domínios):
      • Se alguém está tentando se autenticar com usuário/senha (exemplo: usuário fulano), é possível perceber nos logs se trata-se de um erro na autenticação LDAP (erro da senha ou nome de usuário inexistente são reportados como Invalid credentials pela biblioteca LDAP), exemplo de saída em log (configuração do servidor ldaps://ldap.servidor.com.br e domínios @dominio.servidor.com.br e @outrodominio.servidor.com.br):

        23/09/2016 15:05:03 [exception]    192.168.184.76:42136 failed password validation (validator="openbus.core.services.passwordvalidator.LDAP" entity="fulano"
        errmsg=[[ldap access failed (errmsg='ldap access attempt failed (user="fulano@dominio.servidor.com.br" errmsg="Invalid credentials" server="ldaps://ldap.servidor.com.br"); ldap access attempt failed (user="fulano@outrodominio.servidor.com.br" errmsg="Invalid credentials" server="ldaps://ldap.servidor.com.br")')]])
        23/09/2016 15:05:03 [exception]    192.168.184.76:42136 AccessDenied (entity="fulano")
      • Se os servidores LDAP estão negando requisições, é possível perceber nos logs o erro de comunicação com os servidores LDAP (reportados como Can't contact LDAP server pela biblioteca LDAP), exemplo de saída em log (configuração dos servidores ldaps://ldap.servidor.com.br e ldaps://ldap2.servidor.com.br e domínios @dominio.servidor.com.br e @outrodominio.servidor.com.br):

        26/09/2016 10:15:22 [exception]    192.168.234.52:50272 failed password validation (validator="openbus.core.services.passwordvalidator.LDAP" entity="fulano" errmsg=[=[ldap access failed 
        (errmsg=[[ldap access attempt failed (server="ldaps://ldap.servidor.com.br" user="fulano@dominio.servidor.com.br" errmsg="Can't contact LDAP server"); 
        ldap access attempt failed (server="ldaps://ldap.servidor.com.br" user="fulano@dominio.servidor.com.br" errmsg="Can't contact LDAP server"); 
        ldap access attempt failed (server="ldaps://ldap.servidor.com.br" user="fulano@outrodominio.servidor.com.br" errmsg="Can't contact LDAP server"); 
        ldap access attempt failed (server="ldaps://ldap2.servidor.com.br" user="fulano@dominio.servidor.com.br" errmsg="Can't contact LDAP server"); 
        ldap access attempt failed (server="ldaps://ldap2.servidor.com.br" user="fulano@outrodominio.servidor.com.br" errmsg="Can't contact LDAP server")]])]=])
        26/09/2016 10:15:22 [exception]    192.168.234.52:50272 AccessDenied (entity="fulano")
    • Se algum sistema está tentando se autenticar com uma chave privada mas está pegando uma exceção de MissingCertificate, então a aplicação está usando um nome de entidade que não tem certificado cadastrado, exemplo de saída em log:

      23/09/2016 15:09:50 [exception]   192.168.184.76:42163 MissingCertificate (entity="meunovo_sistema_brasil")
    • Ou então, o sistema pode estar tentando se autenticar com chave privada usando um nome de entidade cadastrada mas com uma chave privada errada, nesse caso, só aparece a tentativa do login mas não sua conclusão exemplo de saída em log:

      23/09/2016 14:56:02 [request]     192.168.137.6:45281 login by certificate initiated (entity="sistemacorreto_brasil")
    • Quando um login por chave privada é concluído com sucesso, o log indicará uma mensagem de "login process concluded" oriundo do mesmo IP e indicando qual foi o LoginId? gerado, exemplo de um caso válido:

      23/09/2016 14:56:27 [request]     192.168.137.6:45281 login process concluded (entity="sistemacorreto_brasil" login="0cc0a4c2-81b7-11e6-91d9-0050569e00ad")

Quais são os níveis e o que querem dizer as tags presentes nos logs?

Existem os níveis de log do processo do barramento:

  1. error : erros lançados durante a execução do serviço, se apresentam em dois tipos de tags:
    • unexpected : erros não esperados, normalmente indica um defeito
    • failure : exceções causadas por problemas no serviço em si
  2. warn : condições adversas encontradas, mas que não impedem o funcionamento, se apresentam em dois tipos de tags:
    • exception : exceções causadas por problemas nas requisições (do inglês: requests) recebidas
    • misconfig : erros na configuração do serviço que são ignorados
  3. info : informações de depuração para o administrador, se apresentam em três tipos de tags:
    • config : informações sobre os parâmetros de configuração do serviço
    • admin : requisições executadas exclusivamente por administradores
    • uptime : informações sobre o início e a finalização do serviço ou outros eventos do seu ciclo de vida
  4. debug : informações de depuração para usuários do serviço, se apresentam em dois tipos de tags:
    • request : alterações no estado do serviço como resultado de uma requisição externa, como uma chamada remota
    • action : alterações no estado do serviço iniciadas pelo próprio serviço, como alguma auto-limpeza
  5. access : informações sobre as requisições interceptadas e que dizem respeito ao protocolo OpenBus
  6. multiplex : informações de depuração mais fina sobre os logins utilizados nas chamadas
  7. database : informações de depuração mais fina sobre a camada de persistência (existe para versões maiores que 2.0.0.9)

Alguns exemplos de logs:

  • exception

    02/08/2016 17:58:29 [exception] 192.168.184.76:45158 UnauthorizedFacets (facets={ "HelloService-v1.2", "HelloService", } entity="fulano")
  • config

    26/09/2016 11:32:50 [config] administrative rights granted (entity="cicrano"))
  • uptime

    27/09/2016 21:01:31 [uptime]                          core services started
  • admin

    02/08/2016 16:30:18 [admin]      192.168.184.76:13700 granted interface removed from entity (interface="IDL:hello/services/v1_01/HelloService:1.0" entity="fulano")
  • request

    28/09/2016 10:13:39 [request]    192.168.234.52:43295 logout performed (entity="fulano" login="5f4673ce-857d-11e6-ae51-0050569e00fc")
  • action

    02/08/2016 16:32:24 [action]                          login expired (entity="sistemacorreto_brasil" login="1c3f8984-58e2-11e6-91d9-0050569e00ad")
  • access

    28/09/2016 04:31:01 [access]     192.168.234.53:38639 got bus call (operation="findServices" remote="28bf0dd2-7b48-11e6-91d9-0050569e00ad" entity="sistemacorreto_brasil")

Em geral nas linhas de cada tipo de log normalmente há a indicação do LoginId da aplicação que está executando a chamada (exemplo: operation="renew" remote="8ee2ce96-8138-11e6-91d9-0050569e00ad" entity="sistemacliente_brasil") ou que é alvo de uma resposta (exemplo: entity="sistemacorreto_brasil" login="7c0e62c4-a5f8-11e5-b1ab-0050569e00ad").

Outros

Como saber a versão da GNU Lib C do seu sistema?

Em sistemas Linux é importante utilizar o sistema de pacotes da distribuição, veja alguns exemplos:

  1. Nos sistemas baseados no RPM (CentOS, Red Hat, Fedora, SuSE) basta executar:

    $ rpm -qa glibc
    glibc-2.5-34
    

    Nesse caso, a versão da glibc é 2.5 (desconsidere o resto da string -34 porque esse é um número de patch dependente da distribuição que não tem grande importância para a compatibilidade binária).

  2. Nos sistemas baseados no DPKG (Debian, Ubuntu) basta executar:

    $ dpkg -l libc6
    ii  libc6       2.11.1-0ubuntu7.7      Embedded GNU C Library: Shared libraries
    

    Nesse caso, a versão da glibc é 2.11.1 (desconsidere o resto da string -0ubuntu7.7 porque esse é um número de patch dependente da distribuição que não tem grande importância para a compatibilidade binária).

Como saber a versão da GNU C++ Standard Library do seu sistema?

Todas as versões podem ser consultadas no manual da libstdc++ presente no site da GNU: http://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html.

Em sistemas Linux, basta verificar o nome completo do arquivo da biblioteca pois ele contém a versão conforme a ABI:

$ ls -l /usr/lib/libstdc++*
lrwxrwxrwx 1 root root     19 2010-05-11 14:53 /usr/lib/libstdc++.so.6 -> libstdc++.so.6.0.13
-rw-r--r-- 1 root root 975088 2010-03-26 19:43 /usr/lib/libstdc++.so.6.0.13

Portanto, no caso desse exemplo acima, a versão da libstdc++ do sistema é 6.0.13.

  • No labels
Write a comment…