diff --git a/java/google/registry/config/CredentialModule.java b/java/google/registry/config/CredentialModule.java index 4061fd1b6..b6ba7fa52 100644 --- a/java/google/registry/config/CredentialModule.java +++ b/java/google/registry/config/CredentialModule.java @@ -79,6 +79,29 @@ public abstract class CredentialModule { return credential; } + /** + * Provides a {@link GoogleCredential} with delegated admin access for a G Suite domain. + * + *

The G Suite domain must grant delegated admin access to the registry service account with + * all scopes in {@code requiredScopes}, including ones not related to G Suite. + */ + @DelegatedCredential + @Provides + @Singleton + public static GoogleCredential provideDelegatedCredential( + @Config("credentialOauthScopes") ImmutableList requiredScopes, + @JsonCredential GoogleCredential googleCredential, + @Config("gSuiteAdminAccountEmailAddress") String gSuiteAdminAccountEmailAddress) { + return new GoogleCredential.Builder() + .setTransport(Utils.getDefaultTransport()) + .setJsonFactory(Utils.getDefaultJsonFactory()) + .setServiceAccountId(googleCredential.getServiceAccountId()) + .setServiceAccountPrivateKey(googleCredential.getServiceAccountPrivateKey()) + .setServiceAccountScopes(requiredScopes) + .setServiceAccountUser(gSuiteAdminAccountEmailAddress) + .build(); + } + /** Dagger qualifier for the Application Default Credential. */ @Qualifier public @interface DefaultCredential {} diff --git a/java/google/registry/config/files/default-config.yaml b/java/google/registry/config/files/default-config.yaml index 3ba24741e..2ff11252b 100644 --- a/java/google/registry/config/files/default-config.yaml +++ b/java/google/registry/config/files/default-config.yaml @@ -185,10 +185,7 @@ credentialOAuth: - https://www.googleapis.com/auth/drive # View and manage groups on your domain in Directory API. - https://www.googleapis.com/auth/admin.directory.group - # Inherited from current code. - # TODO(weiminyu): verify if the scope above is sufficient by itself. - - https://www.googleapis.com/auth/admin.directory.group.member - # View and manage the settings of a Google Apps Group. + # View and manage group settings in Group Settings API. - https://www.googleapis.com/auth/apps.groups.settings icannReporting: diff --git a/java/google/registry/groups/DirectoryModule.java b/java/google/registry/groups/DirectoryModule.java index 700efc48e..e5fe05f6c 100644 --- a/java/google/registry/groups/DirectoryModule.java +++ b/java/google/registry/groups/DirectoryModule.java @@ -16,12 +16,10 @@ package google.registry.groups; import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; import com.google.api.services.admin.directory.Directory; -import com.google.api.services.admin.directory.DirectoryScopes; -import com.google.common.collect.ImmutableSet; import dagger.Module; import dagger.Provides; +import google.registry.config.CredentialModule.DelegatedCredential; import google.registry.config.RegistryConfig.Config; -import javax.inject.Named; /** Dagger module for the Google {@link Directory} service. */ @Module @@ -29,15 +27,8 @@ public final class DirectoryModule { @Provides static Directory provideDirectory( - @Named("delegatedAdmin") GoogleCredential credential, - @Config("projectId") String projectId) { - return new Directory.Builder( - credential.getTransport(), - credential.getJsonFactory(), - credential.createScoped( - ImmutableSet.of( - DirectoryScopes.ADMIN_DIRECTORY_GROUP_MEMBER, - DirectoryScopes.ADMIN_DIRECTORY_GROUP))) + @DelegatedCredential GoogleCredential credential, @Config("projectId") String projectId) { + return new Directory.Builder(credential.getTransport(), credential.getJsonFactory(), credential) .setApplicationName(projectId) .build(); } diff --git a/java/google/registry/groups/GroupssettingsModule.java b/java/google/registry/groups/GroupssettingsModule.java index 7fe3ac481..23621e58c 100644 --- a/java/google/registry/groups/GroupssettingsModule.java +++ b/java/google/registry/groups/GroupssettingsModule.java @@ -16,12 +16,10 @@ package google.registry.groups; import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; import com.google.api.services.groupssettings.Groupssettings; -import com.google.api.services.groupssettings.GroupssettingsScopes; -import com.google.common.collect.ImmutableSet; import dagger.Module; import dagger.Provides; +import google.registry.config.CredentialModule.DelegatedCredential; import google.registry.config.RegistryConfig.Config; -import javax.inject.Named; /** Dagger module for the Google {@link Groupssettings} service. */ @Module @@ -29,12 +27,9 @@ public final class GroupssettingsModule { @Provides static Groupssettings provideDirectory( - @Named("delegatedAdmin") GoogleCredential credential, - @Config("projectId") String projectId) { + @DelegatedCredential GoogleCredential credential, @Config("projectId") String projectId) { return new Groupssettings.Builder( - credential.getTransport(), - credential.getJsonFactory(), - credential.createScoped(ImmutableSet.of(GroupssettingsScopes.APPS_GROUPS_SETTINGS))) + credential.getTransport(), credential.getJsonFactory(), credential) .setApplicationName(projectId) .build(); } diff --git a/java/google/registry/request/Modules.java b/java/google/registry/request/Modules.java index a0fe007c9..5b9cdf0ff 100644 --- a/java/google/registry/request/Modules.java +++ b/java/google/registry/request/Modules.java @@ -31,17 +31,14 @@ import com.google.appengine.api.urlfetch.URLFetchService; import com.google.appengine.api.urlfetch.URLFetchServiceFactory; import com.google.appengine.api.users.UserService; import com.google.appengine.api.users.UserServiceFactory; -import com.google.common.collect.ImmutableSet; import dagger.Binds; import dagger.Module; import dagger.Provides; -import google.registry.config.RegistryConfig.Config; import google.registry.keyring.api.KeyModule.Key; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.Set; import java.util.function.Function; -import javax.inject.Named; import javax.inject.Provider; import javax.inject.Singleton; @@ -206,35 +203,5 @@ public final class Modules { final Provider googleCredentialProvider) { return scopes -> googleCredentialProvider.get().createScoped(scopes); } - - /** - * Provides a GoogleCredential that will connect to GAE using delegated admin access. This is - * needed for API calls requiring domain admin access to the relevant GAFYD using delegated - * scopes, e.g. the Directory API and the Groupssettings API. - * - *

Note that you must call {@link GoogleCredential#createScoped} on the credential provided - * by this method first before using it, as this does not and cannot set the scopes, and a - * credential without scopes doesn't actually provide access to do anything. - */ - @Provides - @Singleton - @Named("delegatedAdmin") - static GoogleCredential provideDelegatedAdminGoogleCredential( - GoogleCredential googleCredential, - HttpTransport httpTransport, - @Config("gSuiteAdminAccountEmailAddress") String gSuiteAdminAccountEmailAddress) { - return new GoogleCredential.Builder() - .setTransport(httpTransport) - .setJsonFactory(googleCredential.getJsonFactory()) - .setServiceAccountId(googleCredential.getServiceAccountId()) - .setServiceAccountPrivateKey(googleCredential.getServiceAccountPrivateKey()) - // Set the scopes to empty because the default value is null, which throws an NPE in the - // GoogleCredential constructor. We don't yet know the actual scopes to use here, and it - // is thus the responsibility of every user of a delegated admin credential to call - // createScoped() on it first to get the version with the correct scopes set. - .setServiceAccountScopes(ImmutableSet.of()) - .setServiceAccountUser(gSuiteAdminAccountEmailAddress) - .build(); - } } }