I am working on google endpoints api 2.0 and was trying to integrate firebase authentication using this
Part of documentation. I encountered a peculiar problem that with the dependencies that I have added to pom.xml com.google.api.server.spi.auth.EspAuthenticator.class doesn't show up. There are other authenticators available such as GoogleJwtAuthenticator and GoogleOAuth2Authenticator, but EspAuthenticator is not available for import. It is not recognised. Here is my pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>war</packaging>
<version>1.0</version>
<groupId>com.google.devrel.training.conference</groupId>
<artifactId>conference</artifactId>
<properties>
<appengine.app.version>1</appengine.app.version>
<appengine.target.version>1.9.53</appengine.target.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- Compile/runtime dependencies -->
<dependency>
<groupId>com.google.endpoints</groupId>
<artifactId>endpoints-framework</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>com.google.appengine</groupId>
<artifactId>appengine-api-1.0-sdk</artifactId>
<version>${appengine.target.version}</version>
</dependency>
<dependency>
<groupId>com.google.appengine</groupId>
<artifactId>appengine-endpoints</artifactId>
<version>${appengine.target.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<dependency>
<groupId>com.googlecode.objectify</groupId>
<artifactId>objectify</artifactId>
<version>5.0</version>
</dependency>
<!-- Test Dependencies -->
<dependency>
<groupId>com.google.appengine</groupId>
<artifactId>appengine-testing</artifactId>
<version>${appengine.target.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.appengine</groupId>
<artifactId>appengine-api-stubs</artifactId>
<version>${appengine.target.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
</dependencies>
<build>
<outputDirectory>target/${project.artifactId}-${project.version}/WEB-INF/classes</outputDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<version>2.5.1</version>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>endpoints-framework-maven-plugin</artifactId>
<version>1.0.0-beta5</version>
<configuration>
<!-- plugin configuration -->
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<webXml>${project.build.directory}/generated-sources/appengine-endpoints/WEB-INF/web.xml</webXml>
<webResources>
<resource>
<!-- this is relative to the pom.xml directory -->
<directory>${project.build.directory}/generated-sources/appengine-endpoints</directory>
<!-- the list has a default value of ** -->
<includes>
<include>WEB-INF/*.discovery</include>
<include>WEB-INF/*.api</include>
</includes>
</resource>
</webResources>
</configuration>
</plugin>
<plugin>
<groupId>com.google.appengine</groupId>
<artifactId>appengine-maven-plugin</artifactId>
<version>${appengine.target.version}</version>
<configuration>
<enableJarClasses>false</enableJarClasses>
</configuration>
<executions>
<execution>
<goals>
<goal>endpoints_get_discovery_doc</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>
com.google.appengine
</groupId>
<artifactId>
appengine-maven-plugin
</artifactId>
<versionRange>
[1.9.3,)
</versionRange>
<goals>
<goal>
endpoints_get_discovery_doc
</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore></ignore>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
And here is my ConferenceApi Code, that I developed from udacity course building scalable apps with java and later migrated to 2.0 version using the migration guide.
package com.google.devrel.training.conference.spi;
import static com.google.devrel.training.conference.service.OfyService.ofy;
import java.util.List;
import com.google.api.server.spi.auth.GoogleOAuth2Authenticator;
import com.google.api.server.spi.auth.EspAuthenticator; // not available
import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiIssuer;
import com.google.api.server.spi.config.ApiIssuerAudience;
import com.google.api.server.spi.config.ApiMethod;
import com.google.api.server.spi.config.ApiMethod.HttpMethod;
import com.google.api.server.spi.response.UnauthorizedException;
import com.google.appengine.api.users.User;
import com.google.devrel.training.conference.Constants;
import com.google.devrel.training.conference.domain.Conference;
import com.google.devrel.training.conference.domain.Profile;
import com.google.devrel.training.conference.form.ConferenceForm;
import com.google.devrel.training.conference.form.ConferenceQueryForm;
import com.google.devrel.training.conference.form.ProfileForm;
import com.google.devrel.training.conference.form.ProfileForm.TeeShirtSize;
import com.google.devrel.training.conference.service.OfyService;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.cmd.Query;
/**
* Defines conference APIs.
*/
@Api(name = "conference", version = "v1", scopes = { Constants.EMAIL_SCOPE },
authenticators = {com.google.api.server.spi.auth.EspAuthenticator.class},
//EspAuthenticator not available
issuers = {
@ApiIssuer(
name = "firebase",
issuer = "https://securetoken.google.com/***PROJECT ID***",
jwksUri = "https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken@system.gserviceaccount.com")
},
issuerAudiences = {
@ApiIssuerAudience(name = "firebase", audiences = "***PROJECT ID***")
},
clientIds = {
Constants.WEB_CLIENT_ID, Constants.API_EXPLORER_CLIENT_ID }, description = "API for the Conference Central Backend application.")
public class ConferenceApi {
/*
* Get the display name from the user's email. For example, if the email is
* lemoncake@example.com, then the display name becomes "lemoncake."
*/
private static String extractDefaultDisplayNameFromEmail(String email) {
return email == null ? null : email.substring(0, email.indexOf("@"));
}
/**
* Creates or updates a Profile object associated with the given user
* object.
*
* @param user
* A User object injected by the cloud endpoints.
* @param profileForm
* A ProfileForm object sent from the client form.
* @return Profile object just created.
* @throws UnauthorizedException
* when the User object is null.
*/
// Declare this method as a method available externally through Endpoints
@ApiMethod(name = "saveProfile", path = "profile", httpMethod = HttpMethod.POST)
// The request that invokes this method should provide data that
// conforms to the fields defined in ProfileForm
// TODO 1 Pass the ProfileForm parameter
// TODO 2 Pass the User parameter
public Profile saveProfile(final User user,ProfileForm profileForm) throws UnauthorizedException {
String userId = null;
String mainEmail = null;
String displayName = "Your name will go here";
TeeShirtSize teeShirtSize = TeeShirtSize.NOT_SPECIFIED;
// TODO 2
// If the user is not logged in, throw an UnauthorizedException
if(user==null){
throw new UnauthorizedException("Unauthorized Exception");
}
// TODO 1
// Set the teeShirtSize to the value sent by the ProfileForm, if sent
// otherwise leave it as the default value
// TODO 1
// Set the displayName to the value sent by the ProfileForm, if sent
// otherwise set it to null
// displayName=profileForm.getDisplayName();
// TODO 2
// Get the userId and mainEmail
userId=user.getUserId();
mainEmail=user.getEmail();
// TODO 2
// If the displayName is null, set it to default value based on the user's email
// by calling extractDefaultDisplayNameFromEmail(...)
// if(displayName==null){
// displayName=extractDefaultDisplayNameFromEmail(mainEmail);
// }
// Create a new Profile entity from the
// userId, displayName, mainEmail and teeShirtSize
Key<Profile> key=Key.create(Profile.class,userId);
Profile profile = ofy().load().key(key).now();
if(profile==null){
if(profileForm.getTeeShirtSize()!=null){
teeShirtSize=profileForm.getTeeShirtSize();
}else{
teeShirtSize=TeeShirtSize.NOT_SPECIFIED;
}
if(profileForm.getDisplayName()!=null){
displayName=profileForm.getDisplayName();
}else{
displayName=extractDefaultDisplayNameFromEmail(mainEmail);
}
profile=new Profile(userId,displayName, mainEmail, teeShirtSize);
}else{
profile.update(profileForm.getDisplayName(), profileForm.getTeeShirtSize());
}
// TODO 3 (In Lesson 3)
// Save the Profile entity in the datastore
ofy().save().entity(profile).now();
// Return the profile
return profile;
}
/**
* Returns a Profile object associated with the given user object. The cloud
* endpoints system automatically inject the User object.
*
* @param user
* A User object injected by the cloud endpoints.
* @return Profile object.
* @throws UnauthorizedException
* when the User object is null.
*/
@ApiMethod(name = "getProfile", path = "profile", httpMethod = HttpMethod.GET)
public Profile getProfile(final User user) throws UnauthorizedException {
if (user == null) {
throw new UnauthorizedException("Authorization required");
}
// TODO
// load the Profile Entity
String userId = user.getUserId(); // TODO
Key<Profile> key = Key.create(Profile.class,userId); // TODO
Profile profile=(Profile) ofy().load().key(key).now(); // TODO load the Profile entity
return profile;
}
/**
* Gets the Profile entity for the current user
* or creates it if it doesn't exist
* @param user
* @return user's Profile
*/
private static Profile getProfileFromUser(User user) {
// First fetch the user's Profile from the datastore.
Profile profile = ofy().load().key(
Key.create(Profile.class, user.getUserId())).now();
if (profile == null) {
// Create a new Profile if it doesn't exist.
// Use default displayName and teeShirtSize
String email = user.getEmail();
profile = new Profile(user.getUserId(),
extractDefaultDisplayNameFromEmail(email), email, TeeShirtSize.NOT_SPECIFIED);
}
return profile;
}
/**
* Creates a new Conference object and stores it to the datastore.
*
* @param user A user who invokes this method, null when the user is not signed in.
* @param conferenceForm A ConferenceForm object representing user's inputs.
* @return A newly created Conference Object.
* @throws UnauthorizedException when the user is not signed in.
*/
@ApiMethod(name = "createConference", path = "conference", httpMethod = HttpMethod.POST)
public Conference createConference(final User user, final ConferenceForm conferenceForm)
throws UnauthorizedException {
if (user == null) {
throw new UnauthorizedException("Authorization required");
}
// TODO (Lesson 4)
// Get the userId of the logged in User
String userId = user.getUserId();
// TODO (Lesson 4)
// Get the key for the User's Profile
Key<Profile> profileKey = Key.create(Profile.class,userId);
// TODO (Lesson 4)
// Allocate a key for the conference -- let App Engine allocate the ID
// Don't forget to include the parent Profile in the allocated ID
final Key<Conference> conferenceKey = OfyService.factory().allocateId(profileKey, Conference.class);
// TODO (Lesson 4)
// Get the Conference Id from the Key
final long conferenceId = conferenceKey.getId();
// TODO (Lesson 4)
// Get the existing Profile entity for the current user if there is one
// Otherwise create a new Profile entity with default values
Profile profile = ofy().load().key(profileKey).now();
if(profile==null){
profile=new Profile(user.getUserId(),user.getEmail(),extractDefaultDisplayNameFromEmail(user.getEmail()),TeeShirtSize.NOT_SPECIFIED);
}
// TODO (Lesson 4)
// Create a new Conference Entity, specifying the user's Profile entity
// as the parent of the conference
Conference conference = new Conference(conferenceId,user.getUserId(),conferenceForm);
// TODO (Lesson 4)
// Save Conference and Profile Entities
ofy().save().entities(profile,conference).now();
return conference;
}
@ApiMethod(name="queryConferences",
path="queryConferences",
httpMethod=HttpMethod.POST)
public List<Conference> queryConferences(ConferenceQueryForm cqf){
return cqf.getQuery().list();
}
@ApiMethod(name="getConferencesCreated",
path="getConferencesCreated",
httpMethod=HttpMethod.POST)
public List<Conference> getConferencesCreated(User user) throws UnauthorizedException{
if (user == null) {
throw new UnauthorizedException("Authorization required");
}
Query<Conference> query= ofy().load().type(Conference.class).ancestor(Key.create(Profile.class,user.getUserId())).order("name");
return query.list();
}
// @ApiMethod(name="filterPlayground",
// path="filterPlayground",
// httpMethod=HttpMethod.POST)
public List<Conference> filterPlayground(){
Query<Conference> query= ofy().load().type(Conference.class);
// query=query.filter("topics=", "Movie Making");
// query=query.filter("month=",6);
query=query.filter("city","London");
query=query.filter("maxAttendees >",10).order("maxAttendees").order("name");
return query.list();
}
}
Please tell me if there is something wrong with pom.xml or there are some other issues that are making EspAuthenticator.class not available.
The Endpoints Framework Auth dependency needs to be included. Check out this doc: https://cloud.google.com/endpoints/docs/frameworks/java/adding-api-management