Commit 8b79c667 authored by Stephane Nicoll's avatar Stephane Nicoll

Polish "Secured HornetQ" contribution

Closes gh-6071
parent 1aa8f490
/* /*
* Copyright 2012-2015 the original author or authors. * Copyright 2012-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -39,7 +39,7 @@ class HornetQConnectionFactoryConfiguration { ...@@ -39,7 +39,7 @@ class HornetQConnectionFactoryConfiguration {
public HornetQConnectionFactory jmsConnectionFactory(ListableBeanFactory beanFactory, public HornetQConnectionFactory jmsConnectionFactory(ListableBeanFactory beanFactory,
HornetQProperties properties) { HornetQProperties properties) {
return new HornetQConnectionFactoryFactory(beanFactory, properties) return new HornetQConnectionFactoryFactory(beanFactory, properties)
.createConnectionFactory(HornetQSecuredConnectionFactory.class); .createConnectionFactory(SpringBootHornetQConnectionFactory.class);
} }
} }
...@@ -28,6 +28,7 @@ import org.hornetq.core.remoting.impl.netty.NettyConnectorFactory; ...@@ -28,6 +28,7 @@ import org.hornetq.core.remoting.impl.netty.NettyConnectorFactory;
import org.hornetq.core.remoting.impl.netty.TransportConstants; import org.hornetq.core.remoting.impl.netty.TransportConstants;
import org.hornetq.jms.client.HornetQConnectionFactory; import org.hornetq.jms.client.HornetQConnectionFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
...@@ -111,8 +112,9 @@ class HornetQConnectionFactoryFactory { ...@@ -111,8 +112,9 @@ class HornetQConnectionFactoryFactory {
this.properties.getEmbedded().generateTransportParameters()); this.properties.getEmbedded().generateTransportParameters());
ServerLocator serviceLocator = HornetQClient ServerLocator serviceLocator = HornetQClient
.createServerLocatorWithoutHA(transportConfiguration); .createServerLocatorWithoutHA(transportConfiguration);
return factoryClass.getConstructor(HornetQProperties.class, ServerLocator.class) Constructor<T> constructor = factoryClass.getDeclaredConstructor(HornetQProperties.class,
.newInstance(this.properties, serviceLocator); ServerLocator.class);
return BeanUtils.instantiateClass(constructor, this.properties, serviceLocator);
} }
catch (NoClassDefFoundError ex) { catch (NoClassDefFoundError ex) {
throw new IllegalStateException("Unable to create InVM " throw new IllegalStateException("Unable to create InVM "
...@@ -128,9 +130,9 @@ class HornetQConnectionFactoryFactory { ...@@ -128,9 +130,9 @@ class HornetQConnectionFactoryFactory {
params.put(TransportConstants.PORT_PROP_NAME, this.properties.getPort()); params.put(TransportConstants.PORT_PROP_NAME, this.properties.getPort());
TransportConfiguration transportConfiguration = new TransportConfiguration( TransportConfiguration transportConfiguration = new TransportConfiguration(
NettyConnectorFactory.class.getName(), params); NettyConnectorFactory.class.getName(), params);
Constructor<T> constructor = factoryClass.getConstructor(HornetQProperties.class, Constructor<T> constructor = factoryClass.getDeclaredConstructor(HornetQProperties.class,
boolean.class, TransportConfiguration[].class); boolean.class, TransportConfiguration[].class);
return constructor.newInstance(this.properties, false, return BeanUtils.instantiateClass(constructor, this.properties, false,
new TransportConfiguration[] { transportConfiguration }); new TransportConfiguration[] { transportConfiguration });
} }
......
/* /*
* Copyright 2012-2015 the original author or authors. * Copyright 2012-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -51,12 +51,12 @@ public class HornetQProperties { ...@@ -51,12 +51,12 @@ public class HornetQProperties {
private int port = 5445; private int port = 5445;
/** /**
* User for a secured connection. * Login user of the broker.
*/ */
private String user; private String user;
/** /**
* Password for a secured connection. * Login password of the broker.
*/ */
private String password; private String password;
...@@ -86,10 +86,6 @@ public class HornetQProperties { ...@@ -86,10 +86,6 @@ public class HornetQProperties {
this.port = port; this.port = port;
} }
public Embedded getEmbedded() {
return this.embedded;
}
public String getUser() { public String getUser() {
return this.user; return this.user;
} }
...@@ -106,6 +102,10 @@ public class HornetQProperties { ...@@ -106,6 +102,10 @@ public class HornetQProperties {
this.password = password; this.password = password;
} }
public Embedded getEmbedded() {
return this.embedded;
}
/** /**
* Configuration for an embedded HornetQ server. * Configuration for an embedded HornetQ server.
*/ */
......
/* /*
* Copyright 2012-2015 the original author or authors. * Copyright 2012-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -50,13 +50,13 @@ class HornetQXAConnectionFactoryConfiguration { ...@@ -50,13 +50,13 @@ class HornetQXAConnectionFactoryConfiguration {
return wrapper.wrapConnectionFactory( return wrapper.wrapConnectionFactory(
new HornetQConnectionFactoryFactory(beanFactory, properties) new HornetQConnectionFactoryFactory(beanFactory, properties)
.createConnectionFactory( .createConnectionFactory(
HornetQXASecuredConnectionFactory.class)); SpringBootHornetQXAConnectionFactory.class));
} }
@Bean @Bean
public HornetQConnectionFactory nonXaJmsConnectionFactory( public HornetQConnectionFactory nonXaJmsConnectionFactory(
ListableBeanFactory beanFactory, HornetQProperties properties) { ListableBeanFactory beanFactory, HornetQProperties properties) {
return new HornetQConnectionFactoryFactory(beanFactory, properties) return new HornetQConnectionFactoryFactory(beanFactory, properties)
.createConnectionFactory(HornetQSecuredConnectionFactory.class); .createConnectionFactory(SpringBootHornetQConnectionFactory.class);
} }
} }
/* /*
* Copyright 2012-2015 the original author or authors. * Copyright 2012-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -23,32 +23,36 @@ import org.hornetq.api.core.TransportConfiguration; ...@@ -23,32 +23,36 @@ import org.hornetq.api.core.TransportConfiguration;
import org.hornetq.api.core.client.ServerLocator; import org.hornetq.api.core.client.ServerLocator;
import org.hornetq.jms.client.HornetQConnectionFactory; import org.hornetq.jms.client.HornetQConnectionFactory;
import org.springframework.util.StringUtils;
/** /**
* Secured HornetQ implementation of a JMS ConnectionFactory. * A {@link HornetQConnectionFactory} that manages the credentials of the connection.
* *
* @author Stéphane Lagraulet * @author Stéphane Lagraulet
* * @author Stephane Nicoll
* @since 1.4.0
*
*/ */
public class HornetQSecuredConnectionFactory extends HornetQConnectionFactory { class SpringBootHornetQConnectionFactory extends HornetQConnectionFactory {
private HornetQProperties properties; private final HornetQProperties properties;
public HornetQSecuredConnectionFactory(HornetQProperties properties, SpringBootHornetQConnectionFactory(HornetQProperties properties,
final ServerLocator serverLocator) { ServerLocator serverLocator) {
super(serverLocator); super(serverLocator);
this.properties = properties; this.properties = properties;
} }
public HornetQSecuredConnectionFactory(HornetQProperties properties, final boolean ha, SpringBootHornetQConnectionFactory(HornetQProperties properties, boolean ha,
final TransportConfiguration... initialConnectors) { TransportConfiguration... initialConnectors) {
super(ha, initialConnectors); super(ha, initialConnectors);
this.properties = properties; this.properties = properties;
} }
public Connection createConnection() throws JMSException { public Connection createConnection() throws JMSException {
return createConnection(this.properties.getUser(), this.properties.getPassword()); String user = this.properties.getUser();
if (StringUtils.hasText(user)) {
return createConnection(user, this.properties.getPassword());
}
return super.createConnection();
} }
} }
/* /*
* Copyright 2012-2015 the original author or authors. * Copyright 2012-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -23,32 +23,36 @@ import org.hornetq.api.core.TransportConfiguration; ...@@ -23,32 +23,36 @@ import org.hornetq.api.core.TransportConfiguration;
import org.hornetq.api.core.client.ServerLocator; import org.hornetq.api.core.client.ServerLocator;
import org.hornetq.jms.client.HornetQXAConnectionFactory; import org.hornetq.jms.client.HornetQXAConnectionFactory;
import org.springframework.util.StringUtils;
/** /**
* Secured HornetQ XA implementation of a JMS ConnectionFactory. * A {@link HornetQXAConnectionFactory} that manages the credentials of the connection.
* *
* @author Stéphane Lagraulet * @author Stéphane Lagraulet
* * @author Stephane Nicoll
* @since 1.4.0
*
*/ */
public class HornetQXASecuredConnectionFactory extends HornetQXAConnectionFactory { class SpringBootHornetQXAConnectionFactory extends HornetQXAConnectionFactory {
private HornetQProperties properties; private final HornetQProperties properties;
public HornetQXASecuredConnectionFactory(HornetQProperties properties, SpringBootHornetQXAConnectionFactory(HornetQProperties properties,
ServerLocator serverLocator) { ServerLocator serverLocator) {
super(serverLocator); super(serverLocator);
this.properties = properties; this.properties = properties;
} }
public HornetQXASecuredConnectionFactory(HornetQProperties properties, boolean ha, SpringBootHornetQXAConnectionFactory(HornetQProperties properties, boolean ha,
TransportConfiguration... initialConnectors) { TransportConfiguration... initialConnectors) {
super(ha, initialConnectors); super(ha, initialConnectors);
this.properties = properties; this.properties = properties;
} }
public Connection createConnection() throws JMSException { public Connection createConnection() throws JMSException {
return createConnection(this.properties.getUser(), this.properties.getPassword()); String user = this.properties.getUser();
if (StringUtils.hasText(user)) {
return createConnection(user, this.properties.getPassword());
}
return super.createConnection();
} }
} }
...@@ -20,6 +20,7 @@ import java.io.File; ...@@ -20,6 +20,7 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.UUID; import java.util.UUID;
import javax.jms.Connection;
import javax.jms.Destination; import javax.jms.Destination;
import javax.jms.JMSException; import javax.jms.JMSException;
import javax.jms.Message; import javax.jms.Message;
...@@ -55,6 +56,9 @@ import org.springframework.jms.support.destination.DestinationResolver; ...@@ -55,6 +56,9 @@ import org.springframework.jms.support.destination.DestinationResolver;
import org.springframework.jms.support.destination.DynamicDestinationResolver; import org.springframework.jms.support.destination.DynamicDestinationResolver;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
/** /**
* Tests for {@link HornetQAutoConfiguration}. * Tests for {@link HornetQAutoConfiguration}.
...@@ -94,6 +98,22 @@ public class HornetQAutoConfigurationTests { ...@@ -94,6 +98,22 @@ public class HornetQAutoConfigurationTests {
assertNettyConnectionFactory(connectionFactory, "192.168.1.144", 9876); assertNettyConnectionFactory(connectionFactory, "192.168.1.144", 9876);
} }
@Test
public void nativeConnectionFactoryCredentials() throws JMSException {
load(EmptyConfiguration.class, "spring.hornetq.mode:native",
"spring.hornetq.user:user", "spring.hornetq.password:secret");
HornetQConnectionFactory connectionFactory = this.context
.getBean(HornetQConnectionFactory.class);
// Validate the secured variant is invoked
HornetQConnectionFactory testCf = spy(connectionFactory);
Connection connection = mock(Connection.class);
doReturn(connection).when(testCf).createConnection("user", "secret");
Connection actual = testCf.createConnection();
assertThat(actual).isSameAs(connection);
}
@Test @Test
public void embeddedConnectionFactory() { public void embeddedConnectionFactory() {
load(EmptyConfiguration.class, "spring.hornetq.mode:embedded"); load(EmptyConfiguration.class, "spring.hornetq.mode:embedded");
......
...@@ -848,7 +848,9 @@ content into your application; rather pick only the properties that you need. ...@@ -848,7 +848,9 @@ content into your application; rather pick only the properties that you need.
spring.hornetq.embedded.topics= # Comma-separated list of topics to create on startup. spring.hornetq.embedded.topics= # Comma-separated list of topics to create on startup.
spring.hornetq.host=localhost # HornetQ broker host. spring.hornetq.host=localhost # HornetQ broker host.
spring.hornetq.mode= # HornetQ deployment mode, auto-detected by default. Can be explicitly set to "native" or "embedded". spring.hornetq.mode= # HornetQ deployment mode, auto-detected by default. Can be explicitly set to "native" or "embedded".
spring.hornetq.password= # Login password of the broker.
spring.hornetq.port=5445 # HornetQ broker port. spring.hornetq.port=5445 # HornetQ broker port.
spring.hornetq.user= # Login user of the broker.
# JMS ({sc-spring-boot-autoconfigure}/jms/JmsProperties.{sc-ext}[JmsProperties]) # JMS ({sc-spring-boot-autoconfigure}/jms/JmsProperties.{sc-ext}[JmsProperties])
spring.jms.jndi-name= # Connection factory JNDI name. When set, takes precedence to others connection factory auto-configurations. spring.jms.jndi-name= # Connection factory JNDI name. When set, takes precedence to others connection factory auto-configurations.
......
...@@ -3953,6 +3953,8 @@ HornetQ configuration is controlled by external configuration properties in ...@@ -3953,6 +3953,8 @@ HornetQ configuration is controlled by external configuration properties in
spring.hornetq.mode=native spring.hornetq.mode=native
spring.hornetq.host=192.168.1.210 spring.hornetq.host=192.168.1.210
spring.hornetq.port=9876 spring.hornetq.port=9876
spring.hornetq.user=admin
spring.hornetq.password=secret
---- ----
When embedding the broker, you can choose if you want to enable persistence, and the list When embedding the broker, you can choose if you want to enable persistence, and the list
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment