diff --git a/java/google/registry/tools/AuthModule.java b/java/google/registry/tools/AuthModule.java new file mode 100644 index 000000000..ac91335eb --- /dev/null +++ b/java/google/registry/tools/AuthModule.java @@ -0,0 +1,155 @@ +// 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.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.collect.ImmutableSet; +import com.google.common.collect.Ordering; +import dagger.Module; +import dagger.Provides; +import google.registry.config.RegistryConfig.Config; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +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"); + + @Provides + public 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 + GoogleAuthorizationCodeFlow provideAuthorizationCodeFlow( + JsonFactory jsonFactory, + GoogleClientSecrets clientSecrets, + @Config("requiredOauthScopes") ImmutableSet requiredOauthScopes, + AbstractDataStoreFactory dataStoreFactory) { + try { + return new GoogleAuthorizationCodeFlow.Builder( + new NetHttpTransport(), jsonFactory, clientSecrets, requiredOauthScopes) + .setDataStoreFactory(dataStoreFactory) + .build(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + + @Provides + AuthorizationCodeInstalledApp provideAuthorizationCodeInstalledApp( + GoogleAuthorizationCodeFlow flow) { + return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()); + } + + @Provides + GoogleClientSecrets provideClientSecrets( + @Config("clientSecretFilename") String clientSecretFilename, JsonFactory jsonFactory) { + try { + // Load the client secrets file. + InputStream secretResourceStream = getClass().getResourceAsStream(clientSecretFilename); + if (secretResourceStream == null) { + throw new RuntimeException("No client secret file found: " + clientSecretFilename); + } + return GoogleClientSecrets.load(jsonFactory, + new InputStreamReader(secretResourceStream, UTF_8)); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + + @Provides + @OAuthClientId String provideClientId(GoogleClientSecrets clientSecrets) { + return clientSecrets.getDetails().getClientId(); + } + + @Provides + @ClientScopeQualifier String provideClientScopeQualifier( + @OAuthClientId String clientId, @Config("requiredOauthScopes") ImmutableSet scopes) { + return clientId + " " + Joiner.on(" ").join(Ordering.natural().sortedCopy(scopes)); + } + + @Provides + @Singleton + public AbstractDataStoreFactory provideDataStoreFactory() { + try { + return new FileDataStoreFactory(DATA_STORE_DIR); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + + /** Wrapper class to hold the login() function. */ + public static class Authorizer { + /** Initiate the login flow. */ + public static void login( + GoogleAuthorizationCodeFlow flow, + @ClientScopeQualifier String clientScopeQualifier) throws Exception { + new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()) + .authorize(clientScopeQualifier); + } + } + + /** Raised when we need a user login. */ + public static class LoginRequiredException extends RuntimeException { + public LoginRequiredException() {} + } + + /** Dagger qualifier for the credential qualifier consisting of client and scopes. */ + @Qualifier + @Documented + @Retention(RetentionPolicy.RUNTIME) + public @interface ClientScopeQualifier {} + + /** Dagger qualifier for the OAuth2 client id. */ + @Qualifier + @Documented + @Retention(RetentionPolicy.RUNTIME) + public @interface OAuthClientId {} +} diff --git a/java/google/registry/tools/DefaultRequestFactoryModule.java b/java/google/registry/tools/DefaultRequestFactoryModule.java index b8f265200..93d493501 100644 --- a/java/google/registry/tools/DefaultRequestFactoryModule.java +++ b/java/google/registry/tools/DefaultRequestFactoryModule.java @@ -14,37 +14,16 @@ 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.http.HttpRequest; import com.google.api.client.http.HttpRequestFactory; import com.google.api.client.http.HttpRequestInitializer; 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.api.client.util.store.AbstractDataStoreFactory; -import com.google.api.client.util.store.FileDataStoreFactory; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Joiner; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Ordering; import dagger.Binds; import dagger.Module; import dagger.Provides; -import google.registry.config.RegistryConfig.Config; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.Collection; import javax.inject.Named; import javax.inject.Provider; -import javax.inject.Singleton; /** * Module for providing the default HttpRequestFactory. @@ -63,31 +42,6 @@ import javax.inject.Singleton; @Module class DefaultRequestFactoryModule { - private static final File DATA_STORE_DIR = - new File(System.getProperty("user.home"), ".config/nomulus/credentials"); - - /** Returns the credential object for the user. */ - @Provides - Credential provideCredential( - AbstractDataStoreFactory dataStoreFactory, - Authorizer authorizer, - @Config("clientSecretFilename") String clientSecretFilename) { - try { - // Load the client secrets file. - JacksonFactory jsonFactory = new JacksonFactory(); - InputStream secretResourceStream = getClass().getResourceAsStream(clientSecretFilename); - if (secretResourceStream == null) { - throw new RuntimeException("No client secret file found: " + clientSecretFilename); - } - GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(jsonFactory, - new InputStreamReader(secretResourceStream, UTF_8)); - - return authorizer.authorize(clientSecrets); - } catch (IOException ex) { - throw new RuntimeException(ex); - } - } - @Provides @Named("default") public HttpRequestFactory provideHttpRequestFactory( @@ -123,66 +77,4 @@ class DefaultRequestFactoryModule { public abstract HttpRequestFactory provideHttpRequestFactory( @Named("default") HttpRequestFactory requestFactory); } - - @Module - static class DataStoreFactoryModule { - @Provides - @Singleton - public AbstractDataStoreFactory provideDataStoreFactory() { - try { - return new FileDataStoreFactory(DATA_STORE_DIR); - } catch (IOException ex) { - throw new RuntimeException(ex); - } - } - } - - /** - * Module to create the Authorizer used by DefaultRequestFactoryModule. - */ - @Module - static class AuthorizerModule { - @Provides - public Authorizer provideAuthorizer( - final JsonFactory jsonFactory, - final AbstractDataStoreFactory dataStoreFactory, - @Config("requiredOauthScopes") final ImmutableSet requiredOauthScopes) { - return new Authorizer() { - @Override - public Credential authorize(GoogleClientSecrets clientSecrets) { - try { - // Run a new auth flow. - GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder( - new NetHttpTransport(), jsonFactory, clientSecrets, requiredOauthScopes) - .setDataStoreFactory(dataStoreFactory) - .build(); - - - return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()) - .authorize(createClientScopeQualifier( - clientSecrets.getDetails().getClientId(), requiredOauthScopes)); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - }; - } - } - - /** - * Create a unique identifier for a given client id and collection of scopes, to be used as an - * identifier for a credential. - */ - @VisibleForTesting - static String createClientScopeQualifier(String clientId, Collection scopes) { - return clientId + " " + Joiner.on(" ").join(Ordering.natural().sortedCopy(scopes)); - } - - /** - * Interface that encapsulates the authorization logic to produce a credential for the user, - * allowing us to override the behavior for unit tests. - */ - interface Authorizer { - Credential authorize(GoogleClientSecrets clientSecrets); - } } diff --git a/java/google/registry/tools/LoginCommand.java b/java/google/registry/tools/LoginCommand.java new file mode 100644 index 000000000..922072132 --- /dev/null +++ b/java/google/registry/tools/LoginCommand.java @@ -0,0 +1,33 @@ +// 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 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 javax.inject.Inject; + +/** Authorizes the nomulus tool for OAuth 2.0 access to remote resources. */ +final class LoginCommand implements Command { + + @Inject GoogleAuthorizationCodeFlow flow; + @Inject @AuthModule.ClientScopeQualifier String clientScopeQualifier; + + @Override + public void run() throws Exception { + new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()) + .authorize(clientScopeQualifier); + } +} \ No newline at end of file diff --git a/java/google/registry/tools/LogoutCommand.java b/java/google/registry/tools/LogoutCommand.java new file mode 100644 index 000000000..ca1c8d70c --- /dev/null +++ b/java/google/registry/tools/LogoutCommand.java @@ -0,0 +1,36 @@ +// 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 com.google.api.client.auth.oauth2.StoredCredential; +import com.google.api.client.util.store.AbstractDataStoreFactory; +import google.registry.util.FormattingLogger; +import java.io.IOException; +import javax.inject.Inject; + +/** Logout (invalidates OAuth credentials). */ +class LogoutCommand implements Command { + + private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass(); + + @Inject AbstractDataStoreFactory dataStoreFactory; + @Inject @AuthModule.ClientScopeQualifier String clientScopeQualifier; + + @Override + public void run() throws IOException { + StoredCredential.getDefaultDataStore(dataStoreFactory).clear(); + logger.infofmt("Logged out - credentials have been removed."); + } +} diff --git a/java/google/registry/tools/RegistryCli.java b/java/google/registry/tools/RegistryCli.java index da6147a01..4cefe89ef 100644 --- a/java/google/registry/tools/RegistryCli.java +++ b/java/google/registry/tools/RegistryCli.java @@ -125,11 +125,23 @@ final class RegistryCli { injectReflectively(RegistryToolComponent.class, component, command); if (!(command instanceof RemoteApiCommand)) { + // TODO(mmuller): this should be in the try/catch LoginRequiredException in case future + // commands use our credential. command.run(); return; } - AppEngineConnection connection = component.appEngineConnection(); + // Get the App Engine connection, advise the user if they are not currently logged in.. + AppEngineConnection connection; + try { + connection = component.appEngineConnection(); + } catch (AuthModule.LoginRequiredException ex) { + System.err.println("==================================================================="); + System.err.println("You must login using 'nomulus login' prior to running this command."); + System.err.println("==================================================================="); + return; + } + if (command instanceof ServerSideCommand) { ((ServerSideCommand) command).setConnection(connection); } diff --git a/java/google/registry/tools/RegistryTool.java b/java/google/registry/tools/RegistryTool.java index f86361cb0..9777644c2 100644 --- a/java/google/registry/tools/RegistryTool.java +++ b/java/google/registry/tools/RegistryTool.java @@ -89,6 +89,8 @@ public final class RegistryTool { .put("list_reserved_lists", ListReservedListsCommand.class) .put("list_tlds", ListTldsCommand.class) .put("load_snapshot", LoadSnapshotCommand.class) + .put("login", LoginCommand.class) + .put("logout", LogoutCommand.class) .put("make_billing_tables", MakeBillingTablesCommand.class) .put("pending_escrow", PendingEscrowCommand.class) .put("publish_detail_report", PublishDetailReportCommand.class) diff --git a/java/google/registry/tools/RegistryToolComponent.java b/java/google/registry/tools/RegistryToolComponent.java index 7b26bfc1a..f03dc905e 100644 --- a/java/google/registry/tools/RegistryToolComponent.java +++ b/java/google/registry/tools/RegistryToolComponent.java @@ -40,12 +40,11 @@ import javax.inject.Singleton; @Component( modules = { AppEngineConnectionFlags.FlagsModule.class, + AuthModule.class, ConfigModule.class, DatastoreServiceModule.class, CloudDnsWriterModule.class, DefaultRequestFactoryModule.class, - DefaultRequestFactoryModule.AuthorizerModule.class, - DefaultRequestFactoryModule.DataStoreFactoryModule.class, DefaultRequestFactoryModule.RequestFactoryModule.class, DnsUpdateWriterModule.class, DummyKeyringModule.class, @@ -72,6 +71,8 @@ interface RegistryToolComponent { void inject(GenerateEscrowDepositCommand command); void inject(GhostrydeCommand command); void inject(ListCursorsCommand command); + void inject(LoginCommand command); + void inject(LogoutCommand command); void inject(PendingEscrowCommand command); void inject(SendEscrowReportToIcannCommand command); void inject(SetupOteCommand command); diff --git a/javatests/google/registry/tools/AuthModuleTest.java b/javatests/google/registry/tools/AuthModuleTest.java new file mode 100644 index 000000000..9d501c7e4 --- /dev/null +++ b/javatests/google/registry/tools/AuthModuleTest.java @@ -0,0 +1,137 @@ +// 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 com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.google.api.client.auth.oauth2.Credential; +import com.google.api.client.auth.oauth2.StoredCredential; +import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets; +import com.google.api.client.http.HttpRequest; +import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.client.util.store.AbstractDataStoreFactory; +import com.google.api.client.util.store.DataStore; +import com.google.common.collect.ImmutableSet; +import google.registry.testing.ExceptionRule; +import java.io.IOException; +import java.io.Serializable; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class AuthModuleTest { + private static final String TEST_CLIENT_SECRET_FILENAME = + "/google/registry/tools/resources/client_secret_UNITTEST.json"; + + private static final Credential FAKE_CREDENTIAL = new Credential( + new Credential.AccessMethod() { + @Override + public void intercept(HttpRequest request, String accessToken) throws IOException {} + + @Override + public String getAccessTokenFromRequest(HttpRequest request) { + return "MockAccessToken"; + } + }); + + @SuppressWarnings("unchecked") + DataStore dataStore = mock(DataStore.class); + + class FakeDataStoreFactory extends AbstractDataStoreFactory { + @Override + protected DataStore createDataStore(String id) { + @SuppressWarnings("unchecked") + DataStore result = (DataStore) dataStore; + return result; + } + } + + @Rule public final ExceptionRule thrown = new ExceptionRule(); + + @Test + public void test_clientScopeQualifier() { + AuthModule authModule = new AuthModule(); + String simpleQualifier = + authModule.provideClientScopeQualifier("client-id", ImmutableSet.of("foo", "bar")); + + // If we change the way we encode client id and scopes, this assertion will break. That's + // probably ok and you can just change the text. The things you have to be aware of are: + // - Names in the new encoding should have a low risk of collision with the old encoding. + // - Changing the encoding will force all OAuth users of the nomulus tool to do a new login + // (existing credentials will not be used). + assertThat(simpleQualifier).isEqualTo("client-id bar foo"); + + // Verify order independence. + assertThat(simpleQualifier).isEqualTo( + authModule.provideClientScopeQualifier("client-id", ImmutableSet.of("bar", "foo"))); + + // Verify changing client id produces a different value. + assertThat(simpleQualifier).isNotEqualTo( + authModule.provideClientScopeQualifier("new-client", ImmutableSet.of("bar", "foo"))); + + // Verify that adding/deleting/modifying scopes produces a different value. + assertThat(simpleQualifier).isNotEqualTo( + authModule.provideClientScopeQualifier("client id", ImmutableSet.of("bar", "foo", "baz"))); + assertThat(simpleQualifier).isNotEqualTo( + authModule.provideClientScopeQualifier("client id", ImmutableSet.of("barx", "foo"))); + assertThat(simpleQualifier).isNotEqualTo( + authModule.provideClientScopeQualifier("client id", ImmutableSet.of("bar", "foox"))); + assertThat(simpleQualifier).isNotEqualTo( + authModule.provideClientScopeQualifier("client id", ImmutableSet.of("bar"))); + + // Verify that delimiting works. + assertThat(simpleQualifier).isNotEqualTo( + authModule.provideClientScopeQualifier("client-id", ImmutableSet.of("barf", "oo"))); + assertThat(simpleQualifier).isNotEqualTo( + authModule.provideClientScopeQualifier("client-idb", ImmutableSet.of("ar", "foo"))); + } + + private Credential getCredential() { + // Reconstruct the entire dependency graph, injecting FakeDatastoreFactory and credential + // parameters. + AuthModule authModule = new AuthModule(); + JacksonFactory jsonFactory = new JacksonFactory(); + GoogleClientSecrets clientSecrets = + authModule.provideClientSecrets(TEST_CLIENT_SECRET_FILENAME, jsonFactory); + ImmutableSet scopes = ImmutableSet.of("scope1"); + return authModule.provideCredential( + authModule.provideAuthorizationCodeFlow( + jsonFactory, clientSecrets, scopes, new FakeDataStoreFactory()), + authModule.provideClientScopeQualifier(authModule.provideClientId(clientSecrets), scopes)); + } + + @Test + public void test_provideCredential() throws Exception { + when(dataStore.get("UNITTEST-CLIENT-ID scope1")).thenReturn( + new StoredCredential(FAKE_CREDENTIAL)); + Credential cred = getCredential(); + assertThat(cred.getAccessToken()).isEqualTo(FAKE_CREDENTIAL.getAccessToken()); + assertThat(cred.getRefreshToken()).isEqualTo(FAKE_CREDENTIAL.getRefreshToken()); + assertThat(cred.getExpirationTimeMilliseconds()).isEqualTo( + FAKE_CREDENTIAL.getExpirationTimeMilliseconds()); + } + + @Test + public void test_provideCredential_notStored() { + thrown.expect(AuthModule.LoginRequiredException.class); + // Doing this without the mock setup should cause us to throw an exception because the + // credential has not been stored. + getCredential(); + } +} diff --git a/javatests/google/registry/tools/BUILD b/javatests/google/registry/tools/BUILD index 1a6813cf4..a731ceff5 100644 --- a/javatests/google/registry/tools/BUILD +++ b/javatests/google/registry/tools/BUILD @@ -41,8 +41,8 @@ java_library( "@com_google_code_findbugs_jsr305", "@com_google_guava", "@com_google_http_client", + "@com_google_http_client_jackson2", "@com_google_oauth_client", - "@com_google_oauth_client_java6", "@com_google_re2j", "@com_google_truth", "@com_googlecode_json_simple", diff --git a/javatests/google/registry/tools/DefaultRequestFactoryModuleTest.java b/javatests/google/registry/tools/DefaultRequestFactoryModuleTest.java index 7382b96e8..58dba7181 100644 --- a/javatests/google/registry/tools/DefaultRequestFactoryModuleTest.java +++ b/javatests/google/registry/tools/DefaultRequestFactoryModuleTest.java @@ -15,20 +15,11 @@ package google.registry.tools; import static com.google.common.truth.Truth.assertThat; -import static google.registry.tools.DefaultRequestFactoryModule.createClientScopeQualifier; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; import com.google.api.client.auth.oauth2.Credential; -import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets; import com.google.api.client.http.HttpRequest; import com.google.api.client.http.HttpRequestFactory; import com.google.api.client.http.HttpRequestInitializer; -import com.google.api.client.util.store.AbstractDataStoreFactory; -import com.google.common.collect.ImmutableList; import com.google.common.net.HostAndPort; import google.registry.testing.Providers; import java.io.IOException; @@ -37,7 +28,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import org.mockito.ArgumentCaptor; @RunWith(JUnit4.class) public class DefaultRequestFactoryModuleTest { @@ -53,18 +43,8 @@ public class DefaultRequestFactoryModuleTest { } }); - private static final String TEST_CLIENT_SECRET_FILENAME = - "/google/registry/tools/resources/client_secret_UNITTEST.json"; - - // Mocks. - AbstractDataStoreFactory dataStoreFactory = mock(AbstractDataStoreFactory.class); - DefaultRequestFactoryModule.Authorizer authorizer = - mock(DefaultRequestFactoryModule.Authorizer.class); Provider credentialProvider = Providers.of(FAKE_CREDENTIAL); - // Captor for client secrets. - ArgumentCaptor secrets = ArgumentCaptor.forClass(GoogleClientSecrets.class); - DefaultRequestFactoryModule module = new DefaultRequestFactoryModule(); @Before @@ -72,19 +52,6 @@ public class DefaultRequestFactoryModuleTest { RegistryToolEnvironment.UNITTEST.setup(); } - @Test - public void test_getCredential() throws Exception { - when(authorizer.authorize(any(GoogleClientSecrets.class))).thenReturn(FAKE_CREDENTIAL); - Credential cred = module.provideCredential( - dataStoreFactory, - authorizer, - TEST_CLIENT_SECRET_FILENAME); - assertThat(cred).isSameAs(FAKE_CREDENTIAL); - verify(authorizer).authorize(secrets.capture()); - assertThat(secrets.getValue().getDetails().getClientId()).isEqualTo( - "UNITTEST-CLIENT-ID"); - } - @Test public void test_provideHttpRequestFactory_localhost() throws Exception { // Make sure that localhost creates a request factory with an initializer. @@ -95,7 +62,6 @@ public class DefaultRequestFactoryModuleTest { HttpRequestInitializer initializer = factory.getInitializer(); assertThat(initializer).isNotNull(); assertThat(initializer).isNotSameAs(FAKE_CREDENTIAL); - verifyZeroInteractions(authorizer); } @Test @@ -108,41 +74,4 @@ public class DefaultRequestFactoryModuleTest { credentialProvider); assertThat(factory.getInitializer()).isSameAs(FAKE_CREDENTIAL); } - - @Test - public void test_createClientScopeQualifier() { - String simpleQualifier = - createClientScopeQualifier("client-id", ImmutableList.of("foo", "bar")); - - // If we change the way we encode client id and scopes, this assertion will break. That's - // probably ok and you can just change the text. The things you have to be aware of are: - // - Names in the new encoding should have a low risk of collision with the old encoding. - // - Changing the encoding will force all OAuth users of the nomulus tool to do a new login - // (existing credentials will not be used). - assertThat(simpleQualifier).isEqualTo("client-id bar foo"); - - // Verify order independence. - assertThat(simpleQualifier).isEqualTo( - createClientScopeQualifier("client-id", ImmutableList.of("bar", "foo"))); - - // Verify changing client id produces a different value. - assertThat(simpleQualifier).isNotEqualTo( - createClientScopeQualifier("new-client", ImmutableList.of("bar", "foo"))); - - // Verify that adding/deleting/modifying scopes produces a different value. - assertThat(simpleQualifier).isNotEqualTo( - createClientScopeQualifier("client id", ImmutableList.of("bar", "foo", "baz"))); - assertThat(simpleQualifier).isNotEqualTo( - createClientScopeQualifier("client id", ImmutableList.of("barx", "foo"))); - assertThat(simpleQualifier).isNotEqualTo( - createClientScopeQualifier("client id", ImmutableList.of("bar", "foox"))); - assertThat(simpleQualifier).isNotEqualTo( - createClientScopeQualifier("client id", ImmutableList.of("bar"))); - - // Verify that delimiting works. - assertThat(simpleQualifier).isNotEqualTo( - createClientScopeQualifier("client-id", ImmutableList.of("barf", "oo"))); - assertThat(simpleQualifier).isNotEqualTo( - createClientScopeQualifier("client-idb", ImmutableList.of("ar", "foo"))); - } }