Nesse post quero falar de como prover segurança na troca de mensagens utilizando JBoss Messaging. Segurança é um conceito bem amplo. Em termos da mensagens, o que queremos é:
- autenticidade: garantia de que a mensagem é de quem achamos que é;
- integridade: garantia que a mensagem é a que foi escrita originalmente;
- confidencialidade: garantia que a mensagem não foi lida por mais ninguém.
Também não queremos que qualquer consumidor leia da fila. Portanto, além de todas essas garantias, vamos adicionar autenticação e autorização para restringir o acesso ao nosso provedor JMS.
Como alguns já devem ter notado, grande parte dos nossos requisitos são atendidos utilizado-se Certificados Digitais. E é justamente o que vamos usar.
Utilizando um canal SSL para envio de mensagens
O JBoss Messaging (JBM) utiliza um subprojeto da JBoss chamado JBoss Remoting para comunicação de rede. Para utilizarmos SSL, basta configurar o conector do JBoss Remoting para utilizar um socket SSL. Para nossa sorte a equipe da JBoss já fez isso para nós, basta copiar o arquivo $JBOSS_HOME/docs/examples/jms/remoting-sslbisocket-service.xml para a pasta de deploy.
Será preciso criar um Keystore $JBOSS_HOME/server/default/conf/messaging.keystore com a par de chaves e o certificado. Se o certificado for auto-assinado, será também preciso adicioná-lo Truststore do cliente. A senha do Keystore deve ser “secureexample”.
Para produção é possível alterar configurações de keystore e senha no MBean org.jboss.remoting.security.SSLSocketBuilder, dentro do arquivo remoting-sslbisocket-service.xml que copiamos.
Feito isso, vamos criar um ConnectionFactory que utilize esse conector. Dentro de deploy, crie um arquivo messaging-secure-socket-service.xml:
<?xml version="1.0" encoding="UTF-8"?>
<server>
<mbean code="org.jboss.jms.server.connectionfactory.ConnectionFactory"
name="jboss.messaging.destination:service=SecureConnectionFactory"
xmbean-dd="xmdesc/ConnectionFactory-xmbean.xml">
<depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends>
<depends optional-attribute-name="Connector">jboss.messaging:service=Connector,transport=sslbisocket</depends>
<attribute name="JNDIBindings">
<bindings>
<binding>/SecureConnectionFactory</binding>
</bindings>
</attribute>
</mbean>
</server>
Note que o atributo Connector possui o Name do MBean que utiliza o conector SSL. Estamos informando para o JBoss que esse ConnectionFactory deve utilizar um canal SSL. Sempre que o client utilizar um ConnectionFactory obtido pelo lookup de “/SecureConnectionFactory” estará se comunicando em um canal encriptado.
NOTA: cuidado para não utilizar binds JNDI padrões do JBM, definidos em connection-factories-service.xml. Eles usam o jboss.messaging:service=Connector,transport=bisocket, que não utiliza Certificado.
Configurando autenticação/autorização para filas
Para autenticar o client vamos utilizar usuário/senha. O JBM por padrão utiliza o Security Domain “messaging” definido em messaging-jboss-beans.xml, que utiliza datasource DefaultDS. Nesse mesmo arquivo é possível alterar o Security Domain utilizado.
As definições de autorização devem ser feitas por fila. Ao definir uma fila, devemos fazê-lo da seguinte forma:
<?xml version="1.0" encoding="UTF-8"?>
<server>
<mbean code="org.jboss.jms.server.destination.QueueService"
name="jboss.messaging.destination:service=Queue,name=securityTestQueue"
xmbean-dd="xmdesc/Queue-xmbean.xml">
<depends optional-attribute-name="ServerPeer">jboss.messaging:service=ServerPeer</depends>
<depends>jboss.messaging:service=PostOffice</depends>
<attribute name="SecurityConfig">
<security>
<role name="guest" read="false" write="false" create="false" />
<role name="publisher" read="true" write="true" create="true" />
</security>
</attribute>
</mbean>
</server>
Note o atributo SecurityConfig. Acho que é tudo bem auto-explicativo, a não ser o create. Esse atributo se aplica a tópico e dá o privilégio do client criar uma subscrição DURABLE.
O para publicar na fila, o client deve obter uma conexão usando a chamada createConnection() que passa usuário e senha:
javax.jms.ConnectionFactory.createConnection(username, password);
NOTA: cuidado ao utilizar os arquivos *-persistence-service.xml que vêm de exemplo no JBoss. Alguns usuário padrões são definidos neles e podem ser utilizados para obter acesso privilegiado. Em um post anterior postei mais informações sobre o JBoss Messaging.
Criando um MDB para consumir
Para consumir mensagens autenticando-se e utilizando o ConnectionFactory sobre SSL, o MDB deve ser configurado com algumas propriedade a mais:
@MessageDriven(activationConfig =
{
@ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Queue"),
@ActivationConfigProperty(propertyName="destination", propertyValue="queue/securityTestQueue"),
@ActivationConfigProperty(propertyName="ConnectionFactoryName", propertyValue="SecureConnectionFactory"),
@ActivationConfigProperty(propertyName="user", propertyValue="john"),
@ActivationConfigProperty(propertyName="password", propertyValue="needle")
})
public class QueueConsumer implements MessageListener {
public void onMessage(Message message) {
System.out.println(this.getClass().getName() + " -> " + message);
}
}
That’s it!