Files
mixtape/zero.Core/ApplicationResolver.cs
T

233 lines
6.2 KiB
C#
Raw Normal View History

2020-11-16 01:07:07 +01:00
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
2020-05-21 13:41:09 +02:00
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.Extensions.Logging;
2020-05-21 13:41:09 +02:00
using Raven.Client.Documents;
using Raven.Client.Documents.Session;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
2020-11-15 16:29:22 +01:00
using zero.Core.Database;
2020-05-21 13:41:09 +02:00
using zero.Core.Entities;
using zero.Core.Extensions;
using zero.Core.Handlers;
2020-05-21 13:41:09 +02:00
using zero.Core.Identity;
using zero.Core.Options;
2020-11-16 01:07:07 +01:00
namespace zero.Core
2020-05-21 13:41:09 +02:00
{
2020-11-16 01:07:07 +01:00
public class ApplicationResolver : IApplicationResolver
2020-05-21 13:41:09 +02:00
{
2020-11-15 16:29:22 +01:00
protected IZeroStore Store { get; private set; }
2020-05-21 13:41:09 +02:00
protected IZeroOptions Options { get; private set; }
2020-11-16 01:07:07 +01:00
protected ILogger<ApplicationResolver> Logger { get; private set; }
2020-11-05 00:46:18 +01:00
protected IHandlerHolder Handler { get; private set; }
2020-11-16 01:07:07 +01:00
private IList<IApplication> Apps { get; set; }
2020-10-26 13:59:46 +01:00
2020-05-21 13:41:09 +02:00
2020-11-16 01:07:07 +01:00
public ApplicationResolver(IZeroStore store, IZeroOptions options, ILogger<ApplicationResolver> logger, IHandlerHolder handler = null)
2020-05-21 13:41:09 +02:00
{
2020-11-15 16:29:22 +01:00
Store = store;
2020-05-21 13:41:09 +02:00
Options = options;
Logger = logger;
Handler = handler;
2020-05-21 13:41:09 +02:00
}
/// <inheritdoc />
2020-11-17 11:27:31 +01:00
public async Task<IApplication> Resolve(HttpContext context, ClaimsPrincipal user)
2020-05-21 13:41:09 +02:00
{
if (context?.Request == null)
{
2020-11-16 01:07:07 +01:00
Logger.LogWarning("Could not resolve application as HTTP request is null");
2020-05-21 13:41:09 +02:00
return null;
}
IApplication app;
2020-11-16 01:07:07 +01:00
if (context.IsBackofficeRequest(Options.BackofficePath))
2020-05-21 13:41:09 +02:00
{
2020-11-04 23:38:06 +01:00
app = await ResolveFromUser(user);
2020-05-21 13:41:09 +02:00
}
else
{
app = await ResolveFromRequest(context);
}
if (app == null)
{
//Logger.LogWarning("Could not resolve application for host {host}", context.Request.Host);
2020-11-17 11:27:31 +01:00
IList<IApplication> apps = await GetApplications();
app = apps.FirstOrDefault();
}
2020-05-21 13:41:09 +02:00
return app;
}
/// <inheritdoc />
public async Task<IApplication> ResolveFromUser(ClaimsPrincipal user)
{
IBackofficeUser userEntity = await GetBackofficeUser(user);
2020-05-21 13:41:09 +02:00
return await ResolveFromUser(userEntity);
}
/// <inheritdoc />
public async Task<IApplication> ResolveFromUser(IBackofficeUser user)
2020-05-21 13:41:09 +02:00
{
if (user == null)
{
return null;
}
string appId;
2020-11-16 14:48:23 +01:00
string[] allowedAppIds = user.GetAllowedAppIds();
2020-05-21 13:41:09 +02:00
if (!user.CurrentAppId.IsNullOrEmpty())
{
if (user.IsSuper || allowedAppIds.Contains(user.CurrentAppId, StringComparer.InvariantCultureIgnoreCase))
{
appId = user.CurrentAppId;
}
else
{
appId = user.AppId;
2020-05-21 13:41:09 +02:00
}
}
else
{
appId = user.AppId;
2020-05-21 13:41:09 +02:00
}
if (appId.IsNullOrEmpty())
{
throw new Exception($"User entity ${user.Id} needs a valid AppId");
}
2020-11-16 01:07:07 +01:00
using IAsyncDocumentSession session = Store.OpenCoreSession();
return await session.LoadAsync<IApplication>(appId);
2020-05-21 13:41:09 +02:00
}
/// <inheritdoc />
public async Task<IApplication> ResolveFromRequest(HttpContext context)
{
2020-11-05 00:46:18 +01:00
return Handler.Get<IApplicationResolverHandler>()?.Resolve(context.Request, await GetApplications()) ?? await ResolveFromUri(context.Request.GetEncodedUrl());
2020-05-21 13:41:09 +02:00
}
/// <inheritdoc />
public async Task<IApplication> ResolveFromUri(string uriString)
{
return ResolveFromUriInternal(new Uri(uriString, UriKind.Absolute), await GetApplications());
}
/// <inheritdoc />
public async Task<IApplication> ResolveFromUri(Uri uri)
{
return ResolveFromUriInternal(uri, await GetApplications());
}
/// <summary>
/// Get matching application from an URI
/// </summary>
2020-10-26 13:59:46 +01:00
IApplication ResolveFromUriInternal(Uri uri, IList<IApplication> apps)
2020-05-21 13:41:09 +02:00
{
2020-10-26 13:59:46 +01:00
foreach (IApplication app in apps)
2020-05-21 13:41:09 +02:00
{
if (app.Domains?.Length < 1)
{
2020-11-16 01:07:07 +01:00
Logger.LogWarning("No domains specified for app {app}", app.Id);
2020-05-21 13:41:09 +02:00
continue;
}
foreach (Uri domain in app.Domains)
2020-05-21 13:41:09 +02:00
{
int compareResult = Uri.Compare(uri, domain, UriComponents.HostAndPort, UriFormat.SafeUnescaped, StringComparison.OrdinalIgnoreCase);
2020-05-21 13:41:09 +02:00
if (compareResult == 0)
{
2020-11-16 01:07:07 +01:00
return app;
2020-05-21 13:41:09 +02:00
}
}
}
2020-11-16 01:07:07 +01:00
return null;
2020-05-21 13:41:09 +02:00
}
2020-11-17 11:27:31 +01:00
/// <summary>
/// Get all applications to choose from
/// </summary>
async Task<IList<IApplication>> GetApplications()
{
if (Apps != null)
{
return Apps;
}
using IAsyncDocumentSession session = Store.OpenCoreSession();
Apps = await session.Query<IApplication>().ToListAsync();
return Apps;
}
/// <summary>
/// Get backoffice user from claims principal
/// </summary>
async Task<IBackofficeUser> GetBackofficeUser(ClaimsPrincipal user)
{
string userId = user.FindFirstValue(Constants.Auth.Claims.UserId);
2020-11-16 01:07:07 +01:00
using IAsyncDocumentSession session = Store.OpenCoreSession();
return await session.LoadAsync<IBackofficeUser>(userId);
}
2020-05-21 13:41:09 +02:00
}
2020-11-16 01:07:07 +01:00
public interface IApplicationResolver
2020-05-21 13:41:09 +02:00
{
/// <summary>
/// Resolves the current application from either the backoffice user (in case it is backoffice request)
/// or the domain (in case it is frontend request).
/// </summary>
2020-11-17 11:27:31 +01:00
Task<IApplication> Resolve(HttpContext context, ClaimsPrincipal user);
2020-05-21 13:41:09 +02:00
/// <summary>
/// Resolves the current application from the request path
/// </summary>
Task<IApplication> ResolveFromRequest(HttpContext context);
/// <summary>
/// Get matching application from an URI string
/// </summary>
Task<IApplication> ResolveFromUri(string uriString);
/// <summary>
/// Get matching application from an URI
/// </summary>
Task<IApplication> ResolveFromUri(Uri uri);
/// <summary>
/// Resolves the current application from the logged-in backoffice user.
/// This method won't return apps the user has no access to.
/// </summary>
Task<IApplication> ResolveFromUser(ClaimsPrincipal user);
/// <summary>
/// Resolves the current application from a user.
/// This method won't return apps the user has no access to.
/// </summary>
Task<IApplication> ResolveFromUser(IBackofficeUser user);
2020-05-21 13:41:09 +02:00
}
}