Implemented as a Groovy script, meaning there is no top-level class per se. Could probably be more concise.
//imports removed for brevity // Housekeeping - see what the User wants // Groovy note: not declaring a var puts it into "the binding", which makes it globally accessible // * this is only valid for Groovy scripts // * declaring a type (or def) of a var automatically scopes it locally config = new Config() parseInput(args) baseUrl = "https://" + config.host + ":" + config.port + "/myapp/" debug "\tBase URL: " + baseUrl println "Loading keys..." // Create client keystore - this needs to contain: // Client's certificate (i.e., Subject CN == clientname) // Client's private key // Needs to be a JKS keystore clientKeys = createKeystore(config.clientKeyFile, config.clientKeyPass) // Truststore for server verification - this needs to contain: // Server certificate: Subject CN == hostname // Server private key // Needs to be a JKS keystore serverTrust = createKeystore(config.serverKeyFile, config.serverKeyPass) debug "\tclient key: " + clientKeys debug "\tserver key: " + serverTrust try { // ** Create Connection ** socketFactory = new SSLSocketFactory( SSLSocketFactory.TLS, clientKeys, config.clientKeyPass, serverTrust, null, new TrustSelfSignedStrategy(), // not a good choice for production SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); // not a good choice for production // Connect socket to enable client PKI authentication HttpParams params = new BasicHttpParams(); params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 1000); SSLSocket socket = (SSLSocket) socketFactory.createSocket(params); socket.setEnabledCipherSuites("SSL_RSA_WITH_RC4_128_MD5"); InetSocketAddress address = new InetSocketAddress(config.host, Integer.parseInt(config.port)); socketFactory.connectSocket(socket, address, null, params); sch = new Scheme("https", new Integer(config.port), socketFactory); httpclient = new DefaultHttpClient(); httpclient.getConnectionManager().getSchemeRegistry().register(sch); // Create a local instance of cookie store cookieStore = new BasicCookieStore(); // Create local HTTP context localContext = new BasicHttpContext(); // Bind custom cookie store to the local context localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore); // ****** Example usage ******* // This is the map-based impl - produces same output as the object-based // .... put your own data in here def data = [ "_method" : "POST" , "displayName" : row[DISPLAY_NAME], "imageUrlSmall" : row[IMAGE_URL_SMALL] , "imageUrlLarge" : row[IMAGE_URL_LARGE], "width" : row[WIDTH], "height" : row[HEIGHT] ] String dataStr = JSONSerializer.toJSON(data) try { int retries = 5 while (!created && retries-- > 0) { rsp = post (baseUrl + "widget", ["data":dataStr]) matcher = rsp =~ /\"success\":([\w]+)/ if (matcher[0]) { val = matcher[0][1] debug "\tCREATE RESPONSE: ${val}" created = Boolean.parseBoolean(val) } // This is just for logging if (!created) { println "ERROR: Creation failed with response: ${rsp}" // Detect message failure and retry // Detect failure by GUID invalid format matcher = rsp =~ /Property [name].*does not match the required pattern/ if (matcher[0]) { debug "\tERROR RECEIVED:: name is not correct format: ${guid}" } } } // end while } catch (Exception e) { debug "Error creating listing: " + e e.printStackTrace() guid = null } } /** * Return a Keystore from a given filename and password */ def KeyStore createKeystore (filename, password) { debug "Default KeyAlgo: " + KeyManagerFactory.getDefaultAlgorithm() debug "Default KeyStore: " + KeyStore.getDefaultType() // jks // Pull off file extension keyType = filename[-3..-1] debug "Requested KeyType: " + keyType // Client keystore, for client authentication KeyStore keys switch (keyType) { case "p12": keys = KeyStore.getInstance("pkcs12"); break default: keys = KeyStore.getInstance(KeyStore.getDefaultType()); } FileInputStream instream = new FileInputStream(new File(filename)); try { keys.load(instream, password.toCharArray()); } finally { try { instream.close(); } catch (Exception ignore) {} } return keys } def post(url, paramMap) { HttpPost httpPost = new HttpPost(url) String result // Add specific params Listnvps = new ArrayList (); // These params always present nvps.add(new BasicNameValuePair("sample1", "3.6.0-GA")) nvps.add(new BasicNameValuePair("dojo.preventCache", "1302893700594")) paramMap.each() { key, value -> debug "${key} ==> ${value}" // Expect the caller to JSON-ize each param, as required if (value instanceof List) { // Add value multiple times with same key value.each { nvps.add(new BasicNameValuePair(key, it.toString())) } } else { nvps.add(new BasicNameValuePair(key, value)) } } httpPost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8)) // Debug debug(dump(httpPost)) debug "Posting request: " + httpPost HttpResponse response = httpclient.execute(httpPost, localContext); //String response = httpclient.execute(httpPost, new BasicResponseHandler()); debug "#### RESPONSE TYPE: " + response.class.name HttpEntity entity = response.getEntity(); debug "#### RESPONSE BODY RECEIVED: " + entity.toString() // ** Dump results ** debug "\t" + response.getStatusLine() StringBuilder sb = new StringBuilder(255) if (entity != null) { InputStream ris = entity.getContent() OutputStream os = new ByteArrayOutputStream(BUFFER_SIZE) byte[] buffer = new byte[BUFFER_SIZE]; try { while ((l = ris.read(buffer)) != -1) { os.write(buffer, 0, l) sb.append(os.toString()) os.reset() } } finally { ris.close() } debug "\tEntity contentLength: " + sb.length() result = sb?.toString() debug "\t-------------------------------------" List cookies = cookieStore.getCookies(); for (int i = 0; i < cookies.size(); i++) { println("\tCookie: " + cookies.get(i)); } debug "\t-------------------------------------" } else { println "Error connecting...check connection details" //!! EXIT HERE return } debug "-------------------------------------" if (result && result.size() > 256) { debug "RESPONSE: " + result.substring(0, 256) } else { debug "RESPONSE: " + result } debug "-------------------------------------" return result } def debug(stmt) { if (config.verbose) { println stmt } } def dump(HttpPost post) { StringBuilder sb = new StringBuilder(128) sb.append("\n\t------------------------------") sb.append("\n\tRequestURL: ").append(post.getURI()) sb.append("\n\tType: ").append(post.getMethod()) sb.append("\n\tParams: ").append(post.getParams()) org.apache.http.params.BasicHttpParams sb.append("\n\t------------------------------") return sb.toString() } class Config { String host = "localhost" String port = "8443" boolean verbose = false String inputFile String clientKeyFile String clientKeyPass String serverKeyFile String serverKeyPass } def parseInput(args) { if (!args || args.length < 1) { usage() } for(int i=0; i < args.length; i++) { it = args[i] println "Processing arg: " + it switch (it) { case "-v": debug "Verbose output enabled " config.verbose = true break case "-h": it = args[++i] debug "Setting Host/Port from: " + it // Parse out host and port def serverAddr = it.split(":") try { if (serverAddr.length > 0 && serverAddr[0] != null) { config.host = serverAddr[0] } if (serverAddr.length > 1 && serverAddr[1] != null) { config.port = serverAddr[1] } } catch(Exception e) { usage() } break case "-clientKeys": it = args[++i] debug "Setting client keyfile to: " + it config.clientKeyFile = it break case "-clientKeyPass": it = args[++i] debug "Setting client keyfile pwd to: " + it config.clientKeyPass = it break case "-serverKeys": it = args[++i] debug "Setting server keyfile to: " + it config.serverKeyFile = it break case "-serverKeyPass": it = args[++i] debug "Setting server keyfile pwd to: " + it config.serverKeyPass = it break default: debug "Setting inputFile to: " + it config.inputFile = it; } } }