javaee-esprit / google-api-java-client

Automatically exported from code.google.com/p/google-api-java-client
0 stars 0 forks source link

GoogleCredential.executeRefreshToken() fails due to wrong Payload #862

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Version of google-api-java-client (e.g. 1.15.0-rc)?
1.17.0

Java environment (e.g. Java 6, Android 2.3, App Engine)?
App Engine

Describe the problem.
When using service accounts the client library fails once the access token 
expires with the following exception:
com.google.api.client.auth.oauth2.TokenResponseException: 403 OK
<!DOCTYPE html><html lang=en><meta charset=utf-8><meta name=viewport 
content="initial-scale=1, minimum-scale=1, width=device-width"><title>Error 403 
(Forbidden)!!1</title><style>*{margin:0;padding:0}html,code{font:15px/22px 
arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% 
auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > 
body{background:url(//www.google.com/images/errors/robot.png) 100% 5px 
no-repeat;padding-right:205px}p{margin:11px 0 
22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}@media 
screen and 
(max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right
:0}}#logo{background:url(//www.google.com/images/errors/logo_sm_2.png) 
no-repeat}@media only screen and 
(min-resolution:192dpi){#logo{background:url(//www.google.com/images/errors/logo
_sm_2_hr.png) no-repeat 0% 0%/100% 
100%;-moz-border-image:url(//www.google.com/images/errors/logo_sm_2_hr.png) 
0}}@media only screen and 
(-webkit-min-device-pixel-ratio:2){#logo{background:url(//www.google.com/images/
errors/logo_sm_2_hr.png) no-repeat;-webkit-background-size:100% 
100%}}#logo{display:inline-block;height:55px;width:150px}</style><a 
href=//www.google.com/><span id=logo 
aria-label=Google></span></a><p><b>403.</b> <ins>That’s an 
error.</ins><p>We're sorry, but you do not have access to this page. 
<ins>That’s all we know.</ins>
    at com.google.api.client.auth.oauth2.TokenResponseException.from(TokenResponseException.java:105)
    at com.google.api.client.auth.oauth2.TokenRequest.executeUnparsed(TokenRequest.java:287)
    at com.google.api.client.auth.oauth2.TokenRequest.execute(TokenRequest.java:307)
    at com.google.api.client.googleapis.auth.oauth2.GoogleCredential.executeRefreshToken(GoogleCredential.java:269)
    at com.google.api.client.auth.oauth2.Credential.refreshToken(Credential.java:489)
    at com.google.api.client.auth.oauth2.Credential.intercept(Credential.java:217)
    at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:859)

When digging into the source code it turns out that the JsonWebToken.Payload is 
using the
    @Key("sub")
    private String subject;
method but service account spefication expects "prn" instead.

Original issue reported on code.google.com by daniel.florey@gmail.com on 25 Mar 2014 at 11:58

GoogleCodeExporter commented 9 years ago
I have fixed the issue by replacing the method with this:

    @Override
    @Beta
    protected TokenResponse executeRefreshToken() throws IOException {
        if (serviceAccountPrivateKey == null) {
            return super.executeRefreshToken();
        }
        // service accounts: no refresh token; instead use private key to
        // request new access token
        JsonWebSignature.Header header = new JsonWebSignature.Header();
        header.setAlgorithm("RS256");
        header.setType("JWT");
        JsonWebToken.Payload payload = new JsonWebToken.Payload();
        long currentTime = getClock().currentTimeMillis();
        payload.setIssuer(serviceAccountId);
        payload.setAudience(getTokenServerEncodedUrl());
        payload.setIssuedAtTimeSeconds(currentTime / 1000);
        payload.setExpirationTimeSeconds(currentTime / 1000 + 3600);
        payload.set("prn", serviceAccountUser);
        payload.put("scope", Joiner.on(' ').join(serviceAccountScopes));
        try {
            String assertion = JsonWebSignature.signUsingRsaSha256(serviceAccountPrivateKey, getJsonFactory(), header, payload);
            TokenRequest request = new TokenRequest(getTransport(), getJsonFactory(), new GenericUrl(getTokenServerEncodedUrl()), "assertion");
            request.put("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer");
            request.put("assertion", assertion);
            return request.execute();
        } catch (GeneralSecurityException exception) {
            IOException e = new IOException();
            e.initCause(exception);
            throw e;
        }
    }

Original comment by daniel.florey@gmail.com on 25 Mar 2014 at 12:36

GoogleCodeExporter commented 9 years ago
Daniel, please investigate.

Original comment by yan...@google.com on 25 Mar 2014 at 1:55

GoogleCodeExporter commented 9 years ago
For some reason it is working now - even without the patch. 
Most likely just an issue with the OAuth endpoint today(?)
Sorry for the noise.

Original comment by daniel.florey@gmail.com on 25 Mar 2014 at 3:04

GoogleCodeExporter commented 9 years ago
Hi, is your application having too many instances simultaneously sending 
"refresh_token" requests with the same access token?

Original comment by wonder...@google.com on 25 Mar 2014 at 6:01

GoogleCodeExporter commented 9 years ago
I tried to figure out if a user comes from a Google Apps domain and has 
installed our app from the marketplace so that service accounts can be used. I 
grabbed a service account access token on login to detect this. It turned out 
that the oauth2 endpoint did not like multiple access token requests for the 
same user.
When only requesting new access tokens when the old ones are about to expire it 
seems to work more reliable.

Original comment by daniel.florey@gmail.com on 25 Mar 2014 at 6:06

GoogleCodeExporter commented 9 years ago
If you have too many instances that sends out "refresh_token" requests for the 
same access token simultaneously, you will hit the "rate limit" at the endpoint 
and therefore get a 403 error.

By the way, were you using GData APIs or any of the new APIs listed on 
https://developers.google.com/api-client-library/java/apis/ ?

Original comment by wonder...@google.com on 25 Mar 2014 at 6:33

GoogleCodeExporter commented 9 years ago

Original comment by wonder...@google.com on 13 May 2014 at 5:57