Search in sources :

Example 31 with AuthenticationSessionModel

use of org.keycloak.sessions.AuthenticationSessionModel in project keycloak by keycloak.

the class OIDCIdentityProvider method preprocessFederatedIdentity.

@Override
public void preprocessFederatedIdentity(KeycloakSession session, RealmModel realm, BrokeredIdentityContext context) {
    AuthenticationSessionModel authenticationSession = session.getContext().getAuthenticationSession();
    if (authenticationSession == null) {
        // no interacting with the brokered OP, likely doing token exchanges
        return;
    }
    String nonce = (String) context.getContextData().get(BROKER_NONCE_PARAM);
    if (nonce == null) {
        throw new IdentityBrokerException("OpenID Provider [" + getConfig().getProviderId() + "] did not return a nonce");
    }
    String expectedNonce = authenticationSession.getClientNote(BROKER_NONCE_PARAM);
    if (!nonce.equals(expectedNonce)) {
        throw new ErrorResponseException(OAuthErrorException.INVALID_TOKEN, "invalid nonce", Response.Status.BAD_REQUEST);
    }
}
Also used : AuthenticationSessionModel(org.keycloak.sessions.AuthenticationSessionModel) IdentityBrokerException(org.keycloak.broker.provider.IdentityBrokerException) ErrorResponseException(org.keycloak.services.ErrorResponseException)

Example 32 with AuthenticationSessionModel

use of org.keycloak.sessions.AuthenticationSessionModel in project keycloak by keycloak.

the class VerifyEmail method requiredActionChallenge.

@Override
public void requiredActionChallenge(RequiredActionContext context) {
    AuthenticationSessionModel authSession = context.getAuthenticationSession();
    if (context.getUser().isEmailVerified()) {
        context.success();
        authSession.removeAuthNote(Constants.VERIFY_EMAIL_KEY);
        return;
    }
    String email = context.getUser().getEmail();
    if (Validation.isBlank(email)) {
        context.ignore();
        return;
    }
    LoginFormsProvider loginFormsProvider = context.form();
    Response challenge;
    authSession.setClientNote(AuthorizationEndpointBase.APP_INITIATED_FLOW, null);
    // Do not allow resending e-mail by simple page refresh, i.e. when e-mail sent, it should be resent properly via email-verification endpoint
    if (!Objects.equals(authSession.getAuthNote(Constants.VERIFY_EMAIL_KEY), email)) {
        authSession.setAuthNote(Constants.VERIFY_EMAIL_KEY, email);
        EventBuilder event = context.getEvent().clone().event(EventType.SEND_VERIFY_EMAIL).detail(Details.EMAIL, email);
        challenge = sendVerifyEmail(context.getSession(), loginFormsProvider, context.getUser(), context.getAuthenticationSession(), event);
    } else {
        challenge = loginFormsProvider.createResponse(UserModel.RequiredAction.VERIFY_EMAIL);
    }
    context.challenge(challenge);
}
Also used : AuthenticationSessionModel(org.keycloak.sessions.AuthenticationSessionModel) LoginFormsProvider(org.keycloak.forms.login.LoginFormsProvider) EventBuilder(org.keycloak.events.EventBuilder)

Example 33 with AuthenticationSessionModel

use of org.keycloak.sessions.AuthenticationSessionModel in project keycloak by keycloak.

the class AccountFormService method forwardToPage.

private Response forwardToPage(String path, AccountPages page) {
    if (auth != null) {
        try {
            auth.require(AccountRoles.MANAGE_ACCOUNT);
        } catch (ForbiddenException e) {
            return session.getProvider(LoginFormsProvider.class).setError(Messages.NO_ACCESS).createErrorPage(Response.Status.FORBIDDEN);
        }
        setReferrerOnPage();
        UserSessionModel userSession = auth.getSession();
        String tabId = session.getContext().getUri().getQueryParameters().getFirst(org.keycloak.models.Constants.TAB_ID);
        if (tabId != null) {
            AuthenticationSessionModel authSession = new AuthenticationSessionManager(session).getAuthenticationSessionByIdAndClient(realm, userSession.getId(), client, tabId);
            if (authSession != null) {
                String forwardedError = authSession.getAuthNote(ACCOUNT_MGMT_FORWARDED_ERROR_NOTE);
                if (forwardedError != null) {
                    try {
                        FormMessage errorMessage = JsonSerialization.readValue(forwardedError, FormMessage.class);
                        account.setError(Response.Status.INTERNAL_SERVER_ERROR, errorMessage.getMessage(), errorMessage.getParameters());
                        authSession.removeAuthNote(ACCOUNT_MGMT_FORWARDED_ERROR_NOTE);
                    } catch (IOException ioe) {
                        throw new RuntimeException(ioe);
                    }
                }
            }
        }
        String locale = session.getContext().getUri().getQueryParameters().getFirst(LocaleSelectorProvider.KC_LOCALE_PARAM);
        if (locale != null) {
            LocaleUpdaterProvider updater = session.getProvider(LocaleUpdaterProvider.class);
            updater.updateUsersLocale(auth.getUser(), locale);
        }
        return account.createResponse(page);
    } else {
        return login(path);
    }
}
Also used : AuthenticationSessionManager(org.keycloak.services.managers.AuthenticationSessionManager) ForbiddenException(org.keycloak.services.ForbiddenException) LoginFormsProvider(org.keycloak.forms.login.LoginFormsProvider) UserSessionModel(org.keycloak.models.UserSessionModel) AuthenticationSessionModel(org.keycloak.sessions.AuthenticationSessionModel) LocaleUpdaterProvider(org.keycloak.locale.LocaleUpdaterProvider) IOException(java.io.IOException) FormMessage(org.keycloak.models.utils.FormMessage)

Example 34 with AuthenticationSessionModel

use of org.keycloak.sessions.AuthenticationSessionModel in project keycloak by keycloak.

the class LoginActionsService method brokerLoginFlow.

protected Response brokerLoginFlow(String authSessionId, String code, String execution, String clientId, String tabId, String flowPath) {
    boolean firstBrokerLogin = flowPath.equals(FIRST_BROKER_LOGIN_PATH);
    EventType eventType = firstBrokerLogin ? EventType.IDENTITY_PROVIDER_FIRST_LOGIN : EventType.IDENTITY_PROVIDER_POST_LOGIN;
    event.event(eventType);
    SessionCodeChecks checks = checksForCode(authSessionId, code, execution, clientId, tabId, flowPath);
    if (!checks.verifyActiveAndValidAction(AuthenticationSessionModel.Action.AUTHENTICATE.name(), ClientSessionCode.ActionType.LOGIN)) {
        return checks.getResponse();
    }
    event.detail(Details.CODE_ID, code);
    final AuthenticationSessionModel authSession = checks.getAuthenticationSession();
    processLocaleParam(authSession);
    String noteKey = firstBrokerLogin ? AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE : PostBrokerLoginConstants.PBL_BROKERED_IDENTITY_CONTEXT;
    SerializedBrokeredIdentityContext serializedCtx = SerializedBrokeredIdentityContext.readFromAuthenticationSession(authSession, noteKey);
    if (serializedCtx == null) {
        ServicesLogger.LOGGER.notFoundSerializedCtxInClientSession(noteKey);
        throw new WebApplicationException(ErrorPage.error(session, authSession, Response.Status.BAD_REQUEST, "Not found serialized context in authenticationSession."));
    }
    BrokeredIdentityContext brokerContext = serializedCtx.deserialize(session, authSession);
    final String identityProviderAlias = brokerContext.getIdpConfig().getAlias();
    String flowId = firstBrokerLogin ? brokerContext.getIdpConfig().getFirstBrokerLoginFlowId() : brokerContext.getIdpConfig().getPostBrokerLoginFlowId();
    if (flowId == null) {
        ServicesLogger.LOGGER.flowNotConfigForIDP(identityProviderAlias);
        throw new WebApplicationException(ErrorPage.error(session, authSession, Response.Status.BAD_REQUEST, "Flow not configured for identity provider"));
    }
    AuthenticationFlowModel brokerLoginFlow = realm.getAuthenticationFlowById(flowId);
    if (brokerLoginFlow == null) {
        ServicesLogger.LOGGER.flowNotFoundForIDP(flowId, identityProviderAlias);
        throw new WebApplicationException(ErrorPage.error(session, authSession, Response.Status.BAD_REQUEST, "Flow not found for identity provider"));
    }
    event.detail(Details.IDENTITY_PROVIDER, identityProviderAlias).detail(Details.IDENTITY_PROVIDER_USERNAME, brokerContext.getUsername());
    AuthenticationProcessor processor = new AuthenticationProcessor() {

        @Override
        public Response authenticateOnly() throws AuthenticationFlowException {
            Response challenge = super.authenticateOnly();
            if (challenge != null) {
                if ("true".equals(authenticationSession.getAuthNote(FORWARDED_PASSIVE_LOGIN))) {
                    // forwarded passive login is incompatible with challenges created by the broker flows.
                    logger.errorf("Challenge encountered when executing %s flow. Auth requests with prompt=none are incompatible with challenges", flowPath);
                    LoginProtocol protocol = session.getProvider(LoginProtocol.class, authSession.getProtocol());
                    protocol.setRealm(realm).setHttpHeaders(headers).setUriInfo(session.getContext().getUri()).setEventBuilder(event);
                    return protocol.sendError(authSession, Error.PASSIVE_INTERACTION_REQUIRED);
                }
            }
            return challenge;
        }

        @Override
        protected Response authenticationComplete() {
            if (firstBrokerLogin) {
                authSession.setAuthNote(AbstractIdpAuthenticator.FIRST_BROKER_LOGIN_SUCCESS, identityProviderAlias);
            } else {
                String authStateNoteKey = PostBrokerLoginConstants.PBL_AUTH_STATE_PREFIX + identityProviderAlias;
                authSession.setAuthNote(authStateNoteKey, "true");
            }
            return redirectToAfterBrokerLoginEndpoint(authSession, firstBrokerLogin);
        }
    };
    return processFlow(checks.isActionRequest(), execution, authSession, flowPath, brokerLoginFlow, null, processor);
}
Also used : Response(javax.ws.rs.core.Response) AuthenticationSessionModel(org.keycloak.sessions.AuthenticationSessionModel) RootAuthenticationSessionModel(org.keycloak.sessions.RootAuthenticationSessionModel) WebApplicationException(javax.ws.rs.WebApplicationException) EventType(org.keycloak.events.EventType) AuthenticationFlowModel(org.keycloak.models.AuthenticationFlowModel) SerializedBrokeredIdentityContext(org.keycloak.authentication.authenticators.broker.util.SerializedBrokeredIdentityContext) AuthenticationProcessor(org.keycloak.authentication.AuthenticationProcessor) OIDCLoginProtocol(org.keycloak.protocol.oidc.OIDCLoginProtocol) LoginProtocol(org.keycloak.protocol.LoginProtocol) BrokeredIdentityContext(org.keycloak.broker.provider.BrokeredIdentityContext) SerializedBrokeredIdentityContext(org.keycloak.authentication.authenticators.broker.util.SerializedBrokeredIdentityContext)

Example 35 with AuthenticationSessionModel

use of org.keycloak.sessions.AuthenticationSessionModel in project keycloak by keycloak.

the class LoginActionsService method handleActionToken.

protected <T extends JsonWebToken & ActionTokenKeyModel> Response handleActionToken(String tokenString, String execution, String clientId, String tabId) {
    T token;
    ActionTokenHandler<T> handler;
    ActionTokenContext<T> tokenContext;
    String eventError = null;
    String defaultErrorMessage = null;
    AuthenticationSessionModel authSession = null;
    // Setup client, so error page will contain "back to application" link
    ClientModel client = null;
    if (clientId != null) {
        client = realm.getClientByClientId(clientId);
    }
    AuthenticationSessionManager authenticationSessionManager = new AuthenticationSessionManager(session);
    if (client != null) {
        session.getContext().setClient(client);
        authSession = authenticationSessionManager.getCurrentAuthenticationSession(realm, client, tabId);
    }
    event.event(EventType.EXECUTE_ACTION_TOKEN);
    // First resolve action token handler
    try {
        if (tokenString == null) {
            throw new ExplainedTokenVerificationException(null, Errors.NOT_ALLOWED, Messages.INVALID_REQUEST);
        }
        TokenVerifier<DefaultActionTokenKey> tokenVerifier = TokenVerifier.create(tokenString, DefaultActionTokenKey.class);
        DefaultActionTokenKey aToken = tokenVerifier.getToken();
        event.detail(Details.TOKEN_ID, aToken.getId()).detail(Details.ACTION, aToken.getActionId()).user(aToken.getUserId());
        handler = resolveActionTokenHandler(aToken.getActionId());
        eventError = handler.getDefaultEventError();
        defaultErrorMessage = handler.getDefaultErrorMessage();
        if (!realm.isEnabled()) {
            throw new ExplainedTokenVerificationException(aToken, Errors.REALM_DISABLED, Messages.REALM_NOT_ENABLED);
        }
        if (!checkSsl()) {
            throw new ExplainedTokenVerificationException(aToken, Errors.SSL_REQUIRED, Messages.HTTPS_REQUIRED);
        }
        TokenVerifier<DefaultActionTokenKey> verifier = tokenVerifier.withChecks(// Token introspection checks
        TokenVerifier.IS_ACTIVE, new TokenVerifier.RealmUrlCheck(Urls.realmIssuer(session.getContext().getUri().getBaseUri(), realm.getName())), ACTION_TOKEN_BASIC_CHECKS);
        String kid = verifier.getHeader().getKeyId();
        String algorithm = verifier.getHeader().getAlgorithm().name();
        SignatureVerifierContext signatureVerifier = session.getProvider(SignatureProvider.class, algorithm).verifier(kid);
        verifier.verifierContext(signatureVerifier);
        verifier.verify();
        token = TokenVerifier.create(tokenString, handler.getTokenClass()).getToken();
    } catch (TokenNotActiveException ex) {
        if (authSession != null) {
            event.clone().error(Errors.EXPIRED_CODE);
            String flowPath = authSession.getClientNote(AuthorizationEndpointBase.APP_INITIATED_FLOW);
            if (flowPath == null) {
                flowPath = AUTHENTICATE_PATH;
            }
            AuthenticationProcessor.resetFlow(authSession, flowPath);
            // Process correct flow
            return processFlowFromPath(flowPath, authSession, Messages.EXPIRED_ACTION_TOKEN_SESSION_EXISTS);
        }
        return handleActionTokenVerificationException(null, ex, Errors.EXPIRED_CODE, Messages.EXPIRED_ACTION_TOKEN_NO_SESSION);
    } catch (ExplainedTokenVerificationException ex) {
        return handleActionTokenVerificationException(null, ex, ex.getErrorEvent(), ex.getMessage());
    } catch (ExplainedVerificationException ex) {
        return handleActionTokenVerificationException(null, ex, ex.getErrorEvent(), ex.getMessage());
    } catch (VerificationException ex) {
        return handleActionTokenVerificationException(null, ex, eventError, defaultErrorMessage);
    }
    // Now proceed with the verification and handle the token
    tokenContext = new ActionTokenContext(session, realm, session.getContext().getUri(), clientConnection, request, event, handler, execution, this::processFlow, this::brokerLoginFlow);
    try {
        String tokenAuthSessionCompoundId = handler.getAuthenticationSessionIdFromToken(token, tokenContext, authSession);
        if (tokenAuthSessionCompoundId != null) {
            // This can happen if the token contains ID but user opens the link in a new browser
            String sessionId = AuthenticationSessionCompoundId.encoded(tokenAuthSessionCompoundId).getRootSessionId();
            LoginActionsServiceChecks.checkNotLoggedInYet(tokenContext, authSession, sessionId);
        }
        if (authSession == null) {
            authSession = handler.startFreshAuthenticationSession(token, tokenContext);
            tokenContext.setAuthenticationSession(authSession, true);
        } else if (tokenAuthSessionCompoundId == null || !LoginActionsServiceChecks.doesAuthenticationSessionFromCookieMatchOneFromToken(tokenContext, authSession, tokenAuthSessionCompoundId)) {
            // There exists an authentication session but no auth session ID was received in the action token
            logger.debugf("Authentication session in progress but no authentication session ID was found in action token %s, restarting.", token.getId());
            authenticationSessionManager.removeAuthenticationSession(realm, authSession, false);
            authSession = handler.startFreshAuthenticationSession(token, tokenContext);
            tokenContext.setAuthenticationSession(authSession, true);
            processLocaleParam(authSession);
        }
        initLoginEvent(authSession);
        event.event(handler.eventType());
        LoginActionsServiceChecks.checkIsUserValid(token, tokenContext);
        LoginActionsServiceChecks.checkIsClientValid(token, tokenContext);
        session.getContext().setClient(authSession.getClient());
        TokenVerifier.createWithoutSignature(token).withChecks(handler.getVerifiers(tokenContext)).verify();
        authSession = tokenContext.getAuthenticationSession();
        event = tokenContext.getEvent();
        event.event(handler.eventType());
        if (!handler.canUseTokenRepeatedly(token, tokenContext)) {
            LoginActionsServiceChecks.checkTokenWasNotUsedYet(token, tokenContext);
            authSession.setAuthNote(AuthenticationManager.INVALIDATE_ACTION_TOKEN, token.serializeKey());
        }
        authSession.setAuthNote(DefaultActionTokenKey.ACTION_TOKEN_USER_ID, token.getUserId());
        authSession.setAuthNote(Constants.KEY, tokenString);
        return handler.handleToken(token, tokenContext);
    } catch (ExplainedTokenVerificationException ex) {
        return handleActionTokenVerificationException(tokenContext, ex, ex.getErrorEvent(), ex.getMessage());
    } catch (LoginActionsServiceException ex) {
        Response response = ex.getResponse();
        return response == null ? handleActionTokenVerificationException(tokenContext, ex, eventError, defaultErrorMessage) : response;
    } catch (VerificationException ex) {
        return handleActionTokenVerificationException(tokenContext, ex, eventError, defaultErrorMessage);
    }
}
Also used : TokenNotActiveException(org.keycloak.exceptions.TokenNotActiveException) AuthenticationSessionModel(org.keycloak.sessions.AuthenticationSessionModel) RootAuthenticationSessionModel(org.keycloak.sessions.RootAuthenticationSessionModel) SignatureVerifierContext(org.keycloak.crypto.SignatureVerifierContext) ExplainedVerificationException(org.keycloak.authentication.ExplainedVerificationException) ActionTokenContext(org.keycloak.authentication.actiontoken.ActionTokenContext) DefaultActionTokenKey(org.keycloak.authentication.actiontoken.DefaultActionTokenKey) AuthenticationSessionManager(org.keycloak.services.managers.AuthenticationSessionManager) Response(javax.ws.rs.core.Response) ClientModel(org.keycloak.models.ClientModel) SignatureProvider(org.keycloak.crypto.SignatureProvider) GET(javax.ws.rs.GET) POST(javax.ws.rs.POST) ExplainedTokenVerificationException(org.keycloak.authentication.actiontoken.ExplainedTokenVerificationException) TokenVerifier(org.keycloak.TokenVerifier) VerificationException(org.keycloak.common.VerificationException) ExplainedVerificationException(org.keycloak.authentication.ExplainedVerificationException) ExplainedTokenVerificationException(org.keycloak.authentication.actiontoken.ExplainedTokenVerificationException)

Aggregations

AuthenticationSessionModel (org.keycloak.sessions.AuthenticationSessionModel)89 RootAuthenticationSessionModel (org.keycloak.sessions.RootAuthenticationSessionModel)48 ClientModel (org.keycloak.models.ClientModel)27 UserModel (org.keycloak.models.UserModel)24 Response (javax.ws.rs.core.Response)23 RealmModel (org.keycloak.models.RealmModel)20 UserSessionModel (org.keycloak.models.UserSessionModel)20 AuthenticationSessionManager (org.keycloak.services.managers.AuthenticationSessionManager)18 KeycloakSession (org.keycloak.models.KeycloakSession)16 ClientSessionContext (org.keycloak.models.ClientSessionContext)13 LoginFormsProvider (org.keycloak.forms.login.LoginFormsProvider)10 URI (java.net.URI)9 UriBuilder (javax.ws.rs.core.UriBuilder)9 EventBuilder (org.keycloak.events.EventBuilder)9 LoginProtocol (org.keycloak.protocol.LoginProtocol)9 GET (javax.ws.rs.GET)8 Path (javax.ws.rs.Path)8 AuthenticationFlowException (org.keycloak.authentication.AuthenticationFlowException)8 OIDCLoginProtocol (org.keycloak.protocol.oidc.OIDCLoginProtocol)8 Map (java.util.Map)7