From d5a3639de1018c0eeaf00d81a9990ce2bd174043 Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Mon, 1 Aug 2016 10:30:20 -0700 Subject: [PATCH 01/15] Add graph tests --- .../ApplicationTokenCredentials.java | 28 +++++++++++++++- .../credentials/UserTokenCredentials.java | 32 ++++++++++++++++++- .../com/microsoft/azure/AzureEnvironment.java | 2 +- 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java index 384ab3f767..abe3a65c9b 100644 --- a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java +++ b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java @@ -24,6 +24,8 @@ * Token based credentials for use with a REST Service Client. */ public class ApplicationTokenCredentials extends TokenCredentials { + /** The endpoint of the target resource. */ + private String resourceEndpoint; /** The active directory application client id. */ private String clientId; /** The tenant or domain the containing the application. */ @@ -56,6 +58,30 @@ public ApplicationTokenCredentials(String clientId, String domain, String secret } else { this.environment = environment; } + this.resourceEndpoint = this.environment.getTokenAudience(); + } + + /** + * Initializes a new instance of the UserTokenCredentials. + * + * @param clientId the active directory application client id. + * @param domain the domain or tenant id containing this application. + * @param secret the authentication secret for the application. + * @param resourceEndpoint the endpoint of the target resource. + * @param environment the Azure environment to authenticate with. + * If null is provided, AzureEnvironment.AZURE will be used. + */ + public ApplicationTokenCredentials(String clientId, String domain, String secret, String resourceEndpoint, AzureEnvironment environment) { + super(null, null); // defer token acquisition + this.clientId = clientId; + this.domain = domain; + this.secret = secret; + this.resourceEndpoint = resourceEndpoint; + if (environment == null) { + this.environment = AzureEnvironment.AZURE; + } else { + this.environment = environment; + } } /** @@ -212,7 +238,7 @@ private void acquireAccessToken() throws IOException { AuthenticationContext context = new AuthenticationContext(authorityUrl, this.getEnvironment().isValidateAuthority(), executor); try { authenticationResult = context.acquireToken( - this.getEnvironment().getTokenAudience(), + this.resourceEndpoint, new ClientCredential(this.getClientId(), this.getSecret()), null).get(); } catch (Exception e) { diff --git a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/UserTokenCredentials.java b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/UserTokenCredentials.java index 60d6bdb3c0..c37479771a 100644 --- a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/UserTokenCredentials.java +++ b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/UserTokenCredentials.java @@ -21,6 +21,8 @@ * Token based credentials for use with a REST Service Client. */ public class UserTokenCredentials extends TokenCredentials { + /** The endpoint of the target resource. */ + private String resourceEndpoint; /** The Active Directory application client id. */ private String clientId; /** The domain or tenant id containing this application. */ @@ -59,6 +61,34 @@ public UserTokenCredentials(String clientId, String domain, String username, Str } else { this.environment = environment; } + this.resourceEndpoint = this.environment.getTokenAudience(); + } + + /** + * Initializes a new instance of the UserTokenCredentials. + * + * @param clientId the active directory application client id. + * @param domain the domain or tenant id containing this application. + * @param username the user name for the Organization Id account. + * @param password the password for the Organization Id account. + * @param clientRedirectUri the Uri where the user will be redirected after authenticating with AD. + * @param resourceEndpoint the endpoint of the target resource. + * @param environment the Azure environment to authenticate with. + * If null is provided, AzureEnvironment.AZURE will be used. + */ + public UserTokenCredentials(String clientId, String domain, String username, String password, String clientRedirectUri, String resourceEndpoint, AzureEnvironment environment) { + super(null, null); // defer token acquisition + this.clientId = clientId; + this.domain = domain; + this.username = username; + this.password = password; + this.clientRedirectUri = clientRedirectUri; + this.resourceEndpoint = resourceEndpoint; + if (environment == null) { + this.environment = AzureEnvironment.AZURE; + } else { + this.environment = environment; + } } /** @@ -136,7 +166,7 @@ private void acquireAccessToken() throws IOException { AuthenticationContext context = new AuthenticationContext(authorityUrl, this.getEnvironment().isValidateAuthority(), Executors.newSingleThreadExecutor()); try { authenticationResult = context.acquireToken( - this.getEnvironment().getTokenAudience(), + this.resourceEndpoint, this.getClientId(), this.getUsername(), this.getPassword(), diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java b/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java index 04a6af99d9..897e29b622 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java @@ -56,7 +56,7 @@ public AzureEnvironment( * Provides the settings for authentication with Azure. */ public static final AzureEnvironment AZURE = new AzureEnvironment( - "https://login.windows.net/", + "https://login.microsoftonline.com/", "https://management.core.windows.net/", true, "https://management.azure.com/"); From e6c05e1dfbaafd5289eb45ed2e1e342f4cbd01fc Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Wed, 3 Aug 2016 17:59:29 -0700 Subject: [PATCH 02/15] Add group & add graph endpoints to AzureEnvironment --- .../ApplicationTokenCredentials.java | 4 +- .../credentials/UserTokenCredentials.java | 2 +- .../com/microsoft/azure/AzureEnvironment.java | 66 ++++++++++++------- 3 files changed, 44 insertions(+), 28 deletions(-) diff --git a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java index abe3a65c9b..cc34d1cea7 100644 --- a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java +++ b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java @@ -58,7 +58,7 @@ public ApplicationTokenCredentials(String clientId, String domain, String secret } else { this.environment = environment; } - this.resourceEndpoint = this.environment.getTokenAudience(); + this.resourceEndpoint = this.environment.getManagementEndpoint(); } /** @@ -155,7 +155,7 @@ public static ApplicationTokenCredentials fromFile(File credentialsFile) throws Properties authSettings = new Properties(); authSettings.put(CredentialSettings.AUTH_URL.toString(), AzureEnvironment.AZURE.getAuthenticationEndpoint()); authSettings.put(CredentialSettings.BASE_URL.toString(), AzureEnvironment.AZURE.getBaseUrl()); - authSettings.put(CredentialSettings.MANAGEMENT_URI.toString(), AzureEnvironment.AZURE.getTokenAudience()); + authSettings.put(CredentialSettings.MANAGEMENT_URI.toString(), AzureEnvironment.AZURE.getManagementEndpoint()); // Load the credentials from the file FileInputStream credentialsFileStream = new FileInputStream(credentialsFile); diff --git a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/UserTokenCredentials.java b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/UserTokenCredentials.java index c37479771a..b703d50ca1 100644 --- a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/UserTokenCredentials.java +++ b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/UserTokenCredentials.java @@ -61,7 +61,7 @@ public UserTokenCredentials(String clientId, String domain, String username, Str } else { this.environment = environment; } - this.resourceEndpoint = this.environment.getTokenAudience(); + this.resourceEndpoint = this.environment.getManagementEndpoint(); } /** diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java b/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java index 897e29b622..df8a724e79 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java @@ -14,17 +14,22 @@ public final class AzureEnvironment { /** * Base URL for calls to Azure management API. */ - private final String baseURL; + private final String resourceManagerEndpoint; /** - * ActiveDirectory Endpoint for the Azure Environment. + * ActiveDirectory Endpoint for the authentications. */ private String authenticationEndpoint; /** - * Token audience for an endpoint. + * Base URL for calls to service management and authentications to Active Directory. */ - private String tokenAudience; + private String managementEndpoint; + + /** + * Base URL for calls to graph API. + */ + private String graphEndpoint; /** * Determines whether the authentication endpoint should @@ -36,20 +41,20 @@ public final class AzureEnvironment { * Initializes an instance of AzureEnvironment class. * * @param authenticationEndpoint ActiveDirectory Endpoint for the Azure Environment. - * @param tokenAudience token audience for an endpoint. - * @param validateAuthority whether the authentication endpoint should - * be validated with Azure AD. - * @param baseUrl the base URL for the current environment. + * @param managementEndpoint token audience for an endpoint. + * @param resourceManagerEndpoint the base URL for the current environment. + * @param graphEndpoint the base URL for graph API. */ public AzureEnvironment( String authenticationEndpoint, - String tokenAudience, - boolean validateAuthority, - String baseUrl) { + String managementEndpoint, + String resourceManagerEndpoint, + String graphEndpoint) { this.authenticationEndpoint = authenticationEndpoint; - this.tokenAudience = tokenAudience; - this.validateAuthority = validateAuthority; - this.baseURL = baseUrl; + this.managementEndpoint = managementEndpoint; + this.resourceManagerEndpoint = resourceManagerEndpoint; + this.graphEndpoint = graphEndpoint; + this.validateAuthority = true; } /** @@ -58,8 +63,8 @@ public AzureEnvironment( public static final AzureEnvironment AZURE = new AzureEnvironment( "https://login.microsoftonline.com/", "https://management.core.windows.net/", - true, - "https://management.azure.com/"); + "https://management.azure.com/", + "https://graph.windows.net/"); /** * Provides the settings for authentication with Azure China. @@ -67,8 +72,8 @@ public AzureEnvironment( public static final AzureEnvironment AZURE_CHINA = new AzureEnvironment( "https://login.chinacloudapi.cn/", "https://management.core.chinacloudapi.cn/", - true, - "https://management.chinacloudapi.cn/"); + "https://management.chinacloudapi.cn/", + "https://graph.chinacloudapi.cn/"); /** * Provides the settings for authentication with Azure US Government. @@ -76,8 +81,8 @@ public AzureEnvironment( public static final AzureEnvironment AZURE_US_GOVERNMENT = new AzureEnvironment( "https://login.microsoftonline.com/", "https://management.core.usgovcloudapi.net/", - true, - "https://management.usgovcloudapi.net/"); + "https://management.usgovcloudapi.net/", + "https://graph.windows.net/"); /** * Provides the settings for authentication with Azure Germany. @@ -85,8 +90,8 @@ public AzureEnvironment( public static final AzureEnvironment AZURE_GERMANY = new AzureEnvironment( "https://login.microsoftonline.de/", "https://management.core.cloudapi.de/", - true, - "https://management.microsoftazure.de/"); + "https://management.microsoftazure.de/", + "https://graph.cloudapi.de/"); /** * Gets the base URL of the management service. @@ -94,7 +99,7 @@ public AzureEnvironment( * @return the Base URL for the management service. */ public String getBaseUrl() { - return this.baseURL; + return this.resourceManagerEndpoint; } /** @@ -122,8 +127,8 @@ public String getAuthenticationEndpoint() { * * @return the token audience for an endpoint. */ - public String getTokenAudience() { - return tokenAudience; + public String getManagementEndpoint() { + return managementEndpoint; } /** @@ -136,4 +141,15 @@ public String getTokenAudience() { public boolean isValidateAuthority() { return validateAuthority; } + + /** + * Sets whether the authentication endpoint should + * be validated with Azure AD. + * + * @param validateAuthority true if the authentication endpoint should + * be validated with Azure AD, false otherwise. + */ + public void setValidateAuthority(boolean validateAuthority) { + this.validateAuthority = validateAuthority; + } } From 89fc914aec9b98702dde62e09f5df6c3da27c285 Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Mon, 8 Aug 2016 11:52:31 -0700 Subject: [PATCH 03/15] Regen graph and a bunch of refactors --- .../azure/credentials/ApplicationTokenCredentials.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java index cc34d1cea7..94af0f3192 100644 --- a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java +++ b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java @@ -177,8 +177,8 @@ public static ApplicationTokenCredentials fromFile(File credentialsFile) throws new AzureEnvironment( authUrl, mgmtUri, - true, - baseUrl) + baseUrl, + "https://graph.windows.net/") // TODO: cred file should contain GRAPH endpoint ).withDefaultSubscriptionId(defaultSubscriptionId); } From ac061a5496f66aee295e8ea2907f9e1c1185fb0c Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Wed, 10 Aug 2016 16:18:38 -0700 Subject: [PATCH 04/15] Allow specifying upn and spn --- .../microsoft/azure/ParallelServiceCall.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 azure-client-runtime/src/main/java/com/microsoft/azure/ParallelServiceCall.java diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/ParallelServiceCall.java b/azure-client-runtime/src/main/java/com/microsoft/azure/ParallelServiceCall.java new file mode 100644 index 0000000000..3163841520 --- /dev/null +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/ParallelServiceCall.java @@ -0,0 +1,50 @@ +package com.microsoft.azure; + +import com.microsoft.rest.ServiceCall; + +import java.util.concurrent.ConcurrentLinkedQueue; + +/** + * Type represents a set of REST calls running possibly in parallel. + */ +public class ParallelServiceCall extends ServiceCall { + private ConcurrentLinkedQueue> serviceCalls; + + /** + * Creates a ParallelServiceCall. + */ + public ParallelServiceCall() { + super(null); + this.serviceCalls = new ConcurrentLinkedQueue<>(); + } + + /** + * Cancels all the service calls currently executing. + */ + public void cancel() { + for (ServiceCall call : this.serviceCalls) { + call.cancel(); + } + } + + /** + * @return true if the call has been canceled; false otherwise. + */ + public boolean isCancelled() { + for (ServiceCall call : this.serviceCalls) { + if (!call.isCanceled()) { + return false; + } + } + return true; + } + + /** + * Add a call to the list of parallel calls. + * + * @param call the call + */ + public void addCall(ServiceCall call) { + this.serviceCalls.add(call); + } +} From c25c32a3973a6709de06674095f31e15370fb39a Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Fri, 2 Sep 2016 15:27:10 -0700 Subject: [PATCH 05/15] Supports spn & upn config in vault creation --- .../ApplicationTokenCredentials.java | 80 ++++++------------- .../credentials/UserTokenCredentials.java | 7 +- .../com/microsoft/azure/AzureEnvironment.java | 4 + .../credentials/AzureTokenCredentials.java | 26 ++++++ .../AzureTokenCredentialsInterceptor.java | 59 ++++++++++++++ .../rest/ServiceResponseBuilder.java | 10 +-- 6 files changed, 126 insertions(+), 60 deletions(-) create mode 100644 azure-client-runtime/src/main/java/com/microsoft/azure/credentials/AzureTokenCredentials.java create mode 100644 azure-client-runtime/src/main/java/com/microsoft/azure/credentials/AzureTokenCredentialsInterceptor.java diff --git a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java index 94af0f3192..ef1ee836ba 100644 --- a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java +++ b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java @@ -12,10 +12,14 @@ import com.microsoft.aad.adal4j.ClientCredential; import com.microsoft.azure.AzureEnvironment; import com.microsoft.rest.credentials.TokenCredentials; +import okhttp3.OkHttpClient; import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; import java.util.Properties; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -23,19 +27,16 @@ /** * Token based credentials for use with a REST Service Client. */ -public class ApplicationTokenCredentials extends TokenCredentials { - /** The endpoint of the target resource. */ - private String resourceEndpoint; +public class ApplicationTokenCredentials extends TokenCredentials implements AzureTokenCredentials { + private Map tokens; + /** The Azure environment to authenticate with. */ + private AzureEnvironment environment; /** The active directory application client id. */ private String clientId; /** The tenant or domain the containing the application. */ private String domain; /** The authentication secret for the application. */ private String secret; - /** The Azure environment to authenticate with. */ - private AzureEnvironment environment; - /** The current authentication result. */ - private AuthenticationResult authenticationResult; /** The default subscription to use, if any. */ private String defaultSubscription; @@ -50,38 +51,11 @@ public class ApplicationTokenCredentials extends TokenCredentials { */ public ApplicationTokenCredentials(String clientId, String domain, String secret, AzureEnvironment environment) { super(null, null); // defer token acquisition + this.environment = environment; this.clientId = clientId; this.domain = domain; this.secret = secret; - if (environment == null) { - this.environment = AzureEnvironment.AZURE; - } else { - this.environment = environment; - } - this.resourceEndpoint = this.environment.getManagementEndpoint(); - } - - /** - * Initializes a new instance of the UserTokenCredentials. - * - * @param clientId the active directory application client id. - * @param domain the domain or tenant id containing this application. - * @param secret the authentication secret for the application. - * @param resourceEndpoint the endpoint of the target resource. - * @param environment the Azure environment to authenticate with. - * If null is provided, AzureEnvironment.AZURE will be used. - */ - public ApplicationTokenCredentials(String clientId, String domain, String secret, String resourceEndpoint, AzureEnvironment environment) { - super(null, null); // defer token acquisition - this.clientId = clientId; - this.domain = domain; - this.secret = secret; - this.resourceEndpoint = resourceEndpoint; - if (environment == null) { - this.environment = AzureEnvironment.AZURE; - } else { - this.environment = environment; - } + this.tokens = new HashMap<>(); } /** @@ -209,42 +183,40 @@ public String getSecret() { return secret; } - /** - * Gets the Azure environment to authenticate with. - * - * @return the Azure environment to authenticate with. - */ - public AzureEnvironment getEnvironment() { - return environment; - } - @Override - public String getToken() throws IOException { - if (authenticationResult == null - || authenticationResult.getAccessToken() == null) { - acquireAccessToken(); + public String getToken(String resource) throws IOException { + AuthenticationResult authenticationResult = tokens.get(resource); + if (authenticationResult == null || authenticationResult.getExpiresOnDate().before(new Date())) { + authenticationResult = acquireAccessToken(resource); } return authenticationResult.getAccessToken(); } @Override - public void refreshToken() throws IOException { - acquireAccessToken(); + public AzureEnvironment getEnvironment() { + return this.environment; } - private void acquireAccessToken() throws IOException { + private AuthenticationResult acquireAccessToken(String resource) throws IOException { String authorityUrl = this.getEnvironment().getAuthenticationEndpoint() + this.getDomain(); ExecutorService executor = Executors.newSingleThreadExecutor(); AuthenticationContext context = new AuthenticationContext(authorityUrl, this.getEnvironment().isValidateAuthority(), executor); try { - authenticationResult = context.acquireToken( - this.resourceEndpoint, + AuthenticationResult result = context.acquireToken( + resource, new ClientCredential(this.getClientId(), this.getSecret()), null).get(); + tokens.put(resource, result); + return result; } catch (Exception e) { throw new IOException(e.getMessage(), e); } finally { executor.shutdown(); } } + + @Override + public void applyCredentialsFilter(OkHttpClient.Builder clientBuilder) { + clientBuilder.interceptors().add(new AzureTokenCredentialsInterceptor(this)); + } } diff --git a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/UserTokenCredentials.java b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/UserTokenCredentials.java index b703d50ca1..704b0fde2b 100644 --- a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/UserTokenCredentials.java +++ b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/UserTokenCredentials.java @@ -20,7 +20,7 @@ /** * Token based credentials for use with a REST Service Client. */ -public class UserTokenCredentials extends TokenCredentials { +public class UserTokenCredentials extends TokenCredentials implements AzureTokenCredentials { /** The endpoint of the target resource. */ private String resourceEndpoint; /** The Active Directory application client id. */ @@ -136,6 +136,11 @@ public String getClientRedirectUri() { return clientRedirectUri; } + @Override + public String getToken(String resource) throws IOException { + return null; + } + /** * Gets the Azure environment to authenticate with. * diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java b/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java index df8a724e79..80e42856e4 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java @@ -131,6 +131,10 @@ public String getManagementEndpoint() { return managementEndpoint; } + public String getGraphEndpoint() { + return graphEndpoint; + } + /** * Gets whether the authentication endpoint should * be validated with Azure AD. diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/credentials/AzureTokenCredentials.java b/azure-client-runtime/src/main/java/com/microsoft/azure/credentials/AzureTokenCredentials.java new file mode 100644 index 0000000000..1f59be80cb --- /dev/null +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/credentials/AzureTokenCredentials.java @@ -0,0 +1,26 @@ +/** + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * + */ + +package com.microsoft.azure.credentials; + +import com.microsoft.azure.AzureEnvironment; +import com.microsoft.rest.credentials.ServiceClientCredentials; + +import java.io.IOException; + +/** + * AzureServiceClientCredentials is the abstraction for credentials used by + * ServiceClients accessing Azure. + */ +public interface AzureTokenCredentials extends ServiceClientCredentials { + String getToken(String resource) throws IOException; + + /** + * @return the environment details the credential has access to. + */ + AzureEnvironment getEnvironment(); +} diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/credentials/AzureTokenCredentialsInterceptor.java b/azure-client-runtime/src/main/java/com/microsoft/azure/credentials/AzureTokenCredentialsInterceptor.java new file mode 100644 index 0000000000..33f8b7c7a1 --- /dev/null +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/credentials/AzureTokenCredentialsInterceptor.java @@ -0,0 +1,59 @@ +/** + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * + */ + +package com.microsoft.azure.credentials; + +import okhttp3.Interceptor; +import okhttp3.Request; +import okhttp3.Response; + +import java.io.IOException; + +/** + * Token credentials filter for placing a token credential into request headers. + */ +public class AzureTokenCredentialsInterceptor implements Interceptor { + /** + * The credentials instance to apply to the HTTP client pipeline. + */ + private AzureTokenCredentials credentials; + + /** + * Initialize a TokenCredentialsFilter class with a + * TokenCredentials credential. + * + * @param credentials a TokenCredentials instance + */ + public AzureTokenCredentialsInterceptor(AzureTokenCredentials credentials) { + this.credentials = credentials; + } + + @Override + public Response intercept(Chain chain) throws IOException { + String resource = credentials.getEnvironment().getManagementEndpoint(); + // Use graph resource if the host if graph endpoint + if (credentials.getEnvironment().getGraphEndpoint().contains(chain.request().url().host())) { + resource = credentials.getEnvironment().getGraphEndpoint(); + } + Request newRequest = chain.request().newBuilder() + .header("Authorization", "Bearer " + credentials.getToken(resource)) + .build(); + return chain.proceed(newRequest); + } + + private Response sendRequestWithToken(Chain chain) throws IOException { + String resource = credentials.getEnvironment().getManagementEndpoint(); + // Use graph resource if the host if graph endpoint + if (chain.request().url().host().equals(credentials.getEnvironment().getGraphEndpoint())) { + resource = credentials.getEnvironment().getGraphEndpoint(); + } + Request newRequest = chain.request().newBuilder() + .header("Authorization", "Bearer " + credentials.getToken(resource)) + .build(); + return chain.proceed(newRequest); + } +} diff --git a/client-runtime/src/main/java/com/microsoft/rest/ServiceResponseBuilder.java b/client-runtime/src/main/java/com/microsoft/rest/ServiceResponseBuilder.java index 3ad57cb938..34d11a14c1 100644 --- a/client-runtime/src/main/java/com/microsoft/rest/ServiceResponseBuilder.java +++ b/client-runtime/src/main/java/com/microsoft/rest/ServiceResponseBuilder.java @@ -9,6 +9,8 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.microsoft.rest.serializer.JacksonMapperAdapter; +import okhttp3.ResponseBody; +import retrofit2.Response; import java.io.IOException; import java.io.InputStream; @@ -18,9 +20,6 @@ import java.util.HashMap; import java.util.Map; -import okhttp3.ResponseBody; -import retrofit2.Response; - /** * The builder for building a {@link ServiceResponse}. * @@ -144,9 +143,10 @@ public ServiceResponse build(Response response) throws E, IOExc return new ServiceResponse<>((T) buildBody(statusCode, responseBody), response); } else { try { - E exception = (E) exceptionType.getConstructor(String.class).newInstance("Invalid status code " + statusCode); + Object errorBody = buildBody(statusCode, responseBody); + E exception = (E) exceptionType.getConstructor(String.class).newInstance(mapperAdapter.serialize(errorBody)); exceptionType.getMethod("setResponse", response.getClass()).invoke(exception, response); - exceptionType.getMethod("setBody", (Class) responseTypes.get(0)).invoke(exception, buildBody(statusCode, responseBody)); + exceptionType.getMethod("setBody", (Class) responseTypes.get(0)).invoke(exception, errorBody); throw exception; } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { throw new IOException("Invalid status code " + statusCode + ", but an instance of " + exceptionType.getCanonicalName() From 7d1f0d83faac62e53970035a56f68050f698c9aa Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Fri, 2 Sep 2016 17:02:33 -0700 Subject: [PATCH 06/15] Enable user login --- .../ApplicationTokenCredentials.java | 1 + .../credentials/UserTokenCredentials.java | 108 ++++++------------ .../UserTokenCredentialsTests.java | 5 +- .../com/microsoft/azure/AzureEnvironment.java | 2 +- 4 files changed, 37 insertions(+), 79 deletions(-) diff --git a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java index ef1ee836ba..7cfd0aa813 100644 --- a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java +++ b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java @@ -28,6 +28,7 @@ * Token based credentials for use with a REST Service Client. */ public class ApplicationTokenCredentials extends TokenCredentials implements AzureTokenCredentials { + /** A mapping from resource endpoint to its cached access token. */ private Map tokens; /** The Azure environment to authenticate with. */ private AzureEnvironment environment; diff --git a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/UserTokenCredentials.java b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/UserTokenCredentials.java index 704b0fde2b..179b6d5a2f 100644 --- a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/UserTokenCredentials.java +++ b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/UserTokenCredentials.java @@ -11,9 +11,12 @@ import com.microsoft.aad.adal4j.AuthenticationResult; import com.microsoft.azure.AzureEnvironment; import com.microsoft.rest.credentials.TokenCredentials; +import okhttp3.OkHttpClient; import java.io.IOException; import java.util.Date; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -21,8 +24,8 @@ * Token based credentials for use with a REST Service Client. */ public class UserTokenCredentials extends TokenCredentials implements AzureTokenCredentials { - /** The endpoint of the target resource. */ - private String resourceEndpoint; + /** A mapping from resource endpoint to its cached access token. */ + private Map tokens; /** The Active Directory application client id. */ private String clientId; /** The domain or tenant id containing this application. */ @@ -31,12 +34,8 @@ public class UserTokenCredentials extends TokenCredentials implements AzureToken private String username; /** The password for the Organization Id account. */ private String password; - /** The Uri where the user will be redirected after authenticating with AD. */ - private String clientRedirectUri; /** The Azure environment to authenticate with. */ private AzureEnvironment environment; - /** The current authentication result. */ - private AuthenticationResult authenticationResult; /** * Initializes a new instance of the UserTokenCredentials. @@ -45,50 +44,17 @@ public class UserTokenCredentials extends TokenCredentials implements AzureToken * @param domain the domain or tenant id containing this application. * @param username the user name for the Organization Id account. * @param password the password for the Organization Id account. - * @param clientRedirectUri the Uri where the user will be redirected after authenticating with AD. * @param environment the Azure environment to authenticate with. * If null is provided, AzureEnvironment.AZURE will be used. */ - public UserTokenCredentials(String clientId, String domain, String username, String password, String clientRedirectUri, AzureEnvironment environment) { + public UserTokenCredentials(String clientId, String domain, String username, String password, AzureEnvironment environment) { super(null, null); // defer token acquisition this.clientId = clientId; this.domain = domain; this.username = username; this.password = password; - this.clientRedirectUri = clientRedirectUri; - if (environment == null) { - this.environment = AzureEnvironment.AZURE; - } else { - this.environment = environment; - } - this.resourceEndpoint = this.environment.getManagementEndpoint(); - } - - /** - * Initializes a new instance of the UserTokenCredentials. - * - * @param clientId the active directory application client id. - * @param domain the domain or tenant id containing this application. - * @param username the user name for the Organization Id account. - * @param password the password for the Organization Id account. - * @param clientRedirectUri the Uri where the user will be redirected after authenticating with AD. - * @param resourceEndpoint the endpoint of the target resource. - * @param environment the Azure environment to authenticate with. - * If null is provided, AzureEnvironment.AZURE will be used. - */ - public UserTokenCredentials(String clientId, String domain, String username, String password, String clientRedirectUri, String resourceEndpoint, AzureEnvironment environment) { - super(null, null); // defer token acquisition - this.clientId = clientId; - this.domain = domain; - this.username = username; - this.password = password; - this.clientRedirectUri = clientRedirectUri; - this.resourceEndpoint = resourceEndpoint; - if (environment == null) { - this.environment = AzureEnvironment.AZURE; - } else { - this.environment = environment; - } + this.environment = environment; + this.tokens = new HashMap<>(); } /** @@ -127,18 +93,13 @@ public String getPassword() { return password; } - /** - * Gets the Uri where the user will be redirected after authenticating with AD. - * - * @return the redirecting Uri. - */ - public String getClientRedirectUri() { - return clientRedirectUri; - } - @Override public String getToken(String resource) throws IOException { - return null; + AuthenticationResult authenticationResult = tokens.get(resource); + if (authenticationResult == null || authenticationResult.getExpiresOnDate().before(new Date())) { + authenticationResult = acquireAccessToken(resource); + } + return authenticationResult.getAccessToken(); } /** @@ -150,50 +111,47 @@ public AzureEnvironment getEnvironment() { return environment; } - @Override - public String getToken() throws IOException { - if (authenticationResult != null - && authenticationResult.getExpiresOnDate().before(new Date())) { - acquireAccessTokenFromRefreshToken(); - } else { - acquireAccessToken(); - } - return authenticationResult.getAccessToken(); - } - - @Override - public void refreshToken() throws IOException { - acquireAccessToken(); - } - - private void acquireAccessToken() throws IOException { + private AuthenticationResult acquireAccessToken(String resource) throws IOException { String authorityUrl = this.getEnvironment().getAuthenticationEndpoint() + this.getDomain(); - AuthenticationContext context = new AuthenticationContext(authorityUrl, this.getEnvironment().isValidateAuthority(), Executors.newSingleThreadExecutor()); + ExecutorService executor = Executors.newSingleThreadExecutor(); + AuthenticationContext context = new AuthenticationContext(authorityUrl, this.getEnvironment().isValidateAuthority(), executor); try { - authenticationResult = context.acquireToken( - this.resourceEndpoint, + AuthenticationResult result = context.acquireToken( + resource, this.getClientId(), this.getUsername(), this.getPassword(), null).get(); + tokens.put(resource, result); + return result; } catch (Exception e) { throw new IOException(e.getMessage(), e); + } finally { + executor.shutdown(); } } - private void acquireAccessTokenFromRefreshToken() throws IOException { + // Refresh tokens are currently not used since we don't know if the refresh token has expired + private AuthenticationResult acquireAccessTokenFromRefreshToken(String resource) throws IOException { String authorityUrl = this.getEnvironment().getAuthenticationEndpoint() + this.getDomain(); ExecutorService executor = Executors.newSingleThreadExecutor(); AuthenticationContext context = new AuthenticationContext(authorityUrl, this.getEnvironment().isValidateAuthority(), executor); try { - authenticationResult = context.acquireTokenByRefreshToken( - authenticationResult.getRefreshToken(), + AuthenticationResult result = context.acquireTokenByRefreshToken( + tokens.get(resource).getRefreshToken(), this.getClientId(), null, null).get(); + tokens.put(resource, result); + return result; } catch (Exception e) { throw new IOException(e.getMessage(), e); } finally { executor.shutdown(); } } + + @Override + public void applyCredentialsFilter(OkHttpClient.Builder clientBuilder) { + clientBuilder.interceptors().add(new AzureTokenCredentialsInterceptor(this)); + } } diff --git a/azure-client-authentication/src/test/java/com/microsoft/azure/credentials/UserTokenCredentialsTests.java b/azure-client-authentication/src/test/java/com/microsoft/azure/credentials/UserTokenCredentialsTests.java index 7905ba7e7b..caab41dd8e 100644 --- a/azure-client-authentication/src/test/java/com/microsoft/azure/credentials/UserTokenCredentialsTests.java +++ b/azure-client-authentication/src/test/java/com/microsoft/azure/credentials/UserTokenCredentialsTests.java @@ -21,7 +21,6 @@ public class UserTokenCredentialsTests { "domain", "username", "password", - "redirect", AzureEnvironment.AZURE ); @@ -36,8 +35,8 @@ public void testAcquireToken() throws Exception { public static class MockUserTokenCredentials extends UserTokenCredentials { private AuthenticationResult authenticationResult; - public MockUserTokenCredentials(String clientId, String domain, String username, String password, String clientRedirectUri, AzureEnvironment environment) { - super(clientId, domain, username, password, clientRedirectUri, environment); + public MockUserTokenCredentials(String clientId, String domain, String username, String password, AzureEnvironment environment) { + super(clientId, domain, username, password, environment); } @Override diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java b/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java index 80e42856e4..cce24b0972 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java @@ -54,7 +54,7 @@ public AzureEnvironment( this.managementEndpoint = managementEndpoint; this.resourceManagerEndpoint = resourceManagerEndpoint; this.graphEndpoint = graphEndpoint; - this.validateAuthority = true; + this.validateAuthority = false; } /** From 7b325e287b2a14571de9782d009d551cf02ebf4d Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Wed, 7 Sep 2016 15:40:55 -0700 Subject: [PATCH 07/15] Add tenantId requirement on roll-up client --- .../azure/credentials/ApplicationTokenCredentials.java | 1 + .../com/microsoft/azure/credentials/UserTokenCredentials.java | 1 + .../com/microsoft/azure/credentials/AzureTokenCredentials.java | 2 ++ 3 files changed, 4 insertions(+) diff --git a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java index 7cfd0aa813..48b4a06101 100644 --- a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java +++ b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java @@ -171,6 +171,7 @@ public String getClientId() { * * @return the tenant or domain the containing the application. */ + @Override public String getDomain() { return domain; } diff --git a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/UserTokenCredentials.java b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/UserTokenCredentials.java index 179b6d5a2f..9da95726b1 100644 --- a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/UserTokenCredentials.java +++ b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/UserTokenCredentials.java @@ -71,6 +71,7 @@ public String getClientId() { * * @return the tenant or domain the containing the application. */ + @Override public String getDomain() { return domain; } diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/credentials/AzureTokenCredentials.java b/azure-client-runtime/src/main/java/com/microsoft/azure/credentials/AzureTokenCredentials.java index 1f59be80cb..52c5e89ab5 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/credentials/AzureTokenCredentials.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/credentials/AzureTokenCredentials.java @@ -19,6 +19,8 @@ public interface AzureTokenCredentials extends ServiceClientCredentials { String getToken(String resource) throws IOException; + String getDomain(); + /** * @return the environment details the credential has access to. */ From bc575ae2415793f7361628272d7eb9ac5a1b9396 Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Thu, 8 Sep 2016 16:18:26 -0700 Subject: [PATCH 08/15] Allow empty pages in paged list --- .../java/com/microsoft/azure/PagedList.java | 55 +++++++++---------- .../com/microsoft/azure/PagedListTests.java | 14 +++-- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/PagedList.java b/azure-client-runtime/src/main/java/com/microsoft/azure/PagedList.java index 8db10337d9..7cae0efe0c 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/PagedList.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/PagedList.java @@ -17,8 +17,6 @@ import java.util.ListIterator; import java.util.NoSuchElementException; -import javax.xml.bind.DataBindingException; - /** * Defines a list response from a paging operation. The pages are * lazy initialized when an instance of this class is iterated. @@ -28,10 +26,10 @@ public abstract class PagedList implements List { /** The actual items in the list. */ private List items; - /** Stores the link to get the next page of items. */ - private String nextPageLink; /** Stores the latest page fetched. */ private Page currentPage; + /** Cached page right after the current one. */ + private Page cachedPage; /** * Creates an instance of Pagedlist. @@ -48,11 +46,26 @@ public PagedList() { public PagedList(Page page) { this(); List retrievedItems = page.getItems(); - if (retrievedItems != null && retrievedItems.size() != 0) { + if (retrievedItems != null) { items.addAll(retrievedItems); } - nextPageLink = page.getNextPageLink(); currentPage = page; + cachePage(page.getNextPageLink()); + } + + private void cachePage(String nextPageLink) { + try { + while (nextPageLink != null) { + cachedPage = nextPage(nextPageLink); + nextPageLink = cachedPage.getNextPageLink(); + if (hasNextPage()) { + // a legit, non-empty page has been fetched, otherwise keep fetching + break; + } + } + } catch (IOException ex) { + throw new RuntimeException(ex); + } } /** @@ -71,7 +84,7 @@ public PagedList(Page page) { * @return true if there are more pages to load. False otherwise. */ public boolean hasNextPage() { - return this.nextPageLink != null; + return this.cachedPage != null && this.cachedPage.getItems() != null && !this.cachedPage.getItems().isEmpty(); } /** @@ -79,14 +92,10 @@ public boolean hasNextPage() { * The exceptions are wrapped into Java Runtime exceptions. */ public void loadNextPage() { - try { - Page nextPage = nextPage(this.nextPageLink); - this.nextPageLink = nextPage.getNextPageLink(); - this.items.addAll(nextPage.getItems()); - this.currentPage = nextPage; - } catch (IOException e) { - throw new DataBindingException(e.getMessage(), e); - } + this.currentPage = cachedPage; + cachedPage = null; + this.items.addAll(currentPage.getItems()); + cachePage(currentPage.getNextPageLink()); } /** @@ -107,15 +116,6 @@ public Page currentPage() { return currentPage; } - /** - * Gets the next page's link. - * - * @return the next page link. - */ - public String nextPageLink() { - return nextPageLink; - } - /** * The implementation of {@link ListIterator} for PagedList. */ @@ -141,17 +141,14 @@ public boolean hasNext() { public E next() { if (!itemsListItr.hasNext()) { if (!hasNextPage()) { - throw new NoSuchElementException(); + throw new NoSuchElementException(); } else { int size = items.size(); loadNextPage(); itemsListItr = items.listIterator(size); } } - if (itemsListItr.hasNext()) { - return itemsListItr.next(); - } - return null; + return itemsListItr.next(); } @Override diff --git a/azure-client-runtime/src/test/java/com/microsoft/azure/PagedListTests.java b/azure-client-runtime/src/test/java/com/microsoft/azure/PagedListTests.java index b82c8d0628..04567aa1c6 100644 --- a/azure-client-runtime/src/test/java/com/microsoft/azure/PagedListTests.java +++ b/azure-client-runtime/src/test/java/com/microsoft/azure/PagedListTests.java @@ -21,11 +21,11 @@ public class PagedListTests { @Before public void setupList() { - list = new PagedList(new TestPage(0, 20)) { + list = new PagedList(new TestPage(0, 21)) { @Override public Page nextPage(String nextPageLink) throws CloudException, IOException { int pageNum = Integer.parseInt(nextPageLink); - return new TestPage(pageNum, 20); + return new TestPage(pageNum, 21); } }; } @@ -119,9 +119,13 @@ public String getNextPageLink() { @Override public List getItems() { - List items = new ArrayList<>(); - items.add(page); - return items; + if (page + 1 != max) { + List items = new ArrayList<>(); + items.add(page); + return items; + } else { + return new ArrayList<>(); + } } } } From 12cd83ead3f5fc5b7ad84975e1b5c8c3221c4bfd Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Thu, 8 Sep 2016 18:09:54 -0700 Subject: [PATCH 09/15] Adapt group paged list to new paged list --- .../main/java/com/microsoft/azure/PagedList.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/PagedList.java b/azure-client-runtime/src/main/java/com/microsoft/azure/PagedList.java index 7cae0efe0c..46c02402ed 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/PagedList.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/PagedList.java @@ -116,6 +116,20 @@ public Page currentPage() { return currentPage; } + /** + * Sets the current page. + * + * @param currentPage the current page. + */ + protected void setCurrentPage(Page currentPage) { + this.currentPage = currentPage; + List retrievedItems = currentPage.getItems(); + if (retrievedItems != null) { + items.addAll(retrievedItems); + } + cachePage(currentPage.getNextPageLink()); + } + /** * The implementation of {@link ListIterator} for PagedList. */ From 2bbd23ad94caf3529075829c5a529ae89dff8ea8 Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Fri, 9 Sep 2016 18:23:22 -0700 Subject: [PATCH 10/15] Add javadocs and address checkstyle --- .../com/microsoft/azure/AzureEnvironment.java | 11 ++++------- .../azure/credentials/AzureTokenCredentials.java | 16 ++++++++++++++-- .../azure/credentials/package-info.java | 6 ++++++ 3 files changed, 24 insertions(+), 9 deletions(-) create mode 100644 azure-client-runtime/src/main/java/com/microsoft/azure/credentials/package-info.java diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java b/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java index cce24b0972..421bc2869d 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java @@ -103,8 +103,6 @@ public String getBaseUrl() { } /** - * Gets a builder for {@link RestClient}. - * * @return a builder for the rest client. */ public RestClient.Builder.Buildable newRestClientBuilder() { @@ -114,8 +112,6 @@ public RestClient.Builder.Buildable newRestClientBuilder() { } /** - * Gets the ActiveDirectory Endpoint for the Azure Environment. - * * @return the ActiveDirectory Endpoint for the Azure Environment. */ public String getAuthenticationEndpoint() { @@ -123,14 +119,15 @@ public String getAuthenticationEndpoint() { } /** - * Gets the token audience for an endpoint. - * - * @return the token audience for an endpoint. + * @return the Azure Resource Manager endpoint for the environment. */ public String getManagementEndpoint() { return managementEndpoint; } + /** + * @return the Graph API endpoint. + */ public String getGraphEndpoint() { return graphEndpoint; } diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/credentials/AzureTokenCredentials.java b/azure-client-runtime/src/main/java/com/microsoft/azure/credentials/AzureTokenCredentials.java index 52c5e89ab5..d91962e798 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/credentials/AzureTokenCredentials.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/credentials/AzureTokenCredentials.java @@ -13,12 +13,24 @@ import java.io.IOException; /** - * AzureServiceClientCredentials is the abstraction for credentials used by - * ServiceClients accessing Azure. + * AzureTokenCredentials represents a credentials object with access to Azure + * Resource management. */ public interface AzureTokenCredentials extends ServiceClientCredentials { + /** + * Override this method to provide the mechanism to get a token. + * + * @param resource the resource the access token is for + * @return the token to access the resource + * @throws IOException exceptions from IO + */ String getToken(String resource) throws IOException; + /** + * Override this method to provide the domain or tenant ID the token is valid in. + * + * @return the domain or tenant ID string + */ String getDomain(); /** diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/credentials/package-info.java b/azure-client-runtime/src/main/java/com/microsoft/azure/credentials/package-info.java new file mode 100644 index 0000000000..22ff7d1a5d --- /dev/null +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/credentials/package-info.java @@ -0,0 +1,6 @@ +/** + * The package contains the credentials classes required for AutoRest generated + * Azure clients to compile and function. To learn more about AutoRest generator, + * see https://github.com/azure/autorest. + */ +package com.microsoft.azure.credentials; \ No newline at end of file From 26d2c0af3a17c659ed6d55d56ff5203beb5abbc5 Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Mon, 12 Sep 2016 18:58:15 -0700 Subject: [PATCH 11/15] Fix merge errors --- .../microsoft/azure/ParallelServiceCall.java | 50 ------------------- 1 file changed, 50 deletions(-) delete mode 100644 azure-client-runtime/src/main/java/com/microsoft/azure/ParallelServiceCall.java diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/ParallelServiceCall.java b/azure-client-runtime/src/main/java/com/microsoft/azure/ParallelServiceCall.java deleted file mode 100644 index 3163841520..0000000000 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/ParallelServiceCall.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.microsoft.azure; - -import com.microsoft.rest.ServiceCall; - -import java.util.concurrent.ConcurrentLinkedQueue; - -/** - * Type represents a set of REST calls running possibly in parallel. - */ -public class ParallelServiceCall extends ServiceCall { - private ConcurrentLinkedQueue> serviceCalls; - - /** - * Creates a ParallelServiceCall. - */ - public ParallelServiceCall() { - super(null); - this.serviceCalls = new ConcurrentLinkedQueue<>(); - } - - /** - * Cancels all the service calls currently executing. - */ - public void cancel() { - for (ServiceCall call : this.serviceCalls) { - call.cancel(); - } - } - - /** - * @return true if the call has been canceled; false otherwise. - */ - public boolean isCancelled() { - for (ServiceCall call : this.serviceCalls) { - if (!call.isCanceled()) { - return false; - } - } - return true; - } - - /** - * Add a call to the list of parallel calls. - * - * @param call the call - */ - public void addCall(ServiceCall call) { - this.serviceCalls.add(call); - } -} From 0eb2adc664a8c04d4b20fc336a7d13f0f94928e9 Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Thu, 15 Sep 2016 00:02:00 -0700 Subject: [PATCH 12/15] Remove throws on many methods --- .../java/com/microsoft/azure/PagedList.java | 23 ++++++------------- .../com/microsoft/azure/PagedListTests.java | 3 +-- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/PagedList.java b/azure-client-runtime/src/main/java/com/microsoft/azure/PagedList.java index 46c02402ed..86a4f9afcd 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/PagedList.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/PagedList.java @@ -7,9 +7,6 @@ package com.microsoft.azure; -import com.microsoft.rest.RestException; - -import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; @@ -54,17 +51,13 @@ public PagedList(Page page) { } private void cachePage(String nextPageLink) { - try { - while (nextPageLink != null) { - cachedPage = nextPage(nextPageLink); - nextPageLink = cachedPage.getNextPageLink(); - if (hasNextPage()) { - // a legit, non-empty page has been fetched, otherwise keep fetching - break; - } + while (nextPageLink != null) { + cachedPage = nextPage(nextPageLink); + nextPageLink = cachedPage.getNextPageLink(); + if (hasNextPage()) { + // a legit, non-empty page has been fetched, otherwise keep fetching + break; } - } catch (IOException ex) { - throw new RuntimeException(ex); } } @@ -73,10 +66,8 @@ private void cachePage(String nextPageLink) { * * @param nextPageLink the link to get the next page of items. * @return the {@link Page} object storing a page of items and a link to the next page. - * @throws RestException thrown if an error is raised from Azure. - * @throws IOException thrown if there's any failure in deserialization. */ - public abstract Page nextPage(String nextPageLink) throws RestException, IOException; + public abstract Page nextPage(String nextPageLink); /** * If there are more pages available. diff --git a/azure-client-runtime/src/test/java/com/microsoft/azure/PagedListTests.java b/azure-client-runtime/src/test/java/com/microsoft/azure/PagedListTests.java index 04567aa1c6..dfac454005 100644 --- a/azure-client-runtime/src/test/java/com/microsoft/azure/PagedListTests.java +++ b/azure-client-runtime/src/test/java/com/microsoft/azure/PagedListTests.java @@ -11,7 +11,6 @@ import org.junit.Before; import org.junit.Test; -import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -23,7 +22,7 @@ public class PagedListTests { public void setupList() { list = new PagedList(new TestPage(0, 21)) { @Override - public Page nextPage(String nextPageLink) throws CloudException, IOException { + public Page nextPage(String nextPageLink) { int pageNum = Integer.parseInt(nextPageLink); return new TestPage(pageNum, 21); } From 29bcf65ece840e3e49a34c2b87f68d71a9149cc2 Mon Sep 17 00:00:00 2001 From: Jianghao Lu Date: Thu, 15 Sep 2016 09:09:15 -0700 Subject: [PATCH 13/15] Let's not break everyone with paged list yet --- .../java/com/microsoft/azure/PagedList.java | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/PagedList.java b/azure-client-runtime/src/main/java/com/microsoft/azure/PagedList.java index 86a4f9afcd..46c02402ed 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/PagedList.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/PagedList.java @@ -7,6 +7,9 @@ package com.microsoft.azure; +import com.microsoft.rest.RestException; + +import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; @@ -51,13 +54,17 @@ public PagedList(Page page) { } private void cachePage(String nextPageLink) { - while (nextPageLink != null) { - cachedPage = nextPage(nextPageLink); - nextPageLink = cachedPage.getNextPageLink(); - if (hasNextPage()) { - // a legit, non-empty page has been fetched, otherwise keep fetching - break; + try { + while (nextPageLink != null) { + cachedPage = nextPage(nextPageLink); + nextPageLink = cachedPage.getNextPageLink(); + if (hasNextPage()) { + // a legit, non-empty page has been fetched, otherwise keep fetching + break; + } } + } catch (IOException ex) { + throw new RuntimeException(ex); } } @@ -66,8 +73,10 @@ private void cachePage(String nextPageLink) { * * @param nextPageLink the link to get the next page of items. * @return the {@link Page} object storing a page of items and a link to the next page. + * @throws RestException thrown if an error is raised from Azure. + * @throws IOException thrown if there's any failure in deserialization. */ - public abstract Page nextPage(String nextPageLink); + public abstract Page nextPage(String nextPageLink) throws RestException, IOException; /** * If there are more pages available. From 989fb1e460c201ab59ce5acf9866a40800a785b0 Mon Sep 17 00:00:00 2001 From: anuchan Date: Thu, 15 Sep 2016 19:47:51 -0700 Subject: [PATCH 14/15] Rework to simplify the create + update logic --- .../src/main/java/com/microsoft/azure/DAGraph.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/DAGraph.java b/azure-client-runtime/src/main/java/com/microsoft/azure/DAGraph.java index 153c38f259..627adbe6b6 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/DAGraph.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/DAGraph.java @@ -122,6 +122,16 @@ public T getNodeData(String key) { return graph.get(key).data(); } + /** + * Checks whether graph contains a node with the given key. + * + * @param key the key of the node + * @return true if there is a node with given key false otherwise. + */ + public boolean containsNodeWithKey(String key) { + return graph.containsKey(key); + } + /** * Reports that a node is resolved hence other nodes depends on it can consume it. * From a800a042490e2fd77153a5e837c7c3d9f6d93123 Mon Sep 17 00:00:00 2001 From: anuchan Date: Fri, 16 Sep 2016 15:22:05 -0700 Subject: [PATCH 15/15] removed unused method --- .../src/main/java/com/microsoft/azure/DAGraph.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/DAGraph.java b/azure-client-runtime/src/main/java/com/microsoft/azure/DAGraph.java index 627adbe6b6..153c38f259 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/DAGraph.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/DAGraph.java @@ -122,16 +122,6 @@ public T getNodeData(String key) { return graph.get(key).data(); } - /** - * Checks whether graph contains a node with the given key. - * - * @param key the key of the node - * @return true if there is a node with given key false otherwise. - */ - public boolean containsNodeWithKey(String key) { - return graph.containsKey(key); - } - /** * Reports that a node is resolved hence other nodes depends on it can consume it. *