Search in sources :

Example 41 with AuthenticatedClientSessionModel

use of org.keycloak.models.AuthenticatedClientSessionModel in project keycloak by keycloak.

the class OIDCAdvancedRequestParamsTest method processClaimsRequestParam.

@Test
public void processClaimsRequestParam() throws Exception {
    Map<String, Object> claims = ImmutableMap.of("id_token", ImmutableMap.of("test_claim", ImmutableMap.of("essential", true)));
    String claimsJson = JsonSerialization.writeValueAsString(claims);
    Map<String, Object> oidcRequest = new HashMap<>();
    oidcRequest.put(OIDCLoginProtocol.CLIENT_ID_PARAM, "test-app");
    oidcRequest.put(OIDCLoginProtocol.RESPONSE_TYPE_PARAM, OAuth2Constants.CODE);
    oidcRequest.put(OIDCLoginProtocol.REDIRECT_URI_PARAM, oauth.getRedirectUri());
    oidcRequest.put(OIDCLoginProtocol.CLAIMS_PARAM, claims);
    String request = new JWSBuilder().jsonContent(oidcRequest).none();
    driver.navigate().to(oauth.getLoginFormUrl() + "&" + OIDCLoginProtocol.REQUEST_PARAM + "=" + request);
    // need to login so session id can be read from event
    loginPage.assertCurrent();
    loginPage.login("test-user@localhost", "password");
    Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
    EventRepresentation loginEvent = events.expectLogin().detail(Details.USERNAME, "test-user@localhost").assertEvent();
    String sessionId = loginEvent.getSessionId();
    String clientId = loginEvent.getClientId();
    testingClient.server("test").run(session -> {
        RealmModel realmModel = session.getContext().getRealm();
        String clientUuid = realmModel.getClientByClientId(clientId).getId();
        UserSessionModel userSession = session.sessions().getUserSession(realmModel, sessionId);
        AuthenticatedClientSessionModel clientSession = userSession.getAuthenticatedClientSessionByClient(clientUuid);
        String claimsInSession = clientSession.getNote(OIDCLoginProtocol.CLAIMS_PARAM);
        assertEquals(claimsJson, claimsInSession);
    });
}
Also used : RealmModel(org.keycloak.models.RealmModel) UserSessionModel(org.keycloak.models.UserSessionModel) HashMap(java.util.HashMap) MultivaluedHashMap(org.keycloak.common.util.MultivaluedHashMap) EventRepresentation(org.keycloak.representations.idm.EventRepresentation) AuthenticatedClientSessionModel(org.keycloak.models.AuthenticatedClientSessionModel) JWSBuilder(org.keycloak.jose.jws.JWSBuilder) AbstractAdminTest(org.keycloak.testsuite.admin.AbstractAdminTest) Test(org.junit.Test) AbstractTestRealmKeycloakTest(org.keycloak.testsuite.AbstractTestRealmKeycloakTest)

Example 42 with AuthenticatedClientSessionModel

use of org.keycloak.models.AuthenticatedClientSessionModel in project keycloak by keycloak.

the class PersistSessionsCommand method createSessionsBatch.

private void createSessionsBatch(final int countInThisBatch) {
    final List<String> userSessionIds = new LinkedList<>();
    KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {

        @Override
        public void run(KeycloakSession session) {
            RealmModel realm = session.realms().getRealmByName("master");
            ClientModel testApp = realm.getClientByClientId("security-admin-console");
            UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
            for (int i = 0; i < countInThisBatch; i++) {
                String username = "john-" + userCounter.incrementAndGet();
                UserModel john = session.users().getUserByUsername(realm, username);
                if (john == null) {
                    john = session.users().addUser(realm, username);
                }
                UserSessionModel userSession = session.sessions().createUserSession(realm, john, username, "127.0.0.2", "form", true, null, null);
                AuthenticatedClientSessionModel clientSession = session.sessions().createClientSession(realm, testApp, userSession);
                clientSession.setRedirectUri("http://redirect");
                clientSession.setNote("foo", "bar-" + i);
                userSessionIds.add(userSession.getId());
            }
        }
    });
    log.infof("%d sessions created in infinispan storage", countInThisBatch);
    // Persist them now
    KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {

        @Override
        public void run(KeycloakSession session) {
            RealmModel realm = session.realms().getRealmByName("master");
            ClientModel testApp = realm.getClientByClientId("security-admin-console");
            UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
            int counter = 0;
            for (String userSessionId : userSessionIds) {
                counter++;
                UserSessionModel userSession = session.sessions().getUserSession(realm, userSessionId);
                persister.createUserSession(userSession, true);
                AuthenticatedClientSessionModel clientSession = userSession.getAuthenticatedClientSessions().get(testApp.getId());
                persister.createClientSession(clientSession, true);
            }
            log.infof("%d user sessions persisted. Continue", counter);
        }
    });
}
Also used : RealmModel(org.keycloak.models.RealmModel) UserModel(org.keycloak.models.UserModel) ClientModel(org.keycloak.models.ClientModel) UserSessionModel(org.keycloak.models.UserSessionModel) UserSessionPersisterProvider(org.keycloak.models.session.UserSessionPersisterProvider) KeycloakSessionTask(org.keycloak.models.KeycloakSessionTask) KeycloakSession(org.keycloak.models.KeycloakSession) AuthenticatedClientSessionModel(org.keycloak.models.AuthenticatedClientSessionModel) LinkedList(java.util.LinkedList)

Example 43 with AuthenticatedClientSessionModel

use of org.keycloak.models.AuthenticatedClientSessionModel in project keycloak by keycloak.

the class AuthorizationTokenService method createAuthorizationResponse.

private AuthorizationResponse createAuthorizationResponse(KeycloakIdentity identity, Collection<Permission> entitlements, KeycloakAuthorizationRequest request, ClientModel targetClient) {
    KeycloakSession keycloakSession = request.getKeycloakSession();
    AccessToken accessToken = identity.getAccessToken();
    RealmModel realm = request.getRealm();
    UserSessionProvider sessions = keycloakSession.sessions();
    UserSessionModel userSessionModel;
    if (accessToken.getSessionState() == null) {
        // Create temporary (request-scoped) transient session
        UserModel user = TokenManager.lookupUserFromStatelessToken(keycloakSession, realm, accessToken);
        userSessionModel = sessions.createUserSession(KeycloakModelUtils.generateId(), realm, user, user.getUsername(), request.getClientConnection().getRemoteAddr(), ServiceAccountConstants.CLIENT_AUTH, false, null, null, UserSessionModel.SessionPersistenceState.TRANSIENT);
    } else {
        userSessionModel = sessions.getUserSession(realm, accessToken.getSessionState());
        if (userSessionModel == null) {
            userSessionModel = sessions.getOfflineUserSession(realm, accessToken.getSessionState());
        }
    }
    ClientModel client = realm.getClientByClientId(accessToken.getIssuedFor());
    AuthenticatedClientSessionModel clientSession = userSessionModel.getAuthenticatedClientSessionByClient(targetClient.getId());
    ClientSessionContext clientSessionCtx;
    if (clientSession == null) {
        RootAuthenticationSessionModel rootAuthSession = keycloakSession.authenticationSessions().getRootAuthenticationSession(realm, userSessionModel.getId());
        if (rootAuthSession == null) {
            if (userSessionModel.getUser().getServiceAccountClientLink() == null) {
                rootAuthSession = keycloakSession.authenticationSessions().createRootAuthenticationSession(realm, userSessionModel.getId());
            } else {
                // if the user session is associated with a service account
                rootAuthSession = new AuthenticationSessionManager(keycloakSession).createAuthenticationSession(realm, false);
            }
        }
        AuthenticationSessionModel authSession = rootAuthSession.createAuthenticationSession(targetClient);
        authSession.setAuthenticatedUser(userSessionModel.getUser());
        authSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
        authSession.setClientNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(keycloakSession.getContext().getUri().getBaseUri(), realm.getName()));
        AuthenticationManager.setClientScopesInSession(authSession);
        clientSessionCtx = TokenManager.attachAuthenticationSession(keycloakSession, userSessionModel, authSession);
    } else {
        clientSessionCtx = DefaultClientSessionContext.fromClientSessionScopeParameter(clientSession, keycloakSession);
    }
    TokenManager tokenManager = request.getTokenManager();
    EventBuilder event = request.getEvent();
    AccessTokenResponseBuilder responseBuilder = tokenManager.responseBuilder(realm, client, event, keycloakSession, userSessionModel, clientSessionCtx).generateAccessToken();
    AccessToken rpt = responseBuilder.getAccessToken();
    Authorization authorization = new Authorization();
    authorization.setPermissions(entitlements);
    rpt.setAuthorization(authorization);
    if (accessToken.getSessionState() == null) {
        // Skip generating refresh token for accessToken without sessionState claim. This is "stateless" accessToken not pointing to any real persistent userSession
        rpt.setSessionState(null);
    } else {
        if (OIDCAdvancedConfigWrapper.fromClientModel(client).isUseRefreshToken()) {
            responseBuilder.generateRefreshToken();
            RefreshToken refreshToken = responseBuilder.getRefreshToken();
            refreshToken.issuedFor(client.getClientId());
            refreshToken.setAuthorization(authorization);
        }
    }
    if (!rpt.hasAudience(targetClient.getClientId())) {
        rpt.audience(targetClient.getClientId());
    }
    return new AuthorizationResponse(responseBuilder.build(), isUpgraded(request, authorization));
}
Also used : UserSessionModel(org.keycloak.models.UserSessionModel) AuthenticationSessionModel(org.keycloak.sessions.AuthenticationSessionModel) RootAuthenticationSessionModel(org.keycloak.sessions.RootAuthenticationSessionModel) AuthenticatedClientSessionModel(org.keycloak.models.AuthenticatedClientSessionModel) AuthorizationResponse(org.keycloak.representations.idm.authorization.AuthorizationResponse) RealmModel(org.keycloak.models.RealmModel) UserModel(org.keycloak.models.UserModel) AuthenticationSessionManager(org.keycloak.services.managers.AuthenticationSessionManager) Authorization(org.keycloak.representations.AccessToken.Authorization) UserSessionProvider(org.keycloak.models.UserSessionProvider) ClientModel(org.keycloak.models.ClientModel) EventBuilder(org.keycloak.events.EventBuilder) RefreshToken(org.keycloak.representations.RefreshToken) DefaultClientSessionContext(org.keycloak.services.util.DefaultClientSessionContext) ClientSessionContext(org.keycloak.models.ClientSessionContext) AccessToken(org.keycloak.representations.AccessToken) KeycloakSession(org.keycloak.models.KeycloakSession) RootAuthenticationSessionModel(org.keycloak.sessions.RootAuthenticationSessionModel) AccessTokenResponseBuilder(org.keycloak.protocol.oidc.TokenManager.AccessTokenResponseBuilder) TokenManager(org.keycloak.protocol.oidc.TokenManager)

Example 44 with AuthenticatedClientSessionModel

use of org.keycloak.models.AuthenticatedClientSessionModel in project keycloak by keycloak.

the class InfinispanUserSessionProvider method importUserSessions.

@Override
public void importUserSessions(Collection<UserSessionModel> persistentUserSessions, boolean offline) {
    if (persistentUserSessions == null || persistentUserSessions.isEmpty()) {
        return;
    }
    Map<UUID, SessionEntityWrapper<AuthenticatedClientSessionEntity>> clientSessionsById = new HashMap<>();
    Map<String, SessionEntityWrapper<UserSessionEntity>> sessionsById = persistentUserSessions.stream().map((UserSessionModel persistentUserSession) -> {
        UserSessionEntity userSessionEntityToImport = createUserSessionEntityInstance(persistentUserSession);
        for (Map.Entry<String, AuthenticatedClientSessionModel> entry : persistentUserSession.getAuthenticatedClientSessions().entrySet()) {
            String clientUUID = entry.getKey();
            AuthenticatedClientSessionModel clientSession = entry.getValue();
            AuthenticatedClientSessionEntity clientSessionToImport = createAuthenticatedClientSessionInstance(clientSession, userSessionEntityToImport.getRealmId(), offline);
            // Update timestamp to same value as userSession. LastSessionRefresh of userSession from DB will have correct value
            clientSessionToImport.setTimestamp(userSessionEntityToImport.getLastSessionRefresh());
            clientSessionsById.put(clientSessionToImport.getId(), new SessionEntityWrapper<>(clientSessionToImport));
            // Update userSession entity with the clientSession
            AuthenticatedClientSessionStore clientSessions = userSessionEntityToImport.getAuthenticatedClientSessions();
            clientSessions.put(clientUUID, clientSessionToImport.getId());
        }
        return userSessionEntityToImport;
    }).map(SessionEntityWrapper::new).collect(Collectors.toMap(sessionEntityWrapper -> sessionEntityWrapper.getEntity().getId(), Function.identity()));
    // Directly put all entities to the infinispan cache
    Cache<String, SessionEntityWrapper<UserSessionEntity>> cache = CacheDecorators.skipCacheLoaders(getCache(offline));
    boolean importWithExpiration = sessionsById.size() == 1;
    if (importWithExpiration) {
        importSessionsWithExpiration(sessionsById, cache, offline ? SessionTimeouts::getOfflineSessionLifespanMs : SessionTimeouts::getUserSessionLifespanMs, offline ? SessionTimeouts::getOfflineSessionMaxIdleMs : SessionTimeouts::getUserSessionMaxIdleMs);
    } else {
        cache.putAll(sessionsById);
    }
    // put all entities to the remoteCache (if exists)
    RemoteCache remoteCache = InfinispanUtil.getRemoteCache(cache);
    if (remoteCache != null) {
        Map<String, SessionEntityWrapper<UserSessionEntity>> sessionsByIdForTransport = sessionsById.values().stream().map(SessionEntityWrapper::forTransport).collect(Collectors.toMap(sessionEntityWrapper -> sessionEntityWrapper.getEntity().getId(), Function.identity()));
        if (importWithExpiration) {
            importSessionsWithExpiration(sessionsByIdForTransport, remoteCache, offline ? SessionTimeouts::getOfflineSessionLifespanMs : SessionTimeouts::getUserSessionLifespanMs, offline ? SessionTimeouts::getOfflineSessionMaxIdleMs : SessionTimeouts::getUserSessionMaxIdleMs);
        } else {
            Retry.executeWithBackoff((int iteration) -> {
                try {
                    remoteCache.putAll(sessionsByIdForTransport);
                } catch (HotRodClientException re) {
                    if (log.isDebugEnabled()) {
                        log.debugf(re, "Failed to put import %d sessions to remoteCache. Iteration '%s'. Will try to retry the task", sessionsByIdForTransport.size(), iteration);
                    }
                    // Rethrow the exception. Retry will take care of handle the exception and eventually retry the operation.
                    throw re;
                }
            }, 10, 10);
        }
    }
    // Import client sessions
    Cache<UUID, SessionEntityWrapper<AuthenticatedClientSessionEntity>> clientSessCache = offline ? offlineClientSessionCache : clientSessionCache;
    clientSessCache = CacheDecorators.skipCacheLoaders(clientSessCache);
    if (importWithExpiration) {
        importSessionsWithExpiration(clientSessionsById, clientSessCache, offline ? SessionTimeouts::getOfflineClientSessionLifespanMs : SessionTimeouts::getClientSessionLifespanMs, offline ? SessionTimeouts::getOfflineClientSessionMaxIdleMs : SessionTimeouts::getClientSessionMaxIdleMs);
    } else {
        clientSessCache.putAll(clientSessionsById);
    }
    // put all entities to the remoteCache (if exists)
    RemoteCache remoteCacheClientSessions = InfinispanUtil.getRemoteCache(clientSessCache);
    if (remoteCacheClientSessions != null) {
        Map<UUID, SessionEntityWrapper<AuthenticatedClientSessionEntity>> sessionsByIdForTransport = clientSessionsById.values().stream().map(SessionEntityWrapper::forTransport).collect(Collectors.toMap(sessionEntityWrapper -> sessionEntityWrapper.getEntity().getId(), Function.identity()));
        if (importWithExpiration) {
            importSessionsWithExpiration(sessionsByIdForTransport, remoteCacheClientSessions, offline ? SessionTimeouts::getOfflineClientSessionLifespanMs : SessionTimeouts::getClientSessionLifespanMs, offline ? SessionTimeouts::getOfflineClientSessionMaxIdleMs : SessionTimeouts::getClientSessionMaxIdleMs);
        } else {
            Retry.executeWithBackoff((int iteration) -> {
                try {
                    remoteCacheClientSessions.putAll(sessionsByIdForTransport);
                } catch (HotRodClientException re) {
                    if (log.isDebugEnabled()) {
                        log.debugf(re, "Failed to put import %d client sessions to remoteCache. Iteration '%s'. Will try to retry the task", sessionsByIdForTransport.size(), iteration);
                    }
                    // Rethrow the exception. Retry will take care of handle the exception and eventually retry the operation.
                    throw re;
                }
            }, 10, 10);
        }
    }
}
Also used : UserSessionProvider(org.keycloak.models.UserSessionProvider) RemoveUserSessionsEvent(org.keycloak.models.sessions.infinispan.events.RemoveUserSessionsEvent) BiFunction(java.util.function.BiFunction) Cache(org.infinispan.Cache) RemoteCache(org.infinispan.client.hotrod.RemoteCache) FuturesHelper(org.keycloak.models.sessions.infinispan.util.FuturesHelper) ClusterProvider(org.keycloak.cluster.ClusterProvider) PersisterLastSessionRefreshStore(org.keycloak.models.sessions.infinispan.changes.sessions.PersisterLastSessionRefreshStore) Future(java.util.concurrent.Future) RealmRemovedSessionEvent(org.keycloak.models.sessions.infinispan.events.RealmRemovedSessionEvent) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AuthenticatedClientSessionModel(org.keycloak.models.AuthenticatedClientSessionModel) Map(java.util.Map) SessionEntity(org.keycloak.models.sessions.infinispan.entities.SessionEntity) Time(org.keycloak.common.util.Time) InfinispanUtil(org.keycloak.connections.infinispan.InfinispanUtil) OfflineUserSessionModel(org.keycloak.models.OfflineUserSessionModel) RealmModel(org.keycloak.models.RealmModel) UserSessionPersisterProvider(org.keycloak.models.session.UserSessionPersisterProvider) CrossDCLastSessionRefreshStore(org.keycloak.models.sessions.infinispan.changes.sessions.CrossDCLastSessionRefreshStore) SessionPredicate(org.keycloak.models.sessions.infinispan.stream.SessionPredicate) Predicate(java.util.function.Predicate) Collection(java.util.Collection) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Set(java.util.Set) UUID(java.util.UUID) Collectors(java.util.stream.Collectors) Serializable(java.io.Serializable) Objects(java.util.Objects) UserProvider(org.keycloak.models.UserProvider) InfinispanChangelogBasedTransaction(org.keycloak.models.sessions.infinispan.changes.InfinispanChangelogBasedTransaction) Stream(java.util.stream.Stream) Flag(org.infinispan.context.Flag) AuthenticatedClientSessionEntity(org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity) DeviceActivityManager(org.keycloak.device.DeviceActivityManager) ClientModel(org.keycloak.models.ClientModel) Mappers(org.keycloak.models.sessions.infinispan.stream.Mappers) InfinispanKeyGenerator(org.keycloak.models.sessions.infinispan.util.InfinispanKeyGenerator) Logger(org.jboss.logging.Logger) UserSessionSpi(org.keycloak.models.UserSessionSpi) HashMap(java.util.HashMap) Function(java.util.function.Function) HotRodClientException(org.infinispan.client.hotrod.exceptions.HotRodClientException) UserModel(org.keycloak.models.UserModel) AuthenticatedClientSessionStore(org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionStore) SessionTimeouts(org.keycloak.models.sessions.infinispan.util.SessionTimeouts) BasicCache(org.infinispan.commons.api.BasicCache) UserSessionPredicate(org.keycloak.models.sessions.infinispan.stream.UserSessionPredicate) StreamSupport(java.util.stream.StreamSupport) Retry(org.keycloak.common.util.Retry) UserSessionEntity(org.keycloak.models.sessions.infinispan.entities.UserSessionEntity) RemoteCacheInvoker(org.keycloak.models.sessions.infinispan.remotestore.RemoteCacheInvoker) Iterator(java.util.Iterator) SessionUpdateTask(org.keycloak.models.sessions.infinispan.changes.SessionUpdateTask) KeycloakSession(org.keycloak.models.KeycloakSession) UserSessionModel(org.keycloak.models.UserSessionModel) CacheCollectors(org.infinispan.stream.CacheCollectors) Comparators(org.keycloak.models.sessions.infinispan.stream.Comparators) Tasks(org.keycloak.models.sessions.infinispan.changes.Tasks) SessionEntityWrapper(org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper) TimeUnit(java.util.concurrent.TimeUnit) Consumer(java.util.function.Consumer) ModelException(org.keycloak.models.ModelException) StreamsUtil.paginatedStream(org.keycloak.utils.StreamsUtil.paginatedStream) SessionEventsSenderTransaction(org.keycloak.models.sessions.infinispan.events.SessionEventsSenderTransaction) Collections(java.util.Collections) OfflineUserSessionModel(org.keycloak.models.OfflineUserSessionModel) UserSessionModel(org.keycloak.models.UserSessionModel) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) AuthenticatedClientSessionModel(org.keycloak.models.AuthenticatedClientSessionModel) HotRodClientException(org.infinispan.client.hotrod.exceptions.HotRodClientException) SessionEntityWrapper(org.keycloak.models.sessions.infinispan.changes.SessionEntityWrapper) AuthenticatedClientSessionEntity(org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionEntity) RemoteCache(org.infinispan.client.hotrod.RemoteCache) UUID(java.util.UUID) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) AuthenticatedClientSessionStore(org.keycloak.models.sessions.infinispan.entities.AuthenticatedClientSessionStore) UserSessionEntity(org.keycloak.models.sessions.infinispan.entities.UserSessionEntity)

Example 45 with AuthenticatedClientSessionModel

use of org.keycloak.models.AuthenticatedClientSessionModel in project keycloak by keycloak.

the class TokenEndpoint method codeToToken.

public Response codeToToken() {
    String code = formParams.getFirst(OAuth2Constants.CODE);
    if (code == null) {
        event.error(Errors.INVALID_CODE);
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_REQUEST, "Missing parameter: " + OAuth2Constants.CODE, Response.Status.BAD_REQUEST);
    }
    OAuth2CodeParser.ParseResult parseResult = OAuth2CodeParser.parseCode(session, code, realm, event);
    if (parseResult.isIllegalCode()) {
        AuthenticatedClientSessionModel clientSession = parseResult.getClientSession();
        // Attempt to use same code twice should invalidate existing clientSession
        if (clientSession != null) {
            clientSession.detachFromUserSession();
        }
        event.error(Errors.INVALID_CODE);
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_GRANT, "Code not valid", Response.Status.BAD_REQUEST);
    }
    AuthenticatedClientSessionModel clientSession = parseResult.getClientSession();
    if (parseResult.isExpiredCode()) {
        event.error(Errors.EXPIRED_CODE);
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_GRANT, "Code is expired", Response.Status.BAD_REQUEST);
    }
    UserSessionModel userSession = null;
    if (clientSession != null) {
        userSession = clientSession.getUserSession();
    }
    if (userSession == null) {
        event.error(Errors.USER_SESSION_NOT_FOUND);
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_GRANT, "User session not found", Response.Status.BAD_REQUEST);
    }
    UserModel user = userSession.getUser();
    if (user == null) {
        event.error(Errors.USER_NOT_FOUND);
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_GRANT, "User not found", Response.Status.BAD_REQUEST);
    }
    event.user(userSession.getUser());
    if (!user.isEnabled()) {
        event.error(Errors.USER_DISABLED);
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_GRANT, "User disabled", Response.Status.BAD_REQUEST);
    }
    OAuth2Code codeData = parseResult.getCodeData();
    String redirectUri = codeData.getRedirectUriParam();
    String redirectUriParam = formParams.getFirst(OAuth2Constants.REDIRECT_URI);
    // KEYCLOAK-4478 Backwards compatibility with the adapters earlier than KC 3.4.2
    if (redirectUriParam != null && redirectUriParam.contains("session_state=") && !redirectUri.contains("session_state=")) {
        redirectUriParam = KeycloakUriBuilder.fromUri(redirectUriParam).replaceQueryParam(OAuth2Constants.SESSION_STATE, null).build().toString();
    }
    if (redirectUri != null && !redirectUri.equals(redirectUriParam)) {
        event.error(Errors.INVALID_CODE);
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_GRANT, "Incorrect redirect_uri", Response.Status.BAD_REQUEST);
    }
    if (!client.getClientId().equals(clientSession.getClient().getClientId())) {
        event.error(Errors.INVALID_CODE);
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_GRANT, "Auth error", Response.Status.BAD_REQUEST);
    }
    if (!client.isStandardFlowEnabled()) {
        event.error(Errors.NOT_ALLOWED);
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_GRANT, "Client not allowed to exchange code", Response.Status.BAD_REQUEST);
    }
    if (!AuthenticationManager.isSessionValid(realm, userSession)) {
        event.error(Errors.USER_SESSION_NOT_FOUND);
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_GRANT, "Session not active", Response.Status.BAD_REQUEST);
    }
    // https://tools.ietf.org/html/rfc7636#section-4.6
    String codeVerifier = formParams.getFirst(OAuth2Constants.CODE_VERIFIER);
    String codeChallenge = codeData.getCodeChallenge();
    String codeChallengeMethod = codeData.getCodeChallengeMethod();
    String authUserId = user.getId();
    String authUsername = user.getUsername();
    if (authUserId == null) {
        authUserId = "unknown";
    }
    if (authUsername == null) {
        authUsername = "unknown";
    }
    if (codeChallengeMethod != null && !codeChallengeMethod.isEmpty()) {
        PkceUtils.checkParamsForPkceEnforcedClient(codeVerifier, codeChallenge, codeChallengeMethod, authUserId, authUsername, event, cors);
    } else {
        // PKCE Activation is OFF, execute the codes implemented in KEYCLOAK-2604
        PkceUtils.checkParamsForPkceNotEnforcedClient(codeVerifier, codeChallenge, codeChallengeMethod, authUserId, authUsername, event, cors);
    }
    try {
        session.clientPolicy().triggerOnEvent(new TokenRequestContext(formParams, parseResult));
    } catch (ClientPolicyException cpe) {
        event.error(cpe.getError());
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_GRANT, cpe.getErrorDetail(), Response.Status.BAD_REQUEST);
    }
    updateClientSession(clientSession);
    updateUserSessionFromClientAuth(userSession);
    // Compute client scopes again from scope parameter. Check if user still has them granted
    // (but in code-to-token request, it could just theoretically happen that they are not available)
    String scopeParam = codeData.getScope();
    Supplier<Stream<ClientScopeModel>> clientScopesSupplier = () -> TokenManager.getRequestedClientScopes(scopeParam, client);
    if (!TokenManager.verifyConsentStillAvailable(session, user, client, clientScopesSupplier.get())) {
        event.error(Errors.NOT_ALLOWED);
        throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_SCOPE, "Client no longer has requested consent from user", Response.Status.BAD_REQUEST);
    }
    ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionAndScopeParameter(clientSession, scopeParam, session);
    // Set nonce as an attribute in the ClientSessionContext. Will be used for the token generation
    clientSessionCtx.setAttribute(OIDCLoginProtocol.NONCE_PARAM, codeData.getNonce());
    return createTokenResponse(user, userSession, clientSessionCtx, scopeParam, true);
}
Also used : TokenRequestContext(org.keycloak.services.clientpolicy.context.TokenRequestContext) ServiceAccountTokenRequestContext(org.keycloak.services.clientpolicy.context.ServiceAccountTokenRequestContext) UserSessionModel(org.keycloak.models.UserSessionModel) AuthenticatedClientSessionModel(org.keycloak.models.AuthenticatedClientSessionModel) OAuth2CodeParser(org.keycloak.protocol.oidc.utils.OAuth2CodeParser) ClientPolicyException(org.keycloak.services.clientpolicy.ClientPolicyException) UserModel(org.keycloak.models.UserModel) DefaultClientSessionContext(org.keycloak.services.util.DefaultClientSessionContext) ClientSessionContext(org.keycloak.models.ClientSessionContext) OAuth2Code(org.keycloak.protocol.oidc.utils.OAuth2Code) Stream(java.util.stream.Stream) CorsErrorResponseException(org.keycloak.services.CorsErrorResponseException)

Aggregations

AuthenticatedClientSessionModel (org.keycloak.models.AuthenticatedClientSessionModel)59 UserSessionModel (org.keycloak.models.UserSessionModel)35 RealmModel (org.keycloak.models.RealmModel)25 ClientModel (org.keycloak.models.ClientModel)23 Test (org.junit.Test)16 AbstractTestRealmKeycloakTest (org.keycloak.testsuite.AbstractTestRealmKeycloakTest)13 UserModel (org.keycloak.models.UserModel)12 KeycloakSession (org.keycloak.models.KeycloakSession)11 ModelTest (org.keycloak.testsuite.arquillian.annotation.ModelTest)11 HashMap (java.util.HashMap)10 Map (java.util.Map)9 ClientSessionContext (org.keycloak.models.ClientSessionContext)9 LinkedList (java.util.LinkedList)8 DefaultClientSessionContext (org.keycloak.services.util.DefaultClientSessionContext)8 OAuthErrorException (org.keycloak.OAuthErrorException)6 VerificationException (org.keycloak.common.VerificationException)6 AccessToken (org.keycloak.representations.AccessToken)6 ClientPolicyException (org.keycloak.services.clientpolicy.ClientPolicyException)6 HashSet (java.util.HashSet)5 List (java.util.List)5