View Javadoc
1   package io.apicurio.registry.maven;
2   
3   import com.github.tomakehurst.wiremock.WireMockServer;
4   import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
5   import io.apicurio.registry.rest.v3.beans.IfArtifactExists;
6   import io.apicurio.registry.types.ArtifactType;
7   import org.apache.maven.plugin.MojoExecutionException;
8   import org.junit.jupiter.api.AfterEach;
9   import org.junit.jupiter.api.BeforeEach;
10  import org.junit.jupiter.api.Test;
11  
12  import java.io.File;
13  import java.nio.file.Files;
14  import java.util.Collections;
15  
16  import static com.github.tomakehurst.wiremock.client.WireMock.*;
17  import static org.junit.jupiter.api.Assertions.*;
18  
19  /**
20   * Integration tests for TLS configuration functionality in the Maven plugin.
21   * These tests use WireMock with HTTPS to verify actual TLS connectivity.
22   */
23  public class TlsIntegrationTest {
24  
25      private static final String CERTS_DIR = "src/test/resources/certs";
26      private static final String PASSWORD = "changeit";
27  
28      private WireMockServer wireMockServer;
29      private RegisterRegistryMojo mojo;
30      private File tempSchemaFile;
31  
32      @BeforeEach
33      void setup() throws Exception {
34          // Create a temporary schema file for testing
35          tempSchemaFile = Files.createTempFile("test-schema", ".avsc").toFile();
36          Files.writeString(tempSchemaFile.toPath(), """
37              {
38                "type": "record",
39                "name": "TestRecord",
40                "namespace": "io.apicurio.test",
41                "fields": [
42                  {"name": "id", "type": "string"}
43                ]
44              }
45              """);
46          tempSchemaFile.deleteOnExit();
47  
48          mojo = new RegisterRegistryMojo();
49      }
50  
51      @AfterEach
52      void tearDown() {
53          if (wireMockServer != null && wireMockServer.isRunning()) {
54              wireMockServer.stop();
55          }
56          if (tempSchemaFile != null) {
57              tempSchemaFile.delete();
58          }
59      }
60  
61      private void startHttpsServer() {
62          WireMockConfiguration config = WireMockConfiguration.wireMockConfig()
63                  .dynamicHttpsPort()
64                  .httpDisabled(true)
65                  .keystorePath(getResourcePath("server-keystore.jks"))
66                  .keystorePassword(PASSWORD)
67                  .keyManagerPassword(PASSWORD)
68                  .keystoreType("JKS");
69  
70          wireMockServer = new WireMockServer(config);
71          wireMockServer.start();
72  
73          // Mock the artifact registration endpoint
74          wireMockServer.stubFor(post(urlPathMatching("/apis/registry/v3/groups/.*/artifacts"))
75                  .willReturn(aResponse()
76                          .withStatus(200)
77                          .withHeader("Content-Type", "application/json")
78                          .withBody("""
79                              {
80                                "version": {
81                                  "version": "1",
82                                  "globalId": 12345,
83                                  "contentId": 67890
84                                },
85                                "artifact": {
86                                  "groupId": "test-group",
87                                  "artifactId": "TestRecord"
88                                }
89                              }
90                              """)));
91      }
92  
93      private String getResourcePath(String filename) {
94          return new File(CERTS_DIR, filename).getAbsolutePath();
95      }
96  
97      private RegisterArtifact createTestArtifact() {
98          RegisterArtifact artifact = new RegisterArtifact();
99          artifact.setGroupId("test-group");
100         artifact.setArtifactId("TestRecord");
101         artifact.setArtifactType(ArtifactType.AVRO);
102         artifact.setFile(tempSchemaFile);
103         artifact.setIfExists(IfArtifactExists.FIND_OR_CREATE_VERSION);
104         return artifact;
105     }
106 
107     // ========================================================================
108     // TLS with Trust Store Tests
109     // ========================================================================
110 
111     @Test
112     void testTlsWithPkcs12TrustStore() throws Exception {
113         startHttpsServer();
114 
115         mojo.setRegistryUrl(wireMockServer.baseUrl() + "/apis/registry/v3");
116         mojo.setTrustStorePath(getResourcePath("truststore.p12"));
117         mojo.setTrustStorePassword(PASSWORD);
118         mojo.setArtifacts(Collections.singletonList(createTestArtifact()));
119 
120         // Should succeed - TLS connection with proper trust store
121         assertDoesNotThrow(() -> mojo.execute());
122 
123         // Verify the request was made
124         wireMockServer.verify(postRequestedFor(urlPathMatching("/apis/registry/v3/groups/.*/artifacts")));
125     }
126 
127     @Test
128     void testTlsWithJksTrustStore() throws Exception {
129         startHttpsServer();
130 
131         mojo.setRegistryUrl(wireMockServer.baseUrl() + "/apis/registry/v3");
132         mojo.setTrustStorePath(getResourcePath("truststore.jks"));
133         mojo.setTrustStorePassword(PASSWORD);
134         mojo.setArtifacts(Collections.singletonList(createTestArtifact()));
135 
136         // Should succeed - TLS connection with JKS trust store
137         assertDoesNotThrow(() -> mojo.execute());
138 
139         wireMockServer.verify(postRequestedFor(urlPathMatching("/apis/registry/v3/groups/.*/artifacts")));
140     }
141 
142     @Test
143     void testTlsWithPemTrustStore() throws Exception {
144         startHttpsServer();
145 
146         mojo.setRegistryUrl(wireMockServer.baseUrl() + "/apis/registry/v3");
147         mojo.setTrustStorePath(getResourcePath("ca-cert.pem"));
148         mojo.setArtifacts(Collections.singletonList(createTestArtifact()));
149 
150         // Should succeed - TLS connection with PEM certificate
151         assertDoesNotThrow(() -> mojo.execute());
152 
153         wireMockServer.verify(postRequestedFor(urlPathMatching("/apis/registry/v3/groups/.*/artifacts")));
154     }
155 
156     @Test
157     void testTlsWithoutTrustStore_Fails() throws Exception {
158         startHttpsServer();
159 
160         mojo.setRegistryUrl(wireMockServer.baseUrl() + "/apis/registry/v3");
161         // No trust store configured - should fail because server uses self-signed cert
162         mojo.setArtifacts(Collections.singletonList(createTestArtifact()));
163 
164         // Should fail - no trust store to validate server certificate
165         assertThrows(MojoExecutionException.class, () -> mojo.execute());
166     }
167 
168     @Test
169     void testTlsWithTrustAll() throws Exception {
170         startHttpsServer();
171 
172         mojo.setRegistryUrl(wireMockServer.baseUrl() + "/apis/registry/v3");
173         mojo.setTrustAll(true);
174         mojo.setArtifacts(Collections.singletonList(createTestArtifact()));
175 
176         // Should succeed - trustAll bypasses certificate validation
177         assertDoesNotThrow(() -> mojo.execute());
178 
179         wireMockServer.verify(postRequestedFor(urlPathMatching("/apis/registry/v3/groups/.*/artifacts")));
180     }
181 
182     // ========================================================================
183     // TLS with Authentication Tests
184     // ========================================================================
185 
186     @Test
187     void testTlsWithBasicAuth() throws Exception {
188         startHttpsServer();
189 
190         // Add basic auth stub
191         wireMockServer.stubFor(post(urlPathMatching("/apis/registry/v3/groups/.*/artifacts"))
192                 .withBasicAuth("testuser", "testpass")
193                 .willReturn(aResponse()
194                         .withStatus(200)
195                         .withHeader("Content-Type", "application/json")
196                         .withBody("""
197                             {
198                               "version": {
199                                 "version": "1",
200                                 "globalId": 12345,
201                                 "contentId": 67890
202                               },
203                               "artifact": {
204                                 "groupId": "test-group",
205                                 "artifactId": "TestRecord"
206                               }
207                             }
208                             """)));
209 
210         mojo.setRegistryUrl(wireMockServer.baseUrl() + "/apis/registry/v3");
211         mojo.setTrustStorePath(getResourcePath("truststore.p12"));
212         mojo.setTrustStorePassword(PASSWORD);
213         mojo.setUsername("testuser");
214         mojo.setPassword("testpass");
215         mojo.setArtifacts(Collections.singletonList(createTestArtifact()));
216 
217         // Should succeed - TLS with basic auth
218         assertDoesNotThrow(() -> mojo.execute());
219 
220         wireMockServer.verify(postRequestedFor(urlPathMatching("/apis/registry/v3/groups/.*/artifacts"))
221                 .withBasicAuth(new com.github.tomakehurst.wiremock.client.BasicCredentials("testuser", "testpass")));
222     }
223 
224     // ========================================================================
225     // Explicit Store Type Tests
226     // ========================================================================
227 
228     @Test
229     void testExplicitTrustStoreType() throws Exception {
230         startHttpsServer();
231 
232         // Rename p12 file extension to test explicit type setting
233         mojo.setRegistryUrl(wireMockServer.baseUrl() + "/apis/registry/v3");
234         mojo.setTrustStorePath(getResourcePath("truststore.p12"));
235         mojo.setTrustStorePassword(PASSWORD);
236         mojo.setTrustStoreType("PKCS12"); // Explicit type
237         mojo.setArtifacts(Collections.singletonList(createTestArtifact()));
238 
239         assertDoesNotThrow(() -> mojo.execute());
240 
241         wireMockServer.verify(postRequestedFor(urlPathMatching("/apis/registry/v3/groups/.*/artifacts")));
242     }
243 }