<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: YounesZn</title>
    <description>The latest articles on DEV Community by YounesZn (@youneszn).</description>
    <link>https://dev.to/youneszn</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F801780%2F5d7aac54-4bc7-42cf-a890-f2f38e91ee7f.jpg</url>
      <title>DEV Community: YounesZn</title>
      <link>https://dev.to/youneszn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/youneszn"/>
    <language>en</language>
    <item>
      <title>The Speakeasy Door to Your Network - Port Knocking (2)</title>
      <dc:creator>YounesZn</dc:creator>
      <pubDate>Thu, 09 Jan 2025 18:55:45 +0000</pubDate>
      <link>https://dev.to/youneszn/the-speakeasy-door-to-your-network-port-knocking-2-j3f</link>
      <guid>https://dev.to/youneszn/the-speakeasy-door-to-your-network-port-knocking-2-j3f</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the first part of this series, we explored the fascinating technique of port knocking—a method to secure services by making them accessible only after a specific sequence of requests, and I mentioned some of the basic attacks and vulnerabilities of this technique. However, theory is just the beginning.&lt;br&gt;&lt;br&gt;
In this part, we’ll delve deeper into the practical side. We’ll discuss some real-world vulnerabilities of port knocking, including insights from a seasoned industry professional who implemented this technique and uncovered its limitations. Finally, we’ll deploy a fully functional port-knocking setup on AWS, transforming the concept into a working solution.&lt;/p&gt;




&lt;h2&gt;
  
  
  Knock, Knock… Who’s Exploiting?
&lt;/h2&gt;

&lt;p&gt;Without much thought, the first approach that comes to mind when facing a port-knocking setup during a pentest is brute-forcing the sequence. Well, that’s exactly what I’d think of too. &lt;br&gt;&lt;br&gt;
From 1 to 65535, you can perform a scan of open ports in the network, but we will get a huge number of combinations to test, except if we can somehow exclude some ports and keep only a subset of ports.&lt;br&gt;
This impractical and noisy attack can be mitigated by banning the attacker’s IP from accessing the network after a certain number of failed attempts within a specific time frame.&lt;br&gt;&lt;br&gt;
Moreover, if an attacker manages to send forged packets with random source network addresses, overwhelming the parser process and consuming excessive resources, this can lead to a DoS attack. &lt;br&gt;&lt;br&gt;
Not only that, but port knocking is also vulnerable to replay attacks, which occur when an attacker intercepts the knock sequence using a packet sniffer and replays the exact same sequence to the target server. If the port-knocking system doesn’t validate the freshness of the sequence (e.g., through timestamps or one-time sequences), the attacker could open the port and gain unauthorized access.&lt;br&gt;
All of the above attacks can be mitigated, but let’s focus on the replay attack and explore how we can solve it and even detect it in the process.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I agree with you that port knocking seems very vulnerable, but in a defense-in-depth strategy, it’s another layer of security, because why make their job easy?&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  One-Time Knocking
&lt;/h2&gt;

&lt;p&gt;There are several security approaches that can be implemented to mitigate the common vulnerabilities of port knocking. These mitigations ensure that while attackers may knock, they’ll never get the door to open. 🛡️&lt;br&gt;&lt;br&gt;
One-Time Passwords (OTPs) are effective in our case. We generate a series of n one-time passwords by repeatedly applying a cryptographic hash function, f(x), to the result of the previous step. Each password in the sequence is unique and can only be used once.&lt;br&gt;&lt;br&gt;
For instance, starting with an initial password p, we compute the cryptographic hash function f(x) repeatedly, as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;f(p) generates the first OTP.&lt;/li&gt;
&lt;li&gt;f(f(p)) generates the second OTP.&lt;/li&gt;
&lt;li&gt;This process continues, producing a chain of n passwords.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a result, detection of attempted replay becomes easy. Simply maintain a list of previously used valid one-time passwords and when you receive an invalid one, compare it to this list. If it’s present, it means someone is attempting to replay a previous password. Congratulations, you’re now one step ahead of the attacker.&lt;/p&gt;




&lt;h2&gt;
  
  
  Limitations of Port Knocking: A Professional Perspective
&lt;/h2&gt;

&lt;p&gt;Let’s get out of my localhost bubble and noob-level testing, I’m still figuring things out and probably missing some big points along the way.&lt;br&gt;&lt;br&gt;
After publishing the first part of this series, I was fortunate to hear from a seasoned DevOps engineer who shared his experience with port knocking in a real production environment. He pointed out exactly what I was missing and highlighted the real-world challenges of using port knocking. A huge thanks to him for taking the time to share his expertise. Now, I’d like to share those insights with you.&lt;br&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reliability Issues : 
On certain platforms, particularly Windows, port knocking can be unreliable. Even when the user provides the correct sequence, connection issues may still occur, causing delays in accessing the system.&lt;/li&gt;
&lt;li&gt;Lack of Configurability : 
In enterprise environments, users are often granted specific access levels, such as read-only or write-only permissions, with ACLs applied. With  port knocking, once a user knows the sequence, they are granted full access without any control, posing a significant security risk, this unrestricted access also needs  a robust mechanisms to trace and log user activities.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Exploring Alternatives&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://github.com/moul/sshportal" rel="noopener noreferrer"&gt;sshportal&lt;/a&gt; : simple, fun and transparent SSH (and telnet) bastion server&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://goteleport.com/" rel="noopener noreferrer"&gt;Teleport&lt;/a&gt; : The easiest and most secure way to access and protect all your infrastructure&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/ovh/the-bastion" rel="noopener noreferrer"&gt;the-bastion by OVH&lt;/a&gt; : Authentication, authorization, traceability and auditability for SSH accesses.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Infrastructure for Future Labs&lt;br&gt;&lt;br&gt;
You can find the GitHub repository for the infrastructure I’ve set up on AWS here :&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/0xkr4k3n/KnockKnock" rel="noopener noreferrer"&gt;Port Knocking Infra&lt;/a&gt;&lt;br&gt;&lt;br&gt;
This will serve as the base for the upcoming labs, where I’ll expand the setup, scale it, and implement new features.&lt;/p&gt;

</description>
      <category>security</category>
      <category>networking</category>
      <category>authentication</category>
      <category>aws</category>
    </item>
    <item>
      <title>The Speakeasy Door to Your Network - Port Knocking (1)</title>
      <dc:creator>YounesZn</dc:creator>
      <pubDate>Thu, 09 Jan 2025 18:54:33 +0000</pubDate>
      <link>https://dev.to/youneszn/the-speakeasy-door-to-your-network-port-knocking-1-5a99</link>
      <guid>https://dev.to/youneszn/the-speakeasy-door-to-your-network-port-knocking-1-5a99</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;It's undeniable that the only truly secure system is one that's powered off. But let me tell you, you might as well throw that system away, because from the birth of the internet, every system has been created for a purpose—and that purpose forces it to be exposed publicly and made available to external users, whether it’s for patching, transmitting data, or enhancing functionality. This exposure may be selective, or it may not be, because some systems must be accessible to anyone, from anywhere.&lt;br&gt;&lt;br&gt;
The dilemma that comes to mind now is: if anyone can access such systems, then where on earth is privacy and security? &lt;br&gt;&lt;br&gt;
Well, humans, being smart, standardized the terms authentication and authorization. These are the key concepts that safeguard our data, preventing unauthorized access and keeping it from being compromised. These concepts are primarily managed by the service or system itself, ensuring that before any access is granted, the user must authenticate in one way or another (passwords, two-factor authentication, security questions ...) .&lt;br&gt;&lt;br&gt;
It seems like a good approach, but sadly, it’s not that simple. Let's imagine a network with thousands of services, placing trust in devices that may not be secure by design to handle authentication is a significant risk. &lt;/p&gt;




&lt;h2&gt;
  
  
  Firewalls Are Life Savers
&lt;/h2&gt;

&lt;p&gt;Here come Firewalls: Instead of allowing every user the possibility to access our network and authenticate, why not restrict access to only trusted users? By applying a set of rules on the first device accessible in the network, the firewall, we can selectively accept or deny connections based on criteria such as the source IP address, port numbers, and protocols used. &lt;br&gt;So, finally, we can say our infrastructure is now safer than ever.&lt;br&gt;&lt;br&gt;
However, never be naive, there are several attacks that attackers can use to bypass firewall rules. Once a rule authorizes a certain type of access, attackers can potentially exploit that opening, and—hoopla!—here's the initial foothold they’ve been waiting for. &lt;br&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;span&gt; So, the hero of our story is already defeated before the battle even begins, thanks, firewalls!  -_- &lt;/span&gt;&lt;br&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Come on, firewalls aren’t that fragile! We can take advantage of the fact that they are often the first accessible devices in our network and cleverly play with firewall logic to build a more secure infrastructure. &lt;br&gt;&lt;br&gt;
For that, there are many innovative ways to implement logical solutions that guarantee a secure network. One of them is the &lt;strong&gt;&lt;em&gt;Port Knocking&lt;/em&gt;&lt;/strong&gt; method.&lt;br&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Port Knocking - The concept
&lt;/h2&gt;

&lt;p&gt;Long story short, imagine an infrastructure where certain services are completely inaccessible to everyone—except the users we choose to authorize. To gain access, these users must demonstrate a specific behavior or follow a unique pattern that we can detect. So, we say, "Ah, that's our guy—let them in!". &lt;br&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk9aegdrrr8c7o5mzurae.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk9aegdrrr8c7o5mzurae.png" alt="Image description" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In general, the concept is to give the user we want to authorize a secret series of steps to execute in order to gain access to a service.&lt;br&gt;&lt;br&gt;
As an example, consider an infrastructure that includes an SSH server. The firewall blocks all access to the SSH server on port 22. However, if a user sends packets to a specific sequence of server ports—such as (&lt;span&gt;1234&lt;/span&gt;, &lt;span&gt;5678&lt;/span&gt;, &lt;span&gt;3456&lt;/span&gt;) in our case—and in the exact order, it triggers actions on the firewall.&lt;br&gt;&lt;br&gt;
The firewall, which is always listening for such a sequence, then temporarily opens port 22 for a limited time. If no connection is made during that window, the port automatically closes again, maintaining security.&lt;br&gt;&lt;br&gt;
Inside the mind of an attacker, this security approach still has its weaknesses. All it takes is to sniff the secret sequence from the network and mimic it to gain access. Worse yet, imagine if the trusted user's IP address belongs to a shared resource, like a public WiFi hotspot. The external IP, which acts as the source address from the NAT provider, would need to be opened. At that point, any user of the hotspot could access the same service without needing to replay the sequence.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Stay tuned for the next part, where we’ll explore how to defend our port knocking logic with secure implementation techniques and a Go-based server as an example. You won't want to miss it!&lt;/p&gt;

</description>
      <category>security</category>
      <category>networking</category>
      <category>authentication</category>
    </item>
    <item>
      <title>Dev/prod parity : Spring Boot Testcontainers</title>
      <dc:creator>YounesZn</dc:creator>
      <pubDate>Thu, 09 Jan 2025 18:47:57 +0000</pubDate>
      <link>https://dev.to/youneszn/devprod-parity-spring-boot-testcontainers-16je</link>
      <guid>https://dev.to/youneszn/devprod-parity-spring-boot-testcontainers-16je</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Dev/prod parity aims to reduce the gap between development and production environments. This article targets the tools gap, especially in integration testing with Spring Testcontainers, as a way to make development and production as similar as possible.&lt;br&gt;
When conducting integration tests involving databases, we must manage all CRUD operations carefully. This is crucial in a centralized database environment where a Test, such as TestDeleteUserByID_ShouldReturnOk(), might ‘accidentally’ decide to wipe out the account of our most faithful client who’s been with us since 2015 🤦‍♂️&lt;br&gt;
To mitigate such risks, we can consider solutions like  database transactions to isolate test data. For example, a test could start a transaction to modify data and then roll back at the end, thereby leaving the database in its original state.&lt;br&gt; However, this raises a critical issue: &lt;span&gt;WHAT TESTS THE TEST ?&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxoon7jzyjps6mmhvcriz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxoon7jzyjps6mmhvcriz.png" alt="Image description" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What if the isolation fails and the code executes changes that are somehow not rolled back, leading to data leaks into the production environment? The potential damage in such scenarios is significant.&lt;br&gt;&lt;br&gt;
Alternatively, self-contained testing with an in-memory database like H2DB presents also some challenges. even if it's easy to set up, H2DB differs from RDBMS so there is a high probability that tests might have different results between development and production environments, so we can't trust those results.&lt;br&gt;&lt;br&gt;
&lt;a href="https://stackoverflow.com/questions/62778900/syntax-error-h2-database-in-postgresql-compatibility" rel="noopener noreferrer"&gt;https://stackoverflow.com/questions/62778900/syntax-error-h2-database-in-postgresql-compatibility&lt;/a&gt;&lt;br&gt;&lt;br&gt;
The next less problematic solution is to clone the database, providing a less risky approach with a production-like environment. However, this method comes with its limits. Given that ORMs automate the creation and setup of the production database schema, we need to think about how to keep the cloned development database in sync.&lt;/p&gt;


&lt;h2&gt;
  
  
  Test Anything You Can Containerize: Database, Message Broker, And More
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;"Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container."&lt;br&gt;&lt;br&gt;
Originally developed for Java, it has since been expanded to support other languages like Go, Rust, and .NET.&lt;br&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The main idea of Testcontainers is to provide an on-demand infrastructure, runnable from the IDE, where tests can be conducted without the need for mocking or using in-memory services, and with automatic cleanup.&lt;br&gt;&lt;br&gt;
We can achieve this in three steps : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start the required services and prepare the infrastructure by setting up Docker containers and configure your application to use this setup as the testing infrastructure.&lt;/li&gt;
&lt;li&gt;Run your tests on the dockerized infrastructure.&lt;/li&gt;
&lt;li&gt;Automatically clean up the dockerized infrastructure once the tests have concluded&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://testcontainers.com/" rel="noopener noreferrer"&gt;Testcontainers library documentation&lt;/a&gt; &lt;/p&gt;


&lt;h2&gt;
  
  
  Spring Boot Testcontainers Implementation
&lt;/h2&gt;

&lt;p&gt;In ApplicationIntegrationTests, which is the base class for integration testing, we define a static PostgreSQLContainer. This container is used across all test instances derived from this class.&lt;br&gt;&lt;br&gt;
 The @Testcontainers annotation enables the discovery of all fields annotated with @Container, managing their container lifecycle methods, and starting the containers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Containers declared as static fields are shared between test methods. They are started only once before any test method is executed and stopped after the last test method has executed.&lt;/li&gt;
&lt;li&gt;Containers declared as instance fields are started and stopped for every test method.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The @DynamicPropertySource annotation allows us to dynamically inject properties into our test environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Testcontainers&lt;/span&gt;
&lt;span class="nd"&gt;@ActiveProfiles&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicationIntegrationTests&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Container&lt;/span&gt;
    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;PostgreSQLContainer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PostgreSQLContainer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"postgres:17.2-alpine"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withDatabaseName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"testcontainersproject"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withUsername&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"root"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withPassword&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"root"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nd"&gt;@DynamicPropertySource&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DynamicPropertyRegistry&lt;/span&gt; &lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"spring.datasource.url"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;postgres:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getJdbcUrl&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"spring.datasource.username"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;postgres:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getUsername&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"spring.datasource.password"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;postgres:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getPassword&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;


&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, we can skip the use of @Testcontainers and @Container and instead manage the container lifecycle directly using @BeforeAll and @AfterAll. This approach allows more control over when and how containers are started and stopped&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@BeforeAll&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;runContainer&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nd"&gt;@AfterAll&lt;/span&gt;
&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;stopContainers&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stop&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the @AfterAll callback method, we explicitly stop the Postgres container. However, even if we don't explicitly stop the container, Testcontainers will automatically clean up and shut down the containers at the end of the test run.&lt;/p&gt;

&lt;p&gt;Now we can create integration tests by extending ApplicationIntegrationTests as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@SpringBootTest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;webEnvironment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SpringBootTest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;WebEnvironment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;RANDOM_PORT&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@AutoConfigureMockMvc&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CategoryControllerTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ApplicationIntegrationTests&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="no"&gt;CATEGORY_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/categories"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
   &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;MockMvc&lt;/span&gt; &lt;span class="n"&gt;mockMvc&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;CategoryRepository&lt;/span&gt; &lt;span class="n"&gt;categoryRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;TestGetAllCategories_ShouldReturnOk&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Category&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;categories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Category&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Electronics"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"All kinds of electronic gadgets from smartphones to laptops"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Category&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Books"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"A wide range of books from novels to educational textbooks"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;categoryRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;saveAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;categories&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;MvcResult&lt;/span&gt; &lt;span class="n"&gt;mvcResult&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;mockMvc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;perform&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;CATEGORY_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;
                        &lt;span class="n"&gt;contentType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;APPLICATION_JSON&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;andExpect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;isOk&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;andReturn&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;mvcResult&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getResponse&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getContentAsString&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;assertNotNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;assertFalse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>springboot</category>
      <category>docker</category>
      <category>testing</category>
      <category>java</category>
    </item>
  </channel>
</rss>
