mirror of https://github.com/apache/jclouds.git
JCLOUDS-1414: OpenStack Keystone V3 - different auth "domains" support
This commit is contained in:
parent
b144d9f473
commit
93a805ca57
|
@ -30,7 +30,9 @@ public abstract class TenantOrDomainAndCredentials<T> {
|
|||
@Nullable public abstract String tenantOrDomainId();
|
||||
@Nullable public abstract String tenantOrDomainName();
|
||||
@Nullable public abstract String scope();
|
||||
public abstract T credentials();
|
||||
@Nullable public abstract String projectDomainName();
|
||||
@Nullable public abstract String projectDomainId();
|
||||
public abstract T credentials();
|
||||
|
||||
TenantOrDomainAndCredentials() {
|
||||
|
||||
|
@ -45,6 +47,8 @@ public abstract class TenantOrDomainAndCredentials<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> projectDomainName(String projectDomainName);
|
||||
public abstract Builder<T> projectDomainId(String projectDomainId);
|
||||
public abstract Builder<T> credentials(T credentials);
|
||||
|
||||
public abstract TenantOrDomainAndCredentials<T> build();
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
package org.jclouds.openstack.keystone.auth.functions;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static org.jclouds.openstack.keystone.config.KeystoneProperties.PROJECT_DOMAIN_ID;
|
||||
import static org.jclouds.openstack.keystone.config.KeystoneProperties.PROJECT_DOMAIN_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;
|
||||
|
@ -51,15 +53,25 @@ public abstract class BaseAuthenticator<C> implements Function<Credentials, Auth
|
|||
@Inject(optional = true)
|
||||
@Named(REQUIRES_TENANT)
|
||||
protected boolean requiresTenant;
|
||||
|
||||
|
||||
@Inject(optional = true)
|
||||
@Named(SCOPE)
|
||||
protected String scope = Scope.UNSCOPED;
|
||||
|
||||
@Inject(optional = true)
|
||||
@Named(PROJECT_DOMAIN_NAME)
|
||||
protected String projectDomainName;
|
||||
|
||||
@Inject(optional = true)
|
||||
@Named(PROJECT_DOMAIN_ID)
|
||||
protected String projectDomainId;
|
||||
|
||||
@PostConstruct
|
||||
public void checkPropertiesAreCompatible() {
|
||||
checkState(defaultTenantName == null || defaultTenantId == null, "you cannot specify both %s and %s",
|
||||
TENANT_NAME, TENANT_ID);
|
||||
checkState(defaultTenantName == null || defaultTenantId == null, "you cannot specify both %s and %s", TENANT_NAME,
|
||||
TENANT_ID);
|
||||
checkState(projectDomainName == null || projectDomainId == null, "you cannot specify both %s and %s",
|
||||
PROJECT_DOMAIN_NAME, PROJECT_DOMAIN_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -74,21 +86,21 @@ public abstract class BaseAuthenticator<C> implements Function<Credentials, Auth
|
|||
}
|
||||
|
||||
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));
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"current configuration is set to [%s]. Unless you set [%s] or [%s], you must prefix your identity with 'tenantName:'",
|
||||
REQUIRES_TENANT, TENANT_NAME, TENANT_ID));
|
||||
}
|
||||
|
||||
|
||||
C creds = createCredentials(usernameOrAccessKey, passwordOrSecretKeyOrToken);
|
||||
TenantOrDomainAndCredentials<C> credsWithTenant = TenantOrDomainAndCredentials.<C> builder().tenantOrDomainId(defaultTenantId)
|
||||
.tenantOrDomainName(tenantName).scope(scope).credentials(creds).build();
|
||||
|
||||
TenantOrDomainAndCredentials<C> credsWithTenant = TenantOrDomainAndCredentials.<C> builder()
|
||||
.tenantOrDomainId(defaultTenantId).tenantOrDomainName(tenantName).scope(scope)
|
||||
.projectDomainName(projectDomainName).projectDomainId(projectDomainId).credentials(creds).build();
|
||||
|
||||
return authenticate(credsWithTenant);
|
||||
}
|
||||
|
||||
public abstract C createCredentials(String identity, String credential);
|
||||
|
||||
|
||||
public abstract AuthInfo authenticate(TenantOrDomainAndCredentials<C> credentials);
|
||||
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ public final class KeystoneProperties {
|
|||
* @see <a href="http://wiki.openstack.org/CLIAuth">openstack docs</a>
|
||||
*/
|
||||
public static final String REQUIRES_TENANT = "jclouds.keystone.requires-tenant";
|
||||
|
||||
|
||||
/**
|
||||
* set this property to specify for scoped authentication.
|
||||
* <p>
|
||||
|
@ -80,13 +80,41 @@ public final class KeystoneProperties {
|
|||
@SinceApiVersion("3")
|
||||
public static final String SCOPE = "jclouds.keystone.scope";
|
||||
|
||||
/**
|
||||
* Set this property to specify the domain name of project (tenant)
|
||||
* scope.<br/>
|
||||
* Required property when authentication {@link #SCOPE} is 'project:' and
|
||||
* project (tenant) domain is different than the user domain (Otherwise, the
|
||||
* domain used is the same as the user). <br/>
|
||||
* Cannot be used simultaneously with {@link #PROJECT_DOMAIN_ID}
|
||||
*
|
||||
* @see <a href=
|
||||
* "https://docs.openstack.org/keystone/latest/api_curl_examples.html#project-scoped">openstack
|
||||
* docs : Identity service (Keystone)</a>
|
||||
*/
|
||||
public static final String PROJECT_DOMAIN_NAME = "jclouds.keystone.project-domain-name";
|
||||
|
||||
/**
|
||||
* Set this property to specify the domain id of project (tenant) scope.<br/>
|
||||
* Required property when authentication {@link #SCOPE} is 'project:' and
|
||||
* project (tenant) domain is different than the user domain (Otherwise, the
|
||||
* domain used is the same as the user). <br/>
|
||||
* Cannot be used simultaneously with {@link #PROJECT_DOMAIN_NAME}
|
||||
*
|
||||
*
|
||||
* @see <a href=
|
||||
* "https://docs.openstack.org/keystone/latest/api_curl_examples.html#project-scoped">openstack
|
||||
* docs : Identity service (Keystone)</a>
|
||||
*/
|
||||
public static final String PROJECT_DOMAIN_ID = "jclouds.keystone.project-domain-id";
|
||||
|
||||
/**
|
||||
* type of the keystone service. ex. {@code compute}
|
||||
*
|
||||
* @see ServiceType
|
||||
*/
|
||||
public static final String SERVICE_TYPE = "jclouds.keystone.service-type";
|
||||
|
||||
|
||||
/**
|
||||
* Version of keystone to be used by services. Default: 3.
|
||||
*/
|
||||
|
|
|
@ -38,6 +38,7 @@ 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.ProjectIdScope.ProjectId;
|
||||
import org.jclouds.openstack.keystone.v3.domain.Auth.ProjectScope;
|
||||
import org.jclouds.openstack.keystone.v3.domain.Auth.ProjectScope.ProjectName;
|
||||
import org.jclouds.rest.MapBinder;
|
||||
|
@ -50,8 +51,7 @@ 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);
|
||||
private static final Set<String> SCOPE_PREFIXES = ImmutableSet.of(PROJECT, PROJECT_ID, DOMAIN, DOMAIN_ID);
|
||||
|
||||
protected BindAuthToJsonPayload(Json jsonBinder) {
|
||||
super(jsonBinder);
|
||||
|
@ -93,15 +93,32 @@ public abstract class BindAuthToJsonPayload<T> extends BindToJsonPayload impleme
|
|||
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));
|
||||
return ProjectScope.create(ProjectName.create(parts[1], parseProjectDomain(credentials, true)));
|
||||
} else if (PROJECT_ID.equals(parts[0])) {
|
||||
return ProjectIdScope.create(Id.create(parts[1]));
|
||||
// tenant (name/id) was never used as domain for project-id; so try to
|
||||
// keep backward compatibility
|
||||
return ProjectIdScope.create(ProjectId.create(parts[1], parseProjectDomain(credentials, false)));
|
||||
} else if (DOMAIN.equals(parts[0])) {
|
||||
return DomainScope.create(Name.create(parts[1]));
|
||||
} else {
|
||||
return DomainIdScope.create(Id.create(parts[1]));
|
||||
}
|
||||
}
|
||||
|
||||
private Object parseProjectDomain(TenantOrDomainAndCredentials<T> credentials, boolean useTenantAsDefaultDomain) {
|
||||
// Before 'projectDomainName'/'projectDomainId' support,
|
||||
// 'tenantOrDomainId' was used as domain (id) for project-scoped by name,
|
||||
// but not by id, so 'useTenantAsDefaultDomain' flag allows to manage that
|
||||
Object domainScope = null;
|
||||
if (useTenantAsDefaultDomain && credentials.tenantOrDomainId() != null) {
|
||||
domainScope = Id.create(credentials.tenantOrDomainId());
|
||||
} else if (credentials.projectDomainName() != null) {
|
||||
domainScope = Name.create(credentials.projectDomainName());
|
||||
} else if (credentials.projectDomainId() != null) {
|
||||
domainScope = Id.create(credentials.projectDomainId());
|
||||
} else if (useTenantAsDefaultDomain) {
|
||||
domainScope = Name.create(credentials.tenantOrDomainName());
|
||||
}
|
||||
return domainScope;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,18 +26,24 @@ import com.google.auto.value.AutoValue;
|
|||
@AutoValue
|
||||
public abstract class Auth {
|
||||
public abstract Identity identity();
|
||||
@Nullable public abstract Object scope();
|
||||
|
||||
@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();
|
||||
|
||||
@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) {
|
||||
|
@ -56,7 +62,9 @@ public abstract class Auth {
|
|||
@AutoValue
|
||||
public abstract static class UserAuth {
|
||||
public abstract String name();
|
||||
|
||||
public abstract DomainAuth domain();
|
||||
|
||||
public abstract String password();
|
||||
|
||||
@SerializedNames({ "name", "domain", "password" })
|
||||
|
@ -66,7 +74,8 @@ public abstract class Auth {
|
|||
|
||||
@AutoValue
|
||||
public abstract static class DomainAuth {
|
||||
@Nullable public abstract String name();
|
||||
@Nullable
|
||||
public abstract String name();
|
||||
|
||||
@SerializedNames({ "name" })
|
||||
public static DomainAuth create(String name) {
|
||||
|
@ -76,7 +85,7 @@ public abstract class Auth {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@AutoValue
|
||||
public abstract static class Id {
|
||||
public abstract String id();
|
||||
|
@ -86,17 +95,18 @@ public abstract class Auth {
|
|||
return new AutoValue_Auth_Id(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@AutoValue
|
||||
public abstract static class Name {
|
||||
@Nullable public abstract String 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";
|
||||
|
@ -108,22 +118,24 @@ public abstract class Auth {
|
|||
@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();
|
||||
|
||||
|
||||
@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);
|
||||
}
|
||||
|
@ -133,17 +145,38 @@ public abstract class Auth {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@AutoValue
|
||||
public abstract static class ProjectIdScope {
|
||||
public abstract Id project();
|
||||
public abstract ProjectId project();
|
||||
|
||||
@SerializedNames({ Scope.PROJECT })
|
||||
public static ProjectIdScope create(Id id) {
|
||||
return new AutoValue_Auth_ProjectIdScope(id);
|
||||
public static ProjectIdScope create(ProjectId project) {
|
||||
return new AutoValue_Auth_ProjectIdScope(project);
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
public abstract static class ProjectId {
|
||||
public abstract String id();
|
||||
|
||||
@Nullable
|
||||
public abstract Object domain();
|
||||
|
||||
@SerializedNames({ "id", Scope.DOMAIN })
|
||||
public static ProjectId create(String id, Object domain) {
|
||||
return new AutoValue_Auth_ProjectIdScope_ProjectId(id, domain);
|
||||
}
|
||||
|
||||
public static ProjectId create(String id, Name domain) {
|
||||
return new AutoValue_Auth_ProjectIdScope_ProjectId(id, domain);
|
||||
}
|
||||
|
||||
public static ProjectId create(String id, Id domain) {
|
||||
return new AutoValue_Auth_ProjectIdScope_ProjectId(id, domain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@AutoValue
|
||||
public abstract static class DomainIdScope {
|
||||
public abstract Id domain();
|
||||
|
@ -153,7 +186,7 @@ public abstract class Auth {
|
|||
return new AutoValue_Auth_DomainIdScope(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@AutoValue
|
||||
public abstract static class DomainScope {
|
||||
public abstract Name domain();
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.jclouds.openstack.keystone.v3.auth;
|
|||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import org.jclouds.openstack.keystone.auth.domain.ApiAccessKeyCredentials;
|
||||
import org.jclouds.openstack.keystone.auth.domain.AuthInfo;
|
||||
import org.jclouds.openstack.keystone.auth.domain.PasswordCredentials;
|
||||
import org.jclouds.openstack.keystone.auth.domain.TenantOrDomainAndCredentials;
|
||||
|
@ -31,71 +32,132 @@ import org.testng.annotations.Test;
|
|||
public class V3AuthenticationApiMockTest extends BaseV3KeystoneApiMockTest {
|
||||
|
||||
public void testAuthenticatePassword() throws InterruptedException {
|
||||
server.enqueue(jsonResponse("/v3/token.json"));
|
||||
|
||||
TenantOrDomainAndCredentials<PasswordCredentials> credentials = TenantOrDomainAndCredentials.<PasswordCredentials> builder()
|
||||
.tenantOrDomainName("domain")
|
||||
.scope("unscoped")
|
||||
TenantOrDomainAndCredentials<PasswordCredentials> credentials = TenantOrDomainAndCredentials
|
||||
.<PasswordCredentials> builder().tenantOrDomainName("domain").scope("unscoped")
|
||||
.credentials(PasswordCredentials.builder().username("identity").password("credential").build()).build();
|
||||
|
||||
AuthInfo authInfo = authenticationApi.authenticatePassword(credentials);
|
||||
|
||||
assertTrue(authInfo instanceof Token);
|
||||
assertEquals(authInfo, tokenFromResource("/v3/token.json"));
|
||||
|
||||
assertEquals(server.getRequestCount(), 1);
|
||||
assertSent(server, "POST", "/auth/tokens", stringFromResource("/v3/auth-password.json"));
|
||||
checkTokenResult(credentials, "/v3/auth-password.json");
|
||||
}
|
||||
|
||||
|
||||
public void testAuthenticatePasswordScoped() throws InterruptedException {
|
||||
server.enqueue(jsonResponse("/v3/token.json"));
|
||||
|
||||
TenantOrDomainAndCredentials<PasswordCredentials> credentials = TenantOrDomainAndCredentials.<PasswordCredentials> builder()
|
||||
.tenantOrDomainName("domain")
|
||||
.scope("projectId:1234567890")
|
||||
TenantOrDomainAndCredentials<PasswordCredentials> credentials = TenantOrDomainAndCredentials
|
||||
.<PasswordCredentials> builder().tenantOrDomainName("domain").scope("projectId:1234567890")
|
||||
.credentials(PasswordCredentials.builder().username("identity").password("credential").build()).build();
|
||||
|
||||
AuthInfo authInfo = authenticationApi.authenticatePassword(credentials);
|
||||
|
||||
assertTrue(authInfo instanceof Token);
|
||||
assertEquals(authInfo, tokenFromResource("/v3/token.json"));
|
||||
checkTokenResult(credentials, "/v3/auth-password-scoped.json");
|
||||
}
|
||||
|
||||
assertEquals(server.getRequestCount(), 1);
|
||||
assertSent(server, "POST", "/auth/tokens", stringFromResource("/v3/auth-password-scoped.json"));
|
||||
public void testAuthenticatePasswordProjectScopedIdDomainBackwardsCompat() throws InterruptedException {
|
||||
// See JCLOUDS-1414, before add of KeystoneProperties.PROJECT_DOMAIN,
|
||||
// TENANT_ID was not used as domain for project-scoped with id
|
||||
// => Unit test only for backward compatibility (is the same as
|
||||
// 'testAuthenticatePasswordScoped' with TENANT-ID in addition)
|
||||
|
||||
TenantOrDomainAndCredentials<PasswordCredentials> credentials = TenantOrDomainAndCredentials
|
||||
.<PasswordCredentials> builder().tenantOrDomainName("domain").scope("projectId:1234567890")
|
||||
.tenantOrDomainId("somethingShouldNotBeUsed")
|
||||
.credentials(PasswordCredentials.builder().username("identity").password("credential").build()).build();
|
||||
|
||||
checkTokenResult(credentials, "/v3/auth-password-scoped.json");
|
||||
}
|
||||
|
||||
public void testAuthenticatePasswordProjectScopedNameDomainBackwardsCompat() throws InterruptedException {
|
||||
// See JCLOUDS-1414, before add of KeystoneProperties.PROJECT_DOMAIN,
|
||||
// domain-id of project-scoped could be filled with TENANT_ID
|
||||
// => Unit test only for backward compatibility
|
||||
|
||||
TenantOrDomainAndCredentials<PasswordCredentials> credentials = TenantOrDomainAndCredentials
|
||||
.<PasswordCredentials> builder().tenantOrDomainName("domain").scope("project:my-project")
|
||||
.tenantOrDomainId("default")
|
||||
.credentials(PasswordCredentials.builder().username("identity").password("credential").build()).build();
|
||||
|
||||
checkTokenResult(credentials, "/v3/auth-password-project-scoped-name-domain-backwards-compat.json");
|
||||
}
|
||||
|
||||
public void testAuthenticatePasswordProjectScopedIdDomainId() throws InterruptedException {
|
||||
|
||||
TenantOrDomainAndCredentials<PasswordCredentials> credentials = TenantOrDomainAndCredentials
|
||||
.<PasswordCredentials> builder().tenantOrDomainName("domain").scope("projectId:42-project-42")
|
||||
.projectDomainId("42-domain-42")
|
||||
.credentials(PasswordCredentials.builder().username("identity").password("credential").build()).build();
|
||||
|
||||
checkTokenResult(credentials, "/v3/auth-password-project-scoped-id-domain-id.json");
|
||||
}
|
||||
|
||||
public void testAuthenticatePasswordProjectScopedIdDomainName() throws InterruptedException {
|
||||
|
||||
TenantOrDomainAndCredentials<PasswordCredentials> credentials = TenantOrDomainAndCredentials
|
||||
.<PasswordCredentials> builder().tenantOrDomainName("domain").scope("projectId:42")
|
||||
.projectDomainName("default")
|
||||
.credentials(PasswordCredentials.builder().username("identity").password("credential").build()).build();
|
||||
|
||||
checkTokenResult(credentials, "/v3/auth-password-project-scoped-id-domain-name.json");
|
||||
}
|
||||
|
||||
public void testAuthenticatePasswordProjectScopedNameDomainId() throws InterruptedException {
|
||||
|
||||
TenantOrDomainAndCredentials<PasswordCredentials> credentials = TenantOrDomainAndCredentials
|
||||
.<PasswordCredentials> builder().tenantOrDomainName("domain").scope("project:my-project")
|
||||
.projectDomainId("42")
|
||||
.credentials(PasswordCredentials.builder().username("identity").password("credential").build()).build();
|
||||
|
||||
checkTokenResult(credentials, "/v3/auth-password-project-scoped-name-domain-id.json");
|
||||
}
|
||||
|
||||
public void testAuthenticatePasswordProjectScopedNameDomainName() throws InterruptedException {
|
||||
|
||||
TenantOrDomainAndCredentials<PasswordCredentials> credentials = TenantOrDomainAndCredentials
|
||||
.<PasswordCredentials> builder().tenantOrDomainName("domain").scope("project:my-project")
|
||||
.projectDomainName("default")
|
||||
.credentials(PasswordCredentials.builder().username("identity").password("credential").build()).build();
|
||||
|
||||
checkTokenResult(credentials, "/v3/auth-password-project-scoped-name-domain-name.json");
|
||||
}
|
||||
|
||||
public void testAuthenticateToken() throws InterruptedException {
|
||||
server.enqueue(jsonResponse("/v3/token.json"));
|
||||
|
||||
TenantOrDomainAndCredentials<TokenCredentials> credentials = TenantOrDomainAndCredentials.<TokenCredentials> builder()
|
||||
.tenantOrDomainName("domain")
|
||||
.scope("unscoped")
|
||||
TenantOrDomainAndCredentials<TokenCredentials> credentials = TenantOrDomainAndCredentials
|
||||
.<TokenCredentials> builder().tenantOrDomainName("domain").scope("unscoped")
|
||||
.credentials(TokenCredentials.builder().id("token").build()).build();
|
||||
|
||||
AuthInfo authInfo = authenticationApi.authenticateToken(credentials);
|
||||
|
||||
assertTrue(authInfo instanceof Token);
|
||||
assertEquals(authInfo, tokenFromResource("/v3/token.json"));
|
||||
|
||||
assertEquals(server.getRequestCount(), 1);
|
||||
assertSent(server, "POST", "/auth/tokens", stringFromResource("/v3/auth-token.json"));
|
||||
checkTokenResult(credentials, "/v3/auth-token.json");
|
||||
}
|
||||
|
||||
|
||||
public void testAuthenticateTokenScoped() throws InterruptedException {
|
||||
|
||||
TenantOrDomainAndCredentials<TokenCredentials> credentials = TenantOrDomainAndCredentials
|
||||
.<TokenCredentials> builder().tenantOrDomainName("domain").scope("domain:mydomain")
|
||||
.credentials(TokenCredentials.builder().id("token").build()).build();
|
||||
|
||||
checkTokenResult(credentials, "/v3/auth-token-scoped.json");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void checkTokenResult(TenantOrDomainAndCredentials<?> credentials, String json) throws InterruptedException {
|
||||
server.enqueue(jsonResponse("/v3/token.json"));
|
||||
|
||||
TenantOrDomainAndCredentials<TokenCredentials> credentials = TenantOrDomainAndCredentials.<TokenCredentials> builder()
|
||||
.tenantOrDomainName("domain")
|
||||
.scope("domain:mydomain")
|
||||
.credentials(TokenCredentials.builder().id("token").build()).build();
|
||||
|
||||
AuthInfo authInfo = authenticationApi.authenticateToken(credentials);
|
||||
AuthInfo authInfo = null;
|
||||
|
||||
if (credentials.credentials() instanceof PasswordCredentials) {
|
||||
authInfo = authenticationApi
|
||||
.authenticatePassword((TenantOrDomainAndCredentials<PasswordCredentials>) credentials);
|
||||
} else if (credentials.credentials() instanceof TokenCredentials) {
|
||||
authInfo = authenticationApi.authenticateToken((TenantOrDomainAndCredentials<TokenCredentials>) credentials);
|
||||
} else if (credentials.credentials() instanceof ApiAccessKeyCredentials) {
|
||||
authInfo = authenticationApi
|
||||
.authenticateAccessKey((TenantOrDomainAndCredentials<ApiAccessKeyCredentials>) credentials);
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format("Unsupported authentication method with class: %s",
|
||||
credentials.credentials().getClass().getName()));
|
||||
}
|
||||
|
||||
assertTrue(authInfo instanceof Token);
|
||||
assertEquals(authInfo, tokenFromResource("/v3/token.json"));
|
||||
|
||||
assertEquals(server.getRequestCount(), 1);
|
||||
assertSent(server, "POST", "/auth/tokens", stringFromResource("/v3/auth-token-scoped.json"));
|
||||
assertSent(server, "POST", "/auth/tokens", stringFromResource(json));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"auth": {
|
||||
"identity": {
|
||||
"methods": [
|
||||
"password"
|
||||
],
|
||||
"password": {
|
||||
"user": {
|
||||
"name": "identity",
|
||||
"domain": {
|
||||
"name": "domain"
|
||||
},
|
||||
"password": "credential"
|
||||
}
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"project": {
|
||||
"id": "42-project-42",
|
||||
"domain": {
|
||||
"id": "42-domain-42"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"auth": {
|
||||
"identity": {
|
||||
"methods": [
|
||||
"password"
|
||||
],
|
||||
"password": {
|
||||
"user": {
|
||||
"name": "identity",
|
||||
"domain": {
|
||||
"name": "domain"
|
||||
},
|
||||
"password": "credential"
|
||||
}
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"project": {
|
||||
"id": "42",
|
||||
"domain": {
|
||||
"name": "default"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"auth": {
|
||||
"identity": {
|
||||
"methods": [
|
||||
"password"
|
||||
],
|
||||
"password": {
|
||||
"user": {
|
||||
"name": "identity",
|
||||
"domain": {
|
||||
"name": "domain"
|
||||
},
|
||||
"password": "credential"
|
||||
}
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"project": {
|
||||
"name": "my-project",
|
||||
"domain": {
|
||||
"id": "default"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"auth": {
|
||||
"identity": {
|
||||
"methods": [
|
||||
"password"
|
||||
],
|
||||
"password": {
|
||||
"user": {
|
||||
"name": "identity",
|
||||
"domain": {
|
||||
"name": "domain"
|
||||
},
|
||||
"password": "credential"
|
||||
}
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"project": {
|
||||
"name": "my-project",
|
||||
"domain": {
|
||||
"id": "42"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"auth": {
|
||||
"identity": {
|
||||
"methods": [
|
||||
"password"
|
||||
],
|
||||
"password": {
|
||||
"user": {
|
||||
"name": "identity",
|
||||
"domain": {
|
||||
"name": "domain"
|
||||
},
|
||||
"password": "credential"
|
||||
}
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"project": {
|
||||
"name": "my-project",
|
||||
"domain": {
|
||||
"name": "default"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue