Add support for OpenStack Keystone V3

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.

Co-authored-by: Andrea Turli <andreaturli@apache.org>
This commit is contained in:
Ignasi Barrera 2017-12-05 17:13:31 +01:00
parent 18eb7f3d38
commit dd73410d12
235 changed files with 6421 additions and 2022 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -32,13 +32,18 @@
<packaging>bundle</packaging>
<properties>
<!-- keystone endpoint -->
<!-- keystone version 2 -->
<test.openstack-keystone.endpoint>http://localhost:5000/v${jclouds.api-version}/</test.openstack-keystone.endpoint>
<!-- keystone version -->
<test.openstack-keystone.api-version>2.0</test.openstack-keystone.api-version>
<test.openstack-keystone.build-version />
<test.openstack-keystone.identity>FIXME_IDENTITY</test.openstack-keystone.identity>
<test.openstack-keystone.credential>FIXME_CREDENTIALS</test.openstack-keystone.credential>
<test.openstack-keystone.identity>FIXME_TENANT:FIXME_USER</test.openstack-keystone.identity>
<test.openstack-keystone.credential>FIXME_PASSWORD</test.openstack-keystone.credential>
<!-- keystone version 3 -->
<test.openstack-keystone-3.endpoint>http://localhost/identity/v3</test.openstack-keystone-3.endpoint>
<test.openstack-keystone-3.api-version>3</test.openstack-keystone-3.api-version>
<test.openstack-keystone-3.build-version />
<test.openstack-keystone-3.identity>FIXME_DOMAIN:FIXME_USER</test.openstack-keystone-3.identity>
<test.openstack-keystone-3.credential>FIXME_PASSWORD</test.openstack-keystone-3.credential>
<test.jclouds.keystone.credential-type>passwordCredentials</test.jclouds.keystone.credential-type>
<jclouds.osgi.export>org.jclouds.openstack*;version="${project.version}"</jclouds.osgi.export>
@ -69,6 +74,13 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<!-- A driver that supports the PATCH verb is needed for tests -->
<dependency>
<groupId>org.apache.jclouds.driver</groupId>
<artifactId>jclouds-okhttp</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
@ -84,8 +96,29 @@
<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>
<id>live</id>
@ -102,6 +135,13 @@
<goal>test</goal>
</goals>
<configuration>
<excludes>
<exclude>none</exclude>
</excludes>
<includes>
<include>**/keystone/v2_0/**/*IntegrationTest.java</include>
<include>**/keystone/v2_0/**/*LiveTest.java</include>
</includes>
<systemPropertyVariables>
<test.openstack-keystone.endpoint>${test.openstack-keystone.endpoint}</test.openstack-keystone.endpoint>
<test.openstack-keystone.api-version>${test.openstack-keystone.api-version}</test.openstack-keystone.api-version>
@ -117,6 +157,43 @@
</plugins>
</build>
</profile>
<profile>
<id>live-v3</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>integration</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<excludes>
<exclude>none</exclude>
</excludes>
<includes>
<include>**/keystone/v3/**/*IntegrationTest.java</include>
<include>**/keystone/v3/**/*LiveTest.java</include>
</includes>
<systemPropertyVariables>
<test.openstack-keystone-3.endpoint>${test.openstack-keystone.endpoint}</test.openstack-keystone-3.endpoint>
<test.openstack-keystone-3.api-version>${test.openstack-keystone.api-version}</test.openstack-keystone-3.api-version>
<test.openstack-keystone-3.build-version>${test.openstack-keystone.build-version}</test.openstack-keystone-3.build-version>
<test.openstack-keystone-3.identity>${test.openstack-keystone-3.identity}</test.openstack-keystone-3.identity>
<test.openstack-keystone-3.credential>${test.openstack-keystone-3.credential}</test.openstack-keystone-3.credential>
<test.jclouds.keystone.credential-type>${test.jclouds.keystone.credential-type}</test.jclouds.keystone.credential-type>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.v2_0.reference;
package org.jclouds.openstack.keystone.auth;
public final class AuthHeaders {

View File

@ -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.TenantOrDomainAndCredentials;
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(TenantOrDomainAndCredentials<PasswordCredentials> credentials);
AuthInfo authenticateAccessKey(TenantOrDomainAndCredentials<ApiAccessKeyCredentials> credentials);
AuthInfo authenticateToken(TenantOrDomainAndCredentials<TokenCredentials> credentials);
}

View File

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.config;
package org.jclouds.openstack.keystone.auth.config;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@ -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.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> provideAuthInfoCache(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> provideAuthInfoSupplier(final LoadingCache<Credentials, AuthInfo> cache,
@Provider final Supplier<Credentials> creds) {
return new Supplier<AuthInfo>() {
@Override
public AuthInfo get() {
return cache.getUnchecked(creds.get());
}
};
}
}

View File

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.config;
package org.jclouds.openstack.keystone.auth.config;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@ -32,7 +32,6 @@ import javax.inject.Qualifier;
public @interface CredentialType {
/**
* @see CredentialTypes
*
*/
String value();
}

View File

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.config;
package org.jclouds.openstack.keystone.auth.config;
import static com.google.common.base.Preconditions.checkArgument;
@ -32,21 +32,33 @@ public class CredentialTypes {
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();
checkArgument(authenticationType.isAnnotationPresent(CredentialType.class),
"programming error: %s should have annotation %s", authenticationType, CredentialType.class.getName());
return authenticationType.getAnnotation(CredentialType.class).value();
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());
}
}

View File

@ -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) {
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();
}
}

View File

@ -14,10 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.functions;
package org.jclouds.openstack.keystone.auth.domain;
import com.google.inject.ImplementedBy;
/**
* Common interface for authentication objects.
*/
public interface AuthInfo {
@ImplementedBy(AdminURL.class)
public interface EndpointToSupplierAdminURI extends EndpointToSupplierURI {
String getAuthToken();
}

View File

@ -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) {
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();
}
}

View File

@ -0,0 +1,52 @@
/*
* 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 TenantOrDomainAndCredentials<T> {
@Nullable public abstract String tenantOrDomainId();
@Nullable public abstract String tenantOrDomainName();
@Nullable public abstract String scope();
public abstract T credentials();
TenantOrDomainAndCredentials() {
}
public static <T> Builder<T> builder() {
return new AutoValue_TenantOrDomainAndCredentials.Builder<T>();
}
@AutoValue.Builder
public abstract static class Builder<T> {
public abstract Builder<T> tenantOrDomainId(String tenantId);
public abstract Builder<T> tenantOrDomainName(String tenantName);
public abstract Builder<T> scope(String scope);
public abstract Builder<T> credentials(T credentials);
public abstract TenantOrDomainAndCredentials<T> build();
}
}

View File

@ -14,26 +14,37 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.functions;
package org.jclouds.openstack.keystone.auth.domain;
import java.net.URI;
import static org.jclouds.openstack.keystone.auth.config.CredentialTypes.TOKEN_CREDENTIALS;
import javax.inject.Singleton;
import org.jclouds.openstack.keystone.auth.config.CredentialType;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import com.google.auto.value.AutoValue;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
@CredentialType(TOKEN_CREDENTIALS)
@AutoValue
public abstract class TokenCredentials {
@Singleton
public class PublicURLOrInternalIfNull implements EndpointToSupplierURI {
// TODO: check accessibility and prioritize private first
@Override
public Supplier<URI> apply(Endpoint input) {
return Suppliers.ofInstance(input.getPublicURL() != null ? input.getPublicURL() : input.getInternalURL());
public abstract String id();
public static TokenCredentials create(String id) {
return builder().id(id).build();
}
public String toString() {
return "supplyPublicURL()";
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();
}
}

View File

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.filters;
package org.jclouds.openstack.keystone.auth.filters;
import javax.inject.Inject;
import javax.inject.Singleton;
@ -22,8 +22,8 @@ import javax.inject.Singleton;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter;
import org.jclouds.openstack.keystone.v2_0.config.Authentication;
import org.jclouds.openstack.v2_0.reference.AuthHeaders;
import org.jclouds.openstack.keystone.auth.AuthHeaders;
import org.jclouds.openstack.keystone.auth.config.Authentication;
import com.google.common.base.Supplier;
@ -36,7 +36,7 @@ public class AuthenticateRequest implements HttpRequestFilter {
private final Supplier<String> authTokenProvider;
@Inject
public AuthenticateRequest(@Authentication Supplier<String> authTokenProvider) {
AuthenticateRequest(@Authentication Supplier<String> authTokenProvider) {
this.authTokenProvider = authTokenProvider;
}

View File

@ -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.TenantOrDomainAndCredentials;
@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(TenantOrDomainAndCredentials<ApiAccessKeyCredentials> credentials) {
return auth.authenticateAccessKey(credentials);
}
}

View File

@ -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.TenantOrDomainAndCredentials;
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(TenantOrDomainAndCredentials<PasswordCredentials> credentials) {
return auth.authenticatePassword(credentials);
}
}

View File

@ -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.TenantOrDomainAndCredentials;
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(TenantOrDomainAndCredentials<TokenCredentials> credentials) {
return auth.authenticateToken(credentials);
}
}

View File

@ -14,26 +14,28 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.functions.internal;
package org.jclouds.openstack.keystone.auth.functions;
import static com.google.common.base.Preconditions.checkState;
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.REQUIRES_TENANT;
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.TENANT_ID;
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.TENANT_NAME;
import static org.jclouds.openstack.keystone.config.KeystoneProperties.REQUIRES_TENANT;
import static org.jclouds.openstack.keystone.config.KeystoneProperties.SCOPE;
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.v2_0.domain.Access;
import org.jclouds.openstack.keystone.auth.domain.AuthInfo;
import org.jclouds.openstack.keystone.auth.domain.TenantOrDomainAndCredentials;
import org.jclouds.openstack.keystone.v3.domain.Auth.Scope;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.inject.Inject;
import com.google.inject.name.Named;
public abstract class BaseAuthenticator<C> implements Function<Credentials, Access> {
public abstract class BaseAuthenticator<C> implements Function<Credentials, AuthInfo> {
@Resource
protected Logger logger = Logger.NULL;
@ -50,6 +52,10 @@ public abstract class BaseAuthenticator<C> implements Function<Credentials, Acce
@Named(REQUIRES_TENANT)
protected boolean requiresTenant;
@Inject(optional = true)
@Named(SCOPE)
protected String scope = Scope.UNSCOPED;
@PostConstruct
public void checkPropertiesAreCompatible() {
checkState(defaultTenantName == null || defaultTenantId == null, "you cannot specify both %s and %s",
@ -57,41 +63,32 @@ public abstract class BaseAuthenticator<C> implements Function<Credentials, Acce
}
@Override
public Access apply(Credentials input) {
Optional<String> tenantName = Optional.fromNullable(defaultTenantName);
Optional<String> tenantId = Optional.fromNullable(defaultTenantId);
public AuthInfo apply(Credentials input) {
String tenantName = defaultTenantName;
String usernameOrAccessKey = input.identity;
String passwordOrSecretKeyOrToken = input.credential;
if (!tenantName.isPresent() && input.identity.indexOf(':') != -1) {
tenantName = Optional.of(input.identity.substring(0, input.identity.lastIndexOf(':')));
if (defaultTenantName == null && input.identity.indexOf(':') != -1) {
tenantName = input.identity.substring(0, input.identity.lastIndexOf(':'));
usernameOrAccessKey = input.identity.substring(input.identity.lastIndexOf(':') + 1);
}
String passwordOrSecretKey = input.credential;
C creds = createCredentials(usernameOrAccessKey, passwordOrSecretKey);
Access access;
if (tenantId.isPresent()) {
access = authenticateWithTenantId(tenantId, creds);
} else if (tenantName.isPresent()) {
access = authenticateWithTenantName(tenantName, creds);
} else if (!requiresTenant) {
access = authenticateWithTenantName(tenantName, creds);
} else {
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));
}
return access;
C creds = createCredentials(usernameOrAccessKey, passwordOrSecretKeyOrToken);
TenantOrDomainAndCredentials<C> credsWithTenant = TenantOrDomainAndCredentials.<C> builder().tenantOrDomainId(defaultTenantId)
.tenantOrDomainName(tenantName).scope(scope).credentials(creds).build();
return authenticate(credsWithTenant);
}
public abstract C createCredentials(String identity, String credential);
protected abstract Access authenticateWithTenantId(Optional<String> tenantId, C apiAccessKeyCredentials);
protected abstract Access authenticateWithTenantName(Optional<String> tenantId, C apiAccessKeyCredentials);
public abstract AuthInfo authenticate(TenantOrDomainAndCredentials<C> credentials);
}

View File

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.handlers;
package org.jclouds.openstack.keystone.auth.handlers;
import java.util.concurrent.TimeUnit;
@ -28,8 +28,8 @@ 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.v2_0.domain.Access;
import org.jclouds.openstack.v2_0.reference.AuthHeaders;
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;
@ -53,12 +53,12 @@ public class RetryOnRenew implements HttpRetryHandler {
@Named(Constants.PROPERTY_MAX_RETRIES)
static int NUM_RETRIES = 5;
private final LoadingCache<Credentials, Access> authenticationResponseCache;
private final LoadingCache<Credentials, AuthInfo> authenticationResponseCache;
private final BackoffLimitedRetryHandler backoffHandler;
@Inject
protected RetryOnRenew(LoadingCache<Credentials, Access> authenticationResponseCache,
RetryOnRenew(LoadingCache<Credentials, AuthInfo> authenticationResponseCache,
BackoffLimitedRetryHandler backoffHandler) {
this.authenticationResponseCache = authenticationResponseCache;
this.backoffHandler = backoffHandler;

View File

@ -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 enum Interface {
PUBLIC, ADMIN, INTERNAL, UNRECOGNIZED;
public static Interface fromValue(String iface) {
return Enums.getIfPresent(Interface.class, iface.toUpperCase()).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();
}
}

View File

@ -14,10 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.v2_0.config;
package org.jclouds.openstack.keystone.catalog.config;
import org.jclouds.openstack.keystone.v2_0.functions.EndpointToSupplierURI;
import org.jclouds.openstack.keystone.v2_0.functions.InternalURL;
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;
@ -30,6 +30,6 @@ import com.google.inject.Singleton;
public class InternalUrlModule extends AbstractModule {
@Override
protected void configure() {
bind(EndpointToSupplierURI.class).to(InternalURL.class);
bind(ServiceEndpointResolutionStrategy.class).to(InternalURL.class);
}
}

View File

@ -0,0 +1,72 @@
/*
* 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.openstack.keystone.config.KeystoneProperties.KEYSTONE_VERSION;
import static org.jclouds.util.Suppliers2.getLastValueInMap;
import java.net.URI;
import java.util.NoSuchElementException;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.location.Provider;
import org.jclouds.openstack.keystone.catalog.suppliers.RegionIdToAdminURIFromServiceEndpointsForTypeAndVersion;
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,
RegionIdToAdminURIFromServiceEndpointsForTypeAndVersion.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, @Named(KEYSTONE_VERSION) String keystoneVersion,
@Provider final Supplier<URI> providerURI) {
// There is a convention to use service types such as "identityv3" for specific endpoints. let's look first for
// those endpoints, and fallback to the default "identity" one or the project URL.
Supplier<URI> identityServiceForSpecificVersionInType = getLastValueInMap(factory.createForApiTypeAndVersion(
ServiceType.IDENTITY + "v" + keystoneVersion, version));
Supplier<URI> identityServiceForVersion = Suppliers2.onThrowable(identityServiceForSpecificVersionInType,
NoSuchElementException.class,
getLastValueInMap(factory.createForApiTypeAndVersion(ServiceType.IDENTITY, version)));
Supplier<URI> whenIdentityServiceIsntListedFallbackToProviderURI = Suppliers2.onThrowable(
identityServiceForVersion, NoSuchElementException.class, providerURI);
Supplier<URI> whenIdentityServiceHasNoAdminURLFallbackToProviderURI = Suppliers2.or(
whenIdentityServiceIsntListedFallbackToProviderURI, providerURI);
return whenIdentityServiceHasNoAdminURLFallbackToProviderURI;
}
}

View File

@ -0,0 +1,160 @@
/*
* 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.List;
import java.util.Map;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.location.Provider;
import org.jclouds.location.suppliers.ImplicitLocationSupplier;
import org.jclouds.location.suppliers.LocationsSupplier;
import org.jclouds.location.suppliers.RegionIdToURISupplier;
import org.jclouds.location.suppliers.RegionIdsSupplier;
import org.jclouds.location.suppliers.all.RegionToProvider;
import org.jclouds.location.suppliers.derived.RegionIdsFromRegionIdToURIKeySet;
import org.jclouds.location.suppliers.implicit.FirstRegion;
import org.jclouds.openstack.keystone.catalog.ServiceEndpoint;
import org.jclouds.openstack.keystone.catalog.suppliers.LocationIdToURIFromServiceEndpointsForTypeAndVersion;
import org.jclouds.openstack.keystone.catalog.suppliers.RegionIdToAdminURIFromServiceEndpointsForTypeAndVersion;
import org.jclouds.openstack.keystone.catalog.suppliers.RegionIdToAdminURISupplier;
import org.jclouds.openstack.keystone.catalog.suppliers.RegionIdToURIFromServiceEndpointsForTypeAndVersion;
import org.jclouds.openstack.keystone.config.KeystoneProperties;
import org.jclouds.openstack.keystone.v2_0.catalog.V2ServiceCatalog;
import org.jclouds.openstack.keystone.v3.catalog.V3ServiceCatalog;
import org.jclouds.rest.annotations.ApiVersion;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.collect.Maps;
import com.google.inject.AbstractModule;
import com.google.inject.Injector;
import com.google.inject.Provides;
import com.google.inject.Scopes;
import com.google.inject.assistedinject.FactoryModuleBuilder;
public class ServiceCatalogModule extends AbstractModule {
@Override
protected void configure() {
}
@Provides
@Singleton
protected final Supplier<List<ServiceEndpoint>> provideServiceCatalog(Injector i,
@Named(KeystoneProperties.KEYSTONE_VERSION) String keystoneVersion) {
Map<String, Supplier<List<ServiceEndpoint>>> serviceCatalogs = Maps.newHashMap();
serviceCatalogs.put("2", i.getInstance(V2ServiceCatalog.class));
serviceCatalogs.put("3", i.getInstance(V3ServiceCatalog.class));
return serviceCatalogs.get(keystoneVersion);
}
/**
* For global services who have no regions, such as DNS. To use, do the following
* <ol>
* <li>add this module to your {@link org.jclouds.apis.ApiMetadata#getDefaultModules()}</li>
* <li>create a service-specific annotation, such as {@code @CloudDNS}, and make sure that has the meta-annotation
* {@link javax.inject.Qualifier}</li>
* <li>add the above annotation to any {@code Api} classes by placing it on the type. ex.
* {@code @Endpoint(CloudDNS.class)}</li>
* <li>add the following to your {@link org.jclouds.rest.config.RestClientModule}</li>
*
* <pre>
* bind(new TypeLiteral&lt;Supplier&lt;URI&gt;&gt;() {
* }).annotatedWith(CloudDNS.class).to(new TypeLiteral&lt;Supplier&lt;URI&gt;&gt;() {
* });
* </pre>
*/
public static class ProviderModule extends AbstractModule {
@Override
protected void configure() {
install(new FactoryModuleBuilder().build(LocationIdToURIFromServiceEndpointsForTypeAndVersion.Factory.class));
}
@Provides
@Singleton
protected final Supplier<URI> provideZoneIdToURISupplierForApiVersion(
@Named(KeystoneProperties.SERVICE_TYPE) String serviceType, @ApiVersion String apiVersion,
LocationIdToURIFromServiceEndpointsForTypeAndVersion.Factory factory) {
return getLastValueInMap(factory.createForApiTypeAndVersion(serviceType, apiVersion));
}
@Provides
@Singleton
final Function<ServiceEndpoint, String> provideProvider(@Provider final String provider) {
return new Function<ServiceEndpoint, String>() {
@Override
public String apply(ServiceEndpoint in) {
return provider;
}
};
}
}
public static class RegionModule extends AbstractModule {
@Override
protected void configure() {
install(new FactoryModuleBuilder().implement(RegionIdToURISupplier.class,
RegionIdToURIFromServiceEndpointsForTypeAndVersion.class).build(RegionIdToURISupplier.Factory.class));
install(new FactoryModuleBuilder().implement(RegionIdToAdminURISupplier.class,
RegionIdToAdminURIFromServiceEndpointsForTypeAndVersion.class).build(RegionIdToAdminURISupplier.Factory.class));
// Dynamically build the region list as opposed to from properties
bind(RegionIdsSupplier.class).to(RegionIdsFromRegionIdToURIKeySet.class);
bind(ImplicitLocationSupplier.class).to(FirstRegion.class).in(Scopes.SINGLETON);
bind(LocationsSupplier.class).to(RegionToProvider.class).in(Scopes.SINGLETON);
}
@Provides
@Singleton
protected final RegionIdToURISupplier guiceProvideRegionIdToURISupplierForApiVersion(
@Named(KeystoneProperties.SERVICE_TYPE) String serviceType, @ApiVersion String apiVersion,
RegionIdToURISupplier.Factory factory) {
return provideRegionIdToURISupplierForApiVersion(serviceType, apiVersion, factory);
}
// Supply the region to id map from keystone, based on the servicetype and
// api version in config
protected RegionIdToURISupplier provideRegionIdToURISupplierForApiVersion(
@Named(KeystoneProperties.SERVICE_TYPE) String serviceType, @ApiVersion String apiVersion,
RegionIdToURISupplier.Factory factory) {
return factory.createForApiTypeAndVersion(serviceType, apiVersion);
}
@Provides
@Singleton
protected final RegionIdToAdminURISupplier guiceProvideRegionIdToAdminURISupplierForApiVersion(
@Named(KeystoneProperties.SERVICE_TYPE) String serviceType, @ApiVersion String apiVersion,
RegionIdToAdminURISupplier.Factory factory) {
return provideRegionIdToAdminURISupplierForApiVersion(serviceType, apiVersion, factory);
}
// Supply the region to id to AdminURL map from keystone, based on the
// servicetype and api version in config
protected RegionIdToAdminURISupplier provideRegionIdToAdminURISupplierForApiVersion(
@Named(KeystoneProperties.SERVICE_TYPE) String serviceType, @ApiVersion String apiVersion,
RegionIdToAdminURISupplier.Factory factory) {
return factory.createForApiTypeAndVersion(serviceType, apiVersion);
}
}
}

View File

@ -14,16 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.functions;
package org.jclouds.openstack.keystone.catalog.functions;
import java.net.URI;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.inject.ImplementedBy;
@ImplementedBy(PublicURLOrInternalIfNull.class)
public interface EndpointToSupplierURI extends Function<Endpoint, Supplier<URI>> {
/**
* Given a sets of endpoints for a particular service and version, return the
* URL of the admin endpoint to be used to connect to the service.
*/
@ImplementedBy(AdminURL.class)
public interface AdminEndpointResolutionStrategy extends ServiceEndpointResolutionStrategy {
}

View File

@ -14,25 +14,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.functions;
package org.jclouds.openstack.keystone.catalog.functions;
import java.net.URI;
import static org.jclouds.openstack.keystone.catalog.ServiceEndpoint.Interface.ADMIN;
import javax.inject.Singleton;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import org.jclouds.openstack.keystone.catalog.ServiceEndpoint;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.base.Predicate;
@Singleton
public class AdminURL implements EndpointToSupplierAdminURI {
@Override
public Supplier<URI> apply(Endpoint input) {
return Suppliers.ofInstance(input.getAdminURL());
}
public class AdminURL extends BaseEndpointResolutionStrategy implements AdminEndpointResolutionStrategy {
public String toString() {
return "supplyAdminURL()";
@Override
protected Predicate<ServiceEndpoint> filter() {
return withIface(ADMIN);
}
}

View File

@ -0,0 +1,62 @@
/*
* 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.functions;
import static com.google.common.collect.Iterables.tryFind;
import java.net.URI;
import java.util.Collection;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.keystone.catalog.ServiceEndpoint;
import org.jclouds.openstack.keystone.catalog.ServiceEndpoint.Interface;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
/**
* Resolves the endpoint to be used to connect to a service based on a given
* predicate.
*/
public abstract class BaseEndpointResolutionStrategy implements ServiceEndpointResolutionStrategy {
protected abstract Predicate<ServiceEndpoint> filter();
@Nullable
@Override
public Supplier<URI> apply(Collection<ServiceEndpoint> input) {
Predicate<ServiceEndpoint> filter = filter();
Optional<ServiceEndpoint> serviceEndpoint = tryFind(input, filter);
return Suppliers.ofInstance(serviceEndpoint.isPresent() ? serviceEndpoint.get().url() : null);
}
protected static Predicate<ServiceEndpoint> withIface(final Interface iface) {
return new Predicate<ServiceEndpoint>() {
@Override
public boolean apply(ServiceEndpoint input) {
return input.iface().equals(iface);
}
@Override
public String toString() {
return "interface(" + iface.name().toLowerCase() + ")";
}
};
}
}

View File

@ -14,20 +14,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.config;
package org.jclouds.openstack.keystone.catalog.functions;
import static org.jclouds.rest.config.BinderUtils.bindHttpApi;
import static org.jclouds.openstack.keystone.catalog.ServiceEndpoint.Interface.INTERNAL;
import org.jclouds.openstack.keystone.v2_0.AuthenticationApi;
import javax.inject.Singleton;
import com.google.inject.AbstractModule;
import org.jclouds.openstack.keystone.catalog.ServiceEndpoint;
public class AuthenticationApiModule extends AbstractModule {
import com.google.common.base.Predicate;
@Singleton
public class InternalURL extends BaseEndpointResolutionStrategy {
@Override
protected void configure() {
// AuthenticationApi is used directly for filters and retry handlers, so let's bind it explicitly
bindHttpApi(binder(), AuthenticationApi.class);
protected Predicate<ServiceEndpoint> filter() {
return withIface(INTERNAL);
}
}

View File

@ -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.catalog.functions;
import static com.google.common.base.Predicates.or;
import static org.jclouds.openstack.keystone.catalog.ServiceEndpoint.Interface.INTERNAL;
import static org.jclouds.openstack.keystone.catalog.ServiceEndpoint.Interface.PUBLIC;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.inject.Singleton;
import org.jclouds.openstack.keystone.catalog.ServiceEndpoint;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
@Singleton
public class PublicURLOrInternal extends BaseEndpointResolutionStrategy {
@Override
public Supplier<URI> apply(Collection<ServiceEndpoint> input) {
List<ServiceEndpoint> publicEndpointsFirst = new ArrayList<ServiceEndpoint>(input);
Collections.sort(publicEndpointsFirst, PublicInterfacesFirst);
return super.apply(publicEndpointsFirst);
}
@Override
protected Predicate<ServiceEndpoint> filter() {
return or(withIface(PUBLIC), withIface(INTERNAL));
}
private static final Comparator<ServiceEndpoint> PublicInterfacesFirst = new Comparator<ServiceEndpoint>() {
@Override
public int compare(ServiceEndpoint left, ServiceEndpoint right) {
// We only care about public interfaces, since the collection will be
// filtered only by public or internal ones
if (PUBLIC.equals(left.iface())) {
return -1;
} else if (PUBLIC.equals(right.iface())) {
return 1;
} else {
return 0;
}
};
};
}

View File

@ -14,27 +14,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.functions;
import static com.google.common.base.Preconditions.checkNotNull;
package org.jclouds.openstack.keystone.catalog.functions;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.location.Provider;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import org.jclouds.openstack.keystone.catalog.ServiceEndpoint;
@Singleton
public class ReturnRegionOrProvider implements EndpointToRegion {
private String provider;
public class ReturnRegionOrProvider implements ServiceEndpointToRegion {
private final String provider;
@Inject
ReturnRegionOrProvider(@Provider String provider) {
this.provider = checkNotNull(provider, "provider");
this.provider = provider;
}
@Override
public String apply(Endpoint input) {
return input.getRegion() != null ? input.getRegion() : provider;
public String apply(ServiceEndpoint input) {
return input.regionId() != null ? input.regionId() : provider;
}
}

View File

@ -14,30 +14,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.functions;
package org.jclouds.openstack.keystone.catalog.functions;
import java.net.URI;
import java.util.Collection;
import javax.inject.Singleton;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import org.jclouds.openstack.keystone.catalog.ServiceEndpoint;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.inject.ImplementedBy;
/**
* Select internal URL endpoints services
*
* Given a sets of endpoints for a particular service and version, return the
* URL to be used to connect to the service.
*/
@Singleton
public class InternalURL implements EndpointToSupplierURI {
@Override
public Supplier<URI> apply(Endpoint input) {
return Suppliers.ofInstance(input.getInternalURL());
}
@ImplementedBy(PublicURLOrInternal.class)
public interface ServiceEndpointResolutionStrategy extends Function<Collection<ServiceEndpoint>, Supplier<URI>> {
@Override
public String toString() {
return "supplyInternalURL()";
}
}

View File

@ -14,14 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.functions;
package org.jclouds.openstack.keystone.catalog.functions;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import org.jclouds.openstack.keystone.catalog.ServiceEndpoint;
import com.google.common.base.Function;
import com.google.inject.ImplementedBy;
@ImplementedBy(ReturnRegionOrProvider.class)
public interface EndpointToRegion extends Function<Endpoint, String> {
public interface ServiceEndpointToRegion extends Function<ServiceEndpoint, String> {
}

View File

@ -0,0 +1,133 @@
/*
* 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.suppliers;
import static com.google.common.collect.Iterables.any;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.isEmpty;
import static com.google.common.collect.Maps.transformValues;
import static com.google.common.collect.Multimaps.asMap;
import static com.google.common.collect.Multimaps.index;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import javax.annotation.Resource;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.logging.Logger;
import org.jclouds.openstack.keystone.catalog.ServiceEndpoint;
import org.jclouds.openstack.keystone.catalog.functions.ServiceEndpointResolutionStrategy;
import org.jclouds.openstack.keystone.catalog.functions.ServiceEndpointToRegion;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Supplier;
import com.google.common.collect.Multimap;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
public class LocationIdToURIFromServiceEndpointsForTypeAndVersion implements Supplier<Map<String, Supplier<URI>>> {
public interface Factory {
LocationIdToURIFromServiceEndpointsForTypeAndVersion createForApiTypeAndVersion(@Assisted("apiType") String apiType,
@Nullable @Assisted("apiVersion") String apiVersion) throws NoSuchElementException;
}
@Resource
protected Logger logger = Logger.NULL;
protected final Supplier<List<ServiceEndpoint>> serviceEndpoints;
protected final ServiceEndpointResolutionStrategy resolveServiceEndpointURI;
protected final ServiceEndpointToRegion serviceEndpointToRegion;
protected final String apiType;
protected final String apiVersion;
@Inject
LocationIdToURIFromServiceEndpointsForTypeAndVersion(Supplier<List<ServiceEndpoint>> serviceEndpoints,
ServiceEndpointResolutionStrategy resolveServiceEndpointURI, ServiceEndpointToRegion serviceEndpointToRegion,
@Assisted("apiType") String apiType, @Nullable @Assisted("apiVersion") String apiVersion) {
this.serviceEndpoints = serviceEndpoints;
this.resolveServiceEndpointURI = resolveServiceEndpointURI;
this.serviceEndpointToRegion = serviceEndpointToRegion;
this.apiType = apiType;
this.apiVersion = apiVersion;
}
@Override
public Map<String, Supplier<URI>> get() {
List<ServiceEndpoint> endpoints = serviceEndpoints.get();
if (endpoints.isEmpty()) {
throw new NoSuchElementException(
"No endpoints were found in the service catalog. Make sure your authentication token has the right scopes and permissions");
}
// Filter endpoints by service type
Iterable<ServiceEndpoint> endpointsForType = filter(endpoints, apiTypeEquals);
if (isEmpty(endpointsForType)) {
throw new NoSuchElementException(String.format("no endpoints for apiType %s in service endpoints %s", apiType,
endpoints));
}
// Check if there are endpoints for a particular version, if specified and
// there are versioned endpoints
boolean checkVersionId = apiVersion != null && any(endpointsForType, versionAware);
Predicate<ServiceEndpoint> versionFilter = checkVersionId ? apiVersionEqualsVersionId : Predicates.<ServiceEndpoint> alwaysTrue();
Iterable<ServiceEndpoint> endpointsForTypeAndVersion = filter(endpointsForType, versionFilter);
if (isEmpty(endpointsForTypeAndVersion)) {
throw new NoSuchElementException(String.format(
"no service endpoints for apiType %s are of version %s, or version agnostic: %s", apiType, apiVersion,
endpointsForType));
}
logger.debug("service endpoints for apiType %s and version %s: %s", apiType, apiVersion,
endpointsForTypeAndVersion);
Multimap<String, ServiceEndpoint> locationToServiceEndpoints = index(endpointsForTypeAndVersion,
serviceEndpointToRegion);
return transformValues(asMap(locationToServiceEndpoints), resolveServiceEndpointURI);
}
private final Predicate<ServiceEndpoint> apiVersionEqualsVersionId = new Predicate<ServiceEndpoint>() {
@Override
public boolean apply(ServiceEndpoint input) {
return input.version().equals(apiVersion);
}
};
private final Predicate<ServiceEndpoint> versionAware = new Predicate<ServiceEndpoint>() {
@Override
public boolean apply(ServiceEndpoint input) {
return input.version() != null;
}
};
private final Predicate<ServiceEndpoint> apiTypeEquals = new Predicate<ServiceEndpoint>() {
@Override
public boolean apply(ServiceEndpoint input) {
return input.type().equals(apiType);
}
};
@Override
public String toString() {
return "locationIdToURIFromServiceEndpointsForTypeAndVersion(" + apiType + ", " + apiVersion + ")";
}
}

View File

@ -0,0 +1,44 @@
/*
* 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.suppliers;
import java.util.List;
import javax.inject.Inject;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.keystone.catalog.ServiceEndpoint;
import org.jclouds.openstack.keystone.catalog.functions.AdminEndpointResolutionStrategy;
import org.jclouds.openstack.keystone.catalog.functions.ServiceEndpointToRegion;
import com.google.common.base.Supplier;
import com.google.inject.assistedinject.Assisted;
public class RegionIdToAdminURIFromServiceEndpointsForTypeAndVersion extends LocationIdToURIFromServiceEndpointsForTypeAndVersion implements
RegionIdToAdminURISupplier {
@Inject
public RegionIdToAdminURIFromServiceEndpointsForTypeAndVersion(Supplier<List<ServiceEndpoint>> serviceEndpoints,
AdminEndpointResolutionStrategy resolveServiceEndpointURI, ServiceEndpointToRegion serviceEndpointToRegion,
@Assisted("apiType") String apiType, @Nullable @Assisted("apiVersion") String apiVersion) {
super(serviceEndpoints, resolveServiceEndpointURI, serviceEndpointToRegion, apiType, apiVersion);
}
@Override
public String toString() {
return "regionIdToAdminURIFromServiceEndpointsForTypeAndVersion(" + apiType + ", " + apiVersion + ")";
}
}

View File

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.suppliers;
package org.jclouds.openstack.keystone.catalog.suppliers;
import java.net.URI;
import java.util.Map;
@ -26,19 +26,11 @@ import com.google.common.base.Supplier;
import com.google.inject.ImplementedBy;
import com.google.inject.assistedinject.Assisted;
@ImplementedBy(RegionIdToAdminURIFromAccessForTypeAndVersion.class)
@ImplementedBy(RegionIdToAdminURIFromServiceEndpointsForTypeAndVersion.class)
public interface RegionIdToAdminURISupplier extends Supplier<Map<String, Supplier<URI>>> {
interface Factory {
/**
*
* @param apiType
* type of the api, according to the provider. ex. {@code compute}
* {@code object-store}
* @param apiVersion
* version of the api, or null
* @return regions mapped to default uri
* @throws NoSuchElementException if the {@code apiType} is not present in the catalog
*/
RegionIdToAdminURISupplier createForApiTypeAndVersion(@Assisted("apiType") String apiType,
@Nullable @Assisted("apiVersion") String apiVersion) throws NoSuchElementException;
}

View File

@ -14,27 +14,29 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.suppliers;
package org.jclouds.openstack.keystone.catalog.suppliers;
import java.util.List;
import javax.inject.Inject;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.location.suppliers.RegionIdToURISupplier;
import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.v2_0.functions.EndpointToRegion;
import org.jclouds.openstack.keystone.v2_0.functions.EndpointToSupplierURI;
import org.jclouds.openstack.keystone.catalog.ServiceEndpoint;
import org.jclouds.openstack.keystone.catalog.functions.ServiceEndpointResolutionStrategy;
import org.jclouds.openstack.keystone.catalog.functions.ServiceEndpointToRegion;
import com.google.common.base.Supplier;
import com.google.inject.assistedinject.Assisted;
public class RegionIdToURIFromAccessForTypeAndVersion extends LocationIdToURIFromAccessForTypeAndVersion implements
public class RegionIdToURIFromServiceEndpointsForTypeAndVersion extends LocationIdToURIFromServiceEndpointsForTypeAndVersion implements
RegionIdToURISupplier {
@Inject
public RegionIdToURIFromAccessForTypeAndVersion(Supplier<Access> access,
EndpointToSupplierURI endpointToSupplierURI, EndpointToRegion endpointToRegion,
public RegionIdToURIFromServiceEndpointsForTypeAndVersion(Supplier<List<ServiceEndpoint>> serviceEndpoints,
ServiceEndpointResolutionStrategy resolveServiceEndpointURI, ServiceEndpointToRegion serviceEndpointToRegion,
@Assisted("apiType") String apiType, @Nullable @Assisted("apiVersion") String apiVersion) {
super(access, endpointToSupplierURI, endpointToRegion, apiType, apiVersion);
super(serviceEndpoints, resolveServiceEndpointURI, serviceEndpointToRegion, apiType, apiVersion);
}
@Override

View File

@ -14,7 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.config;
package org.jclouds.openstack.keystone.config;
import org.jclouds.openstack.keystone.auth.config.CredentialTypes;
import org.jclouds.rest.annotations.SinceApiVersion;
/**
* Configuration properties and constants used in Keystone connections.
@ -28,6 +31,7 @@ public final class KeystoneProperties {
* <ul>
* <li>apiAccessKeyCredentials</li>
* <li>passwordCredentials</li>
* <li>tokenCredentials</li>
* </ul>
*
* @see CredentialTypes
@ -62,6 +66,20 @@ public final class KeystoneProperties {
*/
public static final String REQUIRES_TENANT = "jclouds.keystone.requires-tenant";
/**
* set this property to specify for scoped authentication.
* <p>
* The format is one of the following:
* <ul>
* <li>project:<project-id></li>
* <li>domain:<domain-name></li>
* <li></li>
* </ul>
* For example: <code>project:457841231597451534</code>
*/
@SinceApiVersion("3")
public static final String SCOPE = "jclouds.keystone.scope";
/**
* type of the keystone service. ex. {@code compute}
*
@ -69,6 +87,11 @@ public final class KeystoneProperties {
*/
public static final String SERVICE_TYPE = "jclouds.keystone.service-type";
/**
* Version of keystone to be used by services. Default: 3.
*/
public static final String KEYSTONE_VERSION = "jclouds.keystone.version";
private KeystoneProperties() {
throw new AssertionError("intentionally unimplemented");
}

View File

@ -16,18 +16,19 @@
*/
package org.jclouds.openstack.keystone.v2_0;
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.KEYSTONE_VERSION;
import static org.jclouds.openstack.keystone.config.KeystoneProperties.SERVICE_TYPE;
import java.net.URI;
import java.util.Properties;
import org.jclouds.apis.ApiMetadata;
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.auth.config.AuthenticationModule;
import org.jclouds.openstack.keystone.auth.config.CredentialTypes;
import org.jclouds.openstack.keystone.catalog.config.KeystoneAdminURLModule;
import org.jclouds.openstack.keystone.catalog.config.ServiceCatalogModule;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneHttpApiModule;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneHttpApiModule.KeystoneAdminURLModule;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneParserModule;
import org.jclouds.openstack.v2_0.ServiceType;
import org.jclouds.rest.internal.BaseHttpApiMetadata;
@ -59,6 +60,7 @@ public class KeystoneApiMetadata extends BaseHttpApiMetadata<KeystoneApi> {
Properties properties = BaseHttpApiMetadata.defaultProperties();
properties.setProperty(CREDENTIAL_TYPE, CredentialTypes.PASSWORD_CREDENTIALS);
properties.setProperty(SERVICE_TYPE, ServiceType.IDENTITY);
properties.setProperty(KEYSTONE_VERSION, "2");
return properties;
}
@ -75,8 +77,8 @@ public class KeystoneApiMetadata extends BaseHttpApiMetadata<KeystoneApi> {
.defaultEndpoint("http://localhost:5000/v${jclouds.api-version}/")
.defaultProperties(KeystoneApiMetadata.defaultProperties())
.defaultModules(ImmutableSet.<Class<? extends Module>>builder()
.add(AuthenticationApiModule.class)
.add(KeystoneAuthenticationModule.class)
.add(AuthenticationModule.class)
.add(ServiceCatalogModule.class)
.add(KeystoneAdminURLModule.class)
.add(KeystoneParserModule.class)
.add(KeystoneHttpApiModule.class).build());

View File

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0;
package org.jclouds.openstack.keystone.v2_0.auth;
import java.io.Closeable;
@ -23,13 +23,13 @@ import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.keystone.auth.AuthenticationApi;
import org.jclouds.openstack.keystone.auth.domain.ApiAccessKeyCredentials;
import org.jclouds.openstack.keystone.auth.domain.PasswordCredentials;
import org.jclouds.openstack.keystone.auth.domain.TenantOrDomainAndCredentials;
import org.jclouds.openstack.keystone.v2_0.binders.BindAuthToJsonPayload;
import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.v2_0.domain.ApiAccessKeyCredentials;
import org.jclouds.openstack.keystone.v2_0.domain.PasswordCredentials;
import org.jclouds.rest.annotations.MapBinder;
import org.jclouds.rest.annotations.PayloadParam;
import org.jclouds.rest.annotations.SelectJson;
import com.google.inject.name.Named;
@ -39,7 +39,7 @@ import com.google.inject.name.Named;
*/
@Consumes(MediaType.APPLICATION_JSON)
@Path("/tokens")
public interface AuthenticationApi extends Closeable {
public interface V2AuthenticationApi extends AuthenticationApi, Closeable {
/**
* Authenticate to generate a token.
@ -50,8 +50,8 @@ public interface AuthenticationApi extends Closeable {
@POST
@SelectJson("access")
@MapBinder(BindAuthToJsonPayload.class)
Access authenticateWithTenantNameAndCredentials(@Nullable @PayloadParam("tenantName") String tenantName,
PasswordCredentials passwordCredentials);
@Override
Access authenticatePassword(TenantOrDomainAndCredentials<PasswordCredentials> credentials);
/**
* Authenticate to generate a token.
@ -62,30 +62,7 @@ public interface AuthenticationApi extends Closeable {
@POST
@SelectJson("access")
@MapBinder(BindAuthToJsonPayload.class)
Access authenticateWithTenantIdAndCredentials(@Nullable @PayloadParam("tenantId") String tenantId,
PasswordCredentials passwordCredentials);
@Override
Access authenticateAccessKey(TenantOrDomainAndCredentials<ApiAccessKeyCredentials> credentials);
/**
* Authenticate to generate a token.
*
* @return access with token
*/
@Named("authenticate")
@POST
@SelectJson("access")
@MapBinder(BindAuthToJsonPayload.class)
Access authenticateWithTenantNameAndCredentials(@Nullable @PayloadParam("tenantName") String tenantName,
ApiAccessKeyCredentials apiAccessKeyCredentials);
/**
* Authenticate to generate a token.
*
* @return access with token
*/
@Named("authenticate")
@POST
@SelectJson("access")
@MapBinder(BindAuthToJsonPayload.class)
Access authenticateWithTenantIdAndCredentials(@Nullable @PayloadParam("tenantId") String tenantId,
ApiAccessKeyCredentials apiAccessKeyCredentials);
}

View File

@ -16,24 +16,29 @@
*/
package org.jclouds.openstack.keystone.v2_0.binders;
import com.google.common.base.Predicates;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.Iterables;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.instanceOf;
import static com.google.common.collect.Iterables.tryFind;
import static org.jclouds.openstack.keystone.auth.config.CredentialTypes.findCredentialType;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.http.HttpRequest;
import org.jclouds.json.Json;
import org.jclouds.openstack.keystone.v2_0.config.CredentialType;
import org.jclouds.openstack.keystone.auth.config.CredentialType;
import org.jclouds.openstack.keystone.auth.domain.TenantOrDomainAndCredentials;
import org.jclouds.rest.MapBinder;
import org.jclouds.rest.binders.BindToJsonPayload;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.Map;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
@Singleton
public class BindAuthToJsonPayload extends BindToJsonPayload implements MapBinder {
@ -42,12 +47,9 @@ public class BindAuthToJsonPayload extends BindToJsonPayload implements MapBinde
super(jsonBinder);
}
protected void addCredentialsInArgsOrNull(GeneratedHttpRequest gRequest, Builder<String, Object> builder) {
for (Object arg : Iterables.filter(gRequest.getInvocation().getArgs(), Predicates.notNull())) {
if (arg.getClass().isAnnotationPresent(CredentialType.class)) {
builder.put(arg.getClass().getAnnotation(CredentialType.class).value(), arg);
}
}
protected TenantOrDomainAndCredentials<?> findCredentialsInArgs(GeneratedHttpRequest gRequest) {
Optional<Object> credentials = tryFind(gRequest.getInvocation().getArgs(), instanceOf(TenantOrDomainAndCredentials.class));
return credentials.isPresent() ? (TenantOrDomainAndCredentials<?>) credentials.get() : null;
}
@Override
@ -55,15 +57,25 @@ public class BindAuthToJsonPayload extends BindToJsonPayload implements MapBinde
checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest,
"this binder is only valid for GeneratedHttpRequests!");
GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request;
Builder<String, Object> builder = ImmutableMap.builder();
addCredentialsInArgsOrNull(gRequest, builder);
// TODO: is tenantName permanent? or should we switch to tenantId at some point. seems most tools
// still use tenantName
if (!Strings.isNullOrEmpty((String) postParams.get("tenantName")))
builder.put("tenantName", postParams.get("tenantName"));
else if (!Strings.isNullOrEmpty((String) postParams.get("tenantId")))
builder.put("tenantId", postParams.get("tenantId"));
TenantOrDomainAndCredentials<?> credentials = findCredentialsInArgs(gRequest);
if (credentials != null) {
CredentialType credentialType = findCredentialType(credentials.credentials().getClass());
checkArgument(credentialType != null, "the given credentials must be annotated with @CredentialType");
builder.put(credentialType.value(), credentials.credentials());
// TODO: is tenantName permanent? or should we switch to tenantId at
// some point. seems most tools still use tenantName
if (credentials != null) {
if (!Strings.isNullOrEmpty(credentials.tenantOrDomainId()))
builder.put("tenantId", credentials.tenantOrDomainId());
else if (!Strings.isNullOrEmpty(credentials.tenantOrDomainName()))
builder.put("tenantName", credentials.tenantOrDomainName());
}
}
R authRequest = super.bindToRequest(request, ImmutableMap.of("auth", builder.build()));
authRequest.getPayload().setSensitive(true);
return authRequest;

View File

@ -0,0 +1,105 @@
/*
* 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.v2_0.catalog;
import static org.jclouds.openstack.keystone.catalog.ServiceEndpoint.Interface.ADMIN;
import static org.jclouds.openstack.keystone.catalog.ServiceEndpoint.Interface.INTERNAL;
import static org.jclouds.openstack.keystone.catalog.ServiceEndpoint.Interface.PUBLIC;
import java.net.URI;
import java.util.List;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.logging.Logger;
import org.jclouds.openstack.keystone.auth.domain.AuthInfo;
import org.jclouds.openstack.keystone.catalog.ServiceEndpoint;
import org.jclouds.openstack.keystone.catalog.ServiceEndpoint.Interface;
import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import org.jclouds.openstack.keystone.v2_0.domain.Service;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
@Singleton
public class V2ServiceCatalog implements Supplier<List<ServiceEndpoint>> {
@Resource
private Logger logger = Logger.NULL;
private final Supplier<AuthInfo> authInfo;
@Inject
V2ServiceCatalog(Supplier<AuthInfo> authInfo) {
this.authInfo = authInfo;
}
@Override
public List<ServiceEndpoint> get() {
Access access = (Access) authInfo.get();
ImmutableList.Builder<ServiceEndpoint> serviceEndpoints = ImmutableList.builder();
for (Service service : access) {
for (Endpoint endpoint : service) {
if (endpoint.getAdminURL() != null) {
serviceEndpoints.add(toServiceEndpoint(service.getType(), ADMIN).apply(endpoint));
}
if (endpoint.getInternalURL() != null) {
serviceEndpoints.add(toServiceEndpoint(service.getType(), INTERNAL).apply(endpoint));
}
if (endpoint.getPublicURL() != null) {
serviceEndpoints.add(toServiceEndpoint(service.getType(), PUBLIC).apply(endpoint));
}
}
}
return serviceEndpoints.build();
}
private Function<Endpoint, ServiceEndpoint> toServiceEndpoint(final String type, final Interface iface) {
return new Function<Endpoint, ServiceEndpoint>() {
@Override
public ServiceEndpoint apply(Endpoint input) {
ServiceEndpoint.Builder builder = ServiceEndpoint.builder().id(input.getId()).iface(iface)
.regionId(input.getRegion()).type(type).version(input.getVersionId());
switch (iface) {
case ADMIN:
builder.url(input.getAdminURL());
break;
case INTERNAL:
builder.url(input.getInternalURL());
break;
case PUBLIC:
builder.url(input.getPublicURL());
break;
case UNRECOGNIZED:
URI url = input.getPublicURL() != null ? input.getPublicURL() : input.getInternalURL();
logger.warn("Unrecognized endpoint interface for %s. Using URL: %s", input, url);
builder.url(url);
break;
}
return builder.build();
}
};
}
}

View File

@ -1,257 +0,0 @@
/*
* 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.v2_0.config;
import static com.google.common.base.Preconditions.checkArgument;
import static org.jclouds.util.Suppliers2.getLastValueInMap;
import java.net.URI;
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.location.suppliers.ImplicitLocationSupplier;
import org.jclouds.location.suppliers.LocationsSupplier;
import org.jclouds.location.suppliers.RegionIdToURISupplier;
import org.jclouds.location.suppliers.RegionIdsSupplier;
import org.jclouds.location.suppliers.ZoneIdToURISupplier;
import org.jclouds.location.suppliers.ZoneIdsSupplier;
import org.jclouds.location.suppliers.all.RegionToProvider;
import org.jclouds.location.suppliers.all.ZoneToProvider;
import org.jclouds.location.suppliers.derived.RegionIdsFromRegionIdToURIKeySet;
import org.jclouds.location.suppliers.derived.ZoneIdsFromZoneIdToURIKeySet;
import org.jclouds.location.suppliers.implicit.FirstRegion;
import org.jclouds.location.suppliers.implicit.FirstZone;
import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import org.jclouds.openstack.keystone.v2_0.functions.AuthenticateApiAccessKeyCredentials;
import org.jclouds.openstack.keystone.v2_0.functions.AuthenticatePasswordCredentials;
import org.jclouds.openstack.keystone.v2_0.handlers.RetryOnRenew;
import org.jclouds.openstack.keystone.v2_0.suppliers.LocationIdToURIFromAccessForTypeAndVersion;
import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToAdminURIFromAccessForTypeAndVersion;
import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToAdminURISupplier;
import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToURIFromAccessForTypeAndVersion;
import org.jclouds.openstack.keystone.v2_0.suppliers.ZoneIdToURIFromAccessForTypeAndVersion;
import org.jclouds.rest.annotations.ApiVersion;
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.inject.AbstractModule;
import com.google.inject.Injector;
import com.google.inject.Provides;
import com.google.inject.Scopes;
import com.google.inject.assistedinject.FactoryModuleBuilder;
public class KeystoneAuthenticationModule extends AbstractModule {
/**
* For global services who have no regions, such as DNS. To use, do the following
* <ol>
* <li>add this module to your {@link org.jclouds.apis.ApiMetadata#getDefaultModules()}</li>
* <li>create a service-specific annotation, such as {@code @CloudDNS}, and make sure that has the meta-annotation
* {@link javax.inject.Qualifier}</li>
* <li>add the above annotation to any {@code Api} classes by placing it on the type. ex.
* {@code @Endpoint(CloudDNS.class)}</li>
* <li>add the following to your {@link org.jclouds.rest.config.RestClientModule}</li>
*
* <pre>
* bind(new TypeLiteral&lt;Supplier&lt;URI&gt;&gt;() {
* }).annotatedWith(CloudDNS.class).to(new TypeLiteral&lt;Supplier&lt;URI&gt;&gt;() {
* });
* </pre>
*/
public static class ProviderModule extends AbstractModule {
@Override
protected void configure() {
install(new FactoryModuleBuilder().build(LocationIdToURIFromAccessForTypeAndVersion.Factory.class));
}
@Provides
@Singleton
protected final Supplier<URI> provideZoneIdToURISupplierForApiVersion(
@Named(KeystoneProperties.SERVICE_TYPE) String serviceType, @ApiVersion String apiVersion,
LocationIdToURIFromAccessForTypeAndVersion.Factory factory) {
return getLastValueInMap(factory.createForApiTypeAndVersion(serviceType, apiVersion));
}
@Provides
@Singleton
final Function<Endpoint, String> provideProvider(@Provider final String provider) {
return new Function<Endpoint, String>() {
@Override
public String apply(Endpoint in) {
return provider;
}
};
}
}
public static class RegionModule extends AbstractModule {
@Override
protected void configure() {
install(new FactoryModuleBuilder().implement(RegionIdToURISupplier.class,
RegionIdToURIFromAccessForTypeAndVersion.class).build(RegionIdToURISupplier.Factory.class));
install(new FactoryModuleBuilder().implement(RegionIdToAdminURISupplier.class,
RegionIdToAdminURIFromAccessForTypeAndVersion.class).build(RegionIdToAdminURISupplier.Factory.class));
// dynamically build the region list as opposed to from properties
bind(RegionIdsSupplier.class).to(RegionIdsFromRegionIdToURIKeySet.class);
bind(ImplicitLocationSupplier.class).to(FirstRegion.class).in(Scopes.SINGLETON);
bind(LocationsSupplier.class).to(RegionToProvider.class).in(Scopes.SINGLETON);
}
@Provides
@Singleton
protected final RegionIdToURISupplier guiceProvideRegionIdToURISupplierForApiVersion(
@Named(KeystoneProperties.SERVICE_TYPE) String serviceType, @ApiVersion String apiVersion,
RegionIdToURISupplier.Factory factory) {
return provideRegionIdToURISupplierForApiVersion(serviceType, apiVersion, factory);
}
// supply the region to id map from keystone, based on the servicetype and api version in
// config
protected RegionIdToURISupplier provideRegionIdToURISupplierForApiVersion(
@Named(KeystoneProperties.SERVICE_TYPE) String serviceType, @ApiVersion String apiVersion,
RegionIdToURISupplier.Factory factory) {
return factory.createForApiTypeAndVersion(serviceType, apiVersion);
}
@Provides
@Singleton
protected final RegionIdToAdminURISupplier guiceProvideRegionIdToAdminURISupplierForApiVersion(
@Named(KeystoneProperties.SERVICE_TYPE) String serviceType, @ApiVersion String apiVersion,
RegionIdToAdminURISupplier.Factory factory) {
return provideRegionIdToAdminURISupplierForApiVersion(serviceType, apiVersion, factory);
}
// supply the region to id to AdminURL map from keystone, based on the servicetype and api
// version in
// config
protected RegionIdToAdminURISupplier provideRegionIdToAdminURISupplierForApiVersion(
@Named(KeystoneProperties.SERVICE_TYPE) String serviceType, @ApiVersion String apiVersion,
RegionIdToAdminURISupplier.Factory factory) {
return factory.createForApiTypeAndVersion(serviceType, apiVersion);
}
}
/**
* @deprecated All OpenStack APIs rely on regions in jclouds 2.0. To be removed in jclouds 2.0.
*/
@Deprecated
public static class ZoneModule extends AbstractModule {
@Override
protected void configure() {
install(new FactoryModuleBuilder().implement(ZoneIdToURISupplier.class,
ZoneIdToURIFromAccessForTypeAndVersion.class).build(ZoneIdToURISupplier.Factory.class));
// dynamically build the zone list as opposed to from properties
bind(ZoneIdsSupplier.class).to(ZoneIdsFromZoneIdToURIKeySet.class);
bind(ImplicitLocationSupplier.class).to(FirstZone.class).in(Scopes.SINGLETON);
bind(LocationsSupplier.class).to(ZoneToProvider.class).in(Scopes.SINGLETON);
}
// supply the zone to id map from keystone, based on the servicetype and api version in
// config
@Provides
@Singleton
protected final ZoneIdToURISupplier provideZoneIdToURISupplierForApiVersion(
@Named(KeystoneProperties.SERVICE_TYPE) String serviceType, @ApiVersion String apiVersion,
ZoneIdToURISupplier.Factory factory) {
return factory.createForApiTypeAndVersion(serviceType, apiVersion);
}
}
@Override
protected void configure() {
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(RetryOnRenew.class);
}
/**
* borrowing concurrency code to ensure that caching takes place properly
*/
@Provides
@Singleton
@Authentication
protected final Supplier<String> provideAuthenticationTokenCache(final Supplier<Access> supplier)
throws InterruptedException, ExecutionException, TimeoutException {
return new Supplier<String>() {
@Override
public String get() {
return supplier.get().getToken().getId();
}
};
}
@Provides
@Singleton
protected final Map<String, Function<Credentials, Access>> provideAuthenticationMethods(Injector i) {
return authenticationMethods(i);
}
protected Map<String, Function<Credentials, Access>> authenticationMethods(Injector i) {
Builder<Function<Credentials, Access>> fns = ImmutableSet.<Function<Credentials, Access>> builder();
fns.add(i.getInstance(AuthenticatePasswordCredentials.class));
fns.add(i.getInstance(AuthenticateApiAccessKeyCredentials.class));
return CredentialTypes.indexByCredentialType(fns.build());
}
@Provides
@Singleton
protected final Function<Credentials, Access> authenticationMethodForCredentialType(
@Named(KeystoneProperties.CREDENTIAL_TYPE) String credentialType,
Map<String, Function<Credentials, Access>> 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, Access> provideAccessCache(Function<Credentials, Access> 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<Access> provideAccessSupplier(final LoadingCache<Credentials, Access> cache,
@Provider final Supplier<Credentials> creds) {
return new Supplier<Access>() {
@Override
public Access get() {
return cache.getUnchecked(creds.get());
}
};
}
}

View File

@ -16,10 +16,7 @@
*/
package org.jclouds.openstack.keystone.v2_0.config;
import static org.jclouds.util.Suppliers2.getLastValueInMap;
import java.net.URI;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@ -29,30 +26,21 @@ import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection;
import org.jclouds.http.annotation.ServerError;
import org.jclouds.location.Provider;
import org.jclouds.openstack.keystone.v2_0.KeystoneApi;
import org.jclouds.openstack.keystone.v2_0.handlers.KeystoneErrorHandler;
import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToAdminURIFromAccessForTypeAndVersion;
import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToAdminURISupplier;
import org.jclouds.openstack.v2_0.ServiceType;
import org.jclouds.openstack.v2_0.domain.Extension;
import org.jclouds.openstack.v2_0.functions.PresentWhenExtensionAnnotationMatchesExtensionSet;
import org.jclouds.openstack.v2_0.services.Identity;
import org.jclouds.rest.ConfiguresHttpApi;
import org.jclouds.rest.annotations.ApiVersion;
import org.jclouds.rest.config.HttpApiModule;
import org.jclouds.rest.functions.ImplicitOptionalConverter;
import org.jclouds.util.Suppliers2;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.inject.AbstractModule;
import com.google.inject.Binder;
import com.google.inject.Provides;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import com.google.inject.multibindings.MapBinder;
/**
@ -64,33 +52,6 @@ public class KeystoneHttpApiModule extends HttpApiModule<KeystoneApi> {
public KeystoneHttpApiModule() {
}
public static 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> provideStorageUrl(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;
}
}
// Allow providers to cleanly contribute their own aliases
public static MapBinder<URI, URI> namespaceAliasBinder(Binder binder) {
return MapBinder.newMapBinder(binder, URI.class, URI.class, NamespaceAliases.class).permitDuplicates();

View File

@ -22,6 +22,7 @@ import java.beans.ConstructorProperties;
import java.util.Set;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.keystone.auth.domain.AuthInfo;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
@ -36,7 +37,7 @@ import com.google.common.collect.ImmutableSet;
* "http://docs.openstack.org/api/openstack-identity-service/2.0/content/Identity-Service-Concepts-e1362.html"
* />
*/
public class Access extends ForwardingSet<Service> implements Comparable<Access> {
public class Access extends ForwardingSet<Service> implements Comparable<Access>, AuthInfo {
public static Builder<?> builder() {
return new ConcreteBuilder();
@ -166,4 +167,9 @@ public class Access extends ForwardingSet<Service> implements Comparable<Access>
return serviceCatalog;
}
@Override
public String getAuthToken() {
return token.getId();
}
}

View File

@ -1,140 +0,0 @@
/*
* 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.v2_0.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import java.beans.ConstructorProperties;
import org.jclouds.openstack.keystone.v2_0.config.CredentialType;
import org.jclouds.openstack.keystone.v2_0.config.CredentialTypes;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.base.MoreObjects.ToStringHelper;
/**
* Api AccessKey Credentials
*
* @see <a href="http://docs.openstack.org/api/openstack-identity-service/2.0/content/POST_authenticate_v2.0_tokens_Service_API_Api_Operations.html#d662e583"
/>
*/
@CredentialType(CredentialTypes.API_ACCESS_KEY_CREDENTIALS)
public class ApiAccessKeyCredentials {
public static Builder<?> builder() {
return new ConcreteBuilder();
}
public Builder<?> toBuilder() {
return new ConcreteBuilder().fromApiAccessKeyCredentials(this);
}
public static ApiAccessKeyCredentials createWithAccessKeyAndSecretKey(String accessKey, String secretKey) {
return new ApiAccessKeyCredentials(accessKey, secretKey);
}
public abstract static class Builder<T extends Builder<T>> {
protected abstract T self();
protected String accessKey;
protected String secretKey;
/**
* @see ApiAccessKeyCredentials#getAccessKey()
*/
public T accessKey(String accessKey) {
this.accessKey = accessKey;
return self();
}
/**
* @see ApiAccessKeyCredentials#getSecretKey()
*/
public T secretKey(String secretKey) {
this.secretKey = secretKey;
return self();
}
public ApiAccessKeyCredentials build() {
return new ApiAccessKeyCredentials(accessKey, secretKey);
}
public T fromApiAccessKeyCredentials(ApiAccessKeyCredentials in) {
return this
.accessKey(in.getAccessKey())
.secretKey(in.getSecretKey());
}
}
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
@Override
protected ConcreteBuilder self() {
return this;
}
}
private final String accessKey;
private final String secretKey;
@ConstructorProperties({
"accessKey", "secretKey"
})
protected ApiAccessKeyCredentials(String accessKey, String secretKey) {
this.accessKey = checkNotNull(accessKey, "accessKey");
this.secretKey = checkNotNull(secretKey, "secretKey");
}
/**
* @return the accessKey
*/
public String getAccessKey() {
return this.accessKey;
}
/**
* @return the secretKey
*/
public String getSecretKey() {
return this.secretKey;
}
@Override
public int hashCode() {
return Objects.hashCode(accessKey, secretKey);
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
ApiAccessKeyCredentials that = ApiAccessKeyCredentials.class.cast(obj);
return Objects.equal(this.accessKey, that.accessKey)
&& Objects.equal(this.secretKey, that.secretKey);
}
protected ToStringHelper string() {
return MoreObjects.toStringHelper(this)
.add("accessKey", accessKey).add("secretKey", secretKey);
}
@Override
public String toString() {
return string().toString();
}
}

View File

@ -22,8 +22,8 @@ import java.net.URI;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.base.MoreObjects.ToStringHelper;
import com.google.common.base.Objects;
/**
* An network-accessible address, usually described by URL, where a service may

View File

@ -1,140 +0,0 @@
/*
* 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.v2_0.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import java.beans.ConstructorProperties;
import org.jclouds.openstack.keystone.v2_0.config.CredentialType;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.base.MoreObjects.ToStringHelper;
/**
* Password Credentials
*
* @see <a href="http://docs.openstack.org/api/openstack-identity-service/2.0/content/POST_authenticate_v2.0_tokens_Service_API_Api_Operations.html#d662e583"
/>
*/
@CredentialType("passwordCredentials")
public class PasswordCredentials {
public static Builder<?> builder() {
return new ConcreteBuilder();
}
public Builder<?> toBuilder() {
return new ConcreteBuilder().fromPasswordCredentials(this);
}
public static PasswordCredentials createWithUsernameAndPassword(String username, String password) {
return new PasswordCredentials(username, password);
}
public abstract static class Builder<T extends Builder<T>> {
protected abstract T self();
protected String username;
protected String password;
/**
* @see PasswordCredentials#getUsername()
*/
public T username(String username) {
this.username = username;
return self();
}
/**
* @see PasswordCredentials#getPassword()
*/
public T password(String password) {
this.password = password;
return self();
}
public PasswordCredentials build() {
return new PasswordCredentials(username, password);
}
public T fromPasswordCredentials(PasswordCredentials in) {
return this
.username(in.getUsername())
.password(in.getPassword());
}
}
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
@Override
protected ConcreteBuilder self() {
return this;
}
}
private final String username;
private final String password;
@ConstructorProperties({
"username", "password"
})
protected PasswordCredentials(String username, String password) {
this.username = checkNotNull(username, "username");
this.password = checkNotNull(password, "password");
}
/**
* @return the username
*/
public String getUsername() {
return this.username;
}
/**
* @return the password
*/
public String getPassword() {
return this.password;
}
@Override
public int hashCode() {
return Objects.hashCode(username, password);
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
PasswordCredentials that = PasswordCredentials.class.cast(obj);
return Objects.equal(this.username, that.username)
&& Objects.equal(this.password, that.password);
}
protected ToStringHelper string() {
return MoreObjects.toStringHelper(this)
.add("username", username)
.add("password", password == null ? null : "*****");
}
@Override
public String toString() {
return string().toString();
}
}

View File

@ -30,8 +30,8 @@ import org.jclouds.Fallbacks.EmptyFluentIterableOnNotFoundOr404;
import org.jclouds.Fallbacks.FalseOnNotFoundOr404;
import org.jclouds.Fallbacks.NullOnNotFoundOr404;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.keystone.auth.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.v2_0.domain.Role;
import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
import org.jclouds.openstack.v2_0.ServiceType;
import org.jclouds.openstack.v2_0.services.Extension;
import org.jclouds.rest.annotations.Fallback;

View File

@ -30,9 +30,9 @@ import org.jclouds.Fallbacks.FalseOnNotFoundOr404;
import org.jclouds.Fallbacks.NullOnNotFoundOr404;
import org.jclouds.collect.PagedIterable;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.keystone.auth.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.v2_0.KeystoneFallbacks.EmptyPaginatedCollectionOnNotFoundOr404;
import org.jclouds.openstack.keystone.v2_0.domain.Service;
import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.v2_0.functions.internal.ParseServices;
import org.jclouds.openstack.keystone.v2_0.functions.internal.ParseServices.ToPagedIterable;
import org.jclouds.openstack.v2_0.ServiceType;

View File

@ -28,8 +28,8 @@ import javax.ws.rs.core.MediaType;
import org.jclouds.Fallbacks.FalseOnNotFoundOr404;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.keystone.auth.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.v2_0.domain.Tenant;
import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.v2_0.options.CreateTenantOptions;
import org.jclouds.openstack.keystone.v2_0.options.UpdateTenantOptions;
import org.jclouds.openstack.v2_0.ServiceType;

View File

@ -27,8 +27,8 @@ import javax.ws.rs.core.MediaType;
import org.jclouds.Fallbacks.FalseOnNotFoundOr404;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.keystone.auth.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.v2_0.domain.User;
import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.v2_0.options.CreateUserOptions;
import org.jclouds.openstack.keystone.v2_0.options.UpdateUserOptions;
import org.jclouds.openstack.v2_0.ServiceType;

View File

@ -25,8 +25,8 @@ import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import org.jclouds.Fallbacks.EmptySetOnNotFoundOr404;
import org.jclouds.openstack.keystone.auth.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.v2_0.domain.Tenant;
import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SelectJson;

View File

@ -27,9 +27,9 @@ import org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404;
import org.jclouds.Fallbacks.NullOnNotFoundOr404;
import org.jclouds.collect.PagedIterable;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.keystone.auth.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.v2_0.KeystoneFallbacks.EmptyPaginatedCollectionOnNotFoundOr404;
import org.jclouds.openstack.keystone.v2_0.domain.Tenant;
import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.v2_0.functions.internal.ParseTenants;
import org.jclouds.openstack.keystone.v2_0.functions.internal.ParseTenants.ToPagedIterable;
import org.jclouds.openstack.v2_0.domain.PaginatedCollection;

View File

@ -30,10 +30,10 @@ import org.jclouds.Fallbacks.EmptySetOnNotFoundOr404;
import org.jclouds.Fallbacks.FalseOnNotFoundOr404;
import org.jclouds.Fallbacks.NullOnNotFoundOr404;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.keystone.auth.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import org.jclouds.openstack.keystone.v2_0.domain.Token;
import org.jclouds.openstack.keystone.v2_0.domain.User;
import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
import org.jclouds.openstack.v2_0.services.Identity;
import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.annotations.RequestFilters;

View File

@ -31,10 +31,10 @@ import org.jclouds.Fallbacks.EmptySetOnNotFoundOr404;
import org.jclouds.Fallbacks.NullOnNotFoundOr404;
import org.jclouds.collect.PagedIterable;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.keystone.auth.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.v2_0.KeystoneFallbacks.EmptyPaginatedCollectionOnNotFoundOr404;
import org.jclouds.openstack.keystone.v2_0.domain.Role;
import org.jclouds.openstack.keystone.v2_0.domain.User;
import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.v2_0.functions.internal.ParseUsers;
import org.jclouds.openstack.keystone.v2_0.functions.internal.ParseUsers.ToPagedIterable;
import org.jclouds.openstack.v2_0.domain.PaginatedCollection;

View File

@ -1,60 +0,0 @@
/*
* 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.v2_0.functions;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.openstack.keystone.v2_0.AuthenticationApi;
import org.jclouds.openstack.keystone.v2_0.config.CredentialType;
import org.jclouds.openstack.keystone.v2_0.config.CredentialTypes;
import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.v2_0.domain.ApiAccessKeyCredentials;
import org.jclouds.openstack.keystone.v2_0.functions.internal.BaseAuthenticator;
import com.google.common.base.Optional;
@CredentialType(CredentialTypes.API_ACCESS_KEY_CREDENTIALS)
@Singleton
public class AuthenticateApiAccessKeyCredentials extends BaseAuthenticator<ApiAccessKeyCredentials> {
protected final AuthenticationApi api;
@Inject
public AuthenticateApiAccessKeyCredentials(AuthenticationApi api) {
this.api = api;
}
@Override
protected Access authenticateWithTenantName(Optional<String> tenantName, ApiAccessKeyCredentials apiAccessKeyCredentials) {
return api.authenticateWithTenantNameAndCredentials(tenantName.orNull(), apiAccessKeyCredentials);
}
@Override
protected Access authenticateWithTenantId(Optional<String> tenantId, ApiAccessKeyCredentials apiAccessKeyCredentials) {
return api.authenticateWithTenantIdAndCredentials(tenantId.orNull(), apiAccessKeyCredentials);
}
@Override
public ApiAccessKeyCredentials createCredentials(String identity, String credential) {
return ApiAccessKeyCredentials.createWithAccessKeyAndSecretKey(identity, credential);
}
@Override
public String toString() {
return "authenticateApiAccessKeyCredentials()";
}
}

View File

@ -1,60 +0,0 @@
/*
* 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.v2_0.functions;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.openstack.keystone.v2_0.AuthenticationApi;
import org.jclouds.openstack.keystone.v2_0.config.CredentialType;
import org.jclouds.openstack.keystone.v2_0.config.CredentialTypes;
import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.v2_0.domain.PasswordCredentials;
import org.jclouds.openstack.keystone.v2_0.functions.internal.BaseAuthenticator;
import com.google.common.base.Optional;
@CredentialType(CredentialTypes.PASSWORD_CREDENTIALS)
@Singleton
public class AuthenticatePasswordCredentials extends BaseAuthenticator<PasswordCredentials> {
protected final AuthenticationApi api;
@Inject
public AuthenticatePasswordCredentials(AuthenticationApi api) {
this.api = api;
}
@Override
protected Access authenticateWithTenantName(Optional<String> tenantName, PasswordCredentials apiAccessKeyCredentials) {
return api.authenticateWithTenantNameAndCredentials(tenantName.orNull(), apiAccessKeyCredentials);
}
@Override
protected Access authenticateWithTenantId(Optional<String> tenantId, PasswordCredentials apiAccessKeyCredentials) {
return api.authenticateWithTenantIdAndCredentials(tenantId.orNull(), apiAccessKeyCredentials);
}
@Override
public PasswordCredentials createCredentials(String identity, String credential) {
return PasswordCredentials.createWithUsernameAndPassword(identity, credential);
}
@Override
public String toString() {
return "authenticatePasswordCredentials()";
}
}

View File

@ -1,49 +0,0 @@
/*
* 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.v2_0.functions;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import java.net.URI;
import java.util.Map;
import javax.inject.Inject;
import org.jclouds.openstack.keystone.v2_0.suppliers.RegionIdToAdminURISupplier;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
public final class RegionToAdminEndpointURI implements Function<Object, URI> {
private final RegionIdToAdminURISupplier regionToAdminEndpoints;
@Inject
RegionToAdminEndpointURI(RegionIdToAdminURISupplier regionToAdminEndpoints) {
this.regionToAdminEndpoints = regionToAdminEndpoints;
}
@Override
public URI apply(Object from) {
Map<String, Supplier<URI>> regionToAdminEndpoint = regionToAdminEndpoints.get();
checkState(!regionToAdminEndpoint.isEmpty(), "no region name to admin endpoint mappings in keystone!");
checkArgument(regionToAdminEndpoint.containsKey(from),
"requested location %s, which is not in the keystone admin endpoints: %s", from, regionToAdminEndpoint);
return regionToAdminEndpoint.get(from).get();
}
}

View File

@ -1,208 +0,0 @@
/*
* 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.v2_0.suppliers;
import static com.google.common.collect.Iterables.any;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.isEmpty;
import static com.google.common.collect.Iterables.tryFind;
import static com.google.common.collect.Multimaps.index;
import java.net.URI;
import java.util.Collection;
import java.util.Map;
import java.util.NoSuchElementException;
import javax.annotation.Resource;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.logging.Logger;
import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import org.jclouds.openstack.keystone.v2_0.domain.Service;
import org.jclouds.openstack.keystone.v2_0.functions.EndpointToSupplierURI;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
public class LocationIdToURIFromAccessForTypeAndVersion implements Supplier<Map<String, Supplier<URI>>> {
public interface Factory {
/**
*
* @param apiType
* type of the api, according to the provider. ex.
* {@code compute} {@code object-store}
* @param apiVersion
* version of the api, or null if not available
* @return locations mapped to default uri
* @throws NoSuchElementException
* if the {@code apiType} is not present in the catalog
*/
LocationIdToURIFromAccessForTypeAndVersion createForApiTypeAndVersion(@Assisted("apiType") String apiType,
@Nullable @Assisted("apiVersion") String apiVersion) throws NoSuchElementException;
}
@Resource
protected Logger logger = Logger.NULL;
protected final Supplier<Access> access;
protected final EndpointToSupplierURI endpointToSupplierURI;
protected final Function<Endpoint, String> endpointToLocationId;
protected final String apiType;
protected final String apiVersion;
@Inject
public LocationIdToURIFromAccessForTypeAndVersion(Supplier<Access> access,
EndpointToSupplierURI endpointToSupplierURI, Function<Endpoint, String> endpointToLocationId,
@Assisted("apiType") String apiType, @Nullable @Assisted("apiVersion") String apiVersion) {
this.access = access;
this.endpointToSupplierURI = endpointToSupplierURI;
this.endpointToLocationId = endpointToLocationId;
this.apiType = apiType;
this.apiVersion = apiVersion;
}
@Override
public Map<String, Supplier<URI>> get() {
FluentIterable<Service> services = FluentIterable.from(access.get()).filter(apiTypeEquals);
if (services.isEmpty())
throw new NoSuchElementException(String.format("apiType %s not found in catalog %s", apiType, services));
Iterable<Endpoint> endpoints = concat(services);
if (isEmpty(endpoints))
throw new NoSuchElementException(
String.format("no endpoints for apiType %s in services %s", apiType, services));
boolean checkVersionId = any(endpoints, versionAware);
Multimap<String, Endpoint> locationToEndpoints = index(endpoints, endpointToLocationId);
Map<String, Endpoint> locationToEndpoint;
if (checkVersionId && apiVersion != null) {
locationToEndpoint = refineToVersionSpecificEndpoint(locationToEndpoints);
if (locationToEndpoint.size() == 0)
throw new NoSuchElementException(String.format(
"no endpoints for apiType %s are of version %s, or version agnostic: %s", apiType, apiVersion,
locationToEndpoints));
} else {
locationToEndpoint = firstEndpointInLocation(locationToEndpoints);
}
logger.debug("endpoints for apiType %s and version %s: %s", apiType, apiVersion, locationToEndpoints);
return Maps.transformValues(locationToEndpoint, endpointToSupplierURI);
}
@VisibleForTesting
Map<String, Endpoint> firstEndpointInLocation(Multimap<String, Endpoint> locationToEndpoints) {
Builder<String, Endpoint> locationToEndpointBuilder = ImmutableMap.<String, Endpoint> builder();
for (Map.Entry<String, Collection<Endpoint>> entry : locationToEndpoints.asMap().entrySet()) {
String locationId = entry.getKey();
Collection<Endpoint> endpoints = entry.getValue();
switch (endpoints.size()) {
case 0:
logNoEndpointsInLocation(locationId);
break;
default:
locationToEndpointBuilder.put(locationId, Iterables.get(endpoints, 0));
}
}
return locationToEndpointBuilder.build();
}
@VisibleForTesting
Map<String, Endpoint> refineToVersionSpecificEndpoint(Multimap<String, Endpoint> locationToEndpoints) {
Builder<String, Endpoint> locationToEndpointBuilder = ImmutableMap.<String, Endpoint> builder();
for (Map.Entry<String, Collection<Endpoint>> entry : locationToEndpoints.asMap().entrySet()) {
String locationId = entry.getKey();
Collection<Endpoint> endpoints = entry.getValue();
switch (endpoints.size()) {
case 0:
logNoEndpointsInLocation(locationId);
break;
default:
putIfPresent(locationId, strictMatchEndpointVersion(endpoints, locationId), locationToEndpointBuilder);
}
}
return locationToEndpointBuilder.build();
}
/**
* Prioritizes endpoint.versionId over endpoint.id when matching
*/
private Optional<Endpoint> strictMatchEndpointVersion(Iterable<Endpoint> endpoints, String locationId) {
Optional<Endpoint> endpointOfVersion = tryFind(endpoints, apiVersionEqualsVersionId);
if (!endpointOfVersion.isPresent())
logger.debug("no endpoints of apiType %s matched expected version %s in location %s: %s", apiType, apiVersion,
locationId, endpoints);
return endpointOfVersion;
}
private void logNoEndpointsInLocation(String locationId) {
logger.debug("no endpoints found for apiType %s in location %s", apiType, locationId);
}
private final Predicate<Endpoint> apiVersionEqualsVersionId = new Predicate<Endpoint>() {
@Override
public boolean apply(Endpoint input) {
return input.getVersionId().equals(apiVersion);
}
};
private final Predicate<Endpoint> versionAware = new Predicate<Endpoint>() {
@Override
public boolean apply(Endpoint input) {
return input.getVersionId() != null;
}
};
private final Predicate<Service> apiTypeEquals = new Predicate<Service>() {
@Override
public boolean apply(Service input) {
return input.getType().equals(apiType);
}
};
private static <K, V> void putIfPresent(K key, Optional<V> value, Builder<K, V> builder) {
if (value.isPresent())
builder.put(key, value.get());
}
@Override
public String toString() {
return "locationIdToURIFromAccessForTypeAndVersion(" + apiType + ", " + apiVersion + ")";
}
}

View File

@ -1,42 +0,0 @@
/*
* 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.v2_0.suppliers;
import javax.inject.Inject;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.v2_0.functions.EndpointToRegion;
import org.jclouds.openstack.keystone.v2_0.functions.EndpointToSupplierAdminURI;
import com.google.common.base.Supplier;
import com.google.inject.assistedinject.Assisted;
public class RegionIdToAdminURIFromAccessForTypeAndVersion extends LocationIdToURIFromAccessForTypeAndVersion implements
RegionIdToAdminURISupplier {
@Inject
public RegionIdToAdminURIFromAccessForTypeAndVersion(Supplier<Access> access,
EndpointToSupplierAdminURI endpointToSupplierURI, EndpointToRegion endpointToRegion,
@Assisted("apiType") String apiType, @Nullable @Assisted("apiVersion") String apiVersion) {
super(access, endpointToSupplierURI, endpointToRegion, apiType, apiVersion);
}
@Override
public String toString() {
return "regionIdToAdminURIFromAccessForTypeAndVersion(" + apiType + ", " + apiVersion + ")";
}
}

View File

@ -1,47 +0,0 @@
/*
* 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.v2_0.suppliers;
import javax.inject.Inject;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.location.suppliers.ZoneIdToURISupplier;
import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.v2_0.functions.EndpointToRegion;
import org.jclouds.openstack.keystone.v2_0.functions.EndpointToSupplierURI;
import com.google.common.base.Supplier;
import com.google.inject.assistedinject.Assisted;
public class ZoneIdToURIFromAccessForTypeAndVersion extends LocationIdToURIFromAccessForTypeAndVersion implements
ZoneIdToURISupplier {
@Inject
public ZoneIdToURIFromAccessForTypeAndVersion(
Supplier<Access> access,
// NOTE that in some services, the region is in fact the zone. temporarily, we need
// to use the region field, in this case.
EndpointToSupplierURI endpointToSupplierURI, EndpointToRegion endpointToZone,
@Assisted("apiType") String apiType, @Nullable @Assisted("apiVersion") String apiVersion) {
super(access, endpointToSupplierURI, endpointToZone, apiType, apiVersion);
}
@Override
public String toString() {
return "zoneIdToURIFromAccessForTypeAndVersion(" + apiType + ", " + apiVersion + ")";
}
}

View File

@ -0,0 +1,62 @@
/*
* 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.v3;
import java.io.Closeable;
import org.jclouds.openstack.keystone.v3.features.AuthApi;
import org.jclouds.openstack.keystone.v3.features.CatalogApi;
import org.jclouds.openstack.keystone.v3.features.ProjectApi;
import org.jclouds.openstack.keystone.v3.features.RegionApi;
import org.jclouds.openstack.keystone.v3.features.UserApi;
import org.jclouds.rest.annotations.Delegate;
/**
* Provides access to the OpenStack Identity (Keystone) REST API.
*/
public interface KeystoneApi extends Closeable {
/**
* Provides access to authentication and token management features.
*/
@Delegate
AuthApi getAuthApi();
/**
* Provides access to service catalog features.
*/
@Delegate
CatalogApi getCatalogApi();
/**
* Provides access to region features.
*/
@Delegate
RegionApi getRegionApi();
/**
* Provides access to project features.
*/
@Delegate
ProjectApi getProjectApi();
/**
* Provides access to user features.
*/
@Delegate
UserApi getUserApi();
}

View File

@ -0,0 +1,97 @@
/*
* 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.v3;
import static org.jclouds.openstack.keystone.config.KeystoneProperties.CREDENTIAL_TYPE;
import static org.jclouds.openstack.keystone.config.KeystoneProperties.KEYSTONE_VERSION;
import static org.jclouds.openstack.keystone.config.KeystoneProperties.SERVICE_TYPE;
import java.net.URI;
import java.util.Properties;
import org.jclouds.apis.ApiMetadata;
import org.jclouds.openstack.keystone.auth.config.AuthenticationModule;
import org.jclouds.openstack.keystone.catalog.config.KeystoneAdminURLModule;
import org.jclouds.openstack.keystone.catalog.config.ServiceCatalogModule;
import org.jclouds.openstack.keystone.v3.config.KeystoneHttpApiModule;
import org.jclouds.openstack.v2_0.ServiceType;
import org.jclouds.rest.internal.BaseHttpApiMetadata;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Module;
/**
* Implementation of {@link ApiMetadata} for Keystone 3.0 API
*/
@AutoService(ApiMetadata.class)
public class KeystoneApiMetadata extends BaseHttpApiMetadata<KeystoneApi> {
@Override
public Builder<?> toBuilder() {
return new ConcreteBuilder().fromApiMetadata(this);
}
public KeystoneApiMetadata() {
this(new ConcreteBuilder());
}
protected KeystoneApiMetadata(Builder<?> builder) {
super(builder);
}
public static Properties defaultProperties() {
Properties properties = BaseHttpApiMetadata.defaultProperties();
properties.setProperty(CREDENTIAL_TYPE, org.jclouds.openstack.keystone.auth.config.CredentialTypes.PASSWORD_CREDENTIALS);
properties.setProperty(SERVICE_TYPE, ServiceType.IDENTITY);
properties.setProperty(KEYSTONE_VERSION, "3");
return properties;
}
public abstract static class Builder<T extends Builder<T>> extends BaseHttpApiMetadata.Builder<KeystoneApi, T> {
protected Builder() {
id("openstack-keystone-3")
.name("OpenStack Keystone 3.x API")
.identityName("${domain}:${userName} or ${userName}, if your keystone supports a default project")
.credentialName("${password}")
.endpointName("Keystone V3 base URL")
.documentation(URI.create("http://api.openstack.org/"))
.version("3")
.defaultEndpoint("http://localhost/identity/v3")
.defaultProperties(KeystoneApiMetadata.defaultProperties())
.defaultModules(ImmutableSet.<Class<? extends Module>>builder()
.add(AuthenticationModule.class)
.add(ServiceCatalogModule.class)
.add(KeystoneAdminURLModule.class)
.add(KeystoneHttpApiModule.class)
.build());
}
@Override
public KeystoneApiMetadata build() {
return new KeystoneApiMetadata(this);
}
}
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
@Override
protected ConcreteBuilder self() {
return this;
}
}
}

View File

@ -0,0 +1,60 @@
/*
* 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.v3.auth;
import java.io.Closeable;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import org.jclouds.openstack.keystone.auth.AuthenticationApi;
import org.jclouds.openstack.keystone.auth.domain.PasswordCredentials;
import org.jclouds.openstack.keystone.auth.domain.TenantOrDomainAndCredentials;
import org.jclouds.openstack.keystone.auth.domain.TokenCredentials;
import org.jclouds.openstack.keystone.v3.binders.BindPasswordAuthToJsonPayload;
import org.jclouds.openstack.keystone.v3.binders.BindTokenAuthToJsonPayload;
import org.jclouds.openstack.keystone.v3.domain.Token;
import org.jclouds.openstack.keystone.v3.parsers.ParseTokenFromHttpResponse;
import org.jclouds.rest.annotations.MapBinder;
import org.jclouds.rest.annotations.ResponseParser;
import com.google.inject.name.Named;
/**
* Provides access to the OpenStack Keystone Authentication API.
*/
@Consumes(MediaType.APPLICATION_JSON)
@Path("/auth/tokens")
public interface V3AuthenticationApi extends AuthenticationApi, Closeable {
@Named("token:create")
@POST
@ResponseParser(ParseTokenFromHttpResponse.class)
@MapBinder(BindPasswordAuthToJsonPayload.class)
@Override
Token authenticatePassword(TenantOrDomainAndCredentials<PasswordCredentials> credentials);
@Named("token:create")
@POST
@ResponseParser(ParseTokenFromHttpResponse.class)
@MapBinder(BindTokenAuthToJsonPayload.class)
@Override
Token authenticateToken(TenantOrDomainAndCredentials<TokenCredentials> credentials);
}

View File

@ -0,0 +1,107 @@
/*
* 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.v3.binders;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.instanceOf;
import static com.google.common.collect.Iterables.tryFind;
import static org.jclouds.openstack.keystone.v3.domain.Auth.Scope.DOMAIN;
import static org.jclouds.openstack.keystone.v3.domain.Auth.Scope.DOMAIN_ID;
import static org.jclouds.openstack.keystone.v3.domain.Auth.Scope.PROJECT;
import static org.jclouds.openstack.keystone.v3.domain.Auth.Scope.PROJECT_ID;
import static org.jclouds.openstack.keystone.v3.domain.Auth.Scope.UNSCOPED;
import java.util.Map;
import java.util.Set;
import org.jclouds.http.HttpRequest;
import org.jclouds.json.Json;
import org.jclouds.openstack.keystone.auth.domain.TenantOrDomainAndCredentials;
import org.jclouds.openstack.keystone.v3.domain.Auth;
import org.jclouds.openstack.keystone.v3.domain.Auth.DomainIdScope;
import org.jclouds.openstack.keystone.v3.domain.Auth.DomainScope;
import org.jclouds.openstack.keystone.v3.domain.Auth.Id;
import org.jclouds.openstack.keystone.v3.domain.Auth.Name;
import org.jclouds.openstack.keystone.v3.domain.Auth.ProjectIdScope;
import org.jclouds.openstack.keystone.v3.domain.Auth.ProjectScope;
import org.jclouds.openstack.keystone.v3.domain.Auth.ProjectScope.ProjectName;
import org.jclouds.rest.MapBinder;
import org.jclouds.rest.binders.BindToJsonPayload;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
public abstract class BindAuthToJsonPayload<T> extends BindToJsonPayload implements MapBinder {
private static final Set<String> SCOPE_PREFIXES = ImmutableSet
.of(PROJECT, PROJECT_ID, DOMAIN, DOMAIN_ID);
protected BindAuthToJsonPayload(Json jsonBinder) {
super(jsonBinder);
}
protected abstract Auth buildAuth(TenantOrDomainAndCredentials<T> credentials, Object scope);
@Override
public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest,
"this binder is only valid for GeneratedHttpRequests!");
GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request;
Optional<Object> authentication = tryFind(gRequest.getInvocation().getArgs(),
instanceOf(TenantOrDomainAndCredentials.class));
checkArgument(authentication.isPresent(), "no credentials found in the api call arguments");
@SuppressWarnings("unchecked")
TenantOrDomainAndCredentials<T> credentials = (TenantOrDomainAndCredentials<T>) authentication.get();
Object scope = parseScope(credentials);
Auth auth = buildAuth(credentials, scope);
R authRequest = super.bindToRequest(request, ImmutableMap.of("auth", auth));
authRequest.getPayload().setSensitive(true);
return authRequest;
}
private Object parseScope(TenantOrDomainAndCredentials<T> credentials) {
String scope = credentials.scope();
// If there is no prefix, assume an unscoped authentication
if (!scope.contains(":")) {
checkArgument(scope.equals(UNSCOPED), "Invalid scope: %s", scope);
return UNSCOPED;
}
// Otherwise, parse if it is a project or domain scope
String[] parts = scope.split(":");
checkArgument(parts.length == 2, "Invalid scope: %s", scope);
checkArgument(SCOPE_PREFIXES.contains(parts[0]), "Scope prefix should be: %s", SCOPE_PREFIXES);
if (PROJECT.equals(parts[0])) {
Object domainScope = credentials.tenantOrDomainId() != null ? Id.create(credentials.tenantOrDomainId()) : Name
.create(credentials.tenantOrDomainName());
return ProjectScope.create(ProjectName.create(parts[1], domainScope));
} else if (PROJECT_ID.equals(parts[0])) {
return ProjectIdScope.create(Id.create(parts[1]));
} else if (DOMAIN.equals(parts[0])) {
return DomainScope.create(Name.create(parts[1]));
} else {
return DomainIdScope.create(Id.create(parts[1]));
}
}
}

View File

@ -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.v3.binders;
import static java.util.Collections.singletonList;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.json.Json;
import org.jclouds.openstack.keystone.auth.domain.PasswordCredentials;
import org.jclouds.openstack.keystone.auth.domain.TenantOrDomainAndCredentials;
import org.jclouds.openstack.keystone.v3.domain.Auth;
import org.jclouds.openstack.keystone.v3.domain.Auth.Identity;
import org.jclouds.openstack.keystone.v3.domain.Auth.Identity.PasswordAuth;
import org.jclouds.openstack.keystone.v3.domain.Auth.Identity.PasswordAuth.UserAuth;
import org.jclouds.openstack.keystone.v3.domain.Auth.Identity.PasswordAuth.UserAuth.DomainAuth;
@Singleton
public class BindPasswordAuthToJsonPayload extends BindAuthToJsonPayload<PasswordCredentials> {
@Inject
BindPasswordAuthToJsonPayload(Json jsonBinder) {
super(jsonBinder);
}
@Override
protected Auth buildAuth(TenantOrDomainAndCredentials<PasswordCredentials> credentials, Object scope) {
PasswordCredentials creds = credentials.credentials();
DomainAuth domain = DomainAuth.create(credentials.tenantOrDomainName());
UserAuth user = UserAuth.create(creds.username(), domain, creds.password());
return Auth.create(Identity.create(singletonList("password"), null, PasswordAuth.create(user)), scope);
}
}

View File

@ -0,0 +1,45 @@
/*
* 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.v3.binders;
import static java.util.Collections.singletonList;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.json.Json;
import org.jclouds.openstack.keystone.auth.domain.TenantOrDomainAndCredentials;
import org.jclouds.openstack.keystone.auth.domain.TokenCredentials;
import org.jclouds.openstack.keystone.v3.domain.Auth;
import org.jclouds.openstack.keystone.v3.domain.Auth.Id;
import org.jclouds.openstack.keystone.v3.domain.Auth.Identity;
@Singleton
public class BindTokenAuthToJsonPayload extends BindAuthToJsonPayload<TokenCredentials> {
@Inject
BindTokenAuthToJsonPayload(Json jsonBinder) {
super(jsonBinder);
}
@Override
protected Auth buildAuth(TenantOrDomainAndCredentials<TokenCredentials> credentials, Object scope) {
Id token = Id.create(credentials.credentials().id());
return Auth.create(Identity.create(singletonList("token"), token, null), scope);
}
}

View File

@ -0,0 +1,63 @@
/*
* 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.v3.catalog;
import java.util.List;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.logging.Logger;
import org.jclouds.openstack.keystone.auth.domain.AuthInfo;
import org.jclouds.openstack.keystone.catalog.ServiceEndpoint;
import org.jclouds.openstack.keystone.v3.domain.Catalog;
import org.jclouds.openstack.keystone.v3.domain.Endpoint;
import org.jclouds.openstack.keystone.v3.domain.Token;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
@Singleton
public class V3ServiceCatalog implements Supplier<List<ServiceEndpoint>> {
@Resource
private Logger logger = Logger.NULL;
private final Supplier<AuthInfo> authInfo;
@Inject
V3ServiceCatalog(Supplier<AuthInfo> authInfo) {
this.authInfo = authInfo;
}
@Override
public List<ServiceEndpoint> get() {
Token token = (Token) authInfo.get();
ImmutableList.Builder<ServiceEndpoint> serviceEndpoints = ImmutableList.builder();
for (Catalog catalog : token.catalog()) {
for (Endpoint endpoint : catalog.endpoints()) {
serviceEndpoints.add(ServiceEndpoint.builder().id(endpoint.id()).iface(endpoint.iface())
.regionId(endpoint.regionId()).type(catalog.type()).url(endpoint.url()).build());
}
}
return serviceEndpoints.build();
}
}

View File

@ -0,0 +1,37 @@
/*
* 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.v3.config;
import org.jclouds.json.config.GsonModule;
import org.jclouds.json.config.GsonModule.DateAdapter;
import org.jclouds.openstack.keystone.v3.KeystoneApi;
import org.jclouds.rest.ConfiguresHttpApi;
import org.jclouds.rest.config.HttpApiModule;
/**
* Configures the Keystone API.
*/
@ConfiguresHttpApi
public class KeystoneHttpApiModule extends HttpApiModule<KeystoneApi> {
@Override
protected void configure() {
super.configure();
bind(DateAdapter.class).to(GsonModule.Iso8601DateAdapter.class);
}
}

View File

@ -0,0 +1,166 @@
/*
* 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.v3.domain;
import java.util.List;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
@AutoValue
public abstract class Auth {
public abstract Identity identity();
@Nullable public abstract Object scope();
@SerializedNames({ "identity", "scope" })
public static Auth create(Identity identity, Object scope) {
return new AutoValue_Auth(identity, scope);
}
@AutoValue
public abstract static class Identity {
public abstract List<String> methods();
@Nullable public abstract Id token();
@Nullable public abstract PasswordAuth password();
@SerializedNames({ "methods", "token", "password" })
public static Identity create(List<String> methods, Id token, PasswordAuth password) {
return new AutoValue_Auth_Identity(methods, token, password);
}
@AutoValue
public abstract static class PasswordAuth {
public abstract UserAuth user();
@SerializedNames({ "user" })
public static PasswordAuth create(UserAuth user) {
return new AutoValue_Auth_Identity_PasswordAuth(user);
}
@AutoValue
public abstract static class UserAuth {
public abstract String name();
public abstract DomainAuth domain();
public abstract String password();
@SerializedNames({ "name", "domain", "password" })
public static UserAuth create(String name, DomainAuth domain, String password) {
return new AutoValue_Auth_Identity_PasswordAuth_UserAuth(name, domain, password);
}
@AutoValue
public abstract static class DomainAuth {
@Nullable public abstract String name();
@SerializedNames({ "name" })
public static DomainAuth create(String name) {
return new AutoValue_Auth_Identity_PasswordAuth_UserAuth_DomainAuth(name);
}
}
}
}
}
@AutoValue
public abstract static class Id {
public abstract String id();
@SerializedNames({ "id" })
public static Id create(String id) {
return new AutoValue_Auth_Id(id);
}
}
@AutoValue
public abstract static class Name {
@Nullable public abstract String name();
@SerializedNames({ "name" })
public static Name create(String name) {
return new AutoValue_Auth_Name(name);
}
}
public static class Scope {
public static final String PROJECT = "project";
public static final String PROJECT_ID = "projectId";
public static final String DOMAIN = "domain";
public static final String DOMAIN_ID = "domainId";
public static final String UNSCOPED = "unscoped";
}
@AutoValue
public abstract static class ProjectScope {
public abstract ProjectName project();
@SerializedNames({ Scope.PROJECT })
public static ProjectScope create(ProjectName project) {
return new AutoValue_Auth_ProjectScope(project);
}
@AutoValue
public abstract static class ProjectName {
public abstract String name();
@Nullable public abstract Object domain();
@SerializedNames({ "name", Scope.DOMAIN })
public static ProjectName create(String name, Object domain) {
return new AutoValue_Auth_ProjectScope_ProjectName(name, domain);
}
public static ProjectName create(String name, Name domain) {
return new AutoValue_Auth_ProjectScope_ProjectName(name, domain);
}
public static ProjectName create(String name, Id domain) {
return new AutoValue_Auth_ProjectScope_ProjectName(name, domain);
}
}
}
@AutoValue
public abstract static class ProjectIdScope {
public abstract Id project();
@SerializedNames({ Scope.PROJECT })
public static ProjectIdScope create(Id id) {
return new AutoValue_Auth_ProjectIdScope(id);
}
}
@AutoValue
public abstract static class DomainIdScope {
public abstract Id domain();
@SerializedNames({ Scope.DOMAIN })
public static DomainIdScope create(Id id) {
return new AutoValue_Auth_DomainIdScope(id);
}
}
@AutoValue
public abstract static class DomainScope {
public abstract Name domain();
@SerializedNames({ Scope.DOMAIN })
public static DomainScope create(Name name) {
return new AutoValue_Auth_DomainScope(name);
}
}
}

View File

@ -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.v3.domain;
import java.util.List;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
@AutoValue
public abstract class Catalog {
public abstract String id();
@Nullable public abstract String name();
public abstract String type();
public abstract List<Endpoint> endpoints();
@SerializedNames({ "id", "name", "type", "endpoints" })
public static Catalog create(String id, String name, String type, List<Endpoint> endpoints) {
return builder().id(id).name(name).type(type).endpoints(endpoints).build();
}
Catalog() {
}
public abstract Builder toBuilder();
public static Builder builder() {
return new AutoValue_Catalog.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder id(String id);
public abstract Builder name(String name);
public abstract Builder type(String type);
public abstract Builder endpoints(List<Endpoint> endpoints);
abstract List<Endpoint> endpoints();
abstract Catalog autoBuild();
public Catalog build() {
endpoints(endpoints() == null ? ImmutableList.<Endpoint> of() : ImmutableList.copyOf(endpoints()));
return autoBuild();
}
}
}

View File

@ -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.v3.domain;
import java.net.URI;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
@AutoValue
public abstract class Endpoint {
@Nullable public abstract String id();
@Nullable public abstract String region();
@Nullable public abstract String regionId();
@Nullable public abstract String serviceId();
public abstract URI url();
@Nullable public abstract Boolean enabled();
public abstract String iface();
@SerializedNames({ "id", "region", "region_id", "service_id", "url", "enabled", "interface" })
public static Endpoint create(String id, String region, String regionId, String serviceId, URI url, Boolean enabled,
String iface) {
return builder().id(serviceId).region(region).regionId(regionId).serviceId(serviceId).url(url).enabled(enabled)
.iface(iface).build();
}
Endpoint() {
}
public abstract Builder toBuilder();
public static Builder builder() {
return new AutoValue_Endpoint.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder id(String id);
public abstract Builder region(String region);
public abstract Builder regionId(String regionId);
public abstract Builder serviceId(String serviceId);
public abstract Builder url(URI url);
public abstract Builder enabled(Boolean enabled);
public abstract Builder iface(String iface);
public abstract Endpoint build();
}
}

View File

@ -0,0 +1,56 @@
/*
* 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.v3.domain;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
@AutoValue
public abstract class Group {
public abstract String id();
public abstract String name();
@Nullable public abstract String description();
@Nullable public abstract String domainId();
@Nullable public abstract Link link();
@SerializedNames({ "id", "name", "description", "domain_id", "links" })
public static Group create(String id, String name, String description, String domainId, Link link) {
return builder().id(id).name(name).description(description).domainId(domainId).link(link).build();
}
Group() {
}
public abstract Builder toBuilder();
public static Builder builder() {
return new AutoValue_Group.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder id(String id);
public abstract Builder name(String String);
public abstract Builder description(String description);
public abstract Builder domainId(String domainId);
public abstract Builder link(Link link);
public abstract Group build();
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.v3.domain;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
@AutoValue
public abstract class Link {
public abstract String self();
@SerializedNames({"self"})
public static Link create(String self) {
return new AutoValue_Link(self);
}
Link() {
}
}

View File

@ -0,0 +1,79 @@
/*
* 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.v3.domain;
import java.util.List;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
@AutoValue
public abstract class Project {
public abstract boolean isDomain();
@Nullable public abstract String description();
@Nullable public abstract String domainId();
@Nullable public abstract String domainName();
public abstract boolean enabled();
@Nullable public abstract String id();
public abstract String name();
@Nullable public abstract String parentId();
@Nullable public abstract List<String> tags();
@Nullable public abstract Link link();
@SerializedNames({ "is_domain", "description", "domain_id", "domain_name", "enabled", "id", "name", "parent_id",
"tags", "links" })
public static Project create(boolean isDomain, String description, String domainId, String domainName,
boolean enabled, String id, String name, String parentId, List<String> tags, Link link) {
return builder().isDomain(isDomain).description(description).domainId(domainId).domainName(domainName)
.enabled(enabled).id(id).name(name).parentId(parentId).tags(tags).link(link).build();
}
Project() {
}
public abstract Builder toBuilder();
public static Builder builder() {
return new AutoValue_Project.Builder().isDomain(false).enabled(true);
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder isDomain(boolean isDomain);
public abstract Builder description(String description);
public abstract Builder domainId(String domainId);
public abstract Builder domainName(String domainName);
public abstract Builder enabled(boolean enabled);
public abstract Builder id(String id);
public abstract Builder name(String name);
public abstract Builder parentId(String parentId);
public abstract Builder tags(List<String> tags);
public abstract Builder link(Link link);
abstract List<String> tags();
abstract Project autoBuild();
public Project build() {
tags(tags() == null ? null : ImmutableList.copyOf(tags()));
return autoBuild();
}
}
}

View File

@ -0,0 +1,54 @@
/*
* 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.v3.domain;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
@AutoValue
public abstract class Region {
public abstract String id();
public abstract String description();
@Nullable public abstract Link link();
@Nullable public abstract String parentRegionId();
@SerializedNames({ "id", "description", "links", "parent_region_id" })
public static Region create(String id, String description, Link link, String parentRegionId) {
return builder().id(id).description(description).link(link).parentRegionId(parentRegionId).build();
}
Region() {
}
public abstract Builder toBuilder();
public static Builder builder() {
return new AutoValue_Region.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder id(String id);
public abstract Builder description(String name);
public abstract Builder link(Link link);
public abstract Builder parentRegionId(String parentRegionId);
public abstract Region build();
}
}

View File

@ -0,0 +1,87 @@
/*
* 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.v3.domain;
import java.util.Date;
import java.util.List;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames;
import org.jclouds.openstack.keystone.auth.domain.AuthInfo;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
@AutoValue
public abstract class Token implements AuthInfo {
@Nullable public abstract String id();
public abstract List<String> methods();
@Nullable public abstract Date expiresAt();
@Nullable public abstract Object extras();
@Nullable public abstract List<Catalog> catalog();
@Nullable public abstract List<String> auditIds();
public abstract User user();
public abstract Date issuedAt();
@Override
public String getAuthToken() {
return id();
}
@SerializedNames({ "id", "methods", "expires_at", "extras", "catalog", "audit_ids", "user", "issued_at" })
private static Token create(String id, List<String> methods, Date expiresAt, Object extras, List<Catalog> catalog,
List<String> auditIds, User user, Date issuedAt) {
return builder().id(id).methods(methods).expiresAt(expiresAt).extras(extras).catalog(catalog).auditIds(auditIds)
.user(user).issuedAt(issuedAt).build();
}
Token() {
}
public abstract Builder toBuilder();
public static Builder builder() {
return new AutoValue_Token.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder id(String id);
public abstract Builder methods(List<String> methods);
public abstract Builder expiresAt(Date expiresAt);
public abstract Builder extras(Object extras);
public abstract Builder catalog(List<Catalog> catalog);
public abstract Builder auditIds(List<String> auditIds);
public abstract Builder user(User user);
public abstract Builder issuedAt(Date issuedAt);
abstract List<Catalog> catalog();
abstract List<String> methods();
abstract List<String> auditIds();
abstract Token autoBuild();
public Token build() {
return catalog(catalog() != null ? ImmutableList.copyOf(catalog()) : ImmutableList.<Catalog>of())
.methods(methods() != null ? ImmutableList.copyOf(methods()) : ImmutableList.<String>of())
.auditIds(auditIds() != null ? ImmutableList.copyOf(auditIds()) : ImmutableList.<String>of())
.autoBuild();
}
}
}

View File

@ -0,0 +1,77 @@
/*
* 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.v3.domain;
import java.util.Date;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.SerializedNames;
import com.google.auto.value.AutoValue;
@AutoValue
public abstract class User {
@AutoValue
public abstract static class Domain {
public abstract String id();
public abstract String name();
@SerializedNames({ "id", "name" })
public static Domain create(String id, String name) {
return new AutoValue_User_Domain(id, name);
}
}
public abstract String id();
public abstract String name();
@Nullable public abstract Date passwordExpiresAt();
@Nullable public abstract Domain domain();
@Nullable public abstract String domainId();
@Nullable public abstract String defaultProjectId();
@Nullable public abstract Boolean enabled();
@Nullable public abstract Link link();
@SerializedNames({ "id", "name", "password_expires_at", "domain", "domain_id", "default_project_id", "enabled", "links" })
public static User create(String id, String name, Date passwordExpiresAt, Domain domain, String domainId,
String defaultProjectId, Boolean enabled, Link link) {
return builder().id(id).name(name).passwordExpiresAt(passwordExpiresAt).domain(domain).domainId(domainId)
.defaultProjectId(defaultProjectId).enabled(enabled).link(link).build();
}
User() {
}
public abstract Builder toBuilder();
public static Builder builder() {
return new AutoValue_User.Builder();
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder id(String id);
public abstract Builder name(String name);
public abstract Builder passwordExpiresAt(Date passwordExpiresAt);
public abstract Builder domain(Domain domain);
public abstract Builder domainId(String domainId);
public abstract Builder defaultProjectId(String defaultProjectId);
public abstract Builder enabled(Boolean enabled);
public abstract Builder link(Link link);
public abstract User build();
}
}

View File

@ -0,0 +1,84 @@
/*
* 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.v3.features;
import javax.inject.Named;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.HEAD;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.MediaType;
import org.jclouds.Fallbacks.FalseOnNotFoundOr404;
import org.jclouds.Fallbacks.NullOnNotFoundOr404;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.keystone.auth.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.v3.domain.Token;
import org.jclouds.openstack.keystone.v3.domain.User;
import org.jclouds.openstack.v2_0.services.Identity;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.annotations.Headers;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SelectJson;
/**
* Provides access to the Keystone Authentication API.
*/
@Consumes(MediaType.APPLICATION_JSON)
@RequestFilters(AuthenticateRequest.class)
@Endpoint(Identity.class)
@Path("/auth")
public interface AuthApi {
/**
* Validate a token and, if it is valid, return access information regarding the tenant (though not the service catalog).
*/
@Named("token:get")
@GET
@SelectJson("token")
@Path("/tokens")
@Fallback(NullOnNotFoundOr404.class)
@Nullable
@Headers(keys = "X-Subject-Token", values = "{token}")
Token get(@PathParam("token") String token);
/**
* Validate a token and, if it is valid, return access information regarding the tenant (though not the service catalog).
*/
@Named("token:getuser")
@GET
@SelectJson("user")
@Path("/tokens")
@Fallback(NullOnNotFoundOr404.class)
@Nullable
@Headers(keys = "X-Subject-Token", values = "{token}")
User getUserOfToken(@PathParam("token") String token);
/**
* Validate a token. This is a high-performance variant of the #getToken() call that does not return any further
* information.
*/
@Named("token:check")
@HEAD
@Path("/tokens")
@Headers(keys = "X-Subject-Token", values = "{token}")
@Fallback(FalseOnNotFoundOr404.class)
boolean isValid(@PathParam("token") String token);
}

View File

@ -0,0 +1,54 @@
/*
* 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.v3.features;
import java.util.List;
import javax.inject.Named;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
import org.jclouds.openstack.keystone.auth.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.v3.domain.Endpoint;
import org.jclouds.openstack.v2_0.services.Identity;
import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SelectJson;
/**
* Provides access to the Keystone Admin API.
*/
@Consumes(MediaType.APPLICATION_JSON)
@RequestFilters(AuthenticateRequest.class)
@org.jclouds.rest.annotations.Endpoint(Identity.class)
public interface CatalogApi {
/**
* List all endpoints for a token.
* <p>
* NOTE: currently not working in openstack ( https://bugs.launchpad.net/keystone/+bug/988672 )
*/
@Named("endpoints:list")
@GET
@SelectJson("endpoints")
@Path("/endpoints")
@Fallback(EmptyListOnNotFoundOr404.class)
List<Endpoint> endpoints();
}

View File

@ -0,0 +1,124 @@
/*
* 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.v3.features;
import java.util.List;
import java.util.Set;
import javax.inject.Named;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.HEAD;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.MediaType;
import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
import org.jclouds.Fallbacks.FalseOnNotFoundOr404;
import org.jclouds.Fallbacks.NullOnNotFoundOr404;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.keystone.auth.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.v3.domain.Project;
import org.jclouds.openstack.v2_0.services.Identity;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.annotations.MapBinder;
import org.jclouds.rest.annotations.PATCH;
import org.jclouds.rest.annotations.PayloadParam;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SelectJson;
import org.jclouds.rest.annotations.WrapWith;
import org.jclouds.rest.binders.BindToJsonPayload;
/**
* Provides access to the Keystone Projects API.
*/
@Consumes(MediaType.APPLICATION_JSON)
@RequestFilters(AuthenticateRequest.class)
@Endpoint(Identity.class)
@Path("/projects")
public interface ProjectApi {
@Named("projects:list")
@GET
@SelectJson("projects")
@Fallback(EmptyListOnNotFoundOr404.class)
List<Project> list();
@Named("projects:get")
@GET
@Path("/{id}")
@SelectJson("project")
@Fallback(NullOnNotFoundOr404.class)
Project get(@PathParam("id") String id);
@Named("projects:create")
@POST
@SelectJson("project")
@WrapWith("project")
Project create(@PayloadParam("name") String name, @Nullable @PayloadParam("description") String description,
@PayloadParam("enabled") boolean enabled, @PayloadParam("is_domain") boolean isDomain,
@Nullable @PayloadParam("domain_id") String domainId, @Nullable @PayloadParam("parent_id") String parentId);
@Named("projects:update")
@PATCH
@Path("/{id}")
@SelectJson("project")
Project update(@PathParam("id") String id, @WrapWith("project") Project project);
@Named("projects:delete")
@DELETE
@Path("/{id}")
@Fallback(FalseOnNotFoundOr404.class)
boolean delete(@PathParam("id") String id);
@Named("projects:listTags")
@GET
@Path("/{projectId}/tags")
@SelectJson("tags")
Set<String> listTags(@PathParam("projectId") String projectId);
@Named("projects:hasTag")
@HEAD
@Path("/{projectId}/tags/{tag}")
@Fallback(FalseOnNotFoundOr404.class)
boolean hasTag(@PathParam("projectId") String projectId, @PathParam("tag") String tag);
@Named("projects:addTag")
@PUT
@Path("/{projectId}/tags/{tag}")
void addTag(@PathParam("projectId") String projectId, @PathParam("tag") String tag);
@Named("projects:removeTag")
@DELETE
@Path("/{projectId}/tags/{tag}")
void removeTag(@PathParam("projectId") String projectId, @PathParam("tag") String tag);
@Named("projects:setTags")
@PUT
@Path("/{projectId}/tags")
@MapBinder(BindToJsonPayload.class)
void setTags(@PathParam("projectId") String projectId, @PayloadParam("tags") Set<String> tags);
@Named("projects:removeTags")
@DELETE
@Path("/{projectId}/tags")
void removeAllTags(@PathParam("projectId") String projectId);
}

View File

@ -0,0 +1,87 @@
/*
* 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.v3.features;
import java.util.List;
import javax.inject.Named;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.MediaType;
import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
import org.jclouds.Fallbacks.FalseOnNotFoundOr404;
import org.jclouds.Fallbacks.NullOnNotFoundOr404;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.keystone.auth.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.v3.domain.Region;
import org.jclouds.openstack.v2_0.services.Identity;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.annotations.PATCH;
import org.jclouds.rest.annotations.PayloadParam;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SelectJson;
import org.jclouds.rest.annotations.WrapWith;
/**
* Provides access to the Keystone Region API.
*/
@Consumes(MediaType.APPLICATION_JSON)
@RequestFilters(AuthenticateRequest.class)
@Endpoint(Identity.class)
@Path("/regions")
public interface RegionApi {
@Named("regions:list")
@GET
@SelectJson("regions")
@Fallback(EmptyListOnNotFoundOr404.class)
List<Region> list();
@Named("regions:get")
@GET
@Path("/{id}")
@SelectJson("region")
@Fallback(NullOnNotFoundOr404.class)
Region get(@PathParam("id") String id);
@Named("regions:create")
@POST
@SelectJson("region")
@WrapWith("region")
Region create(@PayloadParam("id") String id, @Nullable @PayloadParam("description") String description,
@Nullable @PayloadParam("parent_region_id") String parentId);
@Named("regions:update")
@PATCH
@Path("/{id}")
@SelectJson("region")
@WrapWith("region")
Region update(@PathParam("id") String id, @Nullable @PayloadParam("description") String description,
@Nullable @PayloadParam("parent_region_id") String parentId);
@Named("regions:delete")
@DELETE
@Path("/{id}")
@Fallback(FalseOnNotFoundOr404.class)
boolean delete(@PathParam("id") String id);
}

View File

@ -0,0 +1,111 @@
/*
* 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.v3.features;
import java.util.List;
import javax.inject.Named;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.MediaType;
import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
import org.jclouds.Fallbacks.FalseOnNotFoundOr404;
import org.jclouds.Fallbacks.NullOnNotFoundOr404;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.keystone.auth.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.v3.domain.Group;
import org.jclouds.openstack.keystone.v3.domain.Project;
import org.jclouds.openstack.keystone.v3.domain.User;
import org.jclouds.openstack.v2_0.services.Identity;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.annotations.PATCH;
import org.jclouds.rest.annotations.PayloadParam;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SelectJson;
import org.jclouds.rest.annotations.WrapWith;
/**
* Provides access to the Keystone User API.
*/
@Consumes(MediaType.APPLICATION_JSON)
@RequestFilters(AuthenticateRequest.class)
@Endpoint(Identity.class)
@Path("/users")
public interface UserApi {
@Named("users:list")
@GET
@SelectJson("users")
@Fallback(EmptyListOnNotFoundOr404.class)
List<User> list();
@Named("users:get")
@GET
@Path("/{id}")
@SelectJson("user")
@Fallback(NullOnNotFoundOr404.class)
User get(@PathParam("id") String id);
@Named("users:create")
@POST
@SelectJson("user")
@WrapWith("user")
User create(@PayloadParam("name") String name, @Nullable @PayloadParam("password") String password,
@Nullable @PayloadParam("enabled") Boolean enabled, @Nullable @PayloadParam("domain_id") String domainId,
@Nullable @PayloadParam("default_project_id") String defaultProjectId);
@Named("users:update")
@PATCH
@Path("/{id}")
@SelectJson("user")
@WrapWith("user")
User update(@PathParam("id") String id, @PayloadParam("name") String name,
@Nullable @PayloadParam("password") String password, @Nullable @PayloadParam("enabled") Boolean enabled,
@Nullable @PayloadParam("domain_id") String domainId,
@Nullable @PayloadParam("default_project_id") String defaultProjectId);
@Named("users:delete")
@DELETE
@Path("/{id}")
@Fallback(FalseOnNotFoundOr404.class)
boolean delete(@PathParam("id") String id);
@Named("users:groups")
@GET
@Path("/{id}/groups")
@SelectJson("groups")
List<Group> listGroups(@PathParam("id") String id);
@Named("users:projects")
@GET
@Path("/{id}/projects")
@SelectJson("projects")
List<Project> listProjects(@PathParam("id") String id);
@Named("users:password")
@POST
@Path("/{id}/password")
@WrapWith("user")
void changePassword(@PathParam("id") String id, @PayloadParam("original_password") String originalPassword,
@PayloadParam("password") String newPassword);
}

View File

@ -0,0 +1,49 @@
/*
* 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.v3.parsers;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Singleton;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.ParseFirstJsonValueNamed;
import org.jclouds.json.internal.GsonWrapper;
import org.jclouds.openstack.keystone.v3.domain.Token;
import com.google.common.base.Function;
import com.google.inject.Inject;
import com.google.inject.TypeLiteral;
@Singleton
public class ParseTokenFromHttpResponse implements Function<HttpResponse, Token> {
private final ParseFirstJsonValueNamed<Token> parser;
@Inject
ParseTokenFromHttpResponse(GsonWrapper gsonView) {
this.parser = new ParseFirstJsonValueNamed<Token>(gsonView, TypeLiteral.get(Token.class), "token");
}
public Token apply(HttpResponse response) {
checkNotNull(response, "response");
Token toParse = parser.apply(response);
checkNotNull(toParse, "parsed result from %s", response);
String xSubjectToken = response.getFirstHeaderOrNull("X-Subject-Token");
return toParse.toBuilder().id(xSubjectToken).build();
}
}

View File

@ -28,7 +28,7 @@ import javax.ws.rs.core.MediaType;
import org.jclouds.Fallbacks.EmptySetOnNotFoundOr404;
import org.jclouds.Fallbacks.NullOnNotFoundOr404;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
import org.jclouds.openstack.keystone.auth.filters.AuthenticateRequest;
import org.jclouds.openstack.v2_0.domain.Extension;
import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.annotations.RequestFilters;

View File

@ -14,11 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.config;
package org.jclouds.openstack.keystone.auth.config;
import static org.testng.Assert.assertEquals;
import org.jclouds.openstack.keystone.v2_0.domain.PasswordCredentials;
import org.jclouds.openstack.keystone.auth.domain.PasswordCredentials;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
@ -27,8 +27,9 @@ import com.google.common.collect.ImmutableSet;
public class CredentialTypesTest {
public void testCredentialTypeOfWhenValid() {
assertEquals(CredentialTypes.credentialTypeOf(PasswordCredentials.createWithUsernameAndPassword("username",
"password")), CredentialTypes.PASSWORD_CREDENTIALS);
assertEquals(
CredentialTypes.credentialTypeOf(PasswordCredentials.builder().username("username").password("password")
.build()), CredentialTypes.PASSWORD_CREDENTIALS);
}
@Test(expectedExceptions = IllegalArgumentException.class)
@ -37,9 +38,10 @@ public class CredentialTypesTest {
}
public void testIndexByCredentialTypeWhenValid() {
assertEquals(CredentialTypes.indexByCredentialType(
ImmutableSet.of(PasswordCredentials.createWithUsernameAndPassword("username", "password"))).keySet(),
ImmutableSet.of(CredentialTypes.PASSWORD_CREDENTIALS));
assertEquals(
CredentialTypes.indexByCredentialType(
ImmutableSet.of(PasswordCredentials.builder().username("username").password("password").build()))
.keySet(), ImmutableSet.of(CredentialTypes.PASSWORD_CREDENTIALS));
}
@Test(expectedExceptions = IllegalArgumentException.class)

View File

@ -14,12 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.config;
package org.jclouds.openstack.keystone.auth.config;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
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.KEYSTONE_VERSION;
import static org.jclouds.openstack.keystone.config.KeystoneProperties.SERVICE_TYPE;
import static org.jclouds.util.Suppliers2.getLastValueInMap;
import static org.testng.Assert.assertTrue;
@ -42,8 +43,10 @@ import org.jclouds.http.HttpResponse;
import org.jclouds.json.config.GsonModule.DateAdapter;
import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
import org.jclouds.location.suppliers.RegionIdToURISupplier;
import org.jclouds.openstack.keystone.catalog.config.ServiceCatalogModule;
import org.jclouds.openstack.keystone.catalog.config.ServiceCatalogModule.ProviderModule;
import org.jclouds.openstack.keystone.catalog.config.ServiceCatalogModule.RegionModule;
import org.jclouds.openstack.keystone.v2_0.KeystoneApi;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.RegionModule;
import org.jclouds.openstack.keystone.v2_0.internal.BaseKeystoneRestApiExpectTest;
import org.jclouds.rest.ConfiguresHttpApi;
import org.jclouds.rest.annotations.ApiVersion;
@ -124,6 +127,7 @@ public class ProviderModuleExpectTest extends BaseRestApiExpectTest<ProviderModu
public static Properties defaultProperties() {
Properties properties = BaseHttpApiMetadata.defaultProperties();
properties.setProperty(SERVICE_TYPE, "dns");
properties.setProperty(KEYSTONE_VERSION, "2");
properties.setProperty(CREDENTIAL_TYPE, CredentialTypes.PASSWORD_CREDENTIALS);
return properties;
}
@ -141,8 +145,8 @@ public class ProviderModuleExpectTest extends BaseRestApiExpectTest<ProviderModu
.defaultEndpoint("http://localhost:5000/v2.0/")
.defaultProperties(DNSApiMetadata.defaultProperties())
.defaultModules(ImmutableSet.<Class<? extends Module>>builder()
.add(AuthenticationApiModule.class)
.add(KeystoneAuthenticationModule.class)
.add(AuthenticationModule.class)
.add(ServiceCatalogModule.class)
.add(RegionModule.class)
.add(DNSHttpApiModule.class).build());
}

View File

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.handlers;
package org.jclouds.openstack.keystone.auth.handlers;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
@ -30,7 +30,7 @@ import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
import org.jclouds.io.Payloads;
import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.auth.domain.AuthInfo;
import org.testng.annotations.Test;
import com.google.common.cache.LoadingCache;
@ -46,7 +46,7 @@ public class RetryOnRenewTest {
HttpRequest request = createMock(HttpRequest.class);
HttpResponse response = createMock(HttpResponse.class);
@SuppressWarnings("unchecked")
LoadingCache<Credentials, Access> cache = createMock(LoadingCache.class);
LoadingCache<Credentials, AuthInfo> cache = createMock(LoadingCache.class);
BackoffLimitedRetryHandler backoffHandler = createMock(BackoffLimitedRetryHandler.class);
expect(command.getCurrentRequest()).andReturn(request);
@ -78,7 +78,7 @@ public class RetryOnRenewTest {
HttpResponse response = createMock(HttpResponse.class);
@SuppressWarnings("unchecked")
LoadingCache<Credentials, Access> cache = createMock(LoadingCache.class);
LoadingCache<Credentials, AuthInfo> cache = createMock(LoadingCache.class);
BackoffLimitedRetryHandler backoffHandler = createMock(BackoffLimitedRetryHandler.class);
expect(command.getCurrentRequest()).andReturn(request).anyTimes();
@ -108,7 +108,7 @@ public class RetryOnRenewTest {
HttpCommand command = createMock(HttpCommand.class);
HttpResponse response = createMock(HttpResponse.class);
@SuppressWarnings("unchecked")
LoadingCache<Credentials, Access> cache = createMock(LoadingCache.class);
LoadingCache<Credentials, AuthInfo> cache = createMock(LoadingCache.class);
BackoffLimitedRetryHandler backoffHandler = createMock(BackoffLimitedRetryHandler.class);
expect(backoffHandler.shouldRetryRequest(command, response)).andReturn(true).once();

View File

@ -0,0 +1,139 @@
/*
* 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.suppliers;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import javax.inject.Singleton;
import org.jclouds.location.Provider;
import org.jclouds.openstack.keystone.auth.domain.AuthInfo;
import org.jclouds.openstack.keystone.catalog.ServiceEndpoint;
import org.jclouds.openstack.keystone.catalog.suppliers.LocationIdToURIFromServiceEndpointsForTypeAndVersion;
import org.jclouds.openstack.keystone.v2_0.catalog.V2ServiceCatalog;
import org.jclouds.openstack.keystone.v2_0.parse.ParseAccessTest;
import org.jclouds.openstack.keystone.v2_0.parse.ParseRackspaceAccessTest;
import org.testng.annotations.Test;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Provides;
import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.FactoryModuleBuilder;
@Test(groups = "unit", testName = "LocationIdToURIFromAccessForTypeAndVersionTest")
public class LocationIdToURIFromAccessForTypeAndVersionTest {
private final LocationIdToURIFromServiceEndpointsForTypeAndVersion.Factory factory = Guice.createInjector(
new AbstractModule() {
@Override
protected void configure() {
bindConstant().annotatedWith(Provider.class).to("openstack-keystone");
bind(new TypeLiteral<Supplier<URI>>() {
}).annotatedWith(Provider.class).toInstance(Suppliers.ofInstance(URI.create("https://identity")));
install(new FactoryModuleBuilder().implement(LocationIdToURIFromServiceEndpointsForTypeAndVersion.class,
LocationIdToURIFromServiceEndpointsForTypeAndVersion.class).build(
LocationIdToURIFromServiceEndpointsForTypeAndVersion.Factory.class));
// We test against a 2.0 service catalog but it is OK for the purpose of this test
bind(new TypeLiteral<Supplier<List<ServiceEndpoint>>>() {
}).to(V2ServiceCatalog.class).in(Scopes.SINGLETON);
}
@Provides
@Singleton
public Supplier<AuthInfo> provide() {
return Suppliers.<AuthInfo> ofInstance(new ParseAccessTest().expected());
}
}).getInstance(LocationIdToURIFromServiceEndpointsForTypeAndVersion.Factory.class);
public void testRegionUnmatchesOkWhenNoVersionIdSet() {
assertEquals(
Maps.transformValues(factory.createForApiTypeAndVersion("compute", "2").get(),
Suppliers.<URI> supplierFunction()),
ImmutableMap.of("az-1.region-a.geo-1",
URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v2/3456"), "az-2.region-a.geo-1",
URI.create("https://az-2.region-a.geo-1.compute.hpcloudsvc.com/v2/3456"), "az-3.region-a.geo-1",
URI.create("https://az-3.region-a.geo-1.compute.hpcloudsvc.com/v2/3456")));
}
public void testRegionMatches() {
assertEquals(
Maps.transformValues(factory.createForApiTypeAndVersion("compute", "2").get(),
Suppliers.<URI> supplierFunction()),
ImmutableMap.of("az-1.region-a.geo-1",
URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v2/3456"), "az-2.region-a.geo-1",
URI.create("https://az-2.region-a.geo-1.compute.hpcloudsvc.com/v2/3456"), "az-3.region-a.geo-1",
URI.create("https://az-3.region-a.geo-1.compute.hpcloudsvc.com/v2/3456")));
}
private final LocationIdToURIFromServiceEndpointsForTypeAndVersion.Factory raxFactory = Guice.createInjector(
new AbstractModule() {
@Override
protected void configure() {
bindConstant().annotatedWith(Provider.class).to("rackspace");
bind(new TypeLiteral<Supplier<URI>>() {
}).annotatedWith(Provider.class).toInstance(Suppliers.ofInstance(URI.create("https://identity")));
install(new FactoryModuleBuilder().implement(LocationIdToURIFromServiceEndpointsForTypeAndVersion.class,
LocationIdToURIFromServiceEndpointsForTypeAndVersion.class).build(
LocationIdToURIFromServiceEndpointsForTypeAndVersion.Factory.class));
// We test against a 2.0 service catalog but it is OK for the purpose of this test
bind(new TypeLiteral<Supplier<List<ServiceEndpoint>>>() {
}).to(V2ServiceCatalog.class).in(Scopes.SINGLETON);
}
@Provides
@Singleton
public Supplier<AuthInfo> provide() {
return Suppliers.<AuthInfo> ofInstance(new ParseRackspaceAccessTest().expected());
}
}).getInstance(LocationIdToURIFromServiceEndpointsForTypeAndVersion.Factory.class);
@Test(expectedExceptions = NoSuchElementException.class)
public void testWhenNotInList() {
assertEquals(
Maps.transformValues(raxFactory.createForApiTypeAndVersion("goo", "1.0").get(),
Suppliers.<URI> supplierFunction()),
ImmutableMap.of("rackspace", URI.create("https://servers.api.rackspacecloud.com/v1.0/40806637803162")));
}
public void testProviderWhenNoRegions() {
Map<String, URI> withNoRegions = Maps.transformValues(raxFactory.createForApiTypeAndVersion("compute", "1.0")
.get(), Suppliers.<URI> supplierFunction());
assertEquals(withNoRegions,
ImmutableMap.of("rackspace", URI.create("https://servers.api.rackspacecloud.com/v1.0/40806637803162")));
}
public void testOkWithNoVersions() {
assertEquals(Maps.transformValues(raxFactory.createForApiTypeAndVersion("rax:database", null).get(),
Suppliers.<URI> supplierFunction()), ImmutableMap.of("DFW",
URI.create("https://dfw.databases.api.rackspacecloud.com/v1.0/40806637803162"), "ORD",
URI.create("https://ord.databases.api.rackspacecloud.com/v1.0/40806637803162")));
}
}

View File

@ -14,18 +14,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.suppliers;
package org.jclouds.openstack.keystone.auth.suppliers;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import javax.inject.Singleton;
import org.jclouds.location.Provider;
import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.auth.domain.AuthInfo;
import org.jclouds.openstack.keystone.catalog.ServiceEndpoint;
import org.jclouds.openstack.keystone.catalog.suppliers.RegionIdToAdminURIFromServiceEndpointsForTypeAndVersion;
import org.jclouds.openstack.keystone.catalog.suppliers.RegionIdToAdminURISupplier;
import org.jclouds.openstack.keystone.v2_0.catalog.V2ServiceCatalog;
import org.jclouds.openstack.keystone.v2_0.parse.ParseAccessTest;
import org.jclouds.openstack.keystone.v2_0.parse.ParseRackspaceAccessTest;
import org.testng.annotations.Test;
@ -37,6 +42,7 @@ import com.google.common.collect.Maps;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Provides;
import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.FactoryModuleBuilder;
@ -50,13 +56,16 @@ public class RegionIdToAdminURIFromAccessForTypeAndVersionTest {
bind(new TypeLiteral<Supplier<URI>>() {
}).annotatedWith(Provider.class).toInstance(Suppliers.ofInstance(URI.create("https://identity")));
install(new FactoryModuleBuilder().implement(RegionIdToAdminURISupplier.class,
RegionIdToAdminURIFromAccessForTypeAndVersion.class).build(RegionIdToAdminURISupplier.Factory.class));
RegionIdToAdminURIFromServiceEndpointsForTypeAndVersion.class).build(RegionIdToAdminURISupplier.Factory.class));
// We test against a 2.0 service catalog but it is OK for the purpose of this test
bind(new TypeLiteral<Supplier<List<ServiceEndpoint>>>() {
}).to(V2ServiceCatalog.class).in(Scopes.SINGLETON);
}
@Provides
@Singleton
public Supplier<Access> provide() {
return Suppliers.ofInstance(new ParseAccessTest().expected());
public Supplier<AuthInfo> provide() {
return Suppliers.<AuthInfo> ofInstance(new ParseAccessTest().expected());
}
}).getInstance(RegionIdToAdminURISupplier.Factory.class);
@ -79,13 +88,16 @@ public class RegionIdToAdminURIFromAccessForTypeAndVersionTest {
bind(new TypeLiteral<Supplier<URI>>() {
}).annotatedWith(Provider.class).toInstance(Suppliers.ofInstance(URI.create("https://identity")));
install(new FactoryModuleBuilder().implement(RegionIdToAdminURISupplier.class,
RegionIdToAdminURIFromAccessForTypeAndVersion.class).build(RegionIdToAdminURISupplier.Factory.class));
RegionIdToAdminURIFromServiceEndpointsForTypeAndVersion.class).build(RegionIdToAdminURISupplier.Factory.class));
// We test against a 2.0 service catalog but it is OK for the purpose of this test
bind(new TypeLiteral<Supplier<List<ServiceEndpoint>>>() {
}).to(V2ServiceCatalog.class).in(Scopes.SINGLETON);
}
@Provides
@Singleton
public Supplier<Access> provide() {
return Suppliers.ofInstance(new ParseRackspaceAccessTest().expected());
public Supplier<AuthInfo> provide() {
return Suppliers.<AuthInfo> ofInstance(new ParseRackspaceAccessTest().expected());
}
}).getInstance(RegionIdToAdminURISupplier.Factory.class);

View File

@ -14,18 +14,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.suppliers;
package org.jclouds.openstack.keystone.auth.suppliers;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import java.util.List;
import java.util.NoSuchElementException;
import javax.inject.Singleton;
import org.jclouds.location.Provider;
import org.jclouds.location.suppliers.RegionIdToURISupplier;
import org.jclouds.openstack.keystone.v2_0.domain.Access;
import org.jclouds.openstack.keystone.auth.domain.AuthInfo;
import org.jclouds.openstack.keystone.catalog.ServiceEndpoint;
import org.jclouds.openstack.keystone.catalog.suppliers.RegionIdToURIFromServiceEndpointsForTypeAndVersion;
import org.jclouds.openstack.keystone.v2_0.catalog.V2ServiceCatalog;
import org.jclouds.openstack.keystone.v2_0.parse.ParseAccessTest;
import org.jclouds.openstack.keystone.v2_0.parse.ParseRackspaceAccessTest;
import org.testng.annotations.Test;
@ -37,6 +41,7 @@ import com.google.common.collect.Maps;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Provides;
import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.FactoryModuleBuilder;
@ -50,18 +55,20 @@ public class RegionIdToURIFromAccessForTypeAndVersionTest {
bind(new TypeLiteral<Supplier<URI>>() {
}).annotatedWith(Provider.class).toInstance(Suppliers.ofInstance(URI.create("https://identity")));
install(new FactoryModuleBuilder().implement(RegionIdToURISupplier.class,
RegionIdToURIFromAccessForTypeAndVersion.class).build(
RegionIdToURIFromServiceEndpointsForTypeAndVersion.class).build(
RegionIdToURISupplier.Factory.class));
// We test against a 2.0 service catalog but it is OK for the purpose of this test
bind(new TypeLiteral<Supplier<List<ServiceEndpoint>>>() {
}).to(V2ServiceCatalog.class).in(Scopes.SINGLETON);
}
@Provides
@Singleton
public Supplier<Access> provide() {
return Suppliers.ofInstance(new ParseAccessTest().expected());
public Supplier<AuthInfo> provide() {
return Suppliers.<AuthInfo> ofInstance(new ParseAccessTest().expected());
}
}).getInstance(RegionIdToURISupplier.Factory.class);
@SuppressWarnings("CheckReturnValue")
@Test(expectedExceptions = NoSuchElementException.class)
public void testRegionUnmatches() {
Maps.transformValues(factory.createForApiTypeAndVersion("compute", "1.0").get(),
@ -84,14 +91,17 @@ public class RegionIdToURIFromAccessForTypeAndVersionTest {
bind(new TypeLiteral<Supplier<URI>>() {
}).annotatedWith(Provider.class).toInstance(Suppliers.ofInstance(URI.create("https://identity")));
install(new FactoryModuleBuilder().implement(RegionIdToURISupplier.class,
RegionIdToURIFromAccessForTypeAndVersion.class).build(
RegionIdToURIFromServiceEndpointsForTypeAndVersion.class).build(
RegionIdToURISupplier.Factory.class));
// We test against a 2.0 service catalog but it is OK for the purpose of this test
bind(new TypeLiteral<Supplier<List<ServiceEndpoint>>>() {
}).to(V2ServiceCatalog.class).in(Scopes.SINGLETON);
}
@Provides
@Singleton
public Supplier<Access> provide() {
return Suppliers.ofInstance(new ParseRackspaceAccessTest().expected());
public Supplier<AuthInfo> provide() {
return Suppliers.<AuthInfo> ofInstance(new ParseRackspaceAccessTest().expected());
}
}).getInstance(RegionIdToURISupplier.Factory.class);

View File

@ -0,0 +1,54 @@
/*
* 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.functions;
import static org.jclouds.openstack.keystone.catalog.ServiceEndpoint.Interface.ADMIN;
import static org.jclouds.openstack.keystone.catalog.ServiceEndpoint.Interface.PUBLIC;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import java.util.Collections;
import org.jclouds.openstack.keystone.catalog.ServiceEndpoint;
import org.testng.annotations.Test;
@Test(groups = "unit", testName = "AdminURLTest")
public class AdminURLTest {
private final AdminURL fn = new AdminURL();
public void testAdminURL() {
assertEquals(
fn.apply(
Collections.singletonList(ServiceEndpoint
.builder()
.type("cdn")
.regionId("LON")
.version("1.0")
.url(URI
.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"))
.iface(ADMIN).build())).get(),
URI.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"));
}
public void testReturnsNullIfNotAdminURI() {
assertEquals(
fn.apply(
Collections.singletonList(ServiceEndpoint.builder().type("cdn").regionId("LON").version("1.0")
.url(URI.create("https://192.168.1.1")).iface(PUBLIC).build())).get(), null);
}
}

View File

@ -14,13 +14,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.functions;
package org.jclouds.openstack.keystone.catalog.functions;
import static org.jclouds.openstack.keystone.catalog.ServiceEndpoint.Interface.INTERNAL;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import java.util.Collections;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import org.jclouds.openstack.keystone.catalog.ServiceEndpoint;
import org.testng.annotations.Test;
/**
@ -31,9 +33,10 @@ public class InternalURLTest {
public void testInternalURL() {
assertEquals(
fn.apply(
Endpoint.builder().region("regionOne").versionId("2.0")
.internalURL(URI.create("https://ericsson.com/v2/1900e98b-7272-4cbd-8e95-0b8c2a9266c0"))
.build()).get(), URI.create("https://ericsson.com/v2/1900e98b-7272-4cbd-8e95-0b8c2a9266c0"));
fn.apply(Collections.singletonList(ServiceEndpoint.builder().type("cdn").regionId("regionOne")
.version("2.0")
.url(URI.create("https://ericsson.com/v2/1900e98b-7272-4cbd-8e95-0b8c2a9266c0"))
.iface(INTERNAL).build())).get(),
URI.create("https://ericsson.com/v2/1900e98b-7272-4cbd-8e95-0b8c2a9266c0"));
}
}

View File

@ -0,0 +1,54 @@
/*
* 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.functions;
import static org.jclouds.openstack.keystone.catalog.ServiceEndpoint.Interface.INTERNAL;
import static org.jclouds.openstack.keystone.catalog.ServiceEndpoint.Interface.PUBLIC;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import java.util.Collections;
import org.jclouds.openstack.keystone.catalog.ServiceEndpoint;
import org.testng.annotations.Test;
@Test(groups = "unit", testName = "PublicURLOrInternalTest")
public class PublicURLOrInternalTest {
private final PublicURLOrInternal fn = new PublicURLOrInternal();
public void testPublicURLNotNullReturnsPublicURL() {
assertEquals(
fn.apply(
Collections.singletonList(ServiceEndpoint
.builder()
.type("cdn")
.regionId("LON")
.version("1.0")
.url(URI
.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"))
.iface(PUBLIC).build())).get(),
URI.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"));
}
public void testPublicURLNullReturnsInternalURL() {
assertEquals(
fn.apply(
Collections.singletonList(ServiceEndpoint.builder().type("cdn").regionId("LON").version("1.0")
.url(URI.create("https://192.168.1.1")).iface(INTERNAL).build())).get(),
URI.create("https://192.168.1.1"));
}
}

View File

@ -14,13 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.keystone.v2_0.functions;
package org.jclouds.openstack.keystone.catalog.functions;
import static org.jclouds.openstack.keystone.catalog.ServiceEndpoint.Interface.PUBLIC;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import org.jclouds.openstack.keystone.v2_0.domain.Endpoint;
import org.jclouds.openstack.keystone.catalog.ServiceEndpoint;
import org.testng.annotations.Test;
@Test(groups = "unit", testName = "ReturnRegionOrProviderTest")
@ -29,16 +30,16 @@ public class ReturnRegionOrProviderTest {
public void testRegionNotNullReturnsRegion() {
assertEquals(
fn.apply(Endpoint.builder().region("LON").versionId("1.0").publicURL(
URI.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"))
.build()), "LON");
fn.apply(ServiceEndpoint.builder().type("cdn").regionId("LON").version("1.0")
.url(URI.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"))
.iface(PUBLIC).build()), "LON");
}
public void testRegionNullReturnsProvider() {
assertEquals(
fn.apply(Endpoint.builder().versionId("1.0").publicURL(
URI.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"))
.build()), "openstack-keystone");
fn.apply(ServiceEndpoint.builder().type("cdn").version("1.0")
.url(URI.create("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953"))
.iface(PUBLIC).build()), "openstack-keystone");
}
}

Some files were not shown because too many files have changed in this diff Show More