Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add self signed jwt support #572

Merged
merged 14 commits into from Mar 16, 2021
36 changes: 28 additions & 8 deletions oauth2_http/java/com/google/auth/oauth2/AppEngineCredentials.java
Expand Up @@ -69,6 +69,7 @@ class AppEngineCredentials extends GoogleCredentials implements ServiceAccountSi
private static final String GET_SIGNATURE_METHOD = "getSignature";

private final Collection<String> scopes;
private final Collection<String> defaultScopes;
private final boolean scopesRequired;

private transient Object appIdentityService;
Expand All @@ -79,19 +80,25 @@ class AppEngineCredentials extends GoogleCredentials implements ServiceAccountSi
private transient Method getSignature;
private transient String account;

AppEngineCredentials(Collection<String> scopes) throws IOException {
AppEngineCredentials(Collection<String> scopes, Collection<String> defaultScopes)
throws IOException {
this.scopes = scopes == null ? ImmutableSet.<String>of() : ImmutableList.copyOf(scopes);
this.scopesRequired = this.scopes.isEmpty();
this.defaultScopes =
arithmetic1728 marked this conversation as resolved.
Show resolved Hide resolved
defaultScopes == null ? ImmutableSet.<String>of() : ImmutableList.copyOf(defaultScopes);
this.scopesRequired = this.scopes.isEmpty() && this.defaultScopes.isEmpty();
init();
}

AppEngineCredentials(Collection<String> scopes, AppEngineCredentials unscoped) {
AppEngineCredentials(
Collection<String> scopes, Collection<String> defaultScopes, AppEngineCredentials unscoped) {
bshaffer marked this conversation as resolved.
Show resolved Hide resolved
this.appIdentityService = unscoped.appIdentityService;
this.getAccessToken = unscoped.getAccessToken;
this.getAccessTokenResult = unscoped.getAccessTokenResult;
this.getExpirationTime = unscoped.getExpirationTime;
this.scopes = scopes == null ? ImmutableSet.<String>of() : ImmutableList.copyOf(scopes);
this.scopesRequired = this.scopes.isEmpty();
this.defaultScopes =
defaultScopes == null ? ImmutableSet.<String>of() : ImmutableList.copyOf(defaultScopes);
this.scopesRequired = this.scopes.isEmpty() && this.defaultScopes.isEmpty();
}

private void init() throws IOException {
Expand Down Expand Up @@ -129,7 +136,11 @@ public AccessToken refreshAccessToken() throws IOException {
throw new IOException("AppEngineCredentials requires createScoped call before use.");
}
try {
Object accessTokenResult = getAccessTokenResult.invoke(appIdentityService, scopes);
Collection<String> scopesToUse = scopes;
if (scopes.isEmpty()) {
scopesToUse = defaultScopes;
}
Object accessTokenResult = getAccessTokenResult.invoke(appIdentityService, scopesToUse);
String accessToken = (String) getAccessToken.invoke(accessTokenResult);
Date expirationTime = (Date) getExpirationTime.invoke(accessTokenResult);
return new AccessToken(accessToken, expirationTime);
Expand All @@ -145,7 +156,13 @@ public boolean createScopedRequired() {

@Override
public GoogleCredentials createScoped(Collection<String> scopes) {
return new AppEngineCredentials(scopes, this);
return new AppEngineCredentials(scopes, null, this);
}

@Override
public GoogleCredentials createScoped(
Collection<String> scopes, Collection<String> defaultScopes) {
return new AppEngineCredentials(scopes, defaultScopes, this);
}

@Override
Expand All @@ -165,13 +182,14 @@ public byte[] sign(byte[] toSign) {

@Override
public int hashCode() {
return Objects.hash(scopes, scopesRequired);
return Objects.hash(scopes, defaultScopes, scopesRequired);
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("scopes", scopes)
.add("defaultScopes", defaultScopes)
.add("scopesRequired", scopesRequired)
.toString();
}
Expand All @@ -182,7 +200,9 @@ public boolean equals(Object obj) {
return false;
}
AppEngineCredentials other = (AppEngineCredentials) obj;
return this.scopesRequired == other.scopesRequired && Objects.equals(this.scopes, other.scopes);
return this.scopesRequired == other.scopesRequired
&& Objects.equals(this.scopes, other.scopes)
&& Objects.equals(this.defaultScopes, other.defaultScopes);
}

private void readObject(ObjectInputStream input) throws IOException, ClassNotFoundException {
Expand Down
Expand Up @@ -99,6 +99,7 @@ public class ComputeEngineCredentials extends GoogleCredentials
private final String transportFactoryClassName;

private final Collection<String> scopes;
private final Collection<String> defaultScopes;

private transient HttpTransportFactory transportFactory;
private transient String serviceAccountEmail;
Expand All @@ -109,9 +110,13 @@ public class ComputeEngineCredentials extends GoogleCredentials
* @param transportFactory HTTP transport factory, creates the transport used to get access
* tokens.
* @param scopes scope strings for the APIs to be called. May be null or an empty collection.
* @param defaultScopes default scope strings for the APIs to be called. May be null or an empty
* collection.
*/
private ComputeEngineCredentials(
HttpTransportFactory transportFactory, Collection<String> scopes) {
HttpTransportFactory transportFactory,
Collection<String> scopes,
Collection<String> defaultScopes) {
arithmetic1728 marked this conversation as resolved.
Show resolved Hide resolved
this.transportFactory =
firstNonNull(
transportFactory,
Expand All @@ -124,12 +129,26 @@ private ComputeEngineCredentials(
scopeList.removeAll(Arrays.asList("", null));
this.scopes = ImmutableSet.<String>copyOf(scopeList);
}
if (defaultScopes == null) {
this.defaultScopes = ImmutableSet.<String>of();
} else {
List<String> scopeList = new ArrayList<String>(defaultScopes);
scopeList.removeAll(Arrays.asList("", null));
this.defaultScopes = ImmutableSet.<String>copyOf(scopeList);
arithmetic1728 marked this conversation as resolved.
Show resolved Hide resolved
}
}

/** Clones the compute engine account with the specified scopes. */
@Override
public GoogleCredentials createScoped(Collection<String> newScopes) {
return new ComputeEngineCredentials(this.transportFactory, newScopes);
return new ComputeEngineCredentials(this.transportFactory, newScopes, null);
}

/** Clones the compute engine account with the specified scopes. */
@Override
public GoogleCredentials createScoped(
Collection<String> newScopes, Collection<String> newDefaultScopes) {
return new ComputeEngineCredentials(this.transportFactory, newScopes, newDefaultScopes);
}

/**
Expand All @@ -138,22 +157,30 @@ public GoogleCredentials createScoped(Collection<String> newScopes) {
* @return new ComputeEngineCredentials
*/
public static ComputeEngineCredentials create() {
return new ComputeEngineCredentials(null, null);
return new ComputeEngineCredentials(null, null, null);
}

public final Collection<String> getScopes() {
return scopes;
}

public final Collection<String> getDefaultScopes() {
return defaultScopes;
}

/**
* If scopes is specified, add "?scopes=comma-separated-list-of-scopes" to the token url.
* If scopes or defaultScopes is specified, add "?scopes=comma-separated-list-of-scopes" to the
* token url. defaultScopes is not used unless scopes is empty.
*
* @return token url with the given scopes
* @return token url with the given scopes or defaultScopes. defaultScopes is not used unless
* scopes is emtpy.
*/
String createTokenUrlWithScopes() {
GenericUrl tokenUrl = new GenericUrl(getTokenServerEncodedUrl());
if (!scopes.isEmpty()) {
tokenUrl.set("scopes", Joiner.on(',').join(scopes));
} else if (!defaultScopes.isEmpty()) {
tokenUrl.set("scopes", Joiner.on(',').join(defaultScopes));
}
return tokenUrl.toString();
}
Expand Down Expand Up @@ -345,7 +372,8 @@ public boolean equals(Object obj) {
}
ComputeEngineCredentials other = (ComputeEngineCredentials) obj;
return Objects.equals(this.transportFactoryClassName, other.transportFactoryClassName)
&& Objects.equals(this.scopes, other.scopes);
&& Objects.equals(this.scopes, other.scopes)
&& Objects.equals(this.defaultScopes, other.defaultScopes);
}

private void readObject(ObjectInputStream input) throws IOException, ClassNotFoundException {
Expand Down Expand Up @@ -438,12 +466,14 @@ private String getDefaultServiceAccount() throws IOException {
public static class Builder extends GoogleCredentials.Builder {
private HttpTransportFactory transportFactory;
private Collection<String> scopes;
private Collection<String> defaultScopes;

protected Builder() {}

protected Builder(ComputeEngineCredentials credentials) {
this.transportFactory = credentials.transportFactory;
this.scopes = credentials.scopes;
this.defaultScopes = credentials.defaultScopes;
}

public Builder setHttpTransportFactory(HttpTransportFactory transportFactory) {
Expand All @@ -453,6 +483,13 @@ public Builder setHttpTransportFactory(HttpTransportFactory transportFactory) {

public Builder setScopes(Collection<String> scopes) {
this.scopes = scopes;
this.defaultScopes = null;
return this;
}

public Builder setScopes(Collection<String> scopes, Collection<String> defaultScopes) {
arithmetic1728 marked this conversation as resolved.
Show resolved Hide resolved
this.scopes = scopes;
this.defaultScopes = defaultScopes;
return this;
}

Expand All @@ -464,8 +501,12 @@ public Collection<String> getScopes() {
return scopes;
}

public Collection<String> getDefaultScopes() {
return defaultScopes;
}

public ComputeEngineCredentials build() {
return new ComputeEngineCredentials(transportFactory, scopes);
return new ComputeEngineCredentials(transportFactory, scopes, defaultScopes);
}
}
}
Expand Up @@ -301,7 +301,8 @@ private GoogleCredentials tryGetAppEngineCredential() throws IOException {
if (!onAppEngine) {
return null;
}
return new AppEngineCredentials(Collections.<String>emptyList());
return new AppEngineCredentials(
Collections.<String>emptyList(), Collections.<String>emptyList());
}

private final GoogleCredentials tryGetComputeCredentials(HttpTransportFactory transportFactory) {
Expand Down
14 changes: 14 additions & 0 deletions oauth2_http/java/com/google/auth/oauth2/GoogleCredentials.java
Expand Up @@ -232,6 +232,20 @@ public GoogleCredentials createScoped(Collection<String> scopes) {
return this;
}

/**
* If the credentials support scopes, creates a copy of the the identity with the specified scopes
* and default scopes; otherwise, returns the same instance. This is mainly used by client
* libraries.
*
* @param scopes Collection of scopes to request.
* @param defaultScopes Collection of default scopes to request.
* @return GoogleCredentials with requested scopes.
*/
public GoogleCredentials createScoped(
Collection<String> scopes, Collection<String> defaultScopes) {
return this;
}

/**
* If the credentials support scopes, creates a copy of the the identity with the specified
* scopes; otherwise, returns the same instance.
Expand Down