I'm trying to create a channel in order to receive push notifications when an edit is made on a Google Spreadsheet. The code will be executed on an App Engine Standard Java8 project.
Because a channel can last a maximum of 24 hours, I'm creating a cron that will renew the channel every day.
Here is my configuration:
I created a service account: xxxx#yyyy.iam.gserviceaccount.com
I verified the domain: yyyy.appspot.com (in Webmaster Tools)
I added the domain to cloud console (section API & Services -> Domain Verification)
I created an endpoint which will handle push notification: https://yyyy.appspot.com/api/drive/push
The sheetId is: foo_bar (copied by the Spreadsheet browser url itself, like https://docs.google.com/spreadsheets/d/foo_bar/edit)
The service account is Can Edit on the Sheet
With the Java library google-api-services-drive:v3-rev102-1.23.0 I created this code
public static void main(String[] args) throws IOException {
String spreadsheetId = "foo_bar";
InputStream json = GoogleDriveApi.class.getClassLoader().getResourceAsStream("bar.json");
GoogleCredential credential = GoogleCredential.fromStream(json, new NetHttpTransport(), new JacksonFactory());
if (credential.createScopedRequired()) {
credential = credential.createScoped(Collections.singleton("https://www.googleapis.com/auth/drive.appdata"));
}
Drive service = new Drive.Builder(new NetHttpTransport(), new JacksonFactory(), credential).build();
Channel channel = new Channel();
channel.setAddress("https://example.com/api/drive/push");
channel.setType("web_hook");
channel.setId(UUID.randomUUID().toString());
Watch action = service.files().watch(spreadsheetId, channel);
System.out.println(action.execute().toPrettyString());
}
When I execute this code I get this error:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 404 Not Found
{
"code" : 404,
"errors" : [ {
"domain" : "global",
"location" : "fileId",
"locationType" : "parameter",
"message" : "File not found: foo_bar.",
"reason" : "notFound"
} ],
"message" : "File not found: foo_bar."
}
From documentation I quote
Each notification channel is associated both with a particular user
and a particular resource (or set of resources). A watch request will
not be successful unless the current user or service account owns or
has permission to access this resource.
In my case Service Account does not OWNS the resource (Spreadsheet) but indeed has permission on it (Can Edit permission, non only Can View)
Can a service account be used to create a channel on Google Drive?
file.watch API requires https://www.googleapis.com/auth/drive scope, in the main example I was using only https://www.googleapis.com/auth/drive.appdata
Using the following line the example works fine
credential = credential.createScoped(Collections.singleton("https://www.googleapis.com/auth/drive"));
Related
I created a service account and generated a json key. I want to execute a get request to get a project.
I using https://cloud.google.com/dns/docs/reference/v1/projects/get
public static Dns createDnsService() throws IOException, GeneralSecurityException {
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
String jsonPath = "testdns-320312-136950c1074b.json";
FileInputStream stream = new FileInputStream(jsonPath);
GoogleCredential credential = GoogleCredential.fromStream(stream);
if (credential.createScopedRequired()) {
credential =credential.createScoped(Arrays.asList("https://www.googleapis.com/auth/cloud-platform"));
}
return new Dns.Builder(httpTransport, jsonFactory, credential)
.setApplicationName("Google-DnsSample/0.1")
.build();
}
When executing the code, I get error:
Exception in thread "main" com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
GET https://dns.googleapis.com/dns/v1/projects/testdns-320312
{
"code" : 403,
"errors" : [ {
"domain" : "global",
"message" : "Forbidden",
"reason" : "forbidden"
} ],
"message" : "Forbidden"
}
#John Hanley is right - you lack proper permissions.
If you didn't assign any role to a service account after you created it you can't use it to do anything.
You need a roles/dns.admin role to be able to administer all the DNS records in your project.
You can do this with the following steps:
In the Google Cloud Console, go to the IAM page.
Go to the IAM page
Select your project from the top pull-down menu.
Click Add.
In New members, enter the email address of a new member.
Select the desired role from the drop-down menu.
Click Save.
Verify that the member is listed with the role that you granted.
Granting DNS admin role to this account will be the easiest way of getting control over Cloud DNS section of your project. If you need more fine-grained / limited access then you can create your custom role and assign it to this account instead of the basic one.
Here's more info about granting roles in GCP that you may find useful.
Very similar question was also answered here.
I am unable to create a google cloud storage bucket using the java sdk, below is the code I am using:
public class App
{
public static void main(String... args) throws Exception {
String projectId = "**********";
Storage storage = StorageOptions.newBuilder().setProjectId(projectId).build().getService();
Page<Bucket> buckets = storage.list();
for (Bucket bucket : buckets.iterateAll()) {
System.out.println(bucket.getName());
}
}
}
And this is the error message I am getting:
Caused by:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 401
Unauthorized { "code" : 401, "errors" : [ {
"domain" : "global",
"location" : "Authorization",
"locationType" : "header",
"message" : "Anonymous caller does not have storage.buckets.list access to project 833568054484.",
"reason" : "required" } ], "message" : "Anonymous caller does not have storage.buckets.list access to project 833568054484." }
You are not authenticating, you can check how to add permissions to your bucket on the Using Cloud IAM permissions documentation.
If you want to give access to authenticated users you have to select the user group allAuthenticatedUsers and give them the Storage Object Viewer Role. This will allow all authenticated users, even anonymously, view/list permissions in your bucket.
NOTE: As you can see on this documentation, the allAuthenticatedUsers member types should only be used when it is acceptable for anyone on the Internet to read and analyze your data. So you should consider a different access management type if that is not the case for you.
1.Create a service account
2.Creating a service account key for the service account just created. Remember the path where you store the key.json file.
3.Assign to the service account the role Storage Admin
4.Provide credentials to your application
a. Using env variable
export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/[FILE_NAME].json"
b. Explicit in code
static void authExplicit(String jsonPath) throws IOException {
// You can specify a credential file by providing a path to GoogleCredentials.
// Otherwise credentials are read from the GOOGLE_APPLICATION_CREDENTIALS environment variable.
GoogleCredentials credentials = GoogleCredentials.fromStream(new FileInputStream(jsonPath))
.createScoped(Lists.newArrayList("https://www.googleapis.com/auth/cloud-platform"));
Storage storage = StorageOptions.newBuilder().setCredentials(credentials).build().getService();
System.out.println("Buckets:");
Page<Bucket> buckets = storage.list();
for (Bucket bucket : buckets.iterateAll()) {
System.out.println(bucket.toString());
}
}
I am trying to get the Delegates for a mailbox using Gmail API.
My application is running on Google App-engine and has the feature of Add, Remove,Get Delegates using Email Setting API.
Now I am planning to migrate these features to Gmail API since Email setting API will be deprecated.
Technology wise I am using Java language.
I have followed all the steps provided by Gmail API documentation. Authentication to Gmail API is successful. But When I am trying to get the delegates it's giving following error-
404 Not Found
{
"code" : 404,
"errors" : [ {
"domain" : "global",
"message" : "Invalid delegate",
"reason" : "notFound"
} ],
"message" : "Invalid delegate"
}
And inside console below is the error -
*com.google.api.client.googleapis.json.GoogleJsonResponseException: 404 Not Found
{
"code" : 404,
"errors" : [ {
"domain" : "global",
"message" : "Invalid delegate",
"reason" : "notFound"
} ],
"message" : "Invalid delegate"
}
at
com.google.api.client.googleapis.json.GoogleJsonResponseException.fro
m(GoogleJsonResponseException.java:150)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClie
ntRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClie
ntRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest
$1.interceptResponse(AbstractGoogleClientRequest.java:321)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1067)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest
.executeUnparsed(AbstractGoogleClientRequest.java:419)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest
.executeUnparsed(AbstractGoogleClientRequest.java:352)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest
.execute(AbstractGoogleClientRequest.java:469)
at com.aeegle.services.GmailService.retrieveEmailDelegates(GmailService.
java:106)
at com.aeegle.DAOImpl.EmailDAOImpl.getDelegatesGmail(EmailDAOImpl.java:1
43)
at controllers.DelegateController.getListDelegatesGmail(DelegateControll
er.java:82)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
sorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at play.mvc.ActionInvoker.invokeWithContinuation(ActionInvoker.java:557)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:508)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:484)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:479)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:161)
at play.server.PlayHandler$NettyInvocation.execute(PlayHandler.java:255)
at play.Invoker$Invocation.run(Invoker.java:278)
at play.server.PlayHandler$NettyInvocation.run(PlayHandler.java:233)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:51
1)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.
access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.
run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.
java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor
.java:624)
at java.lang.Thread.run(Thread.java:748)*
You can observe GmailService line number 106 have an issue. Now I am going to Post my java code.
1: - Authentication Code -
public Gmail getGmailService(String email) throws Exception {
System.out.println("-------------getGmailService");
HttpTransport httpTransport = new NetHttpTransport();
JacksonFactory jsonFactory = new JacksonFactory();
Collection<String> SCOPES = new ArrayList<String>();
SCOPES.add(GmailScopes.GMAIL_SETTINGS_BASIC);
SCOPES.add(GmailScopes.MAIL_GOOGLE_COM);
SCOPES.add(GmailScopes.GMAIL_MODIFY);
SCOPES.add(GmailScopes.GMAIL_READONLY);
GoogleCredential credential;
// To load classpath resources.
ClassLoader classLoader = getClass().getClassLoader();
new File(SERVICE_ACCOUNT_PKCS12_FILE_PATH);
credential = new GoogleCredential.Builder().setTransport(httpTransport).setJsonFactory(jsonFactory)
.setServiceAccountId(SERVICE_ACCOUNT_EMAIL).setServiceAccountUser(email).setServiceAccountScopes(SCOPES)
.setServiceAccountPrivateKeyFromP12File(new File(SERVICE_ACCOUNT_PKCS12_FILE_PATH)).build();
System.out.println("----calling Builder");
service = new Gmail.Builder(httpTransport, jsonFactory, null).setHttpRequestInitializer(credential)
.setApplicationName(APPLICATION_NAME).build();
return service;
}
2:- Next trying to get the Delegates for the mailbox using service object-
public Delegate retrieveEmailDelegates(String user, Gmail service) throws Exception {
if (isBlankOrNullString(user)) {
throw new IllegalArgumentException();
}
Delegate delegatesResponse=null;
try {
System.out.println("Call retrieveEmailDelegates for "+user);
delegatesResponse = service.users().settings().delegates().get(user, "me").execute();
System.out.println("-------service" + delegatesResponse.getDelegateEmail());
} catch (Exception e) {
e.printStackTrace();
throw e;
}
return delegatesResponse;
}
Please help me on this since I am still running this in my localhost machine.
If you want to access other users email account, you must turn on mail delagation that allows the delegate to read, send, and delete on their behalf:
Sign in to your Google Admin console.
Note: Sign in using your administrator account (does not end in
#gmail.com).
From the Admin console Home page, go to Apps>Gsuite>Gmail> User Setting.
Next to Mail delegation, select Let users delegate access to their mailbox to other users in the domain.
(Optional) Select each organization containing users you want to enable mail delegation for and check the Mail Delegation box.
Click Save.
Once enabled, any user who wants to assign a delegate to access their email must set up on mail delegation in their Gmail account.
Disclaimer: I work on Gmail and the Gmail API platform.
Looks like you're trying to get a list of all delegates for an account, so you must use service.users().settings().delegates().list() instead of service.users().settings().delegates().get().
Note that this will require further changes to your code, to deal with the returned ListDelegatesResponse.
As an aside, you are receiving the "Invalid delegate" error because service.users().settings().delegates().get(user, "me") is supplying me as the email of the delegate you are attempting to retrieve. You'd need to supply a valid email address for the request to possibly succeed. However, I realize this is all likely due to your mistaken use of the Get delegate method instead of the List delegates method.
I am attempting to use the Directory API to update Google passwords for users in our domain. I've followed the example for the Plus service account, which is almost identical (https://github.com/google/google-api-java-client-samples/blob/master/plus-serviceaccount-cmdline-sample/src/main/java/com/google/api/services/samples/plus/serviceaccount/cmdline/PlusServiceAccountSample.java).
I'm trying to determine why I am required to pass in the email address of a super admin user to the setServiceAccountUser() in order to set user passwords on the domain. Is there a setting somewhere that will let me use the API without settings the serviceAccountUser?
I receive the message below when I comment out the setServiceAccountUser() call:
{
"code" : 403,
"errors" : [ {
"domain" : "global",
"message" : "Not Authorized to access this resource/api",
"reason" : "forbidden"
} ],
"message" : "Not Authorized to access this resource/api"
Here is the code (from the Plus sample) that is relevant:
// service account credential (uncomment setServiceAccountUser for domain-wide delegation)
GoogleCredential credential = new GoogleCredential.Builder().setTransport(httpTransport)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
.setServiceAccountScopes(Collections.singleton(PlusScopes.PLUS_ME))
.setServiceAccountPrivateKeyFromP12File(new File("key.p12"))
// .setServiceAccountUser("user#example.com")
.build();
Directory API write operations require an admin account. Either a super admin or a delegated admin who has rights to perform API user modifications. This is listed in the prerequisites document.
I’m developing Java code to retrieve Video Id for the corresponding asset id by using service account authentication.I have followed below mentioned steps.
Step 1: A Java program is written to retrieve the access token from Google authentication using service account.
the code is for getting access_token:
String EmailId = "XXXXXXXXXXX#developer.gserviceaccount.com";
//passing Scope
#SuppressWarnings({ "unchecked", "rawtypes" })
List<String>scops = new <String>ArrayList();
scops.add("https://www.googleapis.com/auth/youtubepartner");
final HttpTransport TRANSPORT = new NetHttpTransport();
final JsonFactory JSON_FACTORY = new JacksonFactory();
// Create a listener for automatic refresh OAuthAccessToken
List<CredentialRefreshListener> list = new ArrayList<CredentialRefreshListener>();
list.add(new CredentialRefreshListener() {
#Override
public void onTokenResponse(Credential credential,
TokenResponse tokenResponse) throws IOException {
System.out.println(tokenResponse.toPrettyString());
}
public void onTokenErrorResponse(Credential credential,
TokenErrorResponse tokenErrorResponse)
throws IOException {
System.err.println("Error: "
+ tokenErrorResponse.toPrettyString());
}
});
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(EmailId)
.setServiceAccountScopes(scops)
.setServiceAccountPrivateKeyFromP12File(new File("test.p12"))
.setRefreshListeners(list)
.build();
credential.refreshToken();
Step 2: The access token that is obtained in step 1 is passed as an argument in the below mentioned URL to get Youtube video id
Sample url is:
https://www.googleapis.com/youtube/partner/v1/claimSearch?assetId=xxxxxxxxx&onBehalfOfContentOwner=xxxxxxxx&status=active&access_token=ya29.-gCmzBHciDghrj2EDtBn1Vx0MV38pNLZTvqfwOyG0hNJCj75nsCBA5zaxmP1sr7UqI7ZrYI3AIZstA
I’m getting 403 error code in step 2.
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "accessNotConfigured",
"message": "Access Not Configured. The API is not enabled for your project, or there is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your configuration.",
"extendedHelp": "https://console.developers.google.com"
}
],
"code": 403,
"message": "Access Not Configured. The API is not enabled for your project, or there is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your configuration."
}
}
already enabled “GOOGLE COULD JSON API” and “YOUTUBE DATA API”.
Could any one please help me to resolve this issue?
I know from working on a previous project that you need to enable the API in the Google console. I would try that first.
https://code.google.com/apis/console
You try to use Youtube's Content ID API endpoint /youtube/partner/v1/claimSearch.
This endpoint is not part of the Youtube Data API and you can only access it if you participate in the "Youtube Partner Program". Otherwise it is not even listed in the Developer's Console.
Further information here: https://developers.google.com/youtube/partner/
Note: The YouTube Content ID API is intended for use by YouTube content partners and is not accessible to all developers or to all YouTube users. If you do not see the YouTube Content ID API as one of the services listed in the Google Developers Console, see www.youtube.com/partner to learn more about the YouTube Partner Program.