Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: enrich validator api #1958

Merged
merged 10 commits into from
Feb 26, 2025
Merged

chore: enrich validator api #1958

merged 10 commits into from
Feb 26, 2025

Conversation

MagnusSandgren
Copy link
Collaborator

@MagnusSandgren MagnusSandgren commented Feb 25, 2025

Validatoren kan etter denne pren:

  • Validere token format
  • Validere signatur
  • Validere nbf - kan optes ut gjennom options.ValidateLifetime
  • Validere exp - kan optes ut gjennom options.ValidateLifetime
  • Validere iss - kan optes ut gjennom options.ValidateIssuer. Her sammenliknes dialogportens baseuri (som er konfigurert som en del av sdk ioc registrering) med iss i token. Blir dette korrekt? Kan det være at apim ødelegger for oss?
  • Validere dialogId dersom det optionally sendes inn, mot i claim i token
  • Validere en optional liste med requiredActions mot a claim i token

I tillegg vil validatoren returnere en ClaimsPrinciple som representerer tokenet sammen med en liste av potensielle feil med tokenet. Tror dette skal være dekkende for 99,9% av alle use-case tjenesteeiere måtte ha for dialog token validering. Det er i hvert fall dekkende for adapterens token validering.

@MagnusSandgren MagnusSandgren marked this pull request as ready for review February 26, 2025 08:50
@MagnusSandgren MagnusSandgren requested a review from a team as a code owner February 26, 2025 08:50
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
src/Digdir.Library.Dialogporten.WebApiClient/IDialogTokenValidator.cs (1)

8-11: Consider adding doc comments for the new optional parameters.

The Validate method now has multiple optional parameters (dialogId, requiredActions, options). It would be clearer to future maintainers if each parameter's purpose and usage were documented.

 public interface IDialogTokenValidator
 {
+    /// <summary>
+    /// Validates a Dialog token with optional parameters for dialog context, required actions, and validation settings.
+    /// </summary>
+    /// <param name="token">The token to validate.</param>
+    /// <param name="dialogId">Optional, the dialog ID to check.</param>
+    /// <param name="requiredActions">Optional, the actions that must be included in the token.</param>
+    /// <param name="options">Optional, additional validation parameters (issuer check, lifetime check, etc.).</param>
     IValidationResult Validate(
         ReadOnlySpan<char> token,
         Guid? dialogId = null,
         string[]? requiredActions = null,
         DialogTokenValidationParameters? options = null);
 }
src/Digdir.Library.Dialogporten.WebApiClient/Services/DialogTokenValidator.cs (1)

27-31: Consider using a built-in URI builder for combining segments.

While CombineUriSegments handles trimming and separators, using Uri or existing API might avoid possible edge cases with trailing slashes or special characters.

src/Digdir.Library.Dialogporten.WebApiClient/Common/ClaimsPrincipleExtensions.cs (2)

10-11: Consider using more descriptive claim names or adding documentation

The claim names "i" for dialog ID and "a" for actions are not very descriptive. Consider:

  1. Using more descriptive constant names (e.g., DIALOG_ID_CLAIM instead of just dialogIdClaimName)
  2. Adding XML documentation to explain what these claim types represent
  3. Making the claim names configurable through the validator options

This would improve code readability and maintainability.

Also applies to: 18-19


80-93: Consider using built-in StringComparison instead of custom comparer

While the CaseInsensitiveCharComparer implementation is correct, .NET already provides built-in mechanisms for case-insensitive character comparison. Consider using string.Equals(string1, string2, StringComparison.OrdinalIgnoreCase) instead of the custom comparer for better maintainability and potentially better performance.

-        var cleanedExpectedIssuer = expectedIssuer.AsSpan().TrimEnd('/');
-        var cleanedIssuerClaim = iss.AsSpan().TrimEnd('/');
-        return cleanedExpectedIssuer.SequenceEqual(cleanedIssuerClaim, CaseInsensitiveCharComparer.Instance);
+        var cleanedExpectedIssuer = expectedIssuer.TrimEnd('/');
+        var cleanedIssuerClaim = iss.TrimEnd('/');
+        return string.Equals(cleanedExpectedIssuer, cleanedIssuerClaim, StringComparison.OrdinalIgnoreCase);
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4f93f67 and fd55fbe.

📒 Files selected for processing (9)
  • src/Digdir.Library.Dialogporten.WebApiClient/Common/ClaimsPrincipleExtensions.cs (1 hunks)
  • src/Digdir.Library.Dialogporten.WebApiClient/Digdir.Library.Dialogporten.WebApiClient.csproj (1 hunks)
  • src/Digdir.Library.Dialogporten.WebApiClient/IDialogTokenValidator.cs (1 hunks)
  • src/Digdir.Library.Dialogporten.WebApiClient/Services/DialogTokenValidator.cs (2 hunks)
  • src/Digdir.Library.Dialogporten.WebApiClient/Services/EdDsaSecurityKeysCacheService.cs (1 hunks)
  • src/Digdir.Tool.Dialogporten.Benchmarks/Digdir.Tool.Dialogporten.Benchmarks.csproj (1 hunks)
  • src/Digdir.Tool.Dialogporten.Benchmarks/Program.cs (1 hunks)
  • src/Digdir.Tool.Dialogporten.Benchmarks/TokenValidatorBenchmarks.cs (1 hunks)
  • tests/Digdir.Library.Dialogporten.WebApiClient.Unit.Tests/DialogTokenValidatorTests.cs (15 hunks)
🧰 Additional context used
🧠 Learnings (1)
src/Digdir.Tool.Dialogporten.Benchmarks/Digdir.Tool.Dialogporten.Benchmarks.csproj (1)
Learnt from: oskogstad
PR: Altinn/dialogporten#1941
File: src/Digdir.Library.Dialogporten.WebApiClient.WebApiSample/Digdir.Library.Dialogporten.WebApiClient.WebApiSample.csproj:1-3
Timestamp: 2025-02-23T19:09:42.565Z
Learning: In the Dialogporten solution, common build settings like `TargetFramework`, `UserSecretsId`, `Nullable`, and `ImplicitUsings` are defined in `Directory.Build.props` and shared across all projects, making them redundant in individual .csproj files.
🪛 Gitleaks (8.21.2)
src/Digdir.Tool.Dialogporten.Benchmarks/TokenValidatorBenchmarks.cs

18-18: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.

(jwt)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Dry run deploy apps / Deploy job sync-resource-policy-information-job to test
  • GitHub Check: Dry run deploy apps / Deploy job sync-subject-resource-mappings-job to test
🔇 Additional comments (23)
src/Digdir.Tool.Dialogporten.Benchmarks/Program.cs (1)

3-3: Benchmark focus changed to token validation.

The change from running TokenGenerationBenchmark to TokenValidatorBenchmarks aligns well with the PR objective of enriching the validator API.

src/Digdir.Library.Dialogporten.WebApiClient/Digdir.Library.Dialogporten.WebApiClient.csproj (1)

37-37: Appropriate visibility for benchmarking.

Adding InternalsVisibleTo for the benchmarks project is the correct approach to allow access to internal members for performance testing without exposing them publicly.

src/Digdir.Tool.Dialogporten.Benchmarks/Digdir.Tool.Dialogporten.Benchmarks.csproj (1)

15-15: Required project reference added for benchmarks.

The project reference to WebApiClient is necessary for the validator benchmarks to work with the validation components.

src/Digdir.Library.Dialogporten.WebApiClient/Services/EdDsaSecurityKeysCacheService.cs (1)

24-28: Flexible constructor options enhance testability.

The addition of both a parameterless constructor and one accepting predefined keys improves flexibility, particularly for testing and benchmarking scenarios where specific key sets need to be used.

src/Digdir.Library.Dialogporten.WebApiClient/IDialogTokenValidator.cs (2)

12-12: No functional changes at this line.


14-19: Guard against unintended shared state in DialogTokenValidationParameters.Default.

Because Default returns a single shared instance, mutating any of its properties (e.g., ValidateLifetime) in one place will affect all usage. If you intend for code to adjust these parameters at runtime for different contexts, consider returning a new instance on each get or making the properties read-only.

src/Digdir.Tool.Dialogporten.Benchmarks/TokenValidatorBenchmarks.cs (4)

16-18: Verify if this embedded JWT contains sensitive or live data.

The static analysis suggests this token might be sensitive. If it's only for testing or benchmarking, confirm that it doesn't expose real credentials or personally identifiable information. Otherwise, consider obfuscating or storing it in a secure location.

🧰 Tools
🪛 Gitleaks (8.21.2)

18-18: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.

(jwt)


30-31: Benchmark approach is straightforward and effective.
No concerns for the one-liner benchmark method usage.


33-35: PublicKey import is well-structured.
No issues spotted in the helper method converting base64-URL strings to public keys.


36-41: Clean custom clock implementation.
This sealed class is well-defined for benchmarking. No further remarks.

tests/Digdir.Library.Dialogporten.WebApiClient.Unit.Tests/DialogTokenValidatorTests.cs (8)

6-6: All these lines reference the new or updated test setup.
They appear consistent, and the usage of GetSut with the ValidTimeStamp and ValidPublicKeyPairs is clear. No changes recommended.

Also applies to: 16-16, 29-29, 43-43, 53-53, 68-68, 82-82, 100-100, 108-108


112-127: Good coverage for the 'Not Valid Before' scenario.
The new test (ShouldReturnError_WhenUsedBeforeNbf) adds essential coverage for nbf. No issues found.


128-132: Properly tests empty token handling.
The ShouldReturnError_GivenEmptyToken test covers an important edge case. Looks good.


227-230: Valid token with claims test is well-structured.
The new lines ensure that the test environment uses a preset timestamp. No concerns.


273-286: Test for invalid issuer is appropriate.
This test confirms an invalid issuer triggers the correct error and helps ensure reliability of the code.


288-303: Dialog ID validity check test is thorough.
Ensures that any mismatch in dialogId is caught. Implementation looks correct.


304-318: Action requirement coverage is well-handled.
The test ensures enforcement for required actions in the token.


319-331: Global side-effects for clock skew.

DialogTokenValidationParameters.Default.ClockSkew = TimeSpan.Zero; modifies the default instance for all tests and possibly beyond. This can introduce subtle side-effects if other tests also use DialogTokenValidationParameters.Default.

Would you like to isolate test configurations from the global default to prevent cross-test interference?

src/Digdir.Library.Dialogporten.WebApiClient/Services/DialogTokenValidator.cs (1)

33-39: Expanded validation checks look comprehensive.

The new checks for lifetime (nbf, exp), issuer, dialog ID, and actions are well-integrated. The flow is logically structured and the error messages are clear. Excellent improvement in flexibility and readability.

Also applies to: 55-78

src/Digdir.Library.Dialogporten.WebApiClient/Common/ClaimsPrincipleExtensions.cs (4)

48-51: Excellent approach for issuer validation

The use of Span, trailing slash trimming, and case-insensitive comparison for issuer validation is efficient and handles common URL comparison edge cases correctly.


53-61: Good implementation of time validation with clock skew

The implementation of expiration time and not-before-time validation correctly accounts for clock skew in opposite directions. Adding clock skew to expiration time and subtracting it from not-before time properly increases the validity window to account for clock differences.

Also applies to: 63-71


73-78: Well-designed utility method with proper nullability annotations

The TryGetClaimValue utility method follows the pattern of .NET's TryParse methods, and the use of [NotNullWhen(true)] provides good compiler support for null checking.


30-38:

❓ Verification inconclusive

Verify the actions verification logic

The current implementation requires all specified required actions to be present in the token's actions claim. However, it could be more efficient by using a HashSet for the required actions rather than relying on Distinct and Intersect operations.


🏁 Script executed:

#!/bin/bash
# Confirm whether the actions verification logic is consistent with other parts of the codebase

# Look for other instances of action validation to confirm consistent approach
rg -A 5 -B 5 "requiredActions" --type cs

Length of output: 8801


Review the actions verification logic performance suggestion

The implementation in
src/Digdir.Library.Dialogporten.WebApiClient/Common/ClaimsPrincipleExtensions.cs (lines 30–38) correctly ensures that all required actions are present in the token’s actions claim by using LINQ’s Distinct and Intersect operations. However, as a performance consideration, please review whether replacing these with a HashSet-based approach (using StringComparer.OrdinalIgnoreCase) might simplify the logic and reduce overhead, especially if the list of required actions grows large. Note that similar logic is used elsewhere in the codebase and tests indicate consistent behavior. It’s advisable to benchmark the proposed change to ensure it meets both the efficiency and correctness requirements.

@Altinn Altinn deleted a comment from coderabbitai bot Feb 26, 2025
Copy link
Contributor

coderabbitai bot commented Feb 26, 2025

Warning

Rate limit exceeded

@MagnusSandgren has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 20 minutes and 58 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 2289622 and 5dcc3bb.

📒 Files selected for processing (1)
  • src/Digdir.Library.Dialogporten.WebApiClient/Services/DialogTokenValidator.cs (2 hunks)
📝 Walkthrough

Walkthrough

This pull request enhances the Dialogporten Web API client library by introducing new extension methods for the ClaimsPrincipal class, updating the token validation interface and implementation to accept additional parameters, and modifying project configurations to expose internal members for benchmarking. It also adds new benchmark classes for token validation performance testing, updates constructors for security keys caching, and expands unit test coverage for various validation scenarios.

Changes

File(s) Change Summary
src/.../Common/ClaimsPrincipalExtensions.cs New file providing extension methods for ClaimsPrincipal (e.g., VerifyDialogId, VerifyActions, VerifyExpirationTime, VerifyNotValidBefore, TryGetClaimValue) with an associated helper for case-insensitive comparisons.
src/.../Digdir.Library.Dialogporten.WebApiClient.csproj Added an InternalsVisibleTo declaration for Digdir.Tool.Dialogporten.Benchmarks to expose internal members.
src/.../IDialogTokenValidator.cs Updated the Validate method signature to accept additional optional parameters (dialogId, requiredActions, options); introduced DialogTokenValidationParameters class for validation configuration.
src/.../Services/DialogTokenValidator.cs Updated the Validate method to include new parameters and integrated checks for token lifetime, issuer validation, and required actions; removed the VerifyExpiration method.
src/.../Services/EdDsaSecurityKeysCacheService.cs Introduced a parameterless constructor and an internal constructor accepting a set of public keys for initializing the cache.
src/.../Digdir.Tool.Dialogporten.Benchmarks.csproj, Program.cs, and TokenValidatorBenchmarks.cs Updated project references and modified the benchmark runner invocation from TokenGenerationBenchmark to TokenValidatorBenchmarks; added a new benchmark class for token validation performance testing.
tests/.../DialogTokenValidatorTests.cs Refactored timestamp handling by replacing a constant with a static readonly DateTimeOffset, updated the GetSut method signature, and added test cases for invalid dialog IDs and actions.

Possibly related PRs

Suggested reviewers

  • Fargekritt

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (5)
src/Digdir.Library.Dialogporten.WebApiClient/IDialogTokenValidator.cs (1)

14-20: Consider adding XML documentation or summary comments.
The DialogTokenValidationParameters class is intuitive, but adding code comments for each property would clarify when and why to override defaults, improving maintainability.

src/Digdir.Library.Dialogporten.WebApiClient/Services/DialogTokenValidator.cs (2)

15-15: Naming consistency.
Consider whether TokenPropertyName is needed in the class or if a shared constants file might aid reuse in other validators.


20-25: Dynamic issuer derivation.
Combining settings.BaseUri with "api/v1" is convenient. Just confirm that trailing/leading slashes are properly handled and tested for various host URIs.

src/Digdir.Library.Dialogporten.WebApiClient/Common/ClaimsPrincipalExtensions.cs (2)

1-7: Missing XML documentation for public API.

Consider adding XML documentation comments to describe the purpose and usage of these extension methods, especially since they form part of the validation API.

 namespace Altinn.ApiClients.Dialogporten.Common;

+/// <summary>
+/// Extension methods for ClaimsPrincipal to validate dialog token claims.
+/// </summary>
 internal static class ClaimsPrincipalExtensions
 {

80-94: Consider reusing existing StringComparer.

While the CaseInsensitiveCharComparer implementation is correct, you could potentially leverage existing .NET functionality for case-insensitive string comparison.

 public static bool VerifyIssuer(this ClaimsPrincipal claimsPrincipal, string expectedIssuer)
 {
     const string issuerClaimName = "iss";
     if (!claimsPrincipal.TryGetClaimValue(issuerClaimName, out var iss))
     {
         return false;
     }

-    var cleanedExpectedIssuer = expectedIssuer.AsSpan().TrimEnd('/');
-    var cleanedIssuerClaim = iss.AsSpan().TrimEnd('/');
-    return cleanedExpectedIssuer.SequenceEqual(cleanedIssuerClaim, CaseInsensitiveCharComparer.Instance);
+    return string.Equals(
+        expectedIssuer.TrimEnd('/'),
+        iss.TrimEnd('/'),
+        StringComparison.OrdinalIgnoreCase);
 }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4f93f67 and a98b0cf.

📒 Files selected for processing (9)
  • src/Digdir.Library.Dialogporten.WebApiClient/Common/ClaimsPrincipalExtensions.cs (1 hunks)
  • src/Digdir.Library.Dialogporten.WebApiClient/Digdir.Library.Dialogporten.WebApiClient.csproj (1 hunks)
  • src/Digdir.Library.Dialogporten.WebApiClient/IDialogTokenValidator.cs (1 hunks)
  • src/Digdir.Library.Dialogporten.WebApiClient/Services/DialogTokenValidator.cs (2 hunks)
  • src/Digdir.Library.Dialogporten.WebApiClient/Services/EdDsaSecurityKeysCacheService.cs (1 hunks)
  • src/Digdir.Tool.Dialogporten.Benchmarks/Digdir.Tool.Dialogporten.Benchmarks.csproj (1 hunks)
  • src/Digdir.Tool.Dialogporten.Benchmarks/Program.cs (1 hunks)
  • src/Digdir.Tool.Dialogporten.Benchmarks/TokenValidatorBenchmarks.cs (1 hunks)
  • tests/Digdir.Library.Dialogporten.WebApiClient.Unit.Tests/DialogTokenValidatorTests.cs (15 hunks)
🧰 Additional context used
🧠 Learnings (1)
src/Digdir.Tool.Dialogporten.Benchmarks/Digdir.Tool.Dialogporten.Benchmarks.csproj (1)
Learnt from: oskogstad
PR: Altinn/dialogporten#1941
File: src/Digdir.Library.Dialogporten.WebApiClient.WebApiSample/Digdir.Library.Dialogporten.WebApiClient.WebApiSample.csproj:1-3
Timestamp: 2025-02-23T19:09:42.565Z
Learning: In the Dialogporten solution, common build settings like `TargetFramework`, `UserSecretsId`, `Nullable`, and `ImplicitUsings` are defined in `Directory.Build.props` and shared across all projects, making them redundant in individual .csproj files.
🪛 Gitleaks (8.21.2)
src/Digdir.Tool.Dialogporten.Benchmarks/TokenValidatorBenchmarks.cs

18-18: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.

(jwt)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Dry run deploy apps / Deploy web-api-so to test
  • GitHub Check: build / build-and-test
🔇 Additional comments (25)
src/Digdir.Tool.Dialogporten.Benchmarks/Program.cs (1)

3-3: LGTM: Focus shifted to TokenValidatorBenchmarks

The change properly redirects the benchmark execution from the previous token generation focus to the token validation benchmarks, aligning with the PR's objective to enrich the validator API.

src/Digdir.Tool.Dialogporten.Benchmarks/Digdir.Tool.Dialogporten.Benchmarks.csproj (1)

15-15: LGTM: Required project reference added

The added project reference to the WebApiClient is necessary to support the new TokenValidatorBenchmarks functionality. This correctly integrates the validator components being benchmarked.

src/Digdir.Library.Dialogporten.WebApiClient/Digdir.Library.Dialogporten.WebApiClient.csproj (1)

37-37: LGTM: InternalsVisibleTo declaration for benchmarks

This change appropriately exposes the internal members of the WebApiClient to the benchmarking tool, which is necessary for performance testing the token validation components.

src/Digdir.Library.Dialogporten.WebApiClient/Services/EdDsaSecurityKeysCacheService.cs (1)

24-28: LGTM: Enhanced constructor flexibility for DefaultEdDsaSecurityKeysCache

The added constructors provide better flexibility for initializing the cache:

  1. The parameterless constructor supports default initialization
  2. The internal constructor with public keys parameter enables pre-populating the cache

This enhancement is particularly valuable for testing and benchmarking scenarios, making it easier to set up the cache with predefined keys.

src/Digdir.Library.Dialogporten.WebApiClient/IDialogTokenValidator.cs (1)

8-12: Extend usage documentation for new parameters.
Adding optional parameters for dialog ID, required actions, and validation options significantly enhances flexibility. However, ensure that all implementers and consumers of this interface are well-documented on how to use these parameters.

src/Digdir.Tool.Dialogporten.Benchmarks/TokenValidatorBenchmarks.cs (3)

30-31: Benchmark approach looks correct.
Using [Benchmark] with a direct call to _sut.Validate is a clean way to measure performance.


33-35: Static helper method is cleanly implemented.
Importing the key with ToPublicKey is straightforward and readable. This is a good pattern for test or benchmark setup.


36-40: Clock abstraction facilitates time-based testing.
The BenchmarkClock class is a concise way to provide a reproducible timestamp, aiding test reliability.

src/Digdir.Library.Dialogporten.WebApiClient/Services/DialogTokenValidator.cs (8)

18-18: Assign a default or validate null values for _expectedIssuer.
Ensure settings.BaseUri is never null or empty before concatenation, to avoid unexpected runtime behavior.


27-31: Segment combination logic is well-structured.
Trimming slashes before concatenation ensures a valid combined URI. This helper method is concise and improves readability.


33-39: Optional parameters preserve backward compatibility.
The extended signature with default nulls is a good approach. Verify that all call sites are updated appropriately to avoid mismatched expectations.


55-59: Adding nbf check enhances token validity.
Using options.ValidateLifetime to control the not-before validation fine-tunes security. Ensure thorough testing of clock skew behavior.


60-64: Expiration validation is correct.
The same ClockSkew approach for exp extends consistency to all lifetime checks. Confirm edge cases for tokens close to expiry.


65-69: Issuer validation looks robust.
Confirm that the _expectedIssuer matches expected domains and subdomains if partial matches are required.


70-74: Dialog ID check is straightforward.
Checking if the token claims match dialogId is clear and aligns with the new parameter usage.


75-78: Action list validation is a welcome addition.
This ensures tokens contain all required actions, further tightening security and clarifying usage.

tests/Digdir.Library.Dialogporten.WebApiClient.Unit.Tests/DialogTokenValidatorTests.cs (4)

16-16: Good change: Using DateTimeOffset improves code clarity.

Converting from a constant string to a static readonly DateTimeOffset provides better type safety and reduces repetitive parsing throughout the tests.


111-126: Test coverage improved for token validation failures.

The test for validating the Not-Before (nbf) claim logic is well implemented, with clear error assertions.


273-317: Good test coverage for additional validation scenarios.

These new tests cover important validation scenarios that were previously missing:

  • Invalid issuer verification
  • Invalid dialog ID verification
  • Invalid actions verification

This ensures that the enhanced validation logic in the DialogTokenValidator is working correctly.


319-331: Good practice: Setting ClockSkew to zero for deterministic tests.

Setting DialogTokenValidationParameters.Default.ClockSkew = TimeSpan.Zero is good practice for tests as it eliminates time-based flakiness. The updated constructor parameters also properly support testing the new validation features.

src/Digdir.Library.Dialogporten.WebApiClient/Common/ClaimsPrincipalExtensions.cs (5)

8-14: Well-implemented dialog ID verification.

The method correctly parses and compares the dialog ID from claims.


16-38: Actions verification logic is robust.

The implementation correctly handles edge cases:

  • Empty required actions
  • Missing action claim
  • Case-insensitive comparison
  • Duplicate actions in the requirements

Consider adding XML documentation to clarify the expected format of the actions claim.


40-51: Efficient issuer verification with performance optimizations.

Good use of:

  • AsSpan() to avoid string allocations
  • TrimEnd('/') to normalize URL paths
  • Custom case-insensitive comparison

This approach provides both correctness and performance when comparing issuer URLs.


53-71: Time-based validation handles clock skew properly.

Both VerifyExpirationTime and VerifyNotValidBefore methods:

  • Correctly parse Unix timestamps
  • Apply appropriate clock skew in opposite directions
  • Handle missing claims gracefully with sensible defaults

This is crucial for reliable token validation in distributed systems.


73-78: Well-designed helper method with nullable annotation.

The TryGetClaimValue method uses the [NotNullWhen(true)] attribute which enhances static analysis for null-reference checks, making it safer to use.

@MagnusSandgren MagnusSandgren merged commit 739380a into main Feb 26, 2025
23 checks passed
@MagnusSandgren MagnusSandgren deleted the chore/enrich-validator-api branch February 26, 2025 11:21
oskogstad pushed a commit that referenced this pull request Feb 26, 2025
🤖 I have created a release *beep* *boop*
---


##
[1.55.5](v1.55.4...v1.55.5)
(2025-02-26)


### Bug Fixes

* **webapi:** Clarify use of FCEs in content values
([#1959](#1959))
([584a76c](584a76c))


### Miscellaneous Chores

* **deps:** update dotnet monorepo
([#1961](#1961))
([e3f12d5](e3f12d5))
* **deps:** update grafana/grafana docker tag to v10.4.16
([#1962](#1962))
([4f93f67](4f93f67))
* **deps:** update otel/opentelemetry-collector-contrib docker tag to
v0.119.0 ([#1963](#1963))
([0fca9a5](0fca9a5))
* enrich validator api
([#1958](#1958))
([739380a](739380a))
* **performance:** Fix serviceowner orgno
([#1965](#1965))
([c2de39d](c2de39d))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
@coderabbitai coderabbitai bot mentioned this pull request Feb 27, 2025
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.

3 participants