blob: 22d0e7c37c3f878960b8421c70d0452976f22632 [file] [log] [blame]
/*
* 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.syncope.fit.sra;
import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.fail;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.IOException;
import java.io.InputStream;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URI;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.commons.lang3.StringUtils;
import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.util.EntityUtils;
import org.apache.syncope.common.lib.policy.AuthPolicyTO;
import org.apache.syncope.common.lib.policy.DefaultAuthPolicyConf;
import org.apache.syncope.common.lib.to.SRARouteTO;
import org.apache.syncope.common.lib.types.PolicyType;
import org.apache.syncope.common.lib.types.SRARouteFilter;
import org.apache.syncope.common.lib.types.SRARouteFilterFactory;
import org.apache.syncope.common.lib.types.SRARoutePredicate;
import org.apache.syncope.common.lib.types.SRARoutePredicateFactory;
import org.apache.syncope.common.lib.types.SRARouteType;
import org.apache.syncope.common.rest.api.RESTHeaders;
import org.apache.syncope.fit.AbstractITCase;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
public abstract class AbstractSRAITCase extends AbstractITCase {
protected static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
protected static final int PORT = 8080;
protected static final String SRA_ADDRESS = "http://localhost:" + PORT;
protected static final String QUERY_STRING =
"key1=value1&key2=value2&key2=value3&key3=an%20url%20encoded%20value%3A%20this%21";
protected static final String LOGGED_OUT_HEADER = "X-LOGGED-OUT";
private static Process SRA;
@BeforeAll
public static void sraRouteSetup() {
sraRouteService.list().forEach(route -> sraRouteService.delete(route.getKey()));
SRARouteTO publicRoute = new SRARouteTO();
publicRoute.setName("public");
publicRoute.setTarget(URI.create("http://httpbin.org:80"));
publicRoute.setType(SRARouteType.PUBLIC);
publicRoute.setCsrf(false);
publicRoute.getPredicates().add(new SRARoutePredicate.Builder().
factory(SRARoutePredicateFactory.PATH).args("/public/{segment}").build());
publicRoute.getFilters().add(new SRARouteFilter.Builder().
factory(SRARouteFilterFactory.SET_PATH).args("/{segment}").build());
Response response = sraRouteService.create(publicRoute);
if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
fail("Could not create public SRA Route");
}
SRARouteTO protectedRoute = new SRARouteTO();
protectedRoute.setName("protected");
protectedRoute.setTarget(URI.create("http://httpbin.org:80"));
protectedRoute.setType(SRARouteType.PROTECTED);
protectedRoute.setCsrf(false);
protectedRoute.getPredicates().add(new SRARoutePredicate.Builder().
factory(SRARoutePredicateFactory.PATH).args("/protected/{segment}").build());
protectedRoute.getFilters().add(new SRARouteFilter.Builder().
factory(SRARouteFilterFactory.SET_PATH).args("/{segment}").build());
response = sraRouteService.create(protectedRoute);
if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
fail("Could not create protected SRA Route");
}
SRARouteTO logoutRoute = new SRARouteTO();
logoutRoute.setName("logout");
logoutRoute.setTarget(URI.create("http://httpbin.org:80"));
logoutRoute.setType(SRARouteType.PROTECTED);
logoutRoute.setLogout(true);
logoutRoute.getPredicates().add(new SRARoutePredicate.Builder().
factory(SRARoutePredicateFactory.PATH).args("/protected/logout").build());
logoutRoute.setOrder(-1);
response = sraRouteService.create(logoutRoute);
if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
fail("Could not create logout SRA Route");
}
SRARouteTO postLogout = new SRARouteTO();
postLogout.setName("postLogout");
postLogout.setTarget(URI.create("http://httpbin.org:80"));
postLogout.setType(SRARouteType.PUBLIC);
postLogout.getPredicates().add(new SRARoutePredicate.Builder().
factory(SRARoutePredicateFactory.PATH).args("/logout").build());
postLogout.getFilters().add(new SRARouteFilter.Builder().
factory(SRARouteFilterFactory.SET_STATUS).args("204").build());
postLogout.getFilters().add(new SRARouteFilter.Builder().
factory(SRARouteFilterFactory.SET_RESPONSE_HEADER).args(LOGGED_OUT_HEADER + ", true").build());
postLogout.setOrder(-10);
response = sraRouteService.create(postLogout);
if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
fail("Could not create logout SRA Route");
}
}
protected static void doStartSRA(final String activeProfile)
throws IOException, InterruptedException, TimeoutException {
Properties props = new Properties();
try (InputStream propStream = AbstractSRAITCase.class.getResourceAsStream("/test.properties")) {
props.load(propStream);
} catch (Exception e) {
fail("Could not load /test.properties", e);
}
String javaHome = props.getProperty("java.home");
assertNotNull(javaHome);
String sraJar = props.getProperty("sra.jar");
assertNotNull(sraJar);
String keymasterApiJar = props.getProperty("keymaster-api.jar");
assertNotNull(keymasterApiJar);
String keymasterClientJar = props.getProperty("keymaster-client.jar");
assertNotNull(keymasterClientJar);
String targetTestClasses = props.getProperty("targetTestClasses");
assertNotNull(targetTestClasses);
ProcessBuilder processBuilder = new ProcessBuilder(
javaHome + "/bin/java",
"-Dreactor.netty.http.server.accessLogEnabled=true",
"-jar",
"-Xdebug",
"-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8002",
sraJar);
processBuilder.inheritIO();
Map<String, String> environment = processBuilder.environment();
environment.put("LOADER_PATH", targetTestClasses + "," + keymasterApiJar + "," + keymasterClientJar);
environment.put("SPRING_PROFILES_ACTIVE", activeProfile);
SRA = processBuilder.start();
await().atMost(120, TimeUnit.SECONDS).pollInterval(3, TimeUnit.SECONDS).until(() -> {
boolean connected = false;
try (Socket socket = new Socket()) {
socket.connect(new InetSocketAddress("0.0.0.0", PORT));
connected = socket.isConnected();
} catch (ConnectException e) {
// ignore
}
return connected;
});
assertDoesNotThrow(() -> WebClient.create(SRA_ADDRESS).get().getStatus());
sraRouteService.pushToSRA();
}
@AfterAll
public static void stopSRA() throws InterruptedException {
if (SRA != null) {
SRA.destroy();
SRA.waitFor();
}
}
protected static AuthPolicyTO getAuthPolicy() {
String authModule = "DefaultSyncopeAuthModule";
String description = "SRA auth policy";
return policyService.list(PolicyType.AUTH).stream().
map(AuthPolicyTO.class::cast).
filter(policy -> description.equals(policy.getName())
&& policy.getConf() instanceof DefaultAuthPolicyConf
&& ((DefaultAuthPolicyConf) policy.getConf()).getAuthModules().contains(authModule)).
findFirst().
orElseGet(() -> {
DefaultAuthPolicyConf policyConf = new DefaultAuthPolicyConf();
policyConf.getAuthModules().add(authModule);
AuthPolicyTO policy = new AuthPolicyTO();
policy.setName(description);
policy.setConf(policyConf);
Response response = policyService.create(PolicyType.AUTH, policy);
if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
fail("Could not create Syncope Auth Policy");
}
return policyService.read(PolicyType.AUTH, response.getHeaderString(RESTHeaders.RESOURCE_KEY));
});
}
protected static ObjectNode checkGetResponse(
final CloseableHttpResponse response, final String originalRequestURI) throws IOException {
assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
assertEquals(MediaType.APPLICATION_JSON, response.getFirstHeader(HttpHeaders.CONTENT_TYPE).getValue());
JsonNode json = OBJECT_MAPPER.readTree(EntityUtils.toString(response.getEntity()));
ObjectNode args = (ObjectNode) json.get("args");
assertEquals("value1", args.get("key1").asText());
ArrayNode key2 = (ArrayNode) args.get("key2");
assertEquals("value2", key2.get(0).asText());
assertEquals("value3", key2.get(1).asText());
assertEquals("an url encoded value: this!", args.get("key3").asText());
ObjectNode headers = (ObjectNode) json.get("headers");
assertEquals(MediaType.TEXT_HTML, headers.get(HttpHeaders.ACCEPT).asText());
assertEquals(EN_LANGUAGE, headers.get(HttpHeaders.ACCEPT_LANGUAGE).asText());
assertEquals("localhost:" + PORT, headers.get("X-Forwarded-Host").asText());
assertEquals(
StringUtils.substringBefore(originalRequestURI, "?"),
StringUtils.substringBefore(json.get("url").asText(), "?"));
return headers;
}
protected void checkLogout(final CloseableHttpResponse response) throws IOException {
assertEquals(HttpStatus.SC_NO_CONTENT, response.getStatusLine().getStatusCode());
assertEquals("true", response.getFirstHeader(LOGGED_OUT_HEADER).getValue());
}
}