Skip to content

Commit

Permalink
Support for custom cloud environments by setting Environment to `Cust…
Browse files Browse the repository at this point in the history
…om` followed by specifying the needed Graph and Azure AD endpoints
  • Loading branch information
jansenbe committed Nov 10, 2022
1 parent c746360 commit e818ffc
Show file tree
Hide file tree
Showing 16 changed files with 148 additions and 18 deletions.
9 changes: 9 additions & 0 deletions src/sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).

## [unreleased]

### Added

- Support for custom cloud environments by setting Environment to `Custom` followed by specifying the needed Graph and Azure AD endpoints #1014 [jansenbe - Bert Jansen]

### Changed


## [1.8.0]

### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@ internal override void Init(PnPCoreAuthenticationCredentialConfigurationOptions
options.OnBehalfOf.AuthorityUri,
options.OnBehalfOf.RedirectUri,
TenantId,
options.Environment)
options.Environment,
options.AzureADLoginAuthority)
.Build();
}
else
Expand All @@ -177,7 +178,8 @@ internal override void Init(PnPCoreAuthenticationCredentialConfigurationOptions
options.OnBehalfOf.AuthorityUri,
options.OnBehalfOf.RedirectUri,
TenantId,
options.Environment)
options.Environment,
options.AzureADLoginAuthority)
.Build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ internal override void Init(PnPCoreAuthenticationCredentialConfigurationOptions
options.X509Certificate.AuthorityUri,
options.X509Certificate.RedirectUri,
TenantId,
options.Environment)
options.Environment,
options.AzureADLoginAuthority)
.Build();

// Log the initialization information
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ internal override void Init(PnPCoreAuthenticationCredentialConfigurationOptions
ClientId = ClientId,
TenantId = TenantId,
Environment = options.Environment,
AzureADLoginAuthority = options.AzureADLoginAuthority,
UsernamePassword = new PnPCoreAuthenticationUsernamePasswordOptions
{
Username = credentials.UserName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ internal override void Init(PnPCoreAuthenticationCredentialConfigurationOptions
options.DeviceCode.AuthorityUri,
RedirectUri,
TenantId,
options.Environment)
options.Environment,
options.AzureADLoginAuthority)
.WithHttpClientFactory(msalHttpClientFactory)
.Build();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ internal override void Init(PnPCoreAuthenticationCredentialConfigurationOptions
options.Interactive?.AuthorityUri,
RedirectUri,
TenantId,
options.Environment)
options.Environment,
options.AzureADLoginAuthority)
.Build();

// Log the initialization information
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ internal override void Init(PnPCoreAuthenticationCredentialConfigurationOptions
options.UsernamePassword.AuthorityUri,
options.UsernamePassword.RedirectUri,
TenantId,
options.Environment)
options.Environment,
options.AzureADLoginAuthority)
.WithHttpClientFactory(msalHttpClientFactory)
.Build();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ public IAuthenticationProvider CreateDefault()
public IAuthenticationProvider Create(string name)
{
// Search for the provided configuration
PnPCoreAuthenticationCredentialConfigurationOptions options;
if (!this.options.Credentials.Configurations.TryGetValue(name, out options))
if (!this.options.Credentials.Configurations.TryGetValue(name, out PnPCoreAuthenticationCredentialConfigurationOptions options))
{
throw new ClientException(ErrorType.ConfigurationError,
string.Format(System.Globalization.CultureInfo.InvariantCulture,
Expand All @@ -82,6 +81,11 @@ public IAuthenticationProvider Create(string name)
if (Enum.TryParse(this.options.Environment, out Microsoft365Environment environment))
{
options.Environment = environment;

if (options.Environment == Microsoft365Environment.Custom)
{
options.AzureADLoginAuthority = this.options.AzureADLoginAuthority;
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ public class PnPCoreAuthenticationOptions
/// </summary>
public string Environment { get; set; }

/// <summary>
/// Returns the Azure AD Login authority (e.g. login.microsoftonline.com) to use when <see cref="Environment"/> is set to <see cref="Microsoft365Environment.Custom"/>
/// </summary>
public string AzureADLoginAuthority { get; set; }

/// <summary>
/// The sites options
/// </summary>
Expand Down Expand Up @@ -87,6 +92,11 @@ public class PnPCoreAuthenticationCredentialConfigurationOptions
/// </summary>
public Microsoft365Environment? Environment { get; set; }

/// <summary>
/// Returns the Azure AD Login authority (e.g. login.microsoftonline.com) to use when <see cref="Environment"/> is set to <see cref="Microsoft365Environment.Custom"/>
/// </summary>
public string AzureADLoginAuthority { get; set; }

/// <summary>
/// The options for the X509 Certificate Authentication Provider
/// </summary>
Expand Down
21 changes: 18 additions & 3 deletions src/sdk/PnP.Core.Auth/Utilities/ApplicationBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ internal static class ApplicationBuilderExtensions
/// <param name="redirectUri">The Redirect URI for authentication</param>
/// <param name="tenantId">The ID of the Azure Active Directory Tenant</param>
/// <param name="environment">Information about the configured cloud environment</param>
/// <param name="azureADLoginAuthority">Returns the Azure AD Login authority (e.g. login.microsoftonline.com) to use when environment is set to <see cref="Microsoft365Environment.Custom"/></param>
/// <returns></returns>
internal static T WithPnPAdditionalAuthenticationSettings<T>(this AbstractApplicationBuilder<T> builder,
Uri authorityUri, Uri redirectUri, string tenantId, Microsoft365Environment? environment) where T : AbstractApplicationBuilder<T>
Uri authorityUri, Uri redirectUri, string tenantId, Microsoft365Environment? environment, string azureADLoginAuthority) where T : AbstractApplicationBuilder<T>
{
if (tenantId == null)
{
Expand All @@ -28,11 +29,25 @@ internal static T WithPnPAdditionalAuthenticationSettings<T>(this AbstractApplic
{
if (tenantId.Equals(AuthGlobals.OrganizationsTenantId, StringComparison.InvariantCultureIgnoreCase))
{
builder = builder.WithAuthority($"https://{CloudManager.GetAzureADLoginAuthority(environment.Value)}/{AuthGlobals.OrganizationsTenantId}/");
if (environment.Value == Microsoft365Environment.Custom)
{
builder = builder.WithAuthority($"https://{azureADLoginAuthority}/{AuthGlobals.OrganizationsTenantId}/");
}
else
{
builder = builder.WithAuthority($"https://{CloudManager.GetAzureADLoginAuthority(environment.Value)}/{AuthGlobals.OrganizationsTenantId}/");
}
}
else
{
builder = builder.WithAuthority(authorityUri?.ToString() ?? $"https://{CloudManager.GetAzureADLoginAuthority(environment.Value)}", tenantId, true);
if (environment.Value == Microsoft365Environment.Custom)
{
builder = builder.WithAuthority(authorityUri?.ToString() ?? $"https://{azureADLoginAuthority}", tenantId, true);
}
else
{
builder = builder.WithAuthority(authorityUri?.ToString() ?? $"https://{CloudManager.GetAzureADLoginAuthority(environment.Value)}", tenantId, true);
}
}
}
else
Expand Down
10 changes: 10 additions & 0 deletions src/sdk/PnP.Core/Services/Builder/Configuration/PnPCoreOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ public class PnPCoreOptions
/// </summary>
public string Environment { get; set; }

/// <summary>
/// Returns the Microsoft Graph authority (e.g. graph.microsoft.com) to use when <see cref="Environment"/> is set to <see cref="Microsoft365Environment.Custom"/>
/// </summary>
public string MicrosoftGraphAuthority { get; set; }

/// <summary>
/// Returns the Azure AD Login authority (e.g. login.microsoftonline.com) to use when <see cref="Environment"/> is set to <see cref="Microsoft365Environment.Custom"/>
/// </summary>
public string AzureADLoginAuthority { get; set; }

/// <summary>
/// AAD tenant id, used for telemetry purposes. Can be customized via configuration
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ public void Configure(PnPGlobalSettingsOptions options)
if (Enum.TryParse(pnpCoreOptions.Value.Environment, out Microsoft365Environment environment))
{
options.Environment = environment;

if (options.Environment == Microsoft365Environment.Custom)
{
options.MicrosoftGraphAuthority = pnpCoreOptions.Value.MicrosoftGraphAuthority;
options.AzureADLoginAuthority = pnpCoreOptions.Value.AzureADLoginAuthority;
}
}
}

Expand Down
31 changes: 28 additions & 3 deletions src/sdk/PnP.Core/Services/Core/BatchClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,14 @@ private async Task<bool> ExecuteMicrosoftGraphBatchRequestAsync(Batch batch)

if (PnPContext.Environment.HasValue)
{
graphBaseUri = new Uri($"https://{CloudManager.GetMicrosoftGraphAuthority(PnPContext.Environment.Value)}/");
if (PnPContext.Environment == Microsoft365Environment.Custom)
{
graphBaseUri = new Uri($"https://{PnPContext.MicrosoftGraphAuthority}/");
}
else
{
graphBaseUri = new Uri($"https://{CloudManager.GetMicrosoftGraphAuthority(PnPContext.Environment.Value)}/");
}
}

await PnPContext.AuthenticationProvider.AuthenticateRequestAsync(graphBaseUri, request).ConfigureAwait(false);
Expand Down Expand Up @@ -981,7 +988,18 @@ private async Task ExecuteMicrosoftGraphInteractiveAsync(Batch batch)
}

// Make the request
using (var request = new HttpRequestMessage(graphRequest.Method, $"https://{CloudManager.GetMicrosoftGraphAuthority(PnPContext.Environment.Value)}/{graphEndpoint}/{requestUrl}"))
string graphRequestUrl;

if (PnPContext.Environment.Value == Microsoft365Environment.Custom)
{
graphRequestUrl = $"https://{PnPContext.MicrosoftGraphAuthority}/{graphEndpoint}/{requestUrl}";
}
else
{
graphRequestUrl = $"https://{CloudManager.GetMicrosoftGraphAuthority(PnPContext.Environment.Value)}/{graphEndpoint}/{requestUrl}";
}

using (var request = new HttpRequestMessage(graphRequest.Method, graphRequestUrl))
{
// Add custom PnPContext properties to HttpRequest if needed
AddHttpRequestMessageProperties(request, batch);
Expand Down Expand Up @@ -1041,7 +1059,14 @@ private async Task ExecuteMicrosoftGraphInteractiveAsync(Batch batch)

if (PnPContext.Environment.HasValue)
{
graphBaseUri = new Uri($"https://{CloudManager.GetMicrosoftGraphAuthority(PnPContext.Environment.Value)}/");
if (PnPContext.Environment.Value == Microsoft365Environment.Custom)
{
graphBaseUri = new Uri($"https://{PnPContext.MicrosoftGraphAuthority}/");
}
else
{
graphBaseUri = new Uri($"https://{CloudManager.GetMicrosoftGraphAuthority(PnPContext.Environment.Value)}/");
}
}

// Do we need a streaming download?
Expand Down
7 changes: 6 additions & 1 deletion src/sdk/PnP.Core/Services/Core/Microsoft365Environment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ public enum Microsoft365Environment
/// <summary>
/// DOD US Government environment, see https://docs.microsoft.com/en-us/office365/servicedescriptions/office-365-platform-service-description/office-365-us-government/gcc-high-and-dod
/// </summary>
USGovernmentDoD = 6
USGovernmentDoD = 6,

/// <summary>
/// Custom cloud configuration, specify the endpoints manually
/// </summary>
Custom = 100
}
}
35 changes: 32 additions & 3 deletions src/sdk/PnP.Core/Services/Core/PnPContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,20 @@ internal PnPContext(ILogger logger,
if (globalOptions != null && globalOptions.Environment.HasValue)
{
Environment = globalOptions.Environment.Value;
// Ensure the Microsoft Graph URL is set depending on the used cloud environment
GraphClient.UpdateBaseAddress(CloudManager.GetMicrosoftGraphAuthority(Environment.Value));

if (Environment.Value == Microsoft365Environment.Custom)
{
MicrosoftGraphAuthority = globalOptions.MicrosoftGraphAuthority;
AzureADLoginAuthority = globalOptions.AzureADLoginAuthority;

// Ensure the Microsoft Graph URL is set depending on the used cloud environment
GraphClient.UpdateBaseAddress(MicrosoftGraphAuthority);
}
else
{
// Ensure the Microsoft Graph URL is set depending on the used cloud environment
GraphClient.UpdateBaseAddress(CloudManager.GetMicrosoftGraphAuthority(Environment.Value));
}
}

BatchClient = new BatchClient(this, GlobalOptions, telemetryManager);
Expand Down Expand Up @@ -174,6 +186,16 @@ internal PnPContext(ILogger logger,
/// </summary>
public Microsoft365Environment? Environment { get; internal set; }

/// <summary>
/// Returns the Microsoft Graph authority (e.g. graph.microsoft.com) to use when <see cref="Environment"/> is set to <see cref="Microsoft365Environment.Custom"/>
/// </summary>
public string MicrosoftGraphAuthority { get; internal set; }

/// <summary>
/// Returns the Azure AD Login authority (e.g. login.microsoftonline.com) to use when <see cref="Environment"/> is set to <see cref="Microsoft365Environment.Custom"/>
/// </summary>
public string AzureADLoginAuthority { get; internal set; }

/// <summary>
/// Collection for custom properties that you want to attach to a <see cref="PnPContext"/>
/// </summary>
Expand Down Expand Up @@ -870,7 +892,14 @@ internal async Task SetAADTenantId(bool useOpenIdConfiguration = false)
string loginEndpoint = "login.microsoftonline.com";
if (Environment.HasValue)
{
loginEndpoint = CloudManager.GetAzureADLoginAuthority(Environment.Value);
if (Environment.Value == Microsoft365Environment.Custom)
{
loginEndpoint = AzureADLoginAuthority;
}
else
{
loginEndpoint = CloudManager.GetAzureADLoginAuthority(Environment.Value);
}
}

// Approach might not always work given the tenant name parsing, but at least works for 99%+ of the tenants
Expand Down
10 changes: 10 additions & 0 deletions src/sdk/PnP.Core/Services/Core/PnPGlobalSettingsOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ public class PnPGlobalSettingsOptions
/// </summary>
public Microsoft365Environment? Environment { get; set; }

/// <summary>
/// Returns the Microsoft Graph authority (e.g. graph.microsoft.com) to use when <see cref="Environment"/> is set to <see cref="Microsoft365Environment.Custom"/>
/// </summary>
public string MicrosoftGraphAuthority { get; set; }

/// <summary>
/// Returns the Azure AD Login authority (e.g. login.microsoftonline.com) to use when <see cref="Environment"/> is set to <see cref="Microsoft365Environment.Custom"/>
/// </summary>
public string AzureADLoginAuthority { get; set; }

#region Http request settings

private string httpUserAgent;
Expand Down

0 comments on commit e818ffc

Please sign in to comment.