use of org.keycloak.OAuthErrorException in project keycloak by keycloak.
the class KeycloakInstalled method loginDesktop.
public void loginDesktop() throws IOException, VerificationException, OAuthErrorException, URISyntaxException, ServerRequest.HttpFailure, InterruptedException {
callback = new CallbackListener();
callback.start();
String redirectUri = getRedirectUri(callback);
String state = UUID.randomUUID().toString();
Pkce pkce = deployment.isPkce() ? generatePkce() : null;
String authUrl = createAuthUrl(redirectUri, state, pkce);
desktopProvider.browse(new URI(authUrl));
try {
callback.await();
} catch (InterruptedException e) {
callback.stop();
throw e;
}
if (callback.error != null) {
throw new OAuthErrorException(callback.error, callback.errorDescription);
}
if (!state.equals(callback.state)) {
throw new VerificationException("Invalid state");
}
processCode(callback.code, redirectUri, pkce);
status = Status.LOGGED_DESKTOP;
}
use of org.keycloak.OAuthErrorException in project keycloak by keycloak.
the class TokenManager method validateTokenReuseForRefresh.
private void validateTokenReuseForRefresh(KeycloakSession session, RealmModel realm, RefreshToken refreshToken, TokenValidation validation) throws OAuthErrorException {
if (realm.isRevokeRefreshToken()) {
AuthenticatedClientSessionModel clientSession = validation.clientSessionCtx.getClientSession();
try {
validateTokenReuse(session, realm, refreshToken, clientSession, true);
int currentCount = clientSession.getCurrentRefreshTokenUseCount();
clientSession.setCurrentRefreshTokenUseCount(currentCount + 1);
} catch (OAuthErrorException oee) {
if (logger.isDebugEnabled()) {
logger.debugf("Failed validation of refresh token %s due it was used before. Realm: %s, client: %s, user: %s, user session: %s. Will detach client session from user session", refreshToken.getId(), realm.getName(), clientSession.getClient().getClientId(), clientSession.getUserSession().getUser().getUsername(), clientSession.getUserSession().getId());
}
clientSession.detachFromUserSession();
throw oee;
}
}
}
use of org.keycloak.OAuthErrorException in project keycloak by keycloak.
the class TokenManager method validateTokenReuseForIntrospection.
private boolean validateTokenReuseForIntrospection(KeycloakSession session, RealmModel realm, AccessToken token) {
UserSessionModel userSession = null;
if (token.getType().equals(TokenUtil.TOKEN_TYPE_REFRESH)) {
userSession = session.sessions().getUserSession(realm, token.getSessionState());
} else {
UserSessionManager sessionManager = new UserSessionManager(session);
userSession = sessionManager.findOfflineUserSession(realm, token.getSessionState());
}
ClientModel client = realm.getClientByClientId(token.getIssuedFor());
AuthenticatedClientSessionModel clientSession = userSession.getAuthenticatedClientSessionByClient(client.getId());
try {
validateTokenReuse(session, realm, token, clientSession, false);
return true;
} catch (OAuthErrorException e) {
return false;
}
}
use of org.keycloak.OAuthErrorException in project keycloak by keycloak.
the class TokenManager method validateToken.
public TokenValidation validateToken(KeycloakSession session, UriInfo uriInfo, ClientConnection connection, RealmModel realm, RefreshToken oldToken, HttpHeaders headers) throws OAuthErrorException {
UserSessionModel userSession = null;
boolean offline = TokenUtil.TOKEN_TYPE_OFFLINE.equals(oldToken.getType());
if (offline) {
UserSessionManager sessionManager = new UserSessionManager(session);
userSession = sessionManager.findOfflineUserSession(realm, oldToken.getSessionState());
if (userSession != null) {
// Revoke timeouted offline userSession
if (!AuthenticationManager.isOfflineSessionValid(realm, userSession)) {
sessionManager.revokeOfflineUserSession(userSession);
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Offline session not active", "Offline session not active");
}
} else {
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Offline user session not found", "Offline user session not found");
}
} else {
// Find userSession regularly for online tokens
userSession = session.sessions().getUserSession(realm, oldToken.getSessionState());
if (!AuthenticationManager.isSessionValid(realm, userSession)) {
AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, connection, headers, true);
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Session not active", "Session not active");
}
}
UserModel user = userSession.getUser();
if (user == null) {
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid refresh token", "Unknown user");
}
if (!user.isEnabled()) {
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "User disabled", "User disabled");
}
if (oldToken.isIssuedBeforeSessionStart(userSession.getStarted())) {
logger.debug("Refresh toked issued before the user session started");
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Refresh toked issued before the user session started");
}
ClientModel client = session.getContext().getClient();
AuthenticatedClientSessionModel clientSession = userSession.getAuthenticatedClientSessionByClient(client.getId());
// Can theoretically happen in cross-dc environment. Try to see if userSession with our client is available in remoteCache
if (clientSession == null) {
userSession = new UserSessionCrossDCManager(session).getUserSessionWithClient(realm, userSession.getId(), offline, client.getId());
if (userSession != null) {
clientSession = userSession.getAuthenticatedClientSessionByClient(client.getId());
} else {
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Session doesn't have required client", "Session doesn't have required client");
}
}
if (oldToken.isIssuedBeforeSessionStart(clientSession.getStarted())) {
logger.debug("Refresh toked issued before the client session started");
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Refresh toked issued before the client session started");
}
if (!client.getClientId().equals(oldToken.getIssuedFor())) {
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Unmatching clients", "Unmatching clients");
}
try {
TokenVerifier.createWithoutSignature(oldToken).withChecks(NotBeforeCheck.forModel(client), NotBeforeCheck.forModel(session, realm, user)).verify();
} catch (VerificationException e) {
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale token");
}
// Setup clientScopes from refresh token to the context
String oldTokenScope = oldToken.getScope();
// Case when offline token is migrated from previous version
if (oldTokenScope == null && userSession.isOffline()) {
logger.debugf("Migrating offline token of user '%s' for client '%s' of realm '%s'", user.getUsername(), client.getClientId(), realm.getName());
MigrationUtils.migrateOldOfflineToken(session, realm, client, user);
oldTokenScope = OAuth2Constants.OFFLINE_ACCESS;
}
ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionAndScopeParameter(clientSession, oldTokenScope, session);
// Check user didn't revoke granted consent
if (!verifyConsentStillAvailable(session, user, client, clientSessionCtx.getClientScopesStream())) {
throw new OAuthErrorException(OAuthErrorException.INVALID_SCOPE, "Client no longer has requested consent from user");
}
clientSessionCtx.setAttribute(OIDCLoginProtocol.NONCE_PARAM, oldToken.getNonce());
// recreate token.
AccessToken newToken = createClientAccessToken(session, realm, client, user, userSession, clientSessionCtx);
return new TokenValidation(user, userSession, clientSessionCtx, newToken);
}
use of org.keycloak.OAuthErrorException in project keycloak by keycloak.
the class LogoutEndpoint method logoutToken.
/**
* Logout a session via a non-browser invocation. Similar signature to refresh token except there is no grant_type.
* You must pass in the refresh token and
* authenticate the client if it is not public.
*
* If the client is a confidential client
* you must include the client-id and secret in an Basic Auth Authorization header.
*
* If the client is a public client, then you must include a "client_id" form parameter.
*
* returns 204 if successful, 400 if not with a json error response.
*
* @return
*/
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response logoutToken() {
cors = Cors.add(request).auth().allowedMethods("POST").auth().exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS);
MultivaluedMap<String, String> form = request.getDecodedFormParameters();
checkSsl();
event.event(EventType.LOGOUT);
ClientModel client = authorizeClient();
String refreshToken = form.getFirst(OAuth2Constants.REFRESH_TOKEN);
if (refreshToken == null) {
event.error(Errors.INVALID_TOKEN);
throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_REQUEST, "No refresh token", Response.Status.BAD_REQUEST);
}
try {
session.clientPolicy().triggerOnEvent(new LogoutRequestContext(form));
} catch (ClientPolicyException cpe) {
throw new CorsErrorResponseException(cors, cpe.getError(), cpe.getErrorDetail(), cpe.getErrorStatus());
}
RefreshToken token = null;
try {
// KEYCLOAK-6771 Certificate Bound Token
token = tokenManager.verifyRefreshToken(session, realm, client, request, refreshToken, false);
boolean offline = TokenUtil.TOKEN_TYPE_OFFLINE.equals(token.getType());
UserSessionModel userSessionModel;
if (offline) {
UserSessionManager sessionManager = new UserSessionManager(session);
userSessionModel = sessionManager.findOfflineUserSession(realm, token.getSessionState());
} else {
userSessionModel = session.sessions().getUserSession(realm, token.getSessionState());
}
if (userSessionModel != null) {
checkTokenIssuedAt(token, userSessionModel);
logout(userSessionModel, offline);
}
} catch (OAuthErrorException e) {
// KEYCLOAK-6771 Certificate Bound Token
if (MtlsHoKTokenUtil.CERT_VERIFY_ERROR_DESC.equals(e.getDescription())) {
event.error(Errors.NOT_ALLOWED);
throw new CorsErrorResponseException(cors, e.getError(), e.getDescription(), Response.Status.UNAUTHORIZED);
} else {
event.error(Errors.INVALID_TOKEN);
throw new CorsErrorResponseException(cors, e.getError(), e.getDescription(), Response.Status.BAD_REQUEST);
}
}
return cors.builder(Response.noContent()).build();
}
Aggregations