Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,35 @@
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;

@ConfigProperty(name = "quarkus.oidc.client-id")
Optional<String> clientId;

@ConfigProperty(name = "cognito.domain")
Optional<String> cognitoDomain;

@GET
@Produces("application/json")
@Operation(hidden = true)
Expand All @@ -41,17 +58,59 @@ 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 cognito.domain is configured), redirects to Cognito's logout endpoint.
* For other OIDC providers, performs local logout with Clear-Site-Data header.
*
* NOTE: Cognito behind a reverse proxy is not currently supported.
*/
@POST
@Path("/logout")
@Produces(MediaType.TEXT_HTML)
@Operation(hidden = true)
@PermitAll
public Response logout() {
return Response.ok(LOGGED_OUT_HTML)
public Response logout(@Context UriInfo uriInfo) {

if (cognitoDomain.isPresent()) {
String domain = cognitoDomain.get().trim();

if (domain.endsWith("/")) {
domain = domain.substring(0, domain.length() - 1);
}

// Build logout redirect URI to the logged-out page
// uriInfo.getBaseUri() returns https://host/api/v1/, we need https://host/api/v1/user/logged-out
URI baseUri = uriInfo.getBaseUri();
String logoutRedirectUri = baseUri.getScheme() + "://" + baseUri.getAuthority() + baseUri.getPath() + "user/logged-out";

// Build Cognito logout URL with required parameters
String cognitoLogoutUrl = String.format("%s/logout?client_id=%s&logout_uri=%s",
domain,
clientId.get(),
URLEncoder.encode(logoutRedirectUri, StandardCharsets.UTF_8));

return buildLogoutResponse(Response.seeOther(URI.create(cognitoLogoutUrl)));
}

// For non-Cognito providers, perform local logout
return buildLogoutResponse(Response.ok(LOGGED_OUT_HTML));
}

/**
* Logged-out page endpoint.
* Displays the logout success message after Cognito completes its logout.
*/
@GET
@Path("/logged-out")
@Produces(MediaType.TEXT_HTML)
@Operation(hidden = true)
@PermitAll
public Response loggedOut() {
return buildLogoutResponse(Response.ok(LOGGED_OUT_HTML));
}

private Response buildLogoutResponse(Response.ResponseBuilder responseBuilder) {
return responseBuilder
.header("Clear-Site-Data", "\"cookies\", \"storage\"")
.build();
}
Expand Down
12 changes: 8 additions & 4 deletions src/main/resources/META-INF/resources/error/403.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,14 @@
<link rel="stylesheet" href="https://unpkg.com/@patternfly/patternfly@6.1.0/patternfly.css" crossorigin="anonymous">
<script>
function logout() {
fetch('/api/v1/user/logout', { method: 'POST' })
.then(() => {
window.location.href = "/";
});
// Create and submit a form to trigger logout endpoint
// This ensures cookies are cleared via Clear-Site-Data header
// and allows cross-origin redirects (e.g., to Cognito logout)
const form = document.createElement('form');
form.method = 'POST';
form.action = '/api/v1/user/logout';
document.body.appendChild(form);
form.submit();
}
</script>
</head>
Expand Down
5 changes: 4 additions & 1 deletion src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,16 @@ quarkus.oidc.authentication.java-script-auto-redirect=false
# ==============================================================================

# Allow logout for all authenticated users (even without roles)
quarkus.http.auth.permission.logout.paths=/api/v1/user/logout
exploitiq.security.public-logout-paths=/api/v1/user/logout,/api/v1/user/logged-out
quarkus.http.auth.permission.logout.paths=${exploitiq.security.public-logout-paths}
quarkus.http.auth.permission.logout.policy=permit
quarkus.http.auth.permission.logout.order=1


# Allow health endpoints (for monitoring)
quarkus.http.auth.permission.management.paths=/health,/health/*
quarkus.http.auth.permission.management.policy=permit
quarkus.http.auth.permission.management.order=1


# Allow dev UI in development mode
Expand Down
Loading