1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.fit;
20
21 import static org.awaitility.Awaitility.await;
22 import static org.junit.jupiter.api.Assertions.assertNotNull;
23 import static org.junit.jupiter.api.Assertions.assertTrue;
24
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.Optional;
29 import java.util.concurrent.TimeUnit;
30 import javax.ws.rs.core.HttpHeaders;
31 import javax.ws.rs.core.MediaType;
32 import org.apache.commons.lang3.tuple.Triple;
33 import org.apache.cxf.jaxrs.client.WebClient;
34 import org.apache.http.Consts;
35 import org.apache.http.NameValuePair;
36 import org.apache.http.client.entity.UrlEncodedFormEntity;
37 import org.apache.http.client.methods.CloseableHttpResponse;
38 import org.apache.http.client.methods.HttpPost;
39 import org.apache.http.client.protocol.HttpClientContext;
40 import org.apache.http.impl.client.CloseableHttpClient;
41 import org.apache.http.message.BasicNameValuePair;
42 import org.apache.syncope.client.lib.SyncopeClient;
43 import org.apache.syncope.client.lib.SyncopeClientFactoryBean;
44 import org.apache.syncope.common.rest.api.service.ClientAppService;
45 import org.apache.syncope.common.rest.api.service.OIDCC4UIProviderService;
46 import org.apache.syncope.common.rest.api.service.PolicyService;
47 import org.apache.syncope.common.rest.api.service.SAML2IdPEntityService;
48 import org.apache.syncope.common.rest.api.service.SAML2SP4UIIdPService;
49 import org.apache.syncope.common.rest.api.service.SRARouteService;
50 import org.apache.syncope.common.rest.api.service.UserService;
51 import org.apache.syncope.common.rest.api.service.wa.WAConfigService;
52 import org.apache.syncope.fit.sra.AbstractSRAITCase;
53 import org.apereo.cas.oidc.OidcConstants;
54 import org.jsoup.Connection;
55 import org.jsoup.Jsoup;
56 import org.jsoup.nodes.FormElement;
57 import org.junit.jupiter.api.BeforeAll;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
60
61 public abstract class AbstractITCase {
62
63 protected static final Logger LOG = LoggerFactory.getLogger(AbstractSRAITCase.class);
64
65 protected static final String ADMIN_UNAME = "admin";
66
67 protected static final String ADMIN_PWD = "password";
68
69 private static final String ANONYMOUS_USER = "anonymous";
70
71 private static final String ANONYMOUS_KEY = "anonymousKey";
72
73 protected static final String CORE_ADDRESS = "https://localhost:9443/syncope/rest";
74
75 protected static final String CONSOLE_ADDRESS = "https://localhost:9443/syncope-console/";
76
77 protected static final String ENDUSER_ADDRESS = "https://localhost:9443/syncope-enduser/";
78
79 protected static final String WA_ADDRESS = "https://localhost:9443/syncope-wa";
80
81 protected static final String EN_LANGUAGE = "en-US,en;q=0.5";
82
83 protected static SyncopeClientFactoryBean CLIENT_FACTORY;
84
85 protected static SyncopeClient ADMIN_CLIENT;
86
87 protected static UserService USER_SERVICE;
88
89 protected static PolicyService POLICY_SERVICE;
90
91 protected static ClientAppService CLIENT_APP_SERVICE;
92
93 protected static WAConfigService WA_CONFIG_SERVICE;
94
95 protected static SRARouteService SRA_ROUTE_SERVICE;
96
97 protected static SAML2SP4UIIdPService SAML2SP4UI_IDP_SERVICE;
98
99 protected static OIDCC4UIProviderService OIDCC4UI_PROVIDER_SERVICE;
100
101 @BeforeAll
102 public static void restSetup() {
103 CLIENT_FACTORY = new SyncopeClientFactoryBean().setAddress(CORE_ADDRESS);
104 ADMIN_CLIENT = CLIENT_FACTORY.create(ADMIN_UNAME, ADMIN_PWD);
105
106 USER_SERVICE = ADMIN_CLIENT.getService(UserService.class);
107 POLICY_SERVICE = ADMIN_CLIENT.getService(PolicyService.class);
108 CLIENT_APP_SERVICE = ADMIN_CLIENT.getService(ClientAppService.class);
109 WA_CONFIG_SERVICE = ADMIN_CLIENT.getService(WAConfigService.class);
110 SRA_ROUTE_SERVICE = ADMIN_CLIENT.getService(SRARouteService.class);
111 SAML2SP4UI_IDP_SERVICE = ADMIN_CLIENT.getService(SAML2SP4UIIdPService.class);
112 OIDCC4UI_PROVIDER_SERVICE = ADMIN_CLIENT.getService(OIDCC4UIProviderService.class);
113 }
114
115 @BeforeAll
116 public static void waitForWARefresh() {
117 SAML2IdPEntityService samlIdPEntityService = ADMIN_CLIENT.getService(SAML2IdPEntityService.class);
118
119 await().atMost(120, TimeUnit.SECONDS).pollInterval(20, TimeUnit.SECONDS).until(() -> {
120 boolean refreshed = false;
121 try {
122 String metadata = WebClient.create(
123 WA_ADDRESS + "/idp/metadata").get().readEntity(String.class);
124 if (metadata.contains("localhost:8080")) {
125 throw new IllegalStateException();
126 }
127 metadata = WebClient.create(
128 WA_ADDRESS + "/oidc/" + OidcConstants.WELL_KNOWN_OPENID_CONFIGURATION_URL).
129 get().readEntity(String.class);
130 if (metadata.contains("localhost:8080")) {
131 throw new IllegalStateException();
132 }
133 metadata = WebClient.create(
134 WA_ADDRESS + "/actuator/registeredServices", ANONYMOUS_USER, ANONYMOUS_KEY, null).
135 get().readEntity(String.class);
136 if (metadata.contains("localhost:8080/syncope-wa")) {
137 throw new IllegalStateException();
138 }
139 metadata = WebClient.create(
140 WA_ADDRESS + "/actuator/authenticationHandlers", ANONYMOUS_USER, ANONYMOUS_KEY, null).
141 get().readEntity(String.class);
142 if (!metadata.contains("DefaultLDAPAuthModule")) {
143 throw new IllegalStateException();
144 }
145
146 samlIdPEntityService.get(SAML2IdPEntityService.DEFAULT_OWNER);
147 refreshed = true;
148 } catch (IllegalStateException e) {
149 WebClient.create(
150 WA_ADDRESS + "/actuator/refresh", ANONYMOUS_USER, ANONYMOUS_KEY, null).
151 post(null);
152 } catch (Exception e) {
153
154 }
155 return refreshed;
156 });
157 }
158
159 protected static Triple<String, String, String> parseSAMLRequestForm(final String body) {
160 FormElement form = (FormElement) Jsoup.parse(body).body().getElementsByTag("form").first();
161 assertNotNull(form);
162
163 String action = form.attr("action");
164 assertNotNull(action);
165
166 Optional<String> relayState = form.formData().stream().
167 filter(keyval -> "RelayState".equals(keyval.key())).
168 map(Connection.KeyVal::value).
169 findFirst();
170 assertTrue(relayState.isPresent());
171
172 Optional<String> samlRequest = form.formData().stream().
173 filter(keyval -> "SAMLRequest".equals(keyval.key())).
174 map(Connection.KeyVal::value).
175 findFirst();
176 assertTrue(samlRequest.isPresent());
177
178 return Triple.of(action, relayState.get(), samlRequest.get());
179 }
180
181 protected static Triple<String, String, String> parseSAMLResponseForm(final String body) {
182 FormElement form = (FormElement) Jsoup.parse(body).body().getElementsByTag("form").first();
183 assertNotNull(form);
184
185 String action = form.attr("action");
186 assertNotNull(action);
187
188 Optional<String> relayState = form.formData().stream().
189 filter(keyval -> "RelayState".equals(keyval.key())).
190 map(Connection.KeyVal::value).
191 findFirst();
192 assertTrue(relayState.isPresent());
193
194 Optional<String> samlResponse = form.formData().stream().
195 filter(keyval -> "SAMLResponse".equals(keyval.key())).
196 map(Connection.KeyVal::value).
197 findFirst();
198 assertTrue(samlResponse.isPresent());
199
200 return Triple.of(action, relayState.get(), samlResponse.get());
201 }
202
203 protected static String extractWAExecution(final String body) {
204 FormElement form = (FormElement) Jsoup.parse(body).body().getElementsByTag("form").first();
205 assertNotNull(form);
206
207 Optional<String> execution = form.formData().stream().
208 filter(keyval -> "execution".equals(keyval.key())).
209 map(Connection.KeyVal::value).
210 findFirst();
211 assertTrue(execution.isPresent());
212
213 return execution.get();
214 }
215
216 protected static CloseableHttpResponse authenticateToWA(
217 final String username,
218 final String password,
219 final String body,
220 final CloseableHttpClient httpclient,
221 final HttpClientContext context)
222 throws IOException {
223
224 List<NameValuePair> form = new ArrayList<>();
225 form.add(new BasicNameValuePair("_eventId", "submit"));
226 form.add(new BasicNameValuePair("execution", extractWAExecution(body)));
227 form.add(new BasicNameValuePair("username", username));
228 form.add(new BasicNameValuePair("password", password));
229 form.add(new BasicNameValuePair("geolocation", ""));
230
231 HttpPost post = new HttpPost(WA_ADDRESS + "/login");
232 post.addHeader(HttpHeaders.ACCEPT, MediaType.TEXT_HTML);
233 post.addHeader(HttpHeaders.ACCEPT_LANGUAGE, EN_LANGUAGE);
234 post.setEntity(new UrlEncodedFormEntity(form, Consts.UTF_8));
235 return httpclient.execute(post, context);
236 }
237 }