diff --git a/CHANGELOG.md b/CHANGELOG.md index 573a63b9..2b2244b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ Represents the **NuGet** versions. +## v3.27.1 +- *Fixed:* Updated `Microsoft.Extensions.Caching.Memory` package depenedency to latest (including related); resolve [Microsoft Security Advisory CVE-2024-43483](https://github.com/advisories/GHSA-qj66-m88j-hmgj). +- *Fixed:* Fixed the `ExecutionContext.UserIsAuthorized` to have base implementation similar to `UserIsInRole`. +- *Fixed:* Rationalize the `UtcNow` usage to be consistent, where applicable `ExecutionContext.SystemTime.UtcNow` is leveraged. + ## v3.27.0 - *Fixed:* The `ValueContentResult.TryCreateValueContentResult` would return `NotModified` where the request `ETag` was `null`; this has been corrected to return `OK` with the resulting `value`. - *Fixed:* The `ValueContentResult.TryCreateValueContentResult` now returns `ExtendedStatusCodeResult` versus `StatusCodeResult` as this offers additional capabilities where required. diff --git a/Common.targets b/Common.targets index ddfd497f..5be1cf1e 100644 --- a/Common.targets +++ b/Common.targets @@ -1,6 +1,6 @@  - 3.27.0 + 3.27.1 preview Avanade Avanade diff --git a/src/CoreEx/CoreEx.csproj b/src/CoreEx/CoreEx.csproj index f026c4a2..c7d2368e 100644 --- a/src/CoreEx/CoreEx.csproj +++ b/src/CoreEx/CoreEx.csproj @@ -52,7 +52,7 @@ - + diff --git a/src/CoreEx/Entities/ChangeLog.cs b/src/CoreEx/Entities/ChangeLog.cs index 5b24f3d8..b9376acd 100644 --- a/src/CoreEx/Entities/ChangeLog.cs +++ b/src/CoreEx/Entities/ChangeLog.cs @@ -89,6 +89,6 @@ public static IChangeLogAudit PrepareUpdated(IChangeLogAudit changeLog, Executio /// /// Gets the timestamp. /// - private static DateTime GetTimestamp(ExecutionContext? ec) => ec != null ? ec.Timestamp : (ExecutionContext.HasCurrent ? ExecutionContext.Current.Timestamp : DateTime.UtcNow); + private static DateTime GetTimestamp(ExecutionContext? ec) => ec != null ? ec.Timestamp : ExecutionContext.SystemTime.UtcNow; } } \ No newline at end of file diff --git a/src/CoreEx/Events/EventDataFormatter.cs b/src/CoreEx/Events/EventDataFormatter.cs index 8ef1cb7c..9cbc6e5b 100644 --- a/src/CoreEx/Events/EventDataFormatter.cs +++ b/src/CoreEx/Events/EventDataFormatter.cs @@ -152,7 +152,7 @@ public virtual void Format(EventData @event) var value = @event.Value; @event.Id ??= Guid.NewGuid().ToString(); - @event.Timestamp ??= DateTimeOffset.UtcNow; + @event.Timestamp ??= new DateTimeOffset(ExecutionContext.SystemTime.UtcNow); if (PropertySelection.HasFlag(EventDataProperty.Key)) { diff --git a/src/CoreEx/ExecutionContext.cs b/src/CoreEx/ExecutionContext.cs index ed993c7e..6659e02e 100644 --- a/src/CoreEx/ExecutionContext.cs +++ b/src/CoreEx/ExecutionContext.cs @@ -27,6 +27,7 @@ public class ExecutionContext : ITenantId, IDisposable private Lazy> _properties = new(true); private IReferenceDataContext? _referenceDataContext; private HashSet? _roles; + private HashSet? _permissions; private bool _disposed; private readonly object _lock = new(); @@ -170,7 +171,7 @@ public static object GetRequiredService(Type type) /// Gets or sets the timestamp for the lifetime; i.e (to enable consistent execution-related timestamping). /// /// Defaults the value from , where this has not been registered it will default to . The value will also be passed through . - public DateTime Timestamp { get => _timestamp ??= Cleaner.Clean(GetService()?.UtcNow ?? DateTime.UtcNow); set => _timestamp = Cleaner.Clean(value); } + public DateTime Timestamp { get => _timestamp ??= SystemTime.UtcNow; set => _timestamp = Cleaner.Clean(value); } /// /// Gets the to be passed back to the originating consumer. @@ -249,18 +250,28 @@ public void Dispose() /// Sets (replaces) the roles the current user is in (the roles should be unique). /// /// The of roles the user is in. - public virtual void SetRoles(IEnumerable roles) => _roles = new HashSet(roles.Distinct()); + public virtual void SetRoles(IEnumerable roles) => _roles = new HashSet(roles); /// - /// Checks whether the user has the required . + /// Gets the list of permissions for the (as previously set). + /// + public IEnumerable GetPermissions() => _permissions == null ? Array.Empty() : _permissions; + + /// + /// Sets (replaces) the permissions the current user is in (the roles should be unique). + /// + /// The of roles the user is in. + public virtual void SetPermissions(IEnumerable roles) => _permissions = new HashSet(roles); + + /// + /// Checks whether the user has the required (see and ). /// /// The permission to validate. /// The corresponding . - /// This method is intended to be overridden; this implementation always returns . public virtual Result UserIsAuthorized(string permission) { permission.ThrowIfNullOrEmpty(nameof(permission)); - return Result.AuthorizationError(); + return _permissions is not null && _permissions.Contains(permission) ? Result.Success : Result.AuthorizationError(); } /// @@ -269,12 +280,13 @@ public virtual Result UserIsAuthorized(string permission) /// The entity name. /// The action name. /// The corresponding . - /// This method is intended to be overridden; this implementation always returns . + /// This default implementation formats as {entity}.{action} and invokes . + /// An example is Customer and Create formatted as Customer.Create. public virtual Result UserIsAuthorized(string entity, string action) { entity.ThrowIfNullOrEmpty(nameof(entity)); action.ThrowIfNullOrEmpty(nameof(action)); - return Result.AuthorizationError(); + return UserIsAuthorized($"{entity}.{action}"); } /// @@ -284,8 +296,8 @@ public virtual Result UserIsAuthorized(string entity, string action) /// The corresponding . public virtual Result UserIsInRole(string role) { - var isInRole = (_roles != null) && _roles.TryGetValue(role, out _); - return isInRole ? Result.Success : Result.AuthorizationError(); + role.ThrowIfNullOrEmpty(nameof(role)); + return _roles is not null && _roles.Contains(role) ? Result.Success : Result.AuthorizationError(); } #endregion diff --git a/src/CoreEx/RefData/Extended/ReferenceDataBaseEx.cs b/src/CoreEx/RefData/Extended/ReferenceDataBaseEx.cs index 3831aaa1..123f6124 100644 --- a/src/CoreEx/RefData/Extended/ReferenceDataBaseEx.cs +++ b/src/CoreEx/RefData/Extended/ReferenceDataBaseEx.cs @@ -71,7 +71,7 @@ public virtual bool IsActive if (StartDate != null || EndDate != null) { - var date = ExecutionContext.HasCurrent ? ExecutionContext.Current.ReferenceDataContext[GetType()] : Cleaner.Clean(DateTime.UtcNow, DateTimeTransform.DateOnly); + var date = ExecutionContext.HasCurrent ? ExecutionContext.Current.ReferenceDataContext[GetType()] : Cleaner.Clean(ExecutionContext.SystemTime.UtcNow, DateTimeTransform.DateOnly); if (StartDate != null && date < StartDate) return false;