[PM-29885] Implement SSO cookie vending authentication flow#6522
[PM-29885] Implement SSO cookie vending authentication flow#6522SaintPatrck merged 5 commits intomainfrom
Conversation
|
New Issues (4)Checkmarx found the following issues in this Pull Request
|
...tlin/com/x8bit/bitwarden/data/platform/manager/util/CookieConfigurationDataExtensionsTest.kt
Dismissed
Show dismissed
Hide dismissed
...tlin/com/x8bit/bitwarden/data/platform/manager/util/CookieConfigurationDataExtensionsTest.kt
Dismissed
Show dismissed
Hide dismissed
...tlin/com/x8bit/bitwarden/data/platform/manager/util/CookieConfigurationDataExtensionsTest.kt
Dismissed
Show dismissed
Hide dismissed
...tlin/com/x8bit/bitwarden/data/platform/manager/util/CookieConfigurationDataExtensionsTest.kt
Dismissed
Show dismissed
Hide dismissed
|
Claude finished @SaintPatrck's task in 4m 45s —— View job Re-Review SummaryPR: PM-29885 Implement SSO cookie vending authentication flow Previous Findings Status
Changes Since Last ReviewTwo new commits were pushed:
Verification
ResultNo new issues found. All previous findings have been properly addressed. The implementation is clean, well-tested, and follows established patterns. Re-reviewed commit range: |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #6522 +/- ##
=======================================
Coverage 86.34% 86.35%
=======================================
Files 791 795 +4
Lines 56717 56781 +64
Branches 8213 8229 +16
=======================================
+ Hits 48971 49031 +60
Misses 4891 4891
- Partials 2855 2859 +4 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
5087f55 to
0dc2bc5
Compare
...rc/main/kotlin/com/x8bit/bitwarden/data/platform/manager/network/NetworkCookieManagerImpl.kt
Outdated
Show resolved
Hide resolved
| // Return the response if it is not a redirect or does not contain | ||
| // a Location header. | ||
| val location = response.header(HEADER_LOCATION) | ||
| if (response.code != HTTP_REDIRECT || location == null) { |
There was a problem hiding this comment.
Should this be an &&?
There was a problem hiding this comment.
Hm. Now that I think about it, we shouldn't need this location check. We should technically already have the IdP login URL saved. Could have swore I saw that in the spec somewhere. 🤔
Let me double check with the other teams and make sure we actually need to check and capture this.
Thanks for calling attention to this.
network/src/main/kotlin/com/bitwarden/network/BitwardenServiceClientImpl.kt
Outdated
Show resolved
Hide resolved
Add cookie interceptor that manages ELB session cookies for enterprise SSO configurations. The interceptor attaches stored cookies to API requests, preempts requests when cookie bootstrap is needed, and detects HTTP 302 redirects to trigger cookie re-acquisition via an identity provider. Key components: - CookieInterceptor for OkHttp request/response cookie handling - NetworkCookieManager for bootstrap detection and cookie storage - CookieRedirectException to signal cookie acquisition flow - CookieProvider interface bridging network and app layers Co-Authored-By: Claude <noreply@anthropic.com>
This commit updates the `RetrofitsTest` to ensure that the `CookieInterceptor` is consistently called across all Retrofit client configurations. Previously, the tests for `api`, `identity`, `events`, and `notifications` clients did not verify the presence of the cookie interceptor. This change adds an assertion (`assertTrue(isCookieInterceptorCalled)`) to each relevant test case to confirm that the interceptor is included in the chain.
4307955 to
afec3d5
Compare
This commit refactors the `CookieRedirectException` to simplify its interface and updates the `CookieInterceptor` accordingly. The `location` property has been removed from `CookieRedirectException`. This property was redundant as it was not being used by any of the callers, and its removal simplifies the exception's constructor and message. The `CookieInterceptor` is updated to no longer extract or pass the `Location` header value when throwing a `CookieRedirectException`, aligning with the exception's new, cleaner interface.
afec3d5 to
c421c14
Compare
| if (response.code != HTTP_REDIRECT) { | ||
| return response | ||
| } | ||
|
|
||
| // Close the response body to release the connection back to the pool | ||
| // before throwing to cancel the current request. | ||
| response.close() | ||
| cookieProvider.acquireCookies(hostname) | ||
| throw CookieRedirectException( | ||
| hostname = hostname, | ||
| ) | ||
| } |
There was a problem hiding this comment.
This interceptor is registered via addInterceptor() in RetrofitsImpl, making it an OkHttp application interceptor. OkHttp's internal RetryAndFollowUpInterceptor runs after application interceptors in the chain and automatically follows 302 redirects (the default followRedirects is true and is never set to false in this codebase). As a result, chain.proceed(request) returns the final response after all redirects have been followed -- the application interceptor never sees the intermediate 302 status code.
This means:
- The
response.code != HTTP_REDIRECTcheck on line 66 would only see the final response (e.g., 200 HTML from the IdP, or a parsing error), not the 302. - The
response.close()connection safety andCookieRedirectExceptionthrow on lines 72-76 are unreachable under normal operation. - The expired cookie scenario (cookies were attached but the server rejects them with a redirect) won't trigger the clean re-acquisition flow as designed.
The preemptive bootstrap path (lines 58-61) works correctly because it runs before chain.proceed().
To make the 302 detection work, consider one of:
- Register this as a network interceptor via
addNetworkInterceptor(), which sees raw responses before redirect following. - Set
followRedirects(false)on theOkHttpClientand handle redirects manually. - Detect the redirect condition from the final response characteristics (e.g., unexpected content type or domain change) rather than relying on the 302 status code.
There was a problem hiding this comment.
Updated to use addNetworkInterceptor for cookie interceptor.
This commit updates the construction of the base `OkHttpClient` to use `addNetworkInterceptor` for the `cookieInterceptor` instead of `addInterceptor`. This change ensures that the `cookieInterceptor` is added as a network interceptor, which is the correct type for interceptors that need to operate on the final request just before it's transmitted over the network and observe the response as it comes back. This is particularly important for handling cookies, as they are part of the HTTP headers that are added and processed closer to the network layer.
|
|
||
| private val baseOkHttpClient: OkHttpClient = OkHttpClient.Builder() | ||
| .addInterceptor(headersInterceptor) | ||
| .addNetworkInterceptor(cookieInterceptor) |


🎟️ Tracking
https://bitwarden.atlassian.net/browse/PM-29885
📔 Objective
Add cookie interceptor support for enterprise SSO configurations that require ELB session cookies. The interceptor manages the full cookie lifecycle for API requests behind a load balancer:
CookieheaderKey components:
CookieInterceptor— OkHttp interceptor for request/response cookie handlingNetworkCookieManager/NetworkCookieManagerImpl— Bootstrap detection and cookie storage bridgeCookieRedirectException— Signal exception to trigger cookie acquisition flowCookieProvider— Interface bridging the network and app layers