This is an automated email from the ASF dual-hosted git repository. btellier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-jspf.git
commit 530227acacd5018a752f7aad887793309768cfa2 Author: Emerson Pinter <e...@pinter.dev> AuthorDate: Fri Jan 24 15:53:53 2025 -0300 Add more tests --- .../org/apache/james/jspf/SPFExecutorBaseTest.java | 193 +++++++++++++++++++++ .../dnszones/SPFExecutorIntegrationTest-1.zone | 12 ++ 2 files changed, 205 insertions(+) diff --git a/resolver/src/test/java/org/apache/james/jspf/SPFExecutorBaseTest.java b/resolver/src/test/java/org/apache/james/jspf/SPFExecutorBaseTest.java index ae1c296..acdc376 100644 --- a/resolver/src/test/java/org/apache/james/jspf/SPFExecutorBaseTest.java +++ b/resolver/src/test/java/org/apache/james/jspf/SPFExecutorBaseTest.java @@ -1,22 +1,33 @@ package org.apache.james.jspf; import org.apache.james.jspf.core.DNSService; +import org.apache.james.jspf.core.exceptions.SPFErrorConstants; import org.apache.james.jspf.executor.SPFResult; +import org.apache.james.jspf.helpers.FakeResolver; import org.apache.james.jspf.impl.DNSServiceXBillImpl; import org.apache.james.jspf.impl.SPF; import org.junit.Before; import org.junit.Test; import org.xbill.DNS.DClass; import org.xbill.DNS.Lookup; +import org.xbill.DNS.Name; import org.xbill.DNS.Resolver; +import org.xbill.DNS.SPFRecord; import org.xbill.DNS.SimpleResolver; +import org.xbill.DNS.TXTRecord; +import org.xbill.DNS.TextParseException; +import java.io.IOException; import java.net.UnknownHostException; +import java.nio.file.Paths; import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.Collectors; +import java.util.stream.IntStream; import static org.junit.Assert.assertEquals; public abstract class SPFExecutorBaseTest { + protected final String zonesDir = "src/test/resources/dnszones"; protected abstract SPF createSPF(); @@ -27,6 +38,10 @@ public abstract class SPFExecutorBaseTest { Lookup.getDefaultCache(DClass.IN).clearCache(); } + public String getZonePath(String zoneFile) { + return Paths.get(zonesDir, zoneFile).toAbsolutePath().toString(); + } + @Test public void test() { SPF spf = createSPF(); @@ -68,4 +83,182 @@ public abstract class SPFExecutorBaseTest { assertEquals("Received-SPF: temperror (spfCheck: Error in retrieving data from DNS) client-ip=207.54.72.202; envelope-from=do_not_re...@reyifglerifwukfvbdjhrkbvebvekvfulervkerkeruerbeb.de; helo=reyifglerifwukfvbdjhrkbvebvekvfulervkerkeruerbeb.de;", result.getHeader()); } + + @Test + public void shouldReturnPassIfJustOneTxtSpf1Record() throws IOException { + String testDomain = "spfexecutor.fake"; + String hostname = "shouldReturnPassIfJustOneTxtSpf1Record." + testDomain; + String ip = "192.0.2.127"; + + //setup resolver + FakeResolver fakeResolver = new FakeResolver(); + fakeResolver.fromZoneFile(testDomain, getZonePath("SPFExecutorIntegrationTest-1.zone")); + fakeResolver.addRecords(FakeResolver.genNRandomTXTRecords(hostname + ".", 300)); + + SPF spf = createCustomSPF(new DNSServiceXBillImpl(fakeResolver)); + SPFResult result = spf.checkSPF(ip, "a_user@" + hostname, hostname); + assertEquals(String.format( + "Received-SPF: %3$s (spfCheck: domain of %2$s designates %1$s as permitted sender) client-ip=%1$s; envelope-from=a_user@%2$s; helo=%2$s;", + ip, hostname, SPFErrorConstants.PASS_CONV), + result.getHeader()); + assertEquals(SPFErrorConstants.PASS_CONV, result.getResult()); + } + + @Test + public void shouldReturnErrorIfMoreThanOneTxtSpf1Record() throws IOException { + String testDomain = "spfexecutor.fake"; + String hostname = "shouldReturnErrorIfMoreThanOneTxtSpf1Record." + testDomain; + String ip = "192.0.2.127"; + + //setup resolver + FakeResolver fakeResolver = new FakeResolver(); + fakeResolver.fromZoneFile(testDomain, getZonePath("SPFExecutorIntegrationTest-1.zone")); + + SPF spf = createCustomSPF(new DNSServiceXBillImpl(fakeResolver)); + SPFResult result = spf.checkSPF(ip, "a_user@" + hostname, hostname); + assertEquals(String.format( + "Received-SPF: %3$s (spfCheck: Error in processing SPF Record) client-ip=%1$s; envelope-from=a_user@%2$s; helo=%2$s;", + ip, hostname, SPFErrorConstants.PERM_ERROR_CONV), + result.getHeader()); + assertEquals(SPFErrorConstants.PERM_ERROR_CONV, result.getResult()); + } + + @Test + public void shouldReturnErrorIfMoreThanOneSpfRecord() throws IOException { + String testDomain = "spfexecutor.fake"; + String hostname = "shouldReturnErrorIfMoreThanOneSpfRecord." + testDomain; + String ip = "192.0.2.127"; + + //setup resolver + FakeResolver fakeResolver = new FakeResolver(); + fakeResolver.setRecords(FakeResolver.genNRandomTXTRecords(hostname + ".", 300)); + fakeResolver.addRecord(new SPFRecord( + Name.fromString(hostname + "."), DClass.IN, 30L, String.format("v=spf1 ip4:%s ip4:1.1.1.1 -all", ip))); + fakeResolver.addRecord(new SPFRecord( + Name.fromString(hostname + "."), DClass.IN, 30L, String.format("v=spf1 ip4:%s -all", ip))); + + SPF spf = createCustomSPF(new DNSServiceXBillImpl(fakeResolver)); + SPFResult result = spf.checkSPF(ip, "a_user@" + hostname, hostname); + assertEquals(String.format( + "Received-SPF: %3$s (spfCheck: Error in processing SPF Record) client-ip=%1$s; envelope-from=a_user@%2$s; helo=%2$s;", + ip, hostname, SPFErrorConstants.PERM_ERROR_CONV), + result.getHeader()); + assertEquals(SPFErrorConstants.PERM_ERROR_CONV, result.getResult()); + } + + /* + * Test the limit described in RFC7208 section "4.6.4. DNS Lookup Limits" + */ + @Test + public void shouldReturnErrorIfDepthMoreThan10() throws IOException { + String testDomain = "spfexecutor.fake"; + String hostname = "shouldReturnErrorIfDepthMoreThan10." + testDomain; + String ip = "192.0.2.127"; + + //setup resolver + FakeResolver fakeResolver = new FakeResolver(); + fakeResolver.addRecord(new TXTRecord(Name.fromString(hostname + "."), + DClass.IN, 30L, String.format("v=spf1 ip4:4.3.2.1 include:depth0.%s -all", hostname))); + + fakeResolver.addRecords(IntStream.range(0, 10).mapToObj( + i -> { + try { + String txt = String.format("v=spf1 ip4:4.3.2.2 include:depth%s.%s -all", i + 1, hostname); + return new TXTRecord( + Name.fromString(String.format("depth%s.%s.", i, hostname), Name.fromString(testDomain)), + DClass.IN, 30L, txt); + } catch (TextParseException e) { + throw new RuntimeException(e); + } + }).collect(Collectors.toList())); + + + SPF spf = createCustomSPF(new DNSServiceXBillImpl(fakeResolver)); + SPFResult result = spf.checkSPF(ip, "a_user@" + hostname, hostname); + assertEquals(String.format( + "Received-SPF: %3$s (spfCheck: Error in processing SPF Record) client-ip=%1$s; envelope-from=a_user@%2$s; helo=%2$s;", + ip, hostname, SPFErrorConstants.PERM_ERROR_CONV), + result.getHeader()); + assertEquals(SPFErrorConstants.PERM_ERROR_CONV, result.getResult()); + } + + /* + * Test the limit described in RFC7208 section "4.6.4. DNS Lookup Limits" + */ + @Test + public void shouldReturnPassIfDepth10orLess() throws IOException { + String testDomain = "spfexecutor.fake"; + String hostname = "shouldReturnPassIfDepth10OrLess." + testDomain; + String ip = "192.0.2.127"; + + //setup resolver + FakeResolver fakeResolver = new FakeResolver(); + fakeResolver.addRecord(new TXTRecord(Name.fromString(hostname + "."), + DClass.IN, 30L, String.format("v=spf1 ip4:4.3.2.1 include:depth0.%s -all", hostname))); + + int count = 10; + fakeResolver.addRecords(IntStream.range(0, count).mapToObj( + i -> { + try { + String txt; + if (i == count - 1) { + txt = String.format("v=spf1 ip4:4.3.2.2 ip4:%s -all", ip); + } else { + txt = String.format("v=spf1 ip4:4.3.2.2 include:depth%s.%s -all", i + 1, hostname); + } + return new TXTRecord( + Name.fromString(String.format("depth%s.%s.", i, hostname), Name.fromString(testDomain)), + DClass.IN, 30L, txt); + } catch (TextParseException e) { + throw new RuntimeException(e); + } + }).collect(Collectors.toList())); + + + SPF spf = createCustomSPF(new DNSServiceXBillImpl(fakeResolver)); + SPFResult result = spf.checkSPF(ip, "a_user@" + hostname, hostname); + assertEquals(String.format( + "Received-SPF: %3$s (spfCheck: domain of %2$s designates %1$s as permitted sender) client-ip=%1$s; envelope-from=a_user@%2$s; helo=%2$s;", + ip, hostname, SPFErrorConstants.PASS_CONV), + result.getHeader()); + assertEquals(SPFErrorConstants.PASS_CONV, result.getResult()); + } + + @Test + public void shouldReturnPermErrorIfIncludeDomainNotFound() throws IOException { + String testDomain = "spfexecutor.fake"; + String hostname = "shouldReturnPermErrorIfIncludeDomainNotFound." + testDomain; + String ip = "192.0.2.127"; + + //setup resolver + FakeResolver fakeResolver = new FakeResolver(); + fakeResolver.fromZoneFile(testDomain, getZonePath("SPFExecutorIntegrationTest-1.zone")); + + SPF spf = createCustomSPF(new DNSServiceXBillImpl(fakeResolver)); + SPFResult result = spf.checkSPF(ip, "a_user@" + hostname, hostname); + assertEquals(String.format( + "Received-SPF: %3$s (spfCheck: Error in processing SPF Record) client-ip=%1$s; envelope-from=a_user@%2$s; helo=%2$s;", + ip, hostname, SPFErrorConstants.PERM_ERROR_CONV), + result.getHeader()); + assertEquals(SPFErrorConstants.PERM_ERROR_CONV, result.getResult()); + } + + @Test + public void shouldHandleMultipleStrings() throws IOException { + String testDomain = "spfexecutor.fake"; + String hostname = "shouldReturnPassIfMultipleStrings." + testDomain; + String ip = "192.0.2.127"; + + //setup resolver + FakeResolver fakeResolver = new FakeResolver(); + fakeResolver.fromZoneFile(testDomain, getZonePath("SPFExecutorIntegrationTest-1.zone")); + + SPF spf = createCustomSPF(new DNSServiceXBillImpl(fakeResolver)); + SPFResult result = spf.checkSPF(ip, "a_user@" + hostname, hostname); + assertEquals(String.format( + "Received-SPF: %3$s (spfCheck: domain of %2$s designates %1$s as permitted sender) client-ip=%1$s; envelope-from=a_user@%2$s; helo=%2$s;", + ip, hostname, SPFErrorConstants.PASS_CONV), + result.getHeader()); + assertEquals(SPFErrorConstants.PASS_CONV, result.getResult()); + } } diff --git a/resolver/src/test/resources/dnszones/SPFExecutorIntegrationTest-1.zone b/resolver/src/test/resources/dnszones/SPFExecutorIntegrationTest-1.zone new file mode 100644 index 0000000..8898bee --- /dev/null +++ b/resolver/src/test/resources/dnszones/SPFExecutorIntegrationTest-1.zone @@ -0,0 +1,12 @@ +$TTL 30 +@ 30 IN SOA ns1.fakeresolver.apache. hostmaster.fakeresolver.apache. 1 30 30 30 30 +@ 30 IN NS ns1 + +shouldReturnErrorIfMoreThanOneTxtSpf1Record IN TXT "v=spf1 ip4:192.0.2.162 -all" +shouldReturnErrorIfMoreThanOneTxtSpf1Record IN TXT "v=spf1 ip4:192.0.2.127 ip4:1.1.1.1 -all" + +shouldReturnPassIfJustOneTxtSpf1Record IN TXT "v=spf1 include:_spf.google.com include:spf.protection.outlook.com ip4:2.3.4.5 ip4:192.0.2.127 -all" + +shouldReturnPermErrorIfIncludeDomainNotFound IN TXT "v=spf1 ip4:4.3.2.1 include:unknownDomain.fake -all" + +shouldReturnPassIfMultipleStrings IN TXT "v=spf1 mx a ip4:192.0.2.127 ip4:4.3.2.1 ip4:4.3.2.1 ip4:4.3.2.1 ip4:4.3.2.1 ip4:4.3.2.1 ip4:4.3.2.1 ip4:4.3.2.1 ip4:4.3.2.1 ip4:4.3.2.1 ip4:4.3.2.1 ip4:4.3.2.1 ip4:4.3.2.1 ip4:4.3.2.1 ip4:4.3.2.1 ip4:4.3.2.1 ip4:4.3.2.1 ip4:4.3.2.1 ip4:4.3.2.1" " ip4:4.3.2.1 -all" --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org