-
Notifications
You must be signed in to change notification settings - Fork 569
SMART on FHIR Token Introspection Endpoint #5257
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
base: main
Are you sure you want to change the base?
SMART on FHIR Token Introspection Endpoint #5257
Conversation
src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Controllers/TokenIntrospectionControllerTests.cs
Fixed
Show fixed
Hide fixed
src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Controllers/TokenIntrospectionControllerTests.cs
Fixed
Show fixed
Hide fixed
src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Controllers/TokenIntrospectionControllerTests.cs
Fixed
Show fixed
Hide fixed
src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Controllers/TokenIntrospectionControllerTests.cs
Fixed
Show fixed
Hide fixed
src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Controllers/TokenIntrospectionControllerTests.cs
Fixed
Show fixed
Hide fixed
src/Microsoft.Health.Fhir.Shared.Api/Controllers/TokenIntrospectionController.cs
Fixed
Show fixed
Hide fixed
src/Microsoft.Health.Fhir.Shared.Api/Controllers/TokenIntrospectionController.cs
Fixed
Show fixed
Hide fixed
src/Microsoft.Health.Fhir.Shared.Api/Controllers/TokenIntrospectionController.cs
Fixed
Show fixed
Hide fixed
src/Microsoft.Health.Fhir.Shared.Api/Controllers/TokenIntrospectionController.cs
Fixed
Show fixed
Hide fixed
src/Microsoft.Health.Fhir.Shared.Api/Controllers/TokenIntrospectionController.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.Health.Fhir.Api/Features/Security/DefaultTokenIntrospectionService.cs
Show resolved
Hide resolved
src/Microsoft.Health.Fhir.Api/Features/Security/DefaultTokenIntrospectionService.cs
Show resolved
Hide resolved
src/Microsoft.Health.Fhir.Api/Features/Security/DefaultTokenIntrospectionService.cs
Show resolved
Hide resolved
src/Microsoft.Health.Fhir.Api/Features/Security/DefaultTokenIntrospectionService.cs
Fixed
Show fixed
Hide fixed
…d improve logging
…ment and enhance assertions
test/Microsoft.Health.Fhir.Shared.Tests.E2E/Rest/TokenIntrospectionTests.cs
Fixed
Show fixed
Hide fixed
test/Microsoft.Health.Fhir.Shared.Tests.E2E/Rest/TokenIntrospectionTests.cs
Fixed
Show fixed
Hide fixed
test/Microsoft.Health.Fhir.Shared.Tests.E2E/Rest/TokenIntrospectionTests.cs
Fixed
Show fixed
Hide fixed
test/Microsoft.Health.Fhir.Shared.Tests.E2E/Rest/TokenIntrospectionTests.cs
Fixed
Show fixed
Hide fixed
test/Microsoft.Health.Fhir.Shared.Tests.E2E/Rest/TokenIntrospectionTests.cs
Fixed
Show fixed
Hide fixed
test/Microsoft.Health.Fhir.Shared.Tests.E2E/Rest/TokenIntrospectionTests.cs
Fixed
Show fixed
Hide fixed
test/Microsoft.Health.Fhir.Shared.Tests.E2E/Rest/TokenIntrospectionTests.cs
Fixed
Show fixed
Hide fixed
test/Microsoft.Health.Fhir.Shared.Tests.E2E/Rest/TokenIntrospectionTests.cs
Fixed
Show fixed
Hide fixed
test/Microsoft.Health.Fhir.Shared.Tests.E2E/Rest/TokenIntrospectionTests.cs
Fixed
Show fixed
Hide fixed
test/Microsoft.Health.Fhir.Shared.Tests.E2E/Rest/TokenIntrospectionTests.cs
Fixed
Show fixed
Hide fixed
Updated `DefaultTokenIntrospectionService` to use `IHttpClientFactory` for managing `HttpClient` instances and initialized a shared `ConfigurationManager` for OpenID Connect configurations. Removed inline `ConfigurationManager` instantiation in token validation logic for consistency. Enhanced `TokenIntrospectionControllerTests` by mocking `IHttpClientFactory` with `NSubstitute` to support the updated service constructor. Refactored `TokenIntrospectionTests` to improve handling of unauthenticated requests, added skipping logic for in-process test servers, and leveraged existing test infrastructure. Removed `[Consumes]` attribute from `TokenIntrospectionController` to simplify content type handling. Replaced synchronous calls with asynchronous token validation to align with best practices. Added logging and validation for `httpClientFactory` dependency. Updated namespaces across files to support new functionality.
The test `GivenContentTypeNotFormEncoded_WhenIntrospecting_ThenReturnsUnsupportedMediaType` was removed from `TokenIntrospectionTests.cs`. This test validated that the introspection endpoint returned `UnsupportedMediaType` when the content type was not `application/x-www-form-urlencoded` (per RFC 7662). Its removal suggests that this behavior is no longer relevant or required in the codebase. Other tests, such as `GivenMultipleValidTokens_WhenIntrospecting_ThenEachReturnsCorrectClaims`, remain unchanged.
src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Controllers/TokenIntrospectionControllerTests.cs
Fixed
Show fixed
Hide fixed
test/Microsoft.Health.Fhir.Shared.Tests.E2E/Rest/TokenIntrospectionTests.cs
Fixed
Show fixed
Hide fixed
Refactored `ValidateFormatParametersAttribute` to improve modularity by introducing `ShouldIgnoreValidation` for skipping validation on specific paths (e.g., `/CustomError`). Enhanced `Content-Type` validation for `POST`, `PUT`, and `PATCH` requests with better error handling for unsupported or missing headers.
Updated `TokenIntrospectionController` to remove the `[Authorize]` attribute, allowing unauthenticated access to `/connect/introspect`. Added `[Consumes("application/x-www-form-urlencoded")]` to specify the expected content type.
Removed a skipped test case and related code in `TokenIntrospectionTests` that validated unauthorized access to the token introspection endpoint, aligning with the updated authentication behavior.
test/Microsoft.Health.Fhir.Shared.Tests.E2E/Rest/TokenIntrospectionTests.cs
Fixed
Show fixed
Hide fixed
…token introspection test content handling
6b7008b to
5b23a53
Compare
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
…oved clarity and maintainability
…on local IDisposable Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Switch to TryGetValue for safer JSON field access in TokenIntrospectionTests, replacing ContainsKey/indexer usage. Also remove the unused _testFhirClient field for code clarity.
Maintain and dispose HttpClient instance in tests to ensure proper resource management. The mock IHttpClientFactory now returns a dedicated HttpClient, which is disposed of in the test class's Dispose method.
| 'app_globalReaderUserApp_secret': $(app_globalReaderUserApp_secret) | ||
| 'app_globalWriterUserApp_id': $(app_globalWriterUserApp_id) | ||
| 'app_globalWriterUserApp_secret': $(app_globalWriterUserApp_secret) | ||
| 'app_smartUserClient_id': $(app_smartUserClient_id) |
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.
needed for E2E tests that use SMART client
| serviceName = $webAppName | ||
| keyVaultName = "${{ parameters.keyVaultName }}".ToLower() | ||
| securityAuthenticationAuthority = "https://login.microsoftonline.com/$(tenant-id)" | ||
| securityAuthenticationAuthority = "https://sts.windows.net/$(tenant-id-guid)" |
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.
Our test env has been using an invalid authority for ... not sure how long. I reuse the authority in the OSS service to check the token so I had to fix the authority.
| // If the request is a put or post and has a content-type, check that it's supported | ||
| if (httpContext.Request.Method.Equals(HttpMethod.Post.Method, StringComparison.OrdinalIgnoreCase) || | ||
| httpContext.Request.Method.Equals(HttpMethod.Put.Method, StringComparison.OrdinalIgnoreCase)) | ||
| if (!ShouldIgnoreValidation(httpContext)) |
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.
This avoids format validation on token introspection endpoints
| /// Default implementation of token introspection for OSS (single authority/audience). | ||
| /// PaaS can extend this class and override ValidateToken() to support multiple authorities. | ||
| /// </summary> | ||
| public class DefaultTokenIntrospectionService : ITokenIntrospectionService |
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.
Note - this service can be overriden downstream for token validation
| // Create mock HttpClientFactory that returns HttpClient for named client | ||
| var httpClientFactory = Substitute.For<IHttpClientFactory>(); | ||
| httpClientFactory.CreateClient(DefaultTokenIntrospectionService.OidcConfigurationHttpClientName) | ||
| .Returns(new HttpClient()); |
Check warning
Code scanning / CodeQL
Missing Dispose call on local IDisposable Warning
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 2 days ago
To fix the problem, ensure that the instantiated HttpClient object in the test setup is disposed of properly. Since it is registered as the return value for the substitute's CreateClient method and potentially used throughout the life of the TokenIntrospectionControllerTests test class, the best solution is to store the HttpClient instance in a field, and dispose of it in the test class's Dispose() method (since the class already implements IDisposable).
Make the following changes in src/Microsoft.Health.Fhir.Shared.Api.UnitTests/Controllers/TokenIntrospectionControllerTests.cs:
- Add a private field to hold the created
HttpClient. - In the constructor, assign the new
HttpClientto this field, and return it from the substitute as currently. - Implement or modify the
Dispose()method of the test class so it disposes the field if it is not null.
No new imports are needed, as HttpClient and IDisposable are already imported.
-
Copy modified line R40 -
Copy modified line R67 -
Copy modified line R69 -
Copy modified lines R410-R414
| @@ -37,6 +37,7 @@ | ||
| private readonly SigningCredentials _signingCredentials; | ||
| private readonly string _issuer = "https://test-issuer.com"; | ||
| private readonly string _audience = "test-audience"; | ||
| private readonly HttpClient _httpClient; | ||
|
|
||
| public TokenIntrospectionControllerTests() | ||
| { | ||
| @@ -63,8 +64,9 @@ | ||
|
|
||
| // Create mock HttpClientFactory that returns HttpClient for named client | ||
| var httpClientFactory = Substitute.For<IHttpClientFactory>(); | ||
| _httpClient = new HttpClient(); | ||
| httpClientFactory.CreateClient(DefaultTokenIntrospectionService.OidcConfigurationHttpClientName) | ||
| .Returns(new HttpClient()); | ||
| .Returns(_httpClient); | ||
|
|
||
| // Create introspection service | ||
| _introspectionService = new DefaultTokenIntrospectionService( | ||
| @@ -406,5 +407,10 @@ | ||
| { | ||
| _rsa?.Dispose(); | ||
| } | ||
| public void Dispose() | ||
| { | ||
| _httpClient?.Dispose(); | ||
| _rsa?.Dispose(); | ||
| } | ||
| } | ||
| } |
Description
Implements RFC 7662 token introspection endpoint at /connect/introspect for SMART on FHIR server with swapple support for the introspection endpoint for alternate SMART configurations.
Key Features:
Related issues
Addresses AB#174822
Testing
Test Coverage:
FHIR Team Checklist
Semver Change (docs)
Patch|Skip|Feature|Breaking (reason)