1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.fit.sra;
20
21 import static org.awaitility.Awaitility.await;
22 import static org.hamcrest.MatcherAssert.assertThat;
23 import static org.hamcrest.Matchers.is;
24 import static org.hamcrest.Matchers.oneOf;
25 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
26 import static org.junit.jupiter.api.Assertions.assertEquals;
27 import static org.junit.jupiter.api.Assertions.assertNotNull;
28 import static org.junit.jupiter.api.Assertions.fail;
29
30 import com.fasterxml.jackson.databind.JsonNode;
31 import com.fasterxml.jackson.databind.json.JsonMapper;
32 import com.fasterxml.jackson.databind.node.ArrayNode;
33 import com.fasterxml.jackson.databind.node.ObjectNode;
34 import java.io.IOException;
35 import java.io.InputStream;
36 import java.net.ConnectException;
37 import java.net.InetSocketAddress;
38 import java.net.Socket;
39 import java.net.URI;
40 import java.util.Map;
41 import java.util.Properties;
42 import java.util.concurrent.TimeUnit;
43 import java.util.concurrent.TimeoutException;
44 import javax.ws.rs.core.HttpHeaders;
45 import javax.ws.rs.core.MediaType;
46 import javax.ws.rs.core.Response;
47 import org.apache.commons.lang3.StringUtils;
48 import org.apache.cxf.jaxrs.client.WebClient;
49 import org.apache.http.HttpStatus;
50 import org.apache.http.client.methods.CloseableHttpResponse;
51 import org.apache.http.util.EntityUtils;
52 import org.apache.syncope.common.lib.policy.AttrReleasePolicyTO;
53 import org.apache.syncope.common.lib.policy.AuthPolicyTO;
54 import org.apache.syncope.common.lib.policy.DefaultAttrReleasePolicyConf;
55 import org.apache.syncope.common.lib.policy.DefaultAuthPolicyConf;
56 import org.apache.syncope.common.lib.to.SRARouteTO;
57 import org.apache.syncope.common.lib.types.PolicyType;
58 import org.apache.syncope.common.lib.types.SRARouteFilter;
59 import org.apache.syncope.common.lib.types.SRARouteFilterFactory;
60 import org.apache.syncope.common.lib.types.SRARoutePredicate;
61 import org.apache.syncope.common.lib.types.SRARoutePredicateFactory;
62 import org.apache.syncope.common.lib.types.SRARouteType;
63 import org.apache.syncope.common.rest.api.RESTHeaders;
64 import org.apache.syncope.fit.AbstractITCase;
65 import org.junit.jupiter.api.AfterAll;
66 import org.junit.jupiter.api.BeforeAll;
67
68 public abstract class AbstractSRAITCase extends AbstractITCase {
69
70 protected static final JsonMapper MAPPER = JsonMapper.builder().findAndAddModules().build();
71
72 protected static final String SRA_ADDRESS = "http://127.0.0.1:8080";
73
74 protected static final String QUERY_STRING =
75 "key1=value1&key2=value2&key2=value3&key3=an%20url%20encoded%20value%3A%20this%21";
76
77 protected static final String LOGGED_OUT_HEADER = "X-LOGGED-OUT";
78
79 private static Process SRA;
80
81 @BeforeAll
82 public static void sraRouteSetup() {
83 SRA_ROUTE_SERVICE.list().forEach(route -> SRA_ROUTE_SERVICE.delete(route.getKey()));
84
85 SRARouteTO publicRoute = new SRARouteTO();
86 publicRoute.setName("public");
87 publicRoute.setTarget(URI.create("http://localhost:80"));
88 publicRoute.setType(SRARouteType.PUBLIC);
89 publicRoute.setCsrf(false);
90 publicRoute.getPredicates().add(new SRARoutePredicate.Builder().
91 factory(SRARoutePredicateFactory.PATH).args("/public/{segment}").build());
92 publicRoute.getFilters().add(new SRARouteFilter.Builder().
93 factory(SRARouteFilterFactory.SET_PATH).args("/{segment}").build());
94
95 Response response = SRA_ROUTE_SERVICE.create(publicRoute);
96 if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
97 fail("Could not create public SRA Route");
98 }
99
100 SRARouteTO protectedRoute = new SRARouteTO();
101 protectedRoute.setName("protected");
102 protectedRoute.setTarget(URI.create("http://localhost:80"));
103 protectedRoute.setType(SRARouteType.PROTECTED);
104 protectedRoute.setCsrf(false);
105 protectedRoute.getPredicates().add(new SRARoutePredicate.Builder().
106 factory(SRARoutePredicateFactory.PATH).args("/protected/{segment}").build());
107 protectedRoute.getFilters().add(new SRARouteFilter.Builder().
108 factory(SRARouteFilterFactory.SET_PATH).args("/{segment}").build());
109
110 response = SRA_ROUTE_SERVICE.create(protectedRoute);
111 if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
112 fail("Could not create protected SRA Route");
113 }
114
115 SRARouteTO logoutRoute = new SRARouteTO();
116 logoutRoute.setName("logout");
117 logoutRoute.setTarget(URI.create("http://localhost:80"));
118 logoutRoute.setType(SRARouteType.PROTECTED);
119 logoutRoute.setLogout(true);
120 logoutRoute.getPredicates().add(new SRARoutePredicate.Builder().
121 factory(SRARoutePredicateFactory.PATH).args("/protected/logout").build());
122 logoutRoute.setOrder(-1);
123
124 response = SRA_ROUTE_SERVICE.create(logoutRoute);
125 if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
126 fail("Could not create logout SRA Route");
127 }
128
129 SRARouteTO postLogout = new SRARouteTO();
130 postLogout.setName("postLogout");
131 postLogout.setTarget(URI.create("http://localhost:80"));
132 postLogout.setType(SRARouteType.PUBLIC);
133 postLogout.getPredicates().add(new SRARoutePredicate.Builder().
134 factory(SRARoutePredicateFactory.PATH).args("/logout").build());
135 postLogout.getFilters().add(new SRARouteFilter.Builder().
136 factory(SRARouteFilterFactory.SET_STATUS).args("204").build());
137 postLogout.getFilters().add(new SRARouteFilter.Builder().
138 factory(SRARouteFilterFactory.SET_RESPONSE_HEADER).args(LOGGED_OUT_HEADER + ", true").build());
139 postLogout.setOrder(-10);
140
141 response = SRA_ROUTE_SERVICE.create(postLogout);
142 if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
143 fail("Could not create logout SRA Route");
144 }
145 }
146
147 protected static void doStartSRA(final String activeProfile)
148 throws IOException, InterruptedException, TimeoutException {
149
150 Properties props = new Properties();
151 try (InputStream propStream = AbstractSRAITCase.class.getResourceAsStream("/test.properties")) {
152 props.load(propStream);
153 } catch (Exception e) {
154 fail("Could not load /test.properties", e);
155 }
156
157 String javaHome = props.getProperty("java.home");
158 assertNotNull(javaHome);
159
160 String sraJar = props.getProperty("sra.jar");
161 assertNotNull(sraJar);
162
163 String keymasterApiJar = props.getProperty("keymaster-api.jar");
164 assertNotNull(keymasterApiJar);
165
166 String keymasterClientJar = props.getProperty("keymaster-client.jar");
167 assertNotNull(keymasterClientJar);
168
169 String trustStore = props.getProperty("trustStore");
170 assertNotNull(trustStore);
171 String trustStorePassword = props.getProperty("trustStorePassword");
172 assertNotNull(trustStorePassword);
173
174 String targetTestClasses = props.getProperty("targetTestClasses");
175 assertNotNull(targetTestClasses);
176
177 ProcessBuilder processBuilder = new ProcessBuilder(
178 javaHome + "/bin/java",
179 "-Dreactor.netty.http.server.accessLogEnabled=true",
180 "-Djavax.net.ssl.trustStore=" + trustStore,
181 "-Djavax.net.ssl.trustStorePassword=" + trustStorePassword,
182 "-jar",
183 "-Xdebug",
184 "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8002",
185 sraJar);
186 processBuilder.inheritIO();
187
188 Map<String, String> environment = processBuilder.environment();
189 environment.put("LOADER_PATH", targetTestClasses + "," + keymasterApiJar + "," + keymasterClientJar);
190 environment.put("SPRING_PROFILES_ACTIVE", activeProfile);
191
192 SRA = processBuilder.start();
193
194 await().atMost(120, TimeUnit.SECONDS).pollInterval(3, TimeUnit.SECONDS).until(() -> {
195 boolean connected = false;
196 try (Socket socket = new Socket()) {
197 socket.connect(new InetSocketAddress("0.0.0.0", 8080));
198 connected = socket.isConnected();
199 } catch (ConnectException e) {
200
201 }
202 return connected;
203 });
204 assertDoesNotThrow(() -> WebClient.create(SRA_ADDRESS).get().getStatus());
205
206 SRA_ROUTE_SERVICE.pushToSRA();
207 }
208
209 @AfterAll
210 public static void stopSRA() throws InterruptedException {
211 if (SRA != null) {
212 SRA.destroy();
213 SRA.waitFor();
214 }
215 }
216
217 protected static AuthPolicyTO getAuthPolicy() {
218 String authModule = "DefaultSyncopeAuthModule";
219 String description = "SRA auth policy";
220
221 return POLICY_SERVICE.list(PolicyType.AUTH).stream().
222 map(AuthPolicyTO.class::cast).
223 filter(policy -> description.equals(policy.getName())
224 && policy.getConf() instanceof DefaultAuthPolicyConf
225 && ((DefaultAuthPolicyConf) policy.getConf()).getAuthModules().contains(authModule)).
226 findFirst().
227 orElseGet(() -> {
228 DefaultAuthPolicyConf policyConf = new DefaultAuthPolicyConf();
229 policyConf.getAuthModules().add(authModule);
230
231 AuthPolicyTO policy = new AuthPolicyTO();
232 policy.setName(description);
233 policy.setConf(policyConf);
234
235 Response response = POLICY_SERVICE.create(PolicyType.AUTH, policy);
236 if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
237 fail("Could not create Syncope Auth Policy");
238 }
239
240 return POLICY_SERVICE.read(PolicyType.AUTH, response.getHeaderString(RESTHeaders.RESOURCE_KEY));
241 });
242 }
243
244 protected static AttrReleasePolicyTO getAttrReleasePolicy() {
245 String description = "SRA attr release policy";
246
247 return POLICY_SERVICE.list(PolicyType.ATTR_RELEASE).stream().
248 map(AttrReleasePolicyTO.class::cast).
249 filter(policy -> description.equals(policy.getName())
250 && policy.getConf() instanceof DefaultAttrReleasePolicyConf).
251 findFirst().
252 orElseGet(() -> {
253 DefaultAttrReleasePolicyConf policyConf = new DefaultAttrReleasePolicyConf();
254 policyConf.getAllowedAttrs().add("family_name");
255 policyConf.getAllowedAttrs().add("name");
256 policyConf.getAllowedAttrs().add("given_name");
257 policyConf.getAllowedAttrs().add("email");
258 policyConf.getAllowedAttrs().add("groups");
259
260 AttrReleasePolicyTO policy = new AttrReleasePolicyTO();
261 policy.setName(description);
262 policy.setConf(policyConf);
263
264 Response response = POLICY_SERVICE.create(PolicyType.ATTR_RELEASE, policy);
265 if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
266 fail("Could not create Test Attr Release Policy");
267 }
268
269 return POLICY_SERVICE.read(
270 PolicyType.ATTR_RELEASE,
271 response.getHeaderString(RESTHeaders.RESOURCE_KEY));
272 });
273 }
274
275 protected static ObjectNode checkGetResponse(
276 final CloseableHttpResponse response, final String originalRequestURI) throws IOException {
277
278 assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
279
280 assertEquals(MediaType.APPLICATION_JSON, response.getFirstHeader(HttpHeaders.CONTENT_TYPE).getValue());
281
282 JsonNode json = MAPPER.readTree(EntityUtils.toString(response.getEntity()));
283
284 ObjectNode args = (ObjectNode) json.get("args");
285 assertEquals("value1", args.get("key1").asText());
286
287 ArrayNode key2 = (ArrayNode) args.get("key2");
288 assertEquals("value2", key2.get(0).asText());
289 assertEquals("value3", key2.get(1).asText());
290
291 assertEquals("an url encoded value: this!", args.get("key3").asText());
292
293 ObjectNode headers = (ObjectNode) json.get("headers");
294 assertEquals(MediaType.TEXT_HTML, headers.get(HttpHeaders.ACCEPT).asText());
295 assertThat(headers.get("X-Forwarded-Host").asText(), is(oneOf("localhost:8080", "127.0.0.1:8080")));
296
297 String withHost = StringUtils.substringBefore(originalRequestURI, "?");
298 String withIP = withHost.replace("localhost", "127.0.0.1");
299 assertThat(StringUtils.substringBefore(json.get("url").asText(), "?"), is(oneOf(withHost, withIP)));
300
301 return headers;
302 }
303
304 protected void checkLogout(final CloseableHttpResponse response) throws IOException {
305 assertEquals(HttpStatus.SC_NO_CONTENT, response.getStatusLine().getStatusCode());
306 assertEquals("true", response.getFirstHeader(LOGGED_OUT_HEADER).getValue());
307 }
308 }