case 4725 - sessions end on password reset and login disabled, exact login route, default SuperUser limited when licensed
A password set by someone else (reset code, administrator) or a disabled login replaces the user's session token and download key; changing one's own password keeps the session. PasswordResetCodeExpire is cleared (was DlKeyExpire). The token middleware exempts only the exact login and notify/hello routes and refuses inactive users and users who may not log in. With a purchased licence, notify/hello no longer offers the default SuperUser login and a SuperUser with the default password may only change it (SuperUserDefaultPasswordRoutes). F7, F8 and F9 fixed. Manual and changelog updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -85,12 +85,23 @@ namespace AyaNova.Api.ControllerHelpers
|
||||
return true;//not routed to anything: the request ends in a 404 regardless
|
||||
if (endpoint.Metadata.GetMetadata<IAllowAnonymous>() != null)
|
||||
return true;
|
||||
if (endpoint is not RouteEndpoint routeEndpoint)
|
||||
return false;
|
||||
var key = RouteKey(context);
|
||||
return key != null && Allowed.Contains(key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// "METHOD route template" of the endpoint this request was routed to, API prefix removed
|
||||
/// (e.g. "GET user-option/{id}"); null when not routed to a route endpoint.
|
||||
/// Also used by the token middleware (case 4725)
|
||||
/// </summary>
|
||||
internal static string RouteKey(HttpContext context)
|
||||
{
|
||||
if (context.GetEndpoint() is not RouteEndpoint routeEndpoint)
|
||||
return null;
|
||||
var template = routeEndpoint.RoutePattern.RawText ?? string.Empty;
|
||||
if (template.StartsWith(API_PREFIX))
|
||||
template = template.Substring(API_PREFIX.Length);
|
||||
return Allowed.Contains($"{context.Request.Method.ToUpperInvariant()} {template}");
|
||||
return $"{context.Request.Method.ToUpperInvariant()} {template}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace AyaNova.Api.ControllerHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// case 4725: with a purchased licence, a SuperUser still using the default password may only change it:
|
||||
/// these are the routes the change password page and the app shell need. Everything else answers 403
|
||||
/// until the password is changed.
|
||||
/// See devdocs/modernization/SECURITY-REVIEW.md, F9.
|
||||
/// </summary>
|
||||
internal static class SuperUserDefaultPasswordRoutes
|
||||
{
|
||||
//"METHOD route template" with the API prefix removed, exactly as in the controllers' attributes
|
||||
private static readonly HashSet<string> Allowed = new HashSet<string>
|
||||
{
|
||||
"POST auth/change-password",
|
||||
"GET user-option/{id}",
|
||||
"GET global-biz-setting/client",
|
||||
"GET enum-list/list/{enumkey}",
|
||||
"GET form-custom/{formkey}",
|
||||
"GET translation/list",
|
||||
"POST translation/subset",
|
||||
"GET server-info",
|
||||
"GET notify/new-count",
|
||||
"GET notify/app-notifications",
|
||||
};
|
||||
|
||||
internal static bool IsAllowed(HttpContext context)
|
||||
{
|
||||
var endpoint = context.GetEndpoint();
|
||||
if (endpoint == null)
|
||||
return true;//not routed to anything: the request ends in a 404 regardless
|
||||
if (endpoint.Metadata.GetMetadata<IAllowAnonymous>() != null)
|
||||
return true;
|
||||
var key = CustomerContactRoutes.RouteKey(context);
|
||||
return key != null && Allowed.Contains(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user