AuthorizationFilterHelper
The AuthorizationFilterHelper class generates JOOQ Condition objects from the constraints in the x-cwms-auth-context header for use in database queries.
Package: cwms.cda.helpers
Source: cwms-data-api/src/main/java/cwms/cda/helpers/AuthorizationFilterHelper.java
Purpose
This helper class translates authorization constraints into database query conditions. It:
Parses constraints from the authorization context header
Generates JOOQ conditions for office-based filtering
Applies embargo rules based on time restrictions
Enforces time window limitations
Filters by data classification levels
Constructors
From Javalin Context
public AuthorizationFilterHelper(io.javalin.http.Context ctx)
Creates a helper by extracting constraints from the x-cwms-auth-context header.
Parameters:
Parameter |
Type |
Description |
|---|---|---|
|
|
The Javalin request context |
Behavior:
If authorization is disabled via
AuthorizationContextHelper.isEnabled(), constraints are nullIf header is missing or invalid, constraints are null
All filter methods return
DSL.noCondition()when constraints are null
From JsonNode
public AuthorizationFilterHelper(JsonNode constraints)
Creates a helper from a pre-parsed constraints JSON node.
Parameters:
Parameter |
Type |
Description |
|---|---|---|
|
|
Parsed constraints object |
Status Method
hasAuthorizationContext
public boolean hasAuthorizationContext()
Returns whether authorization constraints are present.
Returns: true if constraints were successfully parsed
Filter Methods
getOfficeFilter
public Condition getOfficeFilter(Field<String> officeField, String requestedOffice)
Generates a condition to filter results by allowed offices.
Parameters:
Parameter |
Type |
Description |
|---|---|---|
|
|
The JOOQ field representing the office column |
|
|
The specific office requested (may be null) |
Returns: JOOQ Condition object
Behavior:
Scenario |
Returned Condition |
|---|---|
No constraints |
|
No |
|
|
|
|
|
|
|
|
|
No |
|
getEmbargoFilter
public Condition getEmbargoFilter(
Field<Timestamp> timestampField,
Field<String> officeField,
String requestedOffice
)
Generates a condition to filter out embargoed data. Embargo rules restrict access to data newer than a specified number of hours.
Parameters:
Parameter |
Type |
Description |
|---|---|---|
|
|
The JOOQ field representing the timestamp column |
|
|
The JOOQ field representing the office column |
|
|
The specific office being queried |
Returns: JOOQ Condition object
Behavior:
Scenario |
Returned Condition |
|---|---|
No constraints |
|
|
|
No |
|
Office-specific rule exists |
|
Default rule exists |
|
The cutoff timestamp is calculated as: now - embargo_hours
For example, with a 168-hour embargo (7 days), users can only see data older than 7 days.
getTsGroupEmbargoFilter
public Condition getTsGroupEmbargoFilter(
Field<Timestamp> timestampField,
String tsGroupId
)
Generates a condition to filter embargoed data based on time series group.
Parameters:
Parameter |
Type |
Description |
|---|---|---|
|
|
The JOOQ field representing the timestamp column |
|
|
The time series group identifier |
Returns: JOOQ Condition object
Behavior:
Scenario |
Returned Condition |
|---|---|
No constraints |
|
|
|
No |
|
Group has 0 hours |
|
Group-specific rule exists |
|
Group not in rules |
|
getTsGroupEmbargoHours
public int getTsGroupEmbargoHours(String tsGroupId)
Returns the embargo duration in hours for a specific time series group.
Parameters:
Parameter |
Type |
Description |
|---|---|---|
|
|
The time series group identifier |
Returns: Number of embargo hours (0 if no embargo applies)
getTimeWindowFilter
public Condition getTimeWindowFilter(
Field<Timestamp> timestampField,
Timestamp userRequestedBeginTime
)
Generates a condition to restrict data to a recent time window. Unlike embargo rules (which hide recent data), time window rules limit how far back users can query.
Parameters:
Parameter |
Type |
Description |
|---|---|---|
|
|
The JOOQ field representing the timestamp column |
|
|
The begin time requested by the user (may be null) |
Returns: JOOQ Condition object
Behavior:
Scenario |
Returned Condition |
|---|---|
No constraints |
|
No |
|
No |
|
User time within window |
|
User time before window |
|
No user time specified |
|
For example, with an 8-hour time window, a dam operator can only see data from the last 8 hours.
getClassificationFilter
public Condition getClassificationFilter(Field<String> classificationField)
Generates a condition to filter by data classification level.
Parameters:
Parameter |
Type |
Description |
|---|---|---|
|
|
The JOOQ field representing the classification column |
Returns: JOOQ Condition object
Behavior:
Scenario |
Returned Condition |
|---|---|
No constraints |
|
No |
|
Empty classification list |
|
Has allowed classifications |
|
Note: Records with null classification are included when classification filtering is active.
getAllFilters
public Condition getAllFilters(
Field<String> officeField,
Field<Timestamp> timestampField,
Field<String> classificationField,
String requestedOffice,
Timestamp userRequestedBeginTime
)
Combines all filter types into a single condition using AND logic.
Parameters:
Parameter |
Type |
Description |
|---|---|---|
|
|
The JOOQ field for office |
|
|
The JOOQ field for timestamp |
|
|
The JOOQ field for classification (may be null) |
|
|
The specific office being queried |
|
|
The begin time requested by the user |
Returns: Combined JOOQ Condition object
Behavior:
Returns
noCondition()if no constraints are presentCombines office, embargo, time window, and classification filters with AND
Skips classification filter if
classificationFieldis null
Usage Examples
Basic Query Filtering
AuthorizationFilterHelper filterHelper = new AuthorizationFilterHelper(ctx);
SelectConditionStep<Record> query = dsl.selectFrom(TIMESERIES)
.where(filterHelper.getOfficeFilter(TIMESERIES.OFFICE_ID, requestedOffice));
Combined Filters
AuthorizationFilterHelper filterHelper = new AuthorizationFilterHelper(ctx);
Condition authFilters = filterHelper.getAllFilters(
TIMESERIES.OFFICE_ID,
TIMESERIES.DATE_TIME,
TIMESERIES.CLASSIFICATION,
requestedOffice,
beginTime
);
List<TimeSeriesRecord> results = dsl.selectFrom(TIMESERIES)
.where(authFilters)
.and(otherConditions)
.fetch();
Selective Filter Application
AuthorizationFilterHelper filterHelper = new AuthorizationFilterHelper(ctx);
Condition baseCondition = LOCATIONS.OFFICE_ID.eq(office);
if (filterHelper.hasAuthorizationContext()) {
Condition officeFilter = filterHelper.getOfficeFilter(LOCATIONS.OFFICE_ID, office);
baseCondition = baseCondition.and(officeFilter);
}
List<LocationRecord> locations = dsl.selectFrom(LOCATIONS)
.where(baseCondition)
.fetch();
Embargo with Time Series Groups
AuthorizationFilterHelper filterHelper = new AuthorizationFilterHelper(ctx);
String tsGroupId = determineTimeSeriesGroup(timeSeriesId);
Condition embargoFilter = filterHelper.getTsGroupEmbargoFilter(
TIMESERIES_VALUES.DATE_TIME,
tsGroupId
);
List<TimeSeriesValue> values = dsl.selectFrom(TIMESERIES_VALUES)
.where(TIMESERIES_VALUES.TS_CODE.eq(tsCode))
.and(embargoFilter)
.fetch();
Checking Embargo Duration
AuthorizationFilterHelper filterHelper = new AuthorizationFilterHelper(ctx);
int embargoHours = filterHelper.getTsGroupEmbargoHours("Reservoir-Levels");
if (embargoHours > 0) {
logger.info("Data embargoed for {} hours", embargoHours);
}
Expected Constraints Format
The helper expects the constraints object in the authorization context to have this structure:
{
"allowed_offices": ["SWT", "SPK"],
"embargo_rules": {
"SPK": 168,
"SWT": 72,
"default": 168
},
"ts_group_embargo": {
"Reservoir-Levels": 24,
"Stream-Flow": 48
},
"embargo_exempt": false,
"time_window": {
"restrict_hours": 8
},
"data_classification": ["public", "internal"]
}
Field |
Type |
Description |
|---|---|---|
|
array |
Office codes user can access, or |
|
object |
Hours of recent data to hide per office |
|
number |
Default embargo hours when office not specified |
|
object |
Hours of recent data to hide per TS group |
|
boolean |
If true, embargo rules do not apply |
|
number |
Only show data from last N hours |
|
array |
Classification levels user can access |
JOOQ Condition Reference
Condition |
Effect |
|---|---|
|
No filtering (all rows pass) |
|
Block all rows |
|
Exact match |
|
Match any in list |
|
Before timestamp (for embargo) |
|
After timestamp (for time window) |
|
All conditions must pass |
|
Any condition must pass |