diff --git a/dqops/src/main/frontend/src/components/UserProfile/index.tsx b/dqops/src/main/frontend/src/components/UserProfile/index.tsx index 42a5422fa7..b79a633f62 100644 --- a/dqops/src/main/frontend/src/components/UserProfile/index.tsx +++ b/dqops/src/main/frontend/src/components/UserProfile/index.tsx @@ -255,6 +255,14 @@ export default function UserProfile({ name, email }: UserProfile) { )} + {userProfile.can_logout === true && ( + + Logout + + )} filter(ServerWebExchange exchange, WebFilterChain chain) { .then(); } + if (Objects.equals(requestPath, LOGOUT_PATH)) { + String hostHeader = request.getHeaders().getHost().getHostString(); + + int portPrefixIndex = hostHeader.indexOf(':'); + if (portPrefixIndex > 0) { + hostHeader = hostHeader.substring(0, portPrefixIndex); + } + + ResponseCookie dqoAccessTokenCookie = ResponseCookie.from(AUTHENTICATION_TOKEN_COOKIE, "") + .maxAge(0L) + .path("/") + .domain(hostHeader) + .build(); + exchange.getResponse().getCookies().add(AUTHENTICATION_TOKEN_COOKIE, dqoAccessTokenCookie); + + try { + String returnUrl = exchange.getRequest().getURI().resolve("/").toString(); + String dqoCloudLoginUrl = this.instanceCloudLoginService.makeDqoLogoutUrl(returnUrl); + + if (log.isDebugEnabled()) { + log.debug("Redirecting the user to logout and authenticate with DQOps Cloud federated authentication at " + dqoCloudLoginUrl); + } + + exchange.getResponse().setStatusCode(HttpStatusCode.valueOf(303)); + exchange.getResponse().getHeaders().add("Location", dqoCloudLoginUrl); + return exchange.getResponse().writeAndFlushWith(Mono.empty()); + } + catch (Exception ex) { + log.error("Cannot create a DQOps Cloud login url: " + ex.getMessage(), ex); + exchange.getResponse().setStatusCode(HttpStatusCode.valueOf(500)); + return exchange.getResponse().writeAndFlushWith(Mono.empty()); + } + } + if (Objects.equals(requestPath, ISSUE_TOKEN_REQUEST_PATH)) { exchange.getResponse().setStatusCode(HttpStatusCode.valueOf(303)); String returnUrl = exchange.getRequest().getQueryParams().getFirst("returnUrl"); diff --git a/dqops/src/main/resources/application.yml b/dqops/src/main/resources/application.yml index 142d1ef74f..b50a2384ee 100644 --- a/dqops/src/main/resources/application.yml +++ b/dqops/src/main/resources/application.yml @@ -115,6 +115,7 @@ dqo: #ui-base-url: http://localhost:8080 #rest-api-base-url: http://localhost:8080 api-key-request-url: ${dqo.cloud.ui-base-url}/requestapikey/ + logout-url: ${dqo.cloud.ui-base-url}/login?logout=true api-key-pickup-timeout-seconds: 600 api-key-pickup-retry-delay-millis: 1000 parallel-file-uploads: 500 diff --git a/dqops/src/main/resources/static/swagger-api/dqops-api-swagger-2.json b/dqops/src/main/resources/static/swagger-api/dqops-api-swagger-2.json index 8799d9b79e..0b607a729f 100644 --- a/dqops/src/main/resources/static/swagger-api/dqops-api-swagger-2.json +++ b/dqops/src/main/resources/static/swagger-api/dqops-api-swagger-2.json @@ -39351,6 +39351,10 @@ "can_use_ai_anomaly_detection" : { "type" : "boolean", "description" : "The DQOps instance is a paid version with advanced AI anomaly prediction." + }, + "can_logout" : { + "type" : "boolean", + "description" : "This instance uses federated authentication and the user can log out." } }, "description" : "The model that describes the current user and his access rights." diff --git a/dqops/src/main/resources/static/swagger-api/dqops-api-swagger-2.yaml b/dqops/src/main/resources/static/swagger-api/dqops-api-swagger-2.yaml index dcc9226188..059c2e3aa0 100644 --- a/dqops/src/main/resources/static/swagger-api/dqops-api-swagger-2.yaml +++ b/dqops/src/main/resources/static/swagger-api/dqops-api-swagger-2.yaml @@ -38080,6 +38080,10 @@ definitions: type: "boolean" description: "The DQOps instance is a paid version with advanced AI anomaly\ \ prediction." + can_logout: + type: "boolean" + description: "This instance uses federated authentication and the user can\ + \ log out." description: "The model that describes the current user and his access rights." DqoUserRolesModel: type: "object"