Merge pull request #208 from 1iveowl/dev/saas-academy

Fixed a few left-over/missing comments
This commit is contained in:
1iveowl 2023-03-17 16:28:56 +01:00 коммит произвёл GitHub
Родитель 0e5782504b 373c418563
Коммит 9fedbbff05
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
10 изменённых файлов: 31 добавлений и 55 удалений

2
.github/workflows/saas-app-deploy.yml поставляемый
Просмотреть файл

@ -1,5 +1,5 @@
---
name: ASDK Administration Service API - Deploy to Azure Web Services
name: ASDK Saas Sample App - Deploy to Azure Web Services
on:
workflow_dispatch:

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

@ -78,7 +78,7 @@ public class TenantsController : ControllerBase
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[SaasAuthorize<SaasTenantPermissionRequirement, TenantPermissionKind>(TenantPermissionKind.Read, "tenantId")]
[SaasAuthorize<SaasTenantPermissionRequirement, TenantPermissionKind>(TenantPermissionKind.Read, routingRestrictionKeyName: "tenantId")]
public async Task<ActionResult<TenantDTO>> GetTenant(Guid tenantId)
{
_logger.LogDebug("{User} requested tenant with ID {TenantID}", User?.Identity?.Name, tenantId);

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

@ -59,37 +59,21 @@ builder.Services.Configure<SqlOptions>(
builder.Services.Configure<SaasAuthorizationOptions>(
builder.Configuration.GetRequiredSection(SaasAuthorizationOptions.SectionName));
// Using Entity Framework for accessing permission data stored in the Permissions Db.
builder.Services.AddDbContext<TenantsContext>(options =>
{
var sqlConnectionString = builder.Configuration.GetRequiredSection(SqlOptions.SectionName)
.Get<SqlOptions>()?.TenantSQLConnectionString
?? throw new NullReferenceException("SQL Connection string cannot be null.");
options.UseSqlServer(sqlConnectionString);
});
builder.Services.AddHttpContextAccessor();
// Add authentication for incoming requests
builder.Services.AddMicrosoftIdentityWebApiAuthentication(builder.Configuration, AzureB2CAdminApiOptions.SectionName);
builder.Services.AddHttpContextAccessor();
// TODO (SaaS): Add necessary roles to scopes for SaaS App operations
// Register authorization handlers for authorization
builder.Services.AddSingleton<IAuthorizationHandler, SaasTenantPermissionAuthorizationHandler>();
builder.Services.AddSingleton<IAuthorizationHandler, SaasUserPermissionAuthorizationHandler>();
// Register the policy provider
builder.Services.AddSingleton<IAuthorizationPolicyProvider, SaasPermissionAuthorizationPolicyProvider>();
//builder.Services.Configure<ClaimToRoleTransformerOptions>(
// builder.Configuration.GetRequiredSection(ClaimToRoleTransformerOptions.SectionName));
// builder.Services.AddTransient<IClaimsTransformation, ClaimPermissionToRoleTransformer>();
builder.Services.AddControllers();
builder.Services.AddScoped<ITenantService, TenantService>();
// builder.Services.AddScoped<IPermissionService, PermissionService>();
builder.Services.AddHttpClient<IPermissionsServiceClient, PermissionsServiceClient>()
.ConfigureHttpClient((serviceProvider, client) =>
@ -107,6 +91,16 @@ builder.Services.AddHttpClient<IPermissionsServiceClient, PermissionsServiceClie
client.DefaultRequestHeaders.Add("x-api-key", apiKey);
});
// Using Entity Framework for accessing permission data stored in the Permissions Db.
builder.Services.AddDbContext<TenantsContext>(options =>
{
var sqlConnectionString = builder.Configuration.GetRequiredSection(SqlOptions.SectionName)
.Get<SqlOptions>()?.TenantSQLConnectionString
?? throw new NullReferenceException("SQL Connection string cannot be null.");
options.UseSqlServer(sqlConnectionString);
});
var app = builder.Build();
//Call this as early as possible to make sure DB is ready

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

@ -8,16 +8,15 @@ namespace Saas.Permissions.Service.Controllers;
public class CustomClaimsController : ControllerBase
{
private readonly IPermissionsService _permissionsService;
private readonly IGraphAPIService _graphAPIService;
private readonly ILogger _logger;
public CustomClaimsController(IPermissionsService permissionsService, IGraphAPIService graphAPIService, ILogger<CustomClaimsController> logger)
public CustomClaimsController(IPermissionsService permissionsService, ILogger<CustomClaimsController> logger)
{
_permissionsService = permissionsService;
_graphAPIService = graphAPIService;
_logger = logger;
}
// This is the endpoint that is called by Azure AD B2C to get alle the custom claims defined for a specific user.
[HttpPost("permissions")]
[Produces("application/json")]
[ProducesResponseType(typeof(PermissionsClaimResponse), StatusCodes.Status200OK)]
@ -28,26 +27,27 @@ public class CustomClaimsController : ControllerBase
{
_logger.LogDebug("Custom claims where requested for user id: {objectId}", request.ObjectId);
// Get all the permissions defined for the specific user with requested objectId from the database.
var permissions = await _permissionsService.GetPermissionsAsync(request.ObjectId);
IEnumerable<string> permissionClaims = new List<string>();
foreach (var permission in permissions)
{
// adding user permission to permissionsClaims list
if (permission.UserPermissions?.Any() ?? false)
{
permissionClaims = permissionClaims
.Concat(permissions
.SelectMany(permission => permission.UserPermissions)
.Select(user => user.ToClaim()));
.Concat(permissions.SelectMany(permission => permission.UserPermissions)
.Select(user => user.ToClaim()));
}
// adding tenant permissions to permissionsClaims list
if (permission.TenantPermissions?.Any() ?? false)
{
permissionClaims = permissionClaims
.Concat(permissions
.SelectMany(permission => permission.TenantPermissions)
.Select(tenant => tenant.ToClaim()));
.Concat(permissions.SelectMany(permission => permission.TenantPermissions)
.Select(tenant => tenant.ToClaim()));
}
}
@ -67,7 +67,8 @@ public class CustomClaimsController : ControllerBase
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> Roles(ClaimsRequest request)
{
// Not using this at the moment. The MS Graph call is expensive and we don't need it for now.
// This request is currently retuning an empty list only.
// The MS Graph call is expensive and we don't need it for now.
// Also having a MS Graph call in the login flow is not ideal, as high volume of logins may hit MS Graph throttloing limits.
// var roles = await _graphAPIService.GetAppRolesAsync(request);

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

@ -8,7 +8,6 @@ using System.Reflection;
namespace Saas.Identity.Authorization.Provider;
public class SaasPermissionAuthorizationPolicyProvider : DefaultAuthorizationPolicyProvider
{
public SaasPermissionAuthorizationPolicyProvider(
IOptions<AuthorizationOptions> options) : base(options)
{
@ -37,11 +36,13 @@ public class SaasPermissionAuthorizationPolicyProvider : DefaultAuthorizationPol
// Create instances of the classes that implement ISaasRequirement and have a SaasRequirementAttribute with the same name as the policy name.
var requirements = requirementsType.Select(type => (IAuthorizationRequirement?)Activator.CreateInstance(type, saasPolicy));
// Create new policy builder.
AuthorizationPolicyBuilder authorizationPolicyBuilder = new();
// Add the default authentication requirement that the user must be authorized.
authorizationPolicyBuilder.RequireAuthenticatedUser();
// Add the requirements to the polic builder.
// Add the requirements matching the policy to the policy builder.
foreach (var requirement in requirements)
{
if (requirement is not null)
@ -50,6 +51,7 @@ public class SaasPermissionAuthorizationPolicyProvider : DefaultAuthorizationPol
}
}
// Build the policy.
return authorizationPolicyBuilder.Build();
}
}

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

@ -6,7 +6,6 @@ public interface ISaasRequirement : IAuthorizationRequirement
{
static abstract string PermissionEntityName { get; }
//static string PermissionClaimsIdentifier { get; } = "permissions";
SaasPolicy Policy { get; }
int PermissionValue();
}

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

@ -5,8 +5,6 @@ namespace Saas.Identity.Authorization.Requirement;
public abstract record SaasRequirementBase
{
// public string PermissionClaimsIdentifier { get; } = "permissions";
public SaasPolicy Policy { get; init; }
protected SaasRequirementBase(SaasPolicy policy)

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

@ -8,7 +8,6 @@ namespace Saas.Identity.Authorization.Requirement;
[SaasRequirement(UserPermission.EntityName)]
public sealed record SaasUserPermissionRequirement : SaasRequirementBase, ISaasRequirement
{
public static string PermissionEntityName => UserPermission.EntityName;
public SaasUserPermissionRequirement(SaasPolicy policy) : base(policy) { }

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

@ -1,5 +1,4 @@

using Saas.Interface;
using Saas.Interface;
namespace Saas.Shared.Options;
@ -18,21 +17,6 @@ public record AzureAdB2CBase
public string? ClientSecret { get; init; }
public KeyVaultCertificate[]? KeyVaultCertificateReferences { get; init; }
//public IEnumerable<CertificateDescription>? ClientCertificates => new CertificateDescription[]
//{
// CertificateDescription.FromKeyVault(KeyVaultCertificateReferences.First().KeyVaultUrl,
// KeyVaultCertificateReferences.First().KeyVaultCertificateName)
//};
//public IEnumerable<CertificateDescription>? ClientCertificates => KeyVaultCertificateReferences?.Select(cert => new CertificateDescription
//{
// //SourceType = CertificateSource.Base64Encoded,
// //Base64EncodedValue = Certificate
// SourceType = CertificateSource.KeyVault,
// KeyVaultUrl = cert.KeyVaultUrl,
// KeyVaultCertificateName = cert.KeyVaultCertificateName
//});
}

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

@ -6,6 +6,5 @@ public class PermissionsApiOptions
public const string SectionName = "PermissionsApi";
public string? ApiKey { get; init; }
public string? SQLConnectionString { get; init; }
}