Revert "feat(auth): Add support for Regional Access Boundaries"#13554
Conversation
This reverts commit b721e43.
There was a problem hiding this comment.
Code Review
This pull request completely removes the Regional Access Boundary (RAB) feature and its associated classes, methods, and tests across the entire library. Feedback on the remaining changes includes an optimization opportunity in GoogleCredentials.java to avoid copying the request metadata map when no modification is needed, and a warning regarding a potential timezone bug reintroduced in TestUtils.java due to the simplified date formatting.
| static Map<String, List<String>> addQuotaProjectIdToRequestMetadata( | ||
| String quotaProjectId, Map<String, List<String>> requestMetadata) { | ||
| Preconditions.checkNotNull(requestMetadata); | ||
| Map<String, List<String>> newRequestMetadata = new HashMap<>(requestMetadata); | ||
| if (quotaProjectId != null && !requestMetadata.containsKey(QUOTA_PROJECT_ID_HEADER_KEY)) { | ||
| return ImmutableMap.<String, List<String>>builder() | ||
| .putAll(requestMetadata) | ||
| .put(QUOTA_PROJECT_ID_HEADER_KEY, Collections.singletonList(quotaProjectId)) | ||
| .build(); | ||
| } | ||
| return requestMetadata; | ||
| } | ||
|
|
||
| /** | ||
| * Adds Regional Access Boundary header to requestMetadata if available. Overwrites if present. If | ||
| * the current RAB is null, it removes any stale header that might have survived serialization. | ||
| * | ||
| * @param uri The URI of the request. | ||
| * @param requestMetadata The request metadata. | ||
| * @return a new map with Regional Access Boundary header added, updated, or removed | ||
| */ | ||
| Map<String, List<String>> addRegionalAccessBoundaryToRequestMetadata( | ||
| URI uri, Map<String, List<String>> requestMetadata) { | ||
| Preconditions.checkNotNull(requestMetadata); | ||
|
|
||
| if (uri != null && uri.getHost() != null) { | ||
| String host = uri.getHost(); | ||
| if (host.endsWith(".rep.googleapis.com") || host.endsWith(".rep.sandbox.googleapis.com")) { | ||
| return requestMetadata; | ||
| } | ||
| newRequestMetadata.put( | ||
| QUOTA_PROJECT_ID_HEADER_KEY, Collections.singletonList(quotaProjectId)); | ||
| } | ||
|
|
||
| RegionalAccessBoundary rab = getRegionalAccessBoundary(); | ||
| if (rab != null) { | ||
| // Overwrite the header to ensure the most recent async update is used, | ||
| // preventing staleness if the token itself hasn't expired yet. | ||
| Map<String, List<String>> newMetadata = new HashMap<>(requestMetadata); | ||
| newMetadata.put( | ||
| RegionalAccessBoundary.X_ALLOWED_LOCATIONS_HEADER_KEY, | ||
| Collections.singletonList(rab.getEncodedLocations())); | ||
| return ImmutableMap.copyOf(newMetadata); | ||
| } else if (requestMetadata.containsKey(RegionalAccessBoundary.X_ALLOWED_LOCATIONS_HEADER_KEY)) { | ||
| // If RAB is null but the header exists (e.g., from a serialized cache), we must strip it | ||
| // to prevent sending stale data to the server. | ||
| Map<String, List<String>> newMetadata = new HashMap<>(requestMetadata); | ||
| newMetadata.remove(RegionalAccessBoundary.X_ALLOWED_LOCATIONS_HEADER_KEY); | ||
| return ImmutableMap.copyOf(newMetadata); | ||
| } | ||
| return requestMetadata; | ||
| return Collections.unmodifiableMap(newRequestMetadata); | ||
| } |
There was a problem hiding this comment.
The current implementation of addQuotaProjectIdToRequestMetadata copies the requestMetadata map into a new HashMap and wraps it in an unmodifiable map on every call, even when quotaProjectId is null or the key is already present. We can optimize this by checking the condition first and only copying the map when a modification is actually required.
| static Map<String, List<String>> addQuotaProjectIdToRequestMetadata( | |
| String quotaProjectId, Map<String, List<String>> requestMetadata) { | |
| Preconditions.checkNotNull(requestMetadata); | |
| Map<String, List<String>> newRequestMetadata = new HashMap<>(requestMetadata); | |
| if (quotaProjectId != null && !requestMetadata.containsKey(QUOTA_PROJECT_ID_HEADER_KEY)) { | |
| return ImmutableMap.<String, List<String>>builder() | |
| .putAll(requestMetadata) | |
| .put(QUOTA_PROJECT_ID_HEADER_KEY, Collections.singletonList(quotaProjectId)) | |
| .build(); | |
| } | |
| return requestMetadata; | |
| } | |
| /** | |
| * Adds Regional Access Boundary header to requestMetadata if available. Overwrites if present. If | |
| * the current RAB is null, it removes any stale header that might have survived serialization. | |
| * | |
| * @param uri The URI of the request. | |
| * @param requestMetadata The request metadata. | |
| * @return a new map with Regional Access Boundary header added, updated, or removed | |
| */ | |
| Map<String, List<String>> addRegionalAccessBoundaryToRequestMetadata( | |
| URI uri, Map<String, List<String>> requestMetadata) { | |
| Preconditions.checkNotNull(requestMetadata); | |
| if (uri != null && uri.getHost() != null) { | |
| String host = uri.getHost(); | |
| if (host.endsWith(".rep.googleapis.com") || host.endsWith(".rep.sandbox.googleapis.com")) { | |
| return requestMetadata; | |
| } | |
| newRequestMetadata.put( | |
| QUOTA_PROJECT_ID_HEADER_KEY, Collections.singletonList(quotaProjectId)); | |
| } | |
| RegionalAccessBoundary rab = getRegionalAccessBoundary(); | |
| if (rab != null) { | |
| // Overwrite the header to ensure the most recent async update is used, | |
| // preventing staleness if the token itself hasn't expired yet. | |
| Map<String, List<String>> newMetadata = new HashMap<>(requestMetadata); | |
| newMetadata.put( | |
| RegionalAccessBoundary.X_ALLOWED_LOCATIONS_HEADER_KEY, | |
| Collections.singletonList(rab.getEncodedLocations())); | |
| return ImmutableMap.copyOf(newMetadata); | |
| } else if (requestMetadata.containsKey(RegionalAccessBoundary.X_ALLOWED_LOCATIONS_HEADER_KEY)) { | |
| // If RAB is null but the header exists (e.g., from a serialized cache), we must strip it | |
| // to prevent sending stale data to the server. | |
| Map<String, List<String>> newMetadata = new HashMap<>(requestMetadata); | |
| newMetadata.remove(RegionalAccessBoundary.X_ALLOWED_LOCATIONS_HEADER_KEY); | |
| return ImmutableMap.copyOf(newMetadata); | |
| } | |
| return requestMetadata; | |
| return Collections.unmodifiableMap(newRequestMetadata); | |
| } | |
| static Map<String, List<String>> addQuotaProjectIdToRequestMetadata( | |
| String quotaProjectId, Map<String, List<String>> requestMetadata) { | |
| Preconditions.checkNotNull(requestMetadata); | |
| if (quotaProjectId != null && !requestMetadata.containsKey(QUOTA_PROJECT_ID_HEADER_KEY)) { | |
| Map<String, List<String>> newRequestMetadata = new HashMap<>(requestMetadata); | |
| newRequestMetadata.put( | |
| QUOTA_PROJECT_ID_HEADER_KEY, Collections.singletonList(quotaProjectId)); | |
| return Collections.unmodifiableMap(newRequestMetadata); | |
| } | |
| return requestMetadata; | |
| } |
| Calendar calendar = Calendar.getInstance(); | ||
| calendar.setTime(new Date()); | ||
| calendar.add(Calendar.SECOND, 300); | ||
| SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); | ||
| dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); | ||
| return dateFormat.format(calendar.getTime()); | ||
| return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(calendar.getTime()); | ||
| } |
There was a problem hiding this comment.
Reverting the timezone setting on SimpleDateFormat reintroduces a timezone bug where the local time is formatted but a literal 'Z' (UTC) is appended, which can cause test failures depending on the system's default timezone. Using java.time.Instant is timezone-safe, cleaner, and avoids using Calendar and SimpleDateFormat entirely.
return java.time.Instant.now().plusSeconds(300).truncatedTo(java.time.temporal.ChronoUnit.SECONDS).toString();
}
Reverts #13499