1

I have a spring boot application that is using camel to get data from object storage (google cloud platform).

This my code in eclipse:

package footballRestAPIs;

import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;

import core.ErrorProcessor;


@Component
public class ListObjFromGCP extends RouteBuilder{
    
    
     @Override
        public void configure() throws Exception {
            
       
            onException(Exception.class).handled(true)
            .process(new ErrorProcessor());
            

            rest("/").produces("application.json") 
            .get("selectPhoto")
            
            .to("direct:selectPhoto");

        from("direct:selectPhoto")
        
          .to("google-storage://sagessapp_test?operation=listObjects")
        
          .log("${body}");
            
            
         
        }

}

And this is the application.properties file where the path to the service account key is:

spring.cloud.gcp.credentials.location=/Users/User/Downloads/gcp-credentials.json

when I run the spring boot application I get the following error:

Caused by: com.google.api.client.googleapis.json.GoogleJsonResponseException: 401 Unauthorized
GET https://storage.googleapis.com/storage/v1/b/sagessapp_test?projection=full
{
  "code" : 401,
  "errors" : [ {
    "domain" : "global",
    "location" : "Authorization",
    "locationType" : "header",
    "message" : "Anonymous caller does not have storage.buckets.get access to the Google Cloud Storage bucket.",
    "reason" : "required"
  } ],
  "message" : "Anonymous caller does not have storage.buckets.get access to the Google Cloud Storage bucket."
}

Is it possible that there is another way to provide the path to the service account key or there is another issue. Thank you!

Jenny
  • 375
  • 4
  • 6
  • 25
  • Are you running the code on your workstation? Are you authenticated with `gcloud auth application-default login`? Did you set the GOOGLE_APPLICATION_CREDENTIALS env var? How do you manage the authentication on the runtime environment? – guillaume blaquiere Nov 18 '21 at 19:09
  • Did you have a chance to check out my [answer](https://stackoverflow.com/a/70028077/13171940)? – Rogelio Monter Feb 15 '22 at 16:05

1 Answers1

2

TL;DR Create a Credentials instance:

Credentials credentials = GoogleCredentials.fromStream(new FileInputStream("path/to/file")); 

Google Cloud Storage Setup

From the documentation, there are some ways to load the credentials*, besides the one you are already using: *Notice that these ways will be used if credentials aren’t specified through properties file

Environment variable

You can set up the environment variable GOOGLE_APPLICATION_CREDENTIALS and use the default instance:

For Linux or Mac:

export GOOGLE_APPLICATION_CREDENTIALS="/path/to/file"

For Windows:

set GOOGLE_APPLICATION_CREDENTIALS="C:\path\to\file"

This is the easiest way to load the credentials.

Cloud SDK

Another way is to provide the credentials using Google Cloud SDK. The steps are as follows:

  1. First install the Cloud SDK.
  2. Then initialize the Cloud SDK. At step 4, select the project you are working on.
  3. Then you can run gcloud auth application-default login command. As posted in this answer:

    This obtains your credentials via a web flow and stores them in 'the well-known location for Application Default Credentials'. Now, any code/SDK you run will be able to find the credentials automatically. This is a good stand-in when you want to locally test code which would normally run on a server and use a server-side credentials file.

Connecting to Storage

Before we can use Google Cloud storage, we have to create a service object. If we've already set up the GOOGLE_APPLICATION_CREDENTIALS environment variable, we can use the default instance:

Storage storage = StorageOptions.getDefaultInstance().getService();

If we don't want to use the environment variable, we have to create a Credentials instance and pass it to Storage with the project name:

Credentials credentials = GoogleCredentials.fromStream(new FileInputStream("path/to/file"));
// The ID of your GCP project
// String projectId = "your-project-id";
Storage storage = StorageOptions.newBuilder().setCredentials(credentials).setProjectId("your-project-id").build().getService();

Creating a Bucket

Buckets are containers that hold objects. They can be used to organize and control data access.

Creating a bucket requires a BucketInfo:

Bucket bucket = storage.create(BucketInfo.of("sample-bucket"));

For this simple example, we pass a bucket name and accept the default properties. Bucket names must be globally unique and also have to follow some requirements. For example, if we choose a name that is already used, create() will fail.

Reading data

Blobs are assigned a BlobId upon creation.

The easiest way to retrieve a Blob is with BlobId:

Blob blob = storage.get(blobId);
String value = new String(blob.getContent());

We pass the id to Storage and get the Blob in return, and getContent() returns the bytes.

If we don't have the BlobId, we can search the Bucket by name:

// The ID of your GCS bucket
// String bucketName = "your-unique-bucket-name";
Page<Blob> blobs = storage.list(bucketName);
for (Blob blob: blobs.getValues()) {
    if (name.equals(blob.getName())) {
        return new String(blob.getContent());
    }
}

Listing Objects

This is a code sample of a function that list all the objects in a Cloud Storage bucket.

import com.google.api.gax.paging.Page;
import com.google.cloud.storage.Blob;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageOptions;

public class ListObjects {
  public static void listObjects(String projectId, String bucketName) {
    // The ID of your GCP project
    // String projectId = "your-project-id";

    // The ID of your GCS bucket
    // String bucketName = "your-unique-bucket-name";

    Storage storage = StorageOptions.newBuilder().setProjectId(projectId).build().getService();
    Page<Blob> blobs = storage.list(bucketName);

    for (Blob blob : blobs.iterateAll()) {
      System.out.println(blob.getName());
    }
  }
}

See also:

Rogelio Monter
  • 1,084
  • 7
  • 18
  • Hello @Rogelio Monter, in this code you provided ```Page blobs = bucket.list();``` what is ```bucket``` and how to define it? Thank you – Jenny Nov 25 '21 at 15:31
  • 1
    @Jenny `Page blobs` variable is defined when you create a bucket as shown in the section *Creating a bucket*. I updated the answer with this info and added at the end a sample from the [official documentation](https://cloud.google.com/storage/docs/samples/storage-list-files) on how to list files with an already created bucket. – Rogelio Monter Nov 25 '21 at 23:07
  • Do you have another doubt @Jenny? Do you have any chance to test the code? – Rogelio Monter Dec 08 '21 at 16:15
  • How do you use it with application default credentials? From your link: https://github.com/googleapis/google-cloud-java#google-cloud-platform-environment I am running my code inside AppEngine with a default service account, and following the steps to use ADP, to which I should not need credentials, is not working with the code of the example. I can access perfectly to my storage from appengine environment using the legacy storage libraries. – Javier Delgado Oct 19 '22 at 21:55