-
Notifications
You must be signed in to change notification settings - Fork 14
fix: implement custom Cognito logout to use correct parameters #299
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: ga-release
Are you sure you want to change the base?
Changes from 3 commits
e62fe1a
79db702
9f1bc01
ac656cd
c2c7d0f
e81e1c4
00ac90e
2e57396
98b46b1
2fcd758
3f296f7
3e7f952
45bcc55
decf74d
bece8b3
f00f862
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,18 +21,32 @@ | |
| import jakarta.ws.rs.POST; | ||
| import jakarta.ws.rs.Path; | ||
| import jakarta.ws.rs.Produces; | ||
| import jakarta.ws.rs.core.Context; | ||
| import jakarta.ws.rs.core.MediaType; | ||
| import jakarta.ws.rs.core.Response; | ||
| import jakarta.ws.rs.core.UriInfo; | ||
|
|
||
| import org.eclipse.microprofile.config.inject.ConfigProperty; | ||
| import org.eclipse.microprofile.openapi.annotations.Operation; | ||
| import com.redhat.ecosystemappeng.exploitiq.service.UserService; | ||
|
|
||
| import java.net.URI; | ||
| import java.net.URLEncoder; | ||
| import java.nio.charset.StandardCharsets; | ||
| import java.util.Optional; | ||
|
|
||
| @Path("/user") | ||
| public class TokenResource { | ||
|
|
||
| @Inject | ||
| UserService userService; | ||
|
|
||
| @ConfigProperty(name = "quarkus.oidc.auth-server-url") | ||
| Optional<String> authServerUrl; | ||
|
zvigrinberg marked this conversation as resolved.
Outdated
|
||
|
|
||
| @ConfigProperty(name = "quarkus.oidc.client-id") | ||
| Optional<String> clientId; | ||
|
|
||
| @GET | ||
| @Produces("application/json") | ||
| @Operation(hidden = true) | ||
|
|
@@ -41,16 +55,51 @@ public String getUserName() { | |
| } | ||
|
|
||
| /** | ||
| * Performs a local logout using the standard 'Clear-Site-Data' header. | ||
| * This feature is available only in secure contexts (HTTPS) | ||
| * https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Clear-Site-Data | ||
| * Logout endpoint with AWS Cognito support. | ||
| * For Cognito (when auth-server-url contains cognito-idp), redirects to Cognito's logout endpoint. | ||
| * For other OIDC providers, performs local logout with Clear-Site-Data header. | ||
| */ | ||
| @POST | ||
| @Path("/logout") | ||
| @Produces(MediaType.TEXT_HTML) | ||
| @Operation(hidden = true) | ||
| @PermitAll | ||
| public Response logout() { | ||
| public Response logout(@Context UriInfo uriInfo) { | ||
| // Check if we're using AWS Cognito | ||
| boolean isCognito = authServerUrl.isPresent() && authServerUrl.get().contains("cognito-idp"); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Redundant Cognito detection with inconsistent dot check (line 73) Line 73 checks authServerUrl.contains("cognito-idp") (no dot), then line 79
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cognito URL prefix recomputed on every request (line 76) The region, domain prefix, and isCognito flag are derived from |
||
|
|
||
| if (isCognito && clientId.isPresent()) { | ||
| // Build Cognito logout URL | ||
| // Extract Cognito domain from auth server URL | ||
| // auth-server-url format: https://cognito-idp.{region}.amazonaws.com/{user-pool-id} | ||
| // user-pool-id format: {region}_{random-string}, e.g., eu-north-1_rIW9qmUNl | ||
| // Cognito domain format: https://{region-lowercase}{random-string-lowercase}.auth.{region}.amazoncognito.com | ||
| // Example: eu-north-1_rIW9qmUNl -> eu-north-1riw9qmunl.auth.eu-north-1.amazoncognito.com | ||
| String authUrl = authServerUrl.get(); | ||
| String region = authUrl.substring(authUrl.indexOf("cognito-idp.") + 12, authUrl.indexOf(".amazonaws.com")); | ||
|
zvigrinberg marked this conversation as resolved.
Outdated
|
||
| String userPoolId = authUrl.substring(authUrl.lastIndexOf("/") + 1); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Trailing slash produces empty userPoolId (line 83) The code extracts the user pool ID via:
If someone configures QUARKUS_OIDC_AUTH_SERVER_URL with a trailing slash |
||
|
|
||
| // Build Cognito domain: replace underscore with nothing, keep hyphens, convert to lowercase | ||
| String cognitoDomain = String.format("https://%s.auth.%s.amazoncognito.com", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cognito domain derivation from pool ID is wrong The code constructs the Cognito logout URL domain by transforming the user This assumes the Cognito hosted-UI domain prefix equals the user pool ID |
||
| userPoolId.replace("_", "").toLowerCase(), region); | ||
|
|
||
| // Build logout redirect URI (application root, not API base) | ||
| // uriInfo.getBaseUri() returns https://host/api/v1/, we need https://host/ | ||
| URI baseUri = uriInfo.getBaseUri(); | ||
| String logoutRedirectUri = baseUri.getScheme() + "://" + baseUri.getAuthority() + "/"; | ||
|
zvigrinberg marked this conversation as resolved.
Outdated
|
||
|
|
||
| // Build Cognito logout URL with required parameters | ||
| String cognitoLogoutUrl = String.format("%s/logout?client_id=%s&logout_uri=%s", | ||
| cognitoDomain, | ||
| clientId.get(), | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @TamarW0 No check on clientId if it's present, could return null and break the logout URL.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the check is done in line 78: |
||
| URLEncoder.encode(logoutRedirectUri, StandardCharsets.UTF_8)); | ||
|
|
||
| return Response.seeOther(URI.create(cognitoLogoutUrl)) | ||
| .header("Clear-Site-Data", "\"cookies\", \"storage\"") | ||
| .build(); | ||
| } | ||
|
|
||
| // For non-Cognito providers, perform local logout | ||
| return Response.ok(LOGGED_OUT_HTML) | ||
| .header("Clear-Site-Data", "\"cookies\", \"storage\"") | ||
| .build(); | ||
|
zvigrinberg marked this conversation as resolved.
Outdated
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.