Skip to end of metadata
Go to start of metadata

OpenBus 2.1

Quais são as novidades na versão 2.1?

Novidades no serviço do núcleo do OpenBus 2.1:

  • Suporte a SSL nos canais de comunicação: passar a ser possível estabelecer canais encriptados na comunicação com o núcleo do barramento e entre as aplicações. Até a versão 2.0, o protocolo continha a assinatura das partes envolvidas nas chamadas para fins de identificação e auditoria mas não permitia a encriptação automática dos dados sendo trafegados.
  • Suporte a domínios de autenticação: ao se autenticar no núcleo é possível indicar um domínio de autenticação, assim o gerente do barramento pode organizar melhor seus diferentes plugins de autenticação (ex: para testes ou o LDAP oficial da compania).
  • Suporte a validadores de tokens de autenticação externa: passa a ser possível validar tokens de autenticação gerados por outras tecnologias de autenticação (ex: Kerberos ou tokens SAML). A partir da validação do token de autenticação, o solicitante consegue uma cadeia no OpenBus e pode realizar chamadas às aplicações conectadas ao barramento. As aplicações, por sua vez, conseguirão identificar a entidade proprietária desses tokens (ex: o login da pessoa que iniciou a comunicação por outros sistemas).

Novidades para desenvolvedores de serviços e aplicações do OpenBus 2.1:

  • Suporte a renovação automática de recursos no SDK Java: a API de desenvolvimento para Java evoluiu para fazer a gerência automática de logins, ofertas e observadores junto ao barramento. Dessa forma, o programador não precisa mais implementar a callback de OnInvalidLogin nem gerenciar manualmente seus logins, ofertas e observadores quando esses recursos se perdem (seja por instabilidades na camada de comunicação ou no código da aplicação).
  • Java 8: o toolkit de desenvolvimento passou a ser implementado em Java 8 tirando proveito dos novos recursos da linguagem.

Sugestões de leituras para administradores:

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.1?


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.1 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 contexto do OpenBus. 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.1.x.y.
  2. Os arquivos em si estão em idl\tecgraf\openbus\core\v2_1\services\access_control.idl e idl\tecgraf\openbus\core\v2_1\services\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 sobrescrever esses valores no ato do registro, ou seja, utilizando o segundo parâmetro do método registerService do OfferRegistry disponível no 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 (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 possíveis conforme o protocolo do OpenBus:

NomeValorvmcidminorDescrição
NoCredential11128880700x42555000774chamada feita sem credencial
NoLogin11128883190x425550001023conexão atual não está logada
InvalidChain11128880650x42555000769cadeia de chamadas inválida
InvalidPublicKey11128880690x42555000773serviço remoto informou chave pública inválida
InvalidRemote11128883180x425550001022serviço remoto não respeita o protocolo
InvalidTarget11128883160x425550001020serviço remoto com login inválido
UnavailableBus11128883170x425550001021serviço remoto sem acesso ao barramento
UnknownBus11128880680x42555000772serviço remoto está em outro barramento
UnverifiedLogin11128880670x42555000771serviço remoto não pôde verificar o login

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.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. A API utiliza chaves privadas serializadas no formato DER do OpenSSL.


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

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

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>

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.1 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 trocar o CN de um certificado que está em um chaveiro JKS?

O utilitário keytool do pacote da Oracle JDK não possui funcionalidade para trocar ou regerar o certificado de um par de chaves público-privada. É uma dificuldade comum que acaba motivando gerar um novo par de chaves desnecessariamente.

É possível realizar essa tarefa com o uso do OpenSSL exportando o JKS para um PKCS#12. A partir do arquivo PKCS#12 será mais fácil de trabalhar.

  1. Após exportar o chaveiro JKS para um arquivo PKCS#12, o primeiro passo é extrair a chave privada:

    openssl pkcs12 -in <arquivo com extensão p12> -nocerts -out example-privatekey.pem
  2. Gerar um novo certificado com outro CN a partir da chave privada exportada tendo a oportunidade de atualizar o CN (Common Name) e outras informações do certificado:

    openssl req -new -x509 -key example-privatekey.pem -out example-updated-public.crt
  3. Gerar um novo arquivo PKCS#12 contendo a chave privada original e o novo certificado associado ao CN correto:

    openssl pkcs12 -export -out example-updated-keypair.p12 -inkey example-privatekey.pem -in example-updated-public.crt

Por fim basta importar de volta o novo arquivo example-updated-keypair.p12 para o JKS e usar o alias de sua preferência.

Usando SSL

Uma das novas funcionalidades do OPENBUS 2.1.x é o suporte a comunicações CORBA sobre SSL. Para ativar esse suporte é necessário realizar alguns ajustes e configurações e, naturalmente, algumas dúvidas podem surgir. A seguir, listamos algumas dúvidas mais comuns.

Como ativar a comunicação SSL no ORB?

Cada ORB possui uma configuração específica, consulte o manual do ORB para a linguagem de interesse, Java: http://www.jacorb.org, C++: http://www.cs.wustl.edu/~schmidt/TAO.html.

Adicionalmente, mantemos uma página com uma matriz de Interoperabilidade de SSLIOP nos ORBs. Nessa página estão as configurações que usamos em nossos testes.

Qual codificação deve ser usada nos certificados SSL?

A codificação usada é a PEM (Privacy Enhanced Mail). Consequentemente, os certificados devem ser arquivos textuais ASCII. Essa regra é válida tanto para o certificado usado pelo barramento quanto para os certificados utilizados pelas aplicações que desejam utilizar SSL nas suas conexões.

Para aplicações que usam o SDK, convém usar um chaveiro JKS (Java KeyStore) para armazenar o par de chaves (certificado público e chave privada) da aplicação e o certificado público da CA (Certificate Authority) que emitiu assinou a chave pública. Lembremos que o certificado público da CA deve constar no repositório de certificados confiáveis do barramento, para que o barramento possa confiar na procedência do certificado da aplicação.

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.

Possuo um certificado auto-assinado que uso para me autenticar no SDK do OpenBus (via loginByCertificate), mas agora preciso de canais SSL. O que devo fazer?

Você pode continuar usando esse certificado para se autenticar no barramento, da mesma forma que antes. Porém, para fazer uso de canais SSL é preciso obter/gerar um novo certificado assinado por uma CA cujo certificado conste no diretório de certificados de CAs confiáveis do barramento (por padrão, o diretório etc/security/certificates, acessado a partir do diretório de instalação do barramento). Dessa forma, o barramento poderá validar a assinatura do seu novo certificado no estabelecimento do canal SSL. Lembre-se que você agora terá que manter dois certificados distintos: um certificado auto-assinado legado, no formato DER, usado para conexão com o barramento (e que também deve estar armazenado junto ao barramento), e outro certificado no formato PEM assinado por uma CA de confiança do barramento para o uso de SSL.

RECOMENDAÇÂO: Após obter um novo certificado assinado por uma CA, você pode usá-lo para substituir o auto-assinado. Dessa forma, o novo certificado terá uma dupla função. Para tanto, informe ao administrador do barramento a sua intenção de fazer a subsituição, repassando o novo certificado, convertido para DER. Contudo, lembre-se de que, ao contrário dos certificados auto-assinados que podem conter datas de expiração arbitrariamente distantes, os certificados assinados por CAs possuem datas de expiração mais curtas (tipicamente 1 ou 2 anos). Você deve renovar o seu certificado quando a data de expiração estiver próxima e (caso ele esteja sendo usado para a dupla função) atualizá-lo junto ao barramento. Além disso, lembre-se que para se conectar ao barramento o certificado precisa estar no formato DER enquanto que para uso de SSL o certificado precisa estar no formato PEM. Aconselhamos manter dois arquivos com o mesmo nome mas extensões diferentes, um com extensão .pem e outro com extensão .crt, para os seus devidos fins. Será o mesmo certificado, porém em dois formatos distintos.

Já possuo um certificado assinado por um provedor de certificados (Certificate Authority) e utilizo-o para me autenticar no SDK do OpenBus (via loginByCertificate). Posso utilizá-lo para realizar comunicações sobre SSL?

Sim, e é o que recomendamos (ler tópico acima).

Não tenho nenhum certificado, é a primeira vez que uso o barramento. Como proceder?

Você deve obter um certificado assinado por uma CA e, então, poderá utilizá-lo tanto para se conectar ao barramento como para realizar conexões CORBA sobre SSL (ver tópicos acima).

Como saber se o meu certificado é auto-assinado?

Os certificados digitais possuem diversas informações, entre elas, o DN (distinguished name) do "dono" do certificado (subject) e o DN de quem o assinou (issuer). Para verificar essas informações, digite o comando abaixo e procure pelos campos subject e issuer.

openssl x509 -in my_certificate.crt -text -noout (ou openssl x509 -in my_certificate.crt -text -noout -inform DER para certificados no formato binário)

O exemplo abaixo mostra um trecho da saída que é mostrada com o comando acima:

...
 Issuer: C=BR, ST=Berkshire, L=Newbury, O=XPTO Corp, OU=Devops Lab, CN=Simple CA for Test Purposes
        Validity
            Not Before: Feb 17 20:11:13 2016 GMT
            Not After : Feb 17 20:21:13 2018 GMT
        Subject: C=BR, L=Default City, O=XPTO Corp, OU=IT Lab, CN=test-host@xptocorp.com
...

Em certificados auto-assinados, os campos Issuer e Subject são idênticos. Em certificados assinados, esses campos são diferentes e o Issuer indentifica quem o assinou.

Estou tentando configurar SSL mas uso connectByAddress(host, port) para fazer a conexão com o barramento. Está correto?

Não. Esse método é comumente utilizado para fazer conexões com o barramento na versão 2.0. Ele ainda pode ser utilizado no SDK 2.1, contudo, usando o endereço no formato de "host" e "port", a invocação ao IIOP Listener/Handler é realizada sem as proteções oferecidas pelo protocolo SSL. Para fazer uso de SSL é imperativo o uso do método connectByReference(ior) cujo parâmetro recebido deve ser o endereço do barramento na forma de IOR ou corbaloc. Exemplo (usando SDK Java):

Connection conn = context.connectByReference(orb.string_to_object("IOR:01ffffff1c00000049444c3a7363732f636f72652f49436f6d706f6e656e743a312e300003000000000000004c000000010102ff1d000"));

ou

Connection conn = context.connectByReference(orb.string_to_object("corbaloc:ssliop:1.2@"+host+":"+port+"/OpenBus_2_1"));

O IOR ou a string corbaloc a ser usada, devem ser obtidos junto ao administrador do barramento. Lembrando que "port" deve ser a porta usada para comunicação via SSL.

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.

ComoConverterX509DERparaPEM

  • No labels