Skip to content

Commit

Permalink
introduce KeystoneProperties/TENANT_NAME KeystoneProperties/TENANT_ID…
Browse files Browse the repository at this point in the history
… properties; set value of prefix to tenantName
  • Loading branch information
Adrian Cole committed Jun 19, 2012
1 parent f686737 commit b5797ad
Show file tree
Hide file tree
Showing 45 changed files with 461 additions and 227 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,25 @@ public interface KeystoneProperties {
* />
*/
public static final String CREDENTIAL_TYPE = "jclouds.keystone.credential-type";


/**
* set this property to specify the tenant id of the authenticated user. Cannot be used simultaneously with {@link #TENANT_NAME}
* @see <a href="http://wiki.openstack.org/CLIAuth">openstack docs</a>
*/
public static final String TENANT_ID = "jclouds.keystone.tenant-id";

/**
* set this property to specify the tenant name of the authenticated user. Cannot be used simultaneously with {@link #TENANT_ID}
* @see <a href="http://wiki.openstack.org/CLIAuth">openstack docs</a>
*/
public static final String TENANT_NAME = "jclouds.keystone.tenant-name";

/**
* set this property to {@code true} to designate that the service requires explicit specification of either {@link #TENANT_NAME} or {@link #TENANT_ID}
* @see <a href="http://wiki.openstack.org/CLIAuth">openstack docs</a>
*/
public static final String REQUIRES_TENANT = "jclouds.keystone.requires-tenant";

/**
* version of the keystone service
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
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> {
Expand All @@ -39,13 +41,13 @@ public AuthenticateApiAccessKeyCredentials(AuthenticationClient client) {
}

@Override
protected Access authenticateWithTenantNameOrNull(String tenantId, ApiAccessKeyCredentials apiAccessKeyCredentials) {
return client.authenticateWithTenantNameAndCredentials(tenantId, apiAccessKeyCredentials);
protected Access authenticateWithTenantName(Optional<String> tenantName, ApiAccessKeyCredentials apiAccessKeyCredentials) {
return client.authenticateWithTenantNameAndCredentials(tenantName.orNull(), apiAccessKeyCredentials);
}

@Override
protected Access authenticateWithTenantId(String tenantId, ApiAccessKeyCredentials apiAccessKeyCredentials) {
return client.authenticateWithTenantIdAndCredentials(tenantId, apiAccessKeyCredentials);
protected Access authenticateWithTenantId(Optional<String> tenantId, ApiAccessKeyCredentials apiAccessKeyCredentials) {
return client.authenticateWithTenantIdAndCredentials(tenantId.orNull(), apiAccessKeyCredentials);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
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> {
Expand All @@ -39,13 +41,13 @@ public AuthenticatePasswordCredentials(AuthenticationClient client) {
}

@Override
protected Access authenticateWithTenantNameOrNull(String tenantId, PasswordCredentials apiAccessKeyCredentials) {
return client.authenticateWithTenantNameAndCredentials(tenantId, apiAccessKeyCredentials);
protected Access authenticateWithTenantName(Optional<String> tenantName, PasswordCredentials apiAccessKeyCredentials) {
return client.authenticateWithTenantNameAndCredentials(tenantName.orNull(), apiAccessKeyCredentials);
}

@Override
protected Access authenticateWithTenantId(String tenantId, PasswordCredentials apiAccessKeyCredentials) {
return client.authenticateWithTenantIdAndCredentials(tenantId, apiAccessKeyCredentials);
protected Access authenticateWithTenantId(Optional<String> tenantId, PasswordCredentials apiAccessKeyCredentials) {
return client.authenticateWithTenantIdAndCredentials(tenantId.orNull(), apiAccessKeyCredentials);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,45 +18,80 @@
*/
package org.jclouds.openstack.keystone.v2_0.functions.internal;

import static com.google.common.base.Preconditions.checkState;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.jclouds.domain.Credentials;
import org.jclouds.logging.Logger;
import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.*;
import org.jclouds.openstack.keystone.v2_0.domain.Access;

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

@Resource
protected Logger logger = Logger.NULL;

@Inject(optional = true)
@Named(TENANT_NAME)
protected String defaultTenantName;

@Inject(optional = true)
@Named(TENANT_ID)
protected String defaultTenantId;

@Inject(optional = true)
@Named(REQUIRES_TENANT)
protected boolean requiresTenant;

@PostConstruct
public void checkPropertiesAreCompatible() {
checkState(defaultTenantName == null || defaultTenantId == null, "you cannot specify both %s and %s",
TENANT_NAME, TENANT_ID);
}

@Override
public Access apply(Credentials input) {
String tenantId = null;
Optional<String> tenantName = Optional.fromNullable(defaultTenantName);
Optional<String> tenantId = Optional.fromNullable(defaultTenantId);

String usernameOrAccessKey = input.identity;
if (input.identity.indexOf(':') == -1) {
logger.debug("Identity %s does not match format tenantName:accessKey", input.identity);
} else {
tenantId = input.identity.substring(0, input.identity.indexOf(':'));

if (!tenantName.isPresent() && input.identity.indexOf(':') != -1) {
tenantName = Optional.of(input.identity.substring(0, input.identity.indexOf(':')));
usernameOrAccessKey = input.identity.substring(input.identity.indexOf(':') + 1);
}

String passwordOrSecretKey = input.credential;

C creds = createCredentials(usernameOrAccessKey, passwordOrSecretKey);

Access access;
if (tenantId != null && tenantId.matches("^[0-9]+$")) {
if (tenantId.isPresent()) {
access = authenticateWithTenantId(tenantId, creds);
} else if (tenantName.isPresent()) {
access = authenticateWithTenantName(tenantName, creds);
} else if (!requiresTenant) {
access = authenticateWithTenantName(tenantName, creds);
} else {
access = authenticateWithTenantNameOrNull(tenantId, creds);
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;
}

public abstract C createCredentials(String identity, String credential);

protected abstract Access authenticateWithTenantId(String tenantId, C apiAccessKeyCredentials);
protected abstract Access authenticateWithTenantId(Optional<String> tenantId, C apiAccessKeyCredentials);

protected abstract Access authenticateWithTenantNameOrNull(String tenantId, C apiAccessKeyCredentials);
protected abstract Access authenticateWithTenantName(Optional<String> tenantId, C apiAccessKeyCredentials);

}
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ public class BaseKeystoneRestClientExpectTest<S> extends BaseRestClientExpectTes

public BaseKeystoneRestClientExpectTest() {
provider = "openstack-keystone";
keystoneAuthWithUsernameAndPassword = KeystoneFixture.INSTANCE.initialAuthWithUsernameAndPassword(identity,
keystoneAuthWithUsernameAndPassword = KeystoneFixture.INSTANCE.initialAuthWithUsernameAndPasswordAndTenantName(identity,
credential);
keystoneAuthWithAccessKeyAndSecretKey = KeystoneFixture.INSTANCE.initialAuthWithAccessKeyAndSecretKey(identity,
keystoneAuthWithAccessKeyAndSecretKey = KeystoneFixture.INSTANCE.initialAuthWithAccessKeyAndSecretKeyAndTenantName(identity,
credential);

authToken = KeystoneFixture.INSTANCE.getAuthToken();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@ public String getTenantName(){
}

public HttpRequest initialAuthWithUsernameAndPassword(String username, String password){
return HttpRequest
.builder()
.method("POST")
.endpoint(URI.create("http://localhost:5000/v2.0/tokens"))
.headers(ImmutableMultimap.of(HttpHeaders.ACCEPT, "application/json"))
.payload(
payloadFromStringWithContentType(
format(
"{\"auth\":{\"passwordCredentials\":{\"username\":\"%s\",\"password\":\"%s\"}}}",
username, password), "application/json")).build();
}

public HttpRequest initialAuthWithUsernameAndPasswordAndTenantName(String username, String password){
return HttpRequest
.builder()
.method("POST")
Expand All @@ -61,7 +74,7 @@ public HttpRequest initialAuthWithUsernameAndPassword(String username, String pa
username, password, getTenantName()), "application/json")).build();
}

public HttpRequest initialAuthWithAccessKeyAndSecretKey(String accessKey, String secretKey){
public HttpRequest initialAuthWithAccessKeyAndSecretKeyAndTenantName(String accessKey, String secretKey){
return HttpRequest
.builder()
.method("POST")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
import org.jclouds.openstack.keystone.v2_0.internal.KeystoneFixture;
import org.jclouds.openstack.nova.v2_0.NovaClient;
import org.jclouds.openstack.nova.v2_0.internal.BaseNovaClientExpectTest;
import org.jclouds.openstack.nova.v2_0.parse.ParseServerListTest;
Expand All @@ -52,6 +53,7 @@ public AccessKeyAndSecretKeyAndTenantIdAuthenticationExpectTest() {
protected Properties setupProperties() {
Properties contextProperties = super.setupProperties();
contextProperties.setProperty("jclouds.keystone.credential-type", "apiAccessKeyCredentials");
contextProperties.setProperty("jclouds.keystone.tenant-id", KeystoneFixture.INSTANCE.getTenantId());
return contextProperties;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.openstack.nova.v2_0;

import static org.testng.Assert.assertEquals;

import java.net.URI;
import java.util.Properties;

import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
import org.jclouds.openstack.keystone.v2_0.internal.KeystoneFixture;
import org.jclouds.openstack.nova.v2_0.NovaClient;
import org.jclouds.openstack.nova.v2_0.internal.BaseNovaClientExpectTest;
import org.jclouds.openstack.nova.v2_0.parse.ParseServerListTest;
import org.testng.annotations.Test;

import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;

/**
*
* @see KeystoneProperties#CREDENTIAL_TYPE
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "AccessKeyAndSecretKeyAndTenantIdAuthenticationExpectTest")
public class AccessKeyAndSecretKeyAndTenantNamePropertyAuthenticationExpectTest extends BaseNovaClientExpectTest {
public AccessKeyAndSecretKeyAndTenantNamePropertyAuthenticationExpectTest() {
identity = "identity";
}

/**
* this reflects the properties that a user would pass to createContext
*/
@Override
protected Properties setupProperties() {
Properties contextProperties = super.setupProperties();
contextProperties.setProperty("jclouds.keystone.credential-type", "apiAccessKeyCredentials");
contextProperties.setProperty("jclouds.keystone.tenant-name", KeystoneFixture.INSTANCE.getTenantName());
return contextProperties;
}

public void testListServersWhenResponseIs2xx() throws Exception {
HttpRequest listServers = HttpRequest
.builder()
.method("GET")
.endpoint(URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers"))
.headers(
ImmutableMultimap.<String, String> builder().put("Accept", "application/json")
.put("X-Auth-Token", authToken).build()).build();

HttpResponse listServersResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResource("/server_list.json")).build();

NovaClient clientWhenServersExist = requestsSendResponses(keystoneAuthWithAccessKeyAndSecretKeyAndTenantName,
responseWithKeystoneAccess, listServers, listServersResponse);

assertEquals(clientWhenServersExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));

assertEquals(clientWhenServersExist.getServerClientForZone("az-1.region-a.geo-1").listServers().toString(),
new ParseServerListTest().expected().toString());
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ ImmutableMultimap.<String, String> builder().put("Accept", "application/json")
HttpResponse listServersResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResource("/server_list.json")).build();

NovaClient clientWhenServersExist = requestsSendResponses(keystoneAuthWithAccessKeyAndSecretKey,
NovaClient clientWhenServersExist = requestsSendResponses(keystoneAuthWithAccessKeyAndSecretKeyAndTenantName,
responseWithKeystoneAccess, listServers, listServersResponse);

assertEquals(clientWhenServersExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,10 @@
import static org.testng.Assert.assertEquals;

import java.net.URI;
import java.util.Properties;

import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
import org.jclouds.openstack.nova.v2_0.NovaClient;
import org.jclouds.openstack.nova.v2_0.internal.BaseNovaClientExpectTest;
import org.jclouds.openstack.nova.v2_0.parse.ParseServerListTest;
import org.testng.annotations.Test;
Expand All @@ -41,17 +39,10 @@
*/
@Test(groups = "unit", testName = "PasswordAuthenticationExpectTest")
public class PasswordAuthenticationExpectTest extends BaseNovaClientExpectTest {

/**
* this reflects the properties that a user would pass to createContext
*/
@Override
protected Properties setupProperties() {
Properties contextProperties = super.setupProperties();
contextProperties.setProperty("jclouds.keystone.credential-type", "passwordCredentials");
return contextProperties;
public PasswordAuthenticationExpectTest() {
identity = "identity";
}

public void testListServersWhenResponseIs2xx() throws Exception {
HttpRequest listServers = HttpRequest
.builder()
Expand Down
Loading

0 comments on commit b5797ad

Please sign in to comment.