Google App Engine GoogleCredential getApplicationDefault - google-app-engine

I am trying to use GoogleCredential getApplicationDefault() to get access to the app engine default service account which I have already created using app engine dashboard. The code is as shown below.
try{
GoogleCredential credential = GoogleCredential.getApplicationDefault();
if (credential.createScopedRequired()){
ArrayList<String> scope = new ArrayList<String>();
scope.add("https://www.googleapis.com/auth/devstorage.read_write");
GoogleCredential scopedCredential = credential.createScoped(scope);
scopedCredential.refreshToken();
return scopedCredential.getAccessToken();
}
}
catch(Exception ex){
entityException = new Entity(Constants.ENTITY_EXCEPTION);
entityException.setProperty("Exception",ex.getMessage());
datastore.put(entityException);
}
return "";
When scopedCredential.refreshToken() is called an exception happens with the message accounts.google.com
Also when I call scopedCredential.getServiceAccountId() and scopedCredential.getServiceAccountPrivateKeyId() I am getting the correct values of the default app engine service account.
Can anyone please help me with this.
Guys,
Can someone help me? I tried adding a new service account, created a p12 file instead of json etc. nothing seems to work. I hv no idea where I m going wrong. Please help.

Hey all I figured it out myself. I specified runtime as java8 and that was causing all the problems. guess these work only on java7 runtime. thanks.

Related

Migrating to firebase from channel api

I am trying to migrate from Channel API in GAE to firebase. To do this, first, I am trying to setup a local development environment. I cloned the sample app from GAE samples. (Link to sample)
When I ran this, I get the following error, when the web client is trying to authenticate with the firebase DB.The error is in the console.
Screenshot of the error
i.e token authentication failed.Clearly, this points to the fact that generated JWT is not correct.
To be sure, I have done the following:
Created a service account in Google cloud console.
Downloaded the JSON and pointed to this JSON in the environment variable "GOOGLE_APPLICATION_CREDENTIALS"
Put the code snipped from the firebase into WEB-INF/view/firebase_config.jspf file
The code to generate the token is as follows ( from FirebaseChannel.java )
public String createFirebaseToken(Game game, String userId) {
final AppIdentityService appIdentity = AppIdentityServiceFactory.getAppIdentityService();
final BaseEncoding base64 = BaseEncoding.base64();
String header = base64.encode("{\"typ\":\"JWT\",\"alg\":\"RS256\"}".getBytes());
// Construct the claim
String channelKey = game.getChannelKey(userId);
String clientEmail = appIdentity.getServiceAccountName();
System.out.println(clientEmail);
long epochTime = System.currentTimeMillis() / 1000;
long expire = epochTime + 60 * 60; // an hour from now
Map<String, Object> claims = new HashMap<String, Object>();
claims.put("iss", clientEmail);
claims.put("sub", clientEmail);
claims.put("aud", IDENTITY_ENDPOINT);
claims.put("uid", channelKey);
claims.put("iat", epochTime);
claims.put("exp", expire);
System.out.println(claims);
String payload = base64.encode(new Gson().toJson(claims).getBytes());
String toSign = String.format("%s.%s", header, payload);
AppIdentityService.SigningResult result =
appIdentity.signForApp(toSign.getBytes());
return String.format("%s.%s", toSign,
base64.encode(result.getSignature()));
}
Instead of Step #2, have also tried 'gcloud auth application-default login' and then running after unsetting the environment variable - resulting in the same issue
Appreciate any help in this regard.
After further research, I found out additional info which may help others facing the same issue. I did the following to be able to run the sample locally.
Its important to ensure that the service account in appengine has the permissions to access resources. Chose "Editor" as the role for permissions (other levels may also work, but I chose this) for the default appengine service account. This will ensure that you do not run into "Unauthorized" error.
My application was enabled for domain authentication and did not use Google authentication. The sample however has been created for Google authentication. I had to make changes to the sample code to send the userId as part of the URL and removed the code that referred to UserServiceFactory.
The console error did show up even now, but the application worked fine. This error probably can be ignored. In the deployed environment, however, this error does not show up.
I would appreciate if Google/Firebase engineers update this answer with official responses, or update the sample documentation appropriately as currently this information does not seem to be mentioned anywhere.

Authenticate service account without downloaded key on google app engine

I am working on a product that is supposed to be installed in Google App Engine.
In this I am using Service account for authenticating Gmail API, Drive API, Calendar API etc.
Its working fine with downloaded P12 file as authentication. But as its product I don't want client to download and upload on app on every install.
Can there be a way to authenticate it without privatekey file or using that API without service account.
In below page its mentioned that there is System-managed key-pairs are managed automatically by Google. Can it be helpful? I did't find any example of it.
https://cloud.google.com/iam/reference/rest/v1/projects.serviceAccounts.keys
In below link it suggest that for Google Cloud Platform I should use Google Managed Key
https://cloud.google.com/iam/docs/understanding-service-accounts
Can this key used without downloaded file ?
Thanks
I could achieve it by IAM API
https://cloud.google.com/iam/reference/rest/v1/projects.serviceAccounts.keys
Below is Java code for it
AppIdentityCredential credential = new AppIdentityCredential(
Arrays.asList("https://www.googleapis.com/auth/cloud-platform"));
Iam iam = new Iam(httpTRANSPORT, jsonFACTORY, credential);
try {
Iam.Projects.ServiceAccounts.Keys.Create keyCreate = iam.projects().serviceAccounts().keys()
.create("projects/myProject/serviceAccounts/myProject#appspot.gserviceaccount.com", new CreateServiceAccountKeyRequest());
ServiceAccountKey key = keyCreate.execute();
} catch (IOException e) {
System.out.println(e.getMessage());
}
Any key can be used to generate GoogleCredential as below
InputStream stream = new ByteArrayInputStream(key.decodePrivateKeyData());
GoogleCredential credential = GoogleCredential.fromStream(stream);

Google App Engine connection request timeout error

I am working on a GAE web app which shows movie related data.To get the movie data I am using API from OMDB (http://www.omdbapi.com/) .Below is the code snippet I use to connect to the API.
When i run it locally it works perfectly fine, but doesn't work when deployed on GAE. It throws connection timeout exception, i tried increasing connection timeout period but that didn't work.
String URLstr = "http://www.omdbapi.com/?t="+URLEncoder.encode(Request,"utf-8");
URL url=null;
URLConnection uc = null;
BufferedReader bf = null;
try {
url= new URL(URLstr);
uc = url.openConnection();
uc.setConnectTimeout(15* 1000);
bf = new BufferedReader(new InputStreamReader(uc.getInputStream()));
} catch (IOException e) {
throw new IllegalArgumentException(e.getMessage());
}
Is my code incorrect? are there some restrictions with GAE that i missed?
Your code looks correct. I am having the exact same issue with OMDB API and Google App Engine as of a few weeks ago. I reached out to Brian who runs OMDB API regarding this and I think it had to do with the App Engine IP range being blocked because of abuse a few weeks ago.
I created the following webapp to figure out what external IP address the url fetch from my app was showing up as to the OMDB servers. I deployed the following to GAE to get the public IP.
import webapp2
import logging
from google.appengine.api import urlfetch
class ifconfig(webapp2.RequestHandler):
def get(self):
url="http://ipecho.net/plain"
urlfetch.set_default_fetch_deadline(60)
result = urlfetch.fetch(url)
logging.debug("I think my external IP is %s " % result.content)
self.response.write(result.content)
app = webapp2.WSGIApplication([
('/ifconfig', ifconfig)
])
In Google App Engine, I went to the instances tab and shutdown the instance, and checked what external IP the new instance had. I did this several times, and in my case it seemed like the external IPs were all coming from 107.178.195.0/24, so I provided this information to OMDB API.
I guess this was in the banned IP block, and Brian was able to unblock that range. This fixed my issue and requests to the API started working again.
This possibly might have resolved the issue for you as well, but if it didn't, you might want to figure out what your public IP is and reach out to Brian to see if it's in an IP range that's being blocked

Google Drive Access using AuthSubUtil.exchangeForSessionToken

On Google AppEngine i have been through authentication for Google Docs ... access using AuthSub authshub.
We managed to AuthSubUtil.exchangeForSessionToken(..).
QUESTION: Is it possible to follow up and get Access to Google Drive using this token?
... new Drive.Builder(httpTransport, jsonFactory, credential);
I'm not sure if AuthSub works with the Google Drive API, but if it does, this code snippet should resolve your problem:
new Drive.Builder(httpTransport, jsonFactory, new HttpRequestInitializer() {
#Override
public void initialize(HttpRequest request) {
HttpHeaders headers = request.getHeaders();
// Not sure if this test is necessary as headers might never be null.
if (headers == null) {
headers = new HttpHeaders();
request.setHeaders(headers);
}
headers.setAuthorization("AuthSub token=\"<TOKEN>\"");
}
}).build();
Important: please be aware that AuthSub is being deprecated and you should try to migrate your application to use OAuth 2.0 as soon as you can.

Cannot read file from cloud storage

Code to read file
boolean lockForRead = false;
String filename = "/gs/smsspamfilteraptosin/Data";
AppEngineFile readableFile = new AppEngineFile(filename);
FileReadChannel readChannel = fileService.openReadChannel(readableFile, lockForRead);
BufferedReader reader = new BufferedReader(Channels.newReader(readChannel, "UTF")); => I think something went wrong here.I put a string test and after this line the string test was null.
String line = reader.readLine();
Path in cloud storage
smsspamfilteraptosin/Data
ACL Permission for app
FULL_CONTROL
When I tried printing out line, the result was null.
And this is what I saw in the admin log : API serving not allowed for this application
Can somebody tell me what I did incorrectly?
Thank you.
I'm getting the same "API serving not allowed for this application" error when I try to follow the tutorial at: http://www.youtube.com/watch?v=v9TG7OzsZqQ
My Cloud Endpoint REST API works well on my local development machine, but is not visible when
when I deploy to App Engine.
Is it possible that this "API serving not allowed for this application" is the result of a dependency on a paid feature that we don't have enabled?
Update: Check GAE: API serving not allowed for this application for a (partial?) solution.
You didn't do something listed in the prerequisites, and this is preventing you from using GCS from app engine.

Resources