added api policies

master
Tudor Stanciu 2023-04-16 03:35:31 +03:00
parent cb6fa0507a
commit 4260d11682
14 changed files with 177 additions and 6 deletions

View File

@ -13,6 +13,8 @@
<NetmashExtensionsSwaggerPackageVersion>1.0.7</NetmashExtensionsSwaggerPackageVersion>
<NetmashTuitioAuthenticationPackageVersion>2.2.1</NetmashTuitioAuthenticationPackageVersion>
<NetmashDatabaseMigrationPackageVersion>1.2.0</NetmashDatabaseMigrationPackageVersion>
<NetmashExtensionsCachingPackageVersion>1.0.1</NetmashExtensionsCachingPackageVersion>
<CorreoPublishedLanguage>1.0.1</CorreoPublishedLanguage>
<ScrutorPackageVersion>4.2.2</ScrutorPackageVersion>
</PropertyGroup>
</Project>

View File

@ -1,6 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
using NetworkResurrector.Api.Application.Services;
using NetworkResurrector.Api.Application.Services.Abstractions;
using NetworkResurrector.Api.Application.Services.Decorators;
namespace NetworkResurrector.Api.Application
{
@ -9,6 +10,8 @@ namespace NetworkResurrector.Api.Application
public static void AddApplicationServices(this IServiceCollection services)
{
services.AddSingleton<INotificationService, NotificationService>();
services.AddScoped<IUserContext, UserContext>();
services.Decorate<IUserContext, UserContextCache>();
}
}
}

View File

@ -11,10 +11,12 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="$(MicrosoftExtensionsPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="$(MicrosoftExtensionsPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="$(MicrosoftExtensionsPackageVersion)" />
<PackageReference Include="Netmash.Extensions.Caching" Version="$(NetmashExtensionsCachingPackageVersion)" />
<PackageReference Include="Netmash.Security.Authentication.Tuitio" Version="$(NetmashTuitioAuthenticationPackageVersion)" />
<PackageReference Include="NBB.Messaging.Abstractions" Version="$(NBBPackageVersion)" />
<PackageReference Include="NetworkResurrector.Agent.Wrapper" Version="1.1.0" />
<PackageReference Include="NetworkResurrector.Server.Wrapper" Version="1.1.1" />
<PackageReference Include="Scrutor" Version="$(ScrutorPackageVersion)" />
</ItemGroup>
<ItemGroup>

View File

@ -1,5 +1,6 @@
using MediatR;
using Netmash.Security.Authentication.Tuitio.Abstractions;
using NetworkResurrector.Api.Application.Services.Abstractions;
using NetworkResurrector.Api.Domain.Repositories;
using System.Collections.Generic;
using System.Linq;
@ -19,19 +20,16 @@ namespace NetworkResurrector.Api.Application.Queries
public class QueryHandler : IRequestHandler<Query, Model>
{
private readonly IUserContextAccessor _userContext;
private readonly ISecurityRepository _securityRepository;
private readonly IUserContext _userContext;
public QueryHandler(IUserContextAccessor userContext, ISecurityRepository securityRepository)
public QueryHandler(IUserContext userContext)
{
_userContext=userContext;
_securityRepository=securityRepository;
}
public async Task<Model> Handle(Query request, CancellationToken cancellationToken)
{
var roles = _userContext.UserRoles.Select(r => r.id);
var permissions = await _securityRepository.GetUserPermissionCodes(roles);
var permissions = await _userContext.GetUserPermissions();
return new Model()
{
Permissions = permissions

View File

@ -0,0 +1,10 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace NetworkResurrector.Api.Application.Services.Abstractions
{
public interface IUserContext
{
Task<IEnumerable<string>> GetUserPermissions();
}
}

View File

@ -0,0 +1,35 @@
using Netmash.Extensions.Caching.Services;
using Netmash.Security.Authentication.Tuitio.Abstractions;
using NetworkResurrector.Api.Application.Services.Abstractions;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace NetworkResurrector.Api.Application.Services.Decorators
{
internal class UserContextCache : IUserContext
{
private readonly IUserContextAccessor _userContextAccessor;
private readonly IUserContext _inner;
private readonly ICacheService _cache;
public UserContextCache(IUserContextAccessor userContextAccessor, IUserContext inner, ICacheService cache)
{
_userContextAccessor=userContextAccessor;
_inner=inner;
_cache=cache;
}
public async Task<IEnumerable<string>> GetUserPermissions()
{
var key = $"UserPermissions_{_userContextAccessor.UserId}";
var result = await _cache.GetAsync<IEnumerable<string>>(key);
if (result == null)
{
result = await _inner.GetUserPermissions();
await _cache.SetAsync(key, result);
}
return result;
}
}
}

View File

@ -0,0 +1,28 @@
using Netmash.Security.Authentication.Tuitio.Abstractions;
using NetworkResurrector.Api.Application.Services.Abstractions;
using NetworkResurrector.Api.Domain.Repositories;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace NetworkResurrector.Api.Application.Services
{
internal class UserContext : IUserContext
{
private readonly IUserContextAccessor _userContext;
private readonly ISecurityRepository _securityRepository;
public UserContext(IUserContextAccessor userContext, ISecurityRepository securityRepository)
{
_userContext=userContext;
_securityRepository=securityRepository;
}
public async Task<IEnumerable<string>> GetUserPermissions()
{
var roles = _userContext.UserRoles.Select(r => r.id);
var permissions = await _securityRepository.GetUserPermissionCodes(roles);
return permissions;
}
}
}

View File

@ -0,0 +1,14 @@
namespace NetworkResurrector.Api.Domain.Constants
{
public struct PermissionCodes
{
public const string
VIEW_DASHBOARD = "VIEW_DASHBOARD",
MANAGE_USERS = "MANAGE_USERS",
MANAGE_SETTINGS = "MANAGE_SETTINGS",
VIEW_MACHINES = "VIEW_MACHINES",
MANAGE_MACHINES = "MANAGE_MACHINES",
OPERATE_MACHINES = "OPERATE_MACHINES",
GUEST_ACCESS = "GUEST_ACCESS";
}
}

View File

@ -0,0 +1,8 @@
namespace NetworkResurrector.Api.Authorization.Constants
{
public struct Policies
{
public const string
OperateMachines = "OPERATE_MACHINES";
}
}

View File

@ -0,0 +1,24 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using NetworkResurrector.Api.Authorization.Constants;
using NetworkResurrector.Api.Authorization.Handlers;
using NetworkResurrector.Api.Authorization.Requirements;
namespace NetworkResurrector.Api.Authorization
{
public static class DependencyInjectionExtensions
{
public static void AddLocalAuthorization(this IServiceCollection services)
{
services.AddAuthorization(options =>
{
options.AddPolicy(Policies.OperateMachines, policy =>
{
policy.Requirements.Add(new OperateMachinesRequirement());
});
});
services.AddScoped<IAuthorizationHandler, OperateMachinesHandler>();
}
}
}

View File

@ -0,0 +1,27 @@
using Microsoft.AspNetCore.Authorization;
using NetworkResurrector.Api.Application.Services.Abstractions;
using NetworkResurrector.Api.Authorization.Requirements;
using System.Linq;
using System.Threading.Tasks;
namespace NetworkResurrector.Api.Authorization.Handlers
{
public class OperateMachinesHandler : AuthorizationHandler<OperateMachinesRequirement>
{
private readonly IUserContext _userContext;
public OperateMachinesHandler(IUserContext userContext)
{
_userContext=userContext;
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, OperateMachinesRequirement requirement)
{
var permissions = await _userContext.GetUserPermissions();
if (permissions.Contains(requirement.PermissionCode))
{
context.Succeed(requirement);
}
}
}
}

View File

@ -0,0 +1,10 @@
using Microsoft.AspNetCore.Authorization;
using NetworkResurrector.Api.Domain.Constants;
namespace NetworkResurrector.Api.Authorization.Requirements
{
public class OperateMachinesRequirement : IAuthorizationRequirement
{
public readonly string PermissionCode = PermissionCodes.OPERATE_MACHINES;
}
}

View File

@ -1,6 +1,7 @@
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using NetworkResurrector.Api.Authorization.Constants;
using NetworkResurrector.Api.PublishedLanguage.Commands;
using System.Threading.Tasks;
@ -26,6 +27,7 @@ namespace NetworkResurrector.Api.Controllers
}
[HttpPost("ping")]
[Authorize(Policy = Policies.OperateMachines)]
public async Task<IActionResult> PingMachine([FromBody] PingMachine pingMachine)
{
var result = await _mediator.Send(pingMachine);

View File

@ -3,6 +3,7 @@ using MediatR.Pipeline;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Netmash.Extensions.Caching;
using Netmash.Extensions.Swagger;
using Netmash.Extensions.Swagger.Constants;
using Netmash.Infrastructure.DatabaseMigration;
@ -10,6 +11,7 @@ using Netmash.Infrastructure.DatabaseMigration.Constants;
using Netmash.Security.Authentication.Tuitio;
using NetworkResurrector.Agent.Wrapper;
using NetworkResurrector.Api.Application;
using NetworkResurrector.Api.Authorization;
using NetworkResurrector.Api.Domain.Data;
using NetworkResurrector.Server.Wrapper;
using Newtonsoft.Json;
@ -26,6 +28,12 @@ namespace NetworkResurrector.Api.Extensions
// Add basic authentication
services.AddTuitioAuthentication(configuration.GetSection("Tuitio")["BaseAddress"]);
// Add authorization
services.AddLocalAuthorization();
// Add cache service
services.AddCacheService();
// MediatR
services.AddMediatR(typeof(Application.Queries.GetMachines).Assembly);
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(RequestPreProcessorBehavior<,>));