Vinay Vishal | 5717147 | 2018-09-18 20:22:00 +0530 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. |
| 3 | * |
| 4 | * This program and the accompanying materials are made available under the |
| 5 | * terms of the Eclipse Public License v. 2.0, which is available at |
| 6 | * http://www.eclipse.org/legal/epl-2.0. |
| 7 | * |
| 8 | * This Source Code may also be made available under the following Secondary |
| 9 | * Licenses when the conditions for such availability set forth in the |
| 10 | * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, |
| 11 | * version 2 with the GNU Classpath Exception, which is available at |
| 12 | * https://www.gnu.org/software/classpath/license.html. |
| 13 | * |
| 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 |
| 15 | */ |
| 16 | |
| 17 | import java.io.*; |
| 18 | import java.net.*; |
| 19 | import java.util.HashMap; |
| 20 | import java.util.Map; |
| 21 | import com.sun.ejte.ccl.reporter.*; |
| 22 | import com.sun.appserv.test.BaseDevTest; |
| 23 | |
| 24 | /** |
| 25 | * Unit test for HA SSO Failover. |
| 26 | * |
| 27 | */ |
| 28 | public class WebTest extends BaseDevTest { |
| 29 | |
| 30 | static class SessionData { |
| 31 | private String jsessionId; |
| 32 | private String jsessionIdVersion; |
| 33 | private String jreplica; |
| 34 | } |
| 35 | |
| 36 | private static final String TEST_NAME = "ha-sso-failover"; |
| 37 | private static final String JSESSIONID = "JSESSIONID"; |
| 38 | private static final String JSESSIONIDVERSION = "JSESSIONIDVERSION"; |
| 39 | private static final String JREPLICA = "JREPLICA"; |
| 40 | private static final String JSESSIONIDSSO = "JSESSIONIDSSO"; |
| 41 | private static final String JSESSIONIDSSOVERSION = "JSESSIONIDSSOVERSION"; |
| 42 | |
| 43 | private static SimpleReporterAdapter stat |
| 44 | = new SimpleReporterAdapter("appserv-tests"); |
| 45 | |
| 46 | private String host; |
| 47 | private int port1; |
| 48 | private int port2; |
| 49 | private String instancename1; |
| 50 | private String contextRootPrefix; |
| 51 | private String user; |
| 52 | private String password; |
| 53 | private Map<String, SessionData> app2Sd = new HashMap<String, SessionData>(); |
| 54 | private String ssoId; |
| 55 | private String ssoIdVersion; |
| 56 | private long ssoIdVersionNumber = -1L; |
| 57 | |
| 58 | public WebTest(String[] args) { |
| 59 | host = args[0]; |
| 60 | port1 = Integer.parseInt(args[1]); |
| 61 | port2 = Integer.parseInt(args[2]); |
| 62 | instancename1 = args[3]; |
| 63 | contextRootPrefix = "/" + args[4]; |
| 64 | user = args[5]; |
| 65 | password = args[6]; |
| 66 | } |
David Matějček | f4dc06a | 2021-05-17 12:10:57 +0200 | [diff] [blame^] | 67 | |
Vinay Vishal | 5717147 | 2018-09-18 20:22:00 +0530 | [diff] [blame] | 68 | public static void main(String[] args) { |
| 69 | |
| 70 | stat.addDescription("Unit test for GlassFish Issue 1933"); |
| 71 | WebTest webTest = new WebTest(args); |
| 72 | |
| 73 | try { |
| 74 | webTest.run(); |
| 75 | stat.addStatus(TEST_NAME, stat.PASS); |
| 76 | } catch( Exception ex) { |
| 77 | ex.printStackTrace(); |
| 78 | stat.addStatus(TEST_NAME, stat.FAIL); |
| 79 | } |
| 80 | |
| 81 | stat.printSummary(); |
| 82 | } |
| 83 | |
| 84 | public String getTestName() { |
| 85 | return TEST_NAME; |
| 86 | } |
| 87 | |
| 88 | public String getTestDescription() { |
| 89 | return TEST_NAME; |
| 90 | } |
| 91 | |
| 92 | public void run() throws Exception { |
| 93 | /* |
| 94 | * Access login.jsp |
| 95 | */ |
| 96 | app2Sd.put("A", new SessionData()); |
| 97 | app2Sd.put("B", new SessionData()); |
| 98 | Socket sock = null; |
| 99 | OutputStream os = null; |
| 100 | InputStream is = null; |
| 101 | BufferedReader br = null; |
| 102 | try { |
| 103 | sock = new Socket(host, new Integer(port1).intValue()); |
| 104 | os = sock.getOutputStream(); |
| 105 | String postData = "j_username=" + user |
| 106 | + "&j_password=" + password; |
| 107 | String post = "POST " + contextRootPrefix + "-a/j_security_check" |
| 108 | + " HTTP/1.0\n" |
| 109 | + "Content-Type: application/x-www-form-urlencoded\n" |
| 110 | + "Content-length: " + postData.length() + "\n\n" |
| 111 | + postData; |
| 112 | System.out.println(post); |
| 113 | os.write(post.getBytes()); |
| 114 | os.flush(); |
| 115 | |
| 116 | is = sock.getInputStream(); |
| 117 | br = new BufferedReader(new InputStreamReader(is)); |
| 118 | |
| 119 | String line = null; |
| 120 | String location = null; |
| 121 | String cookie = null; |
| 122 | while ((line = br.readLine()) != null) { |
| 123 | System.out.println(line); |
| 124 | if (line.startsWith("Location:")) { |
| 125 | location = line; |
| 126 | } else if (line.startsWith("Set-Cookie:") |
| 127 | || line.startsWith("Set-cookie:")) { |
| 128 | cookie = line; |
| 129 | parseCookies(line, app2Sd.get("A")); |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | if (ssoIdVersion != null) { |
| 134 | long ssoVer = Long.valueOf(ssoIdVersion.substring( |
| 135 | JSESSIONIDSSOVERSION.length() + 1)); |
| 136 | if (ssoIdVersionNumber == -1 || |
| 137 | ssoIdVersionNumber + 1 == ssoVer) { |
| 138 | ssoIdVersionNumber = ssoVer; |
| 139 | } else { |
| 140 | throw new Exception("Version number does not match: " + |
| 141 | ssoIdVersionNumber + ", " + ssoVer); |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | if (cookie == null) { |
| 146 | throw new Exception("Missing Set-Cookie response header"); |
| 147 | } else if (location == null) { |
| 148 | throw new Exception("Missing Location response header"); |
| 149 | } |
| 150 | |
| 151 | String redirect = location.substring("Location:".length()).trim(); |
| 152 | // follow the redirect |
| 153 | int cA1 = go(port1, new URL(redirect).getPath(), "A"); |
| 154 | int cB1 = go(port1, contextRootPrefix + "-b/index.jsp", "B"); |
David Matějček | f4dc06a | 2021-05-17 12:10:57 +0200 | [diff] [blame^] | 155 | |
Vinay Vishal | 5717147 | 2018-09-18 20:22:00 +0530 | [diff] [blame] | 156 | // stop inst1 |
| 157 | asadmin("stop-local-instance", instancename1); |
| 158 | |
| 159 | int cB2 = go(port2, contextRootPrefix + "-b/index.jsp", "B"); |
| 160 | int cA2 = go(port2, contextRootPrefix + "-a/index.jsp", "A"); |
| 161 | |
| 162 | if ((cA2 - cA1 != 1) && (cB2 - cB1 != 1)) { |
| 163 | throw new Exception("count does not match: " + cA1 + ", " + cB1 + ", " + cA2 + ", " + cB2); |
| 164 | } |
| 165 | } finally { |
| 166 | close(sock); |
| 167 | close(os); |
| 168 | close(br); |
| 169 | close(is); |
| 170 | } |
| 171 | } |
| 172 | |
| 173 | /* |
| 174 | * Access http://<host>:<port>/web-ha-sso-failover-<aName> . |
| 175 | * @return the associated count value |
| 176 | */ |
| 177 | private int go(int port, String path, String aName) |
| 178 | throws Exception { |
| 179 | |
| 180 | int count = -1; |
| 181 | String countPrefix = aName + ":" + user + ":"; |
| 182 | Socket sock = null; |
| 183 | OutputStream os = null; |
| 184 | InputStream is = null; |
| 185 | BufferedReader br = null; |
| 186 | try { |
| 187 | sock = new Socket(host, port); |
| 188 | os = sock.getOutputStream(); |
| 189 | String get = "GET " + path + " HTTP/1.0\n"; |
| 190 | System.out.println(get); |
| 191 | os.write(get.getBytes()); |
| 192 | StringBuilder sb = new StringBuilder("Cookie: "); |
| 193 | sb.append(ssoId); |
| 194 | if (ssoIdVersion != null) { |
| 195 | sb.append(";" + ssoIdVersion); |
| 196 | } |
| 197 | SessionData data = app2Sd.get(aName); |
| 198 | if (data.jsessionId != null) { |
| 199 | sb.append(";" + data.jsessionId); |
| 200 | } |
| 201 | if (data.jsessionIdVersion != null) { |
| 202 | sb.append(";" + data.jsessionIdVersion); |
| 203 | } |
| 204 | if (data.jreplica != null) { |
| 205 | sb.append(";" + data.jreplica); |
| 206 | } |
| 207 | os.write(sb.toString().getBytes()); |
| 208 | System.out.println(sb); |
| 209 | |
| 210 | os.write("\n\n".getBytes()); |
David Matějček | f4dc06a | 2021-05-17 12:10:57 +0200 | [diff] [blame^] | 211 | |
Vinay Vishal | 5717147 | 2018-09-18 20:22:00 +0530 | [diff] [blame] | 212 | is = sock.getInputStream(); |
| 213 | br = new BufferedReader(new InputStreamReader(is)); |
| 214 | |
| 215 | String line = null; |
| 216 | String cookieHeader = null; |
| 217 | while ((line = br.readLine()) != null) { |
| 218 | System.out.println(line); |
| 219 | if (line.startsWith("Set-Cookie:") || |
| 220 | line.startsWith("Set-cookie:")) { |
| 221 | parseCookies(line, app2Sd.get(aName)); |
| 222 | } |
| 223 | int index = line.indexOf(countPrefix); |
| 224 | if (index >= 0) { |
| 225 | count = Integer.parseInt(line.substring(index + countPrefix.length())); |
| 226 | break; |
| 227 | } |
| 228 | } |
| 229 | } finally { |
| 230 | close(sock); |
| 231 | close(os); |
| 232 | close(br); |
| 233 | close(is); |
David Matějček | f4dc06a | 2021-05-17 12:10:57 +0200 | [diff] [blame^] | 234 | } |
Vinay Vishal | 5717147 | 2018-09-18 20:22:00 +0530 | [diff] [blame] | 235 | |
| 236 | if (count == -1) { |
| 237 | throw new Exception("Failed to access index.jsp"); |
| 238 | } |
| 239 | |
| 240 | System.out.println("Count: " + countPrefix + count); |
| 241 | |
| 242 | return count; |
| 243 | } |
| 244 | |
| 245 | private void parseCookies(String cookie, SessionData data) { |
| 246 | String value = getSessionIdFromCookie(cookie, JSESSIONID); |
| 247 | if (value != null) { |
| 248 | data.jsessionId = value; |
| 249 | } |
| 250 | value = getSessionIdFromCookie(cookie, JSESSIONIDVERSION); |
| 251 | if (value != null) { |
| 252 | data.jsessionIdVersion = value; |
| 253 | } |
| 254 | value = getSessionIdFromCookie(cookie, JREPLICA); |
| 255 | if (value != null) { |
| 256 | data.jreplica = value; |
| 257 | } |
| 258 | value = getSessionIdFromCookie(cookie, JSESSIONIDSSO); |
| 259 | if (value != null) { |
| 260 | ssoId = value; |
| 261 | } |
| 262 | value = getSessionIdFromCookie(cookie, JSESSIONIDSSOVERSION); |
| 263 | if (value != null) { |
| 264 | ssoIdVersion = value; |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | private String getSessionIdFromCookie(String cookie, String field) { |
| 269 | |
| 270 | String ret = null; |
| 271 | |
| 272 | int index = cookie.indexOf(field + "="); |
| 273 | if (index != -1) { |
| 274 | int endIndex = cookie.indexOf(';', index); |
| 275 | if (endIndex != -1) { |
| 276 | ret = cookie.substring(index, endIndex); |
| 277 | } else { |
| 278 | ret = cookie.substring(index); |
| 279 | } |
| 280 | ret = ret.trim(); |
| 281 | } |
| 282 | |
| 283 | return ret; |
| 284 | } |
| 285 | |
| 286 | private void close(Socket sock) { |
| 287 | try { |
| 288 | if (sock != null) { |
| 289 | sock.close(); |
| 290 | } |
| 291 | } catch(IOException ioe) { |
| 292 | // ignore |
| 293 | } |
| 294 | } |
| 295 | |
| 296 | private void close(InputStream is) { |
| 297 | try { |
| 298 | if (is != null) { |
| 299 | is.close(); |
| 300 | } |
| 301 | } catch(IOException ioe) { |
| 302 | // ignore |
| 303 | } |
| 304 | } |
| 305 | |
| 306 | private void close(OutputStream os) { |
| 307 | try { |
| 308 | if (os != null) { |
| 309 | os.close(); |
| 310 | } |
| 311 | } catch(IOException ioe) { |
| 312 | // ignore |
| 313 | } |
| 314 | } |
| 315 | |
| 316 | private void close(Reader reader) { |
| 317 | try { |
| 318 | if (reader != null) { |
| 319 | reader.close(); |
| 320 | } |
| 321 | } catch(IOException ioe) { |
| 322 | // ignore |
| 323 | } |
| 324 | } |
| 325 | } |