Use a service account to get the list of users from Google domain - spring-boot

Hello all.
I have been assigned the task of fetching unanswered emails from the inbox of each member of our Google domain using Spring Boot, but I haven't been able to do it.
In first place, I need the list of users from the domain. This can be achieved via Directory API (which cannot be enabled by that name in the Google Developer console, by the way. Looks like it belongs to Admin SDK or so).
What I have faced so far is this:
There are many related questions on SO, but most of them are outdated.
Java Quickstart for Google Directory API does not include an example using service accounts, and I want to use them because my app runs in a docker container, and using Oauth means I need to manually authorize it every time I deploy a new version or restart the container.
Google documentation makes reference to "API Reference" settings in Admin console, but I don't see that section there.
I am not storing credentials in a JSON file, I have them in an environment variable instead. I am doing this:
var inputStream = IOUtils.toInputStream(apiCredentials, Charset.defaultCharset()); //apiCredentials is a string with the JSON contents.
var credential = GoogleCredential
.fromStream(inputStream, httpTransport, JacksonFactory.getDefaultInstance())
.createScoped(Collections.singleton(DirectoryScopes.ADMIN_DIRECTORY_USER));
var directoryService = new Directory.Builder(httpTransport, JacksonFactory.getDefaultInstance(), credential)
.setApplicationName("My App")
.build();
var result = directoryService.users().list()
.setPageToken(pageToken)
.setDomain("my.domain")
.setMaxResults(10)
.execute();
After this, I get a 400 Bad request error, with no further description.
What am I doing wrong here?

Related

Error after changing my Application ID URI to CDN endpoint

I'm trying to deploy my application built on the team toolkit scaffolding for multi-tenant. I created a CDN endpoint and updated my state JSON object to reflect the new front-end endpoint. After provisioning, deploying and making the account setting change to multi-tenant. I uploaded my app to our company tenant and I'm getting the following error in my tab configuration where the user is supposed to be able to log in.
OutOfRangeInputOne of the request inputs is out of range. RequestId:47fca9cc-f01e-004a-7a11-e434e9000000 Time:2022-10-19T23:24:05.3740757Z
Is there any workaround to get a team's toolkit app to be multi-tenant supported? I am trying to get this app validated for the teams store.
You can follow the steps here to enable multi-tenant in Teams Toolkit:
Provision your Tab project.
Open .fx\states\state.{envName}.json and note the value ofdomain under fx-resource-front-hosting.
Create Azure CDN and CDN endpoint and point to frontend storage. Note you need to choose endpoint type as Storage static website when creating your CDN.
Open templates\azure\provision\azureStorageTab.bicep file, and find the following two lines:
output endpoint string = 'https://${siteDomain}'
output domain string = siteDomain
and replace with:
output endpoint string = 'https://sample.azureedge.net'
output domain string = 'sample.azureedge.net'
Open templates/appPackage/aad.manifest.json, find signInAudience and set value as AzureADMultipleOrgs
Open .fx/configs/azure.parameter.${env}.json and find the following line:
"m365TenantId": "{{state.fx-resource-aad-app-for-teams.tenantId}}",
and replace with:
"m365TenantId": "common",
Run Provision and Deploy in your project.

Get Google Sheet Data using V4 API without OAuth

Using this nodeJS example, I could get the data from a public sheet.
But how do I get the data from a non-public sheet owned by me (my google a/c) ?
Is there some way to send in the username and password as arguments ?
I don't want OAuth way as I want the data to be pulled from the sheet & displayed on a public webpage.
The other option I can think of is to have OAuth2 done once write a script to handle refresh tokens automatically as a cron every hour ?
Since this is a file that you the developer own i would recommend using a service account
If you share the file with the service account it will then have permissions to access it without you needing to go though the oauth2 steps of authorizing your application.
On google cloud console simply create Service account credentials
const {google} = require('googleapis');
const auth = new google.auth.GoogleAuth({
keyFile: '/path/to/your-secret-key.json',
scopes: ['https://www.googleapis.com/auth/spreadsheets'],
});
Then change your auth code slightly. Open the service account key file and look for the service account email address its the only one witha # in it. Share the file with the service account like you would any other user in google drive web app.
Once it has access you shouldn't need to authorize the app again.
I have a video on Google drive API upload file with Nodejs + service account which might help you a bit you just need the authorization code. Everything else you have should work as is.

.Net - Google Play Download Sales Reports

I have a .Net Core application attempting to download the latest sales reports from my Google Play account to view and track sales statistics. These reports are stored on a Google Cloud Storage bucket "owned"/managed by the Google Play Store.
I've been unable to find many other examples or related issues in .Net and have been experiencing a storage permission issue.
I'm following the rather limited guide here: https://support.google.com/googleplay/android-developer/answer/6135870#export under "Download reports using a client library and service account"
Step 1: Create a service account
I've created a new service account for a new project as shown below. I've also granted that service account permissions for all storage objects as shown.
Step 2: Add the service account on your play console
I've also invited this new service account user to my play console and granted it permissions to the app to view it's information and financial reports.
Step 3: Fetch reports using an API call
I've created and downloaded a .JSON key for the service user.
// Scope as specified in https://support.google.com/googleplay/android-developer/answer/6135870#export
string[] scopes = new string[] { "https://www.googleapis.com/auth/devstorage.read_only" };
// Import JSON credential
var credential = GoogleCredential.FromFile(Path.Combine(Environment.CurrentDirectory, "keys/googleplay.json")).CreateScoped(scopes);
// Bucket ID of Google Play Store - Found from reports page "Copy URL"
string bucketId = "pubsite_prod_5XXXXXXXXX2";
var storage = StorageClient.Create(credential);
var bucketObjects = storage.ListObjects(bucketId);
foreach (var bucketObject in bucketObjects)
{
Console.WriteLine(bucketObject.Name);
}
This results in a permission error:
Google.Apis.Requests.RequestError\r\nsupportapp-googleplay#ascendant-nova-300105.iam.gserviceaccount.com does not have storage.objects.list access to the Google Cloud Storage bucket. [403]\r\nErrors [\r\n\tMessage[supportapp-googleplay#ascendant-nova-300105.iam.gserviceaccount.com does not have storage.objects.list access to the Google Cloud Storage bucket.
The service account I've created has the storage.objects.list permission and has been invited to my Play Console as well (as shown in the screenshots). This is a storage bucket hosted/owned by Google Play and not me. How can this permissions issue be resolved to allow my linked account to access Google Play's sales reports via API?
I came back in the morning and magically things now work.
I have also changed to using fromStream instead of fromFile when creating the Google credential.
Changed:
string[] scopes = new string[] { "https://www.googleapis.com/auth/devstorage.read_only" };
var credential = GoogleCredential.FromFile(Path.Combine(Environment.CurrentDirectory, "keys/googleplay.json")).CreateScoped(scopes);
To:
GoogleCredential credential;
using (var stream = new FileStream(Path.Combine(Environment.CurrentDirectory, "keys/googleplay.json"), FileMode.Open, FileAccess.Read))
{
credential = GoogleCredential.FromStream(stream).CreateScoped(scopes);
}
However, both of these credential creation systems work just fine... Perhaps it took Google 12 hours to sync the permissions? Hopefully this example can help someone else out in the future.

Classroom API - Access classroom with Service Account

I need some help as I'm really stuck!!!! I have spent days and hours on this one but I can't figure it. I have searched all possible forums and other similar posts without any success.
So, the requirement :
We are trying to integrate Classroom API on our .Net platforms. The tricky part is that they want to use service accounts.
The problem :
Google.Apis.Requests.RequestError The caller does not have permission [403]
The caller does not have permission] Location[ - ] Reason[forbidden] Domain[global]
I have followed the documentation as shown in :
https://developers.google.com/identity/protocols/OAuth2ServiceAccount.
I understand that we need to set up a service account in the Google API Console, so I've done the following:
1) I have created a service account and enabled G Suite Domain-wide Delegation in the Google API Console
2) In the Admin Console, in Manage API Client Access, I have entered the service account's client id and have enabled scopes.
3) A have downloaded the json file with all the service account credentials (private key, email)
and the code...
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(cr.client_email)
{
Scopes = new[] { ClassroomService.Scope.ClassroomCourses },
}.FromPrivateKey(cr.private_key));
// Create the service.
service = new ClassroomService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Demo-School",
});
and the actual call to the Classroom API to create a course :
var resource = service.Courses.Create(course);
var result = await resource.ExecuteAsync();
So, despite all that, whenever i try to create a course, I get the above error.
When I try to create a Course using the Reference page (https://developers.google.com/classroom/reference/rest/v1/courses/create) it works fine. I can create courses, teachers, set permissions etc..
But when I try to do that programmatically.. i.e from a console app, there is NO way I can get it working.
Can ANYONE please advice???????What am I missing??

Oauth2 on Google Contacts API For DotNet - Token Invalid – AuthSub token has wrong scope

I have created a class that authorises a vb.net app to access Google Fusion Tables using Oauth2. It opens a web browser in a form if needed, encrypts and stores the refresh token, and it works well. I can access the fusion tables data.
However, I would also like to access Contacts. I have requested access to Contacts from the user.
I can retrieve the AccessToken that works for fusion tables and have tried different techniques to get things working on contacts, but no luck. I keep getting a 401-unauthorised error. But I can get Contacts working if I use clientlogin.
Any help would be much appreciated.
My latest try:
Dim rs As New RequestSettings("App Name", p.AccessToken) 'String retrieved from class
Dim cr As New ContactsRequest(rs)
Dim q As New FeedQuery
q.Uri = New Uri("http://www.google.com/m8/feeds/contacts/<EMAIL>/full/<IDCODE>")
Dim c As New Contact
c = cr.Retrieve(Of Contact)(q)
You have to request access to the Contacts API OAuth scope, which is https://www.google.com/m8/feeds/.
The .NET client library includes an OAuth 2.0 sample that uses the Contacts API:
https://code.google.com/p/google-gdata/source/browse/trunk/clients/cs/samples/oauth2_sample/oauth2demo.cs
Thank you to Claudio Cherubino for the suggestion. I was actually already using that scope. Thankfully, I have now, finally, found the answer.
I was literally missing a single letter:
q.Uri = New Uri("http://www.google.com/m8/feeds/contacts/<EMAIL>/full/<IDCODE>")
... is wrong, as the scope I requested was indeed:
https://www.google.com/m8/feeds/
So the Uri needed to match, with httpS. I added the 's' and it works. Correct code below:
q.Uri = New Uri("https://www.google.com/m8/feeds/contacts/<EMAIL>/full/<IDCODE>")
Many thanks for this post for the answer:
http://www.geoffmcqueen.com/2010/03/14/token-invalid-authsub-token-has-wrong-scope-oauth-google-problem

Resources