• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015, Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *    * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *    * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *
15  *    * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 package com.google.auth.appengine;
33 
34 import com.google.appengine.api.appidentity.AppIdentityService;
35 import com.google.appengine.api.appidentity.AppIdentityService.GetAccessTokenResult;
36 import com.google.appengine.api.appidentity.AppIdentityServiceFactory;
37 import com.google.auth.ServiceAccountSigner;
38 import com.google.auth.oauth2.AccessToken;
39 import com.google.auth.oauth2.GoogleCredentials;
40 import com.google.common.base.MoreObjects;
41 import com.google.common.collect.ImmutableList;
42 import com.google.common.collect.ImmutableSet;
43 import com.google.errorprone.annotations.CanIgnoreReturnValue;
44 import java.io.IOException;
45 import java.io.ObjectInputStream;
46 import java.util.Collection;
47 import java.util.Date;
48 import java.util.Objects;
49 
50 /**
51  * OAuth2 credentials representing the built-in service account for Google App Engine. You should
52  * only use this class if you are running on AppEngine and are using urlfetch.
53  *
54  * <p>Fetches access tokens from the App Identity service.
55  */
56 public class AppEngineCredentials extends GoogleCredentials implements ServiceAccountSigner {
57 
58   private static final long serialVersionUID = -2627708355455064660L;
59 
60   private final String appIdentityServiceClassName;
61   private final Collection<String> scopes;
62   private final boolean scopesRequired;
63 
64   private transient AppIdentityService appIdentityService;
65 
AppEngineCredentials(Collection<String> scopes, AppIdentityService appIdentityService)66   private AppEngineCredentials(Collection<String> scopes, AppIdentityService appIdentityService) {
67     this.scopes = scopes == null ? ImmutableSet.<String>of() : ImmutableList.copyOf(scopes);
68     this.appIdentityService =
69         appIdentityService != null
70             ? appIdentityService
71             : AppIdentityServiceFactory.getAppIdentityService();
72     this.appIdentityServiceClassName = this.appIdentityService.getClass().getName();
73     scopesRequired = this.scopes.isEmpty();
74   }
75 
76   /** Refresh the access token by getting it from the App Identity service */
77   @Override
refreshAccessToken()78   public AccessToken refreshAccessToken() throws IOException {
79     if (createScopedRequired()) {
80       throw new IOException("AppEngineCredentials requires createScoped call before use.");
81     }
82     GetAccessTokenResult accessTokenResponse = appIdentityService.getAccessToken(scopes);
83     String accessToken = accessTokenResponse.getAccessToken();
84     Date expirationTime = accessTokenResponse.getExpirationTime();
85     return new AccessToken(accessToken, expirationTime);
86   }
87 
88   @Override
createScopedRequired()89   public boolean createScopedRequired() {
90     return scopesRequired;
91   }
92 
93   @Override
createScoped(Collection<String> scopes)94   public GoogleCredentials createScoped(Collection<String> scopes) {
95     return new AppEngineCredentials(scopes, appIdentityService);
96   }
97 
98   @Override
getAccount()99   public String getAccount() {
100     return appIdentityService.getServiceAccountName();
101   }
102 
103   @Override
sign(byte[] toSign)104   public byte[] sign(byte[] toSign) {
105     return appIdentityService.signForApp(toSign).getSignature();
106   }
107 
108   @Override
hashCode()109   public int hashCode() {
110     return Objects.hash(scopes, scopesRequired, appIdentityServiceClassName);
111   }
112 
113   @Override
toString()114   public String toString() {
115     return MoreObjects.toStringHelper(this)
116         .add("scopes", scopes)
117         .add("scopesRequired", scopesRequired)
118         .add("appIdentityServiceClassName", appIdentityServiceClassName)
119         .toString();
120   }
121 
122   @Override
equals(Object obj)123   public boolean equals(Object obj) {
124     if (!(obj instanceof AppEngineCredentials)) {
125       return false;
126     }
127     AppEngineCredentials other = (AppEngineCredentials) obj;
128     return this.scopesRequired == other.scopesRequired
129         && Objects.equals(this.scopes, other.scopes)
130         && Objects.equals(this.appIdentityServiceClassName, other.appIdentityServiceClassName);
131   }
132 
readObject(ObjectInputStream input)133   private void readObject(ObjectInputStream input) throws IOException, ClassNotFoundException {
134     input.defaultReadObject();
135     appIdentityService = newInstance(appIdentityServiceClassName);
136   }
137 
newBuilder()138   public static Builder newBuilder() {
139     return new Builder();
140   }
141 
142   @Override
toBuilder()143   public Builder toBuilder() {
144     return new Builder(this);
145   }
146 
147   public static class Builder extends GoogleCredentials.Builder {
148 
149     private Collection<String> scopes;
150     private AppIdentityService appIdentityService;
151 
Builder()152     protected Builder() {}
153 
Builder(AppEngineCredentials credentials)154     protected Builder(AppEngineCredentials credentials) {
155       this.scopes = credentials.scopes;
156       this.appIdentityService = credentials.appIdentityService;
157     }
158 
159     @CanIgnoreReturnValue
setScopes(Collection<String> scopes)160     public Builder setScopes(Collection<String> scopes) {
161       this.scopes = scopes;
162       return this;
163     }
164 
165     @CanIgnoreReturnValue
setAppIdentityService(AppIdentityService appIdentityService)166     public Builder setAppIdentityService(AppIdentityService appIdentityService) {
167       this.appIdentityService = appIdentityService;
168       return this;
169     }
170 
getScopes()171     public Collection<String> getScopes() {
172       return scopes;
173     }
174 
getAppIdentityService()175     public AppIdentityService getAppIdentityService() {
176       return appIdentityService;
177     }
178 
179     @Override
build()180     public AppEngineCredentials build() {
181       return new AppEngineCredentials(scopes, appIdentityService);
182     }
183   }
184 }
185