mirror of
https://github.com/google/nomulus.git
synced 2025-05-02 21:17:50 +02:00
ModulesService does not provide a great API. Specifically, it doesn't have a way to get the hostname for a specific service; you have to get the hostname for a specific version as well. This is very rarely what we want, as we publish new versions every week and don't expect old ones to hang around for very long, so a task should execute against whatever the live version is, not whatever the current version was back when the task was enqueued (especially because that version might be deleted by now). This new and improved wrapper API removes the confusion and plays better with dependency injection to boot. We can also fold in other methods having to do with App Engine services, whereas ModulesService was quite limited in scope. This also has the side effect of fixing ResaveEntityAction, which is currently broken because the tasks it's enqueuing to execute up to 30 days in the future have the version hard-coded into the hostname, and we typically delete old versions sooner than that. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=206173763
240 lines
8.9 KiB
Java
240 lines
8.9 KiB
Java
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package google.registry.request;
|
|
|
|
import static com.google.appengine.api.datastore.DatastoreServiceFactory.getDatastoreService;
|
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
|
|
|
import com.google.api.client.extensions.appengine.http.UrlFetchTransport;
|
|
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
|
|
import com.google.api.client.googleapis.extensions.appengine.auth.oauth2.AppIdentityCredential;
|
|
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
|
|
import com.google.api.client.http.HttpRequestInitializer;
|
|
import com.google.api.client.http.HttpTransport;
|
|
import com.google.api.client.http.javanet.NetHttpTransport;
|
|
import com.google.api.client.json.JsonFactory;
|
|
import com.google.api.client.json.jackson2.JacksonFactory;
|
|
import com.google.appengine.api.datastore.DatastoreService;
|
|
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;
|
|
|
|
/** Dagger modules for App Engine services and other vendor classes. */
|
|
public final class Modules {
|
|
|
|
/** Dagger module for {@link DatastoreService}. */
|
|
@Module
|
|
public static final class DatastoreServiceModule {
|
|
private static final DatastoreService datastoreService = getDatastoreService();
|
|
|
|
@Provides
|
|
static DatastoreService provideDatastoreService() {
|
|
return datastoreService;
|
|
}
|
|
}
|
|
|
|
/** Dagger module for {@link URLFetchService}. */
|
|
@Module
|
|
public static final class URLFetchServiceModule {
|
|
private static final URLFetchService fetchService = URLFetchServiceFactory.getURLFetchService();
|
|
|
|
@Provides
|
|
static URLFetchService provideURLFetchService() {
|
|
return fetchService;
|
|
}
|
|
}
|
|
|
|
/** Dagger module for {@link UserService}. */
|
|
@Module
|
|
public static final class UserServiceModule {
|
|
private static final UserService userService = UserServiceFactory.getUserService();
|
|
|
|
@Provides
|
|
static UserService provideUserService() {
|
|
return userService;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Dagger module that causes the Jackson2 JSON parser to be used for Google APIs requests.
|
|
*
|
|
* <p>Jackson1 and GSON can also satisfy the {@link JsonFactory} interface, but we've decided to
|
|
* go with Jackson2, since it's what's used in the public examples for using Google APIs.
|
|
*/
|
|
@Module
|
|
public static final class Jackson2Module {
|
|
@Provides
|
|
static JsonFactory provideJsonFactory() {
|
|
return JacksonFactory.getDefaultInstance();
|
|
}
|
|
}
|
|
|
|
/** Dagger module that causes the App Engine's URL fetcher to be used for Google APIs requests. */
|
|
@Module
|
|
public static final class UrlFetchTransportModule {
|
|
private static final UrlFetchTransport HTTP_TRANSPORT = new UrlFetchTransport();
|
|
|
|
@Provides
|
|
static HttpTransport provideHttpTransport() {
|
|
return HTTP_TRANSPORT;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Dagger module that provides standard {@link NetHttpTransport}. Used in non App Engine
|
|
* environment.
|
|
*/
|
|
@Module
|
|
public static final class NetHttpTransportModule {
|
|
|
|
@Provides
|
|
@Singleton
|
|
static NetHttpTransport provideNetHttpTransport() {
|
|
try {
|
|
return GoogleNetHttpTransport.newTrustedTransport();
|
|
} catch (Exception e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Dagger module providing {@link AppIdentityCredential}.
|
|
*
|
|
* <p>This can be used to authenticate to Google APIs using the identity of your GAE app.
|
|
*
|
|
* @see UseAppIdentityCredentialForGoogleApisModule
|
|
*/
|
|
@Module
|
|
public static final class AppIdentityCredentialModule {
|
|
@Provides
|
|
static Function<Set<String>, AppIdentityCredential> provideAppIdentityCredential() {
|
|
return AppIdentityCredential::new;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Dagger module causing Google APIs requests to be authorized with your GAE app identity.
|
|
*
|
|
* <p>You must also use the {@link AppIdentityCredentialModule}.
|
|
*/
|
|
@Module
|
|
public abstract static class UseAppIdentityCredentialForGoogleApisModule {
|
|
@Binds
|
|
abstract Function<Set<String>, ? extends HttpRequestInitializer> provideHttpRequestInitializer(
|
|
Function<Set<String>, AppIdentityCredential> credential);
|
|
}
|
|
|
|
/**
|
|
* Module indicating Google API requests should be authorized with JSON {@link GoogleCredential}.
|
|
*
|
|
* <p>This is useful when configuring a component that runs the registry outside of the App Engine
|
|
* environment, for example, in a command line environment.
|
|
*
|
|
* <p>You must also use the {@link GoogleCredentialModule}.
|
|
*/
|
|
@Module
|
|
public abstract static class UseGoogleCredentialForGoogleApisModule {
|
|
@Binds
|
|
abstract Function<Set<String>, ? extends HttpRequestInitializer> provideHttpRequestInitializer(
|
|
Function<Set<String>, GoogleCredential> credential);
|
|
}
|
|
|
|
/**
|
|
* Dagger module providing {@link GoogleCredential} from a JSON key file contents.
|
|
*
|
|
* <p>This satisfies the {@link HttpRequestInitializer} interface for authenticating Google APIs
|
|
* requests, just like {@link AppIdentityCredential}.
|
|
*
|
|
* <p>But we consider GAE authentication more desirable and easier to manage operations-wise. So
|
|
* this authentication method should only be used for the following situations:
|
|
*
|
|
* <ol>
|
|
* <li>Locally-running programs (which aren't executing on the App Engine platform)
|
|
* <li>Spreadsheet service (which can't use {@link AppIdentityCredential} due to an old library)
|
|
* </ol>
|
|
*
|
|
* @see google.registry.keyring.api.Keyring#getJsonCredential()
|
|
*/
|
|
@Module
|
|
public static final class GoogleCredentialModule {
|
|
|
|
@Provides
|
|
@Singleton
|
|
static GoogleCredential provideGoogleCredential(
|
|
NetHttpTransport netHttpTransport,
|
|
JsonFactory jsonFactory,
|
|
@Key("jsonCredential") String jsonCredential) {
|
|
try {
|
|
return GoogleCredential.fromStream(
|
|
new ByteArrayInputStream(jsonCredential.getBytes(UTF_8)),
|
|
netHttpTransport,
|
|
jsonFactory);
|
|
} catch (IOException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
|
|
@Provides
|
|
static Function<Set<String>, GoogleCredential> provideScopedGoogleCredential(
|
|
final Provider<GoogleCredential> 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.
|
|
*
|
|
* <p>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();
|
|
}
|
|
}
|
|
}
|