6

I have a java 8 project with the Cloud Endpoints Framework configured.

I followed the documentation here: https://cloud.google.com/endpoints/docs/frameworks/java/get-started-frameworks-java

I try to secure the API with an API Key. I followed the documentation here : https://cloud.google.com/endpoints/docs/frameworks/java/restricting-api-access-with-api-keys-frameworks

The problem is that I can always access the endpoints, whether I set the API Key or not.

Here is the API:

@Api(
        name = "myApi",
        title = "My API",
        version = "v1",
        description = "My API description",
        apiKeyRequired = AnnotationBoolean.TRUE
)
public class MyApiEndpoint {
    @ApiMethod(httpMethod = GET, path = "list", apiKeyRequired = AnnotationBoolean.TRUE)
    public ApiEntityList list() throws Exception {
        return new ApiEntityList();
    }
}

Here is the web.xml:

<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
         http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<filter>
    <filter-name>endpoints-api-controller</filter-name>
    <filter-class>com.google.api.control.extensions.appengine.GoogleAppEngineControlFilter</filter-class>
    <init-param>
        <param-name>endpoints.projectId</param-name>
        <param-value>${app.deploy.project}</param-value>
    </init-param>
    <init-param>
        <param-name>endpoints.serviceName</param-name>
        <param-value>${app.deploy.project}.appspot.com</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>endpoints-api-controller</filter-name>
    <servlet-name>EndpointsServlet</servlet-name>
</filter-mapping>

<filter>
    <filter-name>endpoints-api-configuration</filter-name>
    <filter-class>com.google.api.control.ServiceManagementConfigFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>endpoints-api-configuration</filter-name>
    <servlet-name>EndpointsServlet</servlet-name>
</filter-mapping>

<servlet>
    <servlet-name>EndpointsServlet</servlet-name>
    <servlet-class>com.google.api.server.spi.EndpointsServlet</servlet-class>
    <init-param>
        <param-name>services</param-name>
        <param-value>com.myproject.MyApiEndpoint</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>EndpointsServlet</servlet-name>
    <url-pattern>/_ah/api/*</url-pattern>
</servlet-mapping>

The appengine-web.xml:

<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    <runtime>java8</runtime>
    <threadsafe>true</threadsafe>
    <service>core</service>
    <url-stream-handler>urlfetch</url-stream-handler>
    <system-properties>
        <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
    </system-properties>
    <env-variables>
        <env-var name="ENDPOINTS_SERVICE_NAME" value="${app.deploy.project}.appspot.com" />
    </env-variables>
</appengine-web-app>

I created the API Key as a new credential in the Google Cloud Platform project, without any restriction.

And I can see the lines below in the openapi.json file deployed on GCP:

  "/myApi/v1/list": {
   "get": {
    "operationId": "MyApiList",
    "parameters": [ ],
    "responses": {
     "200": {
      "description": "A successful response",
      "schema": {
       "$ref": "#/definitions/ApiEntityList"
      }
     }
    },
    "security": [
     {
      "api_key": [ ]
     }
    ]
   }
  },
  "securityDefinitions": {
    "api_key": {
      "type": "apiKey",
      "name": "key",
      "in": "query"
    }
  },

All the calls below are NOT rejected, but I expect they are:

It looks like the apiKeyRequired annotation parameter does not have any effect.

Do I miss something here?

lordofmax
  • 593
  • 5
  • 17

4 Answers4

1

Did you make sure that your API was enabled? What I mean is when you create a Cloud Endpoints Project, it also effectively declares those endpoints as a 'private API'. You then have to enable it for API keys to have an effect

  • From your console, type in 'APIs & Services'
  • Click either '+ Enable APIs & Services' || 'Libraries' in the side menu
  • Click 'Private' in the side menu for private APIs
  • You should (hopefully) be able to see your 'API' that you've created through Cloud Endpoints

For some people it seems to do it automatically, but there seems to be a fair number it doesn't. I'm honestly clueless as to why that is.

Hope that helps!

0

I was just testing it and made it work by adding, apart from the api annotation, a top level security directive in the openapi.json file. It should look something like this:

{
 "swagger": "2.0",
 "info": {
  "version": "1.0.0",
  "title": "<PROJECT_ID>.appspot.com"
 },
 "host": "<PROJECT_ID>.appspot.com",
 "basePath": "/_ah/api",
 "schemes": [
  "https"
 ],
 "security": [
     {
      "api_key": [ ]
     }
 ], 

After that I run agiain the deployments $ gcloud endpoints services deploy target/openapi-docs/openapi.json and $ mvn appengine:deploy

0

I think you are not using the default app engine service but rather using a service named "core" going by your URLs.

If this is true, then I think you need to update the following to configure endpoints framework to know which service to apply to:

  1. web.xml:

The parameter value for the parameter name endpoints.serviceName in the filter definition for com.google.api.control.extensions.appengine.GoogleAppEngineControlFilter to include the service name before ${app.deploy.project}.appspot.com

<filter>
    <filter-name>endpoints-api-controller</filter-name>
    <filter-class>com.google.api.control.extensions.appengine.GoogleAppEngineControlFilter</filter-class>
    <init-param>
        <param-name>endpoints.projectId</param-name>
        <param-value>${app.deploy.project}</param-value>
    </init-param>
    <init-param>
        <param-name>endpoints.serviceName</param-name>
        <param-value>core-dot-${app.deploy.project}.appspot.com</param-value>
    </init-param>
</filter>
  1. appengine.web.xml:

The environment variable value for ENDPOINTS_SERVICE_NAME to include the service name before ${app.deploy.project}.appspot.com

<env-variables>
    <env-var name="ENDPOINTS_SERVICE_NAME" value="core-dot-${app.deploy.project}.appspot.com" />
</env-variables>
0

For anyone looking at this question in the future.. I had the same problem and it turned out that I had changed the path specified in my @ApiMethod and didn't deploy the new openAPI docs to Cloud Endpoints.

I had deployed my project to App Engine with mvn appengine:deploy But I forgot that I also needed to redeploy my openAPI docs following this documentation on Deploying the Endpoints Configuration. So it was still using the old resource/path that I initially deployed. When I fixed my openAPI docs base path and my path in the @ApiMethod annotation to what I wanted, I deployed it to Cloud Endpoints and then the apiKeyRequired annotation worked again!