1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.shiro.testing.web;
20
21 import org.apache.shiro.codec.Base64;
22
23 import com.gargoylesoftware.htmlunit.WebClient;
24 import com.github.mjeanroy.junit.servers.jetty.EmbeddedJetty;
25 import com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration;
26 import org.eclipse.jetty.annotations.AnnotationConfiguration;
27 import org.eclipse.jetty.http.HttpVersion;
28 import org.eclipse.jetty.server.HttpConfiguration;
29 import org.eclipse.jetty.server.HttpConnectionFactory;
30 import org.eclipse.jetty.server.SecureRequestCustomizer;
31 import org.eclipse.jetty.server.Server;
32 import org.eclipse.jetty.server.ServerConnector;
33 import org.eclipse.jetty.server.SslConnectionFactory;
34 import org.eclipse.jetty.util.resource.FileResource;
35 import org.eclipse.jetty.util.ssl.SslContextFactory;
36 import org.eclipse.jetty.webapp.Configuration;
37 import org.eclipse.jetty.webapp.FragmentConfiguration;
38 import org.eclipse.jetty.webapp.JettyWebXmlConfiguration;
39 import org.eclipse.jetty.webapp.MetaInfConfiguration;
40 import org.eclipse.jetty.webapp.WebAppContext;
41 import org.eclipse.jetty.webapp.WebInfConfiguration;
42 import org.eclipse.jetty.webapp.WebXmlConfiguration;
43 import org.junit.AfterClass;
44 import org.junit.Before;
45 import org.junit.BeforeClass;
46
47 import java.io.File;
48 import java.io.FilenameFilter;
49 import java.io.IOException;
50 import java.io.UnsupportedEncodingException;
51 import java.net.ServerSocket;
52 import java.net.URL;
53 import java.nio.file.Files;
54 import java.nio.file.Path;
55 import java.nio.file.StandardCopyOption;
56
57 import static com.github.mjeanroy.junit.servers.commons.Strings.isNotBlank;
58 import static org.eclipse.jetty.util.resource.Resource.newResource;
59 import static org.junit.Assert.assertEquals;
60 import static org.junit.Assert.assertTrue;
61
62 public abstract class AbstractContainerIT {
63
64 protected static EmbeddedJetty jetty;
65
66 protected static int tlsPort;
67
68 protected final WebClient webClient = new WebClient();
69
70 protected static final File TEST_KEYSTORE_PATH = setupKeyStore();
71 protected static final String TEST_KEYSTORE_PASSWORD = "password";
72
73 @BeforeClass
74 public static void startContainer() throws Exception {
75
76 EmbeddedJettyConfiguration config = EmbeddedJettyConfiguration.builder()
77 .withWebapp(getWarDir())
78 .build();
79
80 jetty = new EmbeddedJetty(config) {
81
82
83
84
85
86 protected WebAppContext createdWebAppContext() throws Exception {
87 final String path = configuration.getPath();
88 final String webapp = configuration.getWebapp();
89 final String classpath = configuration.getClasspath();
90
91 WebAppContext ctx = new WebAppContext();
92 ctx.setClassLoader(Thread.currentThread().getContextClassLoader());
93 ctx.setContextPath(path);
94
95
96 ctx.setBaseResource(newResource(webapp));
97
98 ctx.setConfigurations(new Configuration[]{
99 new WebInfConfiguration(),
100 new WebXmlConfiguration(),
101 new AnnotationConfiguration(),
102 new JettyWebXmlConfiguration(),
103 new MetaInfConfiguration(),
104 new FragmentConfiguration(),
105 });
106
107 if (isNotBlank(classpath)) {
108
109
110
111
112 File classes = new File(classpath);
113 FileResource containerResources = new FileResource(classes.toURI());
114 ctx.getMetaData().addContainerResource(containerResources);
115 }
116
117 Server server = getDelegate();
118
119
120 ctx.setParentLoaderPriority(true);
121 ctx.setWar(webapp);
122 ctx.setServer(server);
123
124
125 server.setHandler(ctx);
126
127 return ctx;
128 }
129 };
130
131 Server server = jetty.getDelegate();
132
133
134 tlsPort = getFreePort();
135
136 final SslContextFactory sslContextFactory = new SslContextFactory.Server();
137 sslContextFactory.setKeyStorePath(TEST_KEYSTORE_PATH.getAbsolutePath());
138 sslContextFactory.setKeyStorePassword(TEST_KEYSTORE_PASSWORD);
139 sslContextFactory.setKeyManagerPassword(TEST_KEYSTORE_PASSWORD);
140
141 HttpConfiguration https = new HttpConfiguration();
142 https.addCustomizer(new SecureRequestCustomizer());
143
144 final ServerConnector httpsConnector = new ServerConnector(
145 server,
146 new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()),
147 new HttpConnectionFactory(https));
148 httpsConnector.setPort(tlsPort);
149 server.addConnector(httpsConnector);
150
151 jetty.start();
152
153 assertTrue(jetty.isStarted());
154 }
155
156 protected static String getBaseUri() {
157 return "http://localhost:" + jetty.getPort() + "/";
158 }
159
160 protected static String getTlsBaseUri() {
161 return "https://localhost:" + tlsPort + "/";
162 }
163
164 protected static String getWarDir() {
165 File[] warFiles = new File("target").listFiles(new FilenameFilter() {
166 @Override
167 public boolean accept(File dir, String name) {
168 return name.endsWith(".war");
169 }
170 });
171
172 assertEquals("Expected only one war file in target directory, run 'mvn clean' and try again", 1, warFiles.length);
173
174 return warFiles[0].getAbsolutePath().replaceFirst("\\.war$", "");
175 }
176
177 protected static String getBasicAuthorizationHeaderValue(String username, String password) throws UnsupportedEncodingException {
178 String authorizationHeader = username + ":" + password;
179 byte[] valueBytes;
180 valueBytes = authorizationHeader.getBytes("UTF-8");
181 authorizationHeader = new String(Base64.encode(valueBytes));
182 return "Basic " + authorizationHeader;
183 }
184
185 @Before
186 public void beforeTest() {
187 webClient.getOptions().setThrowExceptionOnFailingStatusCode(true);
188 }
189
190 @AfterClass
191 public static void stopContainer() {
192 if (jetty != null) {
193 jetty.stop();
194 }
195 }
196
197 private static int getFreePort() {
198 try (ServerSocket socket = new ServerSocket(0)) {
199 return socket.getLocalPort();
200 } catch (IOException e) {
201 throw new IllegalStateException("Failed to allocate free port", e);
202 }
203 }
204
205
206
207 private static File setupKeyStore() {
208 try {
209 Path outKeyStoreFile = File.createTempFile("test-keystore", "jks").toPath();
210 URL keyStoreResource = Thread.currentThread().getContextClassLoader().getResource("test-keystore.jks");
211 Files.copy(keyStoreResource.openStream(), outKeyStoreFile, StandardCopyOption.REPLACE_EXISTING);
212 File keyStoreFile = outKeyStoreFile.toFile();
213
214
215 System.setProperty("javax.net.ssl.trustStore", keyStoreFile.getAbsolutePath());
216 System.setProperty("javax.net.ssl.trustStorePassword", TEST_KEYSTORE_PASSWORD);
217 return keyStoreFile;
218 } catch (IOException e) {
219 throw new IllegalStateException("Failed to create test keystore", e);
220 }
221 }
222 }