Invalid delegate for mailbox in Gmail API - java

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.

Related

How to log in with a Google Service account in the Google Cloud?

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.

Create Google Drive channel for PUSH notification using Service Account

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"));

Making calls to Google service account without using domain admin user

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.

Youtube Video id by using Service account - got error 403 response

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.

Get the Post Of User On Google Plus

I got a problem on getting the post of user on google plus. I only have the access token and refresh token of this user ( not the ID !), how could i get the post from google plus of this user ?, i do searching a lot, but none of them meets my circumstance. When the user provide his google plus Id on the front end side, the access token and refresh token were generated and stored in database, i, on the backend side, will use these tokens to retrieve the post of this user.
p/s: I use this library https://code.google.com/p/google-plus-java-api/ because it looks so simple, i don't want to use so complicated library just for getting the post, thanks you guy a lot
here is my code
import com.googlecode.googleplus.GooglePlusFactory;
import com.googlecode.googleplus.Plus;
import com.googlecode.googleplus.model.activity.ActivityCollection;
import com.googlecode.googleplus.model.activity.ActivityFeed;
public void getInfo(String accessToken, String refreshToken) {
GooglePlusFactory factory = new GooglePlusFactory(clientId, clientSecret);
Plus plus = factory.getApi(accessToken, refreshToken,null);
if (plus != null) {
ActivityFeed af = plus.getActivityOperations().list("me",ActivityCollection.PUBLIC);
String firstpost = af.getItems().get(0).getObject().getContent();
}
, i got 403 error when call this method, the error output was :
403 Forbidden
{
"code" : 403,
"errors" : [ {
"domain" : "usageLimits",
"message" : "Daily Limit Exceeded. Please sign up",
"reason" : "dailyLimitExceededUnreg",
"extendedHelp" : "https://code.google.com/apis/console"
} ],
"message" : "Daily Limit Exceeded. Please sign up"
}
Actually, i think the reason is not because daily limit exceeded, because i got that message at the first time i run, i also turn the google+ api, google+ domain api on google api console. I suppose the error come from using the "me" in the "list" method to retrieve the post. I still dont' have any idea how to fix this problem
Updated #1#:
I have change my code a lot, so here is exactly what i stuck at, i already get a new accessToken, and (when it is still not expired) , i run this code below:
GoogleCredential credential = new GoogleCredential.Builder()
.setJsonFactory(JSON_FACTORY)
.setTransport(TRANSPORT)
.setClientSecrets(CLIENT_ID, CLIENT_SECRET).build().setAccessToken(newAccessToken);
// Create a new authorized API client.
Plus service = new Plus.Builder(TRANSPORT, JSON_FACTORY, credential)
.setApplicationName(APPLICATION_NAME)
.build();
// Get a list of people that this user has shared with this app.
ActivityFeed feed = service.activities().list("me", "public").execute()
then i got this error:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
{
"code" : 403,
"errors" : [ {
"domain" : "global",
"message" : "Insufficient Permission",
"reason" : "insufficientPermissions"
} ],
"message" : "Insufficient Permission"
}
Using "me" as the ID for the list call should work correctly, and your code generally appears correct.
The error message suggests that your client is unregistered. I would check to make sure of the following:
Make sure you have created a Client ID and Secret (and don't post them here!) for your project and you're passing them to the GooglePlusFactory correctly.
Make sure this project has the Google+ API turned on.
Make sure that the access token you're providing for the user corresponds to them authenticating to this same project
I solved this problem, everything is fine except 1 thing, that's is the access token and refresh token was created by some scopes but not the scopes Plus.me, that why's i can't request a new access token by using this refresh token, and then i got the insufficient permission error 403. So when i get the new access and refresh token by using the approriated scope, i can query with keyword "me". Hope you guy don't stuck like me, it takes me nearly 2 days to figure it out

Categories