From a7e4564c8e6b58a2ffc208610359e516ac61e2fe Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Tue, 15 Jan 2013 21:25:51 -0800 Subject: [PATCH] support changing credentials at runtime --- .../StubComputeServiceDependenciesModule.java | 14 +++-- .../main/java/org/jclouds/ContextBuilder.java | 57 ++++++++++++++----- .../http/filters/BasicAuthentication.java | 23 ++++---- .../org/jclouds/internal/ContextImpl.java | 46 ++++++++------- ...ProviderMetadataContextAndCredentials.java | 13 ++--- .../jclouds/rest/annotations/Credential.java | 42 -------------- .../jclouds/rest/annotations/Identity.java | 42 -------------- .../rest/internal/RestContextImpl.java | 11 ++-- .../java/org/jclouds/ContextBuilderTest.java | 22 ++++++- ...WildcardExtendsExplicitAndRawTypeTest.java | 3 +- .../http/filters/BasicAuthenticationTest.java | 35 +++++++++--- .../org/jclouds/internal/BaseViewTest.java | 9 ++- ...iderMetadataContextAndCredentialsTest.java | 36 +++++------- 13 files changed, 172 insertions(+), 181 deletions(-) delete mode 100644 core/src/main/java/org/jclouds/rest/annotations/Credential.java delete mode 100644 core/src/main/java/org/jclouds/rest/annotations/Identity.java diff --git a/compute/src/main/java/org/jclouds/compute/stub/config/StubComputeServiceDependenciesModule.java b/compute/src/main/java/org/jclouds/compute/stub/config/StubComputeServiceDependenciesModule.java index 87360b08dd..bb2a2d18fb 100644 --- a/compute/src/main/java/org/jclouds/compute/stub/config/StubComputeServiceDependenciesModule.java +++ b/compute/src/main/java/org/jclouds/compute/stub/config/StubComputeServiceDependenciesModule.java @@ -29,13 +29,15 @@ import javax.inject.Singleton; import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.NodeMetadata.Status; import org.jclouds.compute.domain.Processor; import org.jclouds.compute.domain.Volume; -import org.jclouds.compute.domain.NodeMetadata.Status; import org.jclouds.compute.domain.internal.VolumeImpl; +import org.jclouds.domain.Credentials; +import org.jclouds.location.Provider; import org.jclouds.predicates.SocketOpen; -import org.jclouds.rest.annotations.Identity; +import com.google.common.base.Supplier; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; @@ -68,9 +70,9 @@ public class StubComputeServiceDependenciesModule extends AbstractModule { @Provides @Singleton - protected ConcurrentMap provideNodesForIdentity(@Identity String identity) + protected ConcurrentMap provideNodesForIdentity(@Provider Supplier creds) throws ExecutionException { - return backing.get(identity); + return backing.get(creds.get().identity); } protected static final LoadingCache nodeIds = CacheBuilder.newBuilder().build( @@ -85,8 +87,8 @@ public class StubComputeServiceDependenciesModule extends AbstractModule { @Provides @Named("NODE_ID") - protected Integer provideNodeIdForIdentity(@Identity String identity) throws ExecutionException { - return nodeIds.get(identity).incrementAndGet(); + protected Integer provideNodeIdForIdentity(@Provider Supplier creds) throws ExecutionException { + return nodeIds.get(creds.get().identity).incrementAndGet(); } @Singleton diff --git a/core/src/main/java/org/jclouds/ContextBuilder.java b/core/src/main/java/org/jclouds/ContextBuilder.java index c7a65f5518..0a5a80b7d0 100644 --- a/core/src/main/java/org/jclouds/ContextBuilder.java +++ b/core/src/main/java/org/jclouds/ContextBuilder.java @@ -18,6 +18,7 @@ */ package org.jclouds; +import static com.google.common.base.Objects.toStringHelper; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Predicates.containsPattern; import static com.google.common.base.Predicates.instanceOf; @@ -30,6 +31,8 @@ import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Iterables.find; import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Lists.newArrayList; +import static com.google.common.collect.Lists.newArrayListWithCapacity; +import static com.google.common.collect.Maps.filterKeys; import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor; import static org.jclouds.Constants.PROPERTY_API; import static org.jclouds.Constants.PROPERTY_API_VERSION; @@ -84,12 +87,12 @@ import com.google.common.base.Objects; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.base.Splitter; +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableMultimap.Builder; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import com.google.common.reflect.TypeToken; import com.google.common.util.concurrent.ExecutionList; import com.google.inject.Guice; @@ -189,18 +192,18 @@ public class ContextBuilder { protected final String providerId; protected Optional endpoint = Optional.absent(); protected Optional identity = Optional.absent(); + protected Optional> credentialsSupplierOption = Optional.absent(); @Nullable protected String credential; protected ApiMetadata apiMetadata; protected String apiVersion; protected String buildVersion; protected Optional overrides = Optional.absent(); - protected List modules = Lists.newArrayListWithCapacity(3); + protected List modules = newArrayListWithCapacity(3); @Override public String toString() { - return Objects.toStringHelper("").add("providerMetadata", providerMetadata).add("apiMetadata", apiMetadata) - .toString(); + return toStringHelper("").add("providerMetadata", providerMetadata).add("apiMetadata", apiMetadata).toString(); } protected ContextBuilder(ProviderMetadata providerMetadata) { @@ -232,6 +235,20 @@ public class ContextBuilder { return this; } + /** + * returns the current login credentials. jclouds will not cache this value. Use this when you need to change + * credentials at runtime. + */ + public ContextBuilder credentialsSupplier(Supplier credentialsSupplier) { + this.credentialsSupplierOption = Optional.of(checkNotNull(credentialsSupplier, "credentialsSupplier")); + return this; + } + + /** + * constant value of the cloud identity and credential. + * + * @param credential (optional depending on {@link ApiMetadata#getCredentialName()} + */ public ContextBuilder credentials(String identity, @Nullable String credential) { this.identity = Optional.of(checkNotNull(identity, "identity")); this.credential = credential; @@ -289,14 +306,29 @@ public class ContextBuilder { Properties expanded = expandProperties(resolved); - Credentials creds = new Credentials(getAndRemove(expanded, PROPERTY_IDENTITY), getAndRemove(expanded, - PROPERTY_CREDENTIAL)); + Supplier credentialsSupplier = buildCredentialsSupplier(expanded); - ProviderMetadata providerMetadata = new UpdateProviderMetadataFromProperties(apiMetadata, this.providerMetadata).apply(expanded); + ProviderMetadata providerMetadata = new UpdateProviderMetadataFromProperties(apiMetadata, this.providerMetadata) + .apply(expanded); - //We use either the specified name (optional) or a hash of provider/api, endpoint, api version & identity. Hash is used to be something readable. + // We use either the specified name (optional) or a hash of provider/api, endpoint, api version & identity. Hash + // is used to be something readable. return buildInjector(name.or(String.valueOf(Objects.hashCode(providerMetadata.getId(), - providerMetadata.getEndpoint(), providerMetadata.getApiMetadata().getVersion(), creds.identity))), providerMetadata, creds, modules); + providerMetadata.getEndpoint(), providerMetadata.getApiMetadata().getVersion(), credentialsSupplier))), + providerMetadata, credentialsSupplier, modules); + } + + protected Supplier buildCredentialsSupplier(Properties expanded) { + Credentials creds = new Credentials(getAndRemove(expanded, PROPERTY_IDENTITY), getAndRemove(expanded, + PROPERTY_CREDENTIAL)); + + Supplier credentialsSupplier; + if (credentialsSupplierOption.isPresent()) { + credentialsSupplier = credentialsSupplierOption.get(); + } else { + credentialsSupplier = Suppliers.ofInstance(creds); + } + return credentialsSupplier; } private static String getAndRemove(Properties expanded, String key) { @@ -340,7 +372,7 @@ public class ContextBuilder { return Guice.createInjector(new BindPropertiesToExpandedValues(resolved)).getInstance(Properties.class); } - public static Injector buildInjector(String name, ProviderMetadata providerMetadata, Credentials creds, List inputModules) { + public static Injector buildInjector(String name, ProviderMetadata providerMetadata, Supplier creds, List inputModules) { List modules = newArrayList(); modules.addAll(inputModules); boolean restModuleSpecifiedByUser = restClientModulePresent(inputModules); @@ -411,8 +443,7 @@ public class ContextBuilder { @SuppressWarnings( { "unchecked" }) static Map propertiesPrefixedWithJcloudsApiOrProviderId(Properties properties, String apiId, String providerId) { - return Maps.filterKeys(Map.class.cast(properties), containsPattern("^(jclouds|" + providerId + "|" + apiId - + ").*")); + return filterKeys(Map.class.cast(properties), containsPattern("^(jclouds|" + providerId + "|" + apiId + ").*")); } @VisibleForTesting diff --git a/core/src/main/java/org/jclouds/http/filters/BasicAuthentication.java b/core/src/main/java/org/jclouds/http/filters/BasicAuthentication.java index b182f74804..a44c2c50c3 100644 --- a/core/src/main/java/org/jclouds/http/filters/BasicAuthentication.java +++ b/core/src/main/java/org/jclouds/http/filters/BasicAuthentication.java @@ -26,12 +26,13 @@ import static java.lang.String.format; import javax.inject.Inject; import javax.inject.Singleton; -import org.jclouds.crypto.Crypto; +import org.jclouds.domain.Credentials; import org.jclouds.http.HttpException; import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequestFilter; -import org.jclouds.rest.annotations.Credential; -import org.jclouds.rest.annotations.Identity; +import org.jclouds.location.Provider; + +import com.google.common.base.Supplier; /** * Uses Basic Authentication to sign the request. @@ -43,22 +44,24 @@ import org.jclouds.rest.annotations.Identity; @Singleton public class BasicAuthentication implements HttpRequestFilter { - private final String header; + private final Supplier creds; @Inject - public BasicAuthentication(@Identity String user, @Credential String password, Crypto crypto) { - checkNotNull(user, "user"); - checkNotNull(password, "password"); - this.header = basic(user, password); + public BasicAuthentication(@Provider Supplier creds) { + this.creds = checkNotNull(creds, "creds"); } public static String basic(String user, String password) { - return new StringBuilder("Basic ").append(base64().encode(format("%s:%s", user, password).getBytes(UTF_8))) + return new StringBuilder("Basic ").append( + base64().encode( + format("%s:%s", checkNotNull(user, "user"), checkNotNull(password, "password")).getBytes(UTF_8))) .toString(); } @Override public HttpRequest filter(HttpRequest request) throws HttpException { - return request.toBuilder().replaceHeader(AUTHORIZATION, header).build(); + Credentials currentCreds = checkNotNull(creds.get(), "credential supplier returned null"); + return request.toBuilder().replaceHeader(AUTHORIZATION, basic(currentCreds.identity, currentCreds.credential)) + .build(); } } diff --git a/core/src/main/java/org/jclouds/internal/ContextImpl.java b/core/src/main/java/org/jclouds/internal/ContextImpl.java index 8c92c27839..cc92e7f87d 100644 --- a/core/src/main/java/org/jclouds/internal/ContextImpl.java +++ b/core/src/main/java/org/jclouds/internal/ContextImpl.java @@ -18,26 +18,31 @@ */ package org.jclouds.internal; -import com.google.common.base.Objects; -import com.google.common.collect.ImmutableMap; -import com.google.common.io.Closeables; -import com.google.inject.Singleton; +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.io.Closeables.closeQuietly; + +import java.net.URI; +import java.util.Map; +import java.util.Set; + +import javax.inject.Inject; + import org.jclouds.Context; import org.jclouds.annotations.Name; import org.jclouds.domain.Credentials; import org.jclouds.domain.Location; import org.jclouds.domain.LocationScope; import org.jclouds.lifecycle.Closer; +import org.jclouds.location.Provider; import org.jclouds.providers.ProviderMetadata; import org.jclouds.rest.Utils; -import org.jclouds.rest.annotations.Identity; -import javax.inject.Inject; -import java.net.URI; -import java.util.Map; -import java.util.Set; - -import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.base.Objects; +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableMap; +import com.google.inject.Singleton; /** * @author Adrian Cole @@ -46,15 +51,16 @@ import static com.google.common.base.Preconditions.checkNotNull; public class ContextImpl implements Context { private final ProviderMetadata providerMetadata; - private final String identity; + private final Supplier creds; private final Utils utils; private final Closer closer; private final String name; @Inject - protected ContextImpl(@Name String name, ProviderMetadata providerMetadata, @Identity String identity, Utils utils, Closer closer) { + protected ContextImpl(@Name String name, ProviderMetadata providerMetadata, @Provider Supplier creds, + Utils utils, Closer closer) { this.providerMetadata = checkNotNull(providerMetadata, "providerMetadata"); - this.identity = checkNotNull(identity, "identity"); + this.creds = checkNotNull(creds, "creds"); this.utils = checkNotNull(utils, "utils"); this.closer = checkNotNull(closer, "closer"); this.name = checkNotNull(name, "name"); @@ -65,7 +71,7 @@ public class ContextImpl implements Context { */ @Override public void close() { - Closeables.closeQuietly(closer); + closeQuietly(closer); } /** @@ -89,7 +95,7 @@ public class ContextImpl implements Context { */ @Override public String getIdentity() { - return identity; + return creds.get().identity; } /** @@ -134,7 +140,7 @@ public class ContextImpl implements Context { */ @Override public int hashCode() { - return Objects.hashCode(providerMetadata, identity); + return Objects.hashCode(providerMetadata, creds); } /** @@ -149,7 +155,7 @@ public class ContextImpl implements Context { if (getClass() != obj.getClass()) return false; ContextImpl that = ContextImpl.class.cast(obj); - return Objects.equal(this.providerMetadata, that.providerMetadata) && Objects.equal(this.identity, that.identity); + return equal(this.providerMetadata, that.providerMetadata) && equal(this.creds, that.creds); } /** @@ -157,7 +163,7 @@ public class ContextImpl implements Context { */ @Override public String toString() { - return Objects.toStringHelper("").add("providerMetadata", providerMetadata).add("identity", identity).toString(); + return toStringHelper("").add("providerMetadata", providerMetadata).add("identity", getIdentity()).toString(); } /** @@ -191,7 +197,7 @@ public class ContextImpl implements Context { public Map getMetadata() { return ImmutableMap. of("endpoint", URI.create(providerMetadata.getEndpoint()), "apiVersion", providerMetadata.getApiMetadata().getVersion(), "buildVersion", providerMetadata.getApiMetadata() - .getBuildVersion().or(""), "identity", identity); + .getBuildVersion().or(""), "identity", getIdentity()); } /** diff --git a/core/src/main/java/org/jclouds/providers/config/BindProviderMetadataContextAndCredentials.java b/core/src/main/java/org/jclouds/providers/config/BindProviderMetadataContextAndCredentials.java index ccbeb0d190..9d98b61af2 100644 --- a/core/src/main/java/org/jclouds/providers/config/BindProviderMetadataContextAndCredentials.java +++ b/core/src/main/java/org/jclouds/providers/config/BindProviderMetadataContextAndCredentials.java @@ -33,9 +33,8 @@ import org.jclouds.providers.ProviderMetadata; import org.jclouds.rest.annotations.Api; import org.jclouds.rest.annotations.ApiVersion; import org.jclouds.rest.annotations.BuildVersion; -import org.jclouds.rest.annotations.Credential; -import org.jclouds.rest.annotations.Identity; +import com.google.common.base.Supplier; import com.google.common.reflect.TypeToken; import com.google.inject.AbstractModule; import com.google.inject.Injector; @@ -56,9 +55,9 @@ import com.google.inject.name.Names; public class BindProviderMetadataContextAndCredentials extends AbstractModule { private final ProviderMetadata providerMetadata; - private final Credentials creds; + private final Supplier creds; - public BindProviderMetadataContextAndCredentials(ProviderMetadata providerMetadata, Credentials creds) { + public BindProviderMetadataContextAndCredentials(ProviderMetadata providerMetadata, Supplier creds) { this.providerMetadata = checkNotNull(providerMetadata, "providerMetadata"); this.creds = checkNotNull(creds, "creds"); } @@ -70,11 +69,7 @@ public class BindProviderMetadataContextAndCredentials extends AbstractModule { toBind.putAll(providerMetadata.getApiMetadata().getDefaultProperties()); toBind.putAll(providerMetadata.getDefaultProperties()); Names.bindProperties(binder(), toBind); - bind(Credentials.class).annotatedWith(Provider.class).toInstance(creds); - bindConstant().annotatedWith(Identity.class).to(creds.identity); - // nullable - bind(String.class).annotatedWith(Credential.class).toProvider( - com.google.inject.util.Providers.of(creds.credential)); + bind(new TypeLiteral>(){}).annotatedWith(Provider.class).toInstance(creds); bindConstant().annotatedWith(Provider.class).to(providerMetadata.getId()); bind(new TypeLiteral>() { }).annotatedWith(Iso3166.class).toInstance(providerMetadata.getIso3166Codes()); diff --git a/core/src/main/java/org/jclouds/rest/annotations/Credential.java b/core/src/main/java/org/jclouds/rest/annotations/Credential.java deleted file mode 100644 index 64bac143ba..0000000000 --- a/core/src/main/java/org/jclouds/rest/annotations/Credential.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds licenses this file - * to you 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 org.jclouds.rest.annotations; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import javax.inject.Qualifier; - -/** - * Designates that this Resource qualifies an object to a key on a provider. - * - * @author Adrian Cole - */ -@Target( { ANNOTATION_TYPE, FIELD, METHOD, PARAMETER }) -@Retention(RUNTIME) -@Qualifier -public @interface Credential { - -} diff --git a/core/src/main/java/org/jclouds/rest/annotations/Identity.java b/core/src/main/java/org/jclouds/rest/annotations/Identity.java deleted file mode 100644 index ef20f5e554..0000000000 --- a/core/src/main/java/org/jclouds/rest/annotations/Identity.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds licenses this file - * to you 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 org.jclouds.rest.annotations; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import javax.inject.Qualifier; - -/** - * Designates that this Resource qualifies an object to an identity on a provider. - * - * @author Adrian Cole - */ -@Target( { ANNOTATION_TYPE, FIELD, METHOD, PARAMETER }) -@Retention(RUNTIME) -@Qualifier -public @interface Identity { - -} diff --git a/core/src/main/java/org/jclouds/rest/internal/RestContextImpl.java b/core/src/main/java/org/jclouds/rest/internal/RestContextImpl.java index ed78b52328..84085b4ea5 100644 --- a/core/src/main/java/org/jclouds/rest/internal/RestContextImpl.java +++ b/core/src/main/java/org/jclouds/rest/internal/RestContextImpl.java @@ -23,13 +23,15 @@ import static com.google.common.base.Preconditions.checkNotNull; import javax.inject.Inject; import org.jclouds.annotations.Name; +import org.jclouds.domain.Credentials; import org.jclouds.internal.ContextImpl; import org.jclouds.lifecycle.Closer; +import org.jclouds.location.Provider; import org.jclouds.providers.ProviderMetadata; import org.jclouds.rest.RestContext; import org.jclouds.rest.Utils; -import org.jclouds.rest.annotations.Identity; +import com.google.common.base.Supplier; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.Singleton; @@ -45,9 +47,10 @@ public class RestContextImpl extends ContextImpl implements RestContext syncApi, TypeLiteral asyncApi) { - super(name, providerMetadata, identity, utils, closer); + protected RestContextImpl(@Name String name, ProviderMetadata providerMetadata, + @Provider Supplier creds, Utils utils, Closer closer, Injector injector, TypeLiteral syncApi, + TypeLiteral asyncApi) { + super(name, providerMetadata, creds, utils, closer); checkNotNull(injector, "injector"); this.asyncApi = injector.getInstance(Key.get(checkNotNull(asyncApi, "asyncApi"))); this.syncApi = injector.getInstance(Key.get(checkNotNull(syncApi, "syncApi"))); diff --git a/core/src/test/java/org/jclouds/ContextBuilderTest.java b/core/src/test/java/org/jclouds/ContextBuilderTest.java index 8f8cc6a6c7..7d24ffac3d 100644 --- a/core/src/test/java/org/jclouds/ContextBuilderTest.java +++ b/core/src/test/java/org/jclouds/ContextBuilderTest.java @@ -18,6 +18,7 @@ */ package org.jclouds; +import static com.google.common.base.Suppliers.ofInstance; import static org.testng.Assert.assertEquals; import java.net.URI; @@ -27,6 +28,7 @@ import java.util.Properties; import java.util.Set; import org.jclouds.concurrent.config.ExecutorServiceModule; +import org.jclouds.domain.Credentials; import org.jclouds.events.config.EventBusModule; import org.jclouds.http.IntegrationTestAsyncClient; import org.jclouds.http.IntegrationTestClient; @@ -40,7 +42,6 @@ import org.jclouds.providers.AnonymousProviderMetadata; import org.jclouds.providers.ProviderMetadata; import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.annotations.ApiVersion; -import org.jclouds.rest.annotations.Identity; import org.jclouds.rest.config.CredentialStoreModule; import org.testng.annotations.Test; @@ -115,8 +116,23 @@ public class ContextBuilderTest { overrides.setProperty(Constants.PROPERTY_IDENTITY, "foo"); overrides.setProperty(Constants.PROPERTY_CREDENTIAL, "BAR"); ContextBuilder withCredsInProps = testContextBuilder().overrides(overrides); - String identity = withCredsInProps.buildInjector().getInstance(Key.get(String.class, Identity.class)); - assertEquals(identity, "foo"); + Credentials creds = withCredsInProps.buildInjector() + .getInstance(Key.get(new TypeLiteral>() { + }, Provider.class)).get(); + assertEquals(creds, new Credentials("foo", "BAR")); + } + + @Test + public void testProviderMetadataWithCredentialsSetSupplier() { + Properties overrides = new Properties(); + overrides.setProperty(Constants.PROPERTY_IDENTITY, "foo"); + overrides.setProperty(Constants.PROPERTY_CREDENTIAL, "BAR"); + ContextBuilder withCredsSupplier = testContextBuilder().credentialsSupplier( + ofInstance(new Credentials("foo", "BAR"))); + Credentials creds = withCredsSupplier.buildInjector() + .getInstance(Key.get(new TypeLiteral>() { + }, Provider.class)).get(); + assertEquals(creds, new Credentials("foo", "BAR")); } @Test diff --git a/core/src/test/java/org/jclouds/config/BindRestContextWithWildcardExtendsExplicitAndRawTypeTest.java b/core/src/test/java/org/jclouds/config/BindRestContextWithWildcardExtendsExplicitAndRawTypeTest.java index 14b72a7002..dd2bfd0d4d 100644 --- a/core/src/test/java/org/jclouds/config/BindRestContextWithWildcardExtendsExplicitAndRawTypeTest.java +++ b/core/src/test/java/org/jclouds/config/BindRestContextWithWildcardExtendsExplicitAndRawTypeTest.java @@ -18,6 +18,7 @@ */ package org.jclouds.config; +import static com.google.common.base.Suppliers.ofInstance; import static org.easymock.EasyMock.createMock; import static org.testng.Assert.assertEquals; @@ -74,7 +75,7 @@ public class BindRestContextWithWildcardExtendsExplicitAndRawTypeTest { private Injector injectorFor(ProviderMetadata md) { return Guice.createInjector( new BindNameToContext("test"), - new BindProviderMetadataContextAndCredentials(md, new Credentials("user", "pass")), + new BindProviderMetadataContextAndCredentials(md, ofInstance(new Credentials("user", "pass"))), new BindRestContextWithWildcardExtendsExplicitAndRawType(RestApiMetadata.class.cast(md .getApiMetadata())), diff --git a/core/src/test/java/org/jclouds/http/filters/BasicAuthenticationTest.java b/core/src/test/java/org/jclouds/http/filters/BasicAuthenticationTest.java index d3fdd93e30..76c334d3f1 100644 --- a/core/src/test/java/org/jclouds/http/filters/BasicAuthenticationTest.java +++ b/core/src/test/java/org/jclouds/http/filters/BasicAuthenticationTest.java @@ -18,31 +18,50 @@ */ package org.jclouds.http.filters; +import static com.google.common.base.Suppliers.ofInstance; +import static com.google.common.collect.Queues.newArrayDeque; import static com.google.common.net.HttpHeaders.AUTHORIZATION; +import static java.util.Arrays.asList; import static org.testng.Assert.assertEquals; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; +import java.util.Deque; -import org.jclouds.encryption.internal.JCECrypto; +import org.jclouds.domain.Credentials; import org.jclouds.http.HttpRequest; import org.testng.annotations.Test; +import com.google.common.base.Supplier; + /** * * @author Adrian Cole */ @Test(groups = "unit") public class BasicAuthenticationTest { + private static final Credentials credential1 = new Credentials("Aladdin", "open sesame"); + private static final Credentials credential2 = new Credentials("Little", "Mermaid"); - private static final String USER = "Aladdin"; - private static final String PASSWORD = "open sesame"; + public void testAuth() { + HttpRequest request = HttpRequest.builder().method("GET").endpoint("http://localhost").build(); + request = new BasicAuthentication(ofInstance(credential1)).filter(request); + assertEquals(request.getFirstHeaderOrNull(AUTHORIZATION), "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="); + request = new BasicAuthentication(ofInstance(credential2)).filter(request); + assertEquals(request.getFirstHeaderOrNull(AUTHORIZATION), "Basic TGl0dGxlOk1lcm1haWQ="); + } - public void testAuth() throws NoSuchAlgorithmException, CertificateException { - BasicAuthentication filter = new BasicAuthentication(USER, PASSWORD, new JCECrypto(null)); + public void testAuthWithRuntimePasswordChange() { + Supplier credentialRotation = new Supplier() { + Deque rotation = newArrayDeque(asList(credential1, credential2)); + + public Credentials get() { + return rotation.poll(); + } + }; + BasicAuthentication filter = new BasicAuthentication(credentialRotation); HttpRequest request = HttpRequest.builder().method("GET").endpoint("http://localhost").build(); request = filter.filter(request); assertEquals(request.getFirstHeaderOrNull(AUTHORIZATION), "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="); + request = filter.filter(request); + assertEquals(request.getFirstHeaderOrNull(AUTHORIZATION), "Basic TGl0dGxlOk1lcm1haWQ="); } - } diff --git a/core/src/test/java/org/jclouds/internal/BaseViewTest.java b/core/src/test/java/org/jclouds/internal/BaseViewTest.java index 2c5313df25..5e2c677983 100644 --- a/core/src/test/java/org/jclouds/internal/BaseViewTest.java +++ b/core/src/test/java/org/jclouds/internal/BaseViewTest.java @@ -23,11 +23,14 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotEquals; import static org.testng.Assert.fail; +import org.jclouds.domain.Credentials; import org.jclouds.lifecycle.Closer; import org.jclouds.providers.ProviderMetadata; import org.jclouds.rest.Utils; import org.testng.annotations.Test; +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; import com.google.common.reflect.TypeToken; /** @@ -36,10 +39,12 @@ import com.google.common.reflect.TypeToken; @Test(groups = "unit", testName = "BaseViewTest") public class BaseViewTest { + static Supplier creds = Suppliers.ofInstance(new Credentials("identity", null)); + private static class Water extends ContextImpl { protected Water() { - super("water", createMock(ProviderMetadata.class), "identity", createMock(Utils.class), createMock(Closer.class)); + super("water", createMock(ProviderMetadata.class), creds, createMock(Utils.class), createMock(Closer.class)); } public void close() { @@ -49,7 +54,7 @@ public class BaseViewTest { private static class PeanutButter extends ContextImpl { protected PeanutButter() { - super("peanutbutter", createMock(ProviderMetadata.class), "identity", createMock(Utils.class), createMock(Closer.class)); + super("peanutbutter", createMock(ProviderMetadata.class), creds, createMock(Utils.class), createMock(Closer.class)); } public void close() { diff --git a/core/src/test/java/org/jclouds/providers/config/BindProviderMetadataContextAndCredentialsTest.java b/core/src/test/java/org/jclouds/providers/config/BindProviderMetadataContextAndCredentialsTest.java index 8a345016f9..b0627bf5d2 100644 --- a/core/src/test/java/org/jclouds/providers/config/BindProviderMetadataContextAndCredentialsTest.java +++ b/core/src/test/java/org/jclouds/providers/config/BindProviderMetadataContextAndCredentialsTest.java @@ -41,11 +41,11 @@ import org.jclouds.providers.ProviderMetadata; import org.jclouds.rest.annotations.Api; import org.jclouds.rest.annotations.ApiVersion; import org.jclouds.rest.annotations.BuildVersion; -import org.jclouds.rest.annotations.Credential; -import org.jclouds.rest.annotations.Identity; import org.testng.annotations.Test; import com.google.common.base.Predicates; +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; import com.google.common.reflect.TypeToken; import com.google.inject.Guice; import com.google.inject.Key; @@ -63,8 +63,6 @@ public class BindProviderMetadataContextAndCredentialsTest { private final javax.inject.Provider backend; private final ProviderMetadata providerMetadata; private final Credentials creds; - private final String identity; - private final String credential; private final String providerId; private final Set iso3166Codes; private final String apiId; @@ -73,10 +71,9 @@ public class BindProviderMetadataContextAndCredentialsTest { @Inject private ExpectedBindings(@Provider javax.inject.Provider backend, ProviderMetadata providerMetadata, - @Provider Credentials creds, @Identity String identity, @Nullable @Credential String credential, - @Provider String providerId, @Iso3166 Set iso3166Codes, @Api String apiId, - @ApiVersion String apiVersion, @Nullable @BuildVersion String buildVersion, - @Provider TypeToken backendToken, FilterStringsBoundToInjectorByName filter) { + @Provider Supplier creds, @Provider String providerId, @Iso3166 Set iso3166Codes, + @Api String apiId, @ApiVersion String apiVersion, @Nullable @BuildVersion String buildVersion, + @Provider TypeToken backendToken, FilterStringsBoundToInjectorByName filter) { this.backend = backend; assertEquals(backendToken, providerMetadata.getApiMetadata().getContext()); this.providerMetadata = providerMetadata; @@ -86,11 +83,7 @@ public class BindProviderMetadataContextAndCredentialsTest { expected.putAll(providerMetadata.getApiMetadata().getDefaultProperties()); expected.putAll(providerMetadata.getDefaultProperties()); assertEquals(props, expected); - this.creds = creds; - this.identity = identity; - assertEquals(identity, creds.identity); - this.credential = credential; - assertEquals(credential, creds.credential); + this.creds = creds.get(); this.providerId = providerId; assertEquals(providerId, providerMetadata.getId()); this.iso3166Codes = iso3166Codes; @@ -110,12 +103,13 @@ public class BindProviderMetadataContextAndCredentialsTest { ProviderMetadata md = AnonymousProviderMetadata.forClientMappedToAsyncClientOnEndpoint( IntegrationTestClient.class, IntegrationTestAsyncClient.class, "http://localhost"); - Credentials creds = LoginCredentials.builder().user("user").password("password").build(); + Supplier creds = Suppliers. ofInstance(LoginCredentials.builder().user("user") + .password("password").build()); ExpectedBindings bindings = Guice.createInjector(new BindProviderMetadataContextAndCredentials(md, creds)) .getInstance(ExpectedBindings.class); - assertEquals(bindings.identity, "user"); - assertEquals(bindings.credential, "password"); + assertEquals(bindings.creds.identity, "user"); + assertEquals(bindings.creds.credential, "password"); } @Test @@ -123,12 +117,12 @@ public class BindProviderMetadataContextAndCredentialsTest { ProviderMetadata md = AnonymousProviderMetadata.forClientMappedToAsyncClientOnEndpoint( IntegrationTestClient.class, IntegrationTestAsyncClient.class, "http://localhost"); - Credentials creds = LoginCredentials.builder().user("user").build(); + Supplier creds = Suppliers. ofInstance(LoginCredentials.builder().user("user").build()); ExpectedBindings bindings = Guice.createInjector(new BindProviderMetadataContextAndCredentials(md, creds)) .getInstance(ExpectedBindings.class); - assertEquals(bindings.identity, "user"); - assertEquals(bindings.credential, null); + assertEquals(bindings.creds.identity, "user"); + assertEquals(bindings.creds.credential, null); } @Test @@ -138,7 +132,7 @@ public class BindProviderMetadataContextAndCredentialsTest { IntegrationTestClient.class, IntegrationTestAsyncClient.class, "http://localhost"); ApiMetadata apiMd = md.getApiMetadata().toBuilder().buildVersion(null).build(); md = md.toBuilder().apiMetadata(apiMd).build(); - Credentials creds = LoginCredentials.builder().user("user").build(); + Supplier creds = Suppliers. ofInstance(LoginCredentials.builder().user("user").build()); ExpectedBindings bindings = Guice.createInjector(new BindProviderMetadataContextAndCredentials(md, creds)) .getInstance(ExpectedBindings.class); @@ -154,7 +148,7 @@ public class BindProviderMetadataContextAndCredentialsTest { defaultProps.setProperty(Constants.PROPERTY_SESSION_INTERVAL, Integer.MAX_VALUE + ""); md = md.toBuilder().defaultProperties(defaultProps).build(); - Credentials creds = LoginCredentials.builder().user("user").build(); + Supplier creds = Suppliers. ofInstance(LoginCredentials.builder().user("user").build()); int session = Guice.createInjector(new BindProviderMetadataContextAndCredentials(md, creds)).getInstance( Key.get(int.class, Names.named(Constants.PROPERTY_SESSION_INTERVAL)));