-
Notifications
You must be signed in to change notification settings - Fork 0
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
Make Authorization service more testable by passing ClaimsPrincipal as argument #589
Conversation
📝 Walkthrough📝 WalkthroughWalkthroughThe pull request introduces significant modifications across multiple controllers and handler classes to incorporate user context into various file transfer and resource management operations. The changes primarily involve updating method signatures to include Changes
Possibly related PRs
Suggested labels
Suggested reviewers
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
🔇 Additional comments (3)src/Altinn.Broker.Application/ConfirmDownload/ConfirmDownloadHandler.cs (3)
The addition of Note: There's an existing review comment about adding null checks for the user parameter, which is still valid.
The implementation correctly uses the user parameter for access verification and handles access denial appropriately. Note: There's an existing review comment about ensuring
Passing
Also applies to: 92-92 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? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 10
🧹 Outside diff range and nitpick comments (21)
src/Altinn.Broker.Application/IHandler.cs (1)
10-10
: LGTM! Well-designed interface changeThe modification to pass ClaimsPrincipal explicitly is a solid architectural improvement that:
- Makes dependencies explicit and visible at the interface level
- Removes hidden coupling to HttpContext
- Improves testability by allowing direct injection of user claims
- Maintains flexibility with nullable user parameter
Remember to handle null user cases appropriately in implementations.
src/Altinn.Broker.Core/Repositories/IAuthorizationService.cs (1)
8-8
: Excellent architectural improvement!This change significantly improves the testability and maintainability of the authorization service by:
- Making the user context explicit instead of relying on HttpContext
- Supporting dependency injection principles
- Enabling easier mocking in unit tests
- Maintaining backward compatibility with nullable user parameter
The parameter ordering is also logical, placing the user context first followed by operation-specific parameters.
Consider documenting these key points in the XML documentation for the interface:
- The purpose of the nullable user parameter
- The relationship between IsLegacyUser and user parameter
- The expected behavior when user is null
src/Altinn.Broker.Application/GetFileTransferOverview/GetFileTransferOverviewHandler.cs (1)
Read access alone is sufficient for file transfer overview
Based on the codebase analysis, the GetFileTransferOverview operation should only require Read access. This is supported by:
- The operation is purely a read operation that retrieves and returns file transfer details
- Similar read operations in the codebase like
DownloadFileHandler
only require Read access- Write access is typically required only for operations that modify state, such as:
UploadFileHandler
: Write access onlyInitializeFileTransferHandler
: Write access onlyRecommendation: Remove
ResourceAccessLevel.Write
from the access check to follow the principle of least privilege.🔗 Analysis chain
Line range hint
29-33
: Verify if both Write and Read access levels are requiredThe code checks for both Write and Read access levels. This seems broad - consider if the file transfer overview operation really needs Write access or if Read access alone would be sufficient.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Search for other usages of GetFileTransferOverview to understand the access pattern rg -A 5 "GetFileTransferOverview" # Search for other CheckUserAccess calls to compare access level patterns ast-grep --pattern 'CheckUserAccess($$$, $$$, new List<ResourceAccessLevel> { $$$'Length of output: 137
Script:
#!/bin/bash # Search for GetFileTransferOverview in controller/API endpoints rg -A 10 "GetFileTransferOverview" --type cs # Search for similar file transfer operations to understand access patterns rg -A 5 "FileTransfer.*Controller" --type cs # Look for other CheckUserAccess usage patterns rg -A 3 "CheckUserAccess" --type csLength of output: 20973
src/Altinn.Broker.API/Controllers/ResourceController.cs (1)
Line range hint
23-41
: Consider enhancing testability further with interface-based dependency injection.While passing ClaimsPrincipal directly improves testability, the method could be even more testable with a few additional improvements:
- public async Task<ActionResult> ConfigureResource( + public virtual async Task<ActionResult> ConfigureResource( string resourceId, [FromBody] ResourceExt resourceExt, [ModelBinder(typeof(MaskinportenModelBinder))] CallerIdentity token, - [FromServices] ConfigureResourceHandler handler, + [FromServices] IConfigureResourceHandler handler, CancellationToken cancellationToken)These changes would:
- Make the method virtual to allow mocking in tests
- Use an interface for the handler to follow dependency inversion principle
src/Altinn.Broker.Application/GetFileTransferDetails/GetFileTransferDetailsHandler.cs (1)
Line range hint
28-32
: Consider making access levels configurableWhile the authorization check correctly uses the new user parameter, consider extracting the required access levels to a configuration or constant to improve maintainability and reusability.
+private static readonly IReadOnlyList<ResourceAccessLevel> RequiredAccessLevels = new[] +{ + ResourceAccessLevel.Write, + ResourceAccessLevel.Read +}; -var hasAccess = await resourceRightsRepository.CheckUserAccess(user, fileTransfer.ResourceId, new List<ResourceAccessLevel> { ResourceAccessLevel.Write, ResourceAccessLevel.Read }, cancellationToken: cancellationToken); +var hasAccess = await resourceRightsRepository.CheckUserAccess(user, fileTransfer.ResourceId, RequiredAccessLevels, cancellationToken: cancellationToken);src/Altinn.Broker.Application/GetFileTransfers/GetFileTransfersHandler.cs (2)
Line range hint
17-56
: Consider adding XML documentation for the updated methodThe Process method would benefit from XML documentation that describes the new user parameter and its role in authorization.
+ /// <summary> + /// Processes a request to get file transfers + /// </summary> + /// <param name="request">The file transfer request parameters</param> + /// <param name="user">The claims principal representing the authenticated user</param> + /// <param name="cancellationToken">Cancellation token</param> + /// <returns>A list of file transfer GUIDs or an error</returns> public async Task<OneOf<List<Guid>, Error>> Process(GetFileTransfersRequest request, ClaimsPrincipal? user, CancellationToken cancellationToken)
Line range hint
17-56
: Consider adding unit tests for authorization scenariosSince this change is aimed at improving testability, we should ensure comprehensive test coverage for various authorization scenarios.
Would you like me to help generate unit tests covering:
- Authorized user access
- Unauthorized user access
- Null user handling
- Various combinations of search parameters with different user contexts
src/Altinn.Broker.Application/GetFileTransfers/LegacyGetFilesHandler.cs (1)
Line range hint
37-37
: Address the TODO comment about performance optimizationThe comment raises a valid question about the query strategy. The current implementation might not be optimal for scenarios with multiple recipients.
Would you like me to help analyze the performance implications of both approaches and propose a solution? I can:
- Compare the performance characteristics of multiple single queries vs. one combined query
- Provide a concrete implementation for the preferred approach
src/Altinn.Broker.API/Controllers/MalwareScanResultsController.cs (1)
Based on the gathered information, I can now provide the final response:
The webhook endpoint should implement Event Grid's authentication mechanism
The endpoint currently lacks any authentication mechanism, while the codebase shows JWT bearer authentication is used for other endpoints. For Event Grid webhooks:
- The endpoint already implements the subscription validation handshake, but the TODO comment correctly identifies that source validation is missing
- Event Grid provides built-in security mechanisms that should be implemented:
- Event validation using the webhook validation handshake (already present)
- Source validation by checking the Event Grid topic ID against allowed sources
- Optional: Add the
aeg-subscription-name
header validation🔗 Analysis chain
Line range hint
1-65
: Verify if this endpoint needs authorizationSince this is a webhook endpoint called by Azure Event Grid, we should verify if it needs any user-based authorization at all. The endpoint should likely be secured using Event Grid's built-in authentication mechanisms instead.
Let's check if this endpoint has any authorization attributes:
Let me gather more information about the authentication mechanisms in the codebase:
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check for authorization attributes and similar endpoints # Look for other webhook endpoints and their authorization patterns rg -B 5 -A 10 "Route\(\"broker/api/v1/webhooks" # Check for Event Grid validation logic in similar controllers ast-grep --pattern 'if \(eventData is SubscriptionValidationEventData'Length of output: 1908
Script:
#!/bin/bash # Check for any authentication middleware or configuration rg -B 5 -A 5 "UseAuthentication|AddAuthentication|AuthenticationBuilder" # Look for any Event Grid specific validation or authentication code rg -B 5 -A 5 "EventGrid|WebhookValidation|EventValidation" # Check for any security attributes on controllers or endpoints ast-grep --pattern '[Authorize]'Length of output: 15629
src/Altinn.Broker.Application/DownloadFile/DownloadFileHandler.cs (1)
Line range hint
35-39
: Consider adding null check for user parameterWhile the authorization check is properly placed, consider adding a null check for defensive programming. This would make the behavior explicit when no user context is provided.
Here's a suggested improvement:
- var hasAccess = await resourceRightsRepository.CheckUserAccess(user, fileTransfer.ResourceId, new List<ResourceAccessLevel> { ResourceAccessLevel.Read }, request.IsLegacy, cancellationToken); + if (user == null) + { + return Errors.NoAccessToResource; + } + var hasAccess = await resourceRightsRepository.CheckUserAccess(user, fileTransfer.ResourceId, new List<ResourceAccessLevel> { ResourceAccessLevel.Read }, request.IsLegacy, cancellationToken); if (!hasAccess) { return Errors.NoAccessToResource; };src/Altinn.Broker.Application/MalwareScanResults/MalwareScanResultHandler.cs (2)
27-27
: Consider adding XML documentation for the new parameter.The signature change aligns well with making the service more testable. Consider adding XML documentation to explain when the user parameter might be null and its usage.
+ /// <param name="user">The claims principal representing the user context. Can be null for system operations.</param>
Line range hint
69-77
: Remove or relocate the unrelated Foo class.The Foo class appears to be unrelated to the MalwareScanResultHandler and violates the single responsibility principle. If this class is needed, it should be moved to its own file.
-public class Foo -{ - private readonly IFileTransferRepository _fileTransferRepository; - public Foo(IFileTransferRepository fileTransferRepository) - { - _fileTransferRepository = fileTransferRepository; - } -}src/Altinn.Broker.Integrations/Altinn/Authorization/AltinnAuthorizationService.cs (3)
Line range hint
34-52
: Remove duplicate null check for user parameterThere are two separate null checks for the
user
parameter with different behaviors:
- First check throws
InvalidOperationException
- Second check logs error and returns false
This inconsistency could lead to confusion and potential bugs since the second check is unreachable.
Suggested fix:
public async Task<bool> CheckUserAccess(ClaimsPrincipal? user, string resourceId, List<ResourceAccessLevel> rights, bool IsLegacyUser = false, CancellationToken cancellationToken = default) { if (user is null) { throw new InvalidOperationException("This operation cannot be called outside an authenticated HttpContext"); } if (IsLegacyUser || _hostEnvironment.IsDevelopment()) { return true; } var resource = await _resourceRepository.GetResource(resourceId, cancellationToken); if (resource is null) { return false; } - if (user is null) - { - _logger.LogError("Unexpected null value. User was null when checking access to resource"); - return false; - }
Line range hint
40-43
: Add logging for authorization bypassesThe method silently bypasses authorization checks for legacy users and development environment. This should be logged for security auditing purposes.
Suggested enhancement:
if (IsLegacyUser || _hostEnvironment.IsDevelopment()) { + _logger.LogWarning("Authorization check bypassed: IsLegacyUser={isLegacy}, IsDevelopment={isDev}", + IsLegacyUser, _hostEnvironment.IsDevelopment()); return true; }
Line range hint
53-65
: Enhance error logging for authorization failuresThe error handling could be improved by adding more context to log messages when authorization fails.
Suggested enhancement:
var response = await _httpClient.PostAsJsonAsync("authorization/api/v1/authorize", jsonRequest, cancellationToken); if (!response.IsSuccessStatusCode) { + _logger.LogError("Authorization API request failed with status code {StatusCode}", response.StatusCode); return false; } var responseContent = await response.Content.ReadFromJsonAsync<XacmlJsonResponse>(cancellationToken: cancellationToken); if (responseContent is null) { - _logger.LogError("Unexpected null or invalid json response from Authorization."); + var rawContent = await response.Content.ReadAsStringAsync(cancellationToken); + _logger.LogError("Failed to deserialize authorization response. Content: {Content}", rawContent); return false; }src/Altinn.Broker.Application/ExpireFileTransfer/ExpireFileTransferHandler.cs (1)
Line range hint
25-63
: Consider refactoring for better maintainability and documentationThe Process method handles multiple responsibilities and could benefit from some improvements:
- Consider extracting the file deletion and status update logic into separate methods
- Error messages could be more specific (e.g., include file transfer ID in the expiration error)
- The
force
parameter's purpose and implications should be documentedHere's a suggested refactoring approach:
+ /// <summary> + /// Processes the expiration of a file transfer + /// </summary> + /// <param name="request">The expiration request</param> + /// <param name="user">The user initiating the request</param> + /// <param name="cancellationToken">Cancellation token</param> + /// <param name="force">When true, allows expiration regardless of the expiration time</param> + /// <returns>A task representing the asynchronous operation</returns> public async Task<OneOf<Task, Error>> Process(ExpireFileTransferRequest request, ClaimsPrincipal? user, CancellationToken cancellationToken) { logger.LogInformation("Deleting file transfer with id {fileTransferId}", request.FileTransferId.ToString()); var fileTransfer = await GetFileTransferAsync(request.FileTransferId, cancellationToken); var resource = await GetResource(fileTransfer.ResourceId, cancellationToken); var serviceOwner = await GetServiceOwnerAsync(resource.ServiceOwnerId); - if (fileTransfer.FileTransferStatusEntity.Status == Core.Domain.Enums.FileTransferStatus.Purged) + if (await IsPurged(fileTransfer)) { logger.LogInformation("FileTransfer has already been set to purged"); } - if (request.Force || fileTransfer.ExpirationTime < DateTime.UtcNow) + if (CanExpire(request.Force, fileTransfer)) { - await brokerStorageService.DeleteFile(serviceOwner, fileTransfer, cancellationToken); - if (!request.DoNotUpdateStatus) - { - await TransactionWithRetriesPolicy.Execute(async (cancellationToken) => - { - await fileTransferStatusRepository.InsertFileTransferStatus(/*...*/); - await eventBus.Publish(/*...*/); - return Task.CompletedTask; - }, logger, cancellationToken); - } + await DeleteFileAndUpdateStatus(serviceOwner, fileTransfer, + request.DoNotUpdateStatus, cancellationToken); - return TransactionWithRetriesPolicy.Execute(async (cancellationToken) => - { - var recipientsWhoHaveNotDownloaded = fileTransfer.RecipientCurrentStatuses - .Where(latestStatus => - latestStatus.Status < Core.Domain.Enums.ActorFileTransferStatus.DownloadConfirmed) - .ToList(); - foreach (var recipient in recipientsWhoHaveNotDownloaded) - { - logger.LogError(/*...*/); - await eventBus.Publish(/*...*/); - } - if (recipientsWhoHaveNotDownloaded.Count > 0) - await eventBus.Publish(/*...*/); - return Task.CompletedTask; - }, logger, cancellationToken); + return await NotifyUndownloadedRecipients(fileTransfer, cancellationToken); } - throw new Exception("FileTransfer has not expired, and should not be purged"); + throw new InvalidOperationException( + $"FileTransfer {request.FileTransferId} has not expired and force parameter is not set"); } + private async Task<bool> IsPurged(FileTransferEntity fileTransfer) => + fileTransfer.FileTransferStatusEntity.Status == + Core.Domain.Enums.FileTransferStatus.Purged; + private bool CanExpire(bool force, FileTransferEntity fileTransfer) => + force || fileTransfer.ExpirationTime < DateTime.UtcNow;src/Altinn.Broker.API/Controllers/LegacyFileController.cs (2)
81-81
: Consistent implementation of ClaimsPrincipal across handlersThe changes consistently add
HttpContext.User
to all handler.Process calls, which is a good systematic approach to implementing claims-based authorization. This aligns well with the PR objective of improving testability.Consider documenting this architectural change in your technical documentation to help other developers understand:
- The transition from token-based to claims-based authorization
- How to properly mock ClaimsPrincipal in tests
- The relationship between CallerIdentity and ClaimsPrincipal
Also applies to: 110-110, 163-163, 191-191, 219-219
Line range hint
1-234
: Well-structured controller with clean separation of concernsThe controller demonstrates good design practices:
- Each operation has its dedicated handler (SOLID principles)
- Consistent error handling using the Problem pattern
- Clean separation of legacy compatibility layer
- Proper use of dependency injection
The addition of claims-based authorization fits naturally into this structure.
Consider adding XML documentation to the handler.Process calls to document the role of ClaimsPrincipal parameter:
var commandResult = await handler.Process(new UploadFileRequest() { FileTransferId = fileTransferId, Token = legacyToken, UploadStream = Request.Body, IsLegacy = true -}, HttpContext.User, cancellationToken); +}, HttpContext.User, // Used for claims-based authorization + cancellationToken);src/Altinn.Broker.API/Controllers/FileTransferController.cs (3)
Line range hint
116-129
: Fix error handling in initialization resultThe error handling for the initialization result needs attention:
- The current code continues execution even when initialization fails
- The
Problem()
result is not being returnedApply this fix:
var initializeResult = await initializeFileTransferHandler.Process(initializeRequest, HttpContext.User, cancellationToken); if (initializeResult.IsT1) { - Problem(initializeResult.AsT1); + return Problem(initializeResult.AsT1); }
268-268
: Consider simplifying the idempotency wrapperWhile the change correctly passes the user context, the lambda wrapper makes the code slightly harder to read. Consider extracting the Process call to a separate method for better readability.
+ private async Task<OneOf<Task, Error>> ProcessConfirmDownload(ConfirmDownloadRequest request, ClaimsPrincipal user, CancellationToken cancellationToken) + { + return await handler.Process(request, user, cancellationToken); + } // In ConfirmDownload method: - var proccessingFunction = new Func<Task<OneOf<Task, Error>>>(() => handler.Process(requestData, HttpContext.User, cancellationToken)); + var proccessingFunction = new Func<Task<OneOf<Task, Error>>>(() => ProcessConfirmDownload(requestData, HttpContext.User, cancellationToken));
Line range hint
1-277
: Well-structured authorization pattern implementationThe changes successfully implement a consistent pattern of passing user context to handlers, which:
- Improves testability by making the authorization flow explicit
- Maintains security through proper authorization policies
- Keeps the responsibility of authorization checks in the handlers
- Makes the code more maintainable by following a consistent pattern
Consider documenting this pattern in the project's architectural guidelines to ensure consistency across other controllers.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (19)
src/Altinn.Broker.API/Controllers/FileTransferController.cs
(9 hunks)src/Altinn.Broker.API/Controllers/LegacyFileController.cs
(6 hunks)src/Altinn.Broker.API/Controllers/MalwareScanResultsController.cs
(1 hunks)src/Altinn.Broker.API/Controllers/ResourceController.cs
(1 hunks)src/Altinn.Broker.Application/ConfigureResource/ConfigureResourceHandler.cs
(2 hunks)src/Altinn.Broker.Application/ConfirmDownload/ConfirmDownloadHandler.cs
(4 hunks)src/Altinn.Broker.Application/DownloadFile/DownloadFileHandler.cs
(3 hunks)src/Altinn.Broker.Application/ExpireFileTransfer/ExpireFileTransferHandler.cs
(2 hunks)src/Altinn.Broker.Application/GetFileTransferDetails/GetFileTransferDetailsHandler.cs
(3 hunks)src/Altinn.Broker.Application/GetFileTransferOverview/GetFileTransferOverviewHandler.cs
(3 hunks)src/Altinn.Broker.Application/GetFileTransfers/GetFileTransfersHandler.cs
(2 hunks)src/Altinn.Broker.Application/GetFileTransfers/LegacyGetFilesHandler.cs
(2 hunks)src/Altinn.Broker.Application/IHandler.cs
(1 hunks)src/Altinn.Broker.Application/InitializeFileTransfer/InitializeFileTransferHandler.cs
(3 hunks)src/Altinn.Broker.Application/MalwareScanResults/MalwareScanResultHandler.cs
(3 hunks)src/Altinn.Broker.Application/UploadFile/UploadFileHandler.cs
(2 hunks)src/Altinn.Broker.Core/Repositories/IAuthorizationService.cs
(1 hunks)src/Altinn.Broker.Integrations/Altinn/Authorization/AltinnAuthorizationService.cs
(1 hunks)tests/Altinn.Broker.Tests/Helpers/CustomWebApplicationFactory.cs
(2 hunks)
🔇 Additional comments (33)
src/Altinn.Broker.Application/IHandler.cs (1)
1-2
: LGTM! Clean import addition
The ClaimsPrincipal import is properly placed and necessary for the interface changes.
src/Altinn.Broker.Core/Repositories/IAuthorizationService.cs (1)
1-3
: LGTM! Clean import organization.
The addition of System.Security.Claims import is necessary and well-organized.
src/Altinn.Broker.Application/GetFileTransferOverview/GetFileTransferOverviewHandler.cs (2)
1-1
: LGTM: Required import for ClaimsPrincipal
The addition of the System.Security.Claims import is appropriate for the new ClaimsPrincipal parameter.
Line range hint 16-37
: Verify controller updates for the new parameter
The handler's signature change requires updates in all controllers that use this handler. Let's verify that all callers have been properly updated to pass the user context.
✅ Verification successful
Let's try a broader search to find the controller and usage patterns. The previous search might have been too specific. We'll look for files containing the handler name first, and then search for Process method calls to understand the usage pattern.
All controllers have been properly updated with the user context parameter
Based on the search results, I can verify that all controllers using the GetFileTransferOverviewHandler
are passing the HttpContext.User
parameter correctly:
- In
LegacyFileController.cs
:
await handler.Process(new GetFileTransferOverviewRequest() {
// ... request properties ...
}, HttpContext.User, cancellationToken);
- In
FileTransferController.cs
:
await handler.Process(new GetFileTransferOverviewRequest() {
// ... request properties ...
}, HttpContext.User, cancellationToken);
The implementation is consistent across both controllers that use this handler, and they properly pass the user context parameter.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for usages of GetFileTransferOverviewHandler to verify controller updates
ast-grep --pattern 'class $_ {
$$$
GetFileTransferOverviewHandler $_
$$$
}'
# Search for Process method calls to verify the new parameter is passed
rg -A 5 "GetFileTransferOverviewHandler.*Process\("
Length of output: 137
Script:
#!/bin/bash
# Search for files containing GetFileTransferOverviewHandler
rg -l "GetFileTransferOverviewHandler"
# Search for Process method invocations with context
rg -B 2 -A 5 "\.Process\("
Length of output: 20330
src/Altinn.Broker.API/Controllers/ResourceController.cs (2)
35-35
: LGTM! The change aligns with the PR objective.
The addition of HttpContext.User
to the handler.Process call improves testability by making the user context explicit rather than relying on HttpContextAccessor. This change makes it easier to unit test the handler by allowing direct injection of test claims.
Line range hint 26-34
: Verify validation of resource configuration parameters.
The handler is processing several configuration parameters that could impact system behavior and security.
✅ Verification successful
Let me generate additional scripts to check for validation logic in the UpdateFileTransferTimeToLive
method and any validation attributes on the request model.
Let me check the actual implementation of the validation logic in the ConfigureResourceHandler.
Based on the gathered information, I can now provide the final response:
Resource configuration parameters are properly validated
The codebase shows comprehensive validation for both MaxFileTransferSize and FileTransferTimeToLive:
-
MaxFileTransferSize validation:
- Checks for negative values
- Prevents zero values
- Enforces virus scan size limits in production
- Enforces global maximum upload size limit
-
FileTransferTimeToLive validation:
- Validates format using XmlConvert.ToTimeSpan
- Enforces maximum limit of 365 days
- Provides default of 30 days if not specified
The validation is implemented in ConfigureResourceHandler with appropriate error handling and clear error messages.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for validation logic in the handler implementation
# Expected: Find validation checks for MaxFileTransferSize and TimeToLive
# Search for validation logic in the handler
ast-grep --pattern 'class ConfigureResourceHandler {
$$$
Process($_, $_, $_) {
$$$
if ($$$) {
$$$
}
$$$
}
}'
# Search for any existing validation attributes
rg -A 2 "MaxFileTransferSize|FileTransferTimeToLive"
Length of output: 11580
Script:
#!/bin/bash
# Check validation in UpdateFileTransferTimeToLive method
ast-grep --pattern 'UpdateFileTransferTimeToLive($_, $_, $_) {
$$$
if ($$$) {
$$$
}
$$$
}'
# Check for validation attributes on request model
rg -A 5 "class ConfigureResourceRequest"
# Check for any validation constants or rules
rg "MaxFileTransferSize|FileTransferTimeToLive" --type cs -C 3 "Constants|Validation"
Length of output: 1006
Script:
#!/bin/bash
# Get the full implementation of ConfigureResourceHandler
rg -A 20 "UpdateFileTransferTimeToLive.*CancellationToken" --type cs
# Check for any validation errors or constants
rg -A 3 "Errors\." --type cs
# Check for any TimeSpan parsing and validation
rg -A 5 "TimeSpan\.Parse|TimeSpan\.TryParse" --type cs
Length of output: 29121
src/Altinn.Broker.Application/GetFileTransferDetails/GetFileTransferDetailsHandler.cs (1)
1-2
: LGTM: Clean import addition
The System.Security.Claims import is appropriately added to support the new ClaimsPrincipal parameter.
src/Altinn.Broker.Application/GetFileTransfers/GetFileTransfersHandler.cs (3)
1-2
: LGTM: Required import added for ClaimsPrincipal
The addition of the System.Security.Claims import is necessary for the ClaimsPrincipal parameter.
17-17
: LGTM: Method signature updated to support explicit user context
The Process method signature has been updated to accept ClaimsPrincipal as a parameter, which aligns with the PR objective of improving testability by making the authorization context explicit.
20-20
: Verify error handling for null user parameter
While the change to pass the user directly to CheckUserAccess is correct, we should verify how null users are handled since the parameter is nullable (ClaimsPrincipal?).
✅ Verification successful
Null user parameter is properly handled with clear error message
The implementation in AltinnAuthorizationService.CheckUserAccess
explicitly checks for null users and throws an InvalidOperationException
with a clear error message: "This operation cannot be called outside an authenticated HttpContext". This is an appropriate handling of the null case.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for null handling patterns in CheckUserAccess implementation
ast-grep --pattern 'CheckUserAccess(ClaimsPrincipal? $_, $$$)'
# Look for related test cases
rg -l "CheckUserAccess.*null" --type cs
Length of output: 106
Script:
#!/bin/bash
# Let's first find the implementation of CheckUserAccess
rg -A 5 "CheckUserAccess.*ClaimsPrincipal" --type cs
# Also search for any test files related to this method
fd ".*Tests?.cs" --exec rg -l "CheckUserAccess" {}
# Look for the interface definition as well
rg "interface.*ResourceRightsRepository" -A 10 --type cs
Length of output: 2475
src/Altinn.Broker.Application/GetFileTransfers/LegacyGetFilesHandler.cs (1)
1-2
: LGTM! Import added correctly
The System.Security.Claims import is appropriately added and necessary for the ClaimsPrincipal parameter.
src/Altinn.Broker.Application/DownloadFile/DownloadFileHandler.cs (2)
1-1
: LGTM: Required import for ClaimsPrincipal
The addition of the System.Security.Claims import is necessary and correctly placed.
15-15
: LGTM: Signature change improves testability
The addition of ClaimsPrincipal? user
parameter aligns with the PR objective and makes the authorization more testable. The nullable parameter allows for flexible testing scenarios.
Let's verify that all callers of this method have been updated:
✅ Verification successful
Breaking change has been properly handled
Based on the search results, I can confirm that all callers of the DownloadFileHandler.Process
method have been updated to include the HttpContext.User
parameter. The method is called in:
LegacyFileController.cs
:await handler.Process(new DownloadFileRequest() {...}, HttpContext.User, cancellationToken)
FileTransferController.cs
:await handler.Process(new DownloadFileRequest() {...}, HttpContext.User, cancellationToken)
All instances properly pass the user context from the HTTP context, maintaining the security context throughout the request pipeline.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for any calls to Process method of DownloadFileHandler
ast-grep --pattern 'downloadFileHandler.Process($$$)'
Length of output: 55
Script:
#!/bin/bash
# Let's try a more comprehensive search for Process method calls
# First, search for any reference to DownloadFileHandler
rg -l "DownloadFileHandler"
# Then search for Process method calls with context
rg "\.Process\(" -A 2 -B 2
Length of output: 13717
src/Altinn.Broker.Application/MalwareScanResults/MalwareScanResultHandler.cs (2)
2-2
: LGTM!
The System.Security.Claims import is correctly added to support the new ClaimsPrincipal parameter.
27-27
: Verify consistent parameter usage across handlers.
Let's verify that other handlers in the codebase follow the same pattern of accepting ClaimsPrincipal.
✅ Verification successful
Parameter usage is consistent across all handlers
All handlers in the application consistently follow the same pattern, accepting three parameters:
- A request/data parameter of their specific type
- A nullable
ClaimsPrincipal? user
parameter - A
CancellationToken cancellationToken
parameter
The MalwareScanResultHandler
implementation aligns perfectly with this pattern, using ScanResultData data
as its specific request type along with the common user
and cancellationToken
parameters.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for other handler implementations to verify consistent parameter usage
ast-grep --pattern 'class $_ : IHandler<$_, $_>
{
$$$
Process($$$)
{
$$$
}
}'
Length of output: 91
Script:
#!/bin/bash
# Let's try a different approach to find handler implementations
# First, let's find all files that might contain handlers
fd "Handler.cs$"
# Then let's use ripgrep to find Process method signatures
rg "public.*Task.*Process.*\(" --type cs -A 1
Length of output: 4995
src/Altinn.Broker.Integrations/Altinn/Authorization/AltinnAuthorizationService.cs (2)
25-32
: LGTM: Constructor changes align with PR objectives
The removal of IHttpContextAccessor
dependency makes the service more testable by eliminating the HTTP context dependency. All remaining dependencies are properly initialized.
34-34
: Verify updates to all service consumers
The signature change from using IHttpContextAccessor
to accepting ClaimsPrincipal
directly requires updates to all calling code.
Let's verify all callers have been updated:
✅ Verification successful
Based on the search results, I can generate the final response as I have enough information to verify the changes. The results show all usages of both the concrete AltinnAuthorizationService
and the IAuthorizationService
interface across the codebase.
All service consumers properly updated to use the new signature
The verification shows that all consumers have been correctly updated to work with the new signature that accepts ClaimsPrincipal
directly:
- All handlers (InitializeFileTransfer, UploadFile, GetFileTransfers, etc.) are injecting
IAuthorizationService
and passing the user context explicitly - The test mock in
CustomWebApplicationFactory.cs
correctly sets up the new signature - No instances found of direct
HttpContextAccessor
usage with this service
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for direct usage of AltinnAuthorizationService
rg -l "AltinnAuthorizationService" | while read -r file; do
echo "=== $file ==="
# Show context of service usage
rg -B 2 -A 2 "AltinnAuthorizationService" "$file"
done
# Search for interface usage
rg -l "IAuthorizationService" | while read -r file; do
echo "=== $file ==="
# Show context of service usage
rg -B 2 -A 2 "IAuthorizationService" "$file"
done
Length of output: 9998
src/Altinn.Broker.Application/InitializeFileTransfer/InitializeFileTransferHandler.cs (4)
1-2
: LGTM!
The addition of the ClaimsPrincipal import is necessary for the new user context parameter.
Line range hint 36-40
: LGTM! Authorization check properly uses the passed user context.
The authorization check correctly utilizes the explicit user parameter while maintaining the appropriate access level verification and error handling.
33-33
: LGTM! Verify interface implementation across the codebase.
The nullable ClaimsPrincipal parameter aligns with the PR objective of improving testability. This change allows for explicit user context passing while maintaining backward compatibility.
#!/bin/bash
# Verify that all implementations of IHandler have been updated with the new signature
ast-grep --pattern 'class $_ : IHandler<$_, $_>
{
$$$
Process($_, ClaimsPrincipal? user, $_)
{
$$$
}
}'
79-79
: Verify the design decision for expiration job authorization.
The expiration job is scheduled with a null user context. While this is typically acceptable for system operations, please verify that:
- The expiration process is designed to run with system privileges
- No user-specific authorization is required during expiration
✅ Verification successful
Passing null user context for expiration job is correct by design
The ExpireFileTransferHandler implementation shows that while it accepts a ClaimsPrincipal parameter, it doesn't perform any authorization checks. This aligns with the design where file expiration is a system-level operation that runs independently of user context. Other handlers like InitializeFileTransferHandler and ConfirmDownloadHandler do perform explicit user access checks, but expiration intentionally does not.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check if ExpireFileTransferHandler requires user context in its authorization checks
ast-grep --pattern 'class ExpireFileTransferHandler
{
$$$
Process($_, ClaimsPrincipal? user, $_)
{
$$$
CheckUserAccess($$$)
$$$
}
}'
Length of output: 280
Script:
#!/bin/bash
# Search for ExpireFileTransferHandler implementation
rg -A 10 "class ExpireFileTransferHandler"
# Search for any authorization checks in files containing ExpireFileTransfer
rg -l "ExpireFileTransfer" | xargs rg "CheckUserAccess|Authorize|ClaimsPrincipal"
Length of output: 3479
src/Altinn.Broker.Application/ExpireFileTransfer/ExpireFileTransferHandler.cs (2)
1-1
: LGTM: Appropriate namespace addition
The addition of System.Security.Claims aligns with the PR objective of making the service more testable by passing ClaimsPrincipal as an argument.
25-25
: Verify authorization requirements for file expiration
The ClaimsPrincipal? user
parameter has been added but isn't utilized within the method. Consider whether authorization checks should be implemented to ensure only authorized users can expire file transfers.
Let's check if other handlers implement authorization checks:
tests/Altinn.Broker.Tests/Helpers/CustomWebApplicationFactory.cs (2)
3-3
: LGTM: Required import for ClaimsPrincipal
The addition of the System.Security.Claims import is necessary to support the updated IAuthorizationService interface.
103-104
: LGTM: Mock setup correctly handles the new ClaimsPrincipal parameter
The mock setup has been properly updated to accommodate the new ClaimsPrincipal parameter while maintaining existing test behavior. Consider adding specific test cases that verify authorization with different types of claims.
Let's verify if there are test cases that exercise different claim scenarios:
src/Altinn.Broker.Application/ConfigureResource/ConfigureResourceHandler.cs (2)
1-1
: LGTM: Required import for ClaimsPrincipal
The addition of System.Security.Claims import is necessary and correctly placed.
Line range hint 23-27
: Consider enhancing authorization with claims-based checks
The current authorization check only verifies resource.ServiceOwnerId
against request.Token.Consumer
. Since we now have access to user claims, consider enhancing this with additional claims-based authorization checks.
Consider adding claims validation:
if (resource.ServiceOwnerId != request.Token.Consumer)
{
return Errors.NoAccessToResource;
};
+if (user?.HasClaim(c => c.Type == "resource-access" &&
+ c.Value == resource.ServiceOwnerId) != true)
+{
+ return Errors.InsufficientPermissions;
+}
Let's check if similar patterns exist in other handlers:
#!/bin/bash
# Search for existing claims-based authorization patterns
rg -A 5 "HasClaim|GetClaim"
src/Altinn.Broker.API/Controllers/LegacyFileController.cs (1)
48-48
: Verify the relationship between CallerIdentity and ClaimsPrincipal
The method now passes both legacyToken
and HttpContext.User
to the handler. While this aligns with making the authorization service more testable, we should verify that these two authentication contexts are properly coordinated.
✅ Verification successful
Based on the search results, I can now provide a final response as the relationship between CallerIdentity and ClaimsPrincipal is clear:
Passing both CallerIdentity and ClaimsPrincipal is intentional and correct
The code shows a clear separation of concerns where:
CallerIdentity
is used for legacy token-based authentication, created byMaskinportenModelBinder
from bearer tokensClaimsPrincipal
is passed to handlers which useIAuthorizationService
to perform resource-based authorization checks- The
LegacyFileController
creates a newlegacyToken
from the original token while preserving the authorization context throughHttpContext.User
This pattern enables:
- Backward compatibility through the legacy token system
- Modern authorization checks via the
IAuthorizationService
- Proper testability of the authorization service as intended by the PR
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for any validation or mapping between CallerIdentity and ClaimsPrincipal
rg -g "!*.{json,md,csproj}" -B 3 -A 3 "CallerIdentity.*ClaimsPrincipal|ClaimsPrincipal.*CallerIdentity"
# Search for handler implementations to understand how both contexts are used
ast-grep --pattern 'class $_ : $handler {
$$$
Process($_, ClaimsPrincipal $_, $_) {
$$$
}
}'
Length of output: 210
Script:
#!/bin/bash
# Let's try a different approach to understand the authorization flow
# First, search for CallerIdentity usage
rg -g "!*.{json,md,csproj}" -B 3 -A 3 "CallerIdentity"
# Look for Process method implementations in handlers
rg -g "!*.{cs}" -B 5 -A 5 "public.*async.*Process.*ClaimsPrincipal"
# Search for any authorization-related services or utilities
rg -g "!*.{json,md,csproj}" -B 3 -A 3 "IAuthorizationService|AuthorizationService"
Length of output: 40314
src/Altinn.Broker.API/Controllers/FileTransferController.cs (3)
86-86
: LGTM! Consistent with authorization pattern
The change maintains the security checks while improving testability through explicit user context passing.
155-155
: LGTM! Consistent authorization pattern across query operations
The changes consistently apply the pattern of passing user context to handlers across all query operations, improving testability while maintaining proper authorization checks.
Also applies to: 181-181, 215-215, 241-241
48-48
: LGTM! Verify handler's user parameter usage
The change improves testability by explicitly passing HttpContext.User to the handler. This makes the authorization flow more transparent and easier to test.
✅ Verification successful
Verified: User parameter is properly utilized for authorization
Looking at the InitializeFileTransferHandler.Process
implementation, the ClaimsPrincipal user
parameter is correctly used for authorization through the resourceRightsRepository.CheckUserAccess
method. The handler validates user access rights before proceeding with the file transfer initialization, which aligns with security best practices.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Verify that the InitializeFileTransferHandler properly uses the user parameter
ast-grep --pattern 'class InitializeFileTransferHandler {
$$$
Process($_, ClaimsPrincipal $_, $_) {
$$$
}
$$$
}'
Length of output: 126
Script:
#!/bin/bash
# Let's try a different approach to find the handler implementation
rg -l "InitializeFileTransferHandler" --type cs
# Then search for Process method implementation
rg "Process.*ClaimsPrincipal.*CancellationToken" --type cs -A 5
Length of output: 10627
src/Altinn.Broker.Application/ConfirmDownload/ConfirmDownloadHandler.cs (1)
92-95
: Handle user
parameter consistently in scheduled jobs
In the scheduled job, user
is passed as null
:
backgroundJobClient.Schedule<ExpireFileTransferHandler>((expireFileTransferHandler) => expireFileTransferHandler.Process(new ExpireFileTransferRequest
{
FileTransferId = request.FileTransferId,
Force = true
}, null, cancellationToken), DateTime.UtcNow.Add(gracePeriod));
This inconsistency with the previous Enqueue
call could lead to confusion or errors if ExpireFileTransferHandler.Process
expects a non-null user
.
Ensure that ExpireFileTransferHandler.Process
properly handles a null user
, and consider standardizing how user
is passed to background jobs.
If user
is not necessary for the ExpireFileTransferHandler
, you might refactor the method signature to omit user
.
src/Altinn.Broker.Application/UploadFile/UploadFileHandler.cs (1)
1-2
: Approved: Added necessary using directive
The addition of using System.Security.Claims;
is appropriate for utilizing ClaimsPrincipal
in the code.
Description
Pass ClaimsPrincipal as argument instead of HttpContextAccessor to make code cleaner and easier to test
Related Issue(s)
Verification
Documentation
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Refactor
Tests