diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/OpenMetadataApplication.java b/openmetadata-service/src/main/java/org/openmetadata/service/OpenMetadataApplication.java index 80fe64f77d6..565a7485270 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/OpenMetadataApplication.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/OpenMetadataApplication.java @@ -116,6 +116,7 @@ import org.openmetadata.service.security.jwt.JWTTokenGenerator; import org.openmetadata.service.security.saml.OMMicrometerHttpFilter; import org.openmetadata.service.security.saml.SamlAssertionConsumerServlet; import org.openmetadata.service.security.saml.SamlLoginServlet; +import org.openmetadata.service.security.saml.SamlLogoutServlet; import org.openmetadata.service.security.saml.SamlMetadataServlet; import org.openmetadata.service.security.saml.SamlSettingsHolder; import org.openmetadata.service.security.saml.SamlTokenRefreshServlet; @@ -350,6 +351,13 @@ public class OpenMetadataApplication extends Application jwtPrincipalClaims; + private final Map jwtPrincipalClaimsMapping; + + public SamlLogoutServlet( + AuthenticationConfiguration authenticationConfiguration, + AuthorizerConfiguration authorizerConf) { + jwtFilter = new JwtFilter(authenticationConfiguration, authorizerConf); + this.jwtPrincipalClaims = authenticationConfiguration.getJwtPrincipalClaims(); + this.jwtPrincipalClaimsMapping = + listOrEmpty(authenticationConfiguration.getJwtPrincipalClaimsMapping()).stream() + .map(s -> s.split(":")) + .collect(Collectors.toMap(s -> s[0], s -> s[1])); + } + + @Override + protected void doGet( + final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse) + throws IOException { + try { + LOG.debug("Performing application logout"); + HttpSession session = httpServletRequest.getSession(false); + String token = JwtFilter.extractToken(httpServletRequest.getHeader("Authorization")); + if (session != null) { + LOG.debug("Invalidating the session for logout"); + Map claims = jwtFilter.validateJwtAndGetClaims(token); + String userName = + findUserNameFromClaims(jwtPrincipalClaimsMapping, jwtPrincipalClaims, claims); + Date logoutTime = Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant()); + // Mark the token invalid + JwtTokenCacheManager.getInstance() + .markLogoutEventForToken( + new LogoutRequest() + .withUsername(userName) + .withToken(token) + .withLogoutTime(logoutTime)); + // Invalidate the session + session.invalidate(); + + // Redirect to server + writeJsonResponse(httpServletResponse, "Logout successful"); + } else { + LOG.error("No session store available for this web context"); + } + } catch (Exception e) { + getErrorMessage(httpServletResponse, e); + } + } + + public String getBaseUrl(HttpServletRequest request) { + String scheme = request.getScheme(); + String serverName = request.getServerName(); + return String.format("%s://%s", scheme, serverName); + } +} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppAuthenticators/SamlAuthenticator.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppAuthenticators/SamlAuthenticator.tsx index 4f442154ee2..37a1ffd4dc5 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppAuthenticators/SamlAuthenticator.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Auth/AppAuthenticators/SamlAuthenticator.tsx @@ -33,6 +33,7 @@ import { SamlSSOClientConfig } from '../../../generated/configuration/authentica import { postSamlLogout } from '../../../rest/miscAPI'; import { showErrorToast } from '../../../utils/ToastUtils'; +import { ROUTES } from '../../../constants/constants'; import { useApplicationStore } from '../../../hooks/useApplicationStore'; import { AccessTokenResponse, refreshSAMLToken } from '../../../rest/auth-API'; import { AuthenticatorRef } from '../AuthProviders/AuthProvider.interface'; @@ -69,7 +70,8 @@ const SamlAuthenticator = forwardRef( const login = async () => { if (config.idp.authorityUrl) { - window.location.href = config.idp.authorityUrl; + const redirectUri = `${window.location.origin}${ROUTES.SAML_CALLBACK}`; + window.location.href = `${config.idp.authorityUrl}?redirectUri=${redirectUri}`; } else { showErrorToast('SAML IDP Authority URL is not configured.'); } @@ -78,7 +80,7 @@ const SamlAuthenticator = forwardRef( const logout = () => { const token = getOidcToken(); if (token) { - postSamlLogout({ token }) + postSamlLogout() .then(() => { setIsAuthenticated(false); try { diff --git a/openmetadata-ui/src/main/resources/ui/src/rest/miscAPI.ts b/openmetadata-ui/src/main/resources/ui/src/rest/miscAPI.ts index 97d4a61d68f..601ce4294e9 100644 --- a/openmetadata-ui/src/main/resources/ui/src/rest/miscAPI.ts +++ b/openmetadata-ui/src/main/resources/ui/src/rest/miscAPI.ts @@ -94,8 +94,8 @@ export const getVersion = async () => { return response.data; }; -export const postSamlLogout = async (data: { token: string }) => { - const response = await APIClient.post(`/users/logout`, { ...data }); +export const postSamlLogout = async () => { + const response = await APIClient.get(`/saml/logout`); return response.data; };