This is an automated email from the ASF dual-hosted git repository.

rcordier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit a444f47c9502466105cd0a88fe667ded5ab78e03
Author: Quan Tran <[email protected]>
AuthorDate: Tue Jan 9 16:14:40 2024 +0700

    JAMES-3897 CrowdSec integration test for SMTP
---
 third-party/crowdsec/pom.xml                       |   5 +
 .../java/org/apache/james/CrowdsecExtension.java   |  65 +++++-
 .../org/apache/james/CrowdsecIntegrationTest.java  | 220 +++++++++++++++++++++
 ...rowdsecExtension.java => HAProxyExtension.java} |  49 ++---
 .../src/test/resources/crowdsec/acquis.yaml        |   5 +
 .../test/resources/crowdsec/collections/james.yaml |   7 +
 .../resources/crowdsec/parsers/james-auth.yaml     |  75 +++++++
 .../crowdsec/parsers/james-dictionary-attack.yaml  |  25 +++
 .../resources/crowdsec/parsers/syslog-logs.yaml    |  75 +++++++
 .../crowdsec/scenarios/james-bf-auth.yaml          |  14 ++
 .../scenarios/james-dictionary-attack.yaml         |  14 ++
 .../crowdsec/src/test/resources/imapserver.xml     |  64 ++++++
 .../crowdsec/src/test/resources/listeners.xml      |  22 +++
 .../crowdsec/src/test/resources/log/james.log      |   0
 .../crowdsec/src/test/resources/logback-test.xml   |  59 ++++++
 .../src/test/resources/mailetcontainer.xml         | 155 +++++++++++++++
 .../crowdsec/src/test/resources/pop3server.xml     |  23 +++
 .../crowdsec/src/test/resources/smtpserver.xml     |  84 ++++++++
 .../src/test/resources/usersrepository.xml         |  28 +++
 19 files changed, 958 insertions(+), 31 deletions(-)

diff --git a/third-party/crowdsec/pom.xml b/third-party/crowdsec/pom.xml
index 3711c5d2c8..b552553773 100644
--- a/third-party/crowdsec/pom.xml
+++ b/third-party/crowdsec/pom.xml
@@ -42,6 +42,11 @@
             <version>${project.version}</version>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>james-server-memory-app</artifactId>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
             <artifactId>testing-base</artifactId>
diff --git 
a/third-party/crowdsec/src/test/java/org/apache/james/CrowdsecExtension.java 
b/third-party/crowdsec/src/test/java/org/apache/james/CrowdsecExtension.java
index f683c5673e..08da9021c3 100644
--- a/third-party/crowdsec/src/test/java/org/apache/james/CrowdsecExtension.java
+++ b/third-party/crowdsec/src/test/java/org/apache/james/CrowdsecExtension.java
@@ -19,21 +19,32 @@
 
 package org.apache.james;
 
+import static 
org.apache.james.model.CrowdsecClientConfiguration.DEFAULT_API_KEY;
+
 import java.io.IOException;
+import java.net.URL;
 import java.time.Duration;
 import java.util.UUID;
 
+import javax.inject.Singleton;
+
+import org.apache.james.model.CrowdsecClientConfiguration;
+import org.apache.james.model.CrowdsecHttpClient;
 import org.apache.james.util.docker.RateLimiters;
 import org.junit.jupiter.api.extension.ExtensionContext;
+import org.testcontainers.containers.BindMode;
 import org.testcontainers.containers.GenericContainer;
 import org.testcontainers.containers.wait.strategy.HostPortWaitStrategy;
+import org.testcontainers.utility.MountableFile;
 
-import com.google.common.collect.ImmutableList;
+import com.github.fge.lambdas.Throwing;
+import com.google.inject.AbstractModule;
+import com.google.inject.Module;
+import com.google.inject.Provides;
 
 public class CrowdsecExtension implements GuiceModuleTestExtension {
     public static final Duration STARTUP_TIMEOUT = Duration.ofMinutes(5);
     public static final int CROWDSEC_PORT = 8080;
-    public static final int EXPOSED_PORT = 8082;
     public static final String CROWDSEC_IMAGE = 
"crowdsecurity/crowdsec:v1.5.4";
 
     private final GenericContainer<?> crowdsecContainer;
@@ -43,26 +54,74 @@ public class CrowdsecExtension implements 
GuiceModuleTestExtension {
             .withCreateContainerCmdModifier(cmd -> 
cmd.withName("james-crowdsec-test-" + UUID.randomUUID()))
             .withExposedPorts(CROWDSEC_PORT)
             .withStartupTimeout(STARTUP_TIMEOUT)
+            
.withCopyFileToContainer(MountableFile.forClasspathResource("crowdsec/acquis.yaml"),
 "/etc/crowdsec/")
+            
.withCopyFileToContainer(MountableFile.forClasspathResource("crowdsec/parsers/syslog-logs.yaml"),
 "/etc/crowdsec/parsers/s00-raw/")
+            
.withCopyFileToContainer(MountableFile.forClasspathResource("crowdsec/parsers/james-auth.yaml"),
 "/etc/crowdsec/parsers/s01-parse/")
+            
.withCopyFileToContainer(MountableFile.forClasspathResource("crowdsec/scenarios/james-bf-auth.yaml"),
 "/etc/crowdsec/scenarios/")
+            
.withCopyFileToContainer(MountableFile.forClasspathResource("crowdsec/scenarios/james-dictionary-attack.yaml"),
 "/etc/crowdsec/scenarios/")
+            
.withCopyFileToContainer(MountableFile.forClasspathResource("crowdsec/collections/james.yaml"),
 "/etc/crowdsec/collections/")
+            .withFileSystemBind("src/test/resources/log", "/var/log", 
BindMode.READ_WRITE)
             .waitingFor(new 
HostPortWaitStrategy().withRateLimiter(RateLimiters.TWENTIES_PER_SECOND));
     }
 
     @Override
-    public void beforeAll(ExtensionContext context) {
+    public void beforeAll(ExtensionContext context) throws Exception {
         if (!crowdsecContainer.isRunning()) {
             crowdsecContainer.start();
         }
+
+        setApiKey();
+    }
+
+    private void setApiKey() throws IOException, InterruptedException {
+        crowdsecContainer.execInContainer("cscli", "bouncer", "add", 
"bouncer", "-k", DEFAULT_API_KEY);
     }
 
     @Override
     public void afterEach(ExtensionContext extensionContext) throws 
IOException, InterruptedException {
+        resetCrowdSecBanDecisions();
+        resetJamesLogFile();
+    }
+
+    private void resetCrowdSecBanDecisions() throws IOException, 
InterruptedException {
         crowdsecContainer.execInContainer("cscli", "decision", "delete", 
"--all");
     }
 
+    private void resetJamesLogFile() throws IOException, InterruptedException {
+        crowdsecContainer.execInContainer("truncate", "-s", "0", 
"/var/log/james.log");
+    }
+
     @Override
     public void afterAll(ExtensionContext extensionContext) {
 
     }
 
+    @Override
+    public Module getModule() {
+        URL crowdSecUrl = getCrowdSecUrl();
+
+        return new AbstractModule() {
+            @Provides
+            @Singleton
+            public CrowdsecClientConfiguration crowdsecClientConfiguration() {
+                return new CrowdsecClientConfiguration(crowdSecUrl, 
DEFAULT_API_KEY);
+            }
+
+            @Provides
+            @Singleton
+            public CrowdsecHttpClient 
crowdsecHttpClient(CrowdsecClientConfiguration crowdsecClientConfiguration) {
+                return new CrowdsecHttpClient(crowdsecClientConfiguration);
+            }
+        };
+    }
+
+    public URL getCrowdSecUrl() {
+        return Throwing.supplier(() -> new URL("http",
+            crowdsecContainer.getHost(),
+            crowdsecContainer.getMappedPort(CROWDSEC_PORT),
+            "/v1")).get();
+    }
+
     public GenericContainer<?> getCrowdsecContainer() {
         return crowdsecContainer;
     }
diff --git 
a/third-party/crowdsec/src/test/java/org/apache/james/CrowdsecIntegrationTest.java
 
b/third-party/crowdsec/src/test/java/org/apache/james/CrowdsecIntegrationTest.java
new file mode 100644
index 0000000000..24a9dc5bd6
--- /dev/null
+++ 
b/third-party/crowdsec/src/test/java/org/apache/james/CrowdsecIntegrationTest.java
@@ -0,0 +1,220 @@
+/****************************************************************
+ * 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;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static 
org.apache.james.data.UsersRepositoryModuleChooser.Implementation.DEFAULT;
+import static 
org.apache.james.model.CrowdsecClientConfiguration.DEFAULT_API_KEY;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Durations.ONE_HUNDRED_MILLISECONDS;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Base64;
+import java.util.List;
+import java.util.stream.IntStream;
+
+import org.apache.commons.net.smtp.SMTPClient;
+import org.apache.james.model.CrowdsecClientConfiguration;
+import org.apache.james.model.CrowdsecDecision;
+import org.apache.james.model.CrowdsecHttpClient;
+import org.apache.james.modules.protocols.SmtpGuiceProbe;
+import org.apache.james.utils.DataProbeImpl;
+import org.apache.james.utils.TestIMAPClient;
+import org.assertj.core.api.SoftAssertions;
+import org.awaitility.Awaitility;
+import org.awaitility.Durations;
+import org.awaitility.core.ConditionFactory;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.junit.jupiter.api.io.TempDir;
+import org.testcontainers.utility.MountableFile;
+
+import com.github.fge.lambdas.Throwing;
+
+class CrowdsecIntegrationTest {
+    @RegisterExtension
+    static CrowdsecExtension crowdsecExtension = new CrowdsecExtension();
+
+    @RegisterExtension
+    static JamesServerExtension testExtension = new 
JamesServerBuilder<MemoryJamesConfiguration>(tmpDir ->
+        MemoryJamesConfiguration.builder()
+            .workingDirectory(tmpDir)
+            .configurationFromClasspath()
+            .usersRepository(DEFAULT)
+            .build())
+        .server(MemoryJamesServerMain::createServer)
+        .extension(crowdsecExtension)
+        .lifeCycle(JamesServerExtension.Lifecycle.PER_TEST)
+        .build();
+
+    @RegisterExtension
+    public TestIMAPClient testIMAPClient = new TestIMAPClient();
+
+    private static final String LOCALHOST_IP = "127.0.0.1";
+    private static final String DOMAIN = "domain.tld";
+    private static final String BOB = "bob@" + DOMAIN;
+    private static final String BOB_PASSWORD = "bobPassword";
+    private static final String BAD_PASSWORD = "badPassword";
+    private static final ConditionFactory CALMLY_AWAIT = Awaitility
+        .with().pollInterval(ONE_HUNDRED_MILLISECONDS)
+        .and().pollDelay(ONE_HUNDRED_MILLISECONDS)
+        .await();
+
+    private HAProxyExtension haProxyExtension;
+    private SMTPClient smtpProtocol;
+    private CrowdsecHttpClient crowdsecClient;
+
+    @BeforeEach
+    void setup(GuiceJamesServer server, @TempDir Path tempDir) throws 
Exception {
+        server.getProbe(DataProbeImpl.class).fluent()
+            .addDomain(DOMAIN)
+            .addUser(BOB, BOB_PASSWORD);
+
+        haProxyExtension = new 
HAProxyExtension(MountableFile.forHostPath(createHaProxyConfigFile(server, 
tempDir).toString()));
+        haProxyExtension.start();
+
+        smtpProtocol = new SMTPClient();
+        crowdsecClient = new CrowdsecHttpClient(new 
CrowdsecClientConfiguration(crowdsecExtension.getCrowdSecUrl(), 
DEFAULT_API_KEY));
+    }
+
+    private Path createHaProxyConfigFile(GuiceJamesServer server, Path 
tempDir) throws IOException {
+        String smtpServerWithProxySupportIp = 
crowdsecExtension.getCrowdsecContainer().getContainerInfo().getNetworkSettings()
+            .getGateway(); // James server listens at the docker bridge 
network's gateway IP
+        int smtpWithProxySupportPort = 
server.getProbe(SmtpGuiceProbe.class).getSmtpAuthRequiredPort().getValue();
+        String haproxyConfigContent = String.format("global\n" +
+                "  log stdout format raw local0 info\n" +
+                "\n" +
+                "defaults\n" +
+                "  mode tcp\n" +
+                "  timeout client 1800s\n" +
+                "  timeout connect 5s\n" +
+                "  timeout server 1800s\n" +
+                "  log global\n" +
+                "  option tcplog\n" +
+                "\n" +
+                "frontend smtp-frontend\n" +
+                "  bind :25\n" +
+                "  default_backend james-server-smtp\n" +
+                "\n" +
+                "backend james-server-smtp\n" +
+                "  server james1 %s:%d send-proxy\n",
+            smtpServerWithProxySupportIp, smtpWithProxySupportPort);
+        Path haProxyConfigFile = tempDir.resolve("haproxy.cfg");
+        Files.write(haProxyConfigFile, haproxyConfigContent.getBytes());
+
+        return haProxyConfigFile;
+    }
+
+    @AfterEach
+    void teardown() {
+        haProxyExtension.stop();
+    }
+
+    @Nested
+    class SMTP {
+        @Test
+        void 
ehloShouldRejectAfterThreeFailedSMTPAuthentications(GuiceJamesServer server) {
+            // GIVEN a client failed to log in 3 consecutive times in a short 
period
+            IntStream.range(0, 3)
+                .forEach(Throwing.intConsumer(any -> {
+                    smtpProtocol.connect(LOCALHOST_IP, 
server.getProbe(SmtpGuiceProbe.class).getSmtpPort().getValue());
+                    smtpProtocol.sendCommand("EHLO", 
InetAddress.getLocalHost().toString());
+                    smtpProtocol.sendCommand("AUTH PLAIN");
+                    
smtpProtocol.sendCommand(Base64.getEncoder().encodeToString(("\0" + BOB + "\0" 
+ BAD_PASSWORD + "\0").getBytes(UTF_8)));
+                    assertThat(smtpProtocol.getReplyString())
+                        .contains("535 Authentication Failed");
+                }));
+
+            // THEN SMTP usage from the IP would be blocked upon the EHLO 
command. CrowdSec takes time to processing the ban decision therefore the await 
below.
+            CALMLY_AWAIT.atMost(Durations.TEN_SECONDS)
+                .untilAsserted(() -> {
+                    smtpProtocol.connect(LOCALHOST_IP, 
server.getProbe(SmtpGuiceProbe.class).getSmtpPort().getValue());
+                    smtpProtocol.sendCommand("EHLO", 
InetAddress.getLocalHost().toString());
+                    assertThat(smtpProtocol.getReplyString())
+                        .contains("554 Email rejected");
+                });
+        }
+
+        @Test
+        void ehloShouldRejectAfterThreeFailedSMTPAuthenticationsViaProxy() {
+            // GIVEN a client connected via proxy failed to log in 3 
consecutive times in a short period
+            IntStream.range(0, 3)
+                .forEach(Throwing.intConsumer(any -> {
+                    smtpProtocol.connect(LOCALHOST_IP, 
haProxyExtension.getProxiedSmtpPort());
+                    smtpProtocol.sendCommand("EHLO", 
InetAddress.getLocalHost().toString());
+                    smtpProtocol.sendCommand("AUTH PLAIN");
+                    
smtpProtocol.sendCommand(Base64.getEncoder().encodeToString(("\0" + BOB + "\0" 
+ BAD_PASSWORD + "\0").getBytes(UTF_8)));
+                    assertThat(smtpProtocol.getReplyString())
+                        .contains("535 Authentication Failed");
+                }));
+
+            // THEN SMTP usage from the client would be blocked upon the EHLO 
command.
+            CALMLY_AWAIT.atMost(Durations.TEN_SECONDS)
+                .untilAsserted(() -> {
+                    smtpProtocol.connect(LOCALHOST_IP, 
haProxyExtension.getProxiedSmtpPort());
+                    smtpProtocol.sendCommand("EHLO", 
InetAddress.getLocalHost().toString());
+                    assertThat(smtpProtocol.getReplyString())
+                        .contains("554 Email rejected");
+                });
+        }
+
+        @Test
+        void shouldBanRealClientIpAndNotProxyIp() {
+            // GIVEN a client connected via proxy failed to log in 3 
consecutive times in a short period
+            IntStream.range(0, 3)
+                .forEach(Throwing.intConsumer(any -> {
+                    smtpProtocol.connect(LOCALHOST_IP, 
haProxyExtension.getProxiedSmtpPort());
+                    smtpProtocol.sendCommand("EHLO", 
InetAddress.getLocalHost().toString());
+                    smtpProtocol.sendCommand("AUTH PLAIN");
+                    
smtpProtocol.sendCommand(Base64.getEncoder().encodeToString(("\0" + BOB + "\0" 
+ BAD_PASSWORD + "\0").getBytes(UTF_8)));
+                    assertThat(smtpProtocol.getReplyString())
+                        .contains("535 Authentication Failed");
+                }));
+
+            CALMLY_AWAIT.atMost(Durations.TEN_SECONDS)
+                .untilAsserted(() -> {
+                    smtpProtocol.connect(LOCALHOST_IP, 
haProxyExtension.getProxiedSmtpPort());
+                    smtpProtocol.sendCommand("EHLO", 
InetAddress.getLocalHost().toString());
+                    assertThat(smtpProtocol.getReplyString())
+                        .contains("554 Email rejected");
+                });
+
+            // THEN real client IP must be banned, not proxy IP
+            String realClientIp = 
haProxyExtension.getHaproxyContainer().getContainerInfo().getNetworkSettings()
+                .getGateway(); // client connect to HAProxy container via the 
docker bridge network's gateway IP
+            String haProxyIp = 
haProxyExtension.getHaproxyContainer().getContainerInfo().getNetworkSettings()
+                .getIpAddress();
+
+            List<CrowdsecDecision> decisions = 
crowdsecClient.getCrowdsecDecisions().block();
+            SoftAssertions.assertSoftly(softly -> {
+                softly.assertThat(decisions).hasSize(1);
+                
softly.assertThat(decisions.get(0).getValue()).isEqualTo(realClientIp);
+                
softly.assertThat(decisions.get(0).getValue()).isNotEqualTo(haProxyIp);
+            });
+        }
+
+    }
+}
diff --git 
a/third-party/crowdsec/src/test/java/org/apache/james/CrowdsecExtension.java 
b/third-party/crowdsec/src/test/java/org/apache/james/HAProxyExtension.java
similarity index 55%
copy from 
third-party/crowdsec/src/test/java/org/apache/james/CrowdsecExtension.java
copy to 
third-party/crowdsec/src/test/java/org/apache/james/HAProxyExtension.java
index f683c5673e..31f556cfe7 100644
--- a/third-party/crowdsec/src/test/java/org/apache/james/CrowdsecExtension.java
+++ b/third-party/crowdsec/src/test/java/org/apache/james/HAProxyExtension.java
@@ -19,51 +19,44 @@
 
 package org.apache.james;
 
-import java.io.IOException;
-import java.time.Duration;
 import java.util.UUID;
 
 import org.apache.james.util.docker.RateLimiters;
-import org.junit.jupiter.api.extension.ExtensionContext;
 import org.testcontainers.containers.GenericContainer;
 import org.testcontainers.containers.wait.strategy.HostPortWaitStrategy;
+import org.testcontainers.utility.MountableFile;
 
-import com.google.common.collect.ImmutableList;
+public class HAProxyExtension {
+    private static final String HAPROXY_IMAGE = 
"haproxytech/haproxy-alpine:2.9.1";
+    private static final int SMTP_PORT = 25;
 
-public class CrowdsecExtension implements GuiceModuleTestExtension {
-    public static final Duration STARTUP_TIMEOUT = Duration.ofMinutes(5);
-    public static final int CROWDSEC_PORT = 8080;
-    public static final int EXPOSED_PORT = 8082;
-    public static final String CROWDSEC_IMAGE = 
"crowdsecurity/crowdsec:v1.5.4";
+    private final GenericContainer<?> haproxyContainer;
 
-    private final GenericContainer<?> crowdsecContainer;
-
-    public CrowdsecExtension() {
-        this.crowdsecContainer = new GenericContainer<>(CROWDSEC_IMAGE)
-            .withCreateContainerCmdModifier(cmd -> 
cmd.withName("james-crowdsec-test-" + UUID.randomUUID()))
-            .withExposedPorts(CROWDSEC_PORT)
-            .withStartupTimeout(STARTUP_TIMEOUT)
+    public HAProxyExtension(MountableFile haProxyConfigFile) {
+        this.haproxyContainer = new GenericContainer<>(HAPROXY_IMAGE)
+            .withCreateContainerCmdModifier(cmd -> 
cmd.withName("james-haproxy-test-" + UUID.randomUUID()))
+            .withExposedPorts(SMTP_PORT)
+            .withCopyFileToContainer(haProxyConfigFile, 
"/usr/local/etc/haproxy/")
             .waitingFor(new 
HostPortWaitStrategy().withRateLimiter(RateLimiters.TWENTIES_PER_SECOND));
     }
 
-    @Override
-    public void beforeAll(ExtensionContext context) {
-        if (!crowdsecContainer.isRunning()) {
-            crowdsecContainer.start();
+    public void start() {
+        if (!haproxyContainer.isRunning()) {
+            haproxyContainer.start();
         }
     }
 
-    @Override
-    public void afterEach(ExtensionContext extensionContext) throws 
IOException, InterruptedException {
-        crowdsecContainer.execInContainer("cscli", "decision", "delete", 
"--all");
+    public void stop() {
+        if (haproxyContainer.isRunning()) {
+            haproxyContainer.stop();
+        }
     }
 
-    @Override
-    public void afterAll(ExtensionContext extensionContext) {
-
+    public int getProxiedSmtpPort() {
+        return haproxyContainer.getMappedPort(SMTP_PORT);
     }
 
-    public GenericContainer<?> getCrowdsecContainer() {
-        return crowdsecContainer;
+    public GenericContainer<?> getHaproxyContainer() {
+        return this.haproxyContainer;
     }
 }
diff --git a/third-party/crowdsec/src/test/resources/crowdsec/acquis.yaml 
b/third-party/crowdsec/src/test/resources/crowdsec/acquis.yaml
new file mode 100644
index 0000000000..c58183a0f7
--- /dev/null
+++ b/third-party/crowdsec/src/test/resources/crowdsec/acquis.yaml
@@ -0,0 +1,5 @@
+source: file
+filenames:
+ - /var/log/james.log
+labels:
+ type: james
\ No newline at end of file
diff --git 
a/third-party/crowdsec/src/test/resources/crowdsec/collections/james.yaml 
b/third-party/crowdsec/src/test/resources/crowdsec/collections/james.yaml
new file mode 100644
index 0000000000..8d1e046dfd
--- /dev/null
+++ b/third-party/crowdsec/src/test/resources/crowdsec/collections/james.yaml
@@ -0,0 +1,7 @@
+parsers:
+  - crowdsecurity/syslog-logs
+  - linagora/james-auth
+  - linagora/james-dictionary-attack
+scenarios:
+  - apache-james/bf-auth
+author: linagora
\ No newline at end of file
diff --git 
a/third-party/crowdsec/src/test/resources/crowdsec/parsers/james-auth.yaml 
b/third-party/crowdsec/src/test/resources/crowdsec/parsers/james-auth.yaml
new file mode 100644
index 0000000000..52bea127f1
--- /dev/null
+++ b/third-party/crowdsec/src/test/resources/crowdsec/parsers/james-auth.yaml
@@ -0,0 +1,75 @@
+onsuccess: next_stage
+debug: true
+filter: "evt.Parsed.program == 'james'"
+name: linagora/james-auth
+description: "Parser for James IMAP and SMTP authentication "
+
+pattern_syntax:
+  IMAP_AUTH_FAIL_BAD_CREDENTIALS: 'IMAP Authentication 
failed%{DATA:data}because of bad credentials.'
+  IMAP_AUTH_FAIL_DELEGATION_BAD_CREDENTIALS: 'IMAP Authentication with 
delegation failed%{DATA:data}because of bad credentials.'
+  IMAP_AUTH_FAIL_NO_EXISTING_DELEGATION: 'IMAP Authentication with delegation 
failed%{DATA:data}because of non existing delegation.'
+
+  SMTP_AUTH_FAIL: 'SMTP Authentication%{DATA:data}failed.'
+nodes:
+  - grok:
+      name: "IMAP_AUTH_FAIL_BAD_CREDENTIALS"
+      apply_on: message
+      statics:
+        - meta: log_type
+          value: imap-auth-fail
+        - meta: timestamp
+          expression: evt.Parsed.timestamp
+        - meta: level
+          expression: evt.Parsed.level
+        - meta: source_ip
+          expression: evt.Parsed.mdc_ip
+        - meta: host
+          expression: evt.Parsed.mdc_host
+        - meta: user
+          expression: evt.Parsed.user
+  - grok:
+      name: "IMAP_AUTH_FAIL_DELEGATION_BAD_CREDENTIALS"
+      apply_on: message
+      statics:
+        - meta: log_type
+          value: imap-auth-fail
+        - meta: timestamp
+          expression: evt.Parsed.timestamp
+        - meta: level
+          expression: evt.Parsed.level
+        - meta: source_ip
+          expression: evt.Parsed.mdc_ip
+        - meta: host
+          expression: evt.Parsed.mdc_host
+        - meta: user
+          expression: evt.Parsed.user
+  - grok:
+      name: "IMAP_AUTH_FAIL_NO_EXISTING_DELEGATION"
+      apply_on: message
+      statics:
+        - meta: log_type
+          value: imap-auth-fail
+        - meta: timestamp
+          expression: evt.Parsed.timestamp
+        - meta: level
+          expression: evt.Parsed.level
+        - meta: source_ip
+          expression: evt.Parsed.mdc_ip
+        - meta: host
+          expression: evt.Parsed.mdc_host
+        - meta: user
+          expression: evt.Parsed.user
+  - grok:
+      name: "SMTP_AUTH_FAIL"
+      apply_on: message
+      statics:
+        - meta: log_type
+          value: smtp-auth-fail
+        - meta: timestamp
+          expression: evt.Parsed.timestamp
+        - meta: level
+          expression: evt.Parsed.level
+        - meta: source_ip
+          expression: evt.Parsed.mdc_remoteIP
+        - meta: user
+          expression: evt.Parsed.mdc_username
\ No newline at end of file
diff --git 
a/third-party/crowdsec/src/test/resources/crowdsec/parsers/james-dictionary-attack.yaml
 
b/third-party/crowdsec/src/test/resources/crowdsec/parsers/james-dictionary-attack.yaml
new file mode 100644
index 0000000000..1d7a5763dc
--- /dev/null
+++ 
b/third-party/crowdsec/src/test/resources/crowdsec/parsers/james-dictionary-attack.yaml
@@ -0,0 +1,25 @@
+onsuccess: next_stage
+debug: true
+filter: "evt.Parsed.program == 'james'"
+name: linagora/james-dictionary-attack
+description: "Parser for James dictionary attack"
+
+pattern_syntax:
+  DICTIONARY_ATTACK: 'Rejected message. Unknown user: %{EMAILADDRESS:rcpt}'
+nodes:
+  - grok:
+      name: "DICTIONARY_ATTACK"
+      apply_on: message
+      statics:
+        - meta: log_type
+          value: dictionary-attack
+        - meta: timestamp
+          expression: evt.Parsed.timestamp
+        - meta: level
+          expression: evt.Parsed.level
+        - meta: source_ip
+          expression: evt.Parsed.mdc_ip
+        - meta: user
+          expression: evt.Parsed.mdc_user
+        - meta: rcpt
+          expression: evt.Parsed.rcpt
\ No newline at end of file
diff --git 
a/third-party/crowdsec/src/test/resources/crowdsec/parsers/syslog-logs.yaml 
b/third-party/crowdsec/src/test/resources/crowdsec/parsers/syslog-logs.yaml
new file mode 100644
index 0000000000..1b4f50f34e
--- /dev/null
+++ b/third-party/crowdsec/src/test/resources/crowdsec/parsers/syslog-logs.yaml
@@ -0,0 +1,75 @@
+#If it's syslog, we are going to extract progname from it
+filter: "evt.Line.Labels.type == 'syslog'"
+onsuccess: next_stage
+pattern_syntax:
+  RAW_SYSLOG_PREFIX: '^<%{NUMBER:stuff1}>%{NUMBER:stuff2} %{SYSLOGBASE2} 
%{DATA:program} %{NUMBER:pid}'
+  RAW_SYSLOG_META: '\[meta sequenceId="%{NOTDQUOTE:seq_id}"\]'
+name: crowdsecurity/syslog-logs
+nodes:
+  - grok:
+      #this is a named regular expression. grok patterns can be kept into 
separate files for readability
+      pattern: "^%{SYSLOGLINE}" 
+      #This is the field of the `Event` to which the regexp should be applied
+      apply_on: Line.Raw
+  - grok:
+      #a second pattern for unparsed syslog lines, as saw in opnsense
+      pattern: '%{RAW_SYSLOG_PREFIX} - %{RAW_SYSLOG_META} 
%{GREEDYDATA:message}'
+      apply_on: Line.Raw
+#if the node was successfull, statics will be applied.
+statics:
+  - meta: machine
+    expression: evt.Parsed.logsource
+  - parsed: "logsource"
+    value: "syslog"
+# syslog date can be in two different fields (one of hte assignment will fail)
+  - target: evt.StrTime
+    expression: evt.Parsed.timestamp
+  - target: evt.StrTime
+    expression: evt.Parsed.timestamp8601
+  - meta: datasource_path
+    expression: evt.Line.Src
+  - meta: datasource_type
+    expression: evt.Line.Module
+---
+#if it's not syslog, the type is the progname
+filter: "evt.Line.Labels.type != 'syslog'"
+onsuccess: next_stage
+name: crowdsecurity/non-syslog
+debug: true
+statics:
+  - parsed: json_parsed
+    expression: UnmarshalJSON(evt.Line.Raw, evt.Unmarshaled, "message")
+  - parsed: program
+    expression: evt.Line.Labels.type
+  - parsed: timestamp
+    expression: evt.Unmarshaled.message.timestamp
+  - parsed: level
+    expression: evt.Unmarshaled.message.level
+  - parsed: thread
+    expression: evt.Unmarshaled.message.thread
+  - parsed: mdc_protocol
+    expression: evt.Unmarshaled.message.mdc.protocol
+  - parsed: mdc_ip
+    expression: evt.Unmarshaled.message.mdc.ip
+  - parsed: mdc_host
+    expression: evt.Unmarshaled.message.mdc.host
+  - parsed: mdc_action
+    expression: evt.Unmarshaled.message.mdc.action
+  - parsed: mdc_sessionId
+    expression: evt.Unmarshaled.message.mdc.sessionId
+  - parsed: mdc_user
+    expression: evt.Unmarshaled.message.mdc.user
+  - parsed: mdc_remoteIP
+    expression: evt.Unmarshaled.message.mdc.remoteIP
+  - parsed: mdc_username
+    expression: evt.Unmarshaled.message.mdc.username
+  - parsed: logger
+    expression: evt.Unmarshaled.message.logger
+  - parsed: message
+    expression: evt.Unmarshaled.message.message
+  - parsed: context
+    expression: evt.Unmarshaled.message.context
+  - meta: datasource_path
+    expression: evt.Line.Src
+  - meta: datasource_type
+    expression: evt.Line.Module
\ No newline at end of file
diff --git 
a/third-party/crowdsec/src/test/resources/crowdsec/scenarios/james-bf-auth.yaml 
b/third-party/crowdsec/src/test/resources/crowdsec/scenarios/james-bf-auth.yaml
new file mode 100644
index 0000000000..f7d02cec73
--- /dev/null
+++ 
b/third-party/crowdsec/src/test/resources/crowdsec/scenarios/james-bf-auth.yaml
@@ -0,0 +1,14 @@
+type: leaky
+name: apache-james/bf-auth
+debug: true
+description: "Detect login james bruteforce"
+filter: "evt.Meta.log_type == 'imap-auth-fail' || evt.Meta.log_type == 
'smtp-auth-fail'"
+leakspeed: "5m"
+capacity: 2 # 3rd failed authentication would trigger the ban decision
+groupby: evt.Meta.source_ip
+blackhole: 0m # to enable rapidly trigger new ban decision across tests. cf 
https://docs.crowdsec.net/docs/scenarios/format/#blackhole
+reprocess: true
+labels:
+ service: ssh
+ type: bruteforce
+ remediation: true
\ No newline at end of file
diff --git 
a/third-party/crowdsec/src/test/resources/crowdsec/scenarios/james-dictionary-attack.yaml
 
b/third-party/crowdsec/src/test/resources/crowdsec/scenarios/james-dictionary-attack.yaml
new file mode 100644
index 0000000000..380b912774
--- /dev/null
+++ 
b/third-party/crowdsec/src/test/resources/crowdsec/scenarios/james-dictionary-attack.yaml
@@ -0,0 +1,14 @@
+type: leaky
+name: linagora/james-dictionary-attack
+debug: true
+description: "Detect login james bruteforce"
+filter: "evt.Meta.log_type == 'dictionary-attack'"
+leakspeed: "1m"
+capacity: 5
+groupby: evt.Meta.source_ip
+blackhole: 1m
+reprocess: true
+labels:
+  service: ssh
+  type: bruteforce
+  remediation: true
\ No newline at end of file
diff --git a/third-party/crowdsec/src/test/resources/imapserver.xml 
b/third-party/crowdsec/src/test/resources/imapserver.xml
new file mode 100644
index 0000000000..a2ee96c8c9
--- /dev/null
+++ b/third-party/crowdsec/src/test/resources/imapserver.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0"?>
+
+<!--
+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.
+-->
+
+
+<imapservers>
+    <imapserver enabled="true">
+        <jmxName>imapserver</jmxName>
+        <bind>0.0.0.0:0</bind>
+        <connectionBacklog>200</connectionBacklog>
+        <tls socketTLS="false" startTLS="false">
+            <!-- To create a new keystore execute:
+            keytool -genkey -alias james -keyalg RSA -keystore 
/path/to/james/conf/keystore
+              -->
+            <keystore>file://conf/keystore</keystore>
+            <secret>james72laBalle</secret>
+            
<provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
+        </tls>
+        <connectionLimit>0</connectionLimit>
+        <connectionLimitPerIP>0</connectionLimitPerIP>
+        <gracefulShutdown>false</gracefulShutdown>
+        <idleTimeInterval>120</idleTimeInterval>
+        <idleTimeIntervalUnit>SECONDS</idleTimeIntervalUnit>
+        <enableIdle>true</enableIdle>
+        <plainAuthDisallowed>false</plainAuthDisallowed>
+    </imapserver>
+    <imapserver enabled="true">
+        <jmxName>imapserver-ssl</jmxName>
+        <bind>0.0.0.0:0</bind>
+        <connectionBacklog>200</connectionBacklog>
+        <tls socketTLS="false" startTLS="false">
+            <!-- To create a new keystore execute:
+              keytool -genkey -alias james -keyalg RSA -keystore 
/path/to/james/conf/keystore
+             -->
+            <keystore>file://conf/keystore</keystore>
+            <secret>james72laBalle</secret>
+            
<provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
+        </tls>
+        <connectionLimit>0</connectionLimit>
+        <connectionLimitPerIP>0</connectionLimitPerIP>
+        <gracefulShutdown>false</gracefulShutdown>
+        <idleTimeInterval>120</idleTimeInterval>
+        <idleTimeIntervalUnit>SECONDS</idleTimeIntervalUnit>
+        <enableIdle>true</enableIdle>
+        <plainAuthDisallowed>false</plainAuthDisallowed>
+    </imapserver>
+</imapservers>
diff --git a/third-party/crowdsec/src/test/resources/listeners.xml 
b/third-party/crowdsec/src/test/resources/listeners.xml
new file mode 100644
index 0000000000..ae5937f1fa
--- /dev/null
+++ b/third-party/crowdsec/src/test/resources/listeners.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+  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.                                           
+ -->
+
+<listeners>
+</listeners>
\ No newline at end of file
diff --git a/third-party/crowdsec/src/test/resources/log/james.log 
b/third-party/crowdsec/src/test/resources/log/james.log
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/third-party/crowdsec/src/test/resources/logback-test.xml 
b/third-party/crowdsec/src/test/resources/logback-test.xml
new file mode 100644
index 0000000000..ad3f309937
--- /dev/null
+++ b/third-party/crowdsec/src/test/resources/logback-test.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+ -->
+
+<configuration>
+
+    <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
+        <resetJUL>true</resetJUL>
+    </contextListener>
+
+    <appender name="LOG_FILE" 
class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>./src/test/resources/log/james.log</file>
+
+        <rollingPolicy 
class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+            
<fileNamePattern>./src/test/resources/log/james.%i.log.tar.gz</fileNamePattern>
+            <minIndex>1</minIndex>
+            <maxIndex>3</maxIndex>
+        </rollingPolicy>
+
+        <triggeringPolicy 
class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+            <maxFileSize>100MB</maxFileSize>
+        </triggeringPolicy>
+
+        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
+            <layout class="ch.qos.logback.contrib.json.classic.JsonLayout">
+                <timestampFormat>yyyy-MM-dd'T'HH:mm:ss.SSSX</timestampFormat>
+                <timestampFormatTimezoneId>Etc/UTC</timestampFormatTimezoneId>
+
+                <!-- Importance for handling multiple lines log -->
+                <appendLineSeparator>true</appendLineSeparator>
+
+                <jsonFormatter 
class="ch.qos.logback.contrib.jackson.JacksonJsonFormatter">
+                    <prettyPrint>false</prettyPrint>
+                </jsonFormatter>
+            </layout>
+        </encoder>
+    </appender>
+    <root level="WARN">
+        <appender-ref ref="LOG_FILE" />
+    </root>
+
+    <logger name="org.apache.james" level="INFO" />
+</configuration>
\ No newline at end of file
diff --git a/third-party/crowdsec/src/test/resources/mailetcontainer.xml 
b/third-party/crowdsec/src/test/resources/mailetcontainer.xml
new file mode 100644
index 0000000000..a721c7cde5
--- /dev/null
+++ b/third-party/crowdsec/src/test/resources/mailetcontainer.xml
@@ -0,0 +1,155 @@
+<?xml version="1.0"?>
+
+<!--
+  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.
+ -->
+
+<mailetcontainer enableJmx="false">
+
+    <context>
+        <postmaster>postmaster</postmaster>
+    </context>
+
+    <spooler>
+        <threads>20</threads>
+        <errorRepository>memory://var/mail/error/</errorRepository>
+    </spooler>
+
+    <processors>
+        <processor state="root" enableJmx="false">
+            <mailet match="All" class="PostmasterAlias"/>
+            <mailet match="RelayLimit=30" class="Null"/>
+            <mailet match="All" class="ToProcessor">
+                <processor>transport</processor>
+            </mailet>
+        </processor>
+
+        <processor state="error" enableJmx="false">
+            <mailet match="All" class="Bounce">
+                <onMailetException>ignore</onMailetException>
+            </mailet>
+            <mailet match="All" class="ToRepository">
+                <repositoryPath>memory://var/mail/error/</repositoryPath>
+                <onMailetException>propagate</onMailetException>
+            </mailet>
+        </processor>
+
+
+        <processor state="transport" enableJmx="false">
+            <mailet match="SMTPAuthSuccessful" class="SetMimeHeader">
+                <name>X-UserIsAuth</name>
+                <value>true</value>
+            </mailet>
+            <mailet match="All" class="RemoveMimeHeader">
+                <name>bcc</name>
+            </mailet>
+            <mailet match="All" class="RecipientRewriteTable">
+                <errorProcessor>rrt-error</errorProcessor>
+            </mailet>
+            <mailet match="RecipientIsLocal" class="ToProcessor">
+                <processor>local-delivery</processor>
+            </mailet>
+            <mailet match="HostIsLocal" class="ToProcessor">
+                <processor>local-address-error</processor>
+                <notice>550 - Requested action not taken: no such user 
here</notice>
+            </mailet>
+            <mailet match="SMTPAuthSuccessful" class="SetMailAttribute">
+                <RelayAllowed>true</RelayAllowed>
+            </mailet>
+            <mailet match="SMTPIsAuthNetwork" class="SetMailAttribute">
+                <RelayAllowed>true</RelayAllowed>
+            </mailet>
+            <mailet match="SentByMailet" class="SetMailAttribute">
+                <RelayAllowed>true</RelayAllowed>
+            </mailet>
+            <mailet match="org.apache.james.jmap.mailet.SentByJmap" 
class="SetMailAttribute">
+                <RelayAllowed>true</RelayAllowed>
+            </mailet>
+            <mailet match="HasMailAttribute=RelayAllowed" 
class="RemoteDelivery">
+                <outgoingQueue>outgoing</outgoingQueue>
+                <delayTime>5000, 100000, 500000</delayTime>
+                <maxRetries>3</maxRetries>
+                <maxDnsProblemRetries>0</maxDnsProblemRetries>
+                <deliveryThreads>10</deliveryThreads>
+                <sendpartial>true</sendpartial>
+                <bounceProcessor>bounces</bounceProcessor>
+            </mailet>
+            <mailet match="All" class="ToProcessor">
+                <processor>relay-denied</processor>
+            </mailet>
+        </processor>
+
+        <processor state="local-delivery" enableJmx="true">
+            <mailet match="All" class="VacationMailet">
+                <onMailetException>ignore</onMailetException>
+            </mailet>
+            <mailet match="All" class="Sieve">
+                <onMailetException>ignore</onMailetException>
+            </mailet>
+            <mailet match="All" class="AddDeliveredToHeader"/>
+            <mailet match="All" 
class="org.apache.james.jmap.mailet.filter.JMAPFiltering">
+                <onMailetException>ignore</onMailetException>
+            </mailet>
+            <mailet match="All" class="LocalDelivery"/>
+        </processor>
+
+        <processor state="spam" enableJmx="false">
+            <mailet match="All" class="ToRepository">
+                <repositoryPath>memory://var/mail/spam/</repositoryPath>
+            </mailet>
+        </processor>
+
+        <processor state="local-address-error" enableJmx="false">
+            <mailet match="All" class="Bounce">
+                <attachment>none</attachment>
+            </mailet>
+            <mailet match="All" class="ToRepository">
+                
<repositoryPath>memory://var/mail/address-error/</repositoryPath>
+            </mailet>
+        </processor>
+
+        <processor state="relay-denied" enableJmx="false">
+            <mailet match="All" class="Bounce">
+                <attachment>none</attachment>
+            </mailet>
+            <mailet match="All" class="ToRepository">
+                
<repositoryPath>memory://var/mail/relay-denied/</repositoryPath>
+                <notice>Warning: You are sending an e-mail to a remote server. 
You must be authentified to perform such an operation</notice>
+            </mailet>
+        </processor>
+
+        <processor state="bounces" enableJmx="false">
+            <mailet match="All" class="DSNBounce">
+                <passThrough>false</passThrough>
+            </mailet>
+        </processor>
+
+        <processor state="rrt-error" enableJmx="false">
+            <mailet match="All" class="ToRepository">
+                <repositoryPath>memory://var/mail/rrt-error/</repositoryPath>
+                <passThrough>true</passThrough>
+            </mailet>
+            <mailet match="IsSenderInRRTLoop" class="Null"/>
+            <mailet match="All" class="Bounce"/>
+        </processor>
+
+    </processors>
+
+</mailetcontainer>
+
+
diff --git a/third-party/crowdsec/src/test/resources/pop3server.xml 
b/third-party/crowdsec/src/test/resources/pop3server.xml
new file mode 100644
index 0000000000..bec385ae30
--- /dev/null
+++ b/third-party/crowdsec/src/test/resources/pop3server.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!--
+  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.                                           
+ -->
+
+
+<pop3servers>
+</pop3servers>
diff --git a/third-party/crowdsec/src/test/resources/smtpserver.xml 
b/third-party/crowdsec/src/test/resources/smtpserver.xml
new file mode 100644
index 0000000000..abd07ea441
--- /dev/null
+++ b/third-party/crowdsec/src/test/resources/smtpserver.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0"?>
+
+<!--
+  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.
+ -->
+
+<smtpservers>
+    <smtpserver enabled="true">
+        <jmxName>smtpserver-global</jmxName>
+        <bind>0.0.0.0:0</bind>
+        <connectionBacklog>200</connectionBacklog>
+        <tls socketTLS="false" startTLS="false">
+            <keystore>file://conf/keystore</keystore>
+            <secret>james72laBalle</secret>
+            
<provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
+            <algorithm>SunX509</algorithm>
+        </tls>
+        <connectiontimeout>360</connectiontimeout>
+        <connectionLimit>0</connectionLimit>
+        <connectionLimitPerIP>0</connectionLimitPerIP>
+        <auth>
+            <announce>never</announce>
+            <requireSSL>false</requireSSL>
+            <plainAuthEnabled>true</plainAuthEnabled>
+        </auth>
+        <verifyIdentity>false</verifyIdentity>
+        <maxmessagesize>0</maxmessagesize>
+        <addressBracketsEnforcement>true</addressBracketsEnforcement>
+        <smtpGreeting>Apache JAMES awesome SMTP Server</smtpGreeting>
+        <handlerchain>
+            <handler 
class="org.apache.james.smtpserver.fastfail.ValidRcptHandler"/>
+            <handler class="org.apache.james.smtpserver.CoreCmdHandlerLoader"/>
+            <handler class="org.apache.james.CrowdsecEhloHook"/>
+        </handlerchain>
+        <gracefulShutdown>false</gracefulShutdown>
+    </smtpserver>
+    <smtpserver enabled="true">
+        <jmxName>smtpserver-TLS</jmxName>
+        <bind>0.0.0.0:0</bind>
+        <connectionBacklog>200</connectionBacklog>
+        <tls socketTLS="false" startTLS="false">
+            <keystore>file://conf/keystore</keystore>
+            <secret>james72laBalle</secret>
+            
<provider>org.bouncycastle.jce.provider.BouncyCastleProvider</provider>
+            <algorithm>SunX509</algorithm>
+        </tls>
+        <connectiontimeout>360</connectiontimeout>
+        <connectionLimit>0</connectionLimit>
+        <connectionLimitPerIP>0</connectionLimitPerIP>
+        <auth>
+            <announce>forUnauthorizedAddresses</announce>
+            <requireSSL>false</requireSSL>
+        </auth>
+        <!-- Trust authenticated users -->
+        <verifyIdentity>false</verifyIdentity>
+        <maxmessagesize>0</maxmessagesize>
+        <addressBracketsEnforcement>true</addressBracketsEnforcement>
+        <smtpGreeting>Apache JAMES awesome SMTP Server</smtpGreeting>
+        <handlerchain>
+            <handler 
class="org.apache.james.smtpserver.fastfail.ValidRcptHandler"/>
+            <handler class="org.apache.james.smtpserver.CoreCmdHandlerLoader"/>
+            <handler class="org.apache.james.CrowdsecEhloHook"/>
+        </handlerchain>
+        <gracefulShutdown>false</gracefulShutdown>
+        <proxyRequired>true</proxyRequired>
+    </smtpserver>
+</smtpservers>
+
+
diff --git a/third-party/crowdsec/src/test/resources/usersrepository.xml 
b/third-party/crowdsec/src/test/resources/usersrepository.xml
new file mode 100644
index 0000000000..a5390d7140
--- /dev/null
+++ b/third-party/crowdsec/src/test/resources/usersrepository.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<!--
+  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.                                           
+ -->
+
+<!-- Read https://james.apache.org/server/config-users.html for further 
details -->
+
+<usersrepository name="LocalUsers">
+    <algorithm>PBKDF2-SHA512</algorithm>
+    <enableVirtualHosting>true</enableVirtualHosting>    
+    <enableForwarding>true</enableForwarding>
+</usersrepository>
+


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to