You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by na...@apache.org on 2017/12/08 12:56:22 UTC

[7/8] jclouds git commit: Initial work towards Keystone V3 authentication

Initial work towards Keystone V3 authentication

Refactors the Keystone Authentication and Service Catalog classes to a
common model that can be used by V2 and V3 of Keystone. Each version
will have their own Authentication APIs and Service Catalog Suppliers,
and the higher level Keystone Authentication will transparently delegate
to the right API based on the keystone-version property.

OpenStack APIs will just have to define the default keystone-version
property they work with, and declare the generic Keystone Authentication
and Service Catalog modules.


Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/7def8169
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/7def8169
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/7def8169

Branch: refs/heads/keystonev3
Commit: 7def8169b4063ae65b6d57324b98311a7f1115f5
Parents: 624367d
Author: Ignasi Barrera <na...@apache.org>
Authored: Tue Dec 5 17:13:31 2017 +0100
Committer: Ignasi Barrera <na...@apache.org>
Committed: Thu Dec 7 23:40:58 2017 +0100

----------------------------------------------------------------------
 .../openstack/cinder/v1/CinderApiMetadata.java  |  18 +-
 .../v1/extensions/AvailabilityZoneApi.java      |   2 +-
 .../openstack/cinder/v1/features/QuotaApi.java  |   2 +-
 .../cinder/v1/features/SnapshotApi.java         |   2 +-
 .../openstack/cinder/v1/features/VolumeApi.java |   2 +-
 .../cinder/v1/features/VolumeTypeApi.java       |   2 +-
 .../v1/internal/BaseCinderApiLiveTest.java      |   2 +-
 apis/openstack-keystone/pom.xml                 |  21 ++
 .../openstack/keystone/auth/AuthHeaders.java    |  28 ++
 .../keystone/auth/AuthenticationApi.java        |  35 +++
 .../keystone/auth/config/Authentication.java    |  31 +++
 .../auth/config/AuthenticationModule.java       | 142 ++++++++++
 .../keystone/auth/config/CredentialType.java    |  38 +++
 .../keystone/auth/config/CredentialTypes.java   |  66 +++++
 .../auth/domain/ApiAccessKeyCredentials.java    |  51 ++++
 .../keystone/auth/domain/AuthInfo.java          |  25 ++
 .../auth/domain/PasswordCredentials.java        |  59 +++++
 .../auth/domain/TenantAndCredentials.java       |  50 ++++
 .../keystone/auth/domain/TokenCredentials.java  |  50 ++++
 .../auth/filters/AuthenticateRequest.java       |  48 ++++
 .../AuthenticateApiAccessKeyCredentials.java    |  51 ++++
 .../AuthenticatePasswordCredentials.java        |  50 ++++
 .../functions/AuthenticateTokenCredentials.java |  50 ++++
 .../auth/functions/BaseAuthenticator.java       |  88 +++++++
 .../keystone/auth/handlers/RetryOnRenew.java    | 121 +++++++++
 .../keystone/catalog/ServiceEndpoint.java       |  74 ++++++
 .../catalog/config/InternalUrlModule.java       |  35 +++
 .../catalog/config/KeystoneAdminURLModule.java  |  64 +++++
 .../catalog/config/ServiceCatalogModule.java    | 160 ++++++++++++
 .../AdminEndpointResolutionStrategy.java        |  27 ++
 .../keystone/catalog/functions/AdminURL.java    |  34 +++
 .../BaseEndpointResolutionStrategy.java         |  62 +++++
 .../keystone/catalog/functions/InternalURL.java |  34 +++
 .../catalog/functions/PublicURLOrInternal.java  |  66 +++++
 .../functions/ReturnRegionOrProvider.java       |  38 +++
 .../ServiceEndpointResolutionStrategy.java      |  35 +++
 .../functions/ServiceEndpointToRegion.java      |  27 ++
 ...ationIdToURIFromAccessForTypeAndVersion.java | 129 ++++++++++
 ...IdToAdminURIFromAccessForTypeAndVersion.java |  44 ++++
 .../suppliers/RegionIdToAdminURISupplier.java   |  37 +++
 ...egionIdToURIFromAccessForTypeAndVersion.java |  46 ++++
 .../keystone/config/KeystoneProperties.java     |  83 ++++++
 .../keystone/v2_0/AuthenticationApi.java        |  91 -------
 .../keystone/v2_0/KeystoneApiMetadata.java      |  18 +-
 .../keystone/v2_0/auth/V2AuthenticationApi.java |  68 +++++
 .../v2_0/binders/BindAuthToJsonPayload.java     |  66 +++--
 .../keystone/v2_0/catalog/V2ServiceCatalog.java | 105 ++++++++
 .../keystone/v2_0/config/Authentication.java    |  31 ---
 .../v2_0/config/AuthenticationApiModule.java    |  33 ---
 .../keystone/v2_0/config/CredentialType.java    |  38 ---
 .../keystone/v2_0/config/CredentialTypes.java   |  52 ----
 .../config/KeystoneAuthenticationModule.java    | 257 -------------------
 .../v2_0/config/KeystoneHttpApiModule.java      |  39 ---
 .../v2_0/config/KeystoneProperties.java         |  75 ------
 .../openstack/keystone/v2_0/domain/Access.java  |   8 +-
 .../v2_0/domain/ApiAccessKeyCredentials.java    | 140 ----------
 .../keystone/v2_0/domain/Endpoint.java          |   2 +-
 .../v2_0/domain/PasswordCredentials.java        | 140 ----------
 .../keystone/v2_0/extensions/RoleAdminApi.java  |   2 +-
 .../v2_0/extensions/ServiceAdminApi.java        |   2 +-
 .../v2_0/extensions/TenantAdminApi.java         |   2 +-
 .../keystone/v2_0/extensions/UserAdminApi.java  |   2 +-
 .../keystone/v2_0/features/ServiceApi.java      |   2 +-
 .../keystone/v2_0/features/TenantApi.java       |   2 +-
 .../keystone/v2_0/features/TokenApi.java        |   2 +-
 .../keystone/v2_0/features/UserApi.java         |   2 +-
 .../v2_0/filters/AuthenticateRequest.java       |  48 ----
 .../keystone/v2_0/functions/AdminURL.java       |  38 ---
 .../AuthenticateApiAccessKeyCredentials.java    |  60 -----
 .../AuthenticatePasswordCredentials.java        |  60 -----
 .../v2_0/functions/EndpointToRegion.java        |  27 --
 .../functions/EndpointToSupplierAdminURI.java   |  23 --
 .../v2_0/functions/EndpointToSupplierURI.java   |  29 ---
 .../keystone/v2_0/functions/InternalURL.java    |  43 ----
 .../functions/PublicURLOrInternalIfNull.java    |  39 ---
 .../functions/RegionToAdminEndpointURI.java     |  49 ----
 .../v2_0/functions/ReturnRegionOrProvider.java  |  40 ---
 .../functions/internal/BaseAuthenticator.java   |  97 -------
 .../keystone/v2_0/handlers/RetryOnRenew.java    | 121 ---------
 ...ationIdToURIFromAccessForTypeAndVersion.java | 208 ---------------
 ...IdToAdminURIFromAccessForTypeAndVersion.java |  42 ---
 .../suppliers/RegionIdToAdminURISupplier.java   |  45 ----
 ...egionIdToURIFromAccessForTypeAndVersion.java |  44 ----
 .../ZoneIdToURIFromAccessForTypeAndVersion.java |  47 ----
 .../openstack/keystone/v3/KeystoneApi.java      |  35 +++
 .../keystone/v3/KeystoneApiMetadata.java        |  98 +++++++
 .../keystone/v3/auth/V3AuthenticationApi.java   |  60 +++++
 .../v3/binders/BindAuthToJsonPayload.java       |  64 +++++
 .../binders/BindPasswordAuthToJsonPayload.java  |  50 ++++
 .../v3/binders/BindTokenAuthToJsonPayload.java  |  45 ++++
 .../keystone/v3/catalog/V3ServiceCatalog.java   |  63 +++++
 .../openstack/keystone/v3/domain/Auth.java      |  94 +++++++
 .../openstack/keystone/v3/domain/Catalog.java   |  48 ++++
 .../openstack/keystone/v3/domain/Endpoint.java  |  52 ++++
 .../openstack/keystone/v3/domain/Link.java      |  36 +++
 .../openstack/keystone/v3/domain/Region.java    |  46 ++++
 .../openstack/keystone/v3/domain/Token.java     | 103 ++++++++
 .../openstack/keystone/v3/domain/User.java      |  57 ++++
 .../keystone/v3/features/TokenApi.java          | 132 ++++++++++
 .../keystone/v3/parsers/ParseToken.java         |  41 +++
 .../v2_0/config/InternalUrlModule.java          |  35 ---
 .../openstack/v2_0/features/ExtensionApi.java   |   2 +-
 .../openstack/v2_0/reference/AuthHeaders.java   |  28 --
 .../auth/config/CredentialTypesTest.java        |  51 ++++
 .../auth/config/ProviderModuleExpectTest.java   | 180 +++++++++++++
 .../auth/handlers/RetryOnRenewTest.java         | 131 ++++++++++
 ...nIdToURIFromAccessForTypeAndVersionTest.java | 139 ++++++++++
 ...AdminURIFromAccessForTypeAndVersionTest.java | 125 +++++++++
 ...nIdToURIFromAccessForTypeAndVersionTest.java | 128 +++++++++
 .../catalog/functions/AdminURLTest.java         |  54 ++++
 .../catalog/functions/InternalURLTest.java      |  42 +++
 .../functions/PublicURLOrInternalTest.java      |  54 ++++
 .../functions/ReturnRegionOrProviderTest.java   |  45 ++++
 .../v2_0/config/CredentialTypesTest.java        |  49 ----
 .../v2_0/config/ProviderModuleExpectTest.java   | 176 -------------
 .../v2_0/features/TokenApiLiveTest.java         |   2 +-
 .../keystone/v2_0/functions/AdminURLTest.java   |  45 ----
 .../v2_0/functions/InternalURLTest.java         |  39 ---
 .../PublicURLOrInternalIfNullTest.java          |  46 ----
 .../functions/ReturnRegionOrProviderTest.java   |  44 ----
 .../v2_0/handlers/RetryOnRenewTest.java         | 131 ----------
 .../v2_0/internal/BaseKeystoneApiLiveTest.java  |   2 +-
 .../internal/BaseKeystoneRestApiExpectTest.java |   2 +-
 ...nIdToURIFromAccessForTypeAndVersionTest.java | 126 ---------
 ...AdminURIFromAccessForTypeAndVersionTest.java | 113 --------
 ...nIdToURIFromAccessForTypeAndVersionTest.java | 118 ---------
 ...eIdToURIFromAccessForTypeAndVersionTest.java | 113 --------
 .../openstack/nova/v2_0/NovaApiMetadata.java    |  18 +-
 .../v2_0/extensions/AttachInterfaceApi.java     |   2 +-
 .../v2_0/extensions/AvailabilityZoneApi.java    |   2 +-
 .../nova/v2_0/extensions/ConsolesApi.java       |   2 +-
 .../v2_0/extensions/FlavorExtraSpecsApi.java    |   2 +-
 .../nova/v2_0/extensions/FloatingIPApi.java     |   2 +-
 .../nova/v2_0/extensions/FloatingIPPoolApi.java |   2 +-
 .../v2_0/extensions/HostAdministrationApi.java  |   2 +-
 .../nova/v2_0/extensions/HostAggregateApi.java  |   2 +-
 .../nova/v2_0/extensions/HypervisorApi.java     |   2 +-
 .../nova/v2_0/extensions/KeyPairApi.java        |   2 +-
 .../nova/v2_0/extensions/QuotaApi.java          |   2 +-
 .../nova/v2_0/extensions/SecurityGroupApi.java  |   2 +-
 .../nova/v2_0/extensions/ServerAdminApi.java    |   2 +-
 .../extensions/ServerWithSecurityGroupsApi.java |   2 +-
 .../v2_0/extensions/SimpleTenantUsageApi.java   |   2 +-
 .../v2_0/extensions/VirtualInterfaceApi.java    |   2 +-
 .../nova/v2_0/extensions/VolumeApi.java         |   2 +-
 .../v2_0/extensions/VolumeAttachmentApi.java    |   2 +-
 .../nova/v2_0/extensions/VolumeTypeApi.java     |   2 +-
 .../openstack/nova/v2_0/features/FlavorApi.java |   2 +-
 .../openstack/nova/v2_0/features/ImageApi.java  |   2 +-
 .../openstack/nova/v2_0/features/ServerApi.java |   2 +-
 ...tKeyAndTenantIdAuthenticationExpectTest.java |   2 +-
 ...KeyAndSecretKeyAuthenticationExpectTest.java |   2 +-
 .../v2_0/PasswordAuthenticationExpectTest.java  |   2 +-
 ...dAuthenticationWithTenantNameExpectTest.java |   2 +-
 .../compute/NovaComputeServiceLiveTest.java     |   2 +-
 .../v2_0/functions/InternalURLLiveTest.java     |   2 +-
 .../nova/v2_0/internal/BaseNovaApiLiveTest.java |   2 +-
 .../openstack/swift/v1/SwiftApiMetadata.java    |  19 +-
 .../v1/config/SwiftAuthenticationModule.java    |  29 ++-
 .../openstack/swift/v1/features/AccountApi.java |   2 +-
 .../openstack/swift/v1/features/BulkApi.java    |   2 +-
 .../swift/v1/features/ContainerApi.java         |   2 +-
 .../v1/features/DynamicLargeObjectApi.java      |   2 +-
 .../openstack/swift/v1/features/ObjectApi.java  |   4 +-
 .../swift/v1/features/StaticLargeObjectApi.java |   3 +-
 .../openstack/swift/v1/TempAuthMockTest.java    |   2 +-
 .../RegionScopedBlobStoreContextLiveTest.java   |   2 +-
 ...ionScopedSwiftBlobStoreParallelLiveTest.java |   2 +-
 .../SwiftBlobIntegrationLiveTest.java           |   2 +-
 .../integration/SwiftBlobLiveTest.java          |   2 +-
 .../integration/SwiftBlobSignerLiveTest.java    |   2 +-
 .../SwiftContainerIntegrationLiveTest.java      |   4 +-
 .../integration/SwiftContainerLiveTest.java     |   2 +-
 .../SwiftServiceIntegrationLiveTest.java        |   2 +-
 .../swift/v1/internal/BaseSwiftApiLiveTest.java |   2 +-
 .../jclouds/openstack/trove/v1/TroveApi.java    |   3 +-
 .../openstack/trove/v1/TroveApiMetadata.java    |  18 +-
 .../trove/v1/config/TroveHttpApiModule.java     |  20 +-
 .../trove/v1/features/DatabaseApi.java          |   2 +-
 .../openstack/trove/v1/features/FlavorApi.java  |   2 +-
 .../trove/v1/features/InstanceApi.java          |   2 +-
 .../openstack/trove/v1/features/UserApi.java    |   5 +-
 .../trove/v1/features/FlavorApiExpectTest.java  |   2 +-
 .../trove/v1/features/FlavorApiLiveTest.java    |   2 +-
 .../trove/v1/internal/BaseTroveApiLiveTest.java |   2 +-
 .../rackspace/clouddns/v1/CloudDNSApi.java      |   3 +-
 .../clouddns/v1/CloudDNSApiMetadata.java        |  12 +-
 .../clouddns/v1/features/DomainApi.java         |   5 +-
 .../clouddns/v1/features/LimitApi.java          |   2 +-
 .../clouddns/v1/features/RecordApi.java         |   4 +-
 .../clouddns/v1/features/ReverseDNSApi.java     |   4 +-
 .../v1/internal/BaseCloudDNSApiLiveTest.java    |   2 +-
 .../cloudfiles/v1/CloudFilesApiMetadata.java    |  12 +-
 .../cloudfiles/v1/features/CDNApi.java          |   2 +-
 .../v2_0/CloudIdentityApiMetadata.java          |   8 +-
 .../v2_0/CloudIdentityAuthenticationApi.java    |  19 +-
 .../CloudIdentityAuthenticationApiModule.java   |  39 ---
 .../CloudIdentityAuthenticationModule.java      |  33 ++-
 .../config/CloudIdentityCredentialTypes.java    |   2 +-
 .../v2_0/domain/ApiKeyCredentials.java          |   4 +-
 .../AuthenticateApiKeyCredentials.java          |  26 +-
 .../v1/CloudLoadBalancersApiMetadata.java       |  12 +-
 .../v1/features/AccessRuleApi.java              |   2 +-
 .../v1/features/ConnectionApi.java              |   2 +-
 .../v1/features/ContentCachingApi.java          |   2 +-
 .../v1/features/ErrorPageApi.java               |   2 +-
 .../v1/features/HealthMonitorApi.java           |   2 +-
 .../v1/features/LoadBalancerApi.java            |   2 +-
 .../cloudloadbalancers/v1/features/NodeApi.java |   2 +-
 .../v1/features/ReportApi.java                  |   2 +-
 .../v1/features/SSLTerminationApi.java          |   2 +-
 .../v1/features/SessionPersistenceApi.java      |   2 +-
 .../v1/features/VirtualIPApi.java               |   2 +-
 .../BaseCloudLoadBalancersApiLiveTest.java      |   2 +-
 .../uk/CloudBlockStorageUKProviderMetadata.java |  10 +-
 .../us/CloudBlockStorageUSProviderMetadata.java |  10 +-
 .../uk/CloudDatabasesUKProviderMetadata.java    |  12 +-
 .../us/CloudDatabasesUSProviderMetadata.java    |  12 +-
 .../uk/CloudFilesUKProviderMetadata.java        |  12 +-
 .../us/CloudFilesUSProviderMetadata.java        |  14 +-
 .../uk/CloudServersUKProviderMetadata.java      | 135 +++++-----
 .../us/CloudServersUSProviderMetadata.java      |  12 +-
 222 files changed, 4566 insertions(+), 3395 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/CinderApiMetadata.java
----------------------------------------------------------------------
diff --git a/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/CinderApiMetadata.java b/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/CinderApiMetadata.java
index fc9ac76..3e37235 100644
--- a/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/CinderApiMetadata.java
+++ b/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/CinderApiMetadata.java
@@ -16,8 +16,8 @@
  */
 package org.jclouds.openstack.cinder.v1;
 
-import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
-import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.SERVICE_TYPE;
+import static org.jclouds.openstack.keystone.config.KeystoneProperties.CREDENTIAL_TYPE;
+import static org.jclouds.openstack.keystone.config.KeystoneProperties.SERVICE_TYPE;
 
 import java.net.URI;
 import java.util.Properties;
@@ -25,10 +25,11 @@ import java.util.Properties;
 import org.jclouds.apis.ApiMetadata;
 import org.jclouds.openstack.cinder.v1.config.CinderHttpApiModule;
 import org.jclouds.openstack.cinder.v1.config.CinderParserModule;
-import org.jclouds.openstack.keystone.v2_0.config.AuthenticationApiModule;
-import org.jclouds.openstack.keystone.v2_0.config.CredentialTypes;
-import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule;
-import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.RegionModule;
+import org.jclouds.openstack.keystone.auth.config.AuthenticationModule;
+import org.jclouds.openstack.keystone.auth.config.CredentialTypes;
+import org.jclouds.openstack.keystone.catalog.config.ServiceCatalogModule;
+import org.jclouds.openstack.keystone.catalog.config.ServiceCatalogModule.RegionModule;
+import org.jclouds.openstack.keystone.config.KeystoneProperties;
 import org.jclouds.openstack.v2_0.ServiceType;
 import org.jclouds.rest.internal.BaseHttpApiMetadata;
 
@@ -58,6 +59,7 @@ public class CinderApiMetadata extends BaseHttpApiMetadata<CinderApi> {
    public static Properties defaultProperties() {
       Properties properties = BaseHttpApiMetadata.defaultProperties();
       properties.setProperty(SERVICE_TYPE, ServiceType.BLOCK_STORAGE);
+      properties.setProperty(KeystoneProperties.KEYSTONE_VERSION, "2");
       properties.setProperty(CREDENTIAL_TYPE, CredentialTypes.PASSWORD_CREDENTIALS);
       return properties;
    }
@@ -75,8 +77,8 @@ public class CinderApiMetadata extends BaseHttpApiMetadata<CinderApi> {
          .defaultEndpoint("http://localhost:5000/v2.0/")
          .defaultProperties(CinderApiMetadata.defaultProperties())
          .defaultModules(ImmutableSet.<Class<? extends Module>>builder()
-                                     .add(AuthenticationApiModule.class)
-                                     .add(KeystoneAuthenticationModule.class)
+                                     .add(AuthenticationModule.class)
+                                     .add(ServiceCatalogModule.class)
                                      .add(RegionModule.class)
                                      .add(CinderParserModule.class)
                                      .add(CinderHttpApiModule.class)

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/extensions/AvailabilityZoneApi.java
----------------------------------------------------------------------
diff --git a/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/extensions/AvailabilityZoneApi.java b/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/extensions/AvailabilityZoneApi.java
index 4b2abdb..1594419 100644
--- a/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/extensions/AvailabilityZoneApi.java
+++ b/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/extensions/AvailabilityZoneApi.java
@@ -21,7 +21,7 @@ import com.google.common.annotations.Beta;
 import com.google.common.collect.FluentIterable;
 import org.jclouds.Fallbacks;
 import org.jclouds.openstack.cinder.v1.domain.AvailabilityZone;
-import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.keystone.auth.filters.AuthenticateRequest;
 import org.jclouds.openstack.v2_0.ServiceType;
 import org.jclouds.openstack.v2_0.services.Extension;
 import org.jclouds.rest.annotations.Fallback;

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/features/QuotaApi.java
----------------------------------------------------------------------
diff --git a/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/features/QuotaApi.java b/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/features/QuotaApi.java
index e8c39f9..14fa57c 100644
--- a/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/features/QuotaApi.java
+++ b/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/features/QuotaApi.java
@@ -26,7 +26,7 @@ import javax.ws.rs.core.MediaType;
 import org.jclouds.Fallbacks.NullOnNotFoundOr404;
 import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.openstack.cinder.v1.domain.VolumeQuota;
-import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.keystone.auth.filters.AuthenticateRequest;
 import org.jclouds.rest.annotations.Fallback;
 import org.jclouds.rest.annotations.RequestFilters;
 import org.jclouds.rest.annotations.SelectJson;

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/features/SnapshotApi.java
----------------------------------------------------------------------
diff --git a/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/features/SnapshotApi.java b/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/features/SnapshotApi.java
index 4c5be5b..28c3e8b 100644
--- a/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/features/SnapshotApi.java
+++ b/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/features/SnapshotApi.java
@@ -32,7 +32,7 @@ import org.jclouds.Fallbacks.NullOnNotFoundOr404;
 import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.openstack.cinder.v1.domain.Snapshot;
 import org.jclouds.openstack.cinder.v1.options.CreateSnapshotOptions;
-import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.keystone.auth.filters.AuthenticateRequest;
 import org.jclouds.rest.annotations.Fallback;
 import org.jclouds.rest.annotations.MapBinder;
 import org.jclouds.rest.annotations.PayloadParam;

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/features/VolumeApi.java
----------------------------------------------------------------------
diff --git a/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/features/VolumeApi.java b/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/features/VolumeApi.java
index c6d4d54..c9f9820 100644
--- a/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/features/VolumeApi.java
+++ b/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/features/VolumeApi.java
@@ -32,7 +32,7 @@ import org.jclouds.Fallbacks.NullOnNotFoundOr404;
 import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.openstack.cinder.v1.domain.Volume;
 import org.jclouds.openstack.cinder.v1.options.CreateVolumeOptions;
-import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.keystone.auth.filters.AuthenticateRequest;
 import org.jclouds.rest.annotations.Fallback;
 import org.jclouds.rest.annotations.MapBinder;
 import org.jclouds.rest.annotations.PayloadParam;

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/features/VolumeTypeApi.java
----------------------------------------------------------------------
diff --git a/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/features/VolumeTypeApi.java b/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/features/VolumeTypeApi.java
index da59d8b..2ee062e 100644
--- a/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/features/VolumeTypeApi.java
+++ b/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/features/VolumeTypeApi.java
@@ -27,7 +27,7 @@ import org.jclouds.Fallbacks.EmptyFluentIterableOnNotFoundOr404;
 import org.jclouds.Fallbacks.NullOnNotFoundOr404;
 import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.openstack.cinder.v1.domain.VolumeType;
-import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.keystone.auth.filters.AuthenticateRequest;
 import org.jclouds.rest.annotations.Fallback;
 import org.jclouds.rest.annotations.RequestFilters;
 import org.jclouds.rest.annotations.SelectJson;

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-cinder/src/test/java/org/jclouds/openstack/cinder/v1/internal/BaseCinderApiLiveTest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-cinder/src/test/java/org/jclouds/openstack/cinder/v1/internal/BaseCinderApiLiveTest.java b/apis/openstack-cinder/src/test/java/org/jclouds/openstack/cinder/v1/internal/BaseCinderApiLiveTest.java
index 23c4702..88397bc 100644
--- a/apis/openstack-cinder/src/test/java/org/jclouds/openstack/cinder/v1/internal/BaseCinderApiLiveTest.java
+++ b/apis/openstack-cinder/src/test/java/org/jclouds/openstack/cinder/v1/internal/BaseCinderApiLiveTest.java
@@ -20,7 +20,7 @@ import java.util.Properties;
 
 import org.jclouds.apis.BaseApiLiveTest;
 import org.jclouds.openstack.cinder.v1.CinderApi;
-import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
+import org.jclouds.openstack.keystone.config.KeystoneProperties;
 
 /**
  * Tests behavior of CinderApi

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-keystone/pom.xml
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/pom.xml b/apis/openstack-keystone/pom.xml
index a4a2e7a..b0f8cf8 100644
--- a/apis/openstack-keystone/pom.xml
+++ b/apis/openstack-keystone/pom.xml
@@ -84,7 +84,28 @@
       <artifactId>auto-service</artifactId>
       <optional>true</optional>
     </dependency>
+    <dependency>
+      <groupId>com.google.auto.value</groupId>
+      <artifactId>auto-value</artifactId>
+      <scope>provided</scope>
+    </dependency>
   </dependencies>
+  
+  <build>
+    <plugins>
+    <!-- Disabling error-prone compiler due to: https://github.com/google/error-prone/issues/711
+         The fix is only available in error-prone versions that do not support Java 7 -->
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <inherited>false</inherited>
+        <configuration>
+          <source>${maven.compile.source}</source>
+          <target>${maven.compile.target}</target>
+          <encoding>${project.build.sourceEncoding}</encoding>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
 
   <profiles>
     <profile>

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/AuthHeaders.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/AuthHeaders.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/AuthHeaders.java
new file mode 100644
index 0000000..c6d6b27
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/AuthHeaders.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.openstack.keystone.auth;
+
+public final class AuthHeaders {
+
+   public static final String AUTH_USER = "X-Auth-User";
+   public static final String AUTH_KEY = "X-Auth-Key";
+   public static final String AUTH_TOKEN = "X-Auth-Token";
+
+   private AuthHeaders() {
+      throw new AssertionError("intentionally unimplemented");
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/AuthenticationApi.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/AuthenticationApi.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/AuthenticationApi.java
new file mode 100644
index 0000000..ea66e34
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/AuthenticationApi.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.openstack.keystone.auth;
+
+import org.jclouds.openstack.keystone.auth.domain.ApiAccessKeyCredentials;
+import org.jclouds.openstack.keystone.auth.domain.AuthInfo;
+import org.jclouds.openstack.keystone.auth.domain.TenantAndCredentials;
+import org.jclouds.openstack.keystone.auth.domain.PasswordCredentials;
+import org.jclouds.openstack.keystone.auth.domain.TokenCredentials;
+
+/**
+ * Authentication methods to be implemented to all Keystone authentication APIs.
+ */
+public interface AuthenticationApi {
+
+   AuthInfo authenticatePassword(TenantAndCredentials<PasswordCredentials> credentials);
+
+   AuthInfo authenticateAccessKey(TenantAndCredentials<ApiAccessKeyCredentials> credentials);
+
+   AuthInfo authenticateToken(TenantAndCredentials<TokenCredentials> credentials);
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/config/Authentication.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/config/Authentication.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/config/Authentication.java
new file mode 100644
index 0000000..b4d59f5
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/config/Authentication.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.openstack.keystone.auth.config;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.inject.Qualifier;
+
+@Retention(value = RetentionPolicy.RUNTIME)
+@Target(value = { ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
+@Qualifier
+public @interface Authentication {
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/config/AuthenticationModule.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/config/AuthenticationModule.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/config/AuthenticationModule.java
new file mode 100644
index 0000000..dbd9743
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/config/AuthenticationModule.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.openstack.keystone.auth.config;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static org.jclouds.rest.config.BinderUtils.bindHttpApi;
+
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.domain.Credentials;
+import org.jclouds.http.HttpRetryHandler;
+import org.jclouds.http.annotation.ClientError;
+import org.jclouds.location.Provider;
+import org.jclouds.openstack.keystone.auth.AuthenticationApi;
+import org.jclouds.openstack.keystone.auth.domain.AuthInfo;
+import org.jclouds.openstack.keystone.auth.functions.AuthenticateApiAccessKeyCredentials;
+import org.jclouds.openstack.keystone.auth.functions.AuthenticatePasswordCredentials;
+import org.jclouds.openstack.keystone.auth.functions.AuthenticateTokenCredentials;
+import org.jclouds.openstack.keystone.auth.handlers.RetryOnRenew;
+import org.jclouds.openstack.keystone.config.KeystoneProperties;
+import org.jclouds.openstack.keystone.v2_0.auth.V2AuthenticationApi;
+import org.jclouds.openstack.keystone.v3.auth.V3AuthenticationApi;
+
+import com.google.common.base.Function;
+import com.google.common.base.Supplier;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+import com.google.common.collect.Maps;
+import com.google.inject.AbstractModule;
+import com.google.inject.Injector;
+import com.google.inject.Provides;
+
+public class AuthenticationModule extends AbstractModule {
+
+   @Override
+   protected void configure() {
+      bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(RetryOnRenew.class);
+      bindHttpApi(binder(), V2AuthenticationApi.class);
+      bindHttpApi(binder(), V3AuthenticationApi.class);
+   }
+
+   @Provides
+   @Singleton
+   protected final AuthenticationApi provideAuthenticationApi(Injector i,
+         @Named(KeystoneProperties.KEYSTONE_VERSION) String keystoneVersion) {
+      return authenticationApis(i).get(keystoneVersion);
+   }
+
+   protected Map<String, AuthenticationApi> authenticationApis(Injector i) {
+      Map<String, AuthenticationApi> authenticationApis = Maps.newHashMap();
+      authenticationApis.put("2", i.getInstance(V2AuthenticationApi.class));
+      authenticationApis.put("3", i.getInstance(V3AuthenticationApi.class));
+      return authenticationApis;
+   }
+
+   /**
+    * borrowing concurrency code to ensure that caching takes place properly
+    */
+   @Provides
+   @Singleton
+   @Authentication
+   protected final Supplier<String> provideAuthenticationTokenCache(final Supplier<AuthInfo> supplier)
+         throws InterruptedException, ExecutionException, TimeoutException {
+      return new Supplier<String>() {
+         @Override
+         public String get() {
+            return supplier.get().getAuthToken();
+         }
+      };
+   }
+
+   @Provides
+   @Singleton
+   protected final Map<String, Function<Credentials, AuthInfo>> provideAuthenticationMethods(Injector i) {
+      return authenticationMethods(i);
+   }
+
+   protected Map<String, Function<Credentials, AuthInfo>> authenticationMethods(Injector i) {
+      Builder<Function<Credentials, AuthInfo>> fns = ImmutableSet.<Function<Credentials, AuthInfo>> builder();
+      fns.add(i.getInstance(AuthenticatePasswordCredentials.class));
+      fns.add(i.getInstance(AuthenticateApiAccessKeyCredentials.class));
+      fns.add(i.getInstance(AuthenticateTokenCredentials.class));
+      return CredentialTypes.indexByCredentialType(fns.build());
+   }
+
+   @Provides
+   @Singleton
+   protected final Function<Credentials, AuthInfo> authenticationMethodForCredentialType(
+         @Named(KeystoneProperties.CREDENTIAL_TYPE) String credentialType,
+         Map<String, Function<Credentials, AuthInfo>> authenticationMethods) {
+      checkArgument(authenticationMethods.containsKey(credentialType), "credential type %s not in supported list: %s",
+            credentialType, authenticationMethods.keySet());
+      return authenticationMethods.get(credentialType);
+   }
+
+   // TODO: what is the timeout of the session token? modify default accordingly
+   // PROPERTY_SESSION_INTERVAL is default to 60 seconds, but we have this here
+   // at 11 hours for now.
+   @Provides
+   @Singleton
+   public final LoadingCache<Credentials, AuthInfo> provideAccessCache(Function<Credentials, AuthInfo> getAccess) {
+      return CacheBuilder.newBuilder().expireAfterWrite(11, TimeUnit.HOURS).build(CacheLoader.from(getAccess));
+   }
+
+   // Temporary conversion of a cache to a supplier until there is a
+   // single-element cache
+   // http://code.google.com/p/guava-libraries/issues/detail?id=872
+   @Provides
+   @Singleton
+   protected final Supplier<AuthInfo> provideAccessSupplier(final LoadingCache<Credentials, AuthInfo> cache,
+         @Provider final Supplier<Credentials> creds) {
+      return new Supplier<AuthInfo>() {
+         @Override
+         public AuthInfo get() {
+            return cache.getUnchecked(creds.get());
+         }
+      };
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/config/CredentialType.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/config/CredentialType.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/config/CredentialType.java
new file mode 100644
index 0000000..171426f
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/config/CredentialType.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.openstack.keystone.auth.config;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.inject.Qualifier;
+
+/**
+ * @see CredentialTypes
+ */
+@Retention(value = RetentionPolicy.RUNTIME)
+@Target(value = { ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
+@Qualifier
+public @interface CredentialType {
+   /**
+    * @see CredentialTypes
+    * 
+    */
+   String value();
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/config/CredentialTypes.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/config/CredentialTypes.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/config/CredentialTypes.java
new file mode 100644
index 0000000..ed9764a
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/config/CredentialTypes.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.openstack.keystone.auth.config;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.util.Map;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Maps;
+
+/**
+ * Configuration properties and constants used in Keystone connections.
+ */
+public class CredentialTypes {
+
+   public static final String API_ACCESS_KEY_CREDENTIALS = "apiAccessKeyCredentials";
+
+   public static final String PASSWORD_CREDENTIALS = "passwordCredentials";
+
+   public static final String TOKEN_CREDENTIALS = "tokenCredentials";
+
+   public static <T> String credentialTypeOf(T input) {
+      Class<?> authenticationType = input.getClass();
+      CredentialType credentialType = findCredentialType(authenticationType);
+      checkArgument(credentialType != null, "programming error: %s should have annotation %s", authenticationType,
+            CredentialType.class.getName());
+      return credentialType.value();
+   }
+
+   public static <T> Map<String, T> indexByCredentialType(Iterable<T> iterable) {
+      return Maps.uniqueIndex(iterable, new Function<T, String>() {
+
+         @Override
+         public String apply(T input) {
+            return credentialTypeOf(input);
+         }
+
+      });
+   }
+
+   /**
+    * Find an annotation in teh given class or their parents. We need this since
+    * AutoValue classes inherit the classes we define.
+    */
+   public static CredentialType findCredentialType(Class<?> input) {
+      if (input == null)
+         return null;
+      CredentialType ann = input.getAnnotation(CredentialType.class);
+      return ann != null ? ann : findCredentialType(input.getSuperclass());
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/domain/ApiAccessKeyCredentials.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/domain/ApiAccessKeyCredentials.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/domain/ApiAccessKeyCredentials.java
new file mode 100644
index 0000000..c2e1e47
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/domain/ApiAccessKeyCredentials.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.openstack.keystone.auth.domain;
+
+import static org.jclouds.openstack.keystone.auth.config.CredentialTypes.API_ACCESS_KEY_CREDENTIALS;
+
+import org.jclouds.openstack.keystone.auth.config.CredentialType;
+
+import com.google.auto.value.AutoValue;
+
+@CredentialType(API_ACCESS_KEY_CREDENTIALS)
+@AutoValue
+public abstract class ApiAccessKeyCredentials {
+
+   public abstract String accessKey();
+   public abstract String secretKey();
+
+   public static ApiAccessKeyCredentials create(String accessKey, String secretKey, String tenantId, String tenantName) {
+      return builder().accessKey(accessKey).secretKey(secretKey).build();
+   }
+
+   ApiAccessKeyCredentials() {
+
+   }
+
+   public static Builder builder() {
+      return new AutoValue_ApiAccessKeyCredentials.Builder();
+   }
+
+   @AutoValue.Builder
+   public abstract static class Builder {
+      public abstract Builder accessKey(String accessKey);
+      public abstract Builder secretKey(String secretKey);
+
+      public abstract ApiAccessKeyCredentials build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/domain/AuthInfo.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/domain/AuthInfo.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/domain/AuthInfo.java
new file mode 100644
index 0000000..98e62ef
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/domain/AuthInfo.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.openstack.keystone.auth.domain;
+
+/**
+ * Common interface for authentication objects.
+ */
+public interface AuthInfo {
+
+   String getAuthToken();
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/domain/PasswordCredentials.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/domain/PasswordCredentials.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/domain/PasswordCredentials.java
new file mode 100644
index 0000000..d7a039c
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/domain/PasswordCredentials.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.openstack.keystone.auth.domain;
+
+import static org.jclouds.openstack.keystone.auth.config.CredentialTypes.PASSWORD_CREDENTIALS;
+
+import org.jclouds.openstack.keystone.auth.config.CredentialType;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.base.MoreObjects;
+
+@CredentialType(PASSWORD_CREDENTIALS)
+@AutoValue
+public abstract class PasswordCredentials {
+
+   public abstract String username();
+   public abstract String password();
+
+   public static PasswordCredentials create(String username, String password, String tenantId, String tenantName) {
+      return builder().username(username).password(password).build();
+   }
+
+   PasswordCredentials() {
+
+   }
+   
+   @Override
+   public String toString() {
+      return MoreObjects.toStringHelper(this).add("username", username())
+            .add("password", password() == null ? null : "*****").toString();
+   }
+
+   public static Builder builder() {
+      return new AutoValue_PasswordCredentials.Builder();
+   }
+
+   @AutoValue.Builder
+   public abstract static class Builder {
+      public abstract Builder username(String username);
+      public abstract Builder password(String password);
+      
+      public abstract PasswordCredentials build();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/domain/TenantAndCredentials.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/domain/TenantAndCredentials.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/domain/TenantAndCredentials.java
new file mode 100644
index 0000000..5988c67
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/domain/TenantAndCredentials.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.openstack.keystone.auth.domain;
+
+import org.jclouds.javax.annotation.Nullable;
+
+import com.google.auto.value.AutoValue;
+
+/**
+ * Keystone credentials with tenant. Configure the tenant properties to the
+ * configured context credentials.
+ */
+@AutoValue
+public abstract class TenantAndCredentials<T> {
+
+   @Nullable public abstract String tenantId();
+   @Nullable public abstract String tenantName();
+   public abstract T credentials();
+
+   TenantAndCredentials() {
+
+   }
+
+   public static <T> Builder<T> builder() {
+      return new AutoValue_TenantAndCredentials.Builder<T>();
+   }
+
+   @AutoValue.Builder
+   public abstract static class Builder<T> {
+      public abstract Builder<T> tenantId(String tenantId);
+      public abstract Builder<T> tenantName(String tenantName);
+      public abstract Builder<T> credentials(T credentials);
+
+      public abstract TenantAndCredentials<T> build();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/domain/TokenCredentials.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/domain/TokenCredentials.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/domain/TokenCredentials.java
new file mode 100644
index 0000000..7a4e0d3
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/domain/TokenCredentials.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.openstack.keystone.auth.domain;
+
+import static org.jclouds.openstack.keystone.auth.config.CredentialTypes.TOKEN_CREDENTIALS;
+
+import org.jclouds.openstack.keystone.auth.config.CredentialType;
+
+import com.google.auto.value.AutoValue;
+
+@CredentialType(TOKEN_CREDENTIALS)
+@AutoValue
+public abstract class TokenCredentials {
+
+   public abstract String id();
+
+   public static TokenCredentials create(String id, String secretKey, String tenantId, String tenantName) {
+      return builder().id(id).build();
+   }
+
+   TokenCredentials() {
+
+   }
+
+   public static Builder builder() {
+      return new AutoValue_TokenCredentials.Builder();
+   }
+
+   @AutoValue.Builder
+   public abstract static class Builder {
+      public abstract Builder id(String id);
+
+      public abstract TokenCredentials build();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/filters/AuthenticateRequest.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/filters/AuthenticateRequest.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/filters/AuthenticateRequest.java
new file mode 100644
index 0000000..6ee125c
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/filters/AuthenticateRequest.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.openstack.keystone.auth.filters;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpException;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpRequestFilter;
+import org.jclouds.openstack.keystone.auth.AuthHeaders;
+import org.jclouds.openstack.keystone.auth.config.Authentication;
+
+import com.google.common.base.Supplier;
+
+/**
+ * Signs the Keystone-based request. This will update the Authentication Token before 24 hours is up.
+ */
+@Singleton
+public class AuthenticateRequest implements HttpRequestFilter {
+
+   private final Supplier<String> authTokenProvider;
+
+   @Inject
+   AuthenticateRequest(@Authentication Supplier<String> authTokenProvider) {
+      this.authTokenProvider = authTokenProvider;
+   }
+
+   @Override
+   public HttpRequest filter(HttpRequest request) throws HttpException {
+      return request.toBuilder().replaceHeader(AuthHeaders.AUTH_TOKEN, authTokenProvider.get()).build();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/functions/AuthenticateApiAccessKeyCredentials.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/functions/AuthenticateApiAccessKeyCredentials.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/functions/AuthenticateApiAccessKeyCredentials.java
new file mode 100644
index 0000000..ead326e
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/functions/AuthenticateApiAccessKeyCredentials.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.openstack.keystone.auth.functions;
+
+import static org.jclouds.openstack.keystone.auth.config.CredentialTypes.API_ACCESS_KEY_CREDENTIALS;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.openstack.keystone.auth.AuthenticationApi;
+import org.jclouds.openstack.keystone.auth.config.CredentialType;
+import org.jclouds.openstack.keystone.auth.domain.ApiAccessKeyCredentials;
+import org.jclouds.openstack.keystone.auth.domain.AuthInfo;
+import org.jclouds.openstack.keystone.auth.domain.TenantAndCredentials;
+
+@CredentialType(API_ACCESS_KEY_CREDENTIALS)
+@Singleton
+public class AuthenticateApiAccessKeyCredentials extends BaseAuthenticator<ApiAccessKeyCredentials> {
+
+   private final AuthenticationApi auth;
+
+   @Inject
+   AuthenticateApiAccessKeyCredentials(AuthenticationApi auth) {
+      this.auth = auth;
+   }
+
+   @Override
+   public ApiAccessKeyCredentials createCredentials(String identity, String credential) {
+      return ApiAccessKeyCredentials.builder().accessKey(identity).secretKey(credential).build();
+   }
+
+   @Override
+   public AuthInfo authenticate(TenantAndCredentials<ApiAccessKeyCredentials> credentials) {
+      return auth.authenticateAccessKey(credentials);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/functions/AuthenticatePasswordCredentials.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/functions/AuthenticatePasswordCredentials.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/functions/AuthenticatePasswordCredentials.java
new file mode 100644
index 0000000..dc31b75
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/functions/AuthenticatePasswordCredentials.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.openstack.keystone.auth.functions;
+
+import static org.jclouds.openstack.keystone.auth.config.CredentialTypes.PASSWORD_CREDENTIALS;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.openstack.keystone.auth.AuthenticationApi;
+import org.jclouds.openstack.keystone.auth.config.CredentialType;
+import org.jclouds.openstack.keystone.auth.domain.AuthInfo;
+import org.jclouds.openstack.keystone.auth.domain.TenantAndCredentials;
+import org.jclouds.openstack.keystone.auth.domain.PasswordCredentials;
+
+@CredentialType(PASSWORD_CREDENTIALS)
+@Singleton
+public class AuthenticatePasswordCredentials extends BaseAuthenticator<PasswordCredentials> {
+
+   private final AuthenticationApi auth;
+
+   @Inject
+   AuthenticatePasswordCredentials(AuthenticationApi auth) {
+      this.auth = auth;
+   }
+
+   @Override
+   public PasswordCredentials createCredentials(String identity, String credential) {
+      return PasswordCredentials.builder().username(identity).password(credential).build();
+   }
+
+   @Override
+   public AuthInfo authenticate(TenantAndCredentials<PasswordCredentials> credentials) {
+      return auth.authenticatePassword(credentials);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/functions/AuthenticateTokenCredentials.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/functions/AuthenticateTokenCredentials.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/functions/AuthenticateTokenCredentials.java
new file mode 100644
index 0000000..70d6381
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/functions/AuthenticateTokenCredentials.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.openstack.keystone.auth.functions;
+
+import static org.jclouds.openstack.keystone.auth.config.CredentialTypes.TOKEN_CREDENTIALS;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.openstack.keystone.auth.AuthenticationApi;
+import org.jclouds.openstack.keystone.auth.config.CredentialType;
+import org.jclouds.openstack.keystone.auth.domain.AuthInfo;
+import org.jclouds.openstack.keystone.auth.domain.TenantAndCredentials;
+import org.jclouds.openstack.keystone.auth.domain.TokenCredentials;
+
+@CredentialType(TOKEN_CREDENTIALS)
+@Singleton
+public class AuthenticateTokenCredentials extends BaseAuthenticator<TokenCredentials> {
+
+   private final AuthenticationApi auth;
+
+   @Inject
+   AuthenticateTokenCredentials(AuthenticationApi auth) {
+      this.auth = auth;
+   }
+
+   @Override
+   public TokenCredentials createCredentials(String identity, String credential) {
+      return TokenCredentials.builder().id(credential).build();
+   }
+
+   @Override
+   public AuthInfo authenticate(TenantAndCredentials<TokenCredentials> credentials) {
+      return auth.authenticateToken(credentials);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/functions/BaseAuthenticator.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/functions/BaseAuthenticator.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/functions/BaseAuthenticator.java
new file mode 100644
index 0000000..05b2b94
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/functions/BaseAuthenticator.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.openstack.keystone.auth.functions;
+
+import static com.google.common.base.Preconditions.checkState;
+import static org.jclouds.openstack.keystone.config.KeystoneProperties.REQUIRES_TENANT;
+import static org.jclouds.openstack.keystone.config.KeystoneProperties.TENANT_ID;
+import static org.jclouds.openstack.keystone.config.KeystoneProperties.TENANT_NAME;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+
+import org.jclouds.domain.Credentials;
+import org.jclouds.logging.Logger;
+import org.jclouds.openstack.keystone.auth.domain.AuthInfo;
+import org.jclouds.openstack.keystone.auth.domain.TenantAndCredentials;
+
+import com.google.common.base.Function;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+
+public abstract class BaseAuthenticator<C> implements Function<Credentials, AuthInfo> {
+
+   @Resource
+   protected Logger logger = Logger.NULL;
+
+   @Inject(optional = true)
+   @Named(TENANT_NAME)
+   protected String defaultTenantName;
+
+   @Inject(optional = true)
+   @Named(TENANT_ID)
+   protected String defaultTenantId;
+
+   @Inject(optional = true)
+   @Named(REQUIRES_TENANT)
+   protected boolean requiresTenant;
+
+   @PostConstruct
+   public void checkPropertiesAreCompatible() {
+      checkState(defaultTenantName == null || defaultTenantId == null, "you cannot specify both %s and %s",
+            TENANT_NAME, TENANT_ID);
+   }
+
+   @Override
+   public AuthInfo apply(Credentials input) {
+      String tenantName = defaultTenantName;
+      String usernameOrAccessKey = input.identity;
+      String passwordOrSecretKeyOrToken = input.credential;
+
+      if (defaultTenantName == null && input.identity.indexOf(':') != -1) {
+         tenantName = input.identity.substring(0, input.identity.lastIndexOf(':'));
+         usernameOrAccessKey = input.identity.substring(input.identity.lastIndexOf(':') + 1);
+      }
+
+      if (defaultTenantId == null && tenantName == null && requiresTenant) {
+         throw new IllegalArgumentException(
+               String.format(
+                     "current configuration is set to [%s]. Unless you set [%s] or [%s], you must prefix your identity with 'tenantName:'",
+                     REQUIRES_TENANT, TENANT_NAME, TENANT_ID));
+      }
+      
+      C creds = createCredentials(usernameOrAccessKey, passwordOrSecretKeyOrToken);
+      TenantAndCredentials<C> credsWithTenant = TenantAndCredentials.<C> builder().tenantId(defaultTenantId)
+            .tenantName(tenantName).credentials(creds).build();
+      
+      return authenticate(credsWithTenant);
+   }
+
+   public abstract C createCredentials(String identity, String credential);
+   
+   public abstract AuthInfo authenticate(TenantAndCredentials<C> credentials);
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/handlers/RetryOnRenew.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/handlers/RetryOnRenew.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/handlers/RetryOnRenew.java
new file mode 100644
index 0000000..23ef7a1
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/auth/handlers/RetryOnRenew.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.openstack.keystone.auth.handlers;
+
+import java.util.concurrent.TimeUnit;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+
+import org.jclouds.Constants;
+import org.jclouds.domain.Credentials;
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpRetryHandler;
+import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
+import org.jclouds.logging.Logger;
+import org.jclouds.openstack.keystone.auth.AuthHeaders;
+import org.jclouds.openstack.keystone.auth.domain.AuthInfo;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.Multimap;
+import com.google.common.util.concurrent.Uninterruptibles;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+/**
+ * This will parse and set an appropriate exception on the command object.
+ */
+@Singleton
+public class RetryOnRenew implements HttpRetryHandler {
+   @Resource
+   protected Logger logger = Logger.NULL;
+
+   @VisibleForTesting
+   @Inject(optional = true)
+   @Named(Constants.PROPERTY_MAX_RETRIES)
+   static int NUM_RETRIES = 5;
+
+   private final LoadingCache<Credentials, AuthInfo> authenticationResponseCache;
+
+   private final BackoffLimitedRetryHandler backoffHandler;
+
+   @Inject
+   RetryOnRenew(LoadingCache<Credentials, AuthInfo> authenticationResponseCache,
+         BackoffLimitedRetryHandler backoffHandler) {
+      this.authenticationResponseCache = authenticationResponseCache;
+      this.backoffHandler = backoffHandler;
+   }
+
+   /*
+    * The reason retries need to be tracked is that it is possible that a token
+    * can be expired at any time. The reason we track by request is that only
+    * some requests might return a 401 (such as temporary URLs). However
+    * consistent failures of the magnitude this code tracks should indicate a
+    * problem.
+    */
+   private static final Cache<HttpCommand, Integer> retryCountMap = CacheBuilder.newBuilder()
+         .expireAfterWrite(5, TimeUnit.MINUTES).build();
+
+   @Override
+   public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
+      boolean retry = false; // default
+      switch (response.getStatusCode()) {
+         case 401:
+            // Do not retry on 401 from authentication request
+            Multimap<String, String> headers = command.getCurrentRequest().getHeaders();
+            if (headers != null && headers.containsKey(AuthHeaders.AUTH_USER)
+                  && headers.containsKey(AuthHeaders.AUTH_KEY) && !headers.containsKey(AuthHeaders.AUTH_TOKEN)) {
+               retry = false;
+            } else {
+               // This is not an authentication request returning 401
+               // Check if we already had seen this request
+               Integer count = retryCountMap.getIfPresent(command);
+
+               if (count == null) {
+                  // First time this non-authentication request failed
+                  logger.debug("invalidating authentication token - first time for %s", command);
+                  retryCountMap.put(command, 1);
+                  authenticationResponseCache.invalidateAll();
+                  retry = true;
+               } else {
+                  // This request has failed before
+                  if (count + 1 >= NUM_RETRIES) {
+                     logger.debug("too many 401s - giving up after: %s for %s", count, command);
+                     retry = false;
+                  } else {
+                     // Retry just in case
+                     logger.debug("invalidating authentication token - retry %s for %s", count, command);
+                     retryCountMap.put(command, count + 1);
+                     // Wait between retries
+                     authenticationResponseCache.invalidateAll();
+                     Uninterruptibles.sleepUninterruptibly(5, TimeUnit.SECONDS);
+                     retry = true;
+                  }
+               }
+            }
+            break;
+         case 408:
+            return backoffHandler.shouldRetryRequest(command, response);
+      }
+      return retry;
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/catalog/ServiceEndpoint.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/catalog/ServiceEndpoint.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/catalog/ServiceEndpoint.java
new file mode 100644
index 0000000..139751e
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/catalog/ServiceEndpoint.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.openstack.keystone.catalog;
+
+import java.net.URI;
+
+import org.jclouds.javax.annotation.Nullable;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Enums;
+
+/**
+ * Common properties for OpenStack service endpoints.
+ * <p>
+ * This class provides a common view on the service catalog endpoints so it can
+ * be parsed in a generic way for Keystone v2 and v3.
+ */
+@AutoValue
+public abstract class ServiceEndpoint {
+
+   public static enum Interface {
+      PUBLIC, ADMIN, INTERNAL, UNRECOGNIZED;
+
+      public static Interface fromValue(String iface) {
+         return Enums.getIfPresent(Interface.class, iface.toLowerCase()).or(UNRECOGNIZED);
+      }
+   }
+
+   @Nullable public abstract String id();
+   @Nullable public abstract String regionId();
+   public abstract URI url();
+   public abstract Interface iface();
+   public abstract String type();
+   @Nullable public abstract String version();
+   
+   ServiceEndpoint() {
+      
+   }
+   
+   public static Builder builder() {
+      return new AutoValue_ServiceEndpoint.Builder();
+   }
+   
+   @AutoValue.Builder
+   public abstract static class Builder {
+      public abstract Builder id(String id);
+      public abstract Builder regionId(String regionId);
+      public abstract Builder url(URI url);
+      public abstract Builder iface(Interface iface);
+      public abstract Builder type(String type);
+      public abstract Builder version(String version);
+      
+      public Builder iface(String iface) {
+         return iface(Interface.fromValue(iface));
+      }
+      
+      public abstract ServiceEndpoint build();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/catalog/config/InternalUrlModule.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/catalog/config/InternalUrlModule.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/catalog/config/InternalUrlModule.java
new file mode 100644
index 0000000..bda2bed
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/catalog/config/InternalUrlModule.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.openstack.keystone.catalog.config;
+
+import org.jclouds.openstack.keystone.catalog.functions.InternalURL;
+import org.jclouds.openstack.keystone.catalog.functions.ServiceEndpointResolutionStrategy;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Singleton;
+
+/**
+ * Guice module to configure JClouds in order to use the internal urls to
+ * communicate with the services.
+ */
+@Singleton
+public class InternalUrlModule extends AbstractModule {
+   @Override
+   protected void configure() {
+      bind(ServiceEndpointResolutionStrategy.class).to(InternalURL.class);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/7def8169/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/catalog/config/KeystoneAdminURLModule.java
----------------------------------------------------------------------
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/catalog/config/KeystoneAdminURLModule.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/catalog/config/KeystoneAdminURLModule.java
new file mode 100644
index 0000000..d670973
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/catalog/config/KeystoneAdminURLModule.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.openstack.keystone.catalog.config;
+
+import static org.jclouds.util.Suppliers2.getLastValueInMap;
+
+import java.net.URI;
+import java.util.NoSuchElementException;
+
+import javax.inject.Singleton;
+
+import org.jclouds.location.Provider;
+import org.jclouds.openstack.keystone.catalog.suppliers.RegionIdToAdminURIFromAccessForTypeAndVersion;
+import org.jclouds.openstack.keystone.catalog.suppliers.RegionIdToAdminURISupplier;
+import org.jclouds.openstack.v2_0.ServiceType;
+import org.jclouds.openstack.v2_0.services.Identity;
+import org.jclouds.rest.annotations.ApiVersion;
+import org.jclouds.util.Suppliers2;
+
+import com.google.common.base.Supplier;
+import com.google.inject.AbstractModule;
+import com.google.inject.Provides;
+import com.google.inject.assistedinject.FactoryModuleBuilder;
+
+public class KeystoneAdminURLModule extends AbstractModule {
+
+   @Override
+   protected void configure() {
+      install(new FactoryModuleBuilder().implement(RegionIdToAdminURISupplier.class,
+               RegionIdToAdminURIFromAccessForTypeAndVersion.class).build(RegionIdToAdminURISupplier.Factory.class));
+   }
+
+   /**
+    * in some cases, there is no {@link ServiceType#IDENTITY} entry in the service catalog. In
+    * other cases, there's no adminURL entry present. Fallback to the provider in this case.
+    */
+   @Provides
+   @Singleton
+   @Identity
+   protected final Supplier<URI> provideIdentityAdminUrl(final RegionIdToAdminURISupplier.Factory factory,
+            @ApiVersion final String version, @Provider final Supplier<URI> providerURI) {
+      Supplier<URI> identityServiceForVersion = getLastValueInMap(factory.createForApiTypeAndVersion(
+               ServiceType.IDENTITY, version));
+      Supplier<URI> whenIdentityServiceIsntListedFallbackToProviderURI = Suppliers2.onThrowable(
+               identityServiceForVersion, NoSuchElementException.class, providerURI);
+      Supplier<URI> whenIdentityServiceHasNoAdminURLFallbackToProviderURI = Suppliers2.or(
+               whenIdentityServiceIsntListedFallbackToProviderURI, providerURI);
+      return whenIdentityServiceHasNoAdminURLFallbackToProviderURI;
+   }
+}