New sample and version update (#9)

This commit is contained in:
Isaiah Williams 2019-01-18 22:25:32 -06:00 коммит произвёл GitHub
Родитель 762a38f296
Коммит f9ac285402
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
17 изменённых файлов: 1220 добавлений и 4 удалений

7
.vscode/launch.json поставляемый
Просмотреть файл

@ -11,6 +11,13 @@
"request": "launch",
"mainClass": "${file}"
},
{
"type": "java",
"name": "Debug (Launch)-Program<cpvsample>",
"request": "launch",
"mainClass": "com.microsoft.store.samples.secureappmodel.cpvsample.Program",
"projectName": "cpvsample"
},
{
"type": "java",
"name": "Debug (Launch)-Program<cspsample>",

Просмотреть файл

@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.microsoft.store</groupId>
<artifactId>partnercenter-samples</artifactId>
<version>1.8.1</version>
<version>1.10.0</version>
<packaging>jar</packaging>
<name>Samples</name>
<url>http://maven.apache.org</url>
@ -14,7 +14,7 @@
<dependency>
<groupId>com.microsoft.store</groupId>
<artifactId>partnercenter</artifactId>
<version>1.8.1</version>
<version>1.10.0</version>
</dependency>
</dependencies>
<build>

Просмотреть файл

@ -0,0 +1,19 @@
# Secure App Model
## Control Panel Vendor (CPV) Sample
This sample demonstrates how a Control Panel Vendor partner can utilize the refresh token obtained using the [Partner Consent](../partnerconsent/README.md) sample with the [Partner Center Java SDK](https://docs.microsoft.com/java/partnercenter/overview).
### Configuration
The following configurations in the [application.properties](src/main/resources/application.properties) file need to be modified:
* **keyvault.baseurl** - The base address for the instance of Azure Key Vault where the refresh token has been stored.
* **keyvault.clientId** - The identifier for the Azure AD application that has been allowed access to the instance of Azure Key Vault.
* **keyvault.clientSecret** - The application secret associated with the application configured to access the instance of Azure Key Vault.
* **partnercenter.accountId** - The account identifier, also known as the Azure AD tenant identifier, for the partner.
* **partnercenter.clientId** - The application identifier for the Azure AD application configured for use with the Partner Center API.
* **partnercenter.clientSecret** - The application secret associated with the application configured to access the Partner Center API.
* **partnercenter.displayName** - The display name for the Azure AD application. This will be used during the consent process, so it must what is in Azure AD.
Please note that in production scenarios we recommend that you use certificate based authentication to access the instance of Azure Key Vault. The [confidential client flow](https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/wiki/Confidential-client-applications-flows) has been used in the sample for simplicity.

Просмотреть файл

@ -0,0 +1,68 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.microsoft.store.samples.secureappmodel</groupId>
<artifactId>cpvsample</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>cpvsample</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>adal4j</artifactId>
<version>1.6.3</version>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure</artifactId>
<version>1.18.0</version>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-keyvault</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>com.microsoft.graph</groupId>
<artifactId>microsoft-graph</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>com.microsoft.rest</groupId>
<artifactId>client-runtime</artifactId>
<version>1.6.4</version>
</dependency>
<dependency>
<groupId>com.microsoft.store</groupId>
<artifactId>partnercenter</artifactId>
<version>1.10.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.16</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

Просмотреть файл

@ -0,0 +1,225 @@
// -----------------------------------------------------------------------
// <copyright file="Program.java" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------
package com.microsoft.store.samples.secureappmodel.cpvsample;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Properties;
import com.fasterxml.jackson.core.type.TypeReference;
import com.microsoft.azure.PagedList;
import com.microsoft.azure.management.Azure;
import com.microsoft.azure.management.resources.ResourceGroup;
import com.microsoft.graph.models.extensions.Domain;
import com.microsoft.graph.models.extensions.IGraphServiceClient;
import com.microsoft.graph.requests.extensions.GraphServiceClient;
import com.microsoft.graph.requests.extensions.IDomainCollectionPage;
import com.microsoft.store.partnercenter.IAadLoginHandler;
import com.microsoft.store.partnercenter.IPartner;
import com.microsoft.store.partnercenter.IPartnerCredentials;
import com.microsoft.store.partnercenter.PartnerService;
import com.microsoft.store.partnercenter.extensions.PartnerCredentials;
import com.microsoft.store.partnercenter.models.partners.OrganizationProfile;
import com.microsoft.store.samples.secureappmodel.cpvsample.models.ApplicationConsent;
import com.microsoft.store.samples.secureappmodel.cpvsample.models.ApplicationGrant;
import com.microsoft.store.samples.secureappmodel.cpvsample.security.AccessTokenProvider;
import com.microsoft.store.samples.secureappmodel.cpvsample.security.AzureTokenProvider;
import com.microsoft.store.samples.secureappmodel.cpvsample.security.GraphAuthenticationProvider;
import com.microsoft.store.samples.secureappmodel.cpvsample.security.IAccessTokenProvider;
import com.microsoft.store.samples.secureappmodel.cpvsample.security.SecureLoginHandler;
import org.apache.commons.lang3.StringUtils;
/**
* Sample application that demonstrates how a Control Panel Vendor should
* utilize the secure application model to interact with the Partner Center
* API, Microsoft Azure Resource Manager, and Microsoft Graph.
*/
public class Program
{
/**
* Entry point for the console application.
*
* @param args Arguments passed from the command line.
*/
public static void main(String args[])
{
IAccessTokenProvider tokenProvider;
Properties properties;
String customerId;
String partnerId;
try
{
partnerId = "SPECIFY-THE-PARTNER-TENANT-ID-HERE";
customerId = "SPECIFY-THE-CUSTOMER-TENANT-ID-HERE";
properties = new Properties();
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream(PropertyName.APP_PROPERTIES));
tokenProvider = new AccessTokenProvider(properties);
RunPartnerCenterTask(properties, tokenProvider, partnerId, customerId);
/**
* Uncomment the following if you want to run the Azure task sample. Please note that this requires
* the Azure AD application to have the Windows Azure Service Management API configured as one of
* the required permissions.
*/
// RunAzureTask(properties, tokenProvider, "SPECIFY-THE-IDENTIFIER-OF-CUSTOMER");
/**
* Uncomment the following if you want to run the Microsoft Graph task sample. Please note that this
* requires the Azure AD application to have Microsoft Graph configured as one of the required permissions.
* If you are receive an error stating the identity of the calling application could not be established,
* ensure the Azure AD application is configured to be multi-tenanted and has been configured for pre-consent.
*/
// RunGraphTask(properties, tokenProvider, "SPECIFY-THE-IDENTIFIER-OF-CUSTOMER");
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
/**
* Demonstrates how a partner can interact with Microsoft Azure Resource Manager in the context of the customer.
*
* @param properties The configuration information stored in the application.properties file.
* @param tokenProvider Provides the ability to request access tokens.
* @param customerId Identifier of the customer.
*/
private static void RunAzureTask(Properties properties, IAccessTokenProvider tokenProvider, String customerId)
{
Azure.Authenticated azureAuth;
Azure azure;
PagedList<ResourceGroup> resourceGroups;
if(properties == null)
{
throw new IllegalArgumentException("properties cannot be null");
}
if(tokenProvider == null)
{
throw new IllegalArgumentException("tokenProvider cannot be null");
}
if(StringUtils.isEmpty(customerId))
{
throw new IllegalArgumentException("customerId is empty or null");
}
try
{
azureAuth = Azure.authenticate(new AzureTokenProvider(properties, tokenProvider, customerId));
azure = azureAuth.withDefaultSubscription();
resourceGroups = azure.resourceGroups().list();
resourceGroups.forEach(group -> {
System.out.println(group.name());
});
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
/**
* Demonstrates how a partner can interact with Microsoft Graph in the context of the customer.
*
* @param properties The configuration information stored in the application.properties file.
* @param tokenProvider Provides the ability to request access tokens.
* @param customerId Identifier of the customer.
*/
private static void RunGraphTask(Properties properties, IAccessTokenProvider tokenProvider, String customerId)
{
if(properties == null)
{
throw new IllegalArgumentException("properties cannot be null");
}
if(tokenProvider == null)
{
throw new IllegalArgumentException("tokenProvider cannot be null");
}
if(StringUtils.isEmpty(customerId))
{
throw new IllegalArgumentException("customerId is empty or null");
}
IGraphServiceClient graphClient = GraphServiceClient
.builder()
.authenticationProvider(new GraphAuthenticationProvider(properties, tokenProvider, customerId))
.buildClient();
IDomainCollectionPage domains = graphClient.domains().buildRequest().get();
for(Domain domain : domains.getCurrentPage())
{
System.out.println(domain.id);
}
}
private static void RunPartnerCenterTask(Properties properties, IAccessTokenProvider tokenProvider, String partnerId, String customerId)
{
IAadLoginHandler loginHandler = new SecureLoginHandler(properties, tokenProvider);
IPartnerCredentials credentials = PartnerCredentials.getInstance().generateByUserCredentials(
properties.getProperty(PropertyName.PARTNER_CENTER_CLIENT_ID),
loginHandler.authenticate(),
loginHandler);
IPartner partnerOperations = PartnerService.getInstance().createPartnerOperations(credentials);
if(StringUtils.isNoneBlank(customerId))
{
ApplicationGrant azureAppGrant = new ApplicationGrant();
azureAppGrant.setEnterpriseApplication("797f4846-ba00-4fd7-ba43-dac1f8f63013");
azureAppGrant.setScope("user_impersonation");
ApplicationGrant graphAppGrant = new ApplicationGrant();
graphAppGrant.setEnterpriseApplication("00000002-0000-0000-c000-000000000000");
graphAppGrant.setScope("Domain.ReadWrite.All,User.ReadWrite.All,Directory.Read.All");
ApplicationConsent consent = new ApplicationConsent();
consent.setApplicationGrants(Arrays.asList(azureAppGrant, graphAppGrant));
consent.setApplicationId(properties.getProperty(PropertyName.PARTNER_CENTER_CLIENT_ID));
consent.setDisplayName(properties.getProperty(PropertyName.PARTNER_CENTER_DISPLAY_NAME));
// Deletes the existing grant into the customer it is present.
partnerOperations.getServiceClient().delete(
partnerOperations,
new TypeReference<ApplicationConsent>(){},
MessageFormat.format(
"customers/{0}/applicationconsents/{1}",
customerId,
properties.getProperty(PropertyName.PARTNER_CENTER_CLIENT_ID)));
// Consent to the defined applications and the respective scopes.
partnerOperations.getServiceClient().post(
partnerOperations,
new TypeReference<ApplicationConsent>(){},
MessageFormat.format(
"customers/{0}/applicationconsents",
customerId),
consent);
}
OrganizationProfile profile = partnerOperations.getProfiles().getOrganizationProfile().get();
System.out.println(profile.getCompanyName());
}
}

Просмотреть файл

@ -0,0 +1,58 @@
// -----------------------------------------------------------------------
// <copyright file="PropertyName.java" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------
package com.microsoft.store.samples.secureappmodel.cpvsample;
/**
* Provides access to the property names.
*/
public class PropertyName
{
/**
* The name of the application.properties resource file.
*/
public static final String APP_PROPERTIES = "application.properties";
/**
* The name of the Azure AD authority property.
*/
public static final String AZURE_AD_AUTHORITY = "azuread.authority";
/**
* The name of the Azure Key Vault base URL property.
*/
public static final String KEY_VAULT_BASE_URL = "keyvault.baseurl";
/**
* The name of the client identifier property.
*/
public static final String KEY_VAULT_CLIENT_ID = "keyvault.clientId";
/**
* The name of the client secret property.
*/
public static final String KEY_VAULT_CLIENT_SECRET = "keyvault.clientSecret";
/**
* The name of the Partner Center account identifier property.
*/
public static final String PARTNER_CENTER_ACCOUNT_ID = "partnercenter.accountId";
/**
* The name of the Partner Center client identifier property.
*/
public static final String PARTNER_CENTER_CLIENT_ID = "partnercenter.clientId";
/**
* The name fo the Partner Center display name property.
*/
public static final String PARTNER_CENTER_DISPLAY_NAME = "partnercenter.displayName";
/**
* The name of the Partner Center client secret property.
*/
public static final String PARTNER_CENTER_CLIENT_SECRET = "partnercenter.clientSecret";
}

Просмотреть файл

@ -0,0 +1,53 @@
// -----------------------------------------------------------------------
// <copyright file="ApplicationConsent.java" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------
package com.microsoft.store.samples.secureappmodel.cpvsample.models;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonProperty;
public class ApplicationConsent
{
@JsonProperty("applicationGrants")
private List<ApplicationGrant> applicationGrants;
@JsonProperty("applicationId")
private String applicationId;
@JsonProperty("displayName")
private String displayName;
public List<ApplicationGrant> getApplicationGrants()
{
return applicationGrants;
}
public String getApplicationId()
{
return applicationId;
}
public String getDisplayName()
{
return displayName;
}
public void setApplicationGrants(List<ApplicationGrant> value)
{
applicationGrants = value;
}
public void setApplicationId(String value)
{
applicationId = value;
}
public void setDisplayName(String value)
{
displayName = value;
}
}

Просмотреть файл

@ -0,0 +1,38 @@
// -----------------------------------------------------------------------
// <copyright file="ApplicationGrant.java" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------
package com.microsoft.store.samples.secureappmodel.cpvsample.models;
import com.fasterxml.jackson.annotation.JsonProperty;
public class ApplicationGrant
{
@JsonProperty("enterpriseApplicationId")
private String enterpriseApplicationId;
@JsonProperty("scope")
private String scope;
public String getEnterpriseApplicationId()
{
return enterpriseApplicationId;
}
public String getScope()
{
return scope;
}
public void setEnterpriseApplication(String value)
{
enterpriseApplicationId = value;
}
public void setScope(String value)
{
scope = value;
}
}

Просмотреть файл

@ -0,0 +1,176 @@
// -----------------------------------------------------------------------
// <copyright file="AccessTokenProvider.java" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------
package com.microsoft.store.samples.secureappmodel.cpvsample.security;
import java.net.MalformedURLException;
import java.text.MessageFormat;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import com.microsoft.aad.adal4j.AuthenticationContext;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.aad.adal4j.ClientCredential;
import com.microsoft.store.samples.secureappmodel.cpvsample.PropertyName;
/**
* Provides the ability to request access tokens.
*/
public class AccessTokenProvider implements IAccessTokenProvider
{
/**
* Provides access to configuration information stored in the application.properties file.
*/
private Properties properties;
/**
* Initializes a new instance of the {@link AccessTokenProvider} class.
*
* @param properties The persistent set of application properties.
*/
public AccessTokenProvider(Properties properties)
{
if(properties == null)
{
throw new IllegalArgumentException("The properties parameter cannot be null.");
}
this.properties = properties;
}
/**
* Gets an access token from the authority.
*
* @param tenantId Identifier of the Azure AD tenant requesting the token.
* @param resource Identifier of the target resource that is the recipient of the requested token.
* @param clientId The identifier of the client requesting the token.
* @param clientSecret The secure secret of the client requesting the token.
* @return An instance of {@link AuthenticationResult} that contians an access token and refresh token.
*
* @throws ExecutionException {@link ExecutionException}
* @throws InterruptedException {@link InterruptedException}
* @throws MalformedURLException {@link MalformedURLException}
*/
public AuthenticationResult getAccessToken(String tenantId, String resource, String clientId, String clientSecret)
throws ExecutionException, InterruptedException, MalformedURLException
{
AuthenticationContext authContext;
AuthenticationResult authResult;
ExecutorService service = null;
Future<AuthenticationResult> future;
try
{
service = Executors.newFixedThreadPool(1);
authContext = new AuthenticationContext(
MessageFormat.format(
"{0}/{1}",
properties.getProperty(PropertyName.AZURE_AD_AUTHORITY),
tenantId),
true,
service);
future = authContext.acquireToken(
resource,
new ClientCredential(
clientId,
clientSecret),
null);
authResult = future.get();
return authResult;
}
finally
{
service.shutdown();
}
}
/**
* Gets an access token from the authority.
*
* @param tenantId Identifier of the Azure AD tenant requesting the token.
* @param resource Identifier of the target resource that is the recipient of the requested token.
* @param refreshToken The refresh token to use in the request.
* @param clientId The identifier of the client requesting the token.
* @param clientSecret The secure secret of the client requesting the token.
* @return An instance of {@link AuthenticationResult} that contians an access token and refresh token.
*
* @throws ExecutionException {@link ExecutionException}
* @throws InterruptedException {@link InterruptedException}
* @throws MalformedURLException {@link MalformedURLException}
*/
public AuthenticationResult getAccessTokenByRefreshToken(String tenantId, String resource, String refreshToken, String clientId, String clientSecret)
throws ExecutionException, InterruptedException, MalformedURLException
{
AuthenticationContext authContext;
AuthenticationResult authResult;
ExecutorService service = null;
Future<AuthenticationResult> future;
try
{
service = Executors.newFixedThreadPool(1);
authContext = new AuthenticationContext(
MessageFormat.format(
"{0}/{1}",
properties.getProperty(PropertyName.AZURE_AD_AUTHORITY),
tenantId),
true,
service);
future = authContext.acquireTokenByRefreshToken(
refreshToken,
new ClientCredential(
clientId,
clientSecret),
resource,
null);
authResult = future.get();
return authResult;
}
finally
{
service.shutdown();
}
}
/**
* Gets an access token from the authority.
*
* @param tenantId Identifier of the Azure AD tenant requesting the token.
* @param resource Identifier of the target resource that is the recipient of the requested token.
* @param identifier Name of the refresh token stored in an instance of Azure Key Vault.
* @param clientId The identifier of the client requesting the token.
* @param clientSecret The secure secret of the client requesting the token.
* @return An instance of {@link AuthenticationResult} that contians an access token and refresh token.
*
* @throws ExecutionException {@link ExecutionException}
* @throws InterruptedException {@link InterruptedException}
* @throws MalformedURLException {@link MalformedURLException}
*/
public AuthenticationResult getAccessTokenBySecureRefreshToken(String tenantId, String resource, String identifier, String clientId, String clientSecret)
throws ExecutionException, InterruptedException, MalformedURLException
{
IVaultProvider vault = new KeyVaultProvider(
properties.getProperty(PropertyName.KEY_VAULT_BASE_URL),
properties.getProperty(PropertyName.KEY_VAULT_CLIENT_ID),
properties.getProperty(PropertyName.KEY_VAULT_CLIENT_SECRET));
return getAccessTokenByRefreshToken(
tenantId,
resource,
vault.getSecret(identifier),
clientId,
clientSecret);
}
}

Просмотреть файл

@ -0,0 +1,105 @@
// -----------------------------------------------------------------------
// <copyright file="AzureTokenProvider.java" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------
package com.microsoft.store.samples.secureappmodel.cpvsample.security;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.azure.credentials.AzureTokenCredentials;
import com.microsoft.store.samples.secureappmodel.cpvsample.PropertyName;
/**
* Provides authentication for a Microsoft Azure befor a request is sent.
*/
public class AzureTokenProvider extends AzureTokenCredentials
{
/**
* Provides the ability to request access tokens.
*/
private IAccessTokenProvider tokenProvider;
/**
* Provides access to configuration information stored in the application.properties file.
*/
private Properties properties;
/**
* The identifier of the customer that owns the subscription.
*/
private String customerId;
/**
* Initializes a new instance of the {@link AzureTokenProvider} class.
*
* @param properties Provides access to configuration information stored in the application.properties file.
* @param tokenProvider Provides the ability to request access tokens.
* @param customerId Identifier of the customer.
*/
public AzureTokenProvider(Properties properties, IAccessTokenProvider tokenProvider, String customerId)
{
super(null, customerId);
if(properties == null)
{
throw new IllegalArgumentException("properties cannot be null.");
}
if(tokenProvider == null)
{
throw new IllegalArgumentException("tokenProvider cannot be null");
}
this.customerId = customerId;
this.properties = properties;
this.tokenProvider = tokenProvider;
}
/**
* The mechanism to get a token.
*
* @param resource Identifier of the target resource that is the recipient of the requested token.
* @return The token to access the resource
* @throws IOException exceptions from IO
*/
@Override
public String getToken(String resource) throws IOException
{
AuthenticationResult authResult = null;
try
{
authResult = tokenProvider.getAccessTokenBySecureRefreshToken(
customerId,
resource,
properties.getProperty(PropertyName.PARTNER_CENTER_ACCOUNT_ID),
properties.getProperty(PropertyName.PARTNER_CENTER_CLIENT_ID),
properties.getProperty(PropertyName.PARTNER_CENTER_CLIENT_SECRET));
}
catch(ExecutionException ex)
{
ex.printStackTrace();
}
catch(InterruptedException ex)
{
ex.printStackTrace();
}
catch(MalformedURLException ex)
{
ex.printStackTrace();
}
if(authResult == null)
{
throw new NullPointerException("Unable to obtain an access token.");
}
return authResult.getAccessToken();
}
}

Просмотреть файл

@ -0,0 +1,124 @@
// -----------------------------------------------------------------------
// <copyright file="GraphAuthenticationProvider.java" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------
package com.microsoft.store.samples.secureappmodel.cpvsample.security;
import java.net.MalformedURLException;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.graph.authentication.IAuthenticationProvider;
import com.microsoft.graph.http.IHttpRequest;
import com.microsoft.graph.options.HeaderOption;
import com.microsoft.store.samples.secureappmodel.cpvsample.PropertyName;
import org.apache.commons.lang3.StringUtils;
/**
* Provides authentication for a Microsoft Graph request before it is sent.
*/
public class GraphAuthenticationProvider implements IAuthenticationProvider
{
/**
* The authorization header name.
*/
private static final String AUTHORIZATION_HEADER_NAME = "Authorization";
/**
* The bearer prefix.
*/
private static final String OAUTH_BEARER_PREFIX = "Bearer ";
/**
* Provides the ability to request access tokens.
*/
private IAccessTokenProvider tokenProvider;
/**
* Provides access to configuration information stored in the application.properties file.
*/
private Properties properties;
/**
* The identifier of the Azure AD tenant.
*/
private String customerId;
/**
* Initializes a new instance of the {@link GraphAuthenticationProvider} class.
*
* @param customerId The identifier of the Azure AD tenant.
*/
public GraphAuthenticationProvider(Properties properties, IAccessTokenProvider tokenProvider, String customerId)
{
if(properties == null)
{
throw new IllegalArgumentException("properties cannot be null");
}
if(StringUtils.isEmpty(customerId))
{
throw new IllegalArgumentException("tenantId cannot be null");
}
if(tokenProvider == null)
{
throw new IllegalArgumentException("tokenProvider cannot be null");
}
this.properties = properties;
this.customerId = customerId;
this.tokenProvider = tokenProvider;
}
/**
* Authenticates the request
*
* @param request the request to authenticate
*/
@Override
public void authenticateRequest(final IHttpRequest request)
{
AuthenticationResult authResult = null;
// If the request already has an authorization header, do not intercept it.
for (final HeaderOption option : request.getHeaders()) {
if (option.getName().equals(AUTHORIZATION_HEADER_NAME)) {
return;
}
}
try
{
authResult = tokenProvider.getAccessTokenBySecureRefreshToken(
customerId,
"https://graph.microsoft.com",
properties.getProperty(PropertyName.PARTNER_CENTER_ACCOUNT_ID),
properties.getProperty(PropertyName.PARTNER_CENTER_CLIENT_ID),
properties.getProperty(PropertyName.PARTNER_CENTER_CLIENT_SECRET));
}
catch(ExecutionException ex)
{
ex.printStackTrace();
}
catch(InterruptedException ex)
{
ex.printStackTrace();
}
catch(MalformedURLException ex)
{
ex.printStackTrace();
}
if(authResult == null)
{
throw new NullPointerException("Unable to obtain an access token.");
}
request.addHeader(AUTHORIZATION_HEADER_NAME, OAUTH_BEARER_PREFIX + authResult.getAccessToken());
}
}

Просмотреть файл

@ -0,0 +1,68 @@
// -----------------------------------------------------------------------
// <copyright file="IAccessTokenProvider.java" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------
package com.microsoft.store.samples.secureappmodel.cpvsample.security;
import java.net.MalformedURLException;
import java.util.concurrent.ExecutionException;
import com.microsoft.aad.adal4j.AuthenticationResult;
/**
* Represent the ability to obtain access tokens.
*/
public interface IAccessTokenProvider
{
/**
* Gets an access token from the authority.
*
* @param tenantId Identifier of the Azure AD tenant requesting the token.
* @param resource Identifier of the target resource that is the recipient of the requested token.
* @param clientId The identifier of the client requesting the token.
* @param clientSecret The secure secret of the client requesting the token.
* @return An instance of {@link AuthenticationResult} that contians an access token and refresh token.
*
* @throws ExecutionException {@link ExecutionException}
* @throws InterruptedException {@link InterruptedException}
* @throws MalformedURLException {@link MalformedURLException}
*/
public AuthenticationResult getAccessToken(String tenantId, String resource, String clientId, String clientSecret)
throws ExecutionException, InterruptedException, MalformedURLException;
/**
* Gets an access token from the authority.
*
* @param tenantId Identifier of the Azure AD tenant requesting the token.
* @param resource Identifier of the target resource that is the recipient of the requested token.
* @param refreshToken The refresh token to use in the request.
* @param clientId The identifier of the client requesting the token.
* @param clientSecret The secure secret of the client requesting the token.
* @return An instance of {@link AuthenticationResult} that contians an access token and refresh token.
*
* @throws ExecutionException {@link ExecutionException}
* @throws InterruptedException {@link InterruptedException}
* @throws MalformedURLException {@link MalformedURLException}
*/
public AuthenticationResult getAccessTokenByRefreshToken(String tenantId, String resource, String refreshToken, String clientId, String clientSecret)
throws ExecutionException, InterruptedException, MalformedURLException;
/**
* Gets an access token from the authority.
*
* @param tenantId Identifier of the Azure AD tenant requesting the token.
* @param resource Identifier of the target resource that is the recipient of the requested token.
* @param identifier Name of the refresh token stored in an instance of Azure Key Vault.
* @param clientId The identifier of the client requesting the token.
* @param clientSecret The secure secret of the client requesting the token.
* @return An instance of {@link AuthenticationResult} that contians an access token and refresh token.
*
* @throws ExecutionException {@link ExecutionException}
* @throws InterruptedException {@link InterruptedException}
* @throws MalformedURLException {@link MalformedURLException}
*/
public AuthenticationResult getAccessTokenBySecureRefreshToken(String tenantId, String resource, String identifier, String clientId, String clientSecret)
throws ExecutionException, InterruptedException, MalformedURLException;
}

Просмотреть файл

@ -0,0 +1,21 @@
// -----------------------------------------------------------------------
// <copyright file="IVaultProvider.java" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------
package com.microsoft.store.samples.secureappmodel.cpvsample.security;
/**
* Represents a secure mechanism for retrieving and store sensitive information.
*/
public interface IVaultProvider
{
/**
* Gets the specified value from the vault.
*
* @param secretName Identifier of the value to be retrieved.
* @return The value for the specified secret.
*/
String getSecret(String secretName);
}

Просмотреть файл

@ -0,0 +1,154 @@
// -----------------------------------------------------------------------
// <copyright file="KeyVaultProvider.java" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------
package com.microsoft.store.samples.secureappmodel.cpvsample.security;
import java.net.MalformedURLException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import com.microsoft.aad.adal4j.AuthenticationContext;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.aad.adal4j.ClientCredential;
import com.microsoft.azure.keyvault.KeyVaultClient;
import com.microsoft.azure.keyvault.KeyVaultClientCustom;
import com.microsoft.azure.keyvault.authentication.KeyVaultCredentials;
/**
* Provides a secure mechanism for retrieving and store sensitive information using Azure Key Vault.
*/
public class KeyVaultProvider implements IVaultProvider
{
/**
* The client used to interact with the Azure Key Vault service.
*/
private KeyVaultClientCustom client;
/**
* The vault name, e.g. https://myvault.vault.azure.net
*/
private String vaultBaseUrl;
/**
* Initializes a new instance of the {@link KeyVaultProvider} class.
*
* @param vaultBaseUrl The vault name, e.g. https://myvault.vault.azure.net
* @param clientId The identifier of the client requesting the token.
* @param clientSecret The secure secret of the client requesting the token.
*/
public KeyVaultProvider(String vaultBaseUrl, String clientId, String clientSecret)
{
client = getKeyVaultClient(clientId, clientSecret);
this.vaultBaseUrl = vaultBaseUrl;
}
/**
* Gets the specified value from the vault.
*
* @param secretName Identifier of the value to be retrieved.
* @return The value for the specified secret.
*/
public String getSecret(String secretName)
{
return client.getSecret(vaultBaseUrl, secretName).value();
}
/**
* Stores the specified value in the vault.
*
* @param secretName Identifier of the value to be stored.
* @param value The value to be stored.
*/
public void setSecret(String secretName, String value)
{
client.setSecret(vaultBaseUrl, secretName, value);
}
/**
* Gets an access token from the authority.
*
* @param authorization Address of the authority to issue the token.
* @param resource Identifier of the target resource that is the recipient of the requested token.
* @param clientId The identifier of the client requesting the token.
* @param clientSecret The secure secret of the client requesting the token.
* @return An instance of {@link AuthenticationResult} that contians an access token and refresh token.
*
* @throws ExecutionException {@link ExecutionException}
* @throws InterruptedException {@link InterruptedException}
* @throws MalformedURLException {@link MalformedURLException}
*/
private AuthenticationResult getAccessToken(String authorization, String resource, String clientId, String clientSecret)
throws ExecutionException, InterruptedException, MalformedURLException
{
AuthenticationContext authContext;
AuthenticationResult authResult;
ExecutorService service = null;
Future<AuthenticationResult> future;
try
{
service = Executors.newFixedThreadPool(1);
authContext = new AuthenticationContext(authorization, true, service);
future = authContext.acquireToken(
resource,
new ClientCredential(
clientId,
clientSecret),
null);
authResult = future.get();
return authResult;
}
finally
{
service.shutdown();
}
}
/**
* Gets a client that is capable of interacting with the Azure Key Vault service.
*
* @param clientId The identifier of the client requesting the token.
* @param clientSecret The secure secret of the client requesting the token.
*
* @return A client that is capable of interacting with the Azure Key Vault service.
*/
private KeyVaultClientCustom getKeyVaultClient(String clientId, String clientSecret)
{
return new KeyVaultClient(new KeyVaultCredentials()
{
/**
* @param authorization Address of the authority to issue the token.
* @param resource Identifier of the target resource that is the recipient of the requested token, a URL.
* @param scope The scope of the authentication request.
*
* @return Access token to be used with Azure Key Vault operations.
*/
@Override
public String doAuthenticate(String authorization, String resource, String scope)
{
AuthenticationResult authResult;
try
{
authResult = getAccessToken(authorization, resource, clientId, clientSecret);
return authResult.getAccessToken();
}
catch(Exception ex)
{
ex.printStackTrace();
}
return "";
}
});
}
}

Просмотреть файл

@ -0,0 +1,87 @@
// -----------------------------------------------------------------------
// <copyright file="SecureLoginHandler.java" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------
package com.microsoft.store.samples.secureappmodel.cpvsample.security;
import java.net.MalformedURLException;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.store.partnercenter.AuthenticationToken;
import com.microsoft.store.partnercenter.IAadLoginHandler;
import com.microsoft.store.samples.secureappmodel.cpvsample.PropertyName;
import org.joda.time.DateTime;
public class SecureLoginHandler implements IAadLoginHandler
{
/**
* Provides the ability to request access tokens.
*/
private IAccessTokenProvider tokenProvider;
/**
* Provides access to configuration information stored in the application.properties file.
*/
private Properties properties;
/**
* Initializes a new instance of the {@link SecureLoginHandler}
*
* @param tokenProvider Provides the ability to request access tokens.
*/
public SecureLoginHandler(Properties properties, IAccessTokenProvider tokenProvider)
{
if(properties == null)
{
throw new IllegalArgumentException("properties cannot be null");
}
if(tokenProvider == null)
{
throw new IllegalArgumentException("tokenProvider cannot be null");
}
this.properties = properties;
this.tokenProvider = tokenProvider;
}
@Override
public AuthenticationToken authenticate()
{
AuthenticationResult authResult = null;
try
{
authResult = tokenProvider.getAccessTokenBySecureRefreshToken(
properties.getProperty(PropertyName.PARTNER_CENTER_ACCOUNT_ID),
"https://api.partnercenter.microsoft.com",
properties.getProperty(PropertyName.PARTNER_CENTER_ACCOUNT_ID),
properties.getProperty(PropertyName.PARTNER_CENTER_CLIENT_ID),
properties.getProperty(PropertyName.PARTNER_CENTER_CLIENT_SECRET));
}
catch(ExecutionException ex)
{
ex.printStackTrace();
}
catch(InterruptedException ex)
{
ex.printStackTrace();
}
catch(MalformedURLException ex)
{
ex.printStackTrace();
}
if(authResult == null)
{
throw new NullPointerException("Unable to obtain an access token.");
}
return new AuthenticationToken(authResult.getAccessToken(), new DateTime(authResult.getExpiresOnDate()));
}
}

Просмотреть файл

@ -0,0 +1,8 @@
azuread.authority=https://login.microsoftonline.com
keyvault.baseurl=
keyvault.clientId=
keyvault.clientSecret=
partnercenter.accountId=
partnercenter.clientId=
partnercenter.clientSecret=
partnercenter.displayName=

Просмотреть файл

@ -34,12 +34,17 @@
<dependency>
<groupId>com.microsoft.rest</groupId>
<artifactId>client-runtime</artifactId>
<version>1.6.3</version>
<version>1.6.4</version>
</dependency>
<dependency>
<groupId>com.microsoft.store</groupId>
<artifactId>partnercenter</artifactId>
<version>1.8.1</version>
<version>1.10.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.16</version>
</dependency>
</dependencies>
<build>