简体   繁体   中英

java.lang.NoClassDefFoundError: com/google/appengine/api/urlfetch/HTTPMethod

I am attempting to verify Google ID tokens with a backend server as per:

https://developers.google.com/identity/sign-in/android/backend-auth

The tokens are initially retrieved by an android app, and are then passed to a backend login server via sockets which attempts verification. As things stand, there is an error thrown at runtime within the GoogleIdTokenVerifier code I am importing.

ServerThread.java:

GoogleIdToken idToken = GoogleAuthenticator.authenticateToken(tokenJson.getToken());

GoogleAuthenticator.java:

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Collections;
import java.util.Properties;

import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.extensions.appengine.http.UrlFetchTransport;

public class GoogleAuthenticator {

    public GoogleAuthenticator(){

    }

    public static Properties prop;

    public static GoogleIdToken authenticateToken(String inputToken) throws IOException{

    final JacksonFactory jacksonFactory = new JacksonFactory();
    prop = new Properties();
    prop.load(GoogleAuthenticator.class.getClassLoader().getResourceAsStream("config.properties"));

    GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(UrlFetchTransport.getDefaultInstance(), jacksonFactory)
            // Specify the CLIENT_ID of the app that accesses the backend:
            .setAudience(Collections.singletonList(prop.getProperty("google.web.client.id")))
            // Or, if multiple clients access the backend:
            //.setAudience(Arrays.asList(CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3))
            .build();

        GoogleIdToken idToken;
        try {
            idToken = verifier.verify(inputToken);
            return idToken;
        } catch (GeneralSecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
    }
}

pom.xml

    <dependency>
        <groupId>com.google.api-client</groupId>
        <artifactId>google-api-client</artifactId>
        <version>1.25.0</version>
   </dependency>

   <dependency>
        <groupId>com.google.api-client</groupId>
        <artifactId>google-api-client-appengine</artifactId>
        <version>1.25.0</version>
   </dependency>

I am currently seeing the following stack trace:

Exception in thread "Thread-0" java.lang.NoClassDefFoundError: com/google/appengine/api/urlfetch/HTTPMethod
    at com.google.api.client.extensions.appengine.http.UrlFetchTransport.buildRequest(UrlFetchTransport.java:118)
    at com.google.api.client.extensions.appengine.http.UrlFetchTransport.buildRequest(UrlFetchTransport.java:50)
    at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:872)
    at com.google.api.client.googleapis.auth.oauth2.GooglePublicKeysManager.refresh(GooglePublicKeysManager.java:172)
    at com.google.api.client.googleapis.auth.oauth2.GooglePublicKeysManager.getPublicKeys(GooglePublicKeysManager.java:140)
    at com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier.verify(GoogleIdTokenVerifier.java:174)
    at com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier.verify(GoogleIdTokenVerifier.java:192)
    at com.omarhegazi.login.GoogleAuthenticator.authenticateToken(GoogleAuthenticator.java:40)
    at com.omarhegazi.login.ServerThread.run(ServerThread.java:45)

It looks like there's no HTTPMethod class available amongst the dependencies. Any thoughts?

UPDATE 1:

Adding the appengine dependency below has made some progress. I now have the following stack trace error:

Exception in thread "Thread-0" com.google.apphosting.api.ApiProxy$CallNotFoundException: The API package 'urlfetch' or call 'Fetch()' was not found.
    at com.google.apphosting.api.ApiProxy.makeSyncCall(ApiProxy.java:98)
    at com.google.appengine.api.urlfetch.URLFetchServiceImpl.fetch(URLFetchServiceImpl.java:37)
    at com.google.api.client.extensions.appengine.http.UrlFetchRequest.execute(UrlFetchRequest.java:74)
    at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:981)
    at com.google.api.client.googleapis.auth.oauth2.GooglePublicKeysManager.refresh(GooglePublicKeysManager.java:172)
    at com.google.api.client.googleapis.auth.oauth2.GooglePublicKeysManager.getPublicKeys(GooglePublicKeysManager.java:140)
    at com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier.verify(GoogleIdTokenVerifier.java:174)
    at com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier.verify(GoogleIdTokenVerifier.java:192)
    at com.omarhegazi.login.GoogleAuthenticator.authenticateToken(GoogleAuthenticator.java:40)
    at com.omarhegazi.login.ServerThread.run(ServerThread.java:45)

This was using v1.6.1

I've also attempted to use v1.9.70 which results in the following:

Exception in thread "Thread-0" com.google.apphosting.api.ApiProxy$CallNotFoundException: Can't make API call urlfetch.Fetch in a thread that is neither the original request thread nor a thread created by ThreadManager
    at com.google.apphosting.api.ApiProxy$CallNotFoundException.foreignThread(ApiProxy.java:800)
    at com.google.apphosting.api.ApiProxy.makeSyncCall(ApiProxy.java:112)
    at com.google.appengine.api.urlfetch.URLFetchServiceImpl.fetch(URLFetchServiceImpl.java:40)
    at com.google.api.client.extensions.appengine.http.UrlFetchRequest.execute(UrlFetchRequest.java:74)
    at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:981)
    at com.google.api.client.googleapis.auth.oauth2.GooglePublicKeysManager.refresh(GooglePublicKeysManager.java:172)
    at com.google.api.client.googleapis.auth.oauth2.GooglePublicKeysManager.getPublicKeys(GooglePublicKeysManager.java:140)
    at com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier.verify(GoogleIdTokenVerifier.java:174)
    at com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier.verify(GoogleIdTokenVerifier.java:192)
    at com.omarhegazi.login.GoogleAuthenticator.authenticateToken(GoogleAuthenticator.java:40)
    at com.omarhegazi.login.ServerThread.run(ServerThread.java:45)

It looks like the fetch package gets included later than 1.6.1, but there's some issues relating to the threads in which the API calls are made.

Try to include the appengine dependency in your pom.xml :

<dependency>
    <groupId>com.google.appengine</groupId>
    <artifactId>appengine-api-1.0-sdk</artifactId>
    <version>1.6.1</version> <!-- Check your version --> 
</dependency>

Link to the docs

As per ngueno's post above, I needed appengine-api-1.0-sdk v1.9.70 to get this working:

 <dependency>
    <groupId>com.google.appengine</groupId>
    <artifactId>appengine-api-1.0-sdk</artifactId>
    <version>1.9.70</version>
</dependency>

To resolve the "Can't make API call urlfetch.Fetch in a thread that is neither the original request thread nor a thread created by ThreadManager" error that was being thrown with this version of the appengine API, I had to change the HttpTransport used from UrlFetchTransport.getDefaultInstance() to GoogleNetHttpTransport.newTrustedTransport()

ie:

    HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
    prop = new Properties();
prop.load(GoogleAuthenticator.class.getClassLoader().getResourceAsStream("config.properties"));

    GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(httpTransport, gsonFactory)
            // Specify the CLIENT_ID of the app that accesses the backend:
            .setAudience(Collections.singletonList(prop.getProperty("google.client.id")))
            .setIssuer("https://accounts.google.com")
            // Or, if multiple clients access the backend:
            //.setAudience(Arrays.asList(CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3, etc))
            .build();

        // (Receive idTokenString by HTTPS POST)

        GoogleIdToken idToken;

        idToken = verifier.verify(inputToken);

All references and guides used had pointed to the UrlFetchTransport.getDefaultInstance() being Thread safe/the best option to use but it did not work for me here.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM