Skip to content

Commit 462efc4

Browse files
artembilangaryrussell
authored andcommitted
GH-970: Add AmqpAppender.verifyHostname option (#971)
* GH-970: Add `AmqpAppender.verifyHostname` option Fixes #970 * Some code polishing and internal refactoring for `AmqpAppender` **Cherry-pick to 2.1.x** * * Fix Checkstyle violations * Add `verifyHostname` to the Log4J `AmqpAppender` * Document `verifyHostname` option
1 parent e57ef88 commit 462efc4

File tree

5 files changed

+68
-31
lines changed

5 files changed

+68
-31
lines changed

spring-rabbit/src/main/java/org/springframework/amqp/rabbit/log4j2/AmqpAppender.java

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.io.UnsupportedEncodingException;
2121
import java.net.URI;
2222
import java.nio.charset.Charset;
23+
import java.nio.charset.StandardCharsets;
2324
import java.util.Calendar;
2425
import java.util.Map;
2526
import java.util.Map.Entry;
@@ -67,6 +68,7 @@
6768
import org.springframework.amqp.rabbit.core.DeclareExchangeConnectionListener;
6869
import org.springframework.amqp.rabbit.core.RabbitAdmin;
6970
import org.springframework.amqp.rabbit.core.RabbitTemplate;
71+
import org.springframework.amqp.utils.JavaUtils;
7072
import org.springframework.core.io.Resource;
7173
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
7274
import org.springframework.retry.RetryPolicy;
@@ -154,6 +156,7 @@ public static AmqpAppender createAppender(// NOSONAR NCSS line count
154156
@PluginAttribute("password") String password,
155157
@PluginAttribute("virtualHost") String virtualHost,
156158
@PluginAttribute("useSsl") boolean useSsl,
159+
@PluginAttribute("verifyHostname") boolean verifyHostname,
157160
@PluginAttribute("sslAlgorithm") String sslAlgorithm,
158161
@PluginAttribute("sslPropertiesLocation") String sslPropertiesLocation,
159162
@PluginAttribute("keyStore") String keyStore,
@@ -197,6 +200,7 @@ public static AmqpAppender createAppender(// NOSONAR NCSS line count
197200
manager.password = password;
198201
manager.virtualHost = virtualHost;
199202
manager.useSsl = useSsl;
203+
manager.verifyHostname = verifyHostname;
200204
manager.sslAlgorithm = sslAlgorithm;
201205
manager.sslPropertiesLocation = sslPropertiesLocation;
202206
manager.keyStore = keyStore;
@@ -327,9 +331,8 @@ private void doSend(Event event, LogEvent logEvent, MessageProperties amqpProps)
327331
String routingKey;
328332
try {
329333
synchronized (this.layoutMutex) {
330-
msgBody = new StringBuilder(new String(getLayout().toByteArray(logEvent), "UTF-8"));
331-
routingKey = new String(this.manager.routingKeyLayout.toByteArray(logEvent),
332-
"UTF-8");
334+
msgBody = new StringBuilder(new String(getLayout().toByteArray(logEvent), StandardCharsets.UTF_8));
335+
routingKey = new String(this.manager.routingKeyLayout.toByteArray(logEvent), StandardCharsets.UTF_8);
333336
}
334337
Message message = null;
335338
if (this.manager.charset != null) {
@@ -400,6 +403,7 @@ public void run() {
400403
Thread.currentThread().interrupt();
401404
}
402405
}
406+
403407
}
404408

405409
/**
@@ -524,6 +528,8 @@ protected static class AmqpManager extends AbstractManager {
524528
*/
525529
private boolean useSsl;
526530

531+
private boolean verifyHostname = true;
532+
527533
/**
528534
* The SSL algorithm to use.
529535
*/
@@ -626,7 +632,7 @@ private boolean activateOptions() {
626632
ConnectionFactory rabbitConnectionFactory = createRabbitConnectionFactory();
627633
if (rabbitConnectionFactory != null) {
628634
this.routingKeyLayout = PatternLayout.newBuilder()
629-
.withPattern(this.routingKeyPattern.replaceAll("%X\\{applicationId\\}", this.applicationId))
635+
.withPattern(this.routingKeyPattern.replaceAll("%X\\{applicationId}", this.applicationId))
630636
.withCharset(Charset.forName(this.charset))
631637
.withAlwaysWriteExceptions(false)
632638
.withNoConsoleNoAnsi(true)
@@ -675,17 +681,18 @@ protected ConnectionFactory createRabbitConnectionFactory() {
675681
* @param factoryBean the {@link RabbitConnectionFactoryBean}.
676682
*/
677683
protected void configureRabbitConnectionFactory(RabbitConnectionFactoryBean factoryBean) {
678-
679-
Optional.ofNullable(this.host).ifPresent(factoryBean::setHost);
680-
Optional.ofNullable(this.port).ifPresent(factoryBean::setPort);
681-
Optional.ofNullable(this.username).ifPresent(factoryBean::setUsername);
682-
Optional.ofNullable(this.password).ifPresent(factoryBean::setPassword);
683-
Optional.ofNullable(this.virtualHost).ifPresent(factoryBean::setVirtualHost);
684-
// overrides all preceding items when set
685-
Optional.ofNullable(this.uri).ifPresent(factoryBean::setUri);
684+
JavaUtils.INSTANCE
685+
.acceptIfNotNull(this.host, factoryBean::setHost)
686+
.acceptIfNotNull(this.port, factoryBean::setPort)
687+
.acceptIfNotNull(this.username, factoryBean::setUsername)
688+
.acceptIfNotNull(this.password, factoryBean::setPassword)
689+
.acceptIfNotNull(this.virtualHost, factoryBean::setVirtualHost)
690+
// overrides all preceding items when set
691+
.acceptIfNotNull(this.uri, factoryBean::setUri);
686692

687693
if (this.useSsl) {
688694
factoryBean.setUseSSL(true);
695+
factoryBean.setEnableHostnameVerification(this.verifyHostname);
689696
if (this.sslAlgorithm != null) {
690697
factoryBean.setSslAlgorithm(this.sslAlgorithm);
691698
}

spring-rabbit/src/main/java/org/springframework/amqp/rabbit/logback/AmqpAppender.java

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import java.util.Calendar;
2222
import java.util.Map;
2323
import java.util.Map.Entry;
24-
import java.util.Optional;
2524
import java.util.Set;
2625
import java.util.Timer;
2726
import java.util.TimerTask;
@@ -49,6 +48,7 @@
4948
import org.springframework.amqp.rabbit.core.DeclareExchangeConnectionListener;
5049
import org.springframework.amqp.rabbit.core.RabbitAdmin;
5150
import org.springframework.amqp.rabbit.core.RabbitTemplate;
51+
import org.springframework.amqp.utils.JavaUtils;
5252
import org.springframework.core.io.Resource;
5353
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
5454
import org.springframework.util.StringUtils;
@@ -64,7 +64,7 @@
6464
import com.rabbitmq.client.ConnectionFactory;
6565

6666
/**
67-
* A Lockback appender that publishes logging events to an AMQP Exchange.
67+
* A Logback appender that publishes logging events to an AMQP Exchange.
6868
* <p>
6969
* A fully-configured AmqpAppender, with every option set to their defaults, would look like this:
7070
*
@@ -272,6 +272,8 @@ public class AmqpAppender extends AppenderBase<ILoggingEvent> {
272272
*/
273273
private String trustStoreType = "JKS";
274274

275+
private boolean verifyHostname = true;
276+
275277
/**
276278
* Default content-type of log messages.
277279
*/
@@ -381,6 +383,25 @@ public void setUseSsl(boolean ssl) {
381383
this.useSsl = ssl;
382384
}
383385

386+
/**
387+
* Enable server hostname verification for TLS connections.
388+
* @param enable false to disable.
389+
* @since 2.1.6
390+
* @see RabbitConnectionFactoryBean#setEnableHostnameVerification(boolean)
391+
*/
392+
public void setVerifyHostname(boolean enable) {
393+
this.verifyHostname = enable;
394+
}
395+
396+
/**
397+
* Return true (default) if TLS hostname verification is enabled.
398+
* @return true (default) if TLS hostname verification is enabled.
399+
* @since 2.1.6
400+
*/
401+
public boolean isVerifyHostname() {
402+
return this.verifyHostname;
403+
}
404+
384405
public String getSslAlgorithm() {
385406
return this.sslAlgorithm;
386407
}
@@ -589,7 +610,6 @@ public void setConnectionName(String connectionName) {
589610
/**
590611
* Set additional client connection properties to be added to the rabbit connection,
591612
* with the form {@code key:value[,key:value]...}.
592-
*
593613
* @param clientConnectionProperties the properties.
594614
* @since 1.5.6
595615
*/
@@ -620,7 +640,7 @@ public void start() {
620640
if (rabbitConnectionFactory != null) {
621641
super.start();
622642
this.routingKeyLayout.setPattern(this.routingKeyLayout.getPattern()
623-
.replaceAll("%property\\{applicationId\\}", this.applicationId));
643+
.replaceAll("%property\\{applicationId}", this.applicationId));
624644
this.routingKeyLayout.setContext(getContext());
625645
this.routingKeyLayout.start();
626646
this.locationLayout.setContext(getContext());
@@ -645,7 +665,6 @@ public void start() {
645665

646666
/**
647667
* Create the {@link ConnectionFactory}.
648-
*
649668
* @return a {@link ConnectionFactory}.
650669
*/
651670
protected ConnectionFactory createRabbitConnectionFactory() {
@@ -664,21 +683,21 @@ protected ConnectionFactory createRabbitConnectionFactory() {
664683
/**
665684
* Configure the {@link RabbitConnectionFactoryBean}. Sub-classes may override to
666685
* customize the configuration of the bean.
667-
*
668686
* @param factoryBean the {@link RabbitConnectionFactoryBean}.
669687
*/
670688
protected void configureRabbitConnectionFactory(RabbitConnectionFactoryBean factoryBean) {
671-
672-
Optional.ofNullable(this.host).ifPresent(factoryBean::setHost);
673-
Optional.ofNullable(this.port).ifPresent(factoryBean::setPort);
674-
Optional.ofNullable(this.username).ifPresent(factoryBean::setUsername);
675-
Optional.ofNullable(this.password).ifPresent(factoryBean::setPassword);
676-
Optional.ofNullable(this.virtualHost).ifPresent(factoryBean::setVirtualHost);
677-
// overrides all preceding items when set
678-
Optional.ofNullable(this.uri).ifPresent(factoryBean::setUri);
689+
JavaUtils.INSTANCE
690+
.acceptIfNotNull(this.host, factoryBean::setHost)
691+
.acceptIfNotNull(this.port, factoryBean::setPort)
692+
.acceptIfNotNull(this.username, factoryBean::setUsername)
693+
.acceptIfNotNull(this.password, factoryBean::setPassword)
694+
.acceptIfNotNull(this.virtualHost, factoryBean::setVirtualHost)
695+
// overrides all preceding items when set
696+
.acceptIfNotNull(this.uri, factoryBean::setUri);
679697

680698
if (this.useSsl) {
681699
factoryBean.setUseSSL(true);
700+
factoryBean.setEnableHostnameVerification(this.verifyHostname);
682701
if (this.sslAlgorithm != null) {
683702
factoryBean.setSslAlgorithm(this.sslAlgorithm);
684703
}
@@ -708,7 +727,6 @@ protected void configureRabbitConnectionFactory(RabbitConnectionFactoryBean fact
708727
/**
709728
* Subclasses can override this method to add properties to the connection client
710729
* properties.
711-
*
712730
* @param clientProperties the client properties.
713731
* @since 1.5.6
714732
*/
@@ -717,7 +735,6 @@ protected void updateConnectionClientProperties(Map<String, Object> clientProper
717735

718736
/**
719737
* Subclasses can override this method to inject a custom queue implementation.
720-
*
721738
* @return the queue to use for queueing logging events before processing them.
722739
* @since 2.0.1
723740
*/
@@ -773,7 +790,6 @@ else if ("headers".equals(this.exchangeType)) {
773790

774791
/**
775792
* Subclasses may modify the final message before sending.
776-
*
777793
* @param message The message.
778794
* @param event The event.
779795
* @return The modified message.
@@ -920,6 +936,7 @@ private byte[] encodeMessage(ILoggingEvent logEvent) {
920936
return msgBody.getBytes(); //NOSONAR (default charset)
921937
}
922938
}
939+
923940
}
924941

925942
/**

spring-rabbit/src/test/java/org/springframework/amqp/rabbit/logback/AmqpAppenderTests.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
/**
3838
*
3939
* @author Stephen Oakey
40+
* @author Artem Bilan
4041
*
4142
* @since 2.0
4243
*/
@@ -99,15 +100,17 @@ public void testDefaultSslConfiguration() {
99100
public void testSslConfigurationWithAlgorithm() {
100101
AmqpAppender appender = new AmqpAppender();
101102
appender.setUseSsl(true);
103+
appender.setVerifyHostname(false);
102104
String sslAlgorithm = "TLSv2";
103105
appender.setSslAlgorithm(sslAlgorithm);
104106

105107
RabbitConnectionFactoryBean bean = mock(RabbitConnectionFactoryBean.class);
106108
appender.configureRabbitConnectionFactory(bean);
107109

108110
verifyDefaultHostProperties(bean);
109-
verify(bean).setUseSSL(eq(true));
110-
verify(bean).setSslAlgorithm(eq(sslAlgorithm));
111+
verify(bean).setUseSSL(true);
112+
verify(bean).setSslAlgorithm(sslAlgorithm);
113+
verify(bean).setEnableHostnameVerification(false);
111114
}
112115

113116
@Test

src/reference/asciidoc/logging.adoc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ Retries are delayed as follows: `N ^ log(N)`, where `N` is the retry number.
7575
| Whether to use SSL for the RabbitMQ connection.
7676
See <<_rabbitconnectionfactorybean_and_configuring_ssl>>
7777

78+
| verifyHostname
79+
| true
80+
| Enable server hostname verification for TLS connections.
81+
See <<_rabbitconnectionfactorybean_and_configuring_ssl>>
82+
7883
| sslAlgorithm
7984
| null
8085
| The SSL algorithm to use.

src/reference/asciidoc/whats-new.adoc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,3 +112,8 @@ A new `ImmediateRequeueAmqpException` is introduced to notify a listener contain
112112
To use this feature, a new `ImmediateRequeueMessageRecoverer` implementation is added.
113113

114114
See <<async-listeners>> for more information.
115+
116+
===== AMQP Logging Appenders Changes
117+
118+
The Log4J and Logback `AmqpAppender` s now support a `verifyHostname` SSL option.
119+
See <<logging>> for more information.

0 commit comments

Comments
 (0)