I have a simple http service with JSON payload I want to test with a Java test harness.
Initially I set up a client using Basic Auth which works fine; server certificate is in the trustStore and I'm supplying username/password in the code. I send the request, I get the correct response.
public static void main(String[] args) {
// TODO Auto-generated method stub
String xxxURL = new String("https://www.xxx.yyy/zzz/AdminServlet?data=");
String username = new String("username");
String password = new String("password");
String authString = new String (username+":"+password);
String apiList = new String("{\"apiVersion\":\"1.4\",\"method\":\"api.list\",\"params\":{}}"); // Create JSON string. A bit ugly
try
{
System.setProperty("javax.net.ssl.trustStore","C:\\workspace\\http_client_test\\security\\cacerts");
String jsonStr = apiList;
URL url = new URL(xxxURL + URLEncoder.encode(jsonStr, "UTF-8") );
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection(); // create connection object
String encoded = Base64.encodeBase64String(authString.getBytes());
httpConn.setRequestProperty("Authorization", "Basic "+encoded);
httpConn.setRequestMethod("GET");
httpConn.connect(); // open connection
BufferedReader in = new BufferedReader(new InputStreamReader(httpConn.getInputStream()));
String temp = null;
StringBuilder sb = new StringBuilder();
while((temp = in.readLine()) != null)
{
sb.append(temp).append(" ");
}
String result = sb.toString();
System.out.println("result = " + result);
}
catch(Exception e)
{
e.printStackTrace();
}
}
I want to do the same test using mutual authentication. I have set up the keystore and truststore on both server and client, and imported the necessary certificates on each.
My problem is I cannot find out how to tell the HttpURLConnection that I want mutual certificate authentication.
I tried :
public class Test3 {
public static void main(String[] args) {
// TODO Auto-generated method stub
String xxxURL = new String("https://www.xxx.yyy/zzz/AdminServlet?data=");
String apiList = new String("{\"apiVersion\":\"1.4\",\"method\":\"api.list\",\"params\":{}}"); // Create JSON string. A bit ugly
try
{
System.setProperty("javax.net.ssl.trustStore","C:\\workspace\\http_client_test\\security\\cacerts");
System.setProperty("javax.net.ssl.trustStorePassword","changeit");
System.setProperty("javax.net.ssl.keyStore","C:\\workspace\\http_client_test\\security\\keystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword","password");
String jsonStr = apiList;
URL url = new URL(netThingsURL + URLEncoder.encode(jsonStr, "UTF-8") );
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection(); // create connection object
String encoded = Base64.encodeBase64String(authString.getBytes());
httpConn.setRequestProperty("Authorization", "?????????"); // ????????
httpConn.setRequestMethod("GET");
httpConn.connect(); // open connection
BufferedReader in = new BufferedReader(new InputStreamReader(httpConn.getInputStream()));
String temp = null;
StringBuilder sb = new StringBuilder();
while((temp = in.readLine()) != null)
{
sb.append(temp).append(" ");
}
String result = sb.toString();
System.out.println("result = " + result);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
What should I have here : httpConn.setRequestProperty("Authorization", "?????????"); I realise I may need more than just this 1 line. I tried various resources to find appropriate values but drew a blank. I tried various intuitive arguments but get a '401' error or NoSuchAlgorithException.
Any help, code, links to resources is greatly appreciated.
My problem is I cannot find out how to tell the HttpURLConnection that I want mutual certificate authentication.
You can't. You have to configure the server to ask for the client certificate. All you can do at the client is specify where the client certificate is. You can't force it to be sent. Only the server can do that.
Related
I'm having issues trying to send over a JSON string to a REST API. Long story short, I'm taking user input in a form, sending it over to a java servlet to validate and work with it a bit, and then trying to send it to an endpoint.
I have the following method being called on in my doPost method in my servlet, I am using printwriter pw to be able to read back data being returned in my response in the browser console at this point.
String jsonData = //JSON STRING HERE\\
String username = //USERNAME\\
String password = //PASSWORD\\
String endpointURL = //ENDPOINT URL HERE\\
pw.println(sendJson(jsonData, username, password));
private String sendJSON(String jsonData, String usrname, String usrpass) {
try {
String auth = usrname + ":" + usrpass;
byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(StandardCharsets.UTF_8));
String authHeaderValue = "Basic " + new String(encodedAuth);
URL url = new URL(endpointURL);
HttpURLConnection http = (HttpURLConnection)url.openConnection();
http.setConnectTimeout(5000);
http.setReadTimeout(5000);
http.setRequestMethod("POST");
http.setRequestProperty("Content-Type", "application/json; utf-8");
http.setRequestProperty("Authorization", authHeaderValue);
http.setDoOutput(true);
//POST Json to URL using HttpURLConnection
//try(OutputStream os = http.getOutputStream()) {
OutputStream os = http.getOutputStream();
byte[] input = jsonData.getBytes("utf-8");
os.write(input, 0, input.length);
//}
/*String responseBody;
try(BufferedReader br = new BufferedReader(
new InputStreamReader(http.getInputStream(), "utf-8"))) {
StringBuilder response = new StringBuilder();
String responseLine = null;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
//System.out.println(response.toString());
responseBody = response.toString();
return responseBody;
}
return responseBody;*/
BufferedReader in = new BufferedReader(
new InputStreamReader(http.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
return response.toString();
} catch (IOException e) {
return e.toString();
}
}
}
I was having issues with the try's so I rewrote it to try and just get functionality right away first. Right now I'm receiving "java.io.IOException: Server Returned HTTP response code: 500 for URL: //URL HERE\"
Would anybody have any tips to point me in the right direction? I feel like I'm just missing like a small piece of the puzzle at this point, and I'm having a hard time finding any tutorials showing what it is that I'm trying to do. Thank you so much to anyone for any tips/pointers!
Made sure I was able to authenticate and that wasn't the issue by just connecting and returning:
int statusCode = http.getResponseCode();
String statusCodeString = Integer.toString(statusCode);
return statusCodeString;
This worked fine, received 403 response when setting wrong password/username and 400 response when I change to correct.
I attempted using HttpClient as well instead, but was having issues trying to get that to work at all. I also had an error earlier with week trying to do this with a certificate error, but after reimporting the cert to my cacerts file this was resolved (unrelated to this issue I believe).
I am struggling to understand the whole new idea of accessing my organizatioon's Sharepoint content using Sahrepoint REST API and I am trying to implementing it in java. My aim is to read all the files in "abc" folder which is in Documents folder. Steps I did.
Register the app:
Click Generate Client ID,
Click Generate Client Secret,
Gave Title,
Gave Appdomain as companyname.onmicrosoft, and
Gave Request URI as https://companyname.sharepoint.com/Shared%20Documents/Forms/AllItems.aspx
Got the app registered. I have client id, client secret, and tenant id.
I used the below code to generate the access token
public String getSpToken(String shp_clientId, String shp_tenantId, String shp_clientSecret) {
String accessToken = "";
try {
// AccessToken url
String wsURL = "https://accounts.accesscontrol.windows.net/" + shp_tenantId + "/tokens/OAuth/2";
URL url = new URL(wsURL);
URLConnection connection = url.openConnection();
HttpURLConnection httpConn = (HttpURLConnection) connection;
// Set header
httpConn.setRequestProperty("Content-Type", " ");
httpConn.setDoOutput(true);
httpConn.setDoInput(true);
httpConn.setRequestMethod("POST");
// Prepare RequestData
String jsonParam = "grant_type=client_credentials"
+ "&client_id=" + shp_clientId + "#" + shp_tenantId
+ "&client_secret=" + shp_clientSecret
+ "&resource=00000003-0000-0ff1-ce00-000000000000/www.companyname.sharepoint.com#" + shp_tenantId;
// Send Request
DataOutputStream wr = new DataOutputStream(httpConn.getOutputStream());
wr.writeBytes(jsonParam);
wr.flush();
wr.close();
// Read the response.
InputStreamReader isr = null;
if (httpConn.getResponseCode() == 200) {
isr = new InputStreamReader(httpConn.getInputStream());
} else {
isr = new InputStreamReader(httpConn.getErrorStream());
}
BufferedReader in = new BufferedReader(isr);
String responseString = "";
String outputString = "";
// Write response to a String.
while ((responseString = in.readLine()) != null) {
outputString = outputString + responseString;
}
//Printing the response to the console
System.out.println("Output from the REST" + outputString);
// Extracting accessToken from string, here response (outputString)is a Json format string
if (outputString.indexOf("access_token\":\"") > -1) {
int i1 = outputString.indexOf("access_token\":\"");
String str1 = outputString.substring(i1 + 15);
int i2 = str1.indexOf("\"}");
String str2 = str1.substring(0, i2);
accessToken = str2;
}
//Printing the access token
System.out.println("Access token is " + accessToken);
} catch (Exception e) {
accessToken = "Error: " + e.getMessage();
}
return accessToken;
}
Now that I have the access token in the String variable "accessToken", I used the following code to read the filenames inside the folder "abc" in Documents folder using readFiles() method
public void readFiles(String accessToken) {
try {
//Frame SharePoint siteURL
String siteURL = "https://companyname.sharepoint.com";
//Frame SharePoint URL to retrieve the name of all of the files in a folder
String wsUrl = siteURL + "/_api/web/GetFolderByServerRelativeUrl('Shared%20Documents/abc')/Files";
//Create HttpURLConnection
URL url = new URL(wsUrl);
URLConnection connection = url.openConnection();
HttpURLConnection httpConn = (HttpURLConnection) connection;
//Set Header
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Authorization", "Bearer " + accessToken);
httpConn.setRequestProperty("accept", "application/json;odata=verbose"); //To get response in JSON
//httpConn.setRequestProperty("AllowAppOnlyPolicy", "true");
//httpConn.setRequestProperty("Scope", "http://sharepoint/content/sitecollection/web\" Right=\"FullControl");
//Read the response
String httpResponseStr = "";
InputStreamReader isr = null;
System.out.println(httpConn.getResponseCode());
if (httpConn.getResponseCode() == 200) {
isr = new InputStreamReader(httpConn.getInputStream());
} else {
isr = new InputStreamReader(httpConn.getErrorStream());
}
BufferedReader in = new BufferedReader(isr);
String strLine = "";
while ((strLine = in.readLine()) != null) {
httpResponseStr = httpResponseStr + strLine;
}
//Print response
System.out.println(httpResponseStr);
} catch (Exception e) {
System.out.println("Error while reading file: " + e.getMessage());
}
}
}
When I execute the above code I am getting {"error_description":"Exception of type 'Microsoft.IdentityModel.Tokens.AudienceUriValidationFailedException' was thrown."}. Could someone please help me to figure out what I am doing wrong? I have been sitting on this for days and not able to resolve it.
Please help!
I am trying to create a small application that will read the CPU load of computers / laptops and send a push notification to the browser of my main laptop, which will contain the user name and how much the processor is loaded. As a technology for sending notifications, I chose FCM. The code itself is already ready, but I lack one detail. I need to get the device token of my laptop, to which this push notification will be sent (because as I understand it, the device token is the token of the computer where the notification is sent). But I do not know how to get this token. Most of the guidelines are directed to Android, and I need to send it from computer to computer. Maybe someone can tell me a different approach to sending these notifications, or the option that I attached is also suitable for a start? If so, how can I get this token?
public class MetricTesting {
Process p = Runtime.getRuntime().exec("typeperf \"\\238(_Total)\\6\"");
BufferedReader br = new BufferedReader(new
InputStreamReader(p.getInputStream()));
String line;
double pr = 0;
Pattern pattern = Pattern.compile("[\\d]{0,3}\\.\\d{4,}");
while ((line = br.readLine()) != null) {
System.out.println(line);
Matcher m = pattern.matcher(line);
if (!m.find()) {
continue;
}
line = m.group();
pr = Math.round(Double.parseDouble(line) * 10.0) / 10.0;
System.out.println(pr);
if (pr > 5) {
PushNotificationSender.sendPushNotification("??", Double.toString(pr));
System.out.println(System.getProperty("user.name") + ", Processor loaded " + pr + " %");
}
}
String[] g = br.readLine().split("");
System.out.println(Arrays.toString(g));
br.close();
}
}
class PushNotificationSender {
public final static String AUTH_KEY_FCM = "//";
public final static String API_URL_FCM = "https://fcm.googleapis.com/fcm/send";
public static String sendPushNotification(String deviceToken, String pr)
throws IOException, JSONException {
String result = "";
URL url = new URL(API_URL_FCM);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Authorization", "key=" + AUTH_KEY_FCM);
conn.setRequestProperty("Content-Type", "application/json");
JSONObject json = new JSONObject();
json.put("to", deviceToken.trim());
JSONObject info = new JSONObject();
info.put("title", "CPU is overloaded");
info.put("body", System.getProperty("user.name")+"\n"+pr);
json.put("notification", info);
try {
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(json.toString());
wr.flush();
BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
String output;
while ((output = br.readLine()) != null) {
System.out.println(output);
}
result = "OK";
} catch (Exception e) {
e.printStackTrace();
result = "BAD";
}
return result;
}
}
You must try https://firebase.google.com/docs/cloud-messaging/js/client to create a web client for firebase push notification.
In the above article, generating firebase token is also mentioned.
You can try to push notification thru topic instead of firebase token as well.
I'm working with GeoServer and a Java backend. I am able to reset a tile's cache using the Rest API and to prevent any further cahing by removing the tile permanently from GeoServer's GUI (Tile Caching -> Tile Layers -> Check the tile -> Click on "Remove selected cached layers").
I would like to automatize the process and do it from back-end side. I tried truncate operations, dug in the rest api as well as Java objects but haven't been able to figure how.
Is is possible to permanently remove a tile from caching using Java? If yes, how?
Thank you for your help.
If you are trying to avoid caching a layer at all (rather than truncating a layer's cache) then you need to visit its GWC REST endpoint:
http://localhost:8080/geoserver/gwc/rest/layers/zoomstack:airports.xml
which will give you a file like:
<GeoServerLayer>
<id>LayerInfoImpl-36bac688:1666e6c28d4:-7ffd</id>
<enabled>true</enabled>
<inMemoryCached>true</inMemoryCached>
<name>zoomstack:airports</name>
<mimeFormats>
<string>image/png</string>
<string>image/jpeg</string>
</mimeFormats>
<gridSubsets>
<gridSubset>
<gridSetName>osgb</gridSetName>
</gridSubset>
<gridSubset>
<gridSetName>EPSG:900913</gridSetName>
</gridSubset>
<gridSubset>
<gridSetName>EPSG:4326</gridSetName>
</gridSubset>
</gridSubsets>
<metaWidthHeight>
<int>4</int>
<int>4</int>
</metaWidthHeight>
<expireCache>0</expireCache>
<expireClients>0</expireClients>
<parameterFilters>
<styleParameterFilter>
<key>STYLES</key>
<defaultValue/>
</styleParameterFilter>
</parameterFilters>
<gutter>0</gutter>
</GeoServerLayer>
You can then change <enabled>true</enabled> to <enabled>false</enabled> and PUT it back to the server.
As a complement to Ian's answer (works like a charm, thank you Ian), here is a Java snippet (that needs some love, constants, etc.):
private void removeLayerGroupFromCache() throws IOException {
URL url = new URL("http://localhost:8080/geoserver/gwc/rest/layers/layer group name.xml");
String rawLayer = getXMLContent(url);
String updatedLayer = formatXMLContent(rawLayer);
updateLayerInGIS(url, updatedLayer);
}
private String getXMLContent(URL url) throws IOException {
URLConnection urlConnection = setUsernamePassword(url);
InputStreamReader inputStreamReader = new InputStreamReader(urlConnection.getInputStream());
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
StringBuilder result = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
result.append(line);
}
bufferedReader.close();
inputStreamReader.close();
return result.toString();
}
// TODO: This feels akward and should be improved. (Why extra spaces are being added with the urlConnection.getInputStream() call?)
private String formatXMLContent(String originalContent) {
originalContent = originalContent.replaceAll("\\s+", ""); // Removes undesired spaces.
originalContent = originalContent.replaceAll("layergroupname".replaceAll("\\s+", ""), "layer group name"); // Makes sure the name is matching if it contains white spaces.
originalContent = originalContent.replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>".replaceAll("\\s+", ""), "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); // Re-append required spaces to XML declaration.
originalContent = originalContent.replace("<enabled>true</enabled>", "<enabled>false</enabled>"); // Finally, disable the caching for the group.
return originalContent;
}
private URLConnection setUsernamePassword(URL url) throws IOException {
String authStringEncoded = new String(Base64.encodeBase64("username:userpassword".getBytes()));
URLConnection urlConnection = url.openConnection();
urlConnection.setRequestProperty("Authorization", "Basic " + authStringEncoded);
return urlConnection;
}
private void updateLayerInGIS(URL url, String updatedLayer) throws IOException {
Authentication auth = authenticationResolver.retrieve();
String encodedCredentials = java.util.Base64.getEncoder().encodeToString("username:userpassword".getBytes());
URL directUrl = new URL("http", url.getHost(), url.getPort(), url.getFile());
HttpURLConnection httpCon = (HttpURLConnection) directUrl.openConnection();
httpCon.setRequestProperty("Authorization", "Basic " + encodedCredentials);
httpCon.setDoOutput(true);
httpCon.setRequestMethod("POST");
OutputStreamWriter out = new OutputStreamWriter(httpCon.getOutputStream());
out.write(updatedLayer);
out.close();
int statusCode = httpCon.getResponseCode();
if(statusCode >= 200 && statusCode < 400) {
httpCon.getInputStream();
} else {
// Gets a more verbose message on why a non valid code has been returned.
String errorMessage = readStream(httpCon.getErrorStream());
throw new IOException(errorMessage);
}
}
private String readStream(InputStream stream) throws IOException {
StringBuilder builder = new StringBuilder();
try (BufferedReader in = new BufferedReader(new InputStreamReader(stream))) {
String line;
while ((line = in.readLine()) != null) {
builder.append(line);
}
}
return builder.toString();
}
I am editing a Java application and trying to access a secure third party API. There are two String variables that need to be passed, and ID and a token for the secure access. The code below is using Maven. I am trying to tweak the code for just Java.
public class JavaApiStreaming {
public static void main (String[]args) throws IOException {
HttpClient httpClient = HttpClientBuilder.create().build();
try {
// Set these variables to whatever personal ones are preferred
String domain = "https://stream-fxpractice.oanda.com";// trying to access this api
String access_token = "ACCESS-TOKEN"; //using this token
String account_id = "1234567"; //using this ID
String instruments = "EUR_USD,USD_JPY,EUR_JPY";
// This is the part of the code I am trying to edi. to my knowledge this is //maven coding
HttpUriRequest httpGet = new HttpGet(domain + "/v1/prices?accountId=" + account_id + "&instruments=" + instruments);
httpGet.setHeader(new BasicHeader("Authorization", "Bearer " + access_token));
System.out.println("Executing request: " + httpGet.getRequestLine());
HttpResponse resp = httpClient.execute(httpGet);
HttpEntity entity = resp.getEntity();
if (resp.getStatusLine().getStatusCode() == 200 && entity != null) {
InputStream stream = entity.getContent();
String line;
BufferedReader br = new BufferedReader(new InputStreamReader(stream));
while ((line = br.readLine()) != null) {
Object obj = JSONValue.parse(line);
JSONObject tick = (JSONObject) obj;
// unwrap if necessary
if (tick.containsKey("tick")) {
tick = (JSONObject) tick.get("tick");
}
// ignore heartbeats
if (tick.containsKey("instrument")) {
System.out.println("-------");
String instrument = tick.get("instrument").toString();
String time = tick.get("time").toString();
double bid = Double.parseDouble(tick.get("bid").toString());
double ask = Double.parseDouble(tick.get("ask").toString());
System.out.println(instrument);
System.out.println(time);
System.out.println(bid);
System.out.println(ask);
}
}
} else {
// print error message
String responseString = EntityUtils.toString(entity, "UTF-8");
System.out.println(responseString);
}
} finally {
httpClient.getConnectionManager().shutdown();
}
}
}
It seems like you're asking how to use the standard library instead of any dependencies and encode the account_id/access token as part of basic auth header. I would suggest using HttpURLConnection. It's included as part of the Java standard library. Try the following:
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
String encoded = Base64.encode(account_id+":"+access_token);
connection.setRequestProperty("Authorization", "Basic "+encoded);