Getting domain installs for my Google Docs Add-on - google-apps-script

We have a Google-docs Add-on (built on Google Apps Script) for which we enabled the Google Apps Marketplace SDK - so that Google Apps Administrators could install our add-on at the domain level.
We have noticed a few domains have now installed our add-on - but I can't seem to find a way to get information on which domains have installed us. Is it even possible?
I have tried the Marketplace license API https://developers.google.com/apps-marketplace/v2/reference/ but it fails with a 403 error - Not authorized to access the application ID.
{
"error": {
"errors": [
{
"domain": "global",
"reason": "forbidden",
"message": "Not authorized to access the application ID"
}
],
"code": 403,
"message": "Not authorized to access the application ID"
}
}
I even tried by creating a service account and accessed the API using the service account but got the same error.
Any input would be awesome.
Here's my Java (Groovy technically) code so far (the response is the json I've pasted above):
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport
import com.google.api.client.http.GenericUrl
import com.google.api.client.http.HttpRequest
import com.google.api.client.http.HttpRequestFactory
import com.google.api.client.http.HttpTransport
import com.google.api.client.json.JsonFactory
import com.google.api.client.json.jackson2.JacksonFactory
import org.springframework.security.access.annotation.Secured
class DataController {
/**
* Be sure to specify the name of your application. If the application name is {#code null} or
* blank, the application will log a warning. Suggested format is "MyCompany-ProductName/1.0".
*/
private static final String APPLICATION_NAME = "My app name";
private static final String APPLICATION_ID = "12 digit project number";
/** E-mail address of the service account. */
private static final String SERVICE_ACCOUNT_EMAIL = "12digitproejectnumber-compute#developer.gserviceaccount.com";
/** Global instance of the HTTP transport. */
private static HttpTransport httpTransport;
/** Global instance of the JSON factory. */
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
def getLicensedInfo() {
try {
try {
httpTransport = GoogleNetHttpTransport.newTrustedTransport();
GoogleCredential credential = new GoogleCredential.Builder().setTransport(httpTransport)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
.setServiceAccountScopes(Collections.singleton("https://www.googleapis.com/auth/appsmarketplace.license"))
.setServiceAccountPrivateKeyFromP12File(new File("a/valid/path/to/key.p12"))
.build();
credential.refreshToken();
String token = credential.getAccessToken();
HttpRequestFactory requestFactory = httpTransport.createRequestFactory(credential);
GenericUrl url = new GenericUrl("https://www.googleapis.com/appsmarket/v2/licenseNotification/"+APPLICATION_ID);
HttpRequest request = requestFactory.buildGetRequest(url);
com.google.api.client.http.HttpResponse response = request.execute();
log.debug(response.parseAsString());
return;
} catch (IOException e) {
System.err.println(e.getMessage());
}
} catch (Throwable t) {
t.printStackTrace();
}
}
}

When making the request to the GAM License API you need to use the same Google Developers Console project that you used for your listing. In the case of an add-on, this is the console project associated with the script.

Related

Google Drive API to identify the changes in files

I have a list of files and folder stored on a google drive folder. My objective is to identify any changes (modify/create/delete) related to any file/folder within a particular google drive folder i.e get the list of these file name and their drive path.
I have not registered any domain as our spring boot application is deployed on K8's pod and I do not want any notification on any domain or any webhook address. I only want the list of files being modified/deleted when I call the below method/api
Below is the code snippet for spring boot application.
#Component
public class DriveServiceProvider {
#Autowired
private DriveConfig dc;
public Drive getDriveService() throws IOException, GeneralSecurityException {
final GoogleCredentials credentials = GoogleCredentials
.fromStream(new ByteArrayInputStream(new JSONObject(dc.getCred()).toString().getBytes()))
.createScoped(Collections.singletonList("https://www.googleapis.com/auth/drive"));
HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(credentials);
return new Drive.Builder(GoogleNetHttpTransport.newTrustedTransport(), JacksonFactory.getDefaultInstance(), requestInitializer)
.setApplicationName(ApplicationConstants.APPLICATION_NAME).build();
}
}
Controller:
#RestController
#RequestMapping("/admin/watch")
public class TestGoogleWatchController {
#Autowired
private DriveServiceProvider driveServiceProvider;
#PostMapping(value = "/googleWatchNotification")
#ResponseStatus(HttpStatus.OK)
public Channel getNotification() throws IOException, GeneralSecurityException {
try {
StartPageToken pageToken = driveServiceProvider.getDriveService().changes().getStartPageToken().execute();
String savedStartPageToken = pageToken.getStartPageToken();
System.err.println(" savedStartPageToken "+savedStartPageToken );
while (savedStartPageToken != null) {
ChangeList changes = driveServiceProvider.getDriveService().changes().list(savedStartPageToken).execute();
System.err.println("======= changes " + changes.toPrettyString());
System.err.println("============ size ::" + changes.getChanges().size());
System.err.println("============ ChangeList ::" + changes.getChanges());
for (Change changeObj : changes.getChanges()) {
System.err.println(" files "+changeObj.getFileId() + " Kind "+changeObj.getKind() + ", Team Drive ID "+changeObj.getTeamDriveId() + ", Type::"+changeObj.getType()+ ",File ::"+changeObj.getFile()+ ", Is Removed::"+changeObj.getRemoved()+ ",Time ::"+changeObj.getTime());
}
}
}catch(Exception ex) {
}
return null;
}
}
*Below is the output after executing:
savedStartPageToken 165
======= changes {
"changes" : [ ],
"kind" : "drive#changeList",
"newStartPageToken" : "165"
}
============ size ::0
============ ChangeList ::[]*
The savedStartPageToken is printing incrementing numeric value after we change anything in drive, however there the ChangeList is always blank.
I am glad that I am answering my own question. The issue was that I was passing the current token in the changeList api.
Actually, the solution is to find the changes since last token till the current token using a loop.

Google Drive 403 Forbidden error

there are already a few people that have asked questions in regards to this, but I still wasn't able to solve my problem.
So, I did the gradle/java quickstart to Print the names and IDs for up to 10 files in my Googledrive. That was fine, but I want to write a java script to upload files on my drive, I inserted the main function below in my java file.
public class DriveCommandLine {
/** Application name. */
private static final String APPLICATION_NAME =
"Drive API Java Quickstart";
/** Directory to store user credentials for this application. */
private static final java.io.File DATA_STORE_DIR = new java.io.File(
System.getProperty("user.home"), ".credentials/drive-java-quickstart");
/** Global instance of the {#link FileDataStoreFactory}. */
private static FileDataStoreFactory DATA_STORE_FACTORY;
/** Global instance of the JSON factory. */
private static final JsonFactory JSON_FACTORY =
JacksonFactory.getDefaultInstance();
/** Global instance of the HTTP transport. */
private static HttpTransport HTTP_TRANSPORT;
/** Global instance of the scopes required by this quickstart.
*
* If modifying these scopes, delete your previously saved credentials
* at ~/.credentials/drive-java-quickstart
*/
private static final List<String> SCOPES =
Arrays.asList(DriveScopes.DRIVE_METADATA_READONLY);
static {
try {
HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
DATA_STORE_FACTORY = new FileDataStoreFactory(DATA_STORE_DIR);
} catch (Throwable t) {
t.printStackTrace();
System.exit(1);
}
}
/**
* Creates an authorized Credential object.
* #return an authorized Credential object.
* #throws IOException
*/
public static Credential authorize() throws IOException {
// Load client secrets.
InputStream in =
DriveCommandLine.class.getResourceAsStream("/client_secret.json");
GoogleClientSecrets clientSecrets =
GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
// Build flow and trigger user authorization request.
GoogleAuthorizationCodeFlow flow =
new GoogleAuthorizationCodeFlow.Builder(
HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
.setDataStoreFactory(DATA_STORE_FACTORY)
.setAccessType("offline")
.build();
Credential credential = new AuthorizationCodeInstalledApp(
flow, new LocalServerReceiver()).authorize("user");
System.out.println(
"Credentials saved to " + DATA_STORE_DIR.getAbsolutePath());
return credential;
}
/**
* Build and return an authorized Drive client service.
* #return an authorized Drive client service
* #throws IOException
*/
public static Drive getDriveService() throws IOException {
Credential credential = authorize();
return new Drive.Builder(
HTTP_TRANSPORT, JSON_FACTORY, credential)
.setApplicationName(APPLICATION_NAME)
.build();
}
public static void main(String[] args) throws IOException{
//Insert a file
Drive service = getDriveService();
File body = new File();
body.setDescription("A test document");
body.setMimeType("text/plain");
java.io.File fileContent = new java.io.File("D:\\MyFiles\\nkonstantinidis\\Study\\IntelliJ_Shortcuts.txt");
FileContent mediaContent = new FileContent("text/plain", fileContent);
File file = service.files().insert(body, mediaContent).execute();
System.out.println("file ID: " + file.getId());
}
}
And I'm getting an error message shown below when I run it
Exception in thread "main" com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
{
"code" : 403,
"errors" : [ {
"domain" : "global",
"message" : "Insufficient Permission",
"reason" : "insufficientPermissions"
} ],
"message" : "Insufficient Permission"
}
at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:146)
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.executeUnparsed(AbstractGoogleClientRequest.java:432)
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 DriveCommandLine.main(DriveCommandLine.java:114)
I have created the OAuth client ID and enabled google drive but this still doing it's thing.
Could you maybe help me, or even better direct to tutorial for uploading files on google drive, I'm quite bad in Java so bear with me.
Thanks in advance.
You must change SCOPE used for connection (Insufficient Permission message) into appropriate one
private static final List<String> SCOPES = Arrays.asList(DriveScopes.DRIVE_METADATA_READONLY);
From DriveScope.class:
/** View and manage the files in your Google Drive. */
public static final String DRIVE = "https://www.googleapis.com/auth/drive";
/** View and manage its own configuration data in your Google Drive. */
public static final String DRIVE_APPDATA = "https://www.googleapis.com/auth/drive.appdata";
/** View and manage Google Drive files and folders that you have opened or created with this app. */
public static final String DRIVE_FILE = "https://www.googleapis.com/auth/drive.file";
/** View and manage metadata of files in your Google Drive. */
public static final String DRIVE_METADATA = "https://www.googleapis.com/auth/drive.metadata";
/** View metadata for files in your Google Drive. */
public static final String DRIVE_METADATA_READONLY = "https://www.googleapis.com/auth/drive.metadata.readonly";
/** View the photos, videos and albums in your Google Photos. */
public static final String DRIVE_PHOTOS_READONLY = "https://www.googleapis.com/auth/drive.photos.readonly";
/** View the files in your Google Drive. */
public static final String DRIVE_READONLY = "https://www.googleapis.com/auth/drive.readonly";
/** Modify your Google Apps Script scripts' behavior. */
public static final String DRIVE_SCRIPTS = "https://www.googleapis.com/auth/drive.scripts";
Remember to delete saved credentials (created by application) after changing SCOPE

Google Drive REST API (Server to Server): no binding with account files

I try getting list of Google Drive files from my application (simple Google account)(https://developers.google.com/identity/protocols/OAuth2ServiceAccount)
List with OAuth2 authorization work perfect: https://developers.google.com/drive/v3/reference/files/list#try-it
I've create service account with delegation to Google Apps domain (https://console.developers.google.com/iam-admin/serviceaccounts):
and download json service key.
Apply to GD from application:
private static HttpTransport HTTP_TRANSPORT;
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
static {
try {
HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
} catch (Throwable t) {
t.printStackTrace();
System.exit(1);
}
}
public static void main(String[] args) throws IOException {
Credential credential = GoogleCredential
.fromStream(new FileInputStream(".\\config\\google_drive_api.json"))
.createScoped(DriveScopes.all());
Drive service = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential).setApplicationName("javawebinar-1314").build();
FileList result = service.files().list().execute();
List<File> files = result.getFiles();
System.out.println(files.size());
API work: result at the beginning was single "Getting started" file, now result is 0. It seems that service account has no any relation to my own and delegating to doman has no meening for me as I have no domain account.
Are there any possibility to manage my simple google account google drive files by REST API ?

google drive client library invalid grant error on file upload

I always get this error when trying to add files under a folder in google drive, the folder is marked shared with mode "anyone in abc.com can view and edit"
com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
{
"error" : "invalid_grant"
}
I followed this procedure from Google Developers Guide
Delegating domain-wide authority to the service account
If your application accesses user data, the service account that you created needs to be granted access to the Google Apps domain’s user data that you want to access.
The following steps must be performed by an administrator of the Google Apps domain:
Go to your Google Apps domain’s Admin console.
Select Security from the list of controls. If you don't see Security listed, select More controls from the gray bar at the bottom of the page, then select Security from the list of controls. If you can't see the controls, make sure you're signed in as an administrator for the domain.
Select Show more and then Advanced settings from the list of options.
Select Manage API client access in the Authentication section.
In the Client Name field enter the service account's Client ID.
In the One or More API Scopes field enter the list of scopes that your application should be granted access to. For example, if your application needs domain-wide access to the Google Drive API and the Google Calendar API, enter: https://www.googleapis.com/auth/drive, https://www.googleapis.com/auth/calendar.
Click Authorize.
Your application now has the authority to make API calls as users in your domain (to "impersonate" users). When you prepare to make authorized API calls, you specify the user to impersonate.
added the keys in application.properties
#Google Drive
google.drive.service.account=AAAAAAAAAAAA-i8jfnhhug5uoo9rm8ek2sf06b9452vb9#developer.gserviceaccount.com
google.drive.impersonate.account=my.user#abc.com
google.drive.pkey.file=abcdefgh-0aafb873fcc9.p12
google.drive.application.name=myapp-web
And then created a configuration class for drive
#Configuration
public class GoogleDriveAPIConfiguration {
#Resource
private Environment environment;
private final org.springframework.core.io.Resource pkeyFile = new ClassPathResource("abcdefgh-0aafb873fcc9.p12");
private static final String GOOGLE_RIVE_SERVICE_ACCOUNT = "google.drive.service.account";
private static final String GOOGLE_DRIVE_APPLICATION_NAME = "google.drive.application.name";
private static final String GOOGLE_DRIVE_IMPERSONATE_ACCOUNT = "google.drive.impersonate.account";
#Bean
#Autowired
public GoogleCredential googleCredential(JsonFactory jsonFactory, HttpTransport httpTransport)
throws GeneralSecurityException, IOException {
GoogleCredential credential = new GoogleCredential.Builder().setTransport(httpTransport)
.setJsonFactory(jsonFactory).setServiceAccountId(environment.getProperty(GOOGLE_RIVE_SERVICE_ACCOUNT))
.setServiceAccountPrivateKeyFromP12File(getPrivateKeyFile())
.setServiceAccountScopes(Collections.singleton(DriveScopes.DRIVE))
.setServiceAccountId(environment.getProperty(GOOGLE_DRIVE_IMPERSONATE_ACCOUNT))
.build();
return credential;
}
#Bean
public JsonFactory getJsonFactory() {
JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
return JSON_FACTORY;
}
#Bean
public HttpTransport getHttpTransport() throws GeneralSecurityException, IOException {
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
return httpTransport;
}
#Bean
#Autowired
public Drive getDrive(HttpTransport httpTransport, JsonFactory JSON_FACTORY, GoogleCredential credential) {
Drive drive = new Drive.Builder(httpTransport, JSON_FACTORY, credential).setApplicationName(
GOOGLE_DRIVE_APPLICATION_NAME).build();
return drive;
}
private File getPrivateKeyFile() throws IOException {
return pkeyFile.getFile();
}
}
The app starts up without any error, here's file upload code (full file in this gist)
#Autowired
public void setDrive(Drive drive) {
this.drive = drive;
}
#Async
public void uploadResume(UploadData data, byte[] uploadFile) throws GeneralSecurityException, IOException {
LOGGER.info("Uploading file type {} of size {} to Drive",data.getContentType(),uploadFile.length);
com.google.api.services.drive.model.File file = new com.google.api.services.drive.model.File();
List<ParentReference> referneces = new ArrayList<ParentReference>();
referneces.add(buildParentReference(data.getApplication().getRole()));
file.setTitle(data.getFileName());
file.setParents(referneces);
file.setCopyable(true);
file.setEditable(true);
file.setWritersCanShare(true);
file.setTitle(data.getFileName());
ByteArrayInputStream inputBytes = new ByteArrayInputStream(uploadFile);
InputStreamContent fileUpload = new InputStreamContent(data.getContentType(), new BufferedInputStream(inputBytes));
fileUpload.setLength(uploadFile.length);
Drive.Files.Insert request = drive.files().insert(file, fileUpload);
request.getMediaHttpUploader().setProgressListener(getProgressListener());
request.execute();
}
The error message really doesn't help too, any ideas where I am going wrong?

403 Forbidden Error While accessing Google MapsAPI

I am trying to establish connectivity with google maps api using service account. I have a project in place in google maps api, and I have the relvant clientID, .p12 key, email address. I am using google libraries to get the credentials and to call the API as below.
CODE:
package mapsengine;import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.mapsengine.MapsEngine;
import com.google.api.services.mapsengine.model.Map;
import com.google.api.services.mapsengine.model.Layer;
import java.io.File;import java.io.IOException;
import java.util.Collections;
public class Main { /** Provide the ID of the map you wish to read. */
private static final String MAP_ID = "my map id i gave";
private static final String APPLICATION_NAME = "Google-MapsEngineApiSample/1.0";
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
private static final String SERVICE_ACCOUNT_EMAIL= "asajdsjdheemqe#developer.gserviceaccount.com";
private static Credential authorize() throws Exception {
GoogleCredential credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT
) .setJsonFactory(JSON_FACTORY)
.setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
.setServiceAccountScopes(Collections.singleton("https://www.googleapis.com/auth/mapsengine"))
.setServiceAccountPrivateKeyFromP12File(new File("key.p12"))
.build();
credential.refreshToken();
System.out.println(credential);
return credential;
}
public static void main(String[] args)
{ try { // Authorize this application to access the user's data.
Credential credential = authorize();
// Create an authorized Maps Engine client with the credential.
MapsEngine mapsEngine = new MapsEngine.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential) .
setApplicationName(APPLICATION_NAME).build();
System.out.println(mapsEngine);
// Make a request to get the details of a particular map.
// Map map = mapsEngine.maps().get(MAP_ID).execute();
System.out.println(map.getName());
System.out.println(map.getDescription());
}
catch (IOException e) {
System.out.println(e.getMessage());
} catch (Throwable t) {
t.printStackTrace();
}
}
}`
I am getting an error as 403 Forbidden
{
"code" : 403,
"errors" : [ {
"domain" : "mapsengine",
"location" : "id",
"locationType" : "parameter",
"message" : "Permission denied (reader access required).",
"reason" : "noReaderAccess"
} ],
"message" : "Permission denied (reader access required)."
}
But I am able to see that the service email account which I am using has edit access, also i tried by giving view access. What else I am missign here. Please help.
you need to go your map, and add your SERVICE_ACCOUNT_EMAIL address and give it can edit or view premission follow this: https://support.google.com/mapsengine/answer/4618526?hl=en