Skip to content

Udap.Client minor updates and continued work on the Sigil CA tool.#41

Merged
JoeShook merged 49 commits into
udap-tools:mainfrom
JoeShook:develop
May 22, 2026
Merged

Udap.Client minor updates and continued work on the Sigil CA tool.#41
JoeShook merged 49 commits into
udap-tools:mainfrom
JoeShook:develop

Conversation

@JoeShook

Copy link
Copy Markdown
Collaborator

This pull request primarily updates package dependencies to their latest versions, reorganizes CA-related example projects in the Docker build, and refactors the Udap.Client namespace for improved clarity and consistency. It also enhances the IUdapClient interface with better documentation and parameter naming, and makes minor corrections to the README.

Dependency updates:

  • Upgraded multiple NuGet package versions in Directory.Packages.props, including Duende.IdentityServer, Hl7.Fhir, OpenTelemetry, Spectre.Console, Microsoft.*, and others. This ensures the project uses the latest features and security patches.

Project and Dockerfile reorganization:

  • Replaced references to the old Udap.CA project in the Docker build with the new modular CA/Sigil projects (Sigil, Sigil.Common, Sigil.UI, etc.), and updated test project paths accordingly. [1] [2]

Namespace and code refactoring (Udap.Client):

  • Consolidated and standardized namespaces in the Udap.Client library, moving types from Udap.Client.Client to Udap.Client or Udap.Client.Extensions for clarity. Removed an unused extensions file. [1] [2] [3] [4] [5] [6]
  • Improved parameter naming and documentation in IUdapClient, including renaming token to cancellationToken and clarifying property names and XML docs. [1] [2] [3] [4]

Documentation updates:

  • Updated the README to reflect the current implementation status of TEFCA extensions and to clarify package descriptions. [1] [2]

JoeShook and others added 30 commits May 4, 2026 14:43
Widens both dialogs from 600px to 900px default and adds a right-edge
drag handle so users can resize them horizontally as needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduces CertificateExportService in Sigil.Common with two methods:
- ExportPrivateKeyPemAsync: exports PKCS#8 PEM (blocks HSM/KMS levels)
- ExportCertificateDerBase64Async: exports base64 DER for x5c JWT headers

Adds 11 unit tests covering RSA/ECDSA export, round-trip verification,
issued certs, security level enforcement, and error cases.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests for DashboardService, TemplateService, CommunityService,
CertificateManagementService, and CertificateImportService using
EF Core InMemory provider. Extracted shared TestDbContextFactory
from CertificateExportServiceTests. Total: 82 tests (up from 37).
Removes the TEFCASMART constant, TEFCASMARTAuthorizationExtension class,
and all documentation references. No model or validation was ever built
for this extension.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dropped tefca_smart Authorization Extension Object support.
Introduces IssuanceValidator in Sigil.Common/Validators — injected into
CertificateIssuanceService — to detect when a template change would alter
CDP or AIA URLs compared to the original certificate being renewed. Warning
banner displays in the issuance dialog. Includes 12 validator tests and
FEATURES.md updates for recent additions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Detects when a CA has been superseded by a newer key (same Subject DN,
later NotBefore). End-entity certs under superseded CAs show a blue
"New CA" badge. Users can drag these certs onto the new CA node to
open the renewal dialog pre-configured with the target CA as issuer.

- IssuanceValidator.FindSupersededCaIds — groups CAs by Subject DN
- CertificateStatus.Stale enum value with blue badge
- JS drag-drop via event delegation on tree items
- 7 new validator tests for supersession detection

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix two bugs in JwtExtensions: GetHeaderValue throws when x5c missing
  (switched to TryGetHeaderValue), AsArray() throws on non-array nodes
  (switched to 'as JsonArray'). Remove dead X509ChainPolicy.Clone()
  extension shadowed by .NET native method.

- Add 60+ new unit tests across 7 new test files covering Udap.Util
  extensions (Collection, String, Jwt, X509), Udap.Common extensions
  (StringExtensions), IssuedCertificateStore, TrustAnchorFileStore,
  and ChainElementInfo.HasProblems.

- Eliminate all SYSLIB0057 warnings solution-wide using #if NET9_0_OR_GREATER
  conditional compilation for X509CertificateLoader replacements across
  source libraries, test projects, examples, and migrations.

- Fix CS0618 (obsolete BouncyCastle types), CS8604/CS8602 (nullable),
  and CS0168 (unused variable) warnings in source and test projects.

- Add coverage.runsettings to exclude IdentityServerDb.Migrations from
  code coverage.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
….json flexible SDK

Bump Duende.IdentityServer and related packages from 7.4.6 to 7.4.7 across
central props, SDK projects, and example projects. Update DPoP API in
Udap.Proxy.Server to match breaking changes in Duende.AspNetCore.Authentication
.JwtBearer 1.0.2. Update Aspire, MudBlazor, and Meziantou.Extensions.Logging
packages. Relax global.json to accept any 10.0.x SDK.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ReadFromJsonAsync<DiscoveryDocumentResponse> never set HttpStatusCode or
Json, making the OK-path validation branch unreachable dead code. Switch
to ProtocolResponse.FromHttpResponseAsync<ProtocolResponse> which properly
populates HttpStatusCode, HttpResponse, and Json from the HTTP response.

Also remove the unreachable null check (FromHttpResponseAsync never
returns null), make validator methods virtual for testability, and add
comprehensive tests covering both OK and error branches of SendAsync.
"/fhir/r4" is treated as an absolute file URI on Linux, causing
Uri.TryCreate with UriKind.Absolute to succeed. Use "fhir/r4" (no
leading slash) which is unambiguously relative on all platforms.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Unused internal class with no methods or references.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…apping

Columns now have proportional widths with the Base URLs column getting
the most space. URLs display on separate lines instead of truncated
semicolons. Columns are user-resizable via ResizableColumns.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
JoeShook and others added 17 commits May 15, 2026 16:11
BREAKING CHANGES (pre-1.0):
Following: https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/

- Flatten namespaces: Udap.Client.Client → Udap.Client,
  Udap.Client.Client.Extensions → Udap.Client.Extensions,
  Udap.Client.Client.Messages → Udap.Client.Messages
- Rename UdapServerMetaData → UdapServerMetadata (compound word)
- Rename CancellationToken parameter from 'token' to 'cancellationToken'
- Delete unused Udap.Client.Constants class (UDAP_CLIENT_OPTIONS had
  zero consumers and caused ambiguity with Udap.Common.Constants)
- Mark 19-parameter Authorize() overload [Obsolete]

New features:

- Add AuthorizeRequest parameter object and Authorize(AuthorizeRequest)
  overload per member design guidelines
- Add ServiceCollectionExtensions.AddUdapClient() convenience method
  for DI registration (replaces manual 3-line setup)
- Add Microsoft.Extensions.Http package reference for IHttpClientBuilder

Cleanup:

- Remove empty Authentication/ folder from csproj
- Remove redundant 'public' modifier on GeneratePkce() interface member
- Add XML documentation to all undocumented public members
- Convert example projects from NuGet to project references

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Document SSRAA and TEFCA profile requirements

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Community entity now has CrlValidityDays (default 7). CrlGenerationService
looks up the community setting when no explicit validity is passed, so all
callers automatically respect it. Publish CRL button opens a dialog with
the community default pre-filled, allowing override for one-off cases.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PKI CLI now updates CRLs for both SureFhirLabs and TEFCA communities
via configurable config section names. Dockerfile.gcp updated to
reference the renamed Sigil projects under examples/CA/.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Persists the end-entity X.509 certificate (public key only) as an
X509CertificateBase64 client secret during dynamic client registration.
This is purely for admin visibility — expiration monitoring, revocation
checking — and does not affect authentication or PKI chain validation.

The stored certificate is updated during:
- Re-registration (PUT to /connect/register) via UpsertClient
- Certificate rollover during token requests via RolloverClientSecrets

Added UDAP_X509_CERTIFICATE constant to UdapServerConstants. Updated
both EF and InMemory store implementations. Added UpsertClient query
include for ClientSecrets. Documented DCR storage model and rollover
behavior in Udap.Server README.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Duende 7.4.7 corrected the error response for an invalid PKCE
code_verifier from "invalid_client" to "invalid_grant", aligning
with RFC 7636 Section 4.6. Update test expectations to match.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Key Storage dropdown was hidden because it checked the default
ISigningProvider instead of what providers are available. Now uses
a config-driven AvailableProviders list in the Signing section so
users can select between Local and Vault Transit per-issuance.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Certificate Explorer: collapsible tree filter (text + status dropdown)
  with single clear button; immediate updates with 150ms debounce
- System status chip in header: cached health for DB, Vault, GCP KMS;
  click expands a dropdown showing provider configuration and reachability
- Dashboard: Quick Actions card (Create Community, Import, New Root CA,
  New Template) with ?action=new deep-links to auto-open Add dialogs
- Rename Stale badge "New CA" -> "Superseded CA" (clearer wording)
- Rename nav label "Certificates" -> "X509 Templates"

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Vault persistence
- AddVaultDev gains persistent: bool param. When true: server mode with
  file storage in a Docker volume, auto-init + auto-unseal, root-token
  alias of the random root token, KV v2 mount at secret/ (dev parity)
- New VaultInitState + VaultServerConfigurator; init keys persisted to
  %LOCALAPPDATA%/Sigil/vault-{name}-init.json
- Transit re-configured each time Vault becomes healthy (handles dashboard
  restarts too)

Missing-key visual indicator
- VaultTransitSigningProvider.KeyExistsAsync probes /v1/transit/keys/{name}
- CertificateChainNodeViewModel gets KeyIdentifier + RemoteKeyMissing
- Tree load triggers a background parallel check; red warning icon shown
  on CAs whose Vault Transit key is missing (new VaultTransitBadge component)

Phase 2 dialogs
- Issuance dialog refactored into FluentAccordion sections (Identity,
  Extensions, Key & Storage) with live summary text in each header
- IssuancePasswordCache (scoped per Blazor circuit) + "Remember password
  for this session" checkbox per issuing CA
- Shared ImpactConfirmDialog component with severity-colored impact list
- Impact-preview methods on Cert/Community/Template services; wired into
  delete/revoke flows so users see blast radius before confirming
- Subject DN now shows "(required)" label + helper text when empty

Bug fixes
- Surface Vault sign 400 error body instead of silent failure
- Friendly error when issuer's Vault key is missing ("re-create the CA")
- IssueCertificateAsync validates AIA/SAN URIs are absolute up front
- isIssuing now resets if pre-issuance throws (no more stuck Generating...)
- URL validation only checks well-formed absolute http(s); no reachability
  probe (eliminates 5s timeout for non-resolvable runtime URLs)
- noBaseUrlsWarning detects unsubstituted {BaseUrl} in any final URL and
  surfaces a top-of-dialog message bar with "Edit Community (new tab)"
- Communities supports ?edit={id} query param to auto-open the Edit dialog

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Right-click context menus on the certificate tree (via JS interop because
@oncontextmenu doesn't fire reliably through fluent-tree-item's shadow DOM)
mirror toolbar actions for CA / EE / CRL nodes. CRL freshness indicator on
CA rows surfaces expired/expiring/missing CRLs without expanding. Adds
CRLs-only filter, fixes tree header scrolling out of view, and tames the
issuance/templates dialog resize: handle now visible in light mode, resize
JS honors each dialog's declared min-width, content stays clipped to the
dialog frame.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The AddCrlValidityDaysToCommunity migration backfilled existing rows with
0, but the ?? 7 fallback only caught null — so TimeSpan.FromDays(0) made
regenerated CRLs expire instantly. Now treats 0/negative as the 7-day
default in both GenerateCrlAsync and the Publish CRL dialog.

Also adds Download .crl + Re-publish to CRL right-click (Re-publish only
on the latest non-archived CRL via new IsLatestCrl flag), and reorders
OnTreeContextMenuAsync so the menu opens after SelectNode completes —
fixes CA-only items (Regen CRL, Publish AIA, Re-sign) being hidden when
the prior selection had no private key.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
"Community" is the UDAP spec term but doesn't read clearly in a PKI
management UI. Renamed to "Trust Domain" throughout Sigil — entity,
service, viewmodel, DbContext, FK column, routes (/trust-domains),
and all user-facing text. Udap.* libraries are untouched; the spec's
?community= discovery URL parameter and shared models stay intact.

Migration uses RenameTable/RenameColumn/RenameIndex so existing rows
are preserved (EF auto-generated Drop+Create; hand-rewrote to avoid
data loss). PK constraint renames use raw ALTER TABLE ... RENAME
CONSTRAINT because EF lacks a direct helper.

All 101 tests pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
settings.local.json was committed before .gitignore caught it.
Untrack it (file stays on disk) and consolidate the duplicate
.claude entries in .gitignore to a single global .claude/ pattern.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@JoeShook JoeShook closed this May 22, 2026
JoeShook and others added 2 commits May 22, 2026 14:45
Three .csproj conflicts in examples/Udap.Auth.Server, Udap.Identity.Provider,
and Udap.Identity.Provider.2 — all NuGet version bumps. develop already had
newer Npgsql/OpenTelemetry versions than upstream/main, so kept ours.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@JoeShook JoeShook reopened this May 22, 2026
@JoeShook
JoeShook merged commit bdd7b41 into udap-tools:main May 22, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant