From 74401d55a0c60b9d601a4501dc6d4bae6018719e Mon Sep 17 00:00:00 2001 From: Dani Estevez Date: Fri, 10 Aug 2018 12:15:44 -0400 Subject: [PATCH] JCLOUDS-1441: Enables support for ARM regions in China Adds new china regions Fixes pattern matching for China provider oauth string Modifies test for oauth string overrides jclouds.oauth.resource property for tests Graph and Vault API Endpoints need to be configurable jclouds.oauth.resource is not mandatory Adapted Endpoints for APIs GraphRBAC and Vault Adds unit test for china oauth endpoint check Minor fix to regular expression --- .../arm/config/AzureComputeHttpApiModule.java | 16 ++- .../arm/config/AzureOAuthConfigFactory.java | 11 +- .../azurecompute/arm/config/GraphRBAC.java | 13 +- .../arm/config/OAuthResource.java | 5 +- .../azurecompute/arm/domain/Region.java | 2 + .../arm/features/GraphRBACApi.java | 2 +- .../azurecompute/arm/features/VaultApi.java | 123 +++++++++--------- .../arm/config/IsChinaEndpointTest.java | 38 ++++++ .../arm/config/ParseTenantIdTest.java | 7 +- .../internal/BaseAzureComputeApiLiveTest.java | 3 +- 10 files changed, 146 insertions(+), 74 deletions(-) create mode 100644 providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/config/IsChinaEndpointTest.java diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeHttpApiModule.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeHttpApiModule.java index c01fc0a5cb1..10a981ebd62 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeHttpApiModule.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureComputeHttpApiModule.java @@ -54,7 +54,12 @@ public class AzureComputeHttpApiModule extends HttpApiModule { private static final Pattern OAUTH_TENANT_PATTERN = Pattern - .compile("https://login.microsoft(?:online)?.com/([^/]+)/oauth2/token"); + .compile("https://login.(microsoft(?:online)?.com|chinacloudapi.cn)/([^/]+)/oauth2/token"); + + private static final Pattern CHINA_OAUTH_ENDPOINT_PATTERN = Pattern + .compile("https://login.chinacloudapi.cn/([^/]+)/oauth2/token"); + + public static final String IS_CHINA_ENDPOINT = "jclouds.isChinaEndpoint"; @Override protected void bindErrorHandlers() { @@ -92,7 +97,14 @@ protected final String provideTenant(@Named("oauth.endpoint") final String oauth if (!m.matches()) { throw new IllegalArgumentException("Could not parse tenantId from: " + oauthEndpoint); } - return m.group(1); + return m.group(2); + } + + @Provides + @Singleton + @Named(IS_CHINA_ENDPOINT) + protected final boolean isChinaEndpoint(@Named("oauth.endpoint") final String oauthEndpoint) { + return CHINA_OAUTH_ENDPOINT_PATTERN.matcher(oauthEndpoint).matches(); } @Provides diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureOAuthConfigFactory.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureOAuthConfigFactory.java index 9128b594988..7b946b571d2 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureOAuthConfigFactory.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/AzureOAuthConfigFactory.java @@ -16,6 +16,7 @@ */ package org.jclouds.azurecompute.arm.config; +import static org.jclouds.azurecompute.arm.config.AzureComputeHttpApiModule.IS_CHINA_ENDPOINT; import static org.jclouds.oauth.v2.config.OAuthProperties.AUDIENCE; import static org.jclouds.oauth.v2.config.OAuthProperties.RESOURCE; @@ -29,7 +30,7 @@ public class AzureOAuthConfigFactory implements OAuthConfigFactory { private final OAuthScopes scopes; - + @Named(AUDIENCE) @Inject(optional = true) private String audience; @@ -38,6 +39,10 @@ public class AzureOAuthConfigFactory implements OAuthConfigFactory { @Inject(optional = true) private String resource; + @Named(IS_CHINA_ENDPOINT) + @Inject(optional = true) + private boolean isChinaEndpoint; + @Inject AzureOAuthConfigFactory(OAuthScopes scopes) { this.scopes = scopes; @@ -54,7 +59,9 @@ public OAuthConfig forRequest(HttpRequest input) { .getAnnotation(OAuthResource.class); } } - String oauthResource = customResource != null ? customResource.value() : resource; + String oauthResource = customResource == null ? + resource : + (isChinaEndpoint ? customResource.chinaEndpoint() : customResource.value()); return OAuthConfig.create(scopes.forRequest(input), audience, oauthResource); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/GraphRBAC.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/GraphRBAC.java index a7f8b4f28b2..11b13c77747 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/GraphRBAC.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/GraphRBAC.java @@ -16,13 +16,15 @@ */ package org.jclouds.azurecompute.arm.config; +import static org.jclouds.azurecompute.arm.config.AzureComputeHttpApiModule.IS_CHINA_ENDPOINT; + import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.net.URI; - import javax.inject.Inject; +import javax.inject.Named; import javax.inject.Qualifier; import com.google.common.base.Supplier; @@ -35,19 +37,22 @@ @Qualifier public @interface GraphRBAC { - String ENDPOINT = "https://graph.windows.net/"; + String STANDARD_ENDPOINT = "https://graph.windows.net/"; + String CHINA_ENDPOINT = "https://graph.chinacloudapi.cn/"; static class GraphRBACForTenant implements Supplier { private final String tenantId; + private final boolean isChinaEndpoint; @Inject - GraphRBACForTenant(@Tenant String tenantId) { + GraphRBACForTenant(@Tenant String tenantId, @Named(IS_CHINA_ENDPOINT) boolean isChinaEndpoint) { this.tenantId = tenantId; + this.isChinaEndpoint = isChinaEndpoint; } @Override public URI get() { - return URI.create(GraphRBAC.ENDPOINT + tenantId); + return URI.create((isChinaEndpoint ? CHINA_ENDPOINT : STANDARD_ENDPOINT) + tenantId); } } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/OAuthResource.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/OAuthResource.java index 6e5a2dfdc4d..e0349647e9c 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/OAuthResource.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/config/OAuthResource.java @@ -20,7 +20,6 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; - import javax.inject.Qualifier; /** @@ -30,6 +29,8 @@ @Target(value = { ElementType.TYPE, ElementType.METHOD }) @Qualifier public @interface OAuthResource { - + String value(); + + String chinaEndpoint(); } diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Region.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Region.java index ea607a03db4..b448ca31720 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Region.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/domain/Region.java @@ -60,7 +60,9 @@ public enum Region { SOUTH_INDIA("South India", "IN-TN"), WEST_INDIA("West India", "IN-MH"), CHINA_EAST("China East", "CN-SH"), + CHINA_EAST_2("China East 2", "CN-SH"), CHINA_NORTH("China North", "CN-BJ"), + CHINA_NORTH_2("China North 2", "CN-BJ"), CANADA_CENTRAL("Canada Central", "CA-ON"), CANADA_EAST("Canada East", "CA-QC"), FRANCE_CENTRAL("France Central", "FR-IDF"), diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/GraphRBACApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/GraphRBACApi.java index fe2bccc4b1c..38de1173921 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/GraphRBACApi.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/GraphRBACApi.java @@ -37,7 +37,7 @@ @RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) @Consumes(MediaType.APPLICATION_JSON) @Endpoint(GraphRBAC.class) -@OAuthResource(GraphRBAC.ENDPOINT) +@OAuthResource(value = GraphRBAC.STANDARD_ENDPOINT, chinaEndpoint = GraphRBAC.CHINA_ENDPOINT) public interface GraphRBACApi { @Named("servicePrincipal:get") diff --git a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VaultApi.java b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VaultApi.java index 5ae39ba7429..3165b179323 100644 --- a/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VaultApi.java +++ b/providers/azurecompute-arm/src/main/java/org/jclouds/azurecompute/arm/features/VaultApi.java @@ -19,7 +19,6 @@ import java.net.URI; import java.util.List; import java.util.Map; - import javax.inject.Named; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; @@ -30,8 +29,6 @@ import javax.ws.rs.PathParam; import javax.ws.rs.core.MediaType; -import com.google.common.base.Function; - import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404; import org.jclouds.Fallbacks.FalseOnNotFoundOr404; import org.jclouds.Fallbacks.NullOnNotFoundOr404; @@ -75,15 +72,21 @@ import org.jclouds.rest.annotations.Fallback; import org.jclouds.rest.annotations.MapBinder; import org.jclouds.rest.annotations.PATCH; +import org.jclouds.rest.annotations.ParamParser; import org.jclouds.rest.annotations.PayloadParam; import org.jclouds.rest.annotations.RequestFilters; import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.binders.BindToJsonPayload; -import org.jclouds.rest.annotations.ParamParser; + +import com.google.common.base.Function; @RequestFilters({ OAuthFilter.class, ApiVersionFilter.class }) @Consumes(MediaType.APPLICATION_JSON) public interface VaultApi { + + String VAULT_API_STANDARD_ENDPOINT = "https://vault.azure.net"; + String VAULT_API_CHINA_ENDPOINT = "https://vault.azure.cn"; + static class PrependSlashOrEmptyString implements Function { public String apply(Object from) { if ((from == null) || (from.toString().length() == 0)) { @@ -146,14 +149,14 @@ Vault createOrUpdateVault(@PathParam("vaultName") String vaultName, @PayloadPara @GET @Fallback(EmptyListOnNotFoundOr404.class) @Path("/keys") - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) List listKeys(@EndpointParam URI keyVaultUri); @Named("key:create") @POST @MapBinder(BindToJsonPayload.class) @Path("/keys/{keyName}/create") - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) KeyBundle createKey(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName, @Nullable @PayloadParam("attributes") KeyAttributes attributes, @Nullable @PayloadParam("crv") String curveName, @Nullable @PayloadParam("key_ops") List keyOps, @@ -164,7 +167,7 @@ KeyBundle createKey(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") Strin @PUT @MapBinder(BindToJsonPayload.class) @Path("/keys/{keyName}") - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) KeyBundle importKey(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName, @PayloadParam("Hsm") boolean hsm, @Nullable @PayloadParam("attributes") KeyAttributes attributes, @Nullable @PayloadParam("key") JsonWebKey key, @Nullable @PayloadParam("tags") Map tags); @@ -173,14 +176,14 @@ KeyBundle importKey(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") Strin @GET @Path("/keys/{keyName}") @Fallback(NullOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) KeyBundle getKey(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName); @Named("key:delete") @DELETE @Path("/keys/{keyName}") @Fallback(NullOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) DeletedKeyBundle deleteKey(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName); @Named("key:get_versions") @@ -188,14 +191,14 @@ KeyBundle importKey(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") Strin @SelectJson("value") @Path("/keys/{keyName}/versions") @Fallback(EmptyListOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) List getKeyVersions(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName); @Named("key:update") @PATCH @MapBinder(BindToJsonPayload.class) @Path("/keys/{keyName}{keyVersion}") - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) KeyBundle updateKey(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName, @Nullable @PathParam("keyVersion") @ParamParser(PrependSlashOrEmptyString.class) String keyVersion, @@ -207,14 +210,14 @@ KeyBundle updateKey(@EndpointParam URI vaultBaseUrl, @POST @SelectJson("value") @Path("/keys/{keyName}/backup") - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) String backupKey(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName); @Named("key:restore") @POST @MapBinder(BindToJsonPayload.class) @Path("/keys/restore") - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) KeyBundle restoreKey(@EndpointParam URI vaultBaseUrl, @PayloadParam("value") String keyInfo); // Soft-delete key operations @@ -223,27 +226,27 @@ KeyBundle updateKey(@EndpointParam URI vaultBaseUrl, @SelectJson("value") @Path("/deletedkeys") @Fallback(EmptyListOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) List listDeletedKeys(@EndpointParam URI vaultBaseUrl); @Named("key:get_deleted") @GET @Path("/deletedkeys/{keyName}") @Fallback(NullOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) DeletedKeyBundle getDeletedKey(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName); @Named("key:recover_deleted") @POST @Path("/deletedkeys/{keyName}/recover") - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) KeyBundle recoverDeletedKey(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName); @Named("key:purge_deleted") @DELETE @Path("/deletedkeys/{keyName}") @Fallback(FalseOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) boolean purgeDeletedKey(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName); // Key cryptographic operations @@ -251,7 +254,7 @@ KeyBundle updateKey(@EndpointParam URI vaultBaseUrl, @POST @Path("/keys/{keyName}{keyVersion}/encrypt") @MapBinder(BindToJsonPayload.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) KeyOperationResult encrypt(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName, @Nullable @PathParam("keyVersion") @ParamParser(PrependSlashOrEmptyString.class) String keyVersion, @@ -262,7 +265,7 @@ KeyOperationResult encrypt(@EndpointParam URI vaultBaseUrl, @POST @Path("/keys/{keyName}{keyVersion}/decrypt") @MapBinder(BindToJsonPayload.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) KeyOperationResult decrypt(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName, @Nullable @PathParam("keyVersion") @ParamParser(PrependSlashOrEmptyString.class) String keyVersion, @@ -273,7 +276,7 @@ KeyOperationResult decrypt(@EndpointParam URI vaultBaseUrl, @POST @Path("/keys/{keyName}{keyVersion}/sign") @MapBinder(BindToJsonPayload.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) KeyOperationResult sign(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName, @Nullable @PathParam("keyVersion") @ParamParser(PrependSlashOrEmptyString.class) String keyVersion, @@ -284,7 +287,7 @@ KeyOperationResult sign(@EndpointParam URI vaultBaseUrl, @POST @Path("/keys/{keyName}{keyVersion}/verify") @MapBinder(BindToJsonPayload.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) boolean verify(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName, @Nullable @PathParam("keyVersion") @ParamParser(PrependSlashOrEmptyString.class) String keyVersion, @@ -296,7 +299,7 @@ boolean verify(@EndpointParam URI vaultBaseUrl, @POST @Path("/keys/{keyName}{keyVersion}/wrapkey") @MapBinder(BindToJsonPayload.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) KeyOperationResult wrap(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName, @Nullable @PathParam("keyVersion") @ParamParser(PrependSlashOrEmptyString.class) String keyVersion, @@ -307,7 +310,7 @@ KeyOperationResult wrap(@EndpointParam URI vaultBaseUrl, @POST @Path("/keys/{keyName}{keyVersion}/unwrapkey") @MapBinder(BindToJsonPayload.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) KeyOperationResult unwrap(@EndpointParam URI vaultBaseUrl, @PathParam("keyName") String keyName, @Nullable @PathParam("keyVersion") @ParamParser(PrependSlashOrEmptyString.class) String keyVersion, @@ -320,14 +323,14 @@ KeyOperationResult unwrap(@EndpointParam URI vaultBaseUrl, @GET @Fallback(EmptyListOnNotFoundOr404.class) @Path("/secrets") - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) List listSecrets(@EndpointParam URI keyVaultUri); @Named("secret:set") @PUT @MapBinder(BindToJsonPayload.class) @Path("/secrets/{secretName}") - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) SecretBundle setSecret(@EndpointParam URI keyVaultUri, @PathParam("secretName") String secretName, @Nullable @PayloadParam("attributes") SecretAttributes attributes, @Nullable @PayloadParam("contentType") String contentType, @@ -337,7 +340,7 @@ SecretBundle setSecret(@EndpointParam URI keyVaultUri, @PathParam("secretName") @GET @Path("/secrets/{secretName}{secretVersion}") @Fallback(NullOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) SecretBundle getSecret(@EndpointParam URI vaultBaseUrl, @PathParam("secretName") String secretName, @Nullable @PathParam("secretVersion") @ParamParser(PrependSlashOrEmptyString.class) String secretVersion); @@ -346,7 +349,7 @@ SecretBundle getSecret(@EndpointParam URI vaultBaseUrl, @DELETE @Path("/secrets/{secretName}") @Fallback(NullOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) DeletedSecretBundle deleteSecret(@EndpointParam URI vaultBaseUrl, @PathParam("secretName") String secretName); @Named("secret:get_versions") @@ -354,14 +357,14 @@ SecretBundle getSecret(@EndpointParam URI vaultBaseUrl, @SelectJson("value") @Path("/secrets/{secretName}/versions") @Fallback(EmptyListOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) List getSecretVersions(@EndpointParam URI vaultBaseUrl, @PathParam("secretName") String secretName); @Named("secret:update") @PATCH @MapBinder(BindToJsonPayload.class) @Path("/secrets/{secretName}{secretVersion}") - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) SecretBundle updateSecret(@EndpointParam URI vaultBaseUrl, @PathParam("secretName") String secretName, @Nullable @PathParam("secretVersion") @ParamParser(PrependSlashOrEmptyString.class) String secretVersion, @@ -373,14 +376,14 @@ SecretBundle updateSecret(@EndpointParam URI vaultBaseUrl, @POST @SelectJson("value") @Path("/secrets/{secretName}/backup") - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) String backupSecret(@EndpointParam URI vaultBaseUrl, @PathParam("secretName") String secretName); @Named("secret:restore") @POST @MapBinder(BindToJsonPayload.class) @Path("/secrets/restore") - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) SecretBundle restoreSecret(@EndpointParam URI vaultBaseUrl, @PayloadParam("value") String secretInfo); // Soft-delete secret operations @@ -389,27 +392,27 @@ SecretBundle updateSecret(@EndpointParam URI vaultBaseUrl, @SelectJson("value") @Path("/deletedsecrets") @Fallback(EmptyListOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) List listDeletedSecrets(@EndpointParam URI vaultBaseUrl); @Named("secret:get_deleted") @GET @Path("/deletedsecrets/{secretName}") @Fallback(NullOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) DeletedSecretBundle getDeletedSecret(@EndpointParam URI vaultBaseUrl, @PathParam("secretName") String secretName); @Named("secret:recover_deleted") @POST @Path("/deletedsecrets/{secretName}/recover") - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) SecretBundle recoverDeletedSecret(@EndpointParam URI vaultBaseUrl, @PathParam("secretName") String secretName); @Named("secret:purge_deleted") @DELETE @Path("/deletedsecrets/{secretName}") @Fallback(FalseOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) boolean purgeDeletedSecret(@EndpointParam URI vaultBaseUrl, @PathParam("secretName") String secretName); // Certificate operations @@ -417,7 +420,7 @@ SecretBundle updateSecret(@EndpointParam URI vaultBaseUrl, @POST @MapBinder(BindToJsonPayload.class) @Path("/certificates/{certificateName}/create") - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) CertificateOperation createCertificate(@EndpointParam URI vaultBaseUrl, @PathParam("certificateName") String certificateName, @Nullable @PayloadParam("attributes") CertificateAttributes attributes, @@ -428,7 +431,7 @@ CertificateOperation createCertificate(@EndpointParam URI vaultBaseUrl, @GET @Path("/certificates/{certificateName}{certificateVersion}") @Fallback(NullOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) CertificateBundle getCertificate(@EndpointParam URI vaultBaseUrl, @PathParam("certificateName") String certificateName, @Nullable @PathParam("certificateVersion") @ParamParser(PrependSlashOrEmptyString.class) String certificateVersion); @@ -437,7 +440,7 @@ CertificateBundle getCertificate(@EndpointParam URI vaultBaseUrl, @DELETE @Path("/certificates/{certificateName}") @Fallback(NullOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) DeletedCertificateBundle deleteCertificate(@EndpointParam URI vaultBaseUrl, @PathParam("certificateName") String certificateName); @@ -446,7 +449,7 @@ DeletedCertificateBundle deleteCertificate(@EndpointParam URI vaultBaseUrl, @SelectJson("value") @Path("/certificates") @Fallback(EmptyListOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) List getCertificates(@EndpointParam URI vaultBaseUrl); @Named("certificate:list_deleted") @@ -454,21 +457,21 @@ DeletedCertificateBundle deleteCertificate(@EndpointParam URI vaultBaseUrl, @SelectJson("value") @Path("/deletedcertificates") @Fallback(EmptyListOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) List getDeletedCertificates(@EndpointParam URI vaultBaseUrl); @Named("certificate:get_deleted") @GET @Path("/deletedcertificates/{certificateName}") @Fallback(NullOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) DeletedCertificateBundle getDeletedCertificate(@EndpointParam URI vaultBaseUrl, @PathParam("certificateName") String certificateName); @Named("certificate:recover_deleted") @POST @Path("/deletedcertificates/{certificateName}/recover") - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) CertificateBundle recoverDeletedCertificate(@EndpointParam URI vaultBaseUrl, @PathParam("certificateName") String certificateName); @@ -476,7 +479,7 @@ CertificateBundle recoverDeletedCertificate(@EndpointParam URI vaultBaseUrl, @DELETE @Path("/deletedcertificates/{certificateName}") @Fallback(FalseOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) boolean purgeDeletedCertificate(@EndpointParam URI vaultBaseUrl, @PathParam("certificateName") String certificateName); @Named("certificate:get_versions") @@ -484,7 +487,7 @@ CertificateBundle recoverDeletedCertificate(@EndpointParam URI vaultBaseUrl, @SelectJson("value") @Path("/certificates/{certificateName}/versions") @Fallback(EmptyListOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) List getCertificateVersions(@EndpointParam URI vaultBaseUrl, @PathParam("certificateName") String certificateName); @@ -492,7 +495,7 @@ List getCertificateVersions(@EndpointParam URI vaultBaseUrl, @PATCH @MapBinder(BindToJsonPayload.class) @Path("/certificates/{certificateName}{certificateVersion}") - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) CertificateBundle updateCertificate(@EndpointParam URI vaultBaseUrl, @PathParam("certificateName") String certificateName, @Nullable @PathParam("certificateVersion") @ParamParser(PrependSlashOrEmptyString.class) String certificateVersion, @@ -504,7 +507,7 @@ CertificateBundle updateCertificate(@EndpointParam URI vaultBaseUrl, @POST @MapBinder(BindToJsonPayload.class) @Path("/certificates/{certificateName}/import") - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) CertificateBundle importCertificate(@EndpointParam URI vaultBaseUrl, @PathParam("certificateName") String certificateName, @Nullable @PayloadParam("attributes") CertificateAttributes attributes, @@ -515,7 +518,7 @@ CertificateBundle importCertificate(@EndpointParam URI vaultBaseUrl, @POST @MapBinder(BindToJsonPayload.class) @Path("/certificates/{certificateName}/pending/merge") - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) CertificateBundle mergeCertificate(@EndpointParam URI vaultBaseUrl, @PathParam("certificateName") String certificateName, @Nullable @PayloadParam("attributes") CertificateAttributes attributes, @@ -525,7 +528,7 @@ CertificateBundle mergeCertificate(@EndpointParam URI vaultBaseUrl, @GET @Path("/certificates/{certificateName}/pending") @Fallback(NullOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) CertificateOperation getCertificateOperation(@EndpointParam URI vaultBaseUrl, @PathParam("certificateName") String certificateName); @@ -533,7 +536,7 @@ CertificateOperation getCertificateOperation(@EndpointParam URI vaultBaseUrl, @PATCH @Path("/certificates/{certificateName}/pending") @MapBinder(BindToJsonPayload.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) CertificateOperation updateCertificateOperation(@EndpointParam URI vaultBaseUrl, @PathParam("certificateName") String certificateName, @PayloadParam("cancellation_requested") boolean cancellationRequested); @@ -542,7 +545,7 @@ CertificateOperation updateCertificateOperation(@EndpointParam URI vaultBaseUrl, @DELETE @Path("/certificates/{certificateName}/pending") @Fallback(NullOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) CertificateOperation deleteCertificateOperation(@EndpointParam URI vaultBaseUrl, @PathParam("certificateName") String certificateName); @@ -550,7 +553,7 @@ CertificateOperation deleteCertificateOperation(@EndpointParam URI vaultBaseUrl, @PUT @Path("/certificates/issuers/{issuerName}") @MapBinder(BindToJsonPayload.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) IssuerBundle setCertificateIssuer(@EndpointParam URI vaultBaseUrl, @PathParam("issuerName") String issuerName, @Nullable @PayloadParam("attributes") IssuerAttributes attributes, @Nullable @PayloadParam("credentials") IssuerCredentials credentials, @@ -562,21 +565,21 @@ IssuerBundle setCertificateIssuer(@EndpointParam URI vaultBaseUrl, @PathParam("i @SelectJson("value") @Path("/certificates/issuers") @Fallback(EmptyListOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) List getCertificateIssuers(@EndpointParam URI vaultBaseUrl); @Named("certificate:get_issuer") @GET @Path("/certificates/issuers/{issuerName}") @Fallback(NullOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) IssuerBundle getCertificateIssuer(@EndpointParam URI vaultBaseUrl, @PathParam("issuerName") String issuerName); @Named("certificate:update_issuer") @PATCH @Path("/certificates/issuers/{issuerName}") @MapBinder(BindToJsonPayload.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) IssuerBundle updateCertificateIssuer(@EndpointParam URI vaultBaseUrl, @PathParam("issuerName") String issuerName, @Nullable @PayloadParam("attributes") IssuerAttributes attributes, @Nullable @PayloadParam("credentials") IssuerCredentials credentials, @@ -587,35 +590,35 @@ IssuerBundle updateCertificateIssuer(@EndpointParam URI vaultBaseUrl, @PathParam @DELETE @Path("/certificates/issuers/{issuerName}") @Fallback(NullOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) IssuerBundle deleteCertificateIssuer(@EndpointParam URI vaultBaseUrl, @PathParam("issuerName") String issuerName); @Named("certificate:get_contacts") @GET @Path("/certificates/contacts") @Fallback(NullOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) Contacts getCertificateContacts(@EndpointParam URI vaultBaseUrl); @Named("certificate:set_contacts") @PUT @Path("/certificates/contacts") @MapBinder(BindToJsonPayload.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) Contacts setCertificateContacts(@EndpointParam URI vaultBaseUrl, @PayloadParam("contacts") List contacts); @Named("certificate:delete_contacts") @DELETE @Path("/certificates/contacts") @Fallback(NullOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) Contacts deleteCertificateContacts(@EndpointParam URI vaultBaseUrl); @Named("certificate:get_policy") @GET @Path("/certificates/{certificateName}/policy") @Fallback(NullOnNotFoundOr404.class) - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) CertificatePolicy getCertificatePolicy(@EndpointParam URI vaultBaseUrl, @PathParam("certificateName") String certificateName); @@ -623,7 +626,7 @@ CertificatePolicy getCertificatePolicy(@EndpointParam URI vaultBaseUrl, @PATCH @MapBinder(BindToJsonPayload.class) @Path("/certificates/{certificateName}/policy") - @OAuthResource("https://vault.azure.net") + @OAuthResource(value = VAULT_API_STANDARD_ENDPOINT, chinaEndpoint = VAULT_API_CHINA_ENDPOINT) CertificatePolicy updateCertificatePolicy(@EndpointParam URI vaultBaseUrl, @PathParam("certificateName") String certificateName, @Nullable @PayloadParam("attributes") CertificateAttributes attributes, diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/config/IsChinaEndpointTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/config/IsChinaEndpointTest.java new file mode 100644 index 00000000000..35d982037b6 --- /dev/null +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/config/IsChinaEndpointTest.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.azurecompute.arm.config; + +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import org.testng.annotations.Test; + +@Test(groups = "unit", testName = "IsChinaEndpointTest") +public class IsChinaEndpointTest { + + @Test + public void testIsChinaEndpoint() { + AzureComputeHttpApiModule module = new AzureComputeHttpApiModule(); + + assertTrue(module.isChinaEndpoint("https://login.chinacloudapi.cn/tenantId/oauth2/token")); + assertFalse(module.isChinaEndpoint("http://login.chinacloudapi.cn/tenantId/oauth2/token")); + assertFalse(module.isChinaEndpoint("https://login.chinacloudapi.cn/otherpaths/not/oauth")); + assertFalse(module.isChinaEndpoint("https://login.microsoftonline.com/tenantId/oauth2/token")); + assertFalse(module.isChinaEndpoint("https://login.microsoft.com/otherpaths/not/oauth")); + } + +} diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/config/ParseTenantIdTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/config/ParseTenantIdTest.java index 5894505f894..2fafdc97364 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/config/ParseTenantIdTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/config/ParseTenantIdTest.java @@ -30,12 +30,15 @@ public void testParseTenantId() { assertEquals(module.provideTenant("https://login.microsoftonline.com/tenantId/oauth2/token"), "tenantId"); assertEquals(module.provideTenant("https://login.microsoft.com/tenant2/oauth2/token"), "tenant2"); - + assertEquals(module.provideTenant("https://login.chinacloudapi.cn/tenantId/oauth2/token"), "tenantId"); + assertEquals(module.provideTenant("https://login.chinacloudapi.cn/tenant2/oauth2/token"), "tenant2"); + assertInvalid(module, "https://login.microsoftonline.com/a/b/c/oauth2/token"); assertInvalid(module, "https://login.microsoft.com/a/b/c/oauth2/token"); assertInvalid(module, "https://login.microsoftonline.com//oauth2/token"); assertInvalid(module, "https://login.microsoft.com//oauth2/token"); - assertInvalid(module, "https://login.microsoftabc.com/tenant/oauth2/token"); + assertInvalid(module, "https://login.chinacloudapi.cn/a/b/c/oauth2/token"); + assertInvalid(module, "https://login.chinacloudapi.cn//oauth2/token"); } private static void assertInvalid(AzureComputeHttpApiModule module, String endpoint) { diff --git a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java index 11bed4d482c..50f2e41c891 100644 --- a/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java +++ b/providers/azurecompute-arm/src/test/java/org/jclouds/azurecompute/arm/internal/BaseAzureComputeApiLiveTest.java @@ -17,7 +17,6 @@ package org.jclouds.azurecompute.arm.internal; import static com.google.common.base.Preconditions.checkNotNull; - import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.VAULT_CERTIFICATE_DELETE_STATUS; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.VAULT_CERTIFICATE_OPERATION_STATUS; @@ -28,6 +27,7 @@ import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.VAULT_SECRET_DELETE_STATUS; import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.VAULT_SECRET_RECOVERABLE_STATUS; import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_IMAGE_AVAILABLE; +import static org.jclouds.oauth.v2.config.OAuthProperties.RESOURCE; import static org.jclouds.util.Predicates2.retry; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; @@ -166,6 +166,7 @@ public void setup() { // for oauth AzureLiveTestUtils.defaultProperties(properties); checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); + setIfTestSystemPropertyPresent(properties, RESOURCE); return properties; }