You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ma...@apache.org on 2020/05/15 09:04:46 UTC
[james-project] branch master updated: JAMES-3183 adds
X-Originating-IP in network mailet matcher
This is an automated email from the ASF dual-hosted git repository.
matthieu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
The following commit(s) were added to refs/heads/master by this push:
new f67aeee JAMES-3183 adds X-Originating-IP in network mailet matcher
f67aeee is described below
commit f67aeee227d6cd672fe5c7f8e0019c7dd2c8cd60
Author: Jean Helou <jh...@codamens.fr>
AuthorDate: Fri Sep 14 17:33:11 2018 +0200
JAMES-3183 adds X-Originating-IP in network mailet matcher
The X-Originating-IP in network matcher checks the X-Originating-Ip
header of the email. It can be used like the RemoteAddrInNetwork to make
decisions on emails in the mailet pipeline.
Co-authored-by: Matthieu Baechler <ma...@apache.org>
---
server/mailet/mailets/pom.xml | 25 +++++
.../mailets/XOriginatingIpInNetwork.scala | 53 +++++++++
.../mailets/XOriginatingIpInNetworkSpec.scala | 125 +++++++++++++++++++++
3 files changed, 203 insertions(+)
diff --git a/server/mailet/mailets/pom.xml b/server/mailet/mailets/pom.xml
index 401c505..6d88d25 100644
--- a/server/mailet/mailets/pom.xml
+++ b/server/mailet/mailets/pom.xml
@@ -32,6 +32,11 @@
<name>Apache James :: Server :: Mailets</name>
+ <properties>
+ <spec2.version>4.9.4</spec2.version>
+ </properties>
+
+
<dependencies>
<dependency>
<groupId>${james.groupId}</groupId>
@@ -225,6 +230,10 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>org.scala-lang</groupId>
+ <artifactId>scala-library</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
@@ -233,6 +242,18 @@
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
+ <groupId>org.specs2</groupId>
+ <artifactId>specs2-core_${scala.base}</artifactId>
+ <version>${spec2.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.specs2</groupId>
+ <artifactId>specs2-junit_${scala.base}</artifactId>
+ <version>${spec2.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>com.jakewharton.byteunits</groupId>
<artifactId>byteunits</artifactId>
<version>0.9.1</version>
@@ -249,6 +270,10 @@
</configuration>
</plugin>
<plugin>
+ <groupId>net.alchim31.maven</groupId>
+ <artifactId>scala-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
diff --git a/server/mailet/mailets/src/main/scala/org/apache/james/transport/mailets/XOriginatingIpInNetwork.scala b/server/mailet/mailets/src/main/scala/org/apache/james/transport/mailets/XOriginatingIpInNetwork.scala
new file mode 100644
index 0000000..ec17304
--- /dev/null
+++ b/server/mailet/mailets/src/main/scala/org/apache/james/transport/mailets/XOriginatingIpInNetwork.scala
@@ -0,0 +1,53 @@
+/** **************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ * ***************************************************************/
+
+package org.apache.james.transport.mailets
+
+import java.util.{Collection => JavaCollection}
+
+import com.google.common.collect.ImmutableList
+import org.apache.james.core.MailAddress
+import org.apache.james.transport.matchers.AbstractNetworkMatcher
+import org.apache.mailet.Mail
+
+object XOriginatingIpInNetwork {
+ val X_ORIGINATING_IP: String = "X-Originating-IP"
+}
+
+/**
+ * <p>
+ * Checks the first X_ORIGINATING_IP IP address against a comma-delimited list
+ * of IP addresses, domain names or sub-nets.
+ * </p>
+ * <p>
+ * See [[AbstractNetworkMatcher]] for details on how to specify entries.
+ * </p>
+ */
+class XOriginatingIpInNetwork extends AbstractNetworkMatcher {
+ override def `match`(mail: Mail): JavaCollection[MailAddress] = matchOnOriginatingAddr(mail).getOrElse(ImmutableList.of())
+
+ def matchOnOriginatingAddr(mail: Mail): Option[JavaCollection[MailAddress]] =
+ Option(mail.getMessage.getHeader(XOriginatingIpInNetwork.X_ORIGINATING_IP))
+ .flatMap(_.headOption)
+ .map(normalizeIP)
+ .filter(matchNetwork)
+ .map(_ => mail.getRecipients)
+
+ private def normalizeIP(ip: String): String = ip.replace("[", "").replace("]", "")
+}
diff --git a/server/mailet/mailets/src/test/scala/org/apache/james/transport/mailets/XOriginatingIpInNetworkSpec.scala b/server/mailet/mailets/src/test/scala/org/apache/james/transport/mailets/XOriginatingIpInNetworkSpec.scala
new file mode 100644
index 0000000..f7dd673
--- /dev/null
+++ b/server/mailet/mailets/src/test/scala/org/apache/james/transport/mailets/XOriginatingIpInNetworkSpec.scala
@@ -0,0 +1,125 @@
+/** **************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ * ***************************************************************/
+
+package org.apache.james.transport.mailets
+
+import org.apache.james.core.MailAddress
+import org.apache.james.core.builder.MimeMessageBuilder
+import org.apache.james.dnsservice.api.{DNSService, InMemoryDNSService}
+import org.apache.james.transport.mailets.XOriginatingIpInNetwork.X_ORIGINATING_IP
+import org.apache.mailet.base.test.{FakeMail, FakeMatcherConfig}
+import org.junit.runner.RunWith
+import org.specs2.matcher.Matchers
+import org.specs2.mutable.Specification
+import org.specs2.runner.JUnitRunner
+
+import scala.jdk.CollectionConverters._
+
+@RunWith(classOf[JUnitRunner])
+class XOriginatingIpInNetworkSpec extends Specification with Matchers {
+ val dnsServer: DNSService =
+ new InMemoryDNSService()
+ .registerMxRecord("192.168.0.1", "192.168.0.1")
+ .registerMxRecord("192.168.200.1", "192.168.200.1")
+ .registerMxRecord("192.168.200.0", "192.168.200.0")
+ .registerMxRecord("255.255.255.0", "255.255.255.0")
+ val matcherConfig: FakeMatcherConfig =
+ FakeMatcherConfig.builder
+ .matcherName("AllowedNetworkIs")
+ .condition("192.168.200.0/24")
+ .build
+
+ "RemoteAddrOrOriginatingIpInNetwork" should {
+ val testRecipient = new MailAddress("test@james.apache.org")
+ val matcher = new XOriginatingIpInNetwork()
+ matcher.setDNSService(dnsServer)
+ matcher.init(matcherConfig)
+
+ s"match when ip of header $X_ORIGINATING_IP is on the same network" in {
+ val fakeMail =
+ FakeMail.builder
+ .name("mailname")
+ .recipient(testRecipient)
+ .remoteAddr("10.0.0.1")
+ .mimeMessage(
+ MimeMessageBuilder.mimeMessageBuilder()
+ .addToRecipient(testRecipient.toInternetAddress)
+ .addHeader(X_ORIGINATING_IP,"192.168.200.1")
+ .build())
+ .build
+
+ val actual = matcher.`match`(fakeMail).asScala
+
+ actual must contain(exactly(testRecipient))
+ }
+
+ s"match when ip of header $X_ORIGINATING_IP is between brackets" in {
+ val fakeMail =
+ FakeMail.builder
+ .name("mailname")
+ .recipient(testRecipient)
+ .remoteAddr("10.0.0.1")
+ .mimeMessage(
+ MimeMessageBuilder.mimeMessageBuilder()
+ .addToRecipient(testRecipient.toInternetAddress)
+ .addHeader(X_ORIGINATING_IP,"[192.168.200.1]")
+ .build())
+ .build
+
+ val actual = matcher.`match`(fakeMail).asScala
+
+ actual must contain(exactly(testRecipient))
+ }
+
+ s"not match when ip of header $X_ORIGINATING_IP is not on the same network" in {
+ val fakeMail =
+ FakeMail.builder
+ .name("mailname")
+ .recipient(testRecipient)
+ .remoteAddr("10.0.0.1")
+ .mimeMessage(
+ MimeMessageBuilder.mimeMessageBuilder()
+ .addToRecipient(testRecipient.toInternetAddress)
+ .addHeader(X_ORIGINATING_IP,"10.0.0.2")
+ .build())
+ .build
+
+ val actual = matcher.`match`(fakeMail).asScala
+
+ actual must beEmpty
+ }
+
+ s"not match when header $X_ORIGINATING_IP is missing" in {
+ val fakeMail =
+ FakeMail.builder
+ .name("mailname")
+ .recipient(testRecipient)
+ .remoteAddr("10.0.0.1")
+ .mimeMessage(
+ MimeMessageBuilder.mimeMessageBuilder()
+ .addToRecipient(testRecipient.toInternetAddress)
+ .build())
+ .build
+
+ val actual = matcher.`match`(fakeMail).asScala
+
+ actual must beEmpty
+ }
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org