How to use Service Accounts OAuth 2.0 flow with GroupsSettings-api - java

Using google-api-java-client at this page we can read about some flows.
The service accounts flow works fine with calendar api:
GoogleCredential credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId("[[]]")
.setServiceAccountScopes(CalendarScopes.CALENDAR)
.setServiceAccountPrivateKeyFromP12File(new File("key.p12")).build();
But we have always:
503 Service Unavailable
{
"code" : 503,
"errors" : [ {
"domain" : "global",
"message" : "Backend Error",
"reason" : "backendError"
} ],
"message" : "Backend Error"
}
if we use GroupssettingsScopes.APPS_GROUPS_SETTINGS (the api console grant access for this requests).
We have to use a mechanism near at the old 2 legged OAuth 1.0a for manage the groups of a GApps account.
Many thanks in advance

With the Groups Settings API, you will need to impersonate a Google Apps user. And that user needs to be an admin.
In addition, I personnally noticed that it is better to provide the service account id to the setServiceAccountId()method.
Here's what works for me :
GoogleCredential credential = new GoogleCredential.Builder().setTransport(new NetHttpTransport())
.setJsonFactory(new GsonFactory())
.setServiceAccountId("516444413363-4i0cvva2abc8a3t63bbq1a9rfqe42p70#developer.gserviceaccount.com")
.setServiceAccountScopes(Collections.singletonList("https://www.googleapis.com/auth/apps.groups.settings"))
.setServiceAccountUser("admin#my.doma.in")
.setServiceAccountPrivateKeyFromP12File(new File("key.p12")).build();

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.

Why are the new profile scopes breaking requests to Google Classroom API in my app?

I have an application set up to access the Google Classroom API. I have it authorized and can pull Course and Roster data. It's updated to use the V1 calls, but when I add in the Profile.Name and Profile.Email scopes, I get the following error:
{
"code" : 403,
"errors" : [ {
"domain" : "global",
"message" : "Unregistered request was blocked. Please sign up using Google Developers Console.",
"reason" : "forbidden"
} ],
"message" : "Unregistered request was blocked. Please sign up using Google Developers Console.",
"status" : "PERMISSION_DENIED"
}
The service account has been authorized in the admin console with all 4 relevant Classroom scopes. The Domain has also been confirmed as having the Classroom APIs enabled, if I attempt to use them through the OAuth playground it all works fine.
Any ideas as to why I'm getting the error only when I add in the profile scopes?
The issue was that we were required to fill in a second form for Google to authorize the domain, we'd only found the first one. After filling in the new form, it all started working.

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.

Gmail Java API Using GAE Service account

I am trying to read gmail messages using GAE Service account. The code similar to below works well to read Google calendar but fails for gmail. I have only one user in the domain (who is also the admin account). I am trying to access the gmail of that user). Any help on why my code fails would be great.
I have delegated domain wide authority for the following scopes.
Email (Read/Write/Send) https://mail.google.com/
https://www.googleapis.com/auth/admin.directory.user.readonly
Calendar (Read-Write) https://www.googleapis.com/auth/calendar
https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/userinfo.email
https://www.googleapis.com/auth/userinfo.profile
I have enabled below APIs in the Google App Engine:
Admin SDK
Calendar API
Drive API
Gmail API
Google Cloud SQL
Google Cloud Storage
Google Cloud Storage JSON API
Below is the code that creates gmail service:
// Create HTTP transport
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
// Create JsonFactory using com.google.api.client.json.jackson2.JacksonFactory
JsonFactory jsonFactory = new JacksonFactory();
// Get service accont (contain service account email and P12 file name)
BaseGoogleService.GoogleServiceAccount serviceAccount = getGoogleServiceAccount();
//load private key from class path to File object.
Resource resource = appContext.getResource("classpath:"+serviceAccount.getServiceAccountPrivateKeyFile());
File privateKeyFile = resource.getFile();
// Create Google credential for service account
List<String> accountScopes = new ArrayList<String>();
accountScopes.add(GmailScopes.MAIL_GOOGLE_COM);
Credential credential = new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setServiceAccountId(serviceAccount.getServiceAccountId())
.setServiceAccountScopes(accountScopes)
.setServiceAccountPrivateKeyFromP12File(privateKeyFile)
.build();
// Create Gmail client
Gmail gmailClient = new Gmail.Builder(httpTransport, jsonFactory, credential)
.build();
Code that reads gmail messages:
ListMessagesResponse response = gmailClient.users().messages().list(userEmail).setQ(query).execute()
I am getting below error when I execute this code
com.google.api.client.googleapis.json.GoogleJsonResponseException: 500 OK
{
"code" : 500,
"errors" : [ {
"domain" : "global",
"message" : "Backend Error",
"reason" : "backendError"
} ],
"message" : "Backend Error"
}
at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:145)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:312)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1049)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:410)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:343)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:460)
I was able to make it work.
Two things:
Have to add ".setServiceAccountUser(userEmail)" while building GoogleCredential. userEmail represents the email id to impersonate.
This cannot be done for admin account. I had to add a user to the domain and access that user's gmail.

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