@@ -93,6 +93,8 @@ public class ServiceAccountCredentials extends GoogleCredentials
private static final long serialVersionUID = 7807543542681217978L ;
private static final String GRANT_TYPE = "urn:ietf:params:oauth:grant-type:jwt-bearer" ;
private static final String PARSE_ERROR_PREFIX = "Error parsing token refresh response. " ;
private static final int TWELVE_HOURS_IN_SECONDS = 43200 ;
private static final int DEFAULT_LIFETIME_IN_SECONDS = 3600 ;
private final String clientId ;
private final String clientEmail ;
@@ -104,6 +106,7 @@ public class ServiceAccountCredentials extends GoogleCredentials
private final URI tokenServerUri ;
private final Collection <String > scopes ;
private final String quotaProjectId ;
private final int lifetime ;
private transient HttpTransportFactory transportFactory ;
@@ -123,6 +126,10 @@ public class ServiceAccountCredentials extends GoogleCredentials
* authority to the service account.
* @param projectId the project used for billing
* @param quotaProjectId The project used for quota and billing purposes. May be null.
* @param lifetime number of seconds the access token should be valid for. The value should be at
* most 43200 (12 hours). If the token is used for calling a Google API, then the value should
* be at most 3600 (1 hour). If the given value is 0, then the default value 3600 will be used
* when creating the credentials.
*/
ServiceAccountCredentials (
String clientId ,
@@ -134,7 +141,8 @@ public class ServiceAccountCredentials extends GoogleCredentials
URI tokenServerUri ,
String serviceAccountUser ,
String projectId ,
String quotaProjectId ) {
String quotaProjectId ,
int lifetime ) {
this .clientId = clientId ;
this .clientEmail = Preconditions .checkNotNull (clientEmail );
this .privateKey = Preconditions .checkNotNull (privateKey );
@@ -149,6 +157,10 @@ public class ServiceAccountCredentials extends GoogleCredentials
this .serviceAccountUser = serviceAccountUser ;
this .projectId = projectId ;
this .quotaProjectId = quotaProjectId ;
if (lifetime > TWELVE_HOURS_IN_SECONDS ) {
throw new IllegalStateException ("lifetime must be less than or equal to 43200" );
}
this .lifetime = lifetime ;
}
/**
@@ -325,7 +337,8 @@ static ServiceAccountCredentials fromPkcs8(
tokenServerUri ,
serviceAccountUser ,
projectId ,
quotaProject );
quotaProject ,
DEFAULT_LIFETIME_IN_SECONDS );
}
/** Helper to convert from a PKCS#8 String to an RSA private key */
@@ -513,7 +526,21 @@ public GoogleCredentials createScoped(Collection<String> newScopes) {
tokenServerUri ,
serviceAccountUser ,
projectId ,
quotaProjectId );
quotaProjectId ,
lifetime );
}
/**
* Clones the service account with a new lifetime value.
*
* @param lifetime life time value in seconds. The value should be at most 43200 (12 hours). If
* the token is used for calling a Google API, then the value should be at most 3600 (1 hour).
* If the given value is 0, then the default value 3600 will be used when creating the
* credentials.
* @return the cloned service account credentials with the given custom life time
*/
public ServiceAccountCredentials createWithCustomLifetime (int lifetime ) {
return this .toBuilder ().setLifetime (lifetime ).build ();
}
@ Override
@@ -528,7 +555,8 @@ public GoogleCredentials createDelegated(String user) {
tokenServerUri ,
user ,
projectId ,
quotaProjectId );
quotaProjectId ,
lifetime );
}
public final String getClientId () {
@@ -563,6 +591,11 @@ public final URI getTokenServerUri() {
return tokenServerUri ;
}
@ VisibleForTesting
int getLifetime () {
return lifetime ;
}
@ Override
public String getAccount () {
return getClientEmail ();
@@ -618,7 +651,8 @@ public int hashCode() {
transportFactoryClassName ,
tokenServerUri ,
scopes ,
quotaProjectId );
quotaProjectId ,
lifetime );
}
@ Override
@@ -632,6 +666,7 @@ public String toString() {
.add ("scopes" , scopes )
.add ("serviceAccountUser" , serviceAccountUser )
.add ("quotaProjectId" , quotaProjectId )
.add ("lifetime" , lifetime )
.toString ();
}
@@ -648,7 +683,8 @@ public boolean equals(Object obj) {
&& Objects .equals (this .transportFactoryClassName , other .transportFactoryClassName )
&& Objects .equals (this .tokenServerUri , other .tokenServerUri )
&& Objects .equals (this .scopes , other .scopes )
&& Objects .equals (this .quotaProjectId , other .quotaProjectId );
&& Objects .equals (this .quotaProjectId , other .quotaProjectId )
&& Objects .equals (this .lifetime , other .lifetime );
}
String createAssertion (JsonFactory jsonFactory , long currentTime , String audience )
@@ -661,7 +697,7 @@ String createAssertion(JsonFactory jsonFactory, long currentTime, String audienc
JsonWebToken .Payload payload = new JsonWebToken .Payload ();
payload .setIssuer (clientEmail );
payload .setIssuedAtTimeSeconds (currentTime / 1000 );
payload .setExpirationTimeSeconds (currentTime / 1000 + 3600 );
payload .setExpirationTimeSeconds (currentTime / 1000 + this . lifetime );
payload .setSubject (serviceAccountUser );
payload .put ("scope" , Joiner .on (' ' ).join (scopes ));
@@ -693,7 +729,7 @@ String createAssertionForIdToken(
JsonWebToken .Payload payload = new JsonWebToken .Payload ();
payload .setIssuer (clientEmail );
payload .setIssuedAtTimeSeconds (currentTime / 1000 );
payload .setExpirationTimeSeconds (currentTime / 1000 + 3600 );
payload .setExpirationTimeSeconds (currentTime / 1000 + this . lifetime );
payload .setSubject (serviceAccountUser );
if (audience == null ) {
@@ -746,6 +782,7 @@ public static class Builder extends GoogleCredentials.Builder {
private Collection <String > scopes ;
private HttpTransportFactory transportFactory ;
private String quotaProjectId ;
private int lifetime = DEFAULT_LIFETIME_IN_SECONDS ;
protected Builder () {}
@@ -760,6 +797,7 @@ protected Builder(ServiceAccountCredentials credentials) {
this .serviceAccountUser = credentials .serviceAccountUser ;
this .projectId = credentials .projectId ;
this .quotaProjectId = credentials .quotaProjectId ;
this .lifetime = credentials .lifetime ;
}
public Builder setClientId (String clientId ) {
@@ -812,6 +850,11 @@ public Builder setQuotaProjectId(String quotaProjectId) {
return this ;
}
public Builder setLifetime (int lifetime ) {
this .lifetime = lifetime == 0 ? DEFAULT_LIFETIME_IN_SECONDS : lifetime ;
return this ;
}
public String getClientId () {
return clientId ;
}
@@ -852,6 +895,10 @@ public String getQuotaProjectId() {
return quotaProjectId ;
}
public int getLifetime () {
return lifetime ;
}
public ServiceAccountCredentials build () {
return new ServiceAccountCredentials (
clientId ,
@@ -863,7 +910,8 @@ public ServiceAccountCredentials build() {
tokenServerUri ,
serviceAccountUser ,
projectId ,
quotaProjectId );
quotaProjectId ,
lifetime );
}
}
}