Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ public class AzureAd
public string AuthenticationMode { get; set; }

// URL used for initiating authorization request
public string AuthorityUri { get; set; }
public string AuthorityUrl { get; set; }

// Client Id (Application Id) of the AAD app
public string ClientId { get; set; }

// Id of the Azure tenant in which AAD app is hosted. Required only for Service Principal authentication mode.
public string TenantId { get; set; }

// Scope of AAD app. Use the below configuration to use all the permissions provided in the AAD app through Azure portal.
public string[] Scope { get; set; }
// ScopeBase of AAD app. Use the below configuration to use all the permissions provided in the AAD app through Azure portal.
public string[] ScopeBase { get; set; }

// Master user email address. Required only for MasterUser authentication mode.
public string PbiUsername { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ public string GetAccessToken()
if (azureAd.Value.AuthenticationMode.Equals("masteruser", StringComparison.InvariantCultureIgnoreCase))
{
// Create a public client to authorize the app with the AAD app
IPublicClientApplication clientApp = PublicClientApplicationBuilder.Create(azureAd.Value.ClientId).WithAuthority(azureAd.Value.AuthorityUri).Build();
IPublicClientApplication clientApp = PublicClientApplicationBuilder.Create(azureAd.Value.ClientId).WithAuthority(azureAd.Value.AuthorityUrl).Build();
var userAccounts = clientApp.GetAccountsAsync().Result;
try
{
// Retrieve Access token from cache if available
authenticationResult = clientApp.AcquireTokenSilent(azureAd.Value.Scope, userAccounts.FirstOrDefault()).ExecuteAsync().Result;
authenticationResult = clientApp.AcquireTokenSilent(azureAd.Value.ScopeBase, userAccounts.FirstOrDefault()).ExecuteAsync().Result;
}
catch (MsalUiRequiredException)
{
Expand All @@ -45,15 +45,15 @@ public string GetAccessToken()
{
password.AppendChar(key);
}
authenticationResult = clientApp.AcquireTokenByUsernamePassword(azureAd.Value.Scope, azureAd.Value.PbiUsername, password).ExecuteAsync().Result;
authenticationResult = clientApp.AcquireTokenByUsernamePassword(azureAd.Value.ScopeBase, azureAd.Value.PbiUsername, password).ExecuteAsync().Result;
}
}

// Service Principal auth is the recommended by Microsoft to achieve App Owns Data Power BI embedding
else if (azureAd.Value.AuthenticationMode.Equals("serviceprincipal", StringComparison.InvariantCultureIgnoreCase))
{
// For app only authentication, we need the specific tenant id in the authority url
var tenantSpecificUrl = azureAd.Value.AuthorityUri.Replace("organizations", azureAd.Value.TenantId);
var tenantSpecificUrl = azureAd.Value.AuthorityUrl.Replace("organizations", azureAd.Value.TenantId);

// Create a confidential client to authorize the app with the AAD app
IConfidentialClientApplication clientApp = ConfidentialClientApplicationBuilder
Expand All @@ -62,7 +62,7 @@ public string GetAccessToken()
.WithAuthority(tenantSpecificUrl)
.Build();
// Make a client call if Access token is not available in cache
authenticationResult = clientApp.AcquireTokenForClient(azureAd.Value.Scope).ExecuteAsync().Result;
authenticationResult = clientApp.AcquireTokenForClient(azureAd.Value.ScopeBase).ExecuteAsync().Result;
}

return authenticationResult.AccessToken;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public static string ValidateConfig(IOptions<AzureAd> azureAd, IOptions<PowerBI>
{
message = "Authentication mode is not set in appsettings.json file";
}
else if (string.IsNullOrWhiteSpace(azureAd.Value.AuthorityUri))
else if (string.IsNullOrWhiteSpace(azureAd.Value.AuthorityUrl))
{
message = "Authority is not set in appsettings.json file";
}
Expand All @@ -38,9 +38,9 @@ public static string ValidateConfig(IOptions<AzureAd> azureAd, IOptions<PowerBI>
{
message = "Tenant Id is not set in appsettings.json file";
}
else if (azureAd.Value.Scope is null || azureAd.Value.Scope.Length == 0)
else if (azureAd.Value.ScopeBase is null || azureAd.Value.ScopeBase.Length == 0)
{
message = "Scope is not set in appsettings.json file";
message = "Scope base is not set in appsettings.json file";
}
else if (string.IsNullOrWhiteSpace(powerBI.Value.WorkspaceId))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace AppOwnsData.Services
public class PbiEmbedService
{
private readonly AadService aadService;
private readonly string urlPowerBiServiceApiRoot = "https://api.powerbi.com";
private readonly string powerBiApiUrl = "https://api.powerbi.com";

public PbiEmbedService(AadService aadService)
{
Expand All @@ -31,7 +31,7 @@ public PbiEmbedService(AadService aadService)
public PowerBIClient GetPowerBIClient()
{
var tokenCredentials = new TokenCredentials(aadService.GetAccessToken(), "Bearer");
return new PowerBIClient(new Uri(urlPowerBiServiceApiRoot ), tokenCredentials);
return new PowerBIClient(new Uri(powerBiApiUrl ), tokenCredentials);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"AzureAd": {
"AuthenticationMode": "ServicePrincipal",
"AuthorityUri": "https://login.microsoftonline.com/organizations/",
"AuthorityUrl": "https://login.microsoftonline.com/organizations/",
"ClientId": "",
"TenantId": "",
"Scope": ["https://analysis.windows.net/powerbi/api/.default"],
"ScopeBase": ["https://analysis.windows.net/powerbi/api/.default"],
"PbiUsername": "",
"PbiPassword": "",
"ClientSecret": ""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"AzureAd": {
"AuthorityUrl": "https://login.microsoftonline.com/",
"Scopes": ["https://analysis.windows.net/powerbi/api/Report.Read.All https://analysis.windows.net/powerbi/api/Dashboard.Read.All https://analysis.windows.net/powerbi/api/Workspace.Read.All"]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"AzureAd": {
"AuthorityUrl": "https://login.microsoftonline.com/",
"Scopes": ["https://analysis.usgovcloudapi.net/powerbi/api/Report.Read.All https://analysis.usgovcloudapi.net/powerbi/api/Dashboard.Read.All https://analysis.usgovcloudapi.net/powerbi/api/Workspace.Read.All"]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"AzureAd": {
"AuthorityUrl": "https://login.microsoftonline.de/",
"Scopes": ["https://analysis.cloudapi.de/powerbi/api/Report.Read.All https://analysis.cloudapi.de/powerbi/api/Dashboard.Read.All https://analysis.cloudapi.de/powerbi/api/Workspace.Read.All"]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"AzureAd": {
"AuthorityUrl": "https://login.chinacloudapi.cn/",
"Scopes": ["https://analysis.chinacloudapi.cn/powerbi/api/Report.Read.All https://analysis.chinacloudapi.cn/powerbi/api/Dashboard.Read.All https://analysis.chinacloudapi.cn/powerbi/api/Workspace.Read.All"]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

namespace UserOwnsData.Controllers
{
using UserOwnsData.Service;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Identity.Web;
using Microsoft.Graph;
using System.Threading.Tasks;
Expand All @@ -20,11 +20,15 @@ public class HomeController : Controller

private readonly ITokenAcquisition m_tokenAcquisition;

public IConfiguration Configuration { get; }

public HomeController(ITokenAcquisition tokenAcquisition,
GraphServiceClient graphServiceClient)
GraphServiceClient graphServiceClient,
IConfiguration configuration)
{
this.m_tokenAcquisition = tokenAcquisition;
this.m_graphServiceClient = graphServiceClient;
Configuration = configuration;
}

[AllowAnonymous]
Expand All @@ -34,11 +38,11 @@ public IActionResult Index()
}

// Redirects to login page to request increment consent
[AuthorizeForScopes(Scopes = new string[] { PowerBiScopes.ReadDashboard, PowerBiScopes.ReadReport, PowerBiScopes.ReadWorkspace })]
[AuthorizeForScopes(ScopeKeySection = "AzureAd:Scopes")]
public async Task<IActionResult> Embed()
{
// Generate token for the signed in user
var accessToken = await m_tokenAcquisition.GetAccessTokenForUserAsync(new string[] { PowerBiScopes.ReadDashboard, PowerBiScopes.ReadReport, PowerBiScopes.ReadWorkspace });
var accessToken = await m_tokenAcquisition.GetAccessTokenForUserAsync(Configuration["AzureAd:Scopes:0"].Split(" "));

// Get username of logged in user
var userInfo = await m_graphServiceClient.Me.Request().GetAsync();
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

namespace UserOwnsData
{
using UserOwnsData.Service;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
Expand All @@ -21,6 +20,7 @@ public class Startup
public Startup(IConfiguration configuration)
{
Configuration = configuration;
Configuration["AzureAd:Instance"] = Configuration["AzureAd:AuthorityUrl"];
}

public IConfiguration Configuration { get; }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Instance": "",
"AuthorityUrl": "https://login.microsoftonline.com/",
"Domain": "",
"TenantId": "common",
"Scopes": ["https://analysis.windows.net/powerbi/api/Report.Read.All https://analysis.windows.net/powerbi/api/Dashboard.Read.All https://analysis.windows.net/powerbi/api/Workspace.Read.All"],
"ClientId": "",
"ClientSecret": "",
"CallbackPath": "/signin-oidc"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"AzureAd": {
"AuthorityUrl": "https://login.microsoftonline.com/organizations/",
"PowerBiApiUrl": "https://api.powerbi.com/",
"ScopeBase": ["https://analysis.windows.net/powerbi/api/.default"]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"AzureAd": {
"AuthorityUrl": "https://login.microsoftonline.com/organizations/",
"PowerBiApiUrl": "https://api.powerbigov.us/",
"ScopeBase": ["https://analysis.usgovcloudapi.net/powerbi/api/.default"]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"AzureAd": {
"AuthorityUrl": "https://login.microsoftonline.de/organizations/",
"PowerBiApiUrl": "https://api.powerbi.de/",
"ScopeBase": ["https://analysis.cloudapi.de/powerbi/api/.default"]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"AzureAd": {
"AuthorityUrl": "https://login.chinacloudapi.cn/organizations/",
"PowerBiApiUrl": "https://api.powerbi.cn/",
"ScopeBase": ["https://analysis.chinacloudapi.cn/powerbi/api/.default"]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,19 @@ public class AzureAd
public string AuthenticationMode { get; set; }

// URL used for initiating authorization request
public string AuthorityUri { get; set; }
public string AuthorityUrl { get; set; }

// Client Id (Application Id) of the AAD app
public string ClientId { get; set; }

// Id of the Azure tenant in which AAD app is hosted. Required only for Service Principal authentication mode.
public string TenantId { get; set; }

// Scope of AAD app. Use the below configuration to use all the permissions provided in the AAD app through Azure portal.
public string[] Scope { get; set; }
// End point URL for REST API
public string PowerBiApiUrl { get; set; }

// ScopeBase of AAD app. Use the below configuration to use all the permissions provided in the AAD app through Azure portal.
public string[] ScopeBase { get; set; }

// Master user email address. Required only for MasterUser authentication mode.
public string PbiUsername { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ public string GetAccessToken()
if (azureAd.Value.AuthenticationMode.Equals("masteruser", StringComparison.InvariantCultureIgnoreCase))
{
// Create a public client to authorize the app with the AAD app
IPublicClientApplication clientApp = PublicClientApplicationBuilder.Create(azureAd.Value.ClientId).WithAuthority(azureAd.Value.AuthorityUri).Build();
IPublicClientApplication clientApp = PublicClientApplicationBuilder.Create(azureAd.Value.ClientId).WithAuthority(azureAd.Value.AuthorityUrl).Build();
var userAccounts = clientApp.GetAccountsAsync().Result;
try
{
// Retrieve Access token from cache if available
authenticationResult = clientApp.AcquireTokenSilent(azureAd.Value.Scope, userAccounts.FirstOrDefault()).ExecuteAsync().Result;
authenticationResult = clientApp.AcquireTokenSilent(azureAd.Value.ScopeBase, userAccounts.FirstOrDefault()).ExecuteAsync().Result;
}
catch (MsalUiRequiredException)
{
Expand All @@ -45,15 +45,15 @@ public string GetAccessToken()
{
password.AppendChar(key);
}
authenticationResult = clientApp.AcquireTokenByUsernamePassword(azureAd.Value.Scope, azureAd.Value.PbiUsername, password).ExecuteAsync().Result;
authenticationResult = clientApp.AcquireTokenByUsernamePassword(azureAd.Value.ScopeBase, azureAd.Value.PbiUsername, password).ExecuteAsync().Result;
}
}

// Service Principal auth is the recommended by Microsoft to achieve App Owns Data Power BI embedding
else
{
// For app only authentication, we need the specific tenant id in the authority url
var tenantSpecificUrl = azureAd.Value.AuthorityUri.Replace("organizations", azureAd.Value.TenantId);
var tenantSpecificUrl = azureAd.Value.AuthorityUrl.Replace("organizations", azureAd.Value.TenantId);

// Create a confidential client to authorize the app with the AAD app
IConfidentialClientApplication clientApp = ConfidentialClientApplicationBuilder
Expand All @@ -62,10 +62,14 @@ public string GetAccessToken()
.WithAuthority(tenantSpecificUrl)
.Build();
// Make a client call if Access token is not available in cache
authenticationResult = clientApp.AcquireTokenForClient(azureAd.Value.Scope).ExecuteAsync().Result;
authenticationResult = clientApp.AcquireTokenForClient(azureAd.Value.ScopeBase).ExecuteAsync().Result;
}

return authenticationResult.AccessToken;
}

public string GetPowerBiApiUrl() {
return azureAd.Value.PowerBiApiUrl;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public static string ValidateConfig(IOptions<AzureAd> azureAd)
{
message = $"Authentication mode is incorrect or {Constants.InvalidAppSetting}";
}
else if (string.IsNullOrWhiteSpace(azureAd.Value.AuthorityUri))
else if (string.IsNullOrWhiteSpace(azureAd.Value.AuthorityUrl))
{
message = $"Authority {Constants.InvalidAppSetting}";
}
Expand All @@ -38,9 +38,9 @@ public static string ValidateConfig(IOptions<AzureAd> azureAd)
{
message = $"Tenant Id {Constants.InvalidAppSetting}";
}
else if (azureAd.Value.Scope is null || azureAd.Value.Scope.Length == 0)
else if (azureAd.Value.ScopeBase is null || azureAd.Value.ScopeBase.Length == 0)
{
message = $"Scope {Constants.InvalidAppSetting}";
message = $"Scope base {Constants.InvalidAppSetting}";
}
else if (isAuthModeMasterUser && string.IsNullOrWhiteSpace(azureAd.Value.PbiUsername))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ namespace EncryptCredentials.Services
public class PowerBIService
{
private readonly AadService aadService;
private readonly string urlPowerBiServiceApiRoot = "https://api.powerbi.com";

public PowerBIService(AadService aadService)
{
Expand All @@ -30,7 +29,7 @@ public PowerBIService(AadService aadService)
public PowerBIClient GetPowerBIClient()
{
var tokenCredentials = new TokenCredentials(aadService.GetAccessToken(), "Bearer");
return new PowerBIClient(new Uri(urlPowerBiServiceApiRoot), tokenCredentials);
return new PowerBIClient(new Uri(aadService.GetPowerBiApiUrl()), tokenCredentials);
}

/// <summary>
Expand Down Expand Up @@ -110,7 +109,18 @@ public CredentialDetails GetCredentialDetails(Guid gatewayId, string credentialT
var credentials = GetCredentials(credentialType, credentialsArray);

// Get the Getway
var gateway = GetGateway(gatewayId);
Gateway gateway = new Gateway(gatewayId);
try
{
gateway = GetGateway(gatewayId);
}
catch (HttpOperationException e)
{
if (e.Response.ReasonPhrase != "Not Found")
{
throw;
}
}

// Initialize credentialsEncryptor and encryptedConnection for Cloud gateway
var credentialsEncryptor = (AsymmetricKeyEncryptor)null;
Expand Down
Loading