Vertx WebClient SSL redirect fails - java

I am trying to make a connection to a 3rd party API that requires an api key. It works fine using traditional HttpURLConnection... I get a 200 response
HttpURLConnection connection = (HttpURLConnection) new URL("https://www.server.com/download?apikey=<MY_KEY>"
However when using the Vertx WebClient (io.vertx.ext.web.client.WebClient) I always get 403 Forbidden
webClient = WebClient.create(vertx, new WebClientOptions());
webClient.get("/download")
.addQueryParam("apikey", "<MY_KEY>")
.ssl(true)
.host("www.server.com")
.port(443)
.send(downloadFileHandler ->
{
Upon investigation it looks like the reason is because the API is redirecting to another URL, both the original URL and the redirect are using SSL. Somehow the Vertx web client is not maintaining the handshake.

//WebClientOptions webClientOptions = new WebClientOptions();
WebClient client = WebClient.create(vertx, webClientOptions);
WebClientSession session = WebClientSession.create(client);
session.getAbs(url).send(response -> {
if (response.succeeded()) {
HttpResponse<Buffer> httpResponse = response.result();
System.out.println(" -> Response Code : " + httpResponse.statusCode());
promise.complete(httpResponse.bodyAsJsonObject());
} else {
promise.fail(response.cause());
}
});

Related

Using rest api of azure devops

I want to fetch data from the rest api of Azure Devops using Java.But not sure how to establish the connection.May be personal acces token will help,but how to use the token in Code for establishing the connection between code and azure devops? An example from anyone will be very helpful.
A code example will be very helpfull
If I am understanding you correctly, you are trying to call azure APIs, and those API need authorization token?
For example this azure API to send data into Azure queue : https://learn.microsoft.com/en-us/rest/api/servicebus/send-message-to-queue
It needs some payload and Authorization in request header !!
If my Understanding is correct, than from java you need to use any rest client or HTTP client to call the REST API and you need to pass the Authorization token in the request header
For calling a Rest API in java with passing header below is an example:
MultiValueMap<String, String> map= new LinkedMultiValueMap<>();
map.add("Authorization", "Bearer <Azure AD JWT token>"); // set your token here
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON); //someother http headers you want to set
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
RestTemplate restTemplate = new RestTemplate();
String azure_url = "https://azure_url"; // your azure devops REST URL
ResponseEntity<String> response = restTemplate.postForEntity(azure_url, request , String.class);
A small example with httpclient:
static String ServiceUrl = "https://dev.azure.com/<your_org>/";
static String TeamProjectName = "your_team_project_name";
static String UrlEndGetWorkItemById = "/_apis/wit/workitems/";
static Integer WorkItemId = 1208;
static String PAT = "your_pat";
String AuthStr = ":" + PAT;
Base64 base64 = new Base64();
String encodedPAT = new String(base64.encode(AuthStr.getBytes()));
URL url = new URL(ServiceUrl + TeamProjectName + UrlEndGetWorkItemById + WorkItemId.toString());
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestProperty("Authorization", "Basic " + encodedPAT);
con.setRequestMethod("GET");
int status = con.getResponseCode();
Link to the file: ResApiMain.java
You can the use java client library for azure devops rest api. This will take the overload of encoding your personal access token and indeed supports OAuth authentication.
It is been actively developed and used in production.
Source code - https://github.com/hkarthik7/azure-devops-java-sdk
Documentation - https://azure-devops-java-sdk-docs.readthedocs.io/en/latest/?badge=latest
A quick example:
public class Main {
public static void main(String[] args) {
String organisation = "myOrganisationName";
String personalAccessToken = "accessToken";
String projectName = "myProject";
// Connect Azure DevOps API with organisation name and personal access token.
var webApi = new AzDClientApi(organisation, project, personalAccessToken);
// call the respective API with created webApi client connection object;
var core = webApi.getCoreApi();
var wit = webApi.getWorkItemTrackingApi();
try {
// get the list of projects
core.getProjects();
// get a workitem
wit.getWorkItem(15);
// Get a work item and optionally expand the field
wit.getWorkItem(15, WorkItemExpand.ALL);
} catch (AzDException e1) {
e1.printStackTrace();
}
}
}
The library has support to most of the APIs and you can view the documentation and examples folder in the github repo to know how to get the most out of it.

Accessing secured rest api at server side generated by hyperledger composer rest server

I am generating rest apis using composer-rest-server. I am authenticating rest api using passport-jwt. In composer rest server we get access_token in cookie.
We can set withCredentials:true for accessing these apis using client side but how can we call these apis using server side
Now when we make the same api call initiated from the server side(java), it fails. Giving us 401: Authorization Required error.
So my question is - Is it possible to call secured composer APIs from server side(java) ? If anyone has tried this before please let me know.
Try this code to retrieve cookies:
public void getCookieUsingCookieHandler() {
try {
// Instantiate CookieManager;
// make sure to set CookiePolicy
CookieManager manager = new CookieManager();
manager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault(manager);
// get content from URLConnection;
// cookies are set by web site
URL url = new URL("http://host.example.com");
URLConnection connection = url.openConnection();
connection.getContent();
// get cookies from underlying
// CookieStore
CookieStore cookieJar = manager.getCookieStore();
List <HttpCookie> cookies =
cookieJar.getCookies();
for (HttpCookie cookie : cookies) {
if (cookie.getName().equalsIgnoreCase("access_token")) {
System.out.println("CookieHandler retrieved cookie: " + cookie.getValue());
break;
}
}
} catch(Exception e) {
System.out.println("Unable to get cookie using CookieHandler");
e.printStackTrace();
}
}
One can refer it from here: https://docs.oracle.com/javase/tutorial/deployment/doingMoreWithRIA/accessingCookies.html

Https request returns 403

When I make a request to : " https://www.btcturk.com/api/orderbook " via browser or curl I get the response as expected.
When I make the same request via jersey or java libraries such as HttpsURLConnection, I get a 403 forbidden response.
I can use the same methods to make requests to any other urls running under https. An example method can be found below :
public static RestResponse getRestResponse(String url)
{
String jsonString;
try
{
Client client = Client.create();
WebResource webResource = client.resource(url);
ClientResponse response = webResource.accept("application/json")
.get(ClientResponse.class);
if (response.getStatus() != 200) {
return RestResponse.createUnsuccessfulResponse(response.getStatusInfo().getReasonPhrase());
}
jsonString = response.getEntity(String.class);
}
catch(Exception e)
{
return RestResponse.createUnsuccessfulResponse(e);
}
return RestResponse.createSuccessfulResponse(jsonString);
}
The above code is just to give the idea. The whole thing can be found at: https://github.com/cgunduz/btcenter/tree/master/src/main/java/com/cemgunduz/web
My network knowledge is very limited, so any directions towards where I should start would be helpful. Cheers.
You probably have to provide some credentials. Depending on the server configuration you have to provide either a user/password combination or a valid certificate. Try the solutions provided here:
Using HTTPS with REST in Java

Java Proxy: How to extract Destination Host and Port from the HttpRequest?

I am working on a Http Proxy in java. Basically I have 3 applications:
a client application, where I just submit a request to a server VIA a proxy
a proxy that captures the request, modifies it and then forwards it to the web server
the web server
Here is my code for the Client (taken from the apache httpcore examples, but works well):
public class ClientExecuteProxy () {
public static void main(String[] args)throws Exception {
HttpHost proxy = new HttpHost("127.0.0.1", 8080, "http");
DefaultHttpClient httpclient = new DefaultHttpClient();
try {
httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
HttpHost target = new HttpHost("issues.apache.org", 443, "https");
HttpGet req = new HttpGet("/");
System.out.println("executing request to " + target + " via " + proxy);
HttpResponse rsp = httpclient.execute(target, req);
HttpEntity entity = rsp.getEntity();
System.out.println("----------------------------------------");
System.out.println(rsp.getStatusLine());
Header[] headers = rsp.getAllHeaders();
for (int i = 0; i<headers.length; i++) {
System.out.println(headers[i]);
}
System.out.println("----------------------------------------");
if (entity != null) {
System.out.println(EntityUtils.toString(entity));
}
} finally {
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
}
}
If I do a direct execution of the request to the server (if I comment the line "httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);"), it works without any problem. But if I leave it like that, it will pass by the proxy. Here is the part that I do not know how to handle for the proxy:
The proxy listens for the requests, reads its content and verifies if it respects certain policies. If OK it will forward it to the server, else it will drop the request and it will send a HttpResponse with an error. The problem is when the request is OK and it needs to be forwarded. How does the proxy know to what address to forward it? My question is: How do I get the information from the request entered at the line "HttpHost target = new HttpHost("issues.apache.org", 443, "https");"?
I've googled for a couple of hours but found nothing. Can anybody help me please?
When you define an HTTP proxy to an application or browser, either:
There will be a preceding CONNECT request to form a tunnel, that tells you the target host:port, or
The entire target URL is placed in the middle of the GET/POST/... request line. Normally, without a proxy, this is just a relative URL, relative to the host:port of the TCP connection.

Authenticating to sharepoint with kerberos from a java HttpClient

I have a linux\java6 client that will authenticate to sharepoint2010 with NTLM and then send HTTP REST web services using Apache Commons HttpClient.
I can do this with NTLM , but I want to use the same REST API to access sharepoint 2010 that uses kerberos auth.
Any examples how to authenticate and send REST over HTTP with a kerberos sharepoint?
(preferably using HttpClient)
p.s.
I dont have access to sharepoint code, but i do have access to sharepoint admin configurations.
This is roughly how I authenticate with NTLM:
HttpClient httpClient = new HttpClient(new SimpleHttpConnectionManager(true));
AuthPolicy.registerAuthScheme(AuthPolicy.NTLM, JCIFS_NTLMScheme.class);
String localHostName = Inet4Address.getLocalHost().getHostName();
authscope = new AuthScope(uri.getHost(), AuthScope.ANY_PORT);
httpClient.getState().setCredentials(authscope,new NTCredentials(
getUsername(),getPassword(),localHostName,getDomain()));
// after the initial ntlm auth I can call my REST service with "httpClient.executeMethod"
int status = httpClient.executeMethod(new GetMethod(accessURI + "/sitecollection/info"));
Please confirm that your environment is correctly setup for Kerberos, this can be achieved by running kinit. If this fails you will need to ensure that your krb5.ini (windows) or krb5.conf (linux) are setup to point to your domain controller correctly.
Once you have confirmed that Kerberos is functional you can use the example code from HttpClient as pasted below.
Please note that there are many issues that can cause Kerberos to fail, such as time synchronisation, supported encryption types, trust relationships across domain forests and it's also worth ensuring that your client is on a seperate box to the server.
Here is the example code which is available in the HttpClient download, you will need to ensure your JAAS configuration and krb5.conf or ini are correct!
public class ClientKerberosAuthentication {
public static void main(String[] args) throws Exception {
System.setProperty("java.security.auth.login.config", "login.conf");
System.setProperty("java.security.krb5.conf", "krb5.conf");
System.setProperty("sun.security.krb5.debug", "true");
System.setProperty("javax.security.auth.useSubjectCredsOnly","false");
DefaultHttpClient httpclient = new DefaultHttpClient();
try {
httpclient.getAuthSchemes().register(AuthPolicy.SPNEGO, new SPNegoSchemeFactory());
Credentials use_jaas_creds = new Credentials() {
public String getPassword() {
return null;
}
public Principal getUserPrincipal() {
return null;
}
};
httpclient.getCredentialsProvider().setCredentials(
new AuthScope(null, -1, null),
use_jaas_creds);
HttpUriRequest request = new HttpGet("http://kerberoshost/");
HttpResponse response = httpclient.execute(request);
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
System.out.println("----------------------------------------");
if (entity != null) {
System.out.println(EntityUtils.toString(entity));
}
System.out.println("----------------------------------------");
// This ensures the connection gets released back to the manager
EntityUtils.consume(entity);
} finally {
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
}
}

Categories