Search in sources :

Example 41 with AuthenticationSessionModel

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

the class SessionCodeChecks method initialVerify.

public boolean initialVerify() {
    // Basic realm checks and authenticationSession retrieve
    authSession = initialVerifyAuthSession();
    if (authSession == null) {
        return false;
    }
    // Check cached response from previous action request
    response = BrowserHistoryHelper.getInstance().loadSavedResponse(session, authSession);
    if (response != null) {
        return false;
    }
    // Client checks
    event.detail(Details.CODE_ID, authSession.getParentSession().getId());
    ClientModel client = authSession.getClient();
    if (client == null) {
        event.error(Errors.CLIENT_NOT_FOUND);
        response = ErrorPage.error(session, authSession, Response.Status.BAD_REQUEST, Messages.UNKNOWN_LOGIN_REQUESTER);
        clientCode.removeExpiredClientSession();
        return false;
    }
    event.client(client);
    session.getContext().setClient(client);
    if (!client.isEnabled()) {
        event.error(Errors.CLIENT_DISABLED);
        response = ErrorPage.error(session, authSession, Response.Status.BAD_REQUEST, Messages.LOGIN_REQUESTER_NOT_ENABLED);
        clientCode.removeExpiredClientSession();
        return false;
    }
    // Check if it's action or not
    if (code == null) {
        String lastExecFromSession = authSession.getAuthNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION);
        String lastFlow = authSession.getAuthNote(AuthenticationProcessor.CURRENT_FLOW_PATH);
        // Check if we transitted between flows (eg. clicking "register" on login screen)
        if (execution == null && !flowPath.equals(lastFlow)) {
            logger.debugf("Transition between flows! Current flow: %s, Previous flow: %s", flowPath, lastFlow);
            // Don't allow moving to different flow if I am on requiredActions already
            if (AuthenticationSessionModel.Action.AUTHENTICATE.name().equals(authSession.getAction())) {
                authSession.setAuthNote(AuthenticationProcessor.CURRENT_FLOW_PATH, flowPath);
                authSession.removeAuthNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION);
                lastExecFromSession = null;
            }
        }
        if (execution == null || execution.equals(lastExecFromSession)) {
            // Allow refresh of previous page
            clientCode = new ClientSessionCode<>(session, realm, authSession);
            actionRequest = false;
            // Allow refresh, but rewrite browser history
            if (execution == null && lastExecFromSession != null) {
                logger.debugf("Parameter 'execution' is not in the request, but flow wasn't changed. Will update browser history");
                request.setAttribute(BrowserHistoryHelper.SHOULD_UPDATE_BROWSER_HISTORY, true);
            }
            return true;
        } else {
            response = showPageExpired(authSession);
            return false;
        }
    } else {
        ClientSessionCode.ParseResult<AuthenticationSessionModel> result = ClientSessionCode.parseResult(code, tabId, session, realm, client, event, authSession);
        clientCode = result.getCode();
        if (clientCode == null) {
            // In case that is replayed action, but sent to the same FORM like actual FORM, we just re-render the page
            if (ObjectUtil.isEqualOrBothNull(execution, authSession.getAuthNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION))) {
                String latestFlowPath = authSession.getAuthNote(AuthenticationProcessor.CURRENT_FLOW_PATH);
                URI redirectUri = getLastExecutionUrl(latestFlowPath, execution, tabId);
                logger.debugf("Invalid action code, but execution matches. So just redirecting to %s", redirectUri);
                authSession.setAuthNote(LoginActionsService.FORWARDED_ERROR_MESSAGE_NOTE, Messages.EXPIRED_ACTION);
                response = Response.status(Response.Status.FOUND).location(redirectUri).build();
            } else {
                response = showPageExpired(authSession);
            }
            return false;
        }
        actionRequest = true;
        if (execution != null) {
            authSession.setAuthNote(AuthenticationProcessor.LAST_PROCESSED_EXECUTION, execution);
        }
        return true;
    }
}
Also used : ClientModel(org.keycloak.models.ClientModel) AuthenticationSessionModel(org.keycloak.sessions.AuthenticationSessionModel) RootAuthenticationSessionModel(org.keycloak.sessions.RootAuthenticationSessionModel) ClientSessionCode(org.keycloak.services.managers.ClientSessionCode) URI(java.net.URI)

Example 42 with AuthenticationSessionModel

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

the class ClientScopeEvaluateResource method sessionAware.

private <R> R sessionAware(UserModel user, String scopeParam, BiFunction<UserSessionModel, ClientSessionContext, R> function) {
    AuthenticationSessionModel authSession = null;
    AuthenticationSessionManager authSessionManager = new AuthenticationSessionManager(session);
    try {
        RootAuthenticationSessionModel rootAuthSession = authSessionManager.createAuthenticationSession(realm, false);
        authSession = rootAuthSession.createAuthenticationSession(client);
        authSession.setAuthenticatedUser(user);
        authSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
        authSession.setClientNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()));
        authSession.setClientNote(OIDCLoginProtocol.SCOPE_PARAM, scopeParam);
        UserSessionModel userSession = session.sessions().createUserSession(authSession.getParentSession().getId(), realm, user, user.getUsername(), clientConnection.getRemoteAddr(), "example-auth", false, null, null, UserSessionModel.SessionPersistenceState.TRANSIENT);
        AuthenticationManager.setClientScopesInSession(authSession);
        ClientSessionContext clientSessionCtx = TokenManager.attachAuthenticationSession(session, userSession, authSession);
        return function.apply(userSession, clientSessionCtx);
    } finally {
        if (authSession != null) {
            authSessionManager.removeAuthenticationSession(realm, authSession, false);
        }
    }
}
Also used : AuthenticationSessionManager(org.keycloak.services.managers.AuthenticationSessionManager) AuthenticationSessionModel(org.keycloak.sessions.AuthenticationSessionModel) RootAuthenticationSessionModel(org.keycloak.sessions.RootAuthenticationSessionModel) UserSessionModel(org.keycloak.models.UserSessionModel) ClientSessionContext(org.keycloak.models.ClientSessionContext) RootAuthenticationSessionModel(org.keycloak.sessions.RootAuthenticationSessionModel)

Example 43 with AuthenticationSessionModel

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

the class AuthenticationSessionTest method testLimitAuthSessions.

@Test
public void testLimitAuthSessions() {
    RootAuthenticationSessionModel ras = withRealm(realmId, (session, realm) -> session.authenticationSessions().createRootAuthenticationSession(realm));
    List<String> tabIds = withRealm(realmId, (session, realm) -> {
        ClientModel client = realm.getClientByClientId("test-app");
        return IntStream.range(0, 300).mapToObj(i -> {
            Time.setOffset(i);
            return ras.createAuthenticationSession(client);
        }).map(AuthenticationSessionModel::getTabId).collect(Collectors.toList());
    });
    withRealm(realmId, (session, realm) -> {
        ClientModel client = realm.getClientByClientId("test-app");
        // create 301st auth session
        AuthenticationSessionModel as = ras.createAuthenticationSession(client);
        Assert.assertEquals(as, ras.getAuthenticationSession(client, as.getTabId()));
        // assert the first authentication session was deleted
        Assert.assertNull(ras.getAuthenticationSession(client, tabIds.get(0)));
        return null;
    });
}
Also used : ClientModel(org.keycloak.models.ClientModel) AuthenticationSessionModel(org.keycloak.sessions.AuthenticationSessionModel) RootAuthenticationSessionModel(org.keycloak.sessions.RootAuthenticationSessionModel) RootAuthenticationSessionModel(org.keycloak.sessions.RootAuthenticationSessionModel) Test(org.junit.Test) KeycloakModelTest(org.keycloak.testsuite.model.KeycloakModelTest)

Example 44 with AuthenticationSessionModel

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

the class AuthenticatorUtilTest method variousFactoryProviders.

@Test
public void variousFactoryProviders() {
    testingClient.server().run(session -> {
        RealmModel realm = session.realms().getRealm(TEST_REALM_NAME);
        assertThat(realm, notNullValue());
        ClientModel client = realm.getClientByClientId("test-app");
        assertThat(client, notNullValue());
        AuthenticationSessionModel authSession = session.authenticationSessions().createRootAuthenticationSession(realm).createAuthenticationSession(client);
        assertThat(authSession, notNullValue());
        Set<String> callbacksFactories = AuthenticatorUtil.getAuthCallbacksFactoryIds(authSession);
        assertThat(callbacksFactories, notNullValue());
        assertThat(callbacksFactories, Matchers.empty());
        AuthenticatorUtil.setAuthCallbacksFactoryIds(authSession, "factory1");
        callbacksFactories = AuthenticatorUtil.getAuthCallbacksFactoryIds(authSession);
        assertThat(callbacksFactories, notNullValue());
        assertThat(callbacksFactories.size(), is(1));
        String note = authSession.getAuthNote(AuthenticatorUtil.CALLBACKS_FACTORY_IDS_NOTE);
        assertThat(note, notNullValue());
        assertThat(note, is("factory1"));
        AuthenticatorUtil.setAuthCallbacksFactoryIds(authSession, "factory2");
        callbacksFactories = AuthenticatorUtil.getAuthCallbacksFactoryIds(authSession);
        assertThat(callbacksFactories, notNullValue());
        assertThat(callbacksFactories.size(), is(2));
        note = authSession.getAuthNote(AuthenticatorUtil.CALLBACKS_FACTORY_IDS_NOTE);
        assertThat(note, notNullValue());
        assertThat(note, is("factory1" + Constants.CFG_DELIMITER + "factory2"));
        AuthenticatorUtil.setAuthCallbacksFactoryIds(authSession, "factory1");
        callbacksFactories = AuthenticatorUtil.getAuthCallbacksFactoryIds(authSession);
        assertThat(callbacksFactories, notNullValue());
        assertThat(callbacksFactories.size(), is(2));
        note = authSession.getAuthNote(AuthenticatorUtil.CALLBACKS_FACTORY_IDS_NOTE);
        assertThat(note, notNullValue());
        assertThat(note, is("factory1" + Constants.CFG_DELIMITER + "factory2"));
        AuthenticatorUtil.setAuthCallbacksFactoryIds(authSession, "");
        callbacksFactories = AuthenticatorUtil.getAuthCallbacksFactoryIds(authSession);
        assertThat(callbacksFactories, notNullValue());
        assertThat(callbacksFactories.size(), is(2));
        note = authSession.getAuthNote(AuthenticatorUtil.CALLBACKS_FACTORY_IDS_NOTE);
        assertThat(note, notNullValue());
        assertThat(note, is("factory1" + Constants.CFG_DELIMITER + "factory2"));
        AuthenticatorUtil.setAuthCallbacksFactoryIds(authSession, null);
        callbacksFactories = AuthenticatorUtil.getAuthCallbacksFactoryIds(authSession);
        assertThat(callbacksFactories, notNullValue());
        assertThat(callbacksFactories.size(), is(2));
        note = authSession.getAuthNote(AuthenticatorUtil.CALLBACKS_FACTORY_IDS_NOTE);
        assertThat(note, notNullValue());
        assertThat(note, is("factory1" + Constants.CFG_DELIMITER + "factory2"));
    });
}
Also used : RealmModel(org.keycloak.models.RealmModel) ClientModel(org.keycloak.models.ClientModel) AuthenticationSessionModel(org.keycloak.sessions.AuthenticationSessionModel) Test(org.junit.Test) AbstractTestRealmKeycloakTest(org.keycloak.testsuite.AbstractTestRealmKeycloakTest)

Example 45 with AuthenticationSessionModel

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

the class MSADUserAccountControlStorageMapper method processAuthErrorCode.

protected boolean processAuthErrorCode(String errorCode, UserModel user) {
    logger.debugf("MSAD Error code is '%s' after failed LDAP login of user '%s'. Realm is '%s'", errorCode, user.getUsername(), getRealmName());
    if (ldapProvider.getEditMode() == UserStorageProvider.EditMode.WRITABLE) {
        if (errorCode.equals("532") || errorCode.equals("773")) {
            // User needs to change his MSAD password. Allow him to login, but add UPDATE_PASSWORD required action to authenticationSession
            if (user.getRequiredActionsStream().noneMatch(action -> Objects.equals(action, UserModel.RequiredAction.UPDATE_PASSWORD.name()))) {
                // This usually happens when 532 was returned, which means that "pwdLastSet" is set to some positive value, which is older than MSAD password expiration policy.
                AuthenticationSessionModel authSession = session.getContext().getAuthenticationSession();
                if (authSession != null) {
                    if (authSession.getRequiredActions().stream().noneMatch(action -> Objects.equals(action, UserModel.RequiredAction.UPDATE_PASSWORD.name()))) {
                        logger.debugf("Adding requiredAction UPDATE_PASSWORD to the authenticationSession of user %s", user.getUsername());
                        authSession.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
                    }
                } else {
                    // Just a fallback. It should not happen during normal authentication process
                    logger.debugf("Adding requiredAction UPDATE_PASSWORD to the user %s", user.getUsername());
                    user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
                }
            } else {
                // This usually happens when "773" error code is returned by MSAD. This typically happens when "pwdLastSet" is set to 0 and password was manually set
                // by administrator (or user) to expire
                logger.tracef("Skip adding required action UPDATE_PASSWORD. It was already set on user '%s' in realm '%s'", user.getUsername(), getRealmName());
            }
            return true;
        } else if (errorCode.equals("533")) {
            // User is disabled in MSAD. Set him to disabled in KC as well
            if (user.isEnabled()) {
                user.setEnabled(false);
            }
            return true;
        } else if (errorCode.equals("775")) {
            logger.warnf("Locked user '%s' attempt to login. Realm is '%s'", user.getUsername(), getRealmName());
        }
    }
    return false;
}
Also used : AuthenticationSessionModel(org.keycloak.sessions.AuthenticationSessionModel)

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