feat: Add authorization context helpers and server-side filtering for timeseries#1461
Open
feat: Add authorization context helpers and server-side filtering for timeseries#1461
Conversation
…lter generation Add AuthorizationContextHelper and AuthorizationFilterHelper to support fine-grained authorization for CWMS Data API: - AuthorizationContextHelper parses x-cwms-auth-context header and extracts user context (username, offices, roles, persona) - AuthorizationFilterHelper generates JOOQ conditions for server-side filtering: - Office-based filtering (allowed_offices constraint) - Embargo rules (hide recent data by office) - Time window restrictions (limit historical data access) - Data classification filtering (classification levels) Both helpers follow CWMS codebase style with minimal comments and clear naming. All filtering logic generates type-safe JOOQ conditions for database-level enforcement. This infrastructure supports the authorization proxy pattern where OPA makes policy decisions and CWMS Data API enforces them via the authorization context header.
…imeSeriesDaoImpl Integrate authorization helpers into timeseries data retrieval: Controller changes (TimeSeriesController): - Create AuthorizationContextHelper and AuthorizationFilterHelper from request context - Validate office access before querying data (early validation) - Pass AuthorizationFilterHelper to DAO for server-side filtering - Log authorization context for debugging DAO changes (TimeSeriesDaoImpl): - Add method overload accepting AuthorizationFilterHelper parameter - Apply embargo filter to hide recent data based on office-specific rules - Apply time window filter to restrict historical data access - Combine authorization filters with existing filter conditions using JOOQ - All filtering happens at database level via SQL WHERE clauses Backward compatible: Existing methods without authorization filters continue to work unchanged. Authorization filtering only applied when x-cwms-auth-context header is present.
MikeNeilson
reviewed
Nov 13, 2025
Contributor
MikeNeilson
left a comment
There was a problem hiding this comment.
Overall it seems reasonable.
The initial Context helper processing should probably go in ApiServer.java, here:
after the authenticator, and they like the authenticator itself, or what you see on line 360, set a context attributed with the appropriate created object.
cwms-data-api/src/main/java/cwms/cda/helpers/AuthorizationFilterHelper.java
Show resolved
Hide resolved
cwms-data-api/src/main/java/cwms/cda/helpers/AuthorizationFilterHelper.java
Outdated
Show resolved
Hide resolved
| } | ||
|
|
||
| // Add office-specific embargo rules | ||
| if (embargoRulesNode.has("SPK")) { |
Contributor
There was a problem hiding this comment.
it would seem this and below should be one block that uses "requestedOffice" in the has and get methods.
Collaborator
There was a problem hiding this comment.
Do we have a means in the CWMS schema to determine if a given office has embargoRules?
Or is this more of a hold-over?
Contributor
There was a problem hiding this comment.
we still need to sort out exactly how that gets determined and then converted into a policy.
cwms-data-api/src/main/java/cwms/cda/helpers/AuthorizationFilterHelper.java
Outdated
Show resolved
Hide resolved
cwms-data-api/src/main/java/cwms/cda/data/dao/TimeSeriesDaoImpl.java
Outdated
Show resolved
Hide resolved
…ilters * origin: Entity endpoint Controller and Integration test (#1497) Enhancements/blob clob query (#1483) Update treafik for latest docker. (#1493) Bugfix/cda 45 ts vertical datum (#1344) CDA-66: Updated TS identifier descriptor paging (#1481) add in missing expiration date to constant/seasonal levels (#1490) 1351 implement cda gui code formatter (#1460) add missing back tic CWMS Data API documentation /timeseries GET endpoints. (#1476) CDA-60: Accept Header Formatting Documentation (#1463) The temp users set needs to be a LinkedHashSet, otherwise the last user in the list isn't always the last user and the paging doesn't work. Add static analysis unit test for Controller classes (#1362) Bugfix/incorrect parameter warning cda 58 (#1470) Test updates for latest schema and correct release schema image. (#1474) CDA-54 - Implements Entity DTO and Dao (#1482) Update npm pacakges (#1478) Correct required java version (#1462) CDA-40: Exception Handling Implementation Updates (#1358)
- AuthorizationFilterHelper methods now return noCondition() for cleaner downstream logic without null checks - Refactored getEmbargoFilter to use requestedOffice parameter instead of hardcoded office-specific blocks - Simplified getAllFilters by removing null checks - Updated TimeSeriesDaoImpl to pass office parameter and remove null checks
…lter generation Add AuthorizationContextHelper and AuthorizationFilterHelper to support fine-grained authorization for CWMS Data API: - AuthorizationContextHelper parses x-cwms-auth-context header and extracts user context (username, offices, roles, persona) - AuthorizationFilterHelper generates JOOQ conditions for server-side filtering: - Office-based filtering (allowed_offices constraint) - Embargo rules (hide recent data by office) - Time window restrictions (limit historical data access) - Data classification filtering (classification levels) Both helpers follow CWMS codebase style with minimal comments and clear naming. All filtering logic generates type-safe JOOQ conditions for database-level enforcement. This infrastructure supports the authorization proxy pattern where OPA makes policy decisions and CWMS Data API enforces them via the authorization context header.
…imeSeriesDaoImpl Integrate authorization helpers into timeseries data retrieval: Controller changes (TimeSeriesController): - Create AuthorizationContextHelper and AuthorizationFilterHelper from request context - Validate office access before querying data (early validation) - Pass AuthorizationFilterHelper to DAO for server-side filtering - Log authorization context for debugging DAO changes (TimeSeriesDaoImpl): - Add method overload accepting AuthorizationFilterHelper parameter - Apply embargo filter to hide recent data based on office-specific rules - Apply time window filter to restrict historical data access - Combine authorization filters with existing filter conditions using JOOQ - All filtering happens at database level via SQL WHERE clauses Backward compatible: Existing methods without authorization filters continue to work unchanged. Authorization filtering only applied when x-cwms-auth-context header is present.
- AuthorizationFilterHelper methods now return noCondition() for cleaner downstream logic without null checks - Refactored getEmbargoFilter to use requestedOffice parameter instead of hardcoded office-specific blocks - Simplified getAllFilters by removing null checks - Updated TimeSeriesDaoImpl to pass office parameter and remove null checks
* origin/feature/auth-context-and-filters: Return DSL.noCondition() instead of null from filter methods feat: integrate authorization filtering in TimeSeriesController and TimeSeriesDaoImpl feat: add authorization helper classes for header parsing and JOOQ filter generation # Conflicts: # cwms-data-api/src/main/java/cwms/cda/data/dao/TimeSeriesDaoImpl.java
- Convert java.util.logging to Flogger style in controller and DAO - Restore getTimeseries(AuthorizationFilterHelper) in DAO interface and implementation (dropped during auto-merge) - Use public DAO method instead of protected getRequestedTimeSeries
MikeNeilson
previously approved these changes
Feb 11, 2026
…anagement - Remove hardcoded 168-hour embargo defaults from AuthorizationFilterHelper; fall back to no enforcement when TS group is not assigned to user - Fix embargo regex in UserDao to handle both hour (72h) and day (7d) suffixes - Skip TS group privileges query when access management is disabled - Replace wildcard imports with specific imports in UserDao - Remove hardcoded office embargo fallback values from authorization proxy - Add docker-compose.podman.yml for local development with external cwmsdb network - Add persona user groups and TS group authorization setup to users.sql - Add TsGroupPrivilege DTO and wire ts_privileges into User model
- Add @JsonCreator and @JsonProperty to TsGroupPrivilege for Jackson deserialization - Add UserDaoTest covering embargo parsing and privilege bitmask conversion - Add UserTest with serialization round-trip tests following existing DTO patterns - Add AuthorizationContextHelperTest for header parsing and field extraction - Add AuthorizationFilterHelperTest for JOOQ condition generation from constraints - Add Dockerfile.podman for local ARM64 container builds - Update docker-compose.podman.yml for local development environment - Minor updates to TimeSeriesController and TimeSeriesDaoImpl
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add authorization infrastructure to support fine-grained access control for timeseries data:
This implementation supports the authorization proxy pattern where policy decisions are made by OPA and enforcement happens in the CWMS Data API via the authorization context header.
Screenshots
N/A - Backend authorization infrastructure
Todos
Steps to Validate
Start CWMS Data API with authorization proxy:
Test office access validation:
Test embargo filtering (requires OPA policy with embargo rules):
Test time window filtering (requires OPA policy with time_window constraint):
Check logs for filter application:
Verify backward compatibility (requests without authorization header):
Local Environment Notes
Impacted Areas in Application
Notes