use of org.keycloak.sessions.AuthenticationSessionModel in project keycloak by keycloak.
the class LoginActionsServiceChecks method checkIsClientValid.
/**
* Verifies whether the client denoted by client ID in token's {@code iss} ({@code issuedFor})
* field both exists and is enabled.
*/
public static <T extends JsonWebToken> void checkIsClientValid(T token, ActionTokenContext<T> context) throws VerificationException {
String clientId = token.getIssuedFor();
AuthenticationSessionModel authSession = context.getAuthenticationSession();
ClientModel client = authSession == null ? null : authSession.getClient();
try {
checkIsClientValid(context.getSession(), client);
if (clientId != null && !Objects.equals(client.getClientId(), clientId)) {
throw new ExplainedTokenVerificationException(token, Errors.CLIENT_NOT_FOUND, Messages.UNKNOWN_LOGIN_REQUESTER);
}
} catch (ExplainedVerificationException ex) {
throw new ExplainedTokenVerificationException(token, ex);
}
}
use of org.keycloak.sessions.AuthenticationSessionModel in project keycloak by keycloak.
the class LoginActionsServiceChecks method doesAuthenticationSessionFromCookieMatchOneFromToken.
/**
* This check verifies that current authentication session is consistent with the one specified in token.
* Examples:
* <ul>
* <li>1. Email from administrator with reset e-mail - token does not contain auth session ID</li>
* <li>2. Email from "verify e-mail" step within flow - token contains auth session ID.</li>
* <li>3. User clicked the link in an e-mail and gets to a new browser - authentication session cookie is not set</li>
* <li>4. User clicked the link in an e-mail while having authentication running - authentication session cookie
* is already set in the browser</li>
* </ul>
*
* <ul>
* <li>For combinations 1 and 3, 1 and 4, and 2 and 3: Requests next step</li>
* <li>For combination 2 and 4:
* <ul>
* <li>If the auth session IDs from token and cookie match, pass</li>
* <li>Else if the auth session from cookie was forked and its parent auth session ID
* matches that of token, replaces current auth session with that of parent and passes</li>
* <li>Else requests restart by throwing RestartFlow exception</li>
* </ul>
* </li>
* </ul>
*
* When the check passes, it also sets the authentication session in token context accordingly.
*
* @param <T>
*/
public static <T extends JsonWebToken> boolean doesAuthenticationSessionFromCookieMatchOneFromToken(ActionTokenContext<T> context, AuthenticationSessionModel authSessionFromCookie, String authSessionCompoundIdFromToken) throws VerificationException {
if (authSessionCompoundIdFromToken == null) {
return false;
}
if (Objects.equals(AuthenticationSessionCompoundId.fromAuthSession(authSessionFromCookie).getEncodedId(), authSessionCompoundIdFromToken)) {
context.setAuthenticationSession(authSessionFromCookie, false);
return true;
}
// Check if it's forked session. It would have same parent (rootSession) as our browser authenticationSession
String parentTabId = authSessionFromCookie.getAuthNote(AuthenticationProcessor.FORKED_FROM);
if (parentTabId == null) {
return false;
}
AuthenticationSessionModel authSessionFromParent = authSessionFromCookie.getParentSession().getAuthenticationSession(authSessionFromCookie.getClient(), parentTabId);
if (authSessionFromParent == null) {
return false;
}
// It's the correct browser. We won't continue login
// from the login form (browser flow) but from the token's flow
// Don't expire KC_RESTART cookie at this point
LOG.debugf("Switched to forked tab: %s from: %s . Root session: %s", authSessionFromParent.getTabId(), authSessionFromCookie.getTabId(), authSessionFromCookie.getParentSession().getId());
context.setAuthenticationSession(authSessionFromParent, false);
context.setExecutionId(authSessionFromParent.getAuthNote(AuthenticationProcessor.LAST_PROCESSED_EXECUTION));
return true;
}
use of org.keycloak.sessions.AuthenticationSessionModel in project keycloak by keycloak.
the class SessionCodeChecks method initialVerifyAuthSession.
public AuthenticationSessionModel initialVerifyAuthSession() {
// Basic realm checks
if (!checkSsl()) {
event.error(Errors.SSL_REQUIRED);
response = ErrorPage.error(session, null, Response.Status.BAD_REQUEST, Messages.HTTPS_REQUIRED);
return null;
}
if (!realm.isEnabled()) {
event.error(Errors.REALM_DISABLED);
response = ErrorPage.error(session, null, Response.Status.BAD_REQUEST, Messages.REALM_NOT_ENABLED);
return null;
}
// Setup client to be shown on error/info page based on "client_id" parameter
logger.debugf("Will use client '%s' in back-to-application link", clientId);
ClientModel client = null;
if (clientId != null) {
client = realm.getClientByClientId(clientId);
}
if (client != null) {
session.getContext().setClient(client);
}
// object retrieve
AuthenticationSessionManager authSessionManager = new AuthenticationSessionManager(session);
AuthenticationSessionModel authSession = null;
if (authSessionId != null)
authSession = authSessionManager.getAuthenticationSessionByIdAndClient(realm, authSessionId, client, tabId);
AuthenticationSessionModel authSessionCookie = authSessionManager.getCurrentAuthenticationSession(realm, client, tabId);
if (authSession != null && authSessionCookie != null && !authSession.getParentSession().getId().equals(authSessionCookie.getParentSession().getId())) {
event.detail(Details.REASON, "cookie does not match auth_session query parameter");
event.error(Errors.INVALID_CODE);
response = ErrorPage.error(session, null, Response.Status.BAD_REQUEST, Messages.INVALID_CODE);
return null;
}
if (authSession != null) {
session.getProvider(LoginFormsProvider.class).setAuthenticationSession(authSession);
return authSession;
}
if (authSessionCookie != null) {
session.getProvider(LoginFormsProvider.class).setAuthenticationSession(authSessionCookie);
return authSessionCookie;
}
// See if we are already authenticated and userSession with same ID exists.
UserSessionModel userSession = authSessionManager.getUserSessionFromAuthCookie(realm);
if (userSession != null) {
LoginFormsProvider loginForm = session.getProvider(LoginFormsProvider.class).setAuthenticationSession(authSession).setSuccess(Messages.ALREADY_LOGGED_IN);
if (client == null) {
loginForm.setAttribute(Constants.SKIP_LINK, true);
}
response = loginForm.createInfoPage();
return null;
}
// Otherwise just try to restart from the cookie
RootAuthenticationSessionModel existingRootAuthSession = authSessionManager.getCurrentRootAuthenticationSession(realm);
response = restartAuthenticationSessionFromCookie(existingRootAuthSession);
return null;
}
use of org.keycloak.sessions.AuthenticationSessionModel in project keycloak by keycloak.
the class SessionCodeChecks method restartAuthenticationSessionFromCookie.
private Response restartAuthenticationSessionFromCookie(RootAuthenticationSessionModel existingRootSession) {
logger.debug("Authentication session not found. Trying to restart from cookie.");
AuthenticationSessionModel authSession = null;
Cookie cook = RestartLoginCookie.getRestartCookie(session);
if (cook == null) {
event.error(Errors.COOKIE_NOT_FOUND);
return ErrorPage.error(session, authSession, Response.Status.BAD_REQUEST, Messages.COOKIE_NOT_FOUND);
}
try {
authSession = RestartLoginCookie.restartSession(session, realm, existingRootSession, clientId, cook);
} catch (Exception e) {
ServicesLogger.LOGGER.failedToParseRestartLoginCookie(e);
}
if (authSession != null) {
event.clone();
event.detail(Details.RESTART_AFTER_TIMEOUT, "true");
event.error(Errors.EXPIRED_CODE);
String warningMessage = Messages.LOGIN_TIMEOUT;
authSession.setAuthNote(LoginActionsService.FORWARDED_ERROR_MESSAGE_NOTE, warningMessage);
String flowPath = authSession.getClientNote(AuthorizationEndpointBase.APP_INITIATED_FLOW);
if (flowPath == null) {
flowPath = LoginActionsService.AUTHENTICATE_PATH;
}
URI redirectUri = getLastExecutionUrl(flowPath, null, authSession.getTabId());
logger.debugf("Authentication session restart from cookie succeeded. Redirecting to %s", redirectUri);
return Response.status(Response.Status.FOUND).location(redirectUri).build();
} else {
// Finally need to show error as all the fallbacks failed
event.error(Errors.INVALID_CODE);
return ErrorPage.error(session, authSession, Response.Status.BAD_REQUEST, Messages.INVALID_CODE);
}
}
use of org.keycloak.sessions.AuthenticationSessionModel in project keycloak by keycloak.
the class SessionCodeChecks method verifyActiveAndValidAction.
public boolean verifyActiveAndValidAction(String expectedAction, ClientSessionCode.ActionType actionType) {
if (failed()) {
return false;
}
if (!isActionActive(actionType)) {
return false;
}
if (!clientCode.isValidAction(expectedAction)) {
AuthenticationSessionModel authSession = getAuthenticationSession();
if (AuthenticationSessionModel.Action.REQUIRED_ACTIONS.name().equals(authSession.getAction())) {
logger.debugf("Incorrect action '%s' . User authenticated already.", authSession.getAction());
response = showPageExpired(authSession);
return false;
} else {
logger.errorf("Bad action. Expected action '%s', current action '%s'", expectedAction, authSession.getAction());
response = ErrorPage.error(session, authSession, Response.Status.BAD_REQUEST, Messages.EXPIRED_CODE);
return false;
}
}
return true;
}
Aggregations