diff --git a/zero.Core/Api/BackofficeApi.cs b/zero.Core/Api/BackofficeApi.cs
index 4a0d627f..be8d437b 100644
--- a/zero.Core/Api/BackofficeApi.cs
+++ b/zero.Core/Api/BackofficeApi.cs
@@ -25,7 +25,14 @@ namespace zero.Core.Api
protected bool IsCoreDatabase { get; private set; }
- public BackofficeApi(IBackofficeStore store, bool isCoreDatabase = false)
+ public BackofficeApi(IBackofficeStore store)
+ {
+ Store = store.Store;
+ Backoffice = store;
+ IsCoreDatabase = false;
+ }
+
+ internal BackofficeApi(IBackofficeStore store, bool isCoreDatabase)
{
Store = store.Store;
Backoffice = store;
diff --git a/zero.Core/Api/BackofficeStore.cs b/zero.Core/Api/BackofficeStore.cs
index 5b2aef79..4cf65eaf 100644
--- a/zero.Core/Api/BackofficeStore.cs
+++ b/zero.Core/Api/BackofficeStore.cs
@@ -1,5 +1,4 @@
-using Raven.Client.Documents;
-using zero.Core.Database;
+using zero.Core.Database;
using zero.Core.Messages;
using zero.Core.Options;
@@ -9,7 +8,7 @@ namespace zero.Core.Api
{
public IZeroStore Store { get; private set; }
- public IApplicationContext AppContext { get; private set; }
+ public IZeroContext Context { get; private set; }
public IZeroOptions Options { get; private set; }
@@ -18,10 +17,10 @@ namespace zero.Core.Api
public IMessageAggregator Messages { get; private set; }
- public BackofficeStore(IZeroStore store, IApplicationContext appContext, IZeroOptions options, IAuthenticationApi authenticationApi, IMessageAggregator messages)
+ public BackofficeStore(IZeroStore store, IZeroContext context, IZeroOptions options, IAuthenticationApi authenticationApi, IMessageAggregator messages)
{
Store = store;
- AppContext = appContext;
+ Context = context;
Options = options;
Auth = authenticationApi;
Messages = messages;
@@ -33,7 +32,7 @@ namespace zero.Core.Api
{
IZeroStore Store { get; }
- IApplicationContext AppContext { get; }
+ IZeroContext Context { get; }
IZeroOptions Options { get; }
diff --git a/zero.Core/Api/SetupApi.cs b/zero.Core/Api/SetupApi.cs
index a45452d4..7a0775f0 100644
--- a/zero.Core/Api/SetupApi.cs
+++ b/zero.Core/Api/SetupApi.cs
@@ -113,7 +113,7 @@ namespace zero.Core.Api
await session.StoreAsync(app);
// set app-id for user and store it
- //user.AppId = session.Advanced.GetDocumentId(app); // TODO appx fix
+ user.AppId = session.Advanced.GetDocumentId(app);
await session.StoreAsync(user);
// save default user roles
diff --git a/zero.Core/Api/ApplicationContext.cs b/zero.Core/ApplicationResolver.cs
similarity index 63%
rename from zero.Core/Api/ApplicationContext.cs
rename to zero.Core/ApplicationResolver.cs
index 891ec4e1..0267c3e5 100644
--- a/zero.Core/Api/ApplicationContext.cs
+++ b/zero.Core/ApplicationResolver.cs
@@ -1,4 +1,5 @@
-using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.Extensions.Logging;
using Raven.Client.Documents;
@@ -15,29 +16,23 @@ using zero.Core.Handlers;
using zero.Core.Identity;
using zero.Core.Options;
-namespace zero.Core.Api
+namespace zero.Core
{
- public class ApplicationContext : IApplicationContext
+ public class ApplicationResolver : IApplicationResolver
{
- ///
- public IApplication App { get; protected set; }
-
- ///
- public string AppId { get; protected set; }
-
protected IZeroStore Store { get; private set; }
protected IZeroOptions Options { get; private set; }
- protected ILogger Logger { get; private set; }
+ protected ILogger Logger { get; private set; }
protected IHandlerHolder Handler { get; private set; }
- static IList Apps { get; set; }
+ private IList Apps { get; set; }
- public ApplicationContext(IZeroStore store, IZeroOptions options, ILogger logger, IHandlerHolder handler = null)
+ public ApplicationResolver(IZeroStore store, IZeroOptions options, ILogger logger, IHandlerHolder handler = null)
{
Store = store;
Options = options;
@@ -51,12 +46,13 @@ namespace zero.Core.Api
{
if (context?.Request == null)
{
+ Logger.LogWarning("Could not resolve application as HTTP request is null");
return null;
}
IApplication app;
- if (IsBackofficeRequest(context))
+ if (context.IsBackofficeRequest(Options.BackofficePath))
{
app = await ResolveFromUser(user);
}
@@ -72,45 +68,10 @@ namespace zero.Core.Api
app = apps.FirstOrDefault();
}
- App = app;
- AppId = app?.Id;
-
return app;
}
- ///
- public async Task TrySwitchForUser(IBackofficeUser user, string appId)
- {
- if (user == null || appId.IsNullOrEmpty())
- {
- return false;
- }
-
- string[] allowedAppIds = GetAllowedAppIdsForUser(user);
-
- bool isMainId = appId.Equals(user.AppId, StringComparison.InvariantCultureIgnoreCase);
- bool isAllowedId = allowedAppIds.Contains(appId, StringComparer.InvariantCultureIgnoreCase);
-
- if (user.IsSuper || isMainId || isAllowedId)
- {
- user.CurrentAppId = appId;
-
- //byte[] bytes = new byte[20];
- //RandomNumberGenerator.Fill(bytes);
- //user.SecurityStamp = Base32.ToBase32(bytes); // TODO update security stamp but Base32 is .net core internal
-
- using IAsyncDocumentSession session = Store.OpenCoreSession(Options);
- await session.StoreAsync(user);
- await session.SaveChangesAsync();
-
- return true;
- }
-
- return false;
- }
-
-
///
public async Task ResolveFromUser(ClaimsPrincipal user)
{
@@ -151,7 +112,7 @@ namespace zero.Core.Api
throw new Exception($"User entity ${user.Id} needs a valid AppId");
}
- using IAsyncDocumentSession session = Store.OpenCoreSession(Options);
+ using IAsyncDocumentSession session = Store.OpenCoreSession();
return await session.LoadAsync(appId);
}
@@ -177,71 +138,30 @@ namespace zero.Core.Api
}
- ///
- public async Task ForId(string appId)
- {
- using IAsyncDocumentSession session = Store.OpenAsyncSession();
- IApplication app = await session.LoadAsync(appId);
-
- return new ApplicationContext(Store, Options, Logger, Handler)
- {
- App = app,
- AppId = appId
- };
- }
-
-
- ///
- public bool IsBackofficeRequest(HttpContext context)
- {
- string path = Options.BackofficePath.EnsureStartsWith('/').TrimEnd('/');
- return context.Request.Path.ToString().StartsWith(path);
- }
-
-
///
/// Get matching application from an URI
///
IApplication ResolveFromUriInternal(Uri uri, IList apps)
{
- string[] protocols = new string[3] { "https://", "http://", "//" };
-
- IApplication currentApp = null;
-
foreach (IApplication app in apps)
{
if (app.Domains?.Length < 1)
{
+ Logger.LogWarning("No domains specified for app {app}", app.Id);
continue;
}
foreach (Uri domain in app.Domains)
{
- //string normalizedDomain = domain;
-
- //if (!protocols.Any(protocol => domain.StartsWith(protocol, StringComparison.OrdinalIgnoreCase)))
- //{
- // normalizedDomain = "http://" + domain;
- //}
-
- //UriBuilder uriBuilder = new UriBuilder(normalizedDomain);
-
- //if (!uriBuilder.Uri.IsAbsoluteUri)
- //{
- // continue;
- //}
-
int compareResult = Uri.Compare(uri, domain, UriComponents.HostAndPort, UriFormat.SafeUnescaped, StringComparison.OrdinalIgnoreCase);
-
if (compareResult == 0)
{
- currentApp = app;
- break;
+ return app;
}
}
}
- return currentApp;
+ return null;
}
@@ -255,7 +175,7 @@ namespace zero.Core.Api
return Apps;
}
- using IAsyncDocumentSession session = Store.OpenCoreSession(Options);
+ using IAsyncDocumentSession session = Store.OpenCoreSession();
Apps = await session.Query().ToListAsync();
return Apps;
}
@@ -268,7 +188,7 @@ namespace zero.Core.Api
{
string userId = user.FindFirstValue(Constants.Auth.Claims.UserId);
- using IAsyncDocumentSession session = Store.OpenCoreSession(Options);
+ using IAsyncDocumentSession session = Store.OpenCoreSession();
return await session.LoadAsync(userId);
}
@@ -284,34 +204,49 @@ namespace zero.Core.Api
return permissions.Where(x => x.IsTrue).Select(x => x.NormalizedKey).ToArray();
}
+
+
+ ///
+ //public async Task TrySwitchForUser(IBackofficeUser user, string appId)
+ //{
+ // if (user == null || appId.IsNullOrEmpty())
+ // {
+ // return false;
+ // }
+
+ // string[] allowedAppIds = GetAllowedAppIdsForUser(user);
+
+ // bool isMainId = appId.Equals(user.AppId, StringComparison.InvariantCultureIgnoreCase);
+ // bool isAllowedId = allowedAppIds.Contains(appId, StringComparer.InvariantCultureIgnoreCase);
+
+ // if (user.IsSuper || isMainId || isAllowedId)
+ // {
+ // user.CurrentAppId = appId;
+
+ // //byte[] bytes = new byte[20];
+ // //RandomNumberGenerator.Fill(bytes);
+ // //user.SecurityStamp = Base32.ToBase32(bytes); // TODO update security stamp but Base32 is .net core internal
+
+ // using IAsyncDocumentSession session = Store.OpenCoreSession();
+ // await session.StoreAsync(user);
+ // await session.SaveChangesAsync();
+
+ // return true;
+ // }
+
+ // return false;
+ //}
}
-
- public interface IApplicationContext
+ public interface IApplicationResolver
{
- ///
- /// Currently loaded application
- ///
- IApplication App { get; }
-
- ///
- /// Current loaded application Id
- ///
- string AppId { get; }
-
///
/// Resolves the current application from either the backoffice user (in case it is backoffice request)
/// or the domain (in case it is frontend request).
- /// The resolved data is stored in the App + AppId properties.
///
Task Resolve(HttpContext context, ClaimsPrincipal user);
- ///
- /// Try to switch the current application for a user
- ///
- Task TrySwitchForUser(IBackofficeUser user, string appId);
-
///
/// Resolves the current application from the request path
///
@@ -338,15 +273,5 @@ namespace zero.Core.Api
/// This method won't return apps the user has no access to.
///
Task ResolveFromUser(IBackofficeUser user);
-
- ///
- /// Creates a new application context for the specified application.
- ///
- Task ForId(string appId);
-
- ///
- /// Whether the current request is a backoffice request
- ///
- bool IsBackofficeRequest(HttpContext context);
}
}
diff --git a/zero.Core/Constants.cs b/zero.Core/Constants.cs
index e4f422ec..ea528e5d 100644
--- a/zero.Core/Constants.cs
+++ b/zero.Core/Constants.cs
@@ -28,7 +28,7 @@
public const string Email = "zero.claim.email";
public const string Permission = "zero.claim.permission";
public const string DefaultAppId = "zero.claim.defaultAppId";
- public const string AppId = "zero.claim.appId"; // TODO appx fix
+ public const string AppId = "zero.claim.appId";
public const string TicketExpires = "zero.claim.ticketExpires";
}
}
diff --git a/zero.Core/Database/ZeroStore.cs b/zero.Core/Database/ZeroStore.cs
index 2936967b..aa4e932a 100644
--- a/zero.Core/Database/ZeroStore.cs
+++ b/zero.Core/Database/ZeroStore.cs
@@ -1,29 +1,28 @@
-using Raven.Client.Documents;
+using Raven.Client;
+using Raven.Client.Documents;
using Raven.Client.Documents.BulkInsert;
using Raven.Client.Documents.Operations;
+using Raven.Client.Documents.Queries;
using Raven.Client.Documents.Session;
+using System;
using System.Threading;
using System.Threading.Tasks;
-using zero.Core.Extensions;
using zero.Core.Options;
namespace zero.Core.Database
{
public class ZeroStore : DocumentStore, IZeroStore
{
- protected IZeroOptions Options { get; set; }
-
public ZeroStore(IZeroOptions options) : base()
{
Options = options;
Database = null;
}
+ protected IZeroOptions Options { get; set; }
- internal async Task SetContext()
- {
-
- }
+ ///
+ public string ResolvedDatabase { get; set; }
///
@@ -33,20 +32,83 @@ namespace zero.Core.Database
///
public OperationExecutor GetOperationExecutor(string database = null)
{
- if (database.IsNullOrEmpty())
+ return Operations.ForDatabase(database ?? ResolvedDatabase);
+ }
+
+ ///
+ public IAsyncDocumentSession OpenCoreSession()
+ {
+ return OpenAsyncSession(Options.Raven.Database);
+ }
+
+ ///
+ public override IAsyncDocumentSession OpenAsyncSession(string database)
+ {
+ return base.OpenAsyncSession(database);
+ }
+
+ ///
+ public override IAsyncDocumentSession OpenAsyncSession(SessionOptions options)
+ {
+ options.Database = options.Database ?? ResolvedDatabase;
+ return base.OpenAsyncSession(options);
+ }
+
+ ///
+ public override IAsyncDocumentSession OpenAsyncSession()
+ {
+ return base.OpenAsyncSession(ResolvedDatabase);
+ }
+
+ ///
+ public override IDocumentSession OpenSession(SessionOptions options)
+ {
+ options.Database = options.Database ?? ResolvedDatabase;
+ return base.OpenSession(options);
+ }
+
+ ///
+ public override IDocumentSession OpenSession(string database)
+ {
+ return base.OpenSession(database);
+ }
+
+ ///
+ public override IDocumentSession OpenSession()
+ {
+ return base.OpenSession(ResolvedDatabase);
+ }
+
+ ///
+ public override BulkInsertOperation BulkInsert(string database = null, CancellationToken token = default)
+ {
+ return base.BulkInsert(database ?? ResolvedDatabase, token);
+ }
+
+ ///
+ public async Task PurgeAsync(string database = null, string querySuffix = null, Parameters parameters = null)
+ {
+ var collectionName = Conventions.FindCollectionName(typeof(T));
+ var operationQuery = new DeleteByQueryOperation(new IndexQuery()
{
- return Operations;
- }
- else
- {
- return Operations.ForDatabase(database);
- }
+ Query = $"from {collectionName} c {querySuffix ?? String.Empty}",
+ QueryParameters = parameters
+ }, new QueryOperationOptions { AllowStale = true });
+
+ Operation operation = await GetOperationExecutor(database).SendAsync(operationQuery);
+
+ await operation.WaitForCompletionAsync();
}
}
public interface IZeroStore : IDocumentStore
{
+ ///
+ /// The database which has been resolved from the current application
+ ///
+ string ResolvedDatabase { get; set; }
+
///
/// Get underlying raven document store
///
@@ -55,6 +117,16 @@ namespace zero.Core.Database
///
/// Get operation executor
///
- public OperationExecutor GetOperationExecutor(string database = null);
+ OperationExecutor GetOperationExecutor(string database = null);
+
+ ///
+ /// Purges a collection
+ ///
+ Task PurgeAsync(string database = null, string querySuffix = null, Parameters parameters = null);
+
+ ///
+ /// Opens a session for the core database
+ ///
+ IAsyncDocumentSession OpenCoreSession();
}
}
diff --git a/zero.Core/Entities/User/BackofficeUser.cs b/zero.Core/Entities/User/BackofficeUser.cs
index 9b63e8d4..29d6d7d1 100644
--- a/zero.Core/Entities/User/BackofficeUser.cs
+++ b/zero.Core/Entities/User/BackofficeUser.cs
@@ -81,14 +81,14 @@ namespace zero.Core.Entities
public interface IBackofficeUser : IZeroEntity, IZeroDbConventions, IIdentityUserWithRoles
{
///
- /// Application ID the user was created in
+ /// Application the user registered in
///
- public string AppId { get; set; }
+ string AppId { get; set; }
///
/// Currently selected app id for the backoffice
///
- public string CurrentAppId { get; set; }
+ string CurrentAppId { get; set; }
///
/// sudo.
diff --git a/zero.Core/Extensions/HttpContextExtensions.cs b/zero.Core/Extensions/HttpContextExtensions.cs
new file mode 100644
index 00000000..c7cd9662
--- /dev/null
+++ b/zero.Core/Extensions/HttpContextExtensions.cs
@@ -0,0 +1,16 @@
+using Microsoft.AspNetCore.Http;
+
+namespace zero.Core.Extensions
+{
+ internal static class HttpContextExtensions
+ {
+ ///
+ /// Whether the current request is a backoffice request
+ ///
+ public static bool IsBackofficeRequest(this HttpContext context, string backofficePath)
+ {
+ string path = backofficePath.EnsureStartsWith('/').TrimEnd('/');
+ return context.Request.Path.ToString().StartsWith(path);
+ }
+ }
+}
diff --git a/zero.Core/Extensions/ZeroStoreExtensions.cs b/zero.Core/Extensions/ZeroStoreExtensions.cs
deleted file mode 100644
index be7ef806..00000000
--- a/zero.Core/Extensions/ZeroStoreExtensions.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using Raven.Client;
-using Raven.Client.Documents.Operations;
-using Raven.Client.Documents.Queries;
-using Raven.Client.Documents.Session;
-using System;
-using System.Threading.Tasks;
-using zero.Core.Database;
-using zero.Core.Options;
-
-namespace zero.Core.Extensions
-{
- internal static class ZeroStoreExtensions
- {
- ///
- /// Opens a session for the core database
- ///
- public static IAsyncDocumentSession OpenCoreSession(this IZeroStore store, IZeroOptions options)
- {
- return store.OpenAsyncSession(options.Raven.Database);
- }
-
-
- ///
- /// Purges a collection
- ///
- public static async Task PurgeAsync(this IZeroStore store, string database = null, string querySuffix = null, Parameters parameters = null)
- {
- var collectionName = store.Conventions.FindCollectionName(typeof(T));
-
- var operationQuery = new DeleteByQueryOperation(new IndexQuery()
- {
- Query = $"from {collectionName} c {querySuffix ?? String.Empty}",
- QueryParameters = parameters
- }, new QueryOperationOptions
- {
- AllowStale = true
- });
-
- Operation operation = await store.GetOperationExecutor(database).SendAsync(operationQuery);
-
- await operation.WaitForCompletionAsync();
- }
- }
-}
diff --git a/zero.Core/Identity/RavenRoleStore(TRole).cs b/zero.Core/Identity/RavenRoleStore(TRole).cs
index d119ecd9..a4e4d87e 100644
--- a/zero.Core/Identity/RavenRoleStore(TRole).cs
+++ b/zero.Core/Identity/RavenRoleStore(TRole).cs
@@ -56,7 +56,7 @@ namespace zero.Core.Identity
Description = $"The affected role is is not part of this role store and can't be created."
});
}
- using (IAsyncDocumentSession session = Store.OpenCoreSession(Options))
+ using (IAsyncDocumentSession session = Store.OpenCoreSession())
{
await session.StoreAsync(role);
await session.SaveChangesAsync(cancellationToken);
@@ -78,7 +78,7 @@ namespace zero.Core.Identity
}
try
{
- using IAsyncDocumentSession session = Store.OpenCoreSession(Options);
+ using IAsyncDocumentSession session = Store.OpenCoreSession();
await session.StoreAsync(role, cancellationToken);
await session.SaveChangesAsync(cancellationToken);
}
@@ -103,7 +103,7 @@ namespace zero.Core.Identity
}
try
{
- using IAsyncDocumentSession session = Store.OpenCoreSession(Options);
+ using IAsyncDocumentSession session = Store.OpenCoreSession();
session.Delete(role);
await session.SaveChangesAsync(cancellationToken);
}
@@ -145,7 +145,7 @@ namespace zero.Core.Identity
///
public async Task FindByIdAsync(string roleId, CancellationToken cancellationToken)
{
- using IAsyncDocumentSession session = Store.OpenCoreSession(Options);
+ using IAsyncDocumentSession session = Store.OpenCoreSession();
return await ScopeQuery(session.Query()).FirstOrDefaultAsync(x => x.Id == roleId, cancellationToken);
}
@@ -153,7 +153,7 @@ namespace zero.Core.Identity
///
public async Task FindByNameAsync(string normalizedRoleName, CancellationToken cancellationToken)
{
- using IAsyncDocumentSession session = Store.OpenCoreSession(Options);
+ using IAsyncDocumentSession session = Store.OpenCoreSession();
return await ScopeQuery(session.Query()).FirstOrDefaultAsync(x => x.Name == normalizedRoleName, cancellationToken);
}
diff --git a/zero.Core/Identity/RavenUserStore(TUser).cs b/zero.Core/Identity/RavenUserStore(TUser).cs
index b3446cfd..9dbf9ca1 100644
--- a/zero.Core/Identity/RavenUserStore(TUser).cs
+++ b/zero.Core/Identity/RavenUserStore(TUser).cs
@@ -66,7 +66,7 @@ namespace zero.Core.Identity
});
}
- using IAsyncDocumentSession session = Store.OpenCoreSession(Options);
+ using IAsyncDocumentSession session = Store.OpenCoreSession();
// try to reserve the key for the new user
if (!await Store.Raven.ReserveAsync(GetReservationKey(user), user.Id))
@@ -116,7 +116,7 @@ namespace zero.Core.Identity
// Delete the user and save it. We must save it because deleting is a cluster-wide operation.
// Only if the deletion succeeds will we remove the cluster-wide compare/exchange key.
- using IAsyncDocumentSession session = Store.OpenCoreSession(Options);
+ using IAsyncDocumentSession session = Store.OpenCoreSession();
TUser source = await session.LoadAsync(user.Id, cancellationToken);
@@ -139,7 +139,7 @@ namespace zero.Core.Identity
});
}
- using (IAsyncDocumentSession session = Store.OpenCoreSession(Options))
+ using (IAsyncDocumentSession session = Store.OpenCoreSession())
{
TUser source = await session.LoadAsync(user.Id, cancellationToken);
@@ -169,7 +169,7 @@ namespace zero.Core.Identity
}
}
- using (IAsyncDocumentSession session = Store.OpenCoreSession(Options))
+ using (IAsyncDocumentSession session = Store.OpenCoreSession())
{
await session.StoreAsync(user, cancellationToken);
await session.SaveChangesAsync(cancellationToken);
@@ -182,7 +182,7 @@ namespace zero.Core.Identity
///
public async Task FindByIdAsync(string userId, CancellationToken cancellationToken)
{
- using IAsyncDocumentSession session = Store.OpenCoreSession(Options);
+ using IAsyncDocumentSession session = Store.OpenCoreSession();
return await ScopeQuery(session.Query()).FirstOrDefaultAsync(x => x.Id == userId, cancellationToken);
}
@@ -190,7 +190,7 @@ namespace zero.Core.Identity
///
public async Task FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken)
{
- using IAsyncDocumentSession session = Store.OpenCoreSession(Options);
+ using IAsyncDocumentSession session = Store.OpenCoreSession();
return await ScopeQuery(session.Query()).FirstOrDefaultAsync(x => x.Username == normalizedUserName, cancellationToken);
}
@@ -258,7 +258,7 @@ namespace zero.Core.Identity
///
public async Task FindByEmailAsync(string normalizedEmail, CancellationToken cancellationToken)
{
- using IAsyncDocumentSession session = Store.OpenCoreSession(Options);
+ using IAsyncDocumentSession session = Store.OpenCoreSession();
return await ScopeQuery(session.Query()).FirstOrDefaultAsync(x => x.Email == normalizedEmail, cancellationToken);
}
@@ -389,7 +389,7 @@ namespace zero.Core.Identity
return;
}
- using IAsyncDocumentSession session = Store.OpenCoreSession(Options);
+ using IAsyncDocumentSession session = Store.OpenCoreSession();
user.Claims.AddRange(claims.Select(claim => new UserClaim(claim)));
await session.StoreAsync(user, cancellationToken);
@@ -407,7 +407,7 @@ namespace zero.Core.Identity
///
public async Task> GetUsersForClaimAsync(Claim claim, CancellationToken cancellationToken)
{
- using IAsyncDocumentSession session = Store.OpenCoreSession(Options);
+ using IAsyncDocumentSession session = Store.OpenCoreSession();
UserClaim userClaim = new UserClaim(claim);
return await ScopeQuery(session.Query()).Where(x => x.Claims.Any(c => c.Type == userClaim.Type && c.Value == userClaim.Value)).ToListAsync();
}
@@ -422,7 +422,7 @@ namespace zero.Core.Identity
return;
}
- using IAsyncDocumentSession session = Store.OpenCoreSession(Options);
+ using IAsyncDocumentSession session = Store.OpenCoreSession();
IEnumerable userClaims = claims.Select(c => new UserClaim(c)).ToList();
@@ -443,7 +443,7 @@ namespace zero.Core.Identity
return;
}
- using IAsyncDocumentSession session = Store.OpenCoreSession(Options);
+ using IAsyncDocumentSession session = Store.OpenCoreSession();
UserClaim userClaim = new UserClaim(claim);
UserClaim newUserClaim = new UserClaim(newClaim);
diff --git a/zero.Core/Identity/RavenUserStore(TUser,TRole).cs b/zero.Core/Identity/RavenUserStore(TUser,TRole).cs
index 9069a919..5893eacd 100644
--- a/zero.Core/Identity/RavenUserStore(TUser,TRole).cs
+++ b/zero.Core/Identity/RavenUserStore(TUser,TRole).cs
@@ -42,7 +42,7 @@ namespace zero.Core.Identity
///
public async Task> GetUsersInRoleAsync(string roleName, CancellationToken cancellationToken)
{
- using IAsyncDocumentSession session = Store.OpenCoreSession(Options);
+ using IAsyncDocumentSession session = Store.OpenCoreSession();
return await ScopeQuery(session.Query()).Where(x => roleName.In(x.RoleIds)).ToListAsync(); // TODO scope
}
diff --git a/zero.Core/Routing/Routes.cs b/zero.Core/Routing/Routes.cs
index dceb0c52..38abdc69 100644
--- a/zero.Core/Routing/Routes.cs
+++ b/zero.Core/Routing/Routes.cs
@@ -12,6 +12,7 @@ using zero.Core.Api;
using zero.Core.Database;
using zero.Core.Entities;
using zero.Core.Extensions;
+using zero.Core.Options;
namespace zero.Core.Routing
{
@@ -20,15 +21,17 @@ namespace zero.Core.Routing
protected IZeroStore Store { get; set; }
protected ILogger Logger { get; set; }
protected IEnumerable Providers { get; set; }
- protected IApplicationContext Context { get; set; }
+ protected IApplicationResolver AppResolver { get; set; }
+ protected IZeroOptions Options { get; set; }
- public Routes(IZeroStore store, ILogger logger, IEnumerable providers, IApplicationContext context)
+ public Routes(IZeroStore store, ILogger logger, IEnumerable providers, IApplicationResolver appResolver, IZeroOptions options)
{
Store = store;
Logger = logger;
Providers = providers;
- Context = context;
+ AppResolver = appResolver;
+ Options = options;
}
@@ -128,7 +131,12 @@ namespace zero.Core.Routing
///
public async Task ResolveUrl(HttpContext context)
{
- IApplication app = await Context.ResolveFromRequest(context);
+ if (context.IsBackofficeRequest(Options.BackofficePath))
+ {
+ return null;
+ }
+
+ IApplication app = await AppResolver.ResolveFromRequest(context);
string path = context.Request.Path;
if (app == null)
diff --git a/zero.Core/Security/ZeroBackofficeClaimsPrincipalFactory.cs b/zero.Core/Security/ZeroBackofficeClaimsPrincipalFactory.cs
index 3874e8c0..ac4f5b23 100644
--- a/zero.Core/Security/ZeroBackofficeClaimsPrincipalFactory.cs
+++ b/zero.Core/Security/ZeroBackofficeClaimsPrincipalFactory.cs
@@ -55,16 +55,16 @@ namespace zero.Core.Security
.Select(x => x.NormalizedKey)
.ToArray();
- string currentAppId = user.CurrentAppId; // ?? user.AppId; // TODO appx fix
+ string currentAppId = user.CurrentAppId ?? user.AppId;
- //if (!user.IsSuper && !appIds.Contains(currentAppId))
- //{
- // currentAppId = user.AppId;
- //}
+ if (!user.IsSuper && !appIds.Contains(currentAppId))
+ {
+ currentAppId = user.AppId;
+ }
claims.RemoveAll(x => x.Type == Constants.Auth.Claims.AppId);
claims.Add(new Claim(Constants.Auth.Claims.AppId, currentAppId));
- //claims.Add(new Claim(Constants.Auth.Claims.DefaultAppId, user.AppId));
+ claims.Add(new Claim(Constants.Auth.Claims.DefaultAppId, user.AppId));
return claims;
}
diff --git a/zero.Core/Security/ZeroClaimsPrinicipalFactory.cs b/zero.Core/Security/ZeroClaimsPrinicipalFactory.cs
index 5d725d1e..0f265e01 100644
--- a/zero.Core/Security/ZeroClaimsPrinicipalFactory.cs
+++ b/zero.Core/Security/ZeroClaimsPrinicipalFactory.cs
@@ -137,8 +137,6 @@ namespace zero.Core.Security
claims.Add(new Claim(Constants.Auth.Claims.Email, await UserManager.GetEmailAsync(user)));
}
- //claims.Add(new Claim(Constants.Auth.Claims.AppId, user.AppId)); // TODO appx fix
-
return claims;
}
}
diff --git a/zero.Core/ZeroContext.cs b/zero.Core/ZeroContext.cs
index 3e6fafd9..fe8a7751 100644
--- a/zero.Core/ZeroContext.cs
+++ b/zero.Core/ZeroContext.cs
@@ -3,9 +3,9 @@ using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Security.Claims;
using System.Threading.Tasks;
-using zero.Core.Api;
+using zero.Core.Database;
using zero.Core.Entities;
-using zero.Core.Identity;
+using zero.Core.Extensions;
using zero.Core.Options;
using zero.Core.Routing;
@@ -14,7 +14,7 @@ namespace zero.Core
public class ZeroContext : IZeroContext
{
///
- public IApplication App { get; protected set; }
+ public IApplication Application { get; protected set; }
///
public string AppId { get; protected set; }
@@ -22,9 +22,6 @@ namespace zero.Core
///
public ClaimsPrincipal BackofficeUser { get; protected set; }
- ///
- public ClaimsIdentity BackofficeIdentity { get; protected set; }
-
///
public bool IsBackofficeRequest { get; protected set; }
@@ -38,50 +35,58 @@ namespace zero.Core
public IResolvedRoute ResolvedRoute { get; private set; }
- protected IApplicationContext AppContext { get; private set; }
+ protected IApplicationResolver AppResolver { get; private set; }
protected ILogger Logger { get; private set; }
+ protected IZeroStore Store { get; private set; }
+
private bool _resolved = false;
- public ZeroContext(IZeroOptions options, IApplicationContext appContext, ILogger logger)
+ public ZeroContext(IZeroOptions options, IApplicationResolver appResolver, ILogger logger, IZeroStore store)
{
Options = options;
- AppContext = appContext;
+ AppResolver = appResolver;
Logger = logger;
+ Store = store;
}
///
public async virtual Task Resolve(HttpContext context)
{
- if (_resolved || context?.Request is null)
+ if (_resolved)
{
return;
}
+ if (context?.Request is null)
+ {
+ Store.ResolvedDatabase = null;
+ return;
+ }
+
_resolved = true;
+ // check if the current request is a backoffice request
+ IsBackofficeRequest = context.IsBackofficeRequest(Options.BackofficePath);
+
+ // get the currently logged-in backoffice user
+ BackofficeUser = new ClaimsPrincipal();
AuthenticateResult authResult = await context.AuthenticateAsync(Constants.Auth.BackofficeScheme);
if (authResult?.Principal is not null)
{
BackofficeUser = authResult.Principal;
- if (BackofficeUserIdentity.TryGet(authResult.Principal, out BackofficeUserIdentity identity))
- {
- BackofficeIdentity = identity;
- }
- }
- else
- {
- BackofficeUser = new ClaimsPrincipal();
}
- App = await AppContext.Resolve(context, BackofficeUser);
- AppId = App.Id;
+ // resolve current application
+ Application = await AppResolver.Resolve(context, BackofficeUser);
+ AppId = Application.Id;
- IsBackofficeRequest = AppContext.IsBackofficeRequest(context);
+ // set default database for document store
+ Store.ResolvedDatabase = Application.Database;
if (IsBackofficeRequest is false && context.Request.RouteValues.TryGetValue("zero.route", out object route))
{
@@ -97,7 +102,7 @@ namespace zero.Core
///
/// Currently loaded application
///
- IApplication App { get; }
+ IApplication Application { get; }
///
/// Current loaded application Id
@@ -109,11 +114,6 @@ namespace zero.Core
///
ClaimsPrincipal BackofficeUser { get; }
- ///
- /// Resolved backoffice user identity
- ///
- ClaimsIdentity BackofficeIdentity { get; }
-
///
/// Whether the current request is a backoffice request or not
///
diff --git a/zero.Web/Controllers/AuthenticationController.cs b/zero.Web/Controllers/AuthenticationController.cs
index 7a4255dd..79e5cd12 100644
--- a/zero.Web/Controllers/AuthenticationController.cs
+++ b/zero.Web/Controllers/AuthenticationController.cs
@@ -11,13 +11,11 @@ namespace zero.Web.Controllers
public class AuthenticationController : BackofficeController
{
IAuthenticationApi Api;
- IApplicationContext AppContext;
- public AuthenticationController(IAuthenticationApi api, IApplicationContext appContext)
+ public AuthenticationController(IAuthenticationApi api)
{
Api = api;
- AppContext = appContext;
}
@@ -43,7 +41,8 @@ namespace zero.Web.Controllers
public async Task SwitchApp(string appId)
{
BackofficeUser user = await Api.GetUser();
- return EntityResult.Maybe(await AppContext.TrySwitchForUser(user, appId));
+ return EntityResult.Fail();
+ //return EntityResult.Maybe(await AppContext.TrySwitchForUser(user, appId)); // TODO appx
}
}
}
diff --git a/zero.Web/Controllers/ZeroController.cs b/zero.Web/Controllers/ZeroController.cs
index cbe43c0a..1800e1a6 100644
--- a/zero.Web/Controllers/ZeroController.cs
+++ b/zero.Web/Controllers/ZeroController.cs
@@ -5,6 +5,7 @@ using zero.Core.Api;
using zero.Core.Entities;
using zero.Core.Routing;
using Microsoft.Extensions.DependencyInjection;
+using zero.Core;
namespace zero.Web.Controllers
{
@@ -23,7 +24,7 @@ namespace zero.Web.Controllers
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
- Application = filterContext.HttpContext.RequestServices.GetService()?.App;
+ Application = filterContext.HttpContext.RequestServices.GetService()?.Application;
if (filterContext.RouteData.Values.TryGetValue("zero.route", out object route))
{
diff --git a/zero.Web/Routing/ZeroRoutesTransformer.cs b/zero.Web/Routing/ZeroRoutesTransformer.cs
index b857997b..65b2ed17 100644
--- a/zero.Web/Routing/ZeroRoutesTransformer.cs
+++ b/zero.Web/Routing/ZeroRoutesTransformer.cs
@@ -2,30 +2,22 @@
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Routing;
using System.Threading.Tasks;
-using zero.Core.Api;
using zero.Core.Routing;
namespace zero.Web.Routing
{
public class ZeroRoutesTransformer : DynamicRouteValueTransformer
{
- Core.Routing.IRoutes Routes;
- IApplicationContext Context;
+ IRoutes Routes;
- public ZeroRoutesTransformer(Core.Routing.IRoutes routes, IApplicationContext context)
+ public ZeroRoutesTransformer(IRoutes routes)
{
Routes = routes;
- Context = context;
}
public override async ValueTask TransformAsync(HttpContext httpContext, RouteValueDictionary values)
{
- if (Context.IsBackofficeRequest(httpContext))
- {
- return null;
- }
-
IResolvedRoute route = await Routes.ResolveUrl(httpContext);
if (route == null)
diff --git a/zero.Web/ZeroBuilder.cs b/zero.Web/ZeroBuilder.cs
index 4b0b2a04..aee62e04 100644
--- a/zero.Web/ZeroBuilder.cs
+++ b/zero.Web/ZeroBuilder.cs
@@ -104,7 +104,7 @@ namespace zero.Web
// add default services
Services.AddHttpContextAccessor();
- Services.AddScoped();
+ Services.AddScoped();
Services.AddScoped();
Services.AddScoped();
diff --git a/zero.Web/ZeroVue.cs b/zero.Web/ZeroVue.cs
index 3a17fe96..9bccb9c7 100644
--- a/zero.Web/ZeroVue.cs
+++ b/zero.Web/ZeroVue.cs
@@ -29,17 +29,17 @@ namespace zero.Web
protected IEnumerable Plugins { get; private set; }
- protected IApplicationContext AppContext { get; private set; }
+ protected IZeroContext Context { get; private set; }
- public ZeroVue(IZeroOptions options, IWebHostEnvironment env, IApplicationsApi applicationsApi, IAuthenticationApi authenticationApi, IEnumerable plugins, IApplicationContext appContext)
+ public ZeroVue(IZeroOptions options, IWebHostEnvironment env, IApplicationsApi applicationsApi, IAuthenticationApi authenticationApi, IEnumerable plugins, IZeroContext context)
{
Environment = env;
Options = options;
ApplicationsApi = applicationsApi;
AuthenticationApi = authenticationApi;
Plugins = plugins;
- AppContext = appContext;
+ Context = context;
//zero.path = "@Model.BackofficePath.EnsureEndsWith('/')";
//zero.translations = @Html.Raw(text);
}
@@ -61,7 +61,7 @@ namespace zero.Web
config.Applications = await CreateApplications();
config.Alias = CreateAliases();
config.SettingsAreas = CreateSettingsAreas();
- config.AppId = AppContext.AppId;
+ config.AppId = Context.AppId;
//config.SharedAppId = Constants.Database.SharedAppId; // TODO appx
BackofficeUser user = await AuthenticationApi.GetUser();