13

My app uses Oauthed Cloud Endpoints and is working fine in production.

My problem is that on the local devserver, my User user is always set to example@example.com, even though I've gone through the usual auth, access code, etc etc etc and have a valid authed user.

I get that example@example.com is useful to test oauth endpoints before I have oauth working properly, but since my app is working I'd rather see the actual user there.

To be specific, my endpoint method is

@ApiMethod(name = "insertEmp"), etc
public Emp insertEmp(User user, Emp emp) {
      System.out.println(user.getEmail());  // (A) log "appengine" email
      System.out.println(OAuthServiceFactory.getOAuthService().getCurrentUser().getEmail(); // (B) log authed email

       ...

When deployed, everything is fine, and both (A) and (B) log the authenticated user (my.email@gmail.com).

When testing on my local devserver, (A) always logs "example@example.com", even though I have gone through the Oauth sequence and have a valid, authenticated user, and (B) logs my.email@gmail.com. So I can do hi-fidelity testing, I need the User to be the real authenticated user.

So in simple terms, how do I get (A) and (B) to be the same?

pinoyyid
  • 21,499
  • 14
  • 64
  • 115

7 Answers7

4

It seems it can't be done. I've ended up coding around it by putting the following code at the top of my Endpoint methods.

if ("example@example.com".equalsIgnoreCase(user.getEmail()) {
    user = new User(OAuthServiceFactory.getOAuthService().getCurrentUser().getEmail(),"foo");
}

So now, even on devserver, the User email matches the Oauth email.

pinoyyid
  • 21,499
  • 14
  • 64
  • 115
  • 3
    Doesn't work for me... using appengine 1.9.3 and the email continues the same: example@example.com – Renan Franca May 01 '14 at 23:32
  • 1
    Are you still able to get the real email? I am getting null back as the user, and if I call OAuthServiceFactory.getOa..().getCurrentUser() I get example@example.com – Patrick Jackson Dec 07 '14 at 12:57
  • Same here. I get example@example.com for the user returned by endpoints and from OAuthServiceFactory.getOAuthService().getCurrentUser() – Patrick Jackson Dec 07 '14 at 14:03
  • 1
    I abandoned cloud endpoints in the end. More trouble than it's worth – pinoyyid Dec 08 '14 at 07:53
  • @pinoyyid do you have a write up anywhere of why you abandoned end points? – Chad Brockman May 05 '16 at 18:51
  • nothing detailed. It came down to company policy to reduce dependency on third party code and services that were outside of our control. We looked at endpoints and concluded it was just as easy to implement our own endpoint framework. – pinoyyid May 06 '16 at 04:26
2

This is not so easy. You'll have to make your settings in the APIs Console. Here you will be able to add "localhost" (http://localhost/) Then you can authenticate, through Google, even though you are running you application on your localhost for development. I have used it extensively, and it works OK Links: https://code.google.com/apis/console/ Just remember the ID's you use here is completely independent of you appengine ID. Took me a few hours to figure that one out.

Lars Christoffersen
  • 1,719
  • 13
  • 24
  • 2
    Thanks, but this isn't the answer to my question. I'm already past the issue of configuring my local server into API console, and Oauth *is* working. My question is that even though Oauth is working, Cloud Endpoints ignores it and substitutes example@example.com as the authenticated user – pinoyyid Oct 02 '13 at 01:29
  • 1
    @pinoyyid : Google is talking about this in its documentation "Important: If the backend API is Auth-protected, your client must provide support as described above under Adding Authentication Support with OAuth 2.0. However, when running against the local dev server, no credentials page is displayed in response to a user's attempt to sign in. Instead, the sign-on simply occurs, granting the user access to the protected API, and the user returned is always example@example.com" at https://cloud.google.com/appengine/docs/java/endpoints/consume_android#making_authenticated_calls – maya Jun 03 '15 at 05:24
0

The thing is that when you are doing the authentication in local, you are not doing it through the Google servers so authenticating your user is something that actually is not happening in local.

Google always provides the example@example.com user when you try to simulate the log in, it happens basically in all the services, like when you provide a log in through your Google Account in any web site (for instance using GWT and App Engine).

What can be different in your site if you test with your real user or you consider example@example.com user as your user?

Sca09
  • 361
  • 4
  • 13
  • 1
    but ... I **am** going through the google servers. If I call the oauth endpoint from my servlet, I am getting the genuine, authenticated google user. The problem is that the appengine/endpoint code in devserver is ignoring it. I can't do hi-fi testing because I want to test the onboarding process where I take a user from unknown, to having a stored credential capable of accessing Google APIs. This is being stymied because instead of the actual user, my CE endpoint classes are being presented with a fake user. – pinoyyid Oct 03 '13 at 14:14
  • I've updated the question to demonstrate the discrepancy in more detail. – pinoyyid Oct 03 '13 at 14:22
0

In your endpoint API you need this

ApiMethod ( name="YourEndPointName", path="yourPath",
            clientIds={"YourId.apps.googleusercontent.com"},
                    scopes =   { "https://www.googleapis.com/auth/userinfo.profile" })

Then in the called method, you will have a User object from the GAPI. Use this to get the actual email from the google User object like this

public myEndPointMethod( Foo foo, User user ){
    email = user.getEmail();
}
Lars Christoffersen
  • 1,719
  • 13
  • 24
  • Please read the question. I already have that! The problem is the value returned by user.getEmail(). – pinoyyid Oct 04 '13 at 01:42
  • in addition, the scope should "email" as declared on https://developers.google.com/+/api/oauth#profile, since userionfo.profile doesn't contain user's email, and therefore user parameter will be null. + the scope you mention has been deprecated. – Pega88 Jan 08 '15 at 20:15
  • what is 'YourId'? I have myapp-xxxx.appspot.com - I feel I am getting close but somewhat stuck – Marc Apr 12 '17 at 01:31
  • Sorry, but this is a long time ago and I don't have the source code anymore. So I can't help you. Could be you google id? – Lars Christoffersen Apr 18 '17 at 08:50
0

I replaced the Oauth2 user (example@example.com) with user from UserFactory and it works fine. I use this method to validate user for all API authenticated API requests.

public static User isAuthenticated(User user) throws OAuthRequestException{

    if(user == null){
        throw new OAuthRequestException("Please login before making requests");
    } 
    if(SystemProperty.environment.value() ==
            SystemProperty.Environment.Value.Development && "example@example.com".equalsIgnoreCase(user.getEmail()) ) {

        //Replace the user from the user factory here.
        user = UserServiceFactory.getUserService().getCurrentUser();

    }
    return user;

}
Rahul
  • 49
  • 5
  • This does not work. I get null from UserServiceFactory.getUserService().getCurrentUser() and example@example.com from OAuthServiceFactory.getUserService() – Patrick Jackson Dec 07 '14 at 14:17
0

Using the go runtime I have resorted to this function to obtain a User that is functional on both the dev server and production:

func currentUser(c context.Context) *user.User {
    const scope = "https://www.googleapis.com/auth/userinfo.email"
    const devClient = "123456789.apps.googleusercontent.com"

    allowedClients := map[string]bool{
        "client-id-here.apps.googleusercontent.com": true,
        devClient: true,                // dev server
    }

    usr, err := user.CurrentOAuth(c, scope)
    if err != nil {
        log.Printf("Warning: Could not get current user: %s", err)
        return nil
    }

    if !allowedClients[usr.ClientID] {
        log.Printf("Warning: Unauthorized client connecting with the server: %s", usr.ClientID)
        return nil
    }

    if (usr.ClientID == devClient) {
        usr = user.Current(c)           // replace with a more interesting user for dev server
    }
    return usr
}

This will use the dev server login information entered using http://localhost:8080/_ah/login

-1

It's not possible. I use another endpoint to replace user_id in current session.