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.
Related
I'm trying to consume an external api exposed a payment provider.
I user Jersey and javax.ws.rs for request, because I can easily send authent with Digest.
But when it comes to make the request, a GET with payload, Jersey returns
> IllegalStateException. Entity must be null for http method GET
CashTransactionResponse responseData = null;
//We connect to intouch server
String requestUrl = rootUrlTouchPay + agency.getAgencyCode() + "/" + IntouchMethodApis.TRANSACTION + "?loginAgent=" + agency.getLogin() + "&passwordAgent=" + agency.getPassword();
ClientConfig clientConfig = new ClientConfig();
//Open Digest authentication
HttpAuthenticationFeature feature = HttpAuthenticationFeature.digest(BASIC_LOGIN, BASIC_PWD);
clientConfig.register(feature);
clientConfig.register(JacksonFeature.class);
//Create new rest client
Client client = ClientBuilder.newClient(clientConfig);
clientConfig.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true);
//Set the url
WebTarget webTarget = client.target(requestUrl);
Invocation.Builder invocationBuilder = webTarget.request(javax.ws.rs.core.MediaType.APPLICATION_JSON);
logger.info("Initialisation of cashout service successful for cash");
// create request
Gson gson = new Gson();
String transactionString = gson.toJson(cashRequest);
Response response = null;
// start the response
if (cashRequest.getServiceCode().contains(TelecomEnum.WAVE.name().toUpperCase())) {
response = invocationBuilder.method("GET", Entity.entity(transactionString, javax.ws.rs.core.MediaType.APPLICATION_JSON));
} else {
response = invocationBuilder.put(Entity.entity(transactionString, javax.ws.rs.core.MediaType.APPLICATION_JSON));
}
Please how could i do to send my GET request with body ?
Thanks
I believe the problem is in
Client client = ClientBuilder.newClient(clientConfig);
clientConfig.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true);
The client copied the values from clientConfig and any further settings on clientConfig do not have any impact on the client.
Either switch the lines or set the ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION property on the client.
Instead of doing an invocationBuilder.method("GET", ...), use invocationBuilder.post(entity), as described here. This will allow you to POST your transaction String to the endpoint.
I want to get list of my albums from Google Photos.
And I'm using new REST API.
I wrote the code which executes GET request:
GET
https://photoslibrary.googleapis.com/v1/albums
according to the official guide: https://developers.google.com/photos/library/guides/list
And this code only returns response with status 200, but without json body:
Listing:
public static void main(String[] args) throws IOException, GeneralSecurityException, ServiceException, ParseException {
GoogleCredential credential = createCredential();
if (!credential.refreshToken()) {
throw new RuntimeException("Failed OAuth to refresh the token");
}
System.out.println(credential.getAccessToken());
doGetRequest(credential.getAccessToken(), "https://photoslibrary.googleapis.com/v1/albums");
}
private static GoogleCredential createCredential() {
try {
return new GoogleCredential.Builder()
.setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(emailAccount)
.setServiceAccountPrivateKeyFromP12File(ENCRYPTED_FILE)
.setServiceAccountScopes(SCOPE)
.setServiceAccountUser(emailAccount)
.build();
} catch (Exception e) {
throw new RuntimeException("Error while creating Google credential");
}
}
private static void doGetRequest(String accessToken, String url) throws IOException, ParseException {
logger.debug("doGetRequest, with params: url: {}, access token: {}", accessToken, url);
HttpGet get = new HttpGet(url);
get.addHeader("Authorization",
"Bearer" + " " + accessToken);
HttpClient client = HttpClientBuilder.create().build();
HttpResponse response = client.execute(get);
String json = EntityUtils.toString(response.getEntity());
System.out.println(json);
}
Also i tried to use other REST clients (e.g. Postman) and the same result i recieve is:
{}
It looks like you are using a service account to access the API. Service accounts are not supported by the Google Photos Library API.
You will need to set up OAuth 2.0 for a Web Application as described here:
Go to the Google Developers console and open your project
Go to the Credentials Page from the menu
Click Create Credentials > OAuth client ID
Set the application type to Web application and complete the form. Also specify a redirect URI for your application to receive the callback from the OAuth request and the URIs of your application.
You will then use the client Id and client secret returned on this page as part of your requests. If you need offline access, which means access when the user is not present in the browser, you can also request an offline access_type and use refresh tokens to maintain access.
It looks like you are using the Google API Java client, which also has support for this flow. Set the client secrets on the builder by calling setClientSecrets(..) like this:
return new GoogleCredential.Builder()
.setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setClientSecrets(CLIENT_ID, CLIENT_SECRET)
.build();
You also need to handle the callback from the OAuth request in your application where you will receive the access tokens at the callback URL that you have configured in the developer console.
There is also a more complete example in the documentation for the client library.
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());
}
});
implementing service something similar with tinyurl or bit.ly, I'm would like to expose service as API, I'm using java and jersey as RESTfull service implementation.
I'm looking for simplest way for authentification of users who use API, OAuth is first thing coming in mind, but the problem is I don't need this 3 iteration calls with request token query, than access token query with callback url passing. I just need to give user ability to invoke api with no additional security calls to my server.
Thanks to patrickmcgraw comment I used 2-legged oauth authentificaton.
Here is some java code.
For client side (using Jersey api):
OAuthParameters params = new OAuthParameters().signatureMethod("HMAC-SHA1").
consumerKey("consumerKey").version("1.1");
OAuthSecrets secrets = new OAuthSecrets().consumerSecret("secretKey");
OAuthClientFilter filter = new OAuthClientFilter(client().getProviders(), params, secrets);
WebResource webResource = resource();
webResource.addFilter(filter);
String responseMsg = webResource.path("oauth").get(String.class);
On provider side:
#Path("oauth")
public class OAuthService {
#GET
#Produces("text/html")
public String secretService(#Context HttpContext httpContext) {
OAuthServerRequest request = new OAuthServerRequest(httpContext.getRequest());
OAuthParameters params = new OAuthParameters();
params.readRequest(request);
OAuthSecrets secrets = new OAuthSecrets().consumerSecret("secretKey");
try {
if(!OAuthSignature.verify(request, params, secrets))
return "false";
} catch (OAuthSignatureException ose) {
return "false";
}
return "OK";
}
}
Here is code for PHP client:
<?php
require_once 'oauth.php';
$key = 'consumerKey';
$secret = 'secretKey';
$consumer = new OAuthConsumer($key, $secret);
$api_endpoint = 'http://localhost:9998/oauth';
$sig_method = new OAuthSignatureMethod_HMAC_SHA1;
$parameters = null;
$req = OAuthRequest::from_consumer_and_token($consumer, null, "GET", $api_endpoint, $parameters);
$sig_method = new OAuthSignatureMethod_HMAC_SHA1();
$req->sign_request($sig_method, $consumer, null);//note: double entry of token
//get data using signed url
$ch = curl_init($req->to_url());
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$res = curl_exec($ch);
echo $res;
curl_close($ch);
if youre using http at the transport layer you can always use basic http authentication
How can I specify the username and password for making Basic-Auth requests with App Engine's URLFetch service (in Java)?
It seems I can set HTTP headers:
URL url = new URL("http://www.example.com/comment");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("X-MyApp-Version", "2.7.3");
What are the appropriate headers for Basic-Auth?
This is a basic auth header over http:
Authorization: Basic base64 encoded(username:password)
eg:
GET /private/index.html HTTP/1.0
Host: myhost.com
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
You will need to do this:
URL url = new URL("http://www.example.com/comment");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Authorization",
"Basic "+codec.encodeBase64String(("username:password").getBytes());
And to do that you will want to get a base64 codec api, like the Apache Commons Codec
For those interested in doing this in Python (as I was), the code looks like this:
result = urlfetch.fetch("http://www.example.com/comment",
headers={"Authorization":
"Basic %s" % base64.b64encode("username:pass")})
You set up an Authenticator before you call openConnection() like this,
Authenticator.setDefault(new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password.toCharArray());
}
});
Since there is only one global default authenticator, this doesn't really work well when you have multiple users doing the URLFetch in multiple threads. I would use Apache HttpClient if that's the case.
EDIT: I was wrong. App Engine doesn't allow Authenticator. Even if it's allowed, we would have the multi-thread issue with a global authenticator instance. Even though you can't create threads, your requests may still get served in different threads. So we just add the header manually using this function,
import com.google.appengine.repackaged.com.google.common.util.Base64;
/**
* Preemptively set the Authorization header to use Basic Auth.
* #param connection The HTTP connection
* #param username Username
* #param password Password
*/
public static void setBasicAuth(HttpURLConnection connection,
String username, String password) {
StringBuilder buf = new StringBuilder(username);
buf.append(':');
buf.append(password);
byte[] bytes = null;
try {
bytes = buf.toString().getBytes("ISO-8859-1");
} catch (java.io.UnsupportedEncodingException uee) {
assert false;
}
String header = "Basic " + Base64.encode(bytes);
connection.setRequestProperty("Authorization", header);
}
Using HttpURLConnection gave me some problems (for some reason the server I was trying to connect to didn't accept auth credentials), and finally I realized that it's actually much easier to do using GAE's low-level URLFetch API (com.google.appengine.api.urlfetch) like so:
URL fetchurl = new URL(url);
String nameAndPassword = credentials.get("name")+":"+credentials.get("password");
String authorizationString = "Basic " + Base64.encode(nameAndPassword.getBytes());
HTTPRequest request = new HTTPRequest(fetchurl);
request.addHeader(new HTTPHeader("Authorization", authorizationString));
HTTPResponse response = URLFetchServiceFactory.getURLFetchService().fetch(request);
System.out.println(new String(response.getContent()));
This worked.
There is a wrapper on Apache HttpClient for App Engine
please go through the post http://esxx.blogspot.com/2009/06/using-apaches-httpclient-on-google-app.html
http://peterkenji.blogspot.com/2009/08/using-apache-httpclient-4-with-google.html
Note on the first answer: setRequestProperty should get the property name without the colon ("Authorization" rather than "Authorization:").