Search in sources :

Example 1 with LogoutTokenValidationCode

use of org.keycloak.protocol.oidc.LogoutTokenValidationCode in project keycloak by keycloak.

the class LogoutEndpoint method backchannelLogout.

/**
 * Backchannel logout endpoint implementation for Keycloak, which tries to logout the user from all sessions via
 * POST with a valid LogoutToken.
 *
 * Logout a session via a non-browser invocation. Will be implemented as a backchannel logout based on the
 * specification
 * https://openid.net/specs/openid-connect-backchannel-1_0.html
 *
 * @return
 */
@Path("/backchannel-logout")
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response backchannelLogout() {
    MultivaluedMap<String, String> form = request.getDecodedFormParameters();
    event.event(EventType.LOGOUT);
    String encodedLogoutToken = form.getFirst(OAuth2Constants.LOGOUT_TOKEN);
    if (encodedLogoutToken == null) {
        event.error(Errors.INVALID_TOKEN);
        throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "No logout token", Response.Status.BAD_REQUEST);
    }
    LogoutTokenValidationCode validationCode = tokenManager.verifyLogoutToken(session, realm, encodedLogoutToken);
    if (!validationCode.equals(LogoutTokenValidationCode.VALIDATION_SUCCESS)) {
        event.error(Errors.INVALID_TOKEN);
        throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, validationCode.getErrorMessage(), Response.Status.BAD_REQUEST);
    }
    LogoutToken logoutToken = tokenManager.toLogoutToken(encodedLogoutToken).get();
    Stream<String> identityProviderAliases = tokenManager.getValidOIDCIdentityProvidersForBackchannelLogout(realm, session, encodedLogoutToken, logoutToken).map(idp -> idp.getConfig().getAlias());
    boolean logoutOfflineSessions = Boolean.parseBoolean(logoutToken.getEvents().getOrDefault(TokenUtil.TOKEN_BACKCHANNEL_LOGOUT_EVENT_REVOKE_OFFLINE_TOKENS, false).toString());
    BackchannelLogoutResponse backchannelLogoutResponse;
    if (logoutToken.getSid() != null) {
        backchannelLogoutResponse = backchannelLogoutWithSessionId(logoutToken.getSid(), identityProviderAliases, logoutOfflineSessions, logoutToken.getSubject());
    } else {
        backchannelLogoutResponse = backchannelLogoutFederatedUserId(logoutToken.getSubject(), identityProviderAliases, logoutOfflineSessions);
    }
    if (!backchannelLogoutResponse.getLocalLogoutSucceeded()) {
        event.error(Errors.LOGOUT_FAILED);
        throw new ErrorResponseException(OAuthErrorException.SERVER_ERROR, "There was an error in the local logout", Response.Status.NOT_IMPLEMENTED);
    }
    session.getProvider(SecurityHeadersProvider.class).options().allowEmptyContentType();
    if (oneOrMoreDownstreamLogoutsFailed(backchannelLogoutResponse)) {
        return Cors.add(request).auth().builder(Response.status(Response.Status.GATEWAY_TIMEOUT).type(MediaType.APPLICATION_JSON_TYPE)).build();
    }
    return Cors.add(request).auth().builder(Response.ok().type(MediaType.APPLICATION_JSON_TYPE)).build();
}
Also used : LogoutTokenValidationCode(org.keycloak.protocol.oidc.LogoutTokenValidationCode) LogoutToken(org.keycloak.representations.LogoutToken) ErrorResponseException(org.keycloak.services.ErrorResponseException) CorsErrorResponseException(org.keycloak.services.CorsErrorResponseException) BackchannelLogoutResponse(org.keycloak.protocol.oidc.BackchannelLogoutResponse) Path(javax.ws.rs.Path) POST(javax.ws.rs.POST) Consumes(javax.ws.rs.Consumes)

Aggregations

Consumes (javax.ws.rs.Consumes)1 POST (javax.ws.rs.POST)1 Path (javax.ws.rs.Path)1 BackchannelLogoutResponse (org.keycloak.protocol.oidc.BackchannelLogoutResponse)1 LogoutTokenValidationCode (org.keycloak.protocol.oidc.LogoutTokenValidationCode)1 LogoutToken (org.keycloak.representations.LogoutToken)1 CorsErrorResponseException (org.keycloak.services.CorsErrorResponseException)1 ErrorResponseException (org.keycloak.services.ErrorResponseException)1