mirror of
https://github.com/google/nomulus
synced 2026-01-09 07:33:42 +00:00
The scenarios in which the credential is used are: 1) Calls to Nomulus GAE HTTP endpoints. 2) Calls to Google APIs within the tool. 3) Calls to GAE APIs within the tool. From now on the tool should not depend on ADCs created from gcloud any more (expect for beam pipeline deployments which need some more investigation as the dependency on ADC is not apparent). Using the nomulus tool requires running "nomulus login" first, but only once. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=224165735
216 lines
7.5 KiB
Java
216 lines
7.5 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.tools;
|
|
|
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
|
|
|
import com.google.api.client.auth.oauth2.Credential;
|
|
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
|
|
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
|
|
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
|
|
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
|
|
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets.Details;
|
|
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
|
|
import com.google.api.client.http.javanet.NetHttpTransport;
|
|
import com.google.api.client.json.JsonFactory;
|
|
import com.google.api.client.util.store.AbstractDataStoreFactory;
|
|
import com.google.api.client.util.store.FileDataStoreFactory;
|
|
import com.google.common.base.Joiner;
|
|
import com.google.common.base.Supplier;
|
|
import com.google.common.collect.ImmutableList;
|
|
import com.google.common.collect.ImmutableMap;
|
|
import com.google.common.collect.Ordering;
|
|
import com.google.gson.Gson;
|
|
import dagger.Binds;
|
|
import dagger.Module;
|
|
import dagger.Provides;
|
|
import google.registry.config.CredentialModule.DefaultCredential;
|
|
import google.registry.config.RegistryConfig.Config;
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.lang.annotation.Documented;
|
|
import java.lang.annotation.Retention;
|
|
import java.lang.annotation.RetentionPolicy;
|
|
import javax.inject.Qualifier;
|
|
import javax.inject.Singleton;
|
|
|
|
/**
|
|
* Module providing the dependency graph for authorization credentials.
|
|
*/
|
|
@Module
|
|
public class AuthModule {
|
|
|
|
private static final File DATA_STORE_DIR =
|
|
new File(System.getProperty("user.home"), ".config/nomulus/credentials");
|
|
|
|
@Module
|
|
abstract static class LocalCredentialModule {
|
|
@Binds
|
|
@DefaultCredential
|
|
abstract GoogleCredential provideLocalCredentialAsDefaultCredential(
|
|
@LocalCredential GoogleCredential credential);
|
|
}
|
|
|
|
@Provides
|
|
@StoredCredential
|
|
static Credential provideCredential(
|
|
GoogleAuthorizationCodeFlow flow, @ClientScopeQualifier String clientScopeQualifier) {
|
|
try {
|
|
// Try to load the credentials, throw an exception if we fail.
|
|
Credential credential = flow.loadCredential(clientScopeQualifier);
|
|
if (credential == null) {
|
|
throw new LoginRequiredException();
|
|
}
|
|
return credential;
|
|
} catch (IOException ex) {
|
|
throw new RuntimeException(ex);
|
|
}
|
|
}
|
|
|
|
@Provides
|
|
@LocalCredential
|
|
public static GoogleCredential provideLocalCredential(
|
|
@LocalCredentialStream Supplier<InputStream> credentialStream) {
|
|
try {
|
|
return GoogleCredential.fromStream(credentialStream.get());
|
|
} catch (IOException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
|
|
@Provides
|
|
public static GoogleAuthorizationCodeFlow provideAuthorizationCodeFlow(
|
|
JsonFactory jsonFactory,
|
|
GoogleClientSecrets clientSecrets,
|
|
@Config("localCredentialOauthScopes") ImmutableList<String> requiredOauthScopes,
|
|
AbstractDataStoreFactory dataStoreFactory) {
|
|
try {
|
|
return new GoogleAuthorizationCodeFlow.Builder(
|
|
new NetHttpTransport(), jsonFactory, clientSecrets, requiredOauthScopes)
|
|
.setDataStoreFactory(dataStoreFactory)
|
|
.build();
|
|
} catch (IOException ex) {
|
|
throw new RuntimeException(ex);
|
|
}
|
|
}
|
|
|
|
@Provides
|
|
public static AuthorizationCodeInstalledApp provideAuthorizationCodeInstalledApp(
|
|
GoogleAuthorizationCodeFlow flow) {
|
|
return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver());
|
|
}
|
|
|
|
@Provides
|
|
static Details provideDefaultInstalledDetails() {
|
|
return new Details()
|
|
.setAuthUri("https://accounts.google.com/o/oauth2/auth")
|
|
.setTokenUri("https://accounts.google.com/o/oauth2/token")
|
|
.setRedirectUris(ImmutableList.of("urn:ietf:wg:oauth:2.0:oob", "http://localhost"));
|
|
}
|
|
|
|
@Provides
|
|
public static GoogleClientSecrets provideClientSecrets(
|
|
@Config("toolsClientId") String clientId,
|
|
@Config("toolsClientSecret") String clientSecret,
|
|
Details details) {
|
|
return new GoogleClientSecrets()
|
|
.setInstalled(details.setClientId(clientId).setClientSecret(clientSecret));
|
|
}
|
|
|
|
@Provides
|
|
@LocalCredentialStream
|
|
public static Supplier<InputStream> provideLocalCredentialStream(
|
|
GoogleClientSecrets clientSecrets, @StoredCredential Credential credential) {
|
|
String json =
|
|
new Gson()
|
|
.toJson(
|
|
ImmutableMap.<String, String>builder()
|
|
.put("type", "authorized_user")
|
|
.put("client_id", clientSecrets.getDetails().getClientId())
|
|
.put("client_secret", clientSecrets.getDetails().getClientSecret())
|
|
.put("refresh_token", credential.getRefreshToken())
|
|
.build());
|
|
// A supplier is provided so that each binding gets a fresh stream, to avoid contention.
|
|
return () -> new ByteArrayInputStream(json.getBytes(UTF_8));
|
|
}
|
|
|
|
@Provides
|
|
@OAuthClientId
|
|
static String provideClientId(GoogleClientSecrets clientSecrets) {
|
|
return clientSecrets.getDetails().getClientId();
|
|
}
|
|
|
|
@Provides
|
|
@ClientScopeQualifier
|
|
static String provideClientScopeQualifier(
|
|
@OAuthClientId String clientId,
|
|
@Config("localCredentialOauthScopes") ImmutableList<String> scopes) {
|
|
return clientId + " " + Joiner.on(" ").join(Ordering.natural().sortedCopy(scopes));
|
|
}
|
|
|
|
@Provides
|
|
@Singleton
|
|
public static AbstractDataStoreFactory provideDataStoreFactory() {
|
|
try {
|
|
return new FileDataStoreFactory(DATA_STORE_DIR);
|
|
} catch (IOException ex) {
|
|
throw new RuntimeException(ex);
|
|
}
|
|
}
|
|
|
|
/** Raised when we need a user login. */
|
|
static class LoginRequiredException extends RuntimeException {
|
|
LoginRequiredException() {}
|
|
}
|
|
|
|
/**
|
|
* Dagger qualifier for the {@link Credential} constructed from the data stored on disk.
|
|
*
|
|
* <p>This {@link Credential} should not be used in another module, hence the private qualifier.
|
|
* It's only use is to build a {@link GoogleCredential}, which is used in injection sites
|
|
* elsewhere.
|
|
*/
|
|
@Qualifier
|
|
@Documented
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
private @interface StoredCredential {}
|
|
|
|
/** Dagger qualifier for the local credential used in the nomulus tool. */
|
|
@Qualifier
|
|
@Documented
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface LocalCredential {}
|
|
|
|
/** Dagger qualifier for the JSON stream used to create the local credential. */
|
|
@Qualifier
|
|
@Documented
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface LocalCredentialStream {}
|
|
|
|
/** Dagger qualifier for the credential qualifier consisting of client and scopes. */
|
|
@Qualifier
|
|
@Documented
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface ClientScopeQualifier {}
|
|
|
|
/** Dagger qualifier for the OAuth2 client id. */
|
|
@Qualifier
|
|
@Documented
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@interface OAuthClientId {}
|
|
}
|