package org.joget.designer.jped; import java.awt.Component; import java.awt.GridLayout; import java.awt.Window; import java.awt.event.HierarchyEvent; import java.awt.event.HierarchyListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URLEncoder; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import javax.net.ssl.SSLException; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.JTextField; import javax.swing.SwingUtilities; import org.apache.http.HttpEntity; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.StatusLine; import org.apache.http.auth.AuthenticationException; import org.apache.http.client.CookieStore; import org.apache.http.client.HttpResponseException; import org.apache.http.client.RedirectStrategy; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.TrustSelfSignedStrategy; import org.apache.http.cookie.Cookie; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.entity.mime.content.FileBody; import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.cookie.BasicClientCookie; import org.apache.http.message.BasicNameValuePair; import org.apache.http.protocol.HttpContext; import org.apache.http.ssl.SSLContextBuilder; import org.enhydra.jawe.ResourceManager; import org.joget.designer.Designer; /** * Utility methods for making HTTP requests. */ public class HttpUtil { public static boolean SSL_TRUSTED = false; /** * Make a HTTP POST request to a URL, passing in a JSESSIONID cookie, * with support for SSL (including prompting a warning for self-signed certs). * If the JSESSIONID is invalid, then a password dialog appears. * @param cookieStore * @param url * @param port * @param sessionId * @param cookieDomain * @param cookiePath * @param username * @param password * @param trustAllSsl * @param failOnError * @param filename * @param file * @return * @throws IOException * @throws NoSuchAlgorithmException * @throws KeyManagementException * @throws KeyStoreException * @throws UnrecoverableKeyException * @throws AuthenticationException */ public static String httpPost(CookieStore cookieStore, String url, int port, String sessionId, String cookieDomain, String cookiePath, String username, String password, boolean trustAllSsl, boolean failOnError, String filename, File file) throws IOException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException, AuthenticationException { String contents = null; HttpClientBuilder httpClientBuilder = HttpClients.custom(); // Set no redirect httpClientBuilder.setRedirectStrategy(new RedirectStrategy() { @Override public boolean isRedirected(HttpRequest httpRequest, HttpResponse httpResponse, HttpContext httpContext) { return false; } @Override public HttpUriRequest getRedirect(HttpRequest httpRequest, HttpResponse httpResponse, HttpContext httpContext) { return null; } }); // set csrf token in URL if (url.contains("?" + Designer.TOKEN_NAME)) { url = url.substring(0, url.indexOf("?" + Designer.TOKEN_NAME)); } url += "?" + Designer.TOKEN_NAME + "=" + URLEncoder.encode(Designer.TOKEN_VALUE, "UTF-8"); // Prepare a request object HttpPost httpRequest = new HttpPost(url); if (file != null) { HttpEntity reqEntity = MultipartEntityBuilder.create().addPart("packageXpdl", new FileBody(file)).build(); httpRequest.setEntity(reqEntity); } else { if (username != null && password != null) { List<NameValuePair> formparams = new ArrayList<NameValuePair>(); formparams.add(new BasicNameValuePair("j_username", username)); formparams.add(new BasicNameValuePair("j_password", password)); formparams.add(new BasicNameValuePair("username", username)); formparams.add(new BasicNameValuePair("password", password)); UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams, "UTF-8"); httpRequest.setEntity(entity); } } // set referer header String referer = "http://" + Designer.DOMAIN; httpRequest.addHeader("Referer", referer); // Set session cookie if (cookieStore == null) { cookieStore = new BasicCookieStore(); } if (sessionId != null) { BasicClientCookie cookie = new BasicClientCookie("JSESSIONID", sessionId); cookie.setDomain(cookieDomain); cookie.setPath(cookiePath); cookieStore.addCookie(cookie); } httpClientBuilder.setDefaultCookieStore(cookieStore); // Prepare SSL trust SSLContextBuilder builder = new SSLContextBuilder(); builder.loadTrustMaterial(null, new TrustSelfSignedStrategy()); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(), NoopHostnameVerifier.INSTANCE); if (SSL_TRUSTED || trustAllSsl) { httpClientBuilder.setSSLSocketFactory(sslsf); } // Execute the request CloseableHttpClient httpClient = httpClientBuilder.build(); try { HttpResponse response = null; try { response = httpClient.execute(httpRequest); } catch (SSLException se) { int result = JOptionPane.showConfirmDialog(null, ResourceManager.getLanguageDependentString("InvalidSSLPrompt"), ResourceManager.getLanguageDependentString("InvalidSSLTitle"), JOptionPane.YES_NO_OPTION); if (result == JOptionPane.YES_OPTION) { httpClientBuilder.setSSLSocketFactory(sslsf); httpClient = httpClientBuilder.build(); response = httpClient.execute(httpRequest); SSL_TRUSTED = true; } } // Examine the response status if (response == null) { throw new HttpResponseException(403, ResourceManager.getLanguageDependentString("InvalidSSLMessage")); } StatusLine status = response.getStatusLine(); if (status == null || status.getStatusCode() == 302 || status.getStatusCode() == 401 || status.getStatusCode() == 500) { if (failOnError) { throw new AuthenticationException(ResourceManager.getLanguageDependentString("AuthenticationFailed")); } // Request is unauthenticated, attempt to authenticate String credentials = password; if (credentials == null) { // prompt for username and password JTextField uField = new JTextField(15); uField.setText(username); JPasswordField pField = new JPasswordField(15); pField.addHierarchyListener(new HierarchyListener() { public void hierarchyChanged(HierarchyEvent e) { final Component c = e.getComponent(); if (c.isShowing() && (e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0) { Window toplevel = SwingUtilities.getWindowAncestor(c); toplevel.addWindowFocusListener(new WindowAdapter() { @Override public void windowGainedFocus(WindowEvent e) { c.requestFocus(); } }); } } }); JPanel pPanel = new JPanel(new GridLayout(2,2)); pPanel.add(new JLabel(ResourceManager.getLanguageDependentString("UsernameKey"))); pPanel.add(uField); pPanel.add(new JLabel(ResourceManager.getLanguageDependentString("PasswordKey"))); pPanel.add(pField); int okCxl = JOptionPane.showConfirmDialog(null, pPanel, ResourceManager.getLanguageDependentString("SessionTimedOut"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); if (okCxl == JOptionPane.OK_OPTION) { username = uField.getText(); credentials = new String(pField.getPassword()); Designer.USERNAME = username; } else if (okCxl == JOptionPane.CANCEL_OPTION) { return null; } } try { // login and store session cookie String loginUrl = Designer.URLPATH + "/web/json/directory/user/sso"; String ssoResponse = HttpUtil.httpPost(cookieStore, loginUrl, port, null, cookieDomain, cookiePath, username, credentials, true, true, null, null); String isAdminStr = "isAdmin"; if (!ssoResponse.contains(isAdminStr)) { throw new AuthenticationException(); } List<Cookie> cookies = cookieStore.getCookies(); for (Cookie ck: cookies) { if ("JSESSIONID".equalsIgnoreCase(ck.getName())) { sessionId = ck.getValue(); Designer.SESSION = sessionId; } } // set new csrf token String tokenAttr = "\"token\":\""; if (ssoResponse.contains(tokenAttr)) { String csrfToken = ssoResponse.substring(ssoResponse.indexOf(tokenAttr) + tokenAttr.length(), ssoResponse.length()-2); StringTokenizer st = new StringTokenizer(csrfToken, "="); if (st.countTokens() == 2) { Designer.TOKEN_NAME = st.nextToken(); Designer.TOKEN_VALUE = st.nextToken(); } } // repeat request with session cookie contents = HttpUtil.httpPost(cookieStore, url, port, sessionId, cookieDomain, cookiePath, null, null, true, true, filename, file); // return contents return contents; } catch(AuthenticationException ate) { JOptionPane.showMessageDialog(null, ResourceManager.getLanguageDependentString("InvalidLogin")); // repeat request return HttpUtil.httpPost(null, url, port, sessionId, cookieDomain, cookiePath, username, null, false, false, filename, file); } catch(HttpResponseException hre) { throw new AuthenticationException(ResourceManager.getLanguageDependentString("InvalidLogin")); } } // Get hold of the response entity HttpEntity entity = response.getEntity(); // If the response does not enclose an entity, there is no need // to worry about connection release if (entity != null) { InputStream instream = null; try { instream = entity.getContent(); contents = ""; BufferedReader reader = new BufferedReader(new InputStreamReader(instream, "UTF-8")); String line = reader.readLine(); while (line != null) { contents += line; line = reader.readLine(); } } catch (IOException ex) { // In case of an IOException the connection will be released // back to the connection manager automatically throw ex; } catch (RuntimeException ex) { // In case of an unexpected exception you may want to abort // the HTTP request in order to shut down the underlying // connection and release it back to the connection manager. httpRequest.abort(); throw ex; } finally { // Closing the input stream will trigger connection release if (instream != null) { instream.close(); } } } } finally { // When HttpClient instance is no longer needed, // shut down the connection manager to ensure // immediate deallocation of all system resources httpClient.close(); } return contents; } }