How to include OAuth headers into async fetch request? - java

I would like to use asynchronous requests in my google engine application to trigger google app script (which is deployed as web app) :
URLFetchService fetcher = URLFetchServiceFactory.getURLFetchService();
Future future = fetcher.fetchAsync(req);
HTTPResponse response = (HTTPResponse) future.get();
but fetchAsync method accepts only urls or com.google.appengine.api.urlfetch.HTTPRequest
which does not offer much more options : https://developers.google.com/appengine/docs/java/javadoc/com/google/appengine/api/urlfetch/HTTPRequest
I do not see way how to add OAuth security headers into asynchrounous fetch service. We build authorized requests by using standart HttpRequest method.
Sample HttpRequest with included OAuth :
HttpRequest contactrequest = rf.buildGetRequest(shortenEndpoint);
GoogleHeaders headers = new GoogleHeaders();
headers.setContentType("application/x-www-form-urlencoded");
headers.setAuthorization("OAuth " + creds.getAccessToken());
contactrequest.setHeaders(headers);
contactrequest.getHeaders().set("GData-Version", "3.0");
Is there a way how to send async OAuth authorized requests ?

Answer : OAuth headers cannot be specified in fetchAsync service. Alternative is use queque tasks.
Now new question come up : how to pass 'user context' when you invoking google app script programatically : Invoking Google App script programatically and user identity? ?

Related

Implementing auto-post in linkedin using spring boot

I am implementing auto-post feature in linkedin using spring boot and oauth2. I have created the app in linkedin and the permissions it request are r_liteprofile, w_member_social. I am able to get access_token but when i am sending POST request to https://api.linkedin.com/v2/ugcPosts along with the token then the server is responding with 403 Forbidden status. What am i doing wrong?
Does we need any more permission than r_liteprofile, w_member_social to post in linkedin?
TokenResponse tokenResponse = gson.fromJson(token, TokenResponse.class);
String post_url = "https://api.linkedin.com/v2/ugcPosts";
HttpPost wallPost = new HttpPost(post_url);
ArrayList mediaList = new ArrayList();
wallPost.setHeader("Content-Type","application/json");
wallPost.setHeader("Authorization","Bearer "+tokenResponse.getAccess_token());
wallPost.setHeader("X-RestLi-Protocol-Version","2.0.0");
I have used HttpClient to send the request along with above headers.
The following image shows the token and permissions.
There is nothing wrong with the OAuth token as if there was the response would be 401 (https://developer.linkedin.com/docs/v2/oauth2-client-credentials-flow)
I think you need to add 'w_share' scope to your application. Current scopes do now allow posting updates to LinkedIn. See details here: https://learn.microsoft.com/en-us/linkedin/shared/references/migrations/default-scopes-migration

Vert.x Oauth 2 Authorization server

Can some one help me to setup Oauth 2 Authorisation server Vert.x (3.3.0).I dont find any documentation related to it.
I found vertx-auth-oauth2 this vert.x module but I guess it will be useful if Authorisation server is different
e.g
The following code snippet is from vert.x documentation
OAuth2Auth oauth2 = OAuth2Auth.create(vertx, OAuth2FlowType.AUTH_CODE, new OAuth2ClientOptions()
.setClientID("YOUR_CLIENT_ID")
.setClientSecret("YOUR_CLIENT_SECRET")
.setSite("https://github.com/login")
.setTokenPath("/oauth/access_token")
.setAuthorizationPath("/oauth/authorize")
);
// when there is a need to access a protected resource or call a protected method,
// call the authZ url for a challenge
String authorization_uri = oauth2.authorizeURL(new JsonObject()
.put("redirect_uri", "http://localhost:8080/callback")
.put("scope", "notifications")
.put("state", "3(#0/!~"));
// when working with web application use the above string as a redirect url
// in this case GitHub will call you back in the callback uri one should now complete the handshake as:
String code = "xxxxxxxxxxxxxxxxxxxxxxxx"; // the code is provided as a url parameter by github callback call
oauth2.getToken(new JsonObject().put("code", code).put("redirect_uri", "http://localhost:8080/callback"), res -> {
if (res.failed()) {
// error, the code provided is not valid
} else {
// save the token and continue...
}
});
It is using Github as Authorisation server.I am curious to know how to implement Authorisation server in vert.x ,i know spring security provides this feature i.e Oauth2Server and OAuth2Client.
Vert.x OAuth2 is just a OAuth2Client, there is no server implementation so you cannot get it from the Vert.x Project itself.
Vert.x OAuth2 supports the following flows:
Authorization Code Flow (for apps with servers that can store persistent information).
Password Credentials Flow (when previous flow can’t be used or during development).
Client Credentials Flow (the client can request an access token using only its client credentials)

Pass Crendentials from dotNet client to Java Web Service

I have a dot net application that call a java web service. I am trying to implement authentication by passing credentials to the java service. Here is the dot net code setting the credentials. How can I get these credentials in my java application? They aren't set in the headers...
System.Net.NetworkCredential serviceCredentials = new NetworkCredential("user", "pass");
serviceInstance.Credentials = serviceCredentials;
serviceInstance is an instance of SoapHttpClientProtocol.
I've tried injecting the WebServiceContext like so
#Resource
WebServiceContext wsctx;
and pulling the crentials from the headers but they aren't there.
You are not passing the credentials to your service the correct way. In order to get the Authorize http request header do the following:
// Create the network credentials and assign
// them to the service credentials
NetworkCredential netCredential = new NetworkCredential("user", "pass");
Uri uri = new Uri(serviceInstance.Url);
ICredentials credentials = netCredential.GetCredential(uri, "Basic");
serviceInstance.Credentials = credentials;
// Be sure to set PreAuthenticate to true or else
// authentication will not be sent.
serviceInstance.PreAuthenticate = true;
Note: Be sure to set PreAuthenticate to true or else authentication will not be sent.
see this article for more information.
I had to dig-up some old code for this one :)
Update:
After inspecting the request/response headers using fiddler as suggested in the comments below a WWW-Authenticate header was missing at the Java Web Service side.
A more elegant way of implementing "JAX-WS Basic authentication" can be found in this article here using a SoapHeaderInterceptor (Apache CXF Interceptors)

Google Drive API through Google App Engine

I'm trying to use the Google Drive API through the App Identity interface provided with Google App Engine. This basically allows my web application to communicate with Google's APIs from server to server.
I don't need my users to login, I simply need to display my own Google Drive documents.
However, after I set all the appropriate values and scopes, and enable all the right Google Drive knobs on the console page, I still get this for a simple GET request to https://www.googleapis.com/drive/v2/files:
{ "error": { "errors": [ { "domain": "usageLimits", "reason": "dailyLimitExceededUnreg", "message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.", "extendedHelp": "https://code.google.com/apis/console" } ], "code": 403, "message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup." }}
What's wrong? What am I missing? Here's the code that actually does the request - funny thing is that it works great if I use other APIs such as the URL shortener API:
var scopes = new java.util.ArrayList();
scopes.add("https://www.googleapis.com/auth/drive");
var appIdentity = AppIdentityServiceFactory.getAppIdentityService();
var accessToken = appIdentity.getAccessToken(scopes);
var url = new URL("https://www.googleapis.com/drive/v2/files");
var connection = url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("GET");
connection.addRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("Authorization", "OAuth " + accessToken.getAccessToken());
EDIT
If I simply change the API to use the urlshortner API for example, it works:
var url = new URL("https://www.googleapis.com/urlshortener/v1/url/history");
And output:
{ "kind": "urlshortener#urlHistory", "totalItems": 0, "itemsPerPage": 30}
So there must be something not working with Google Drive and App Identity?
EDIT 2
I've found some help from the correct answer here: https://stackoverflow.com/a/12526286/50394
But it's talking about setting Client API scopes on Google Apps, and I'm not using Google Apps, I'm simply using Google App Engine's domain foo.appspot.com
The 403 error you are getting means that there was no Authorization header in your GET. The logic is that without an Authorization header, you are anonymous (you are legion blah blah :-)). The Drive quota for anonymous use is zero, hence the message. URL shortener has a higher quota for anonymous so it works.
I suggest you change the URL to point to an http server of your own, and check what headers you are actually sending.
AFAICT you should be using Bearer in the Authorization header.
Probably what's happening is, Drive API doesn't recognize the service account (because of the wrong header?) and thus taking it as an anonymous request since no key parameter wasn't provided either (see common query params).
Try this:
connection.addRequestProperty("Authorization", "Bearer " + accessToken.getAccessToken());
Or you could try adding the token as access_token query param.
I think you should at least setup an API console entry with Drive API enabled at https://code.google.com/apis/console
Once you create this you'll get an ID you can use in your GoogleCredential object. From the GoogleCredential object you can get the access token which you can than add to your request.
What I read here (Google drive via service accounts) was that you use a slightly different style that uses an API KEY that you retrieve from the Developer Console.
The pertinent parts for me were to generate a "Key for Server Applications", then use this technique, which I hadn't read anywhere else!
HttpTransport httpTransport = new NetHttpTransport();
JsonFactory jsonFactory = new JacksonFactory();
AppIdentityCredential credential =
new AppIdentityCredential.Builder(DriveScopes.DRIVE).build();
// API_KEY is from the Google Console as a server API key
GoogleClientRequestInitializer keyInitializer =
new CommonGoogleClientRequestInitializer(API_KEY);
Drive service = new Drive.Builder(httpTransport, jsonFactory, null)
.setHttpRequestInitializer(credential)
.setGoogleClientRequestInitializer(keyInitializer)
.build();
This answer claims that:
Service Accounts are not supported by the Drive SDK due to its
security model.
If that's still true, one workaround is to perform a regular OAuth dance once with a regular Google Account, and persist the access and refresh token in the datastore.

Http 400 in appengine when using URLFetch with Http Method 'DELETE'

I've been unable to make a "DELETE" request using the code below :
URLFetchService fetchService = URLFetchServiceFactory.getURLFetchService();
URL posturl = new URL("http://www.example.com/comment?token=xxx");
HTTPResponse response = fetchService.fetch(new HTTPRequest(posturl, HTTPMethod.DELETE));
int responseCode = response.getResponseCode();
This is for Google Appengine. The 'DELETE' request is for the facebook graph API. The above code gives me a status code 400 - Bad Request.
This is for face4j an open source java library that I've built for the facebook graph API.
This isn't really an App Engine problem; it just means that the destination webserver wouldn't accept your request.
If you're actually trying to send a DELETE to example.com, that's your problem. If that's supposed to be a scrubbed URL, you've omitted the detail that would facilitate troubleshooting.

Categories