yavsc/src/Yavsc.Org/Views/Client/EditClaims.cshtml

68 lines
2 KiB
Text
Raw Normal View History

yavsc-org: OAuth2 client admin editor overhaul — per-collection pages + missing fields The OAuth2 client editor at /Client/Edit/{id} previously exposed 8 fields out of ~30 scalars and 10 collections on the IdentityServer8 Client entity. Editing the collections (RedirectUris, Scopes, Grant Types, Cors Origins, IdP Restrictions, Claims, Properties, Secrets) was either impossible or jammed into a single broken text input that bound against an IEnumerable<string> property. Restructure into per-collection subpages, each with its own list/add/remove flow: - RedirectUris /Client/EditRedirectUris/{id} - PostLogoutRedirectUris /Client/EditPostLogoutRedirectUris/{id} - Scopes /Client/EditScopes/{id} - GrantTypes /Client/EditGrantTypes/{id} - CorsOrigins /Client/EditCorsOrigins/{id} - IdPRestrictions /Client/EditIdPRestrictions/{id} - Claims /Client/EditClaims/{id} - Properties /Client/EditProperties/{id} - Secrets /Client/EditSecrets/{id} Implementation: - New partial class ClientController.Collections.cs with one GET/Add/Remove trio per collection. Add/Remove dispatch through generic helpers that handle the EF row + ClientId check. - Shared _EditableStringList.cshtml partial consumed by the six single-string-field collection pages. Uses reflection to pull the value field and the row Id off the entity — avoids six nearly-identical table+form copies. - Claims / Properties / Secrets each have their own view because they carry 2+ fields (Type+Value, Key+Value, or Type+Value+Description+Expiration). - Main Edit.cshtml enriched: ClientId/Id hidden, all scalar fields split into fieldsets (Core, Security, Logout, Tokens, Device flow, Tokens extra), nav links to the 9 subpages with current row counts as badges. - ClientController.Edit(int) GET now loads the client with all navigations via LoadClientAsync so the Edit.cshtml nav badges render real counts. Field-correctness notes (verified by disassembling HigginsSoft IdentityServer8.EntityFramework.Entities.Client 8.0.5-preview-net9): - The property is PairWiseSubjectSalt, not PairwiseSubjectSalt (capital W on 'Wise'). - CibaLifetime and PollingInterval do NOT exist on Client in this IdentityServer8 version — those properties were a guess. The Device flow fieldset contains DeviceCodeLifetime + UserCodeType instead. - AllowedIdentityTokenSigningAlgorithms and AllowAccessTokensViaBrowser were missing from the original form and are now exposed. - ConsentLifetime and UserSsoLifetime are int? (nullable); the form binds them as plain int fields which accept empty strings. Security: - All new actions stay under [Authorize('AdministratorOnly')]. - Each Add/Remove takes an explicit id (Client.Id) and the row's ClientId is checked on the server before any delete; a rowId from another client returns NotFound. Docs: - doc/dev-tracking/client-editor-overhaul.md — inventory, status, follow-up ideas (confirmation prompts, validation, MVC tests).
2026-06-21 16:53:34 +01:00
@model IEnumerable<IdentityServer8.EntityFramework.Entities.ClientClaim>
2026-07-04 20:03:56 +01:00
@{
ViewBag.Title = Localizer["Client"];
}
yavsc-org: OAuth2 client admin editor overhaul — per-collection pages + missing fields The OAuth2 client editor at /Client/Edit/{id} previously exposed 8 fields out of ~30 scalars and 10 collections on the IdentityServer8 Client entity. Editing the collections (RedirectUris, Scopes, Grant Types, Cors Origins, IdP Restrictions, Claims, Properties, Secrets) was either impossible or jammed into a single broken text input that bound against an IEnumerable<string> property. Restructure into per-collection subpages, each with its own list/add/remove flow: - RedirectUris /Client/EditRedirectUris/{id} - PostLogoutRedirectUris /Client/EditPostLogoutRedirectUris/{id} - Scopes /Client/EditScopes/{id} - GrantTypes /Client/EditGrantTypes/{id} - CorsOrigins /Client/EditCorsOrigins/{id} - IdPRestrictions /Client/EditIdPRestrictions/{id} - Claims /Client/EditClaims/{id} - Properties /Client/EditProperties/{id} - Secrets /Client/EditSecrets/{id} Implementation: - New partial class ClientController.Collections.cs with one GET/Add/Remove trio per collection. Add/Remove dispatch through generic helpers that handle the EF row + ClientId check. - Shared _EditableStringList.cshtml partial consumed by the six single-string-field collection pages. Uses reflection to pull the value field and the row Id off the entity — avoids six nearly-identical table+form copies. - Claims / Properties / Secrets each have their own view because they carry 2+ fields (Type+Value, Key+Value, or Type+Value+Description+Expiration). - Main Edit.cshtml enriched: ClientId/Id hidden, all scalar fields split into fieldsets (Core, Security, Logout, Tokens, Device flow, Tokens extra), nav links to the 9 subpages with current row counts as badges. - ClientController.Edit(int) GET now loads the client with all navigations via LoadClientAsync so the Edit.cshtml nav badges render real counts. Field-correctness notes (verified by disassembling HigginsSoft IdentityServer8.EntityFramework.Entities.Client 8.0.5-preview-net9): - The property is PairWiseSubjectSalt, not PairwiseSubjectSalt (capital W on 'Wise'). - CibaLifetime and PollingInterval do NOT exist on Client in this IdentityServer8 version — those properties were a guess. The Device flow fieldset contains DeviceCodeLifetime + UserCodeType instead. - AllowedIdentityTokenSigningAlgorithms and AllowAccessTokensViaBrowser were missing from the original form and are now exposed. - ConsentLifetime and UserSsoLifetime are int? (nullable); the form binds them as plain int fields which accept empty strings. Security: - All new actions stay under [Authorize('AdministratorOnly')]. - Each Add/Remove takes an explicit id (Client.Id) and the row's ClientId is checked on the server before any delete; a rowId from another client returns NotFound. Docs: - doc/dev-tracking/client-editor-overhaul.md — inventory, status, follow-up ideas (confirmation prompts, validation, MVC tests).
2026-06-21 16:53:34 +01:00
@{
ViewData["Title"] = "Edit Client Claims";
var clientId = Model.FirstOrDefault()?.ClientId ?? 0;
}
<h2>Client Claims</h2>
<p class="text-muted">
Claims issued by IdentityServer on this client's behalf. Use sparingly:
these claims are emitted on every token, regardless of the user's
identity. For user-derived claims, prefer the API resource scope.
</p>
@if (TempData["Error"] is string err)
{
<div class="alert alert-danger">@err</div>
}
<table class="table">
<thead>
<tr><th>Type</th><th>Value</th><th></th></tr>
</thead>
<tbody>
@if (!Model.Any())
{
<tr><td colspan="3" class="text-muted">—</td></tr>
}
else
{
foreach (var c in Model)
{
<tr>
<td>@c.Type</td>
<td>@c.Value</td>
<td>
<form asp-action="RemoveClaim" method="post" class="form-inline">
@Html.AntiForgeryToken()
<input type="hidden" name="id" value="@clientId" />
<input type="hidden" name="rowId" value="@c.Id" />
<button type="submit" class="btn btn-link btn-sm text-danger">Remove</button>
</form>
</td>
</tr>
}
}
</tbody>
</table>
<form asp-action="AddClaim" method="post" class="form-inline">
@Html.AntiForgeryToken()
<input type="hidden" name="id" value="@clientId" />
<div class="form-group mr-2">
<input type="text" name="type" class="form-control" placeholder="role" />
</div>
<div class="form-group mr-2">
<input type="text" name="value" class="form-control" placeholder="admin" />
</div>
<button type="submit" class="btn btn-primary">Add</button>
</form>
<p>
<a asp-action="Edit" asp-route-id="@clientId">Back to client</a>
2026-07-04 20:03:56 +01:00
</p>