keycloak-aplcache
Changes
model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java 2(+1 -1)
model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java 1(+1 -0)
model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/AuthenticatedClientSessionAdapter.java 195(+195 -0)
model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/AuthenticationSessionAdapter.java 101(+60 -41)
model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/AuthenticationSessionEntity.java 26(+18 -8)
model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/ClientLoginSessionEntity.java 111(+111 -0)
model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/ClientSessionEntity.java 1(+0 -1)
model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/UserSessionEntity.java 10(+10 -0)
model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanAuthenticationSessionProvider.java 183(+183 -0)
model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanAuthenticationSessionProviderFactory.java 47(+19 -28)
model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java 21(+13 -8)
model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/AuthenticationSessionPredicate.java 105(+105 -0)
model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java 15(+11 -4)
model/infinispan/src/main/resources/META-INF/services/org.keycloak.sessions.AuthenticationSessionProviderFactory 18(+18 -0)
model/jpa/src/main/java/org/keycloak/models/jpa/session/JpaUserSessionPersisterProvider.java 12(+6 -6)
server-spi-private/src/main/java/org/keycloak/authentication/AuthenticationFlowContext.java 9(+4 -5)
server-spi-private/src/main/java/org/keycloak/broker/provider/BrokeredIdentityContext.java 13(+6 -7)
server-spi-private/src/main/java/org/keycloak/models/session/DisabledUserSessionPersisterProvider.java 5(+2 -3)
server-spi-private/src/main/java/org/keycloak/models/session/PersistentAuthenticatedClientSessionAdapter.java 10(+4 -6)
server-spi-private/src/main/java/org/keycloak/models/session/PersistentUserSessionAdapter.java 4(+2 -2)
server-spi-private/src/main/java/org/keycloak/models/session/UserSessionPersisterProvider.java 4(+2 -2)
server-spi-private/src/main/java/org/keycloak/sessions/AuthenticationSessionProviderFactory.java 2(+1 -1)
services/src/main/java/org/keycloak/authentication/authenticators/broker/AbstractIdpAuthenticator.java 14(+7 -7)
services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpConfirmLinkAuthenticator.java 10(+5 -5)
services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpCreateUserIfUniqueAuthenticator.java 8(+4 -4)
services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpReviewProfileAuthenticator.java 6(+3 -3)
services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpUsernamePasswordForm.java 6(+3 -3)
services/src/main/java/org/keycloak/authentication/authenticators/broker/util/SerializedBrokeredIdentityContext.java 21(+10 -11)
services/src/main/java/org/keycloak/authentication/authenticators/browser/AbstractUsernameFormAuthenticator.java 6(+3 -3)
services/src/main/java/org/keycloak/authentication/authenticators/browser/CookieAuthenticator.java 5(+2 -3)
services/src/main/java/org/keycloak/authentication/authenticators/browser/IdentityProviderAuthenticator.java 2(+1 -1)
services/src/main/java/org/keycloak/authentication/authenticators/browser/ScriptBasedAuthenticator.java 2(+1 -1)
services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoAuthenticator.java 3(+1 -2)
services/src/main/java/org/keycloak/authentication/authenticators/browser/UsernamePasswordForm.java 4(+2 -2)
services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidateUsername.java 2(+1 -1)
services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetCredentialChooseUser.java 7(+3 -4)
services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetCredentialEmail.java 22(+10 -12)
services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetPassword.java 9(+1 -8)
services/src/main/java/org/keycloak/authentication/authenticators/x509/ValidateX509CertificateUsername.java 2(+1 -1)
services/src/main/java/org/keycloak/authentication/authenticators/x509/X509ClientCertificateAuthenticator.java 4(+2 -2)
services/src/main/java/org/keycloak/broker/provider/HardcodedUserSessionAttributeMapper.java 4(+2 -2)
services/src/main/java/org/keycloak/forms/login/freemarker/FreeMarkerLoginFormsProvider.java 21(+11 -10)
services/src/main/java/org/keycloak/protocol/saml/mappers/SAMLAttributeStatementMapper.java 4(+2 -2)
services/src/main/java/org/keycloak/protocol/saml/mappers/UserAttributeStatementMapper.java 4(+2 -2)
services/src/main/java/org/keycloak/protocol/saml/mappers/UserPropertyAttributeStatementMapper.java 4(+2 -2)
services/src/main/java/org/keycloak/protocol/saml/mappers/UserSessionNoteStatementMapper.java 4(+2 -2)
services/src/main/java/org/keycloak/protocol/saml/profile/ecp/authenticator/HttpBasicAuthenticator.java 2(+1 -1)
testsuite/integration/src/test/java/org/keycloak/testsuite/model/AuthenticationSessionProviderTest.java 122(+122 -0)
testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java 1219(+646 -573)
testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/forms/PassThroughRegistration.java 10(+5 -5)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AssertEvents.java 5(+3 -2)
Details
diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
index 916db65..934f0e8 100755
--- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
+++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
@@ -27,7 +27,6 @@ import org.infinispan.eviction.EvictionStrategy;
import org.infinispan.eviction.EvictionType;
import org.infinispan.manager.DefaultCacheManager;
import org.infinispan.manager.EmbeddedCacheManager;
-import org.infinispan.persistence.remote.configuration.ExhaustedAction;
import org.infinispan.persistence.remote.configuration.RemoteStoreConfigurationBuilder;
import org.infinispan.transaction.LockingMode;
import org.infinispan.transaction.TransactionMode;
@@ -181,6 +180,7 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
cacheManager.defineConfiguration(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME, sessionCacheConfiguration);
cacheManager.defineConfiguration(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME, sessionCacheConfiguration);
cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME, sessionCacheConfiguration);
+ cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHENTICATION_SESSIONS_CACHE_NAME, sessionCacheConfiguration);
ConfigurationBuilder replicationConfigBuilder = new ConfigurationBuilder();
if (clustered) {
diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java
index 7c255fd..6d8b7f4 100755
--- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java
+++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java
@@ -36,6 +36,7 @@ public interface InfinispanConnectionProvider extends Provider {
String SESSION_CACHE_NAME = "sessions";
String OFFLINE_SESSION_CACHE_NAME = "offlineSessions";
String LOGIN_FAILURE_CACHE_NAME = "loginFailures";
+ String AUTHENTICATION_SESSIONS_CACHE_NAME = "authenticationSessions";
String WORK_CACHE_NAME = "work";
String AUTHORIZATION_CACHE_NAME = "authorization";
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/AuthenticatedClientSessionAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/AuthenticatedClientSessionAdapter.java
new file mode 100644
index 0000000..6eaba69
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/AuthenticatedClientSessionAdapter.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.sessions.infinispan;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.infinispan.Cache;
+import org.keycloak.models.AuthenticatedClientSessionModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.sessions.infinispan.entities.ClientLoginSessionEntity;
+import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
+import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class AuthenticatedClientSessionAdapter implements AuthenticatedClientSessionModel {
+
+ private final ClientLoginSessionEntity entity;
+ private final InfinispanUserSessionProvider provider;
+ private final Cache<String, SessionEntity> cache;
+ private UserSessionAdapter userSession;
+
+ public AuthenticatedClientSessionAdapter(ClientLoginSessionEntity entity, UserSessionAdapter userSession, InfinispanUserSessionProvider provider, Cache<String, SessionEntity> cache) {
+ this.provider = provider;
+ this.entity = entity;
+ this.cache = cache;
+ this.userSession = userSession;
+ }
+
+ private void update() {
+ provider.getTx().replace(cache, userSession.getEntity().getId(), userSession.getEntity());
+ }
+
+
+ @Override
+ public void setUserSession(UserSessionModel userSession) {
+ String clientUUID = entity.getClient();
+ UserSessionEntity sessionEntity = this.userSession.getEntity();
+
+ // Dettach userSession
+ if (userSession == null) {
+ if (sessionEntity.getClientLoginSessions() != null) {
+ sessionEntity.getClientLoginSessions().remove(clientUUID);
+ update();
+ this.userSession = null;
+ }
+ } else {
+ this.userSession = (UserSessionAdapter) userSession;
+
+ if (sessionEntity.getClientLoginSessions() == null) {
+ sessionEntity.setClientLoginSessions(new HashMap<>());
+ }
+ sessionEntity.getClientLoginSessions().put(clientUUID, entity);
+ update();
+ }
+ }
+
+ @Override
+ public UserSessionModel getUserSession() {
+ return this.userSession;
+ }
+
+ @Override
+ public String getRedirectUri() {
+ return entity.getRedirectUri();
+ }
+
+ @Override
+ public void setRedirectUri(String uri) {
+ entity.setRedirectUri(uri);
+ update();
+ }
+
+ @Override
+ public String getId() {
+ return entity.getId();
+ }
+
+ @Override
+ public RealmModel getRealm() {
+ return userSession.getRealm();
+ }
+
+ @Override
+ public ClientModel getClient() {
+ String client = entity.getClient();
+ return getRealm().getClientById(client);
+ }
+
+ @Override
+ public int getTimestamp() {
+ return entity.getTimestamp();
+ }
+
+ @Override
+ public void setTimestamp(int timestamp) {
+ entity.setTimestamp(timestamp);
+ update();
+ }
+
+ @Override
+ public String getAction() {
+ return entity.getAction();
+ }
+
+ @Override
+ public void setAction(String action) {
+ entity.setAction(action);
+ update();
+ }
+
+ @Override
+ public String getProtocol() {
+ return entity.getAuthMethod();
+ }
+
+ @Override
+ public void setProtocol(String method) {
+ entity.setAuthMethod(method);
+ update();
+ }
+
+ @Override
+ public Set<String> getRoles() {
+ return entity.getRoles();
+ }
+
+ @Override
+ public void setRoles(Set<String> roles) {
+ entity.setRoles(roles);
+ update();
+ }
+
+ @Override
+ public Set<String> getProtocolMappers() {
+ return entity.getProtocolMappers();
+ }
+
+ @Override
+ public void setProtocolMappers(Set<String> protocolMappers) {
+ entity.setProtocolMappers(protocolMappers);
+ update();
+ }
+
+ @Override
+ public String getNote(String name) {
+ return entity.getNotes()==null ? null : entity.getNotes().get(name);
+ }
+
+ @Override
+ public void setNote(String name, String value) {
+ if (entity.getNotes() == null) {
+ entity.setNotes(new HashMap<>());
+ }
+ entity.getNotes().put(name, value);
+ update();
+ }
+
+ @Override
+ public void removeNote(String name) {
+ if (entity.getNotes() != null) {
+ entity.getNotes().remove(name);
+ update();
+ }
+ }
+
+ @Override
+ public Map<String, String> getNotes() {
+ if (entity.getNotes() == null || entity.getNotes().isEmpty()) return Collections.emptyMap();
+ Map<String, String> copy = new HashMap<>();
+ copy.putAll(entity.getNotes());
+ return copy;
+ }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/ClientLoginSessionEntity.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/ClientLoginSessionEntity.java
new file mode 100644
index 0000000..15ed11d
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/ClientLoginSessionEntity.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.sessions.infinispan.entities;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ClientLoginSessionEntity {
+
+ private String id;
+ private String client;
+ private String authMethod;
+ private String redirectUri;
+ private int timestamp;
+ private String action;
+
+ private Set<String> roles;
+ private Set<String> protocolMappers;
+ private Map<String, String> notes;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getClient() {
+ return client;
+ }
+
+ public void setClient(String client) {
+ this.client = client;
+ }
+
+ public String getAuthMethod() {
+ return authMethod;
+ }
+
+ public void setAuthMethod(String authMethod) {
+ this.authMethod = authMethod;
+ }
+
+ public String getRedirectUri() {
+ return redirectUri;
+ }
+
+ public void setRedirectUri(String redirectUri) {
+ this.redirectUri = redirectUri;
+ }
+
+ public int getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(int timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ public String getAction() {
+ return action;
+ }
+
+ public void setAction(String action) {
+ this.action = action;
+ }
+
+ public Set<String> getRoles() {
+ return roles;
+ }
+
+ public void setRoles(Set<String> roles) {
+ this.roles = roles;
+ }
+
+ public Set<String> getProtocolMappers() {
+ return protocolMappers;
+ }
+
+ public void setProtocolMappers(Set<String> protocolMappers) {
+ this.protocolMappers = protocolMappers;
+ }
+
+ public Map<String, String> getNotes() {
+ return notes;
+ }
+
+ public void setNotes(Map<String, String> notes) {
+ this.notes = notes;
+ }
+
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/ClientSessionEntity.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/ClientSessionEntity.java
index 6bce9e9..0cbdc79 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/ClientSessionEntity.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/ClientSessionEntity.java
@@ -18,7 +18,6 @@
package org.keycloak.models.sessions.infinispan.entities;
import org.keycloak.models.ClientSessionModel;
-import org.keycloak.sessions.LoginSessionModel;
import java.util.HashMap;
import java.util.HashSet;
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/UserSessionEntity.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/UserSessionEntity.java
index 538babf..3a5a4eb 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/UserSessionEntity.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/UserSessionEntity.java
@@ -52,6 +52,8 @@ public class UserSessionEntity extends SessionEntity {
private Map<String, String> notes = new ConcurrentHashMap<>();
+ private Map<String, ClientLoginSessionEntity> clientLoginSessions;
+
public String getUser() {
return user;
}
@@ -120,6 +122,14 @@ public class UserSessionEntity extends SessionEntity {
this.notes = notes;
}
+ public Map<String, ClientLoginSessionEntity> getClientLoginSessions() {
+ return clientLoginSessions;
+ }
+
+ public void setClientLoginSessions(Map<String, ClientLoginSessionEntity> clientLoginSessions) {
+ this.clientLoginSessions = clientLoginSessions;
+ }
+
public UserSessionModel.State getState() {
return state;
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanAuthenticationSessionProvider.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanAuthenticationSessionProvider.java
new file mode 100644
index 0000000..9e021db
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanAuthenticationSessionProvider.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.sessions.infinispan;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import org.infinispan.Cache;
+import org.infinispan.context.Flag;
+import org.jboss.logging.Logger;
+import org.keycloak.common.util.Time;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.sessions.infinispan.entities.AuthenticationSessionEntity;
+import org.keycloak.models.sessions.infinispan.stream.AuthenticationSessionPredicate;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.models.utils.RealmInfoUtil;
+import org.keycloak.services.util.CookieHelper;
+import org.keycloak.sessions.AuthenticationSessionModel;
+import org.keycloak.sessions.AuthenticationSessionProvider;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class InfinispanAuthenticationSessionProvider implements AuthenticationSessionProvider {
+
+ private static final Logger log = Logger.getLogger(InfinispanAuthenticationSessionProvider.class);
+
+ private final KeycloakSession session;
+ private final Cache<String, AuthenticationSessionEntity> cache;
+ protected final InfinispanKeycloakTransaction tx;
+
+ public static final String AUTH_SESSION_ID = "AUTH_SESSION_ID";
+
+ public InfinispanAuthenticationSessionProvider(KeycloakSession session, Cache<String, AuthenticationSessionEntity> cache) {
+ this.session = session;
+ this.cache = cache;
+
+ this.tx = new InfinispanKeycloakTransaction();
+ session.getTransactionManager().enlistAfterCompletion(tx);
+ }
+
+
+ @Override
+ public AuthenticationSessionModel createAuthenticationSession(RealmModel realm, ClientModel client, boolean browser) {
+ String id = KeycloakModelUtils.generateId();
+
+ AuthenticationSessionEntity entity = new AuthenticationSessionEntity();
+ entity.setId(id);
+ entity.setRealm(realm.getId());
+ entity.setTimestamp(Time.currentTime());
+ entity.setClientUuid(client.getId());
+
+ tx.put(cache, id, entity);
+
+ if (browser) {
+ setBrowserCookie(id, realm);
+ }
+
+ AuthenticationSessionAdapter wrap = wrap(realm, entity);
+ return wrap;
+ }
+
+ private AuthenticationSessionAdapter wrap(RealmModel realm, AuthenticationSessionEntity entity) {
+ return entity==null ? null : new AuthenticationSessionAdapter(session, this, cache, realm, entity);
+ }
+
+ @Override
+ public String getCurrentAuthenticationSessionId(RealmModel realm) {
+ return getIdFromBrowserCookie();
+ }
+
+ @Override
+ public AuthenticationSessionModel getCurrentAuthenticationSession(RealmModel realm) {
+ String authSessionId = getIdFromBrowserCookie();
+ return authSessionId==null ? null : getAuthenticationSession(realm, authSessionId);
+ }
+
+ @Override
+ public AuthenticationSessionModel getAuthenticationSession(RealmModel realm, String authenticationSessionId) {
+ AuthenticationSessionEntity entity = getAuthenticationSessionEntity(realm, authenticationSessionId);
+ return wrap(realm, entity);
+ }
+
+ private AuthenticationSessionEntity getAuthenticationSessionEntity(RealmModel realm, String authSessionId) {
+ AuthenticationSessionEntity entity = cache.get(authSessionId);
+
+ // Chance created in this transaction TODO:mposolda should it be opposite and rather look locally first? Check performance...
+ if (entity == null) {
+ entity = tx.get(cache, authSessionId);
+ }
+
+ return entity;
+ }
+
+ @Override
+ public void removeAuthenticationSession(RealmModel realm, AuthenticationSessionModel authenticationSession) {
+ tx.remove(cache, authenticationSession.getId());
+ }
+
+ @Override
+ public void removeExpired(RealmModel realm) {
+ log.debugf("Removing expired sessions");
+
+ int expired = Time.currentTime() - RealmInfoUtil.getDettachedClientSessionLifespan(realm);
+
+
+ // Each cluster node cleanups just local sessions, which are those owned by himself (+ few more taking l1 cache into account)
+ Iterator<Map.Entry<String, AuthenticationSessionEntity>> itr = cache.getAdvancedCache().withFlags(Flag.CACHE_MODE_LOCAL)
+ .entrySet().stream().filter(AuthenticationSessionPredicate.create(realm.getId()).expired(expired)).iterator();
+
+ int counter = 0;
+ while (itr.hasNext()) {
+ counter++;
+ AuthenticationSessionEntity entity = itr.next().getValue();
+ tx.remove(cache, entity.getId());
+ }
+
+ log.debugf("Removed %d expired user sessions for realm '%s'", counter, realm.getName());
+ }
+
+ @Override
+ public void onRealmRemoved(RealmModel realm) {
+ Iterator<Map.Entry<String, AuthenticationSessionEntity>> itr = cache.entrySet().stream().filter(AuthenticationSessionPredicate.create(realm.getId())).iterator();
+ while (itr.hasNext()) {
+ cache.remove(itr.next().getKey());
+ }
+ }
+
+ @Override
+ public void onClientRemoved(RealmModel realm, ClientModel client) {
+ Iterator<Map.Entry<String, AuthenticationSessionEntity>> itr = cache.entrySet().stream().filter(AuthenticationSessionPredicate.create(realm.getId()).client(client.getId())).iterator();
+ while (itr.hasNext()) {
+ cache.remove(itr.next().getKey());
+ }
+ }
+
+ @Override
+ public void close() {
+
+ }
+
+ // COOKIE STUFF
+
+ protected void setBrowserCookie(String authSessionId, RealmModel realm) {
+ String cookiePath = CookieHelper.getRealmCookiePath(realm);
+ boolean sslRequired = realm.getSslRequired().isRequired(session.getContext().getConnection());
+ CookieHelper.addCookie(AUTH_SESSION_ID, authSessionId, cookiePath, null, null, -1, sslRequired, true);
+
+ // TODO trace with isTraceEnabled
+ log.infof("Set AUTH_SESSION_ID cookie with value %s", authSessionId);
+ }
+
+ protected String getIdFromBrowserCookie() {
+ String cookieVal = CookieHelper.getCookieValue(AUTH_SESSION_ID);
+
+ if (log.isTraceEnabled()) {
+ if (cookieVal != null) {
+ log.tracef("Found AUTH_SESSION_ID cookie with value %s", cookieVal);
+ } else {
+ log.tracef("Not found AUTH_SESSION_ID cookie");
+ }
+ }
+
+ return cookieVal;
+ }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java
index 7fa9f81..72ea8be 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java
@@ -23,7 +23,7 @@ import org.infinispan.context.Flag;
import org.jboss.logging.Logger;
import org.keycloak.common.util.Time;
import org.keycloak.models.ClientInitialAccessModel;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.KeycloakSession;
@@ -35,6 +35,7 @@ import org.keycloak.models.UserSessionModel;
import org.keycloak.models.UserSessionProvider;
import org.keycloak.models.session.UserSessionPersisterProvider;
import org.keycloak.models.sessions.infinispan.entities.ClientInitialAccessEntity;
+import org.keycloak.models.sessions.infinispan.entities.ClientLoginSessionEntity;
import org.keycloak.models.sessions.infinispan.entities.ClientSessionEntity;
import org.keycloak.models.sessions.infinispan.entities.LoginFailureEntity;
import org.keycloak.models.sessions.infinispan.entities.LoginFailureKey;
@@ -57,7 +58,6 @@ import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
@@ -90,7 +90,8 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
return offline ? offlineSessionCache : sessionCache;
}
- /*
+
+ // TODO:mposolda remove
@Override
public ClientSessionModel createClientSession(RealmModel realm, ClientModel client) {
String id = KeycloakModelUtils.generateId();
@@ -106,12 +107,16 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
ClientSessionAdapter wrap = wrap(realm, entity, false);
return wrap;
- }*/
+ }
- // TODO:mposolda
@Override
- public ClientLoginSessionModel createClientSession(RealmModel realm, ClientModel client, UserSessionModel userSession) {
- return null;
+ public AuthenticatedClientSessionModel createClientSession(RealmModel realm, ClientModel client, UserSessionModel userSession) {
+ ClientLoginSessionEntity entity = new ClientLoginSessionEntity();
+ entity.setClient(client.getId());
+
+ AuthenticatedClientSessionAdapter adapter = new AuthenticatedClientSessionAdapter(entity, (UserSessionAdapter) userSession, this, sessionCache);
+ adapter.setUserSession(userSession);
+ return adapter;
}
@Override
@@ -629,7 +634,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
}*/
@Override
- public ClientLoginSessionModel createOfflineClientSession(ClientLoginSessionModel clientSession) {
+ public AuthenticatedClientSessionModel createOfflineClientSession(AuthenticatedClientSessionModel clientSession) {
return null;
}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/AuthenticationSessionPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/AuthenticationSessionPredicate.java
new file mode 100644
index 0000000..c471793
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/AuthenticationSessionPredicate.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.sessions.infinispan.stream;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.function.Predicate;
+
+import org.keycloak.models.sessions.infinispan.entities.AuthenticationSessionEntity;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class AuthenticationSessionPredicate implements Predicate<Map.Entry<String, AuthenticationSessionEntity>>, Serializable {
+
+ private String realm;
+
+ private String client;
+
+ private String user;
+
+ private Integer expired;
+
+ //private String brokerSessionId;
+ //private String brokerUserId;
+
+ private AuthenticationSessionPredicate(String realm) {
+ this.realm = realm;
+ }
+
+ public static AuthenticationSessionPredicate create(String realm) {
+ return new AuthenticationSessionPredicate(realm);
+ }
+
+ public AuthenticationSessionPredicate user(String user) {
+ this.user = user;
+ return this;
+ }
+
+ public AuthenticationSessionPredicate client(String client) {
+ this.client = client;
+ return this;
+ }
+
+ public AuthenticationSessionPredicate expired(Integer expired) {
+ this.expired = expired;
+ return this;
+ }
+
+// public UserSessionPredicate brokerSessionId(String id) {
+// this.brokerSessionId = id;
+// return this;
+// }
+
+// public UserSessionPredicate brokerUserId(String id) {
+// this.brokerUserId = id;
+// return this;
+// }
+
+ @Override
+ public boolean test(Map.Entry<String, AuthenticationSessionEntity> entry) {
+ AuthenticationSessionEntity entity = entry.getValue();
+
+ if (!realm.equals(entity.getRealm())) {
+ return false;
+ }
+
+ if (user != null && !entity.getAuthUserId().equals(user)) {
+ return false;
+ }
+
+ if (client != null && !entity.getClientUuid().equals(client)) {
+ return false;
+ }
+
+// if (brokerSessionId != null && !brokerSessionId.equals(entity.getBrokerSessionId())) {
+// return false;
+// }
+//
+// if (brokerUserId != null && !brokerUserId.equals(entity.getBrokerUserId())) {
+// return false;
+// }
+
+ if (expired != null && entity.getTimestamp() > expired) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java
index 6c81313..245e3e8 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionAdapter.java
@@ -18,12 +18,13 @@
package org.keycloak.models.sessions.infinispan;
import org.infinispan.Cache;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.sessions.infinispan.entities.ClientLoginSessionEntity;
import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
@@ -61,10 +62,16 @@ public class UserSessionAdapter implements UserSessionModel {
this.offline = offline;
}
- // TODO;mposolda
@Override
- public Map<String, ClientLoginSessionModel> getClientLoginSessions() {
- return null;
+ public Map<String, AuthenticatedClientSessionModel> getAuthenticatedClientSessions() {
+ Map<String, ClientLoginSessionEntity> clientSessionEntities = entity.getClientLoginSessions();
+ Map<String, AuthenticatedClientSessionModel> result = new HashMap<>();
+
+ clientSessionEntities.forEach((String key, ClientLoginSessionEntity value) -> {
+ result.put(key, new AuthenticatedClientSessionAdapter(value, this, provider, cache));
+ });
+
+ return Collections.unmodifiableMap(result);
}
public String getId() {
diff --git a/model/infinispan/src/main/resources/META-INF/services/org.keycloak.sessions.AuthenticationSessionProviderFactory b/model/infinispan/src/main/resources/META-INF/services/org.keycloak.sessions.AuthenticationSessionProviderFactory
new file mode 100644
index 0000000..2c7b298
--- /dev/null
+++ b/model/infinispan/src/main/resources/META-INF/services/org.keycloak.sessions.AuthenticationSessionProviderFactory
@@ -0,0 +1,18 @@
+#
+# Copyright 2016 Red Hat, Inc. and/or its affiliates
+# and other contributors as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.keycloak.models.sessions.infinispan.InfinispanAuthenticationSessionProviderFactory
\ No newline at end of file
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/session/JpaUserSessionPersisterProvider.java b/model/jpa/src/main/java/org/keycloak/models/jpa/session/JpaUserSessionPersisterProvider.java
index e842948..170654f 100644
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/session/JpaUserSessionPersisterProvider.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/session/JpaUserSessionPersisterProvider.java
@@ -17,7 +17,7 @@
package org.keycloak.models.jpa.session;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.KeycloakSession;
@@ -25,7 +25,7 @@ import org.keycloak.models.ModelException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
-import org.keycloak.models.session.PersistentClientSessionAdapter;
+import org.keycloak.models.session.PersistentAuthenticatedClientSessionAdapter;
import org.keycloak.models.session.PersistentClientSessionModel;
import org.keycloak.models.session.PersistentUserSessionAdapter;
import org.keycloak.models.session.PersistentUserSessionModel;
@@ -69,8 +69,8 @@ public class JpaUserSessionPersisterProvider implements UserSessionPersisterProv
}
@Override
- public void createClientSession(UserSessionModel userSession, ClientLoginSessionModel clientSession, boolean offline) {
- PersistentClientSessionAdapter adapter = new PersistentClientSessionAdapter(clientSession);
+ public void createClientSession(UserSessionModel userSession, AuthenticatedClientSessionModel clientSession, boolean offline) {
+ PersistentAuthenticatedClientSessionAdapter adapter = new PersistentAuthenticatedClientSessionAdapter(clientSession);
PersistentClientSessionModel model = adapter.getUpdatedModel();
PersistentClientSessionEntity entity = new PersistentClientSessionEntity();
@@ -260,7 +260,7 @@ public class JpaUserSessionPersisterProvider implements UserSessionPersisterProv
return new PersistentUserSessionAdapter(model, realm, user, clientSessions);
}
- private PersistentClientSessionAdapter toAdapter(RealmModel realm, PersistentUserSessionAdapter userSession, PersistentClientSessionEntity entity) {
+ private PersistentAuthenticatedClientSessionAdapter toAdapter(RealmModel realm, PersistentUserSessionAdapter userSession, PersistentClientSessionEntity entity) {
ClientModel client = realm.getClientById(entity.getClientId());
PersistentClientSessionModel model = new PersistentClientSessionModel();
@@ -270,7 +270,7 @@ public class JpaUserSessionPersisterProvider implements UserSessionPersisterProv
model.setUserId(userSession.getUser().getId());
model.setTimestamp(entity.getTimestamp());
model.setData(entity.getData());
- return new PersistentClientSessionAdapter(model, realm, client, userSession);
+ return new PersistentAuthenticatedClientSessionAdapter(model, realm, client, userSession);
}
@Override
diff --git a/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java b/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java
index 1494126..0348b68 100755
--- a/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java
+++ b/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java
@@ -20,7 +20,7 @@ package org.keycloak.models;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.cache.UserCache;
import org.keycloak.provider.Provider;
-import org.keycloak.sessions.LoginSessionProvider;
+import org.keycloak.sessions.AuthenticationSessionProvider;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
import java.util.Set;
@@ -103,7 +103,7 @@ public interface KeycloakSession {
UserSessionProvider sessions();
- LoginSessionProvider loginSessions();
+ AuthenticationSessionProvider authenticationSessions();
diff --git a/server-spi/src/main/java/org/keycloak/models/UserSessionModel.java b/server-spi/src/main/java/org/keycloak/models/UserSessionModel.java
index 99f69f7..9e1a2b6 100755
--- a/server-spi/src/main/java/org/keycloak/models/UserSessionModel.java
+++ b/server-spi/src/main/java/org/keycloak/models/UserSessionModel.java
@@ -53,7 +53,7 @@ public interface UserSessionModel {
void setLastSessionRefresh(int seconds);
- Map<String, ClientLoginSessionModel> getClientLoginSessions();
+ Map<String, AuthenticatedClientSessionModel> getAuthenticatedClientSessions();
// TODO: Remove
List<ClientSessionModel> getClientSessions();
diff --git a/server-spi/src/main/java/org/keycloak/models/UserSessionProvider.java b/server-spi/src/main/java/org/keycloak/models/UserSessionProvider.java
index fbd5761..7925bf7 100755
--- a/server-spi/src/main/java/org/keycloak/models/UserSessionProvider.java
+++ b/server-spi/src/main/java/org/keycloak/models/UserSessionProvider.java
@@ -27,7 +27,8 @@ import java.util.List;
*/
public interface UserSessionProvider extends Provider {
- ClientLoginSessionModel createClientSession(RealmModel realm, ClientModel client, UserSessionModel userSession);
+ ClientSessionModel createClientSession(RealmModel realm, ClientModel client);
+ AuthenticatedClientSessionModel createClientSession(RealmModel realm, ClientModel client, UserSessionModel userSession);
ClientSessionModel getClientSession(RealmModel realm, String id);
ClientSessionModel getClientSession(String id);
@@ -64,7 +65,7 @@ public interface UserSessionProvider extends Provider {
// Removes the attached clientSessions as well
void removeOfflineUserSession(RealmModel realm, UserSessionModel userSession);
- ClientLoginSessionModel createOfflineClientSession(ClientLoginSessionModel clientSession);
+ AuthenticatedClientSessionModel createOfflineClientSession(AuthenticatedClientSessionModel clientSession);
ClientSessionModel getOfflineClientSession(RealmModel realm, String clientSessionId);
List<UserSessionModel> getOfflineUserSessions(RealmModel realm, UserModel user);
diff --git a/server-spi/src/main/java/org/keycloak/sessions/CommonClientSessionModel.java b/server-spi/src/main/java/org/keycloak/sessions/CommonClientSessionModel.java
index c2e5193..e6a9288 100644
--- a/server-spi/src/main/java/org/keycloak/sessions/CommonClientSessionModel.java
+++ b/server-spi/src/main/java/org/keycloak/sessions/CommonClientSessionModel.java
@@ -24,7 +24,7 @@ import org.keycloak.models.ClientModel;
import org.keycloak.models.RealmModel;
/**
- * Predecesor of LoginSessionModel, ClientLoginSessionModel and ClientSessionModel (then action tickets). Maybe we will remove it later...
+ * Predecesor of AuthenticationSessionModel, ClientLoginSessionModel and ClientSessionModel (then action tickets). Maybe we will remove it later...
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
diff --git a/server-spi-private/src/main/java/org/keycloak/authentication/AuthenticationFlowContext.java b/server-spi-private/src/main/java/org/keycloak/authentication/AuthenticationFlowContext.java
index 80c7575..e872565 100755
--- a/server-spi-private/src/main/java/org/keycloak/authentication/AuthenticationFlowContext.java
+++ b/server-spi-private/src/main/java/org/keycloak/authentication/AuthenticationFlowContext.java
@@ -18,11 +18,10 @@
package org.keycloak.authentication;
import org.keycloak.forms.login.LoginFormsProvider;
-import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.utils.FormMessage;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
import java.net.URI;
@@ -63,7 +62,7 @@ public interface AuthenticationFlowContext extends AbstractAuthenticationFlowCon
*
* @return
*/
- LoginSessionModel getLoginSession();
+ AuthenticationSessionModel getAuthenticationSession();
/**
* Create a Freemarker form builder that presets the user, action URI, and a generated access code
@@ -81,11 +80,11 @@ public interface AuthenticationFlowContext extends AbstractAuthenticationFlowCon
URI getActionUrl(String code);
/**
- * Get the action URL for the required action. This auto-generates the access code.
+ * Get the refresh URL for the required action.
*
* @return
*/
- URI getActionUrl();
+ URI getRefreshExecutionUrl();
/**
* End the flow and redirect browser based on protocol specific respones. This should only be executed
diff --git a/server-spi-private/src/main/java/org/keycloak/authentication/FormContext.java b/server-spi-private/src/main/java/org/keycloak/authentication/FormContext.java
index b131c20..2c1255d 100755
--- a/server-spi-private/src/main/java/org/keycloak/authentication/FormContext.java
+++ b/server-spi-private/src/main/java/org/keycloak/authentication/FormContext.java
@@ -22,11 +22,10 @@ import org.keycloak.common.ClientConnection;
import org.keycloak.events.EventBuilder;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.AuthenticatorConfigModel;
-import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
import javax.ws.rs.core.UriInfo;
@@ -80,11 +79,11 @@ public interface FormContext {
RealmModel getRealm();
/**
- * LoginSessionModel attached to this flow
+ * AuthenticationSessionModel attached to this flow
*
* @return
*/
- LoginSessionModel getLoginSession();
+ AuthenticationSessionModel getAuthenticationSession();
/**
* Information about the IP address from the connecting HTTP client.
diff --git a/server-spi-private/src/main/java/org/keycloak/authentication/RequiredActionContext.java b/server-spi-private/src/main/java/org/keycloak/authentication/RequiredActionContext.java
index df0bc66..caaa14e 100755
--- a/server-spi-private/src/main/java/org/keycloak/authentication/RequiredActionContext.java
+++ b/server-spi-private/src/main/java/org/keycloak/authentication/RequiredActionContext.java
@@ -21,12 +21,10 @@ import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.common.ClientConnection;
import org.keycloak.events.EventBuilder;
import org.keycloak.forms.login.LoginFormsProvider;
-import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
-import org.keycloak.models.UserSessionModel;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
@@ -91,7 +89,7 @@ public interface RequiredActionContext {
*/
UserModel getUser();
RealmModel getRealm();
- LoginSessionModel getLoginSession();
+ AuthenticationSessionModel getAuthenticationSession();
ClientConnection getConnection();
UriInfo getUriInfo();
KeycloakSession getSession();
diff --git a/server-spi-private/src/main/java/org/keycloak/broker/provider/BrokeredIdentityContext.java b/server-spi-private/src/main/java/org/keycloak/broker/provider/BrokeredIdentityContext.java
index bcce1b8..a2b1dc5 100755
--- a/server-spi-private/src/main/java/org/keycloak/broker/provider/BrokeredIdentityContext.java
+++ b/server-spi-private/src/main/java/org/keycloak/broker/provider/BrokeredIdentityContext.java
@@ -16,10 +16,9 @@
*/
package org.keycloak.broker.provider;
-import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.Constants;
import org.keycloak.models.IdentityProviderModel;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
import java.util.ArrayList;
import java.util.HashMap;
@@ -47,7 +46,7 @@ public class BrokeredIdentityContext {
private IdentityProviderModel idpConfig;
private IdentityProvider idp;
private Map<String, Object> contextData = new HashMap<>();
- private LoginSessionModel loginSession;
+ private AuthenticationSessionModel authenticationSession;
public BrokeredIdentityContext(String id) {
if (id == null) {
@@ -191,12 +190,12 @@ public class BrokeredIdentityContext {
this.lastName = lastName;
}
- public LoginSessionModel getLoginSession() {
- return loginSession;
+ public AuthenticationSessionModel getAuthenticationSession() {
+ return authenticationSession;
}
- public void setLoginSession(LoginSessionModel loginSession) {
- this.loginSession = loginSession;
+ public void setAuthenticationSession(AuthenticationSessionModel authenticationSession) {
+ this.authenticationSession = authenticationSession;
}
public void setName(String name) {
diff --git a/server-spi-private/src/main/java/org/keycloak/events/Details.java b/server-spi-private/src/main/java/org/keycloak/events/Details.java
index 0ef227d..3e72e8e 100755
--- a/server-spi-private/src/main/java/org/keycloak/events/Details.java
+++ b/server-spi-private/src/main/java/org/keycloak/events/Details.java
@@ -48,6 +48,7 @@ public interface Details {
String CLIENT_SESSION_STATE = "client_session_state";
String CLIENT_SESSION_HOST = "client_session_host";
String RESTART_AFTER_TIMEOUT = "restart_after_timeout";
+ String RESTART_REQUESTED = "restart_requested";
String CONSENT = "consent";
String CONSENT_VALUE_NO_CONSENT_REQUIRED = "no_consent_required"; // No consent is required by client
diff --git a/server-spi-private/src/main/java/org/keycloak/forms/login/LoginFormsPages.java b/server-spi-private/src/main/java/org/keycloak/forms/login/LoginFormsPages.java
index fcaff7a..476e3aa 100755
--- a/server-spi-private/src/main/java/org/keycloak/forms/login/LoginFormsPages.java
+++ b/server-spi-private/src/main/java/org/keycloak/forms/login/LoginFormsPages.java
@@ -24,6 +24,6 @@ public enum LoginFormsPages {
LOGIN, LOGIN_TOTP, LOGIN_CONFIG_TOTP, LOGIN_VERIFY_EMAIL,
LOGIN_IDP_LINK_CONFIRM, LOGIN_IDP_LINK_EMAIL,
- OAUTH_GRANT, LOGIN_RESET_PASSWORD, LOGIN_UPDATE_PASSWORD, REGISTER, INFO, ERROR, LOGIN_UPDATE_PROFILE, CODE;
+ OAUTH_GRANT, LOGIN_RESET_PASSWORD, LOGIN_UPDATE_PASSWORD, REGISTER, INFO, ERROR, LOGIN_UPDATE_PROFILE, LOGIN_PAGE_EXPIRED, CODE;
}
diff --git a/server-spi-private/src/main/java/org/keycloak/forms/login/LoginFormsProvider.java b/server-spi-private/src/main/java/org/keycloak/forms/login/LoginFormsProvider.java
index a379e9d..f94e588 100755
--- a/server-spi-private/src/main/java/org/keycloak/forms/login/LoginFormsProvider.java
+++ b/server-spi-private/src/main/java/org/keycloak/forms/login/LoginFormsProvider.java
@@ -22,7 +22,7 @@ import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.FormMessage;
import org.keycloak.provider.Provider;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
@@ -68,6 +68,8 @@ public interface LoginFormsProvider extends Provider {
public Response createIdpLinkEmailPage();
+ public Response createLoginExpiredPage();
+
public Response createErrorPage();
public Response createOAuthGrant();
@@ -76,7 +78,7 @@ public interface LoginFormsProvider extends Provider {
public LoginFormsProvider setClientSessionCode(String accessCode);
- public LoginFormsProvider setLoginSession(LoginSessionModel loginSession);
+ public LoginFormsProvider setAuthenticationSession(AuthenticationSessionModel authenticationSession);
public LoginFormsProvider setAccessRequest(List<RoleModel> realmRolesRequested, MultivaluedMap<String,RoleModel> resourceRolesRequested, List<ProtocolMapperModel> protocolMappers);
public LoginFormsProvider setAccessRequest(String message);
diff --git a/server-spi-private/src/main/java/org/keycloak/models/session/DisabledUserSessionPersisterProvider.java b/server-spi-private/src/main/java/org/keycloak/models/session/DisabledUserSessionPersisterProvider.java
index c860ea3..51efc23 100644
--- a/server-spi-private/src/main/java/org/keycloak/models/session/DisabledUserSessionPersisterProvider.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/session/DisabledUserSessionPersisterProvider.java
@@ -18,9 +18,8 @@
package org.keycloak.models.session;
import org.keycloak.Config;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
-import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
@@ -71,7 +70,7 @@ public class DisabledUserSessionPersisterProvider implements UserSessionPersiste
}
@Override
- public void createClientSession(UserSessionModel userSession, ClientLoginSessionModel clientSession, boolean offline) {
+ public void createClientSession(UserSessionModel userSession, AuthenticatedClientSessionModel clientSession, boolean offline) {
}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/session/PersistentUserSessionAdapter.java b/server-spi-private/src/main/java/org/keycloak/models/session/PersistentUserSessionAdapter.java
index 882dd53..7b14ec1 100644
--- a/server-spi-private/src/main/java/org/keycloak/models/session/PersistentUserSessionAdapter.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/session/PersistentUserSessionAdapter.java
@@ -18,7 +18,7 @@
package org.keycloak.models.session;
import com.fasterxml.jackson.annotation.JsonProperty;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.ModelException;
import org.keycloak.models.RealmModel;
@@ -162,7 +162,7 @@ public class PersistentUserSessionAdapter implements UserSessionModel {
// TODO:mposolda
@Override
- public Map<String, ClientLoginSessionModel> getClientLoginSessions() {
+ public Map<String, AuthenticatedClientSessionModel> getAuthenticatedClientSessions() {
return null;
}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/session/UserSessionPersisterProvider.java b/server-spi-private/src/main/java/org/keycloak/models/session/UserSessionPersisterProvider.java
index cbaf31e..c5370ed 100644
--- a/server-spi-private/src/main/java/org/keycloak/models/session/UserSessionPersisterProvider.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/session/UserSessionPersisterProvider.java
@@ -17,7 +17,7 @@
package org.keycloak.models.session;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
@@ -35,7 +35,7 @@ public interface UserSessionPersisterProvider extends Provider {
void createUserSession(UserSessionModel userSession, boolean offline);
// Assuming that corresponding userSession is already persisted
- void createClientSession(UserSessionModel userSession, ClientLoginSessionModel clientSession, boolean offline);
+ void createClientSession(UserSessionModel userSession, AuthenticatedClientSessionModel clientSession, boolean offline);
void updateUserSession(UserSessionModel userSession, boolean offline);
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
index 3ebe6d3..fb2c727 100755
--- a/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
@@ -45,9 +45,8 @@ import org.keycloak.events.admin.AuthDetails;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.AuthenticationFlowModel;
import org.keycloak.models.AuthenticatorConfigModel;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
-import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.ClientTemplateModel;
import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.GroupModel;
@@ -486,7 +485,7 @@ public class ModelToRepresentation {
rep.setUsername(session.getUser().getUsername());
rep.setUserId(session.getUser().getId());
rep.setIpAddress(session.getIpAddress());
- for (ClientLoginSessionModel clientSession : session.getClientLoginSessions().values()) {
+ for (AuthenticatedClientSessionModel clientSession : session.getAuthenticatedClientSessions().values()) {
ClientModel client = clientSession.getClient();
rep.getClients().put(client.getId(), client.getClientId());
}
diff --git a/server-spi-private/src/main/java/org/keycloak/protocol/LoginProtocol.java b/server-spi-private/src/main/java/org/keycloak/protocol/LoginProtocol.java
index 015ead0..8fc9fd9 100755
--- a/server-spi-private/src/main/java/org/keycloak/protocol/LoginProtocol.java
+++ b/server-spi-private/src/main/java/org/keycloak/protocol/LoginProtocol.java
@@ -18,14 +18,13 @@
package org.keycloak.protocol;
import org.keycloak.events.EventBuilder;
-import org.keycloak.models.ClientLoginSessionModel;
-import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.provider.Provider;
import org.keycloak.services.managers.ClientSessionCode;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
@@ -68,19 +67,19 @@ public interface LoginProtocol extends Provider {
LoginProtocol setEventBuilder(EventBuilder event);
- Response authenticated(UserSessionModel userSession, ClientSessionCode<ClientLoginSessionModel> accessCode);
+ Response authenticated(UserSessionModel userSession, ClientSessionCode<AuthenticatedClientSessionModel> accessCode);
- Response sendError(LoginSessionModel loginSession, Error error);
+ Response sendError(AuthenticationSessionModel authSession, Error error);
- void backchannelLogout(UserSessionModel userSession, ClientLoginSessionModel clientSession);
- Response frontchannelLogout(UserSessionModel userSession, ClientLoginSessionModel clientSession);
+ void backchannelLogout(UserSessionModel userSession, AuthenticatedClientSessionModel clientSession);
+ Response frontchannelLogout(UserSessionModel userSession, AuthenticatedClientSessionModel clientSession);
Response finishLogout(UserSessionModel userSession);
/**
* @param userSession
- * @param loginSession
+ * @param authSession
* @return true if SSO cookie authentication can't be used. User will need to "actively" reauthenticate
*/
- boolean requireReauthentication(UserSessionModel userSession, LoginSessionModel loginSession);
+ boolean requireReauthentication(UserSessionModel userSession, AuthenticationSessionModel authSession);
}
diff --git a/server-spi-private/src/main/java/org/keycloak/services/managers/ClientSessionCode.java b/server-spi-private/src/main/java/org/keycloak/services/managers/ClientSessionCode.java
index 4096924..873c614 100755
--- a/server-spi-private/src/main/java/org/keycloak/services/managers/ClientSessionCode.java
+++ b/server-spi-private/src/main/java/org/keycloak/services/managers/ClientSessionCode.java
@@ -64,7 +64,7 @@ public class ClientSessionCode<CLIENT_SESSION extends CommonClientSessionModel>
public static class ParseResult<CLIENT_SESSION extends CommonClientSessionModel> {
ClientSessionCode<CLIENT_SESSION> code;
- boolean loginSessionNotFound;
+ boolean authSessionNotFound;
boolean illegalHash;
CLIENT_SESSION clientSession;
@@ -72,8 +72,8 @@ public class ClientSessionCode<CLIENT_SESSION extends CommonClientSessionModel>
return code;
}
- public boolean isLoginSessionNotFound() {
- return loginSessionNotFound;
+ public boolean isAuthSessionNotFound() {
+ return authSessionNotFound;
}
public boolean isIllegalHash() {
@@ -94,7 +94,7 @@ public class ClientSessionCode<CLIENT_SESSION extends CommonClientSessionModel>
try {
result.clientSession = getClientSession(code, session, realm, sessionClass);
if (result.clientSession == null) {
- result.loginSessionNotFound = true;
+ result.authSessionNotFound = true;
return result;
}
@@ -111,25 +111,15 @@ public class ClientSessionCode<CLIENT_SESSION extends CommonClientSessionModel>
}
}
- public static <CLIENT_SESSION extends CommonClientSessionModel> ClientSessionCode<CLIENT_SESSION> parse(String code, KeycloakSession session, RealmModel realm, Class<CLIENT_SESSION> sessionClass) {
- try {
- CLIENT_SESSION clientSession = getClientSession(code, session, realm, sessionClass);
- if (clientSession == null) {
- return null;
- }
-
- if (!verifyCode(code, clientSession)) {
- return null;
- }
+ public static <CLIENT_SESSION extends CommonClientSessionModel> CLIENT_SESSION getClientSession(String code, KeycloakSession session, RealmModel realm, Class<CLIENT_SESSION> sessionClass) {
+ CLIENT_SESSION clientSession = CodeGenerateUtil.parseSession(code, session, realm, sessionClass);
- return new ClientSessionCode<>(session, realm, clientSession);
- } catch (RuntimeException e) {
- return null;
+ // TODO:mposolda Move this to somewhere else? Maybe LoginActionsService.sessionCodeChecks should be somehow even for non-action URLs...
+ if (clientSession != null) {
+ session.getContext().setClient(clientSession.getClient());
}
- }
- public static <CLIENT_SESSION extends CommonClientSessionModel> CLIENT_SESSION getClientSession(String code, KeycloakSession session, RealmModel realm, Class<CLIENT_SESSION> sessionClass) {
- return CodeGenerateUtil.parseSession(code, session, realm, sessionClass);
+ return clientSession;
}
public CLIENT_SESSION getClientSession() {
@@ -173,6 +163,10 @@ public class ClientSessionCode<CLIENT_SESSION extends CommonClientSessionModel>
return true;
}
+ public void removeExpiredClientSession() {
+ CodeGenerateUtil.removeExpiredSession(session, commonLoginSession);
+ }
+
public Set<RoleModel> getRequestedRoles() {
Set<RoleModel> requestedRoles = new HashSet<>();
@@ -222,18 +216,18 @@ public class ClientSessionCode<CLIENT_SESSION extends CommonClientSessionModel>
return nextCode;
}
- private static String generateCode(CommonClientSessionModel loginSession) {
+ private static String generateCode(CommonClientSessionModel authSession) {
try {
String actionId = Base64Url.encode(KeycloakModelUtils.generateSecret());
StringBuilder sb = new StringBuilder();
sb.append(actionId);
sb.append('.');
- sb.append(loginSession.getId());
+ sb.append(authSession.getId());
// https://tools.ietf.org/html/rfc7636#section-4
- String codeChallenge = loginSession.getNote(OAuth2Constants.CODE_CHALLENGE);
- String codeChallengeMethod = loginSession.getNote(OAuth2Constants.CODE_CHALLENGE_METHOD);
+ String codeChallenge = authSession.getNote(OAuth2Constants.CODE_CHALLENGE);
+ String codeChallengeMethod = authSession.getNote(OAuth2Constants.CODE_CHALLENGE_METHOD);
if (codeChallenge != null) {
logger.debugf("PKCE received codeChallenge = %s", codeChallenge);
if (codeChallengeMethod == null) {
@@ -244,9 +238,9 @@ public class ClientSessionCode<CLIENT_SESSION extends CommonClientSessionModel>
}
}
- String code = CodeGenerateUtil.generateCode(loginSession, actionId);
+ String code = CodeGenerateUtil.generateCode(authSession, actionId);
- loginSession.setNote(ACTIVE_CODE, code);
+ authSession.setNote(ACTIVE_CODE, code);
return code;
} catch (Exception e) {
@@ -254,15 +248,15 @@ public class ClientSessionCode<CLIENT_SESSION extends CommonClientSessionModel>
}
}
- private static boolean verifyCode(String code, CommonClientSessionModel loginSession) {
+ public static boolean verifyCode(String code, CommonClientSessionModel authSession) {
try {
- String activeCode = loginSession.getNote(ACTIVE_CODE);
+ String activeCode = authSession.getNote(ACTIVE_CODE);
if (activeCode == null) {
logger.debug("Active code not found in client session");
return false;
}
- loginSession.removeNote(ACTIVE_CODE);
+ authSession.removeNote(ACTIVE_CODE);
return MessageDigest.isEqual(code.getBytes(), activeCode.getBytes());
} catch (Exception e) {
diff --git a/server-spi-private/src/main/java/org/keycloak/services/managers/CodeGenerateUtil.java b/server-spi-private/src/main/java/org/keycloak/services/managers/CodeGenerateUtil.java
index 9c6a571..5313e73 100644
--- a/server-spi-private/src/main/java/org/keycloak/services/managers/CodeGenerateUtil.java
+++ b/server-spi-private/src/main/java/org/keycloak/services/managers/CodeGenerateUtil.java
@@ -17,70 +17,149 @@
package org.keycloak.services.managers;
-import org.keycloak.models.ClientLoginSessionModel;
-import org.keycloak.models.ClientModel;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.sessions.CommonClientSessionModel;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
/**
- * TODO: More object oriented and rather add parsing/generating logic into the session implementations itself
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
class CodeGenerateUtil {
- static <CS extends CommonClientSessionModel> CS parseSession(String code, KeycloakSession session, RealmModel realm, Class<CS> expectedClazz) {
- CommonClientSessionModel result = null;
- if (expectedClazz.equals(ClientSessionModel.class)) {
+ private static final Map<Class<? extends CommonClientSessionModel>, ClientSessionParser<?>> PARSERS = new HashMap<>();
+
+ static {
+ PARSERS.put(ClientSessionModel.class, new ClientSessionModelParser());
+ PARSERS.put(AuthenticationSessionModel.class, new AuthenticationSessionModelParser());
+ PARSERS.put(AuthenticatedClientSessionModel.class, new AuthenticatedClientSessionModelParser());
+ }
+
+
+ public static <CS extends CommonClientSessionModel> CS parseSession(String code, KeycloakSession session, RealmModel realm, Class<CS> expectedClazz) {
+ ClientSessionParser<?> parser = PARSERS.get(expectedClazz);
+
+ CommonClientSessionModel result = parser.parseSession(code, session, realm);
+ return expectedClazz.cast(result);
+ }
+
+ public static String generateCode(CommonClientSessionModel clientSession, String actionId) {
+ ClientSessionParser parser = getParser(clientSession);
+ return parser.generateCode(clientSession, actionId);
+ }
+
+ public static void removeExpiredSession(KeycloakSession session, CommonClientSessionModel clientSession) {
+ ClientSessionParser parser = getParser(clientSession);
+ parser.removeExpiredSession(session, clientSession);
+ }
+
+ private static ClientSessionParser<?> getParser(CommonClientSessionModel clientSession) {
+ for (Class<?> c : PARSERS.keySet()) {
+ if (c.isAssignableFrom(clientSession.getClass())) {
+ return PARSERS.get(c);
+ }
+ }
+ return null;
+ }
+
+
+ private interface ClientSessionParser<CS extends CommonClientSessionModel> {
+
+ CS parseSession(String code, KeycloakSession session, RealmModel realm);
+
+ String generateCode(CS clientSession, String actionId);
+
+ void removeExpiredSession(KeycloakSession session, CS clientSession);
+
+ }
+
+
+ // IMPLEMENTATIONS
+
+
+ // TODO: remove
+ private static class ClientSessionModelParser implements ClientSessionParser<ClientSessionModel> {
+
+
+ @Override
+ public ClientSessionModel parseSession(String code, KeycloakSession session, RealmModel realm) {
try {
String[] parts = code.split("\\.");
String id = parts[2];
- result = session.sessions().getClientSession(realm, id);
+ return session.sessions().getClientSession(realm, id);
} catch (ArrayIndexOutOfBoundsException e) {
return null;
}
- } else if (expectedClazz.equals(LoginSessionModel.class)) {
- result = session.loginSessions().getCurrentLoginSession(realm);
- } else if (expectedClazz.equals(ClientLoginSessionModel.class)) {
+ }
+
+ @Override
+ public String generateCode(ClientSessionModel clientSession, String actionId) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("cls.");
+ sb.append(actionId);
+ sb.append('.');
+ sb.append(clientSession.getId());
+
+ return sb.toString();
+ }
+
+ @Override
+ public void removeExpiredSession(KeycloakSession session, ClientSessionModel clientSession) {
+ session.sessions().removeClientSession(clientSession.getRealm(), clientSession);
+ }
+ }
+
+
+ private static class AuthenticationSessionModelParser implements ClientSessionParser<AuthenticationSessionModel> {
+
+ @Override
+ public AuthenticationSessionModel parseSession(String code, KeycloakSession session, RealmModel realm) {
+ // Read authSessionID from cookie. Code is ignored for now
+ return session.authenticationSessions().getCurrentAuthenticationSession(realm);
+ }
+
+ @Override
+ public String generateCode(AuthenticationSessionModel clientSession, String actionId) {
+ return actionId;
+ }
+
+ @Override
+ public void removeExpiredSession(KeycloakSession session, AuthenticationSessionModel clientSession) {
+ session.authenticationSessions().removeAuthenticationSession(clientSession.getRealm(), clientSession);
+ }
+ }
+
+
+ private static class AuthenticatedClientSessionModelParser implements ClientSessionParser<AuthenticatedClientSessionModel> {
+
+ @Override
+ public AuthenticatedClientSessionModel parseSession(String code, KeycloakSession session, RealmModel realm) {
try {
String[] parts = code.split("\\.");
- String userSessionId = parts[1];
- String clientUUID = parts[2];
+ String userSessionId = parts[2];
+ String clientUUID = parts[3];
UserSessionModel userSession = session.sessions().getUserSession(realm, userSessionId);
if (userSession == null) {
return null;
}
- result = userSession.getClientLoginSessions().get(clientUUID);
+ return userSession.getAuthenticatedClientSessions().get(clientUUID);
} catch (ArrayIndexOutOfBoundsException e) {
return null;
}
- } else {
- throw new IllegalArgumentException("Not known impl: " + expectedClazz.getName());
}
- return expectedClazz.cast(result);
- }
-
- static String generateCode(CommonClientSessionModel clientSession, String actionId) {
- if (clientSession instanceof ClientSessionModel) {
- StringBuilder sb = new StringBuilder();
- sb.append("cls.");
- sb.append(actionId);
- sb.append('.');
- sb.append(clientSession.getId());
-
- return sb.toString();
- } else if (clientSession instanceof LoginSessionModel) {
- // Should be sufficient. LoginSession itself is in the cookie
- return actionId;
- } else if (clientSession instanceof ClientLoginSessionModel) {
- String userSessionId = ((ClientLoginSessionModel) clientSession).getUserSession().getId();
+ @Override
+ public String generateCode(AuthenticatedClientSessionModel clientSession, String actionId) {
+ String userSessionId = clientSession.getUserSession().getId();
String clientUUID = clientSession.getClient().getId();
StringBuilder sb = new StringBuilder();
sb.append("uss.");
@@ -90,9 +169,13 @@ class CodeGenerateUtil {
sb.append('.');
sb.append(clientUUID);
return sb.toString();
- } else {
- throw new IllegalArgumentException("Not known impl: " + clientSession.getClass().getName());
}
+
+ @Override
+ public void removeExpiredSession(KeycloakSession session, AuthenticatedClientSessionModel clientSession) {
+ throw new IllegalStateException("Not yet implemented");
+ }
+
}
diff --git a/server-spi-private/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/server-spi-private/src/main/resources/META-INF/services/org.keycloak.provider.Spi
index f858ea1..b046e7d 100755
--- a/server-spi-private/src/main/resources/META-INF/services/org.keycloak.provider.Spi
+++ b/server-spi-private/src/main/resources/META-INF/services/org.keycloak.provider.Spi
@@ -32,7 +32,7 @@ org.keycloak.timer.TimerSpi
org.keycloak.scripting.ScriptingSpi
org.keycloak.services.managers.BruteForceProtectorSpi
org.keycloak.services.resource.RealmResourceSPI
-org.keycloak.sessions.LoginSessionSpi
+org.keycloak.sessions.AuthenticationSessionSpi
org.keycloak.protocol.ClientInstallationSpi
org.keycloak.protocol.LoginProtocolSpi
org.keycloak.protocol.ProtocolMapperSpi
diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
index 4a5053f..70c876f 100755
--- a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
+++ b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
@@ -31,7 +31,7 @@ import org.keycloak.forms.login.LoginFormsProvider;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.AuthenticationFlowModel;
import org.keycloak.models.AuthenticatorConfigModel;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.KeycloakSession;
@@ -51,7 +51,7 @@ import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.messages.Messages;
import org.keycloak.services.resources.LoginActionsService;
import org.keycloak.services.util.CacheControlUtil;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
@@ -66,10 +66,14 @@ import java.util.Map;
*/
public class AuthenticationProcessor {
public static final String CURRENT_AUTHENTICATION_EXECUTION = "current.authentication.execution";
+ public static final String LAST_PROCESSED_EXECUTION = "last.processed.execution";
+ public static final String CURRENT_FLOW_PATH = "current.flow.path";
+ public static final String FORKED_FROM = "forked.from";
+
protected static final Logger logger = Logger.getLogger(AuthenticationProcessor.class);
protected RealmModel realm;
protected UserSessionModel userSession;
- protected LoginSessionModel loginSession;
+ protected AuthenticationSessionModel authenticationSession;
protected ClientConnection connection;
protected UriInfo uriInfo;
protected KeycloakSession session;
@@ -129,8 +133,8 @@ public class AuthenticationProcessor {
return clientAuthAttributes;
}
- public LoginSessionModel getLoginSession() {
- return loginSession;
+ public AuthenticationSessionModel getAuthenticationSession() {
+ return authenticationSession;
}
public ClientConnection getConnection() {
@@ -154,8 +158,8 @@ public class AuthenticationProcessor {
return this;
}
- public AuthenticationProcessor setLoginSession(LoginSessionModel loginSession) {
- this.loginSession = loginSession;
+ public AuthenticationProcessor setAuthenticationSession(AuthenticationSessionModel authenticationSession) {
+ this.authenticationSession = authenticationSession;
return this;
}
@@ -210,8 +214,8 @@ public class AuthenticationProcessor {
}
public String generateCode() {
- ClientSessionCode accessCode = new ClientSessionCode(session, getRealm(), getLoginSession());
- loginSession.setTimestamp(Time.currentTime());
+ ClientSessionCode accessCode = new ClientSessionCode(session, getRealm(), getAuthenticationSession());
+ authenticationSession.setTimestamp(Time.currentTime());
return accessCode.getCode();
}
@@ -229,15 +233,15 @@ public class AuthenticationProcessor {
}
public void setAutheticatedUser(UserModel user) {
- UserModel previousUser = getLoginSession().getAuthenticatedUser();
+ UserModel previousUser = getAuthenticationSession().getAuthenticatedUser();
if (previousUser != null && !user.getId().equals(previousUser.getId()))
throw new AuthenticationFlowException(AuthenticationFlowError.USER_CONFLICT);
validateUser(user);
- getLoginSession().setAuthenticatedUser(user);
+ getAuthenticationSession().setAuthenticatedUser(user);
}
public void clearAuthenticatedUser() {
- getLoginSession().setAuthenticatedUser(null);
+ getAuthenticationSession().setAuthenticatedUser(null);
}
public class Result implements AuthenticationFlowContext, ClientAuthenticationFlowContext {
@@ -360,7 +364,7 @@ public class AuthenticationProcessor {
@Override
public UserModel getUser() {
- return getLoginSession().getAuthenticatedUser();
+ return getAuthenticationSession().getAuthenticatedUser();
}
@Override
@@ -394,8 +398,8 @@ public class AuthenticationProcessor {
}
@Override
- public LoginSessionModel getLoginSession() {
- return AuthenticationProcessor.this.getLoginSession();
+ public AuthenticationSessionModel getAuthenticationSession() {
+ return AuthenticationProcessor.this.getAuthenticationSession();
}
@Override
@@ -480,19 +484,22 @@ public class AuthenticationProcessor {
}
@Override
- public URI getActionUrl() {
- return getActionUrl(generateAccessCode());
+ public URI getRefreshExecutionUrl() {
+ return LoginActionsService.loginActionsBaseUrl(getUriInfo())
+ .path(AuthenticationProcessor.this.flowPath)
+ .queryParam("execution", getExecution().getId())
+ .build(getRealm().getName());
}
@Override
public void cancelLogin() {
getEvent().error(Errors.REJECTED_BY_USER);
- LoginProtocol protocol = getSession().getProvider(LoginProtocol.class, getLoginSession().getProtocol());
+ LoginProtocol protocol = getSession().getProvider(LoginProtocol.class, getAuthenticationSession().getProtocol());
protocol.setRealm(getRealm())
.setHttpHeaders(getHttpRequest().getHttpHeaders())
.setUriInfo(getUriInfo())
.setEventBuilder(event);
- Response response = protocol.sendError(getLoginSession(), Error.CANCELLED_BY_USER);
+ Response response = protocol.sendError(getAuthenticationSession(), Error.CANCELLED_BY_USER);
forceChallenge(response);
}
@@ -536,7 +543,7 @@ public class AuthenticationProcessor {
public void logFailure() {
if (realm.isBruteForceProtected()) {
- String username = loginSession.getNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME);
+ String username = authenticationSession.getAuthNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME);
// todo need to handle non form failures
if (username == null) {
@@ -566,7 +573,7 @@ public class AuthenticationProcessor {
}
public boolean isSuccessful(AuthenticationExecutionModel model) {
- ClientSessionModel.ExecutionStatus status = loginSession.getExecutionStatus().get(model.getId());
+ ClientSessionModel.ExecutionStatus status = authenticationSession.getExecutionStatus().get(model.getId());
if (status == null) return false;
return status == ClientSessionModel.ExecutionStatus.SUCCESS;
}
@@ -599,10 +606,10 @@ public class AuthenticationProcessor {
} else if (e.getError() == AuthenticationFlowError.FORK_FLOW) {
ForkFlowException reset = (ForkFlowException)e;
- LoginSessionModel clone = clone(session, loginSession);
+ AuthenticationSessionModel clone = clone(session, authenticationSession);
clone.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
AuthenticationProcessor processor = new AuthenticationProcessor();
- processor.setLoginSession(clone)
+ processor.setAuthenticationSession(clone)
.setFlowPath(LoginActionsService.AUTHENTICATE_PATH)
.setFlowId(realm.getBrowserFlow().getId())
.setForwardedErrorMessage(reset.getErrorMessage())
@@ -694,22 +701,23 @@ public class AuthenticationProcessor {
}
- public Response redirectToFlow() {
- String code = generateCode();
+ public Response redirectToFlow(String execution) {
+ logger.info("Redirecting to flow with execution: " + execution);
+ authenticationSession.setAuthNote(LAST_PROCESSED_EXECUTION, execution);
URI redirect = LoginActionsService.loginActionsBaseUrl(getUriInfo())
.path(flowPath)
- .queryParam(OAuth2Constants.CODE, code).build(getRealm().getName());
+ .queryParam("execution", execution).build(getRealm().getName());
return Response.status(302).location(redirect).build();
}
- public static Response redirectToRequiredActions(KeycloakSession session, RealmModel realm, LoginSessionModel loginSession, UriInfo uriInfo) {
+ public static Response redirectToRequiredActions(KeycloakSession session, RealmModel realm, AuthenticationSessionModel authSession, UriInfo uriInfo) {
// redirect to non-action url so browser refresh button works without reposting past data
- ClientSessionCode<LoginSessionModel> accessCode = new ClientSessionCode<>(session, realm, loginSession);
+ ClientSessionCode<AuthenticationSessionModel> accessCode = new ClientSessionCode<>(session, realm, authSession);
accessCode.setAction(ClientSessionModel.Action.REQUIRED_ACTIONS.name());
- loginSession.setTimestamp(Time.currentTime());
+ authSession.setTimestamp(Time.currentTime());
URI redirect = LoginActionsService.loginActionsBaseUrl(uriInfo)
.path(LoginActionsService.REQUIRED_ACTION)
@@ -718,25 +726,30 @@ public class AuthenticationProcessor {
}
- public static void resetFlow(LoginSessionModel loginSession) {
+ public static void resetFlow(AuthenticationSessionModel authSession) {
logger.debug("RESET FLOW");
- loginSession.setTimestamp(Time.currentTime());
- loginSession.setAuthenticatedUser(null);
- loginSession.clearExecutionStatus();
- loginSession.clearUserSessionNotes();
- loginSession.removeNote(CURRENT_AUTHENTICATION_EXECUTION);
+ authSession.setTimestamp(Time.currentTime());
+ authSession.setAuthenticatedUser(null);
+ authSession.clearExecutionStatus();
+ authSession.clearUserSessionNotes();
+ authSession.clearAuthNotes();
}
- public static LoginSessionModel clone(KeycloakSession session, LoginSessionModel loginSession) {
- // TODO: Doublecheck false...
- LoginSessionModel clone = session.loginSessions().createLoginSession(loginSession.getRealm(), loginSession.getClient(), false);
- for (Map.Entry<String, String> entry : loginSession.getNotes().entrySet()) {
+ public static AuthenticationSessionModel clone(KeycloakSession session, AuthenticationSessionModel authSession) {
+ AuthenticationSessionModel clone = session.authenticationSessions().createAuthenticationSession(authSession.getRealm(), authSession.getClient(), true);
+
+ // Transfer just the client "notes", but not "authNotes"
+ for (Map.Entry<String, String> entry : authSession.getNotes().entrySet()) {
clone.setNote(entry.getKey(), entry.getValue());
}
- clone.setRedirectUri(loginSession.getRedirectUri());
- clone.setProtocol(loginSession.getProtocol());
+
+ clone.setRedirectUri(authSession.getRedirectUri());
+ clone.setProtocol(authSession.getProtocol());
clone.setTimestamp(Time.currentTime());
- clone.removeNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION);
+
+ clone.setAuthNote(FORKED_FROM, authSession.getId());
+ logger.infof("Forked authSession %s from authSession %s", clone.getId(), authSession.getId());
+
return clone;
}
@@ -744,27 +757,26 @@ public class AuthenticationProcessor {
public Response authenticationAction(String execution) {
logger.debug("authenticationAction");
- checkClientSession();
- String current = loginSession.getNote(CURRENT_AUTHENTICATION_EXECUTION);
+ checkClientSession(true);
+ String current = authenticationSession.getAuthNote(CURRENT_AUTHENTICATION_EXECUTION);
if (!execution.equals(current)) {
- logger.debug("Current execution does not equal executed execution. Might be a page refresh");
- //logFailure();
- //resetFlow(clientSession);
- return authenticate();
+ // TODO:mposolda debug
+ logger.info("Current execution does not equal executed execution. Might be a page refresh");
+ return redirectToFlow(current);
}
- UserModel authUser = loginSession.getAuthenticatedUser();
+ UserModel authUser = authenticationSession.getAuthenticatedUser();
validateUser(authUser);
AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution);
if (model == null) {
logger.debug("Cannot find execution, reseting flow");
logFailure();
- resetFlow(loginSession);
+ resetFlow(authenticationSession);
return authenticate();
}
- event.client(loginSession.getClient().getClientId())
- .detail(Details.REDIRECT_URI, loginSession.getRedirectUri())
- .detail(Details.AUTH_METHOD, loginSession.getProtocol());
- String authType = loginSession.getNote(Details.AUTH_TYPE);
+ event.client(authenticationSession.getClient().getClientId())
+ .detail(Details.REDIRECT_URI, authenticationSession.getRedirectUri())
+ .detail(Details.AUTH_METHOD, authenticationSession.getProtocol());
+ String authType = authenticationSession.getAuthNote(Details.AUTH_TYPE);
if (authType != null) {
event.detail(Details.AUTH_TYPE, authType);
}
@@ -772,40 +784,43 @@ public class AuthenticationProcessor {
AuthenticationFlow authenticationFlow = createFlowExecution(this.flowId, model);
Response challenge = authenticationFlow.processAction(execution);
if (challenge != null) return challenge;
- if (loginSession.getAuthenticatedUser() == null) {
+ if (authenticationSession.getAuthenticatedUser() == null) {
throw new AuthenticationFlowException(AuthenticationFlowError.UNKNOWN_USER);
}
return authenticationComplete();
}
- public void checkClientSession() {
- ClientSessionCode code = new ClientSessionCode(session, realm, loginSession);
- String action = ClientSessionModel.Action.AUTHENTICATE.name();
- if (!code.isValidAction(action)) {
- throw new AuthenticationFlowException(AuthenticationFlowError.INVALID_CLIENT_SESSION);
+ private void checkClientSession(boolean checkAction) {
+ ClientSessionCode code = new ClientSessionCode(session, realm, authenticationSession);
+
+ if (checkAction) {
+ String action = ClientSessionModel.Action.AUTHENTICATE.name();
+ if (!code.isValidAction(action)) {
+ throw new AuthenticationFlowException(AuthenticationFlowError.INVALID_CLIENT_SESSION);
+ }
}
if (!code.isActionActive(ClientSessionCode.ActionType.LOGIN)) {
throw new AuthenticationFlowException(AuthenticationFlowError.EXPIRED_CODE);
}
- loginSession.setTimestamp(Time.currentTime());
+ authenticationSession.setTimestamp(Time.currentTime());
}
public Response authenticateOnly() throws AuthenticationFlowException {
logger.debug("AUTHENTICATE ONLY");
- checkClientSession();
- event.client(loginSession.getClient().getClientId())
- .detail(Details.REDIRECT_URI, loginSession.getRedirectUri())
- .detail(Details.AUTH_METHOD, loginSession.getProtocol());
- String authType = loginSession.getNote(Details.AUTH_TYPE);
+ checkClientSession(false);
+ event.client(authenticationSession.getClient().getClientId())
+ .detail(Details.REDIRECT_URI, authenticationSession.getRedirectUri())
+ .detail(Details.AUTH_METHOD, authenticationSession.getProtocol());
+ String authType = authenticationSession.getAuthNote(Details.AUTH_TYPE);
if (authType != null) {
event.detail(Details.AUTH_TYPE, authType);
}
- UserModel authUser = loginSession.getAuthenticatedUser();
+ UserModel authUser = authenticationSession.getAuthenticatedUser();
validateUser(authUser);
AuthenticationFlow authenticationFlow = createFlowExecution(this.flowId, null);
Response challenge = authenticationFlow.processFlow();
if (challenge != null) return challenge;
- if (loginSession.getAuthenticatedUser() == null) {
+ if (authenticationSession.getAuthenticatedUser() == null) {
throw new AuthenticationFlowException(AuthenticationFlowError.UNKNOWN_USER);
}
return challenge;
@@ -834,26 +849,32 @@ public class AuthenticationProcessor {
}
// May create userSession too
- public ClientLoginSessionModel attachSession() {
- return attachSession(loginSession, userSession, session, realm, connection, event);
+ public AuthenticatedClientSessionModel attachSession() {
+ AuthenticatedClientSessionModel clientSession = attachSession(authenticationSession, userSession, session, realm, connection, event);
+
+ if (userSession == null) {
+ userSession = clientSession.getUserSession();
+ }
+
+ return clientSession;
}
// May create new userSession too (if userSession argument is null)
- public static ClientLoginSessionModel attachSession(LoginSessionModel loginSession, UserSessionModel userSession, KeycloakSession session, RealmModel realm, ClientConnection connection, EventBuilder event) {
- String username = loginSession.getAuthenticatedUser().getUsername();
- String attemptedUsername = loginSession.getNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME);
+ public static AuthenticatedClientSessionModel attachSession(AuthenticationSessionModel authSession, UserSessionModel userSession, KeycloakSession session, RealmModel realm, ClientConnection connection, EventBuilder event) {
+ String username = authSession.getAuthenticatedUser().getUsername();
+ String attemptedUsername = authSession.getAuthNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME);
if (attemptedUsername != null) username = attemptedUsername;
- String rememberMe = loginSession.getNote(Details.REMEMBER_ME);
+ String rememberMe = authSession.getAuthNote(Details.REMEMBER_ME);
boolean remember = rememberMe != null && rememberMe.equalsIgnoreCase("true");
if (userSession == null) { // if no authenticator attached a usersession
- userSession = session.sessions().createUserSession(realm, loginSession.getAuthenticatedUser(), username, connection.getRemoteAddr(), loginSession.getProtocol(), remember, null, null);
+ userSession = session.sessions().createUserSession(realm, authSession.getAuthenticatedUser(), username, connection.getRemoteAddr(), authSession.getProtocol(), remember, null, null);
userSession.setState(UserSessionModel.State.LOGGING_IN);
}
if (remember) {
event.detail(Details.REMEMBER_ME, "true");
}
- ClientLoginSessionModel clientSession = TokenManager.attachLoginSession(session, userSession, loginSession);
+ AuthenticatedClientSessionModel clientSession = TokenManager.attachAuthenticationSession(session, userSession, authSession);
event.user(userSession.getUser())
.detail(Details.USERNAME, username)
@@ -863,13 +884,13 @@ public class AuthenticationProcessor {
}
public void evaluateRequiredActionTriggers() {
- AuthenticationManager.evaluateRequiredActionTriggers(session, loginSession, connection, request, uriInfo, event, realm, loginSession.getAuthenticatedUser());
+ AuthenticationManager.evaluateRequiredActionTriggers(session, authenticationSession, connection, request, uriInfo, event, realm, authenticationSession.getAuthenticatedUser());
}
public Response finishAuthentication(LoginProtocol protocol) {
event.success();
- RealmModel realm = loginSession.getRealm();
- ClientLoginSessionModel clientSession = attachSession();
+ RealmModel realm = authenticationSession.getRealm();
+ AuthenticatedClientSessionModel clientSession = attachSession();
return AuthenticationManager.redirectAfterSuccessfulFlow(session, realm, userSession,clientSession, request, uriInfo, connection, event, protocol);
}
@@ -886,20 +907,26 @@ public class AuthenticationProcessor {
protected Response authenticationComplete() {
// attachSession(); // Session will be attached after requiredActions + consents are finished.
+ AuthenticationManager.setRolesAndMappersInSession(authenticationSession);
+
if (isActionRequired()) {
- // TODO:mposolda Changed this to avoid additional redirect. Doublecheck consequences...
- //return redirectToRequiredActions(session, realm, loginSession, uriInfo);
- return AuthenticationManager.nextActionAfterAuthentication(session, loginSession, connection, request, uriInfo, event);
+ // TODO:mposolda This was changed to avoid additional redirect. Doublecheck consequences...
+ //return redirectToRequiredActions(session, realm, authenticationSession, uriInfo);
+ ClientSessionCode<AuthenticationSessionModel> accessCode = new ClientSessionCode<>(session, realm, authenticationSession);
+ accessCode.setAction(ClientSessionModel.Action.REQUIRED_ACTIONS.name());
+ authenticationSession.setAuthNote(CURRENT_FLOW_PATH, LoginActionsService.REQUIRED_ACTION);
+
+ return AuthenticationManager.nextActionAfterAuthentication(session, authenticationSession, connection, request, uriInfo, event);
} else {
- event.detail(Details.CODE_ID, loginSession.getId()); // todo This should be set elsewhere. find out why tests fail. Don't know where this is supposed to be set
+ event.detail(Details.CODE_ID, authenticationSession.getId()); // todo This should be set elsewhere. find out why tests fail. Don't know where this is supposed to be set
// the user has successfully logged in and we can clear his/her previous login failure attempts.
logSuccess();
- return AuthenticationManager.finishedRequiredActions(session, loginSession, connection, request, uriInfo, event);
+ return AuthenticationManager.finishedRequiredActions(session, authenticationSession, connection, request, uriInfo, event);
}
}
public boolean isActionRequired() {
- return AuthenticationManager.isActionRequired(session, loginSession, connection, request, uriInfo, event);
+ return AuthenticationManager.isActionRequired(session, authenticationSession, connection, request, uriInfo, event);
}
public AuthenticationProcessor.Result createAuthenticatorContext(AuthenticationExecutionModel model, Authenticator authenticator, List<AuthenticationExecutionModel> executions) {
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/broker/AbstractIdpAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/broker/AbstractIdpAuthenticator.java
index fd65f61..9ba2053 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/broker/AbstractIdpAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/broker/AbstractIdpAuthenticator.java
@@ -29,7 +29,7 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.services.messages.Messages;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
import javax.ws.rs.core.Response;
@@ -59,13 +59,13 @@ public abstract class AbstractIdpAuthenticator implements Authenticator {
@Override
public void authenticate(AuthenticationFlowContext context) {
- LoginSessionModel loginSession = context.getLoginSession();
+ AuthenticationSessionModel authSession = context.getAuthenticationSession();
- SerializedBrokeredIdentityContext serializedCtx = SerializedBrokeredIdentityContext.readFromLoginSession(loginSession, BROKERED_CONTEXT_NOTE);
+ SerializedBrokeredIdentityContext serializedCtx = SerializedBrokeredIdentityContext.readFromLoginSession(authSession, BROKERED_CONTEXT_NOTE);
if (serializedCtx == null) {
throw new AuthenticationFlowException("Not found serialized context in clientSession", AuthenticationFlowError.IDENTITY_PROVIDER_ERROR);
}
- BrokeredIdentityContext brokerContext = serializedCtx.deserialize(context.getSession(), loginSession);
+ BrokeredIdentityContext brokerContext = serializedCtx.deserialize(context.getSession(), authSession);
if (!brokerContext.getIdpConfig().isEnabled()) {
sendFailureChallenge(context, Errors.IDENTITY_PROVIDER_ERROR, Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR, AuthenticationFlowError.IDENTITY_PROVIDER_ERROR);
@@ -76,7 +76,7 @@ public abstract class AbstractIdpAuthenticator implements Authenticator {
@Override
public void action(AuthenticationFlowContext context) {
- LoginSessionModel clientSession = context.getLoginSession();
+ AuthenticationSessionModel clientSession = context.getAuthenticationSession();
SerializedBrokeredIdentityContext serializedCtx = SerializedBrokeredIdentityContext.readFromLoginSession(clientSession, BROKERED_CONTEXT_NOTE);
if (serializedCtx == null) {
@@ -112,8 +112,8 @@ public abstract class AbstractIdpAuthenticator implements Authenticator {
}
- public static UserModel getExistingUser(KeycloakSession session, RealmModel realm, LoginSessionModel loginSession) {
- String existingUserId = loginSession.getNote(EXISTING_USER_INFO);
+ public static UserModel getExistingUser(KeycloakSession session, RealmModel realm, AuthenticationSessionModel authSession) {
+ String existingUserId = authSession.getAuthNote(EXISTING_USER_INFO);
if (existingUserId == null) {
throw new AuthenticationFlowException("Unexpected state. There is no existing duplicated user identified in ClientSession",
AuthenticationFlowError.INTERNAL_ERROR);
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpConfirmLinkAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpConfirmLinkAuthenticator.java
index 0b84872..d4cfcf5 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpConfirmLinkAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpConfirmLinkAuthenticator.java
@@ -29,7 +29,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.services.ServicesLogger;
import org.keycloak.services.messages.Messages;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
@@ -41,9 +41,9 @@ public class IdpConfirmLinkAuthenticator extends AbstractIdpAuthenticator {
@Override
protected void authenticateImpl(AuthenticationFlowContext context, SerializedBrokeredIdentityContext serializedCtx, BrokeredIdentityContext brokerContext) {
- LoginSessionModel loginSession = context.getLoginSession();
+ AuthenticationSessionModel authSession = context.getAuthenticationSession();
- String existingUserInfo = loginSession.getNote(EXISTING_USER_INFO);
+ String existingUserInfo = authSession.getAuthNote(EXISTING_USER_INFO);
if (existingUserInfo == null) {
ServicesLogger.LOGGER.noDuplicationDetected();
context.attempted();
@@ -65,8 +65,8 @@ public class IdpConfirmLinkAuthenticator extends AbstractIdpAuthenticator {
String action = formData.getFirst("submitAction");
if (action != null && action.equals("updateProfile")) {
- context.getLoginSession().setNote(ENFORCE_UPDATE_PROFILE, "true");
- context.getLoginSession().removeNote(EXISTING_USER_INFO);
+ context.getAuthenticationSession().setAuthNote(ENFORCE_UPDATE_PROFILE, "true");
+ context.getAuthenticationSession().removeAuthNote(EXISTING_USER_INFO);
context.resetFlow();
} else if (action != null && action.equals("linkAccount")) {
context.success();
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpCreateUserIfUniqueAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpCreateUserIfUniqueAuthenticator.java
index f905e0c..aacd1e6 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpCreateUserIfUniqueAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpCreateUserIfUniqueAuthenticator.java
@@ -53,7 +53,7 @@ public class IdpCreateUserIfUniqueAuthenticator extends AbstractIdpAuthenticator
KeycloakSession session = context.getSession();
RealmModel realm = context.getRealm();
- if (context.getLoginSession().getNote(EXISTING_USER_INFO) != null) {
+ if (context.getAuthenticationSession().getAuthNote(EXISTING_USER_INFO) != null) {
context.attempted();
return;
}
@@ -61,7 +61,7 @@ public class IdpCreateUserIfUniqueAuthenticator extends AbstractIdpAuthenticator
String username = getUsername(context, serializedCtx, brokerContext);
if (username == null) {
ServicesLogger.LOGGER.resetFlow(realm.isRegistrationEmailAsUsername() ? "Email" : "Username");
- context.getLoginSession().setNote(ENFORCE_UPDATE_PROFILE, "true");
+ context.getAuthenticationSession().setAuthNote(ENFORCE_UPDATE_PROFILE, "true");
context.resetFlow();
return;
}
@@ -91,14 +91,14 @@ public class IdpCreateUserIfUniqueAuthenticator extends AbstractIdpAuthenticator
userRegisteredSuccess(context, federatedUser, serializedCtx, brokerContext);
context.setUser(federatedUser);
- context.getLoginSession().setNote(BROKER_REGISTERED_NEW_USER, "true");
+ context.getAuthenticationSession().setAuthNote(BROKER_REGISTERED_NEW_USER, "true");
context.success();
} else {
logger.debugf("Duplication detected. There is already existing user with %s '%s' .",
duplication.getDuplicateAttributeName(), duplication.getDuplicateAttributeValue());
// Set duplicated user, so next authenticators can deal with it
- context.getLoginSession().setNote(EXISTING_USER_INFO, duplication.serialize());
+ context.getAuthenticationSession().setAuthNote(EXISTING_USER_INFO, duplication.serialize());
Response challengeResponse = context.form()
.setError(Messages.FEDERATED_IDENTITY_EXISTS, duplication.getDuplicateAttributeName(), duplication.getDuplicateAttributeValue())
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpReviewProfileAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpReviewProfileAuthenticator.java
index edd3c62..245f258 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpReviewProfileAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpReviewProfileAuthenticator.java
@@ -73,7 +73,7 @@ public class IdpReviewProfileAuthenticator extends AbstractIdpAuthenticator {
}
protected boolean requiresUpdateProfilePage(AuthenticationFlowContext context, SerializedBrokeredIdentityContext userCtx, BrokeredIdentityContext brokerContext) {
- String enforceUpdateProfile = context.getLoginSession().getNote(ENFORCE_UPDATE_PROFILE);
+ String enforceUpdateProfile = context.getAuthenticationSession().getAuthNote(ENFORCE_UPDATE_PROFILE);
if (Boolean.parseBoolean(enforceUpdateProfile)) {
return true;
}
@@ -122,12 +122,12 @@ public class IdpReviewProfileAuthenticator extends AbstractIdpAuthenticator {
}
userCtx.setEmail(email);
- context.getLoginSession().setNote(UPDATE_PROFILE_EMAIL_CHANGED, "true");
+ context.getAuthenticationSession().setAuthNote(UPDATE_PROFILE_EMAIL_CHANGED, "true");
}
AttributeFormDataProcessor.process(formData, realm, userCtx);
- userCtx.saveToLoginSession(context.getLoginSession(), BROKERED_CONTEXT_NOTE);
+ userCtx.saveToLoginSession(context.getAuthenticationSession(), BROKERED_CONTEXT_NOTE);
logger.debugf("Profile updated successfully after first authentication with identity provider '%s' for broker user '%s'.", brokerContext.getIdpConfig().getAlias(), userCtx.getUsername());
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpUsernamePasswordForm.java b/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpUsernamePasswordForm.java
index 071a1ec..edcc030 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpUsernamePasswordForm.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/broker/IdpUsernamePasswordForm.java
@@ -39,7 +39,7 @@ public class IdpUsernamePasswordForm extends UsernamePasswordForm {
@Override
protected Response challenge(AuthenticationFlowContext context, MultivaluedMap<String, String> formData) {
- UserModel existingUser = AbstractIdpAuthenticator.getExistingUser(context.getSession(), context.getRealm(), context.getLoginSession());
+ UserModel existingUser = AbstractIdpAuthenticator.getExistingUser(context.getSession(), context.getRealm(), context.getAuthenticationSession());
return setupForm(context, formData, existingUser)
.setStatus(Response.Status.OK)
@@ -48,7 +48,7 @@ public class IdpUsernamePasswordForm extends UsernamePasswordForm {
@Override
protected boolean validateForm(AuthenticationFlowContext context, MultivaluedMap<String, String> formData) {
- UserModel existingUser = AbstractIdpAuthenticator.getExistingUser(context.getSession(), context.getRealm(), context.getLoginSession());
+ UserModel existingUser = AbstractIdpAuthenticator.getExistingUser(context.getSession(), context.getRealm(), context.getAuthenticationSession());
context.setUser(existingUser);
// Restore formData for the case of error
@@ -58,7 +58,7 @@ public class IdpUsernamePasswordForm extends UsernamePasswordForm {
}
protected LoginFormsProvider setupForm(AuthenticationFlowContext context, MultivaluedMap<String, String> formData, UserModel existingUser) {
- SerializedBrokeredIdentityContext serializedCtx = SerializedBrokeredIdentityContext.readFromLoginSession(context.getLoginSession(), AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE);
+ SerializedBrokeredIdentityContext serializedCtx = SerializedBrokeredIdentityContext.readFromLoginSession(context.getAuthenticationSession(), AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE);
if (serializedCtx == null) {
throw new AuthenticationFlowException("Not found serialized context in clientSession", AuthenticationFlowError.IDENTITY_PROVIDER_ERROR);
}
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/broker/util/SerializedBrokeredIdentityContext.java b/services/src/main/java/org/keycloak/authentication/authenticators/broker/util/SerializedBrokeredIdentityContext.java
index 86bb979..e648242 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/broker/util/SerializedBrokeredIdentityContext.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/broker/util/SerializedBrokeredIdentityContext.java
@@ -24,14 +24,13 @@ import org.keycloak.broker.provider.IdentityProvider;
import org.keycloak.broker.provider.IdentityProviderDataMarshaller;
import org.keycloak.common.util.Base64Url;
import org.keycloak.common.util.reflections.Reflections;
-import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.Constants;
import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelException;
import org.keycloak.models.RealmModel;
import org.keycloak.services.resources.IdentityBrokerService;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
import org.keycloak.util.JsonSerialization;
import java.io.IOException;
@@ -247,7 +246,7 @@ public class SerializedBrokeredIdentityContext implements UpdateProfileContext {
}
}
- public BrokeredIdentityContext deserialize(KeycloakSession session, LoginSessionModel loginSession) {
+ public BrokeredIdentityContext deserialize(KeycloakSession session, AuthenticationSessionModel authSession) {
BrokeredIdentityContext ctx = new BrokeredIdentityContext(getId());
ctx.setUsername(getBrokerUsername());
@@ -259,7 +258,7 @@ public class SerializedBrokeredIdentityContext implements UpdateProfileContext {
ctx.setBrokerUserId(getBrokerUserId());
ctx.setToken(getToken());
- RealmModel realm = loginSession.getRealm();
+ RealmModel realm = authSession.getRealm();
IdentityProviderModel idpConfig = realm.getIdentityProviderByAlias(getIdentityProviderId());
if (idpConfig == null) {
throw new ModelException("Can't find identity provider with ID " + getIdentityProviderId() + " in realm " + realm.getName());
@@ -283,7 +282,7 @@ public class SerializedBrokeredIdentityContext implements UpdateProfileContext {
}
}
- ctx.setLoginSession(loginSession);
+ ctx.setAuthenticationSession(authSession);
return ctx;
}
@@ -300,7 +299,7 @@ public class SerializedBrokeredIdentityContext implements UpdateProfileContext {
ctx.setToken(context.getToken());
ctx.setIdentityProviderId(context.getIdpConfig().getAlias());
- ctx.emailAsUsername = context.getLoginSession().getRealm().isRegistrationEmailAsUsername();
+ ctx.emailAsUsername = context.getAuthenticationSession().getRealm().isRegistrationEmailAsUsername();
IdentityProviderDataMarshaller serializer = context.getIdp().getMarshaller();
@@ -315,23 +314,23 @@ public class SerializedBrokeredIdentityContext implements UpdateProfileContext {
}
// Save this context as note to clientSession
- public void saveToLoginSession(LoginSessionModel loginSession, String noteKey) {
+ public void saveToLoginSession(AuthenticationSessionModel authSession, String noteKey) {
try {
String asString = JsonSerialization.writeValueAsString(this);
- loginSession.setNote(noteKey, asString);
+ authSession.setAuthNote(noteKey, asString);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
- public static SerializedBrokeredIdentityContext readFromLoginSession(LoginSessionModel loginSession, String noteKey) {
- String asString = loginSession.getNote(noteKey);
+ public static SerializedBrokeredIdentityContext readFromLoginSession(AuthenticationSessionModel authSession, String noteKey) {
+ String asString = authSession.getAuthNote(noteKey);
if (asString == null) {
return null;
} else {
try {
SerializedBrokeredIdentityContext serializedCtx = JsonSerialization.readValue(asString, SerializedBrokeredIdentityContext.class);
- serializedCtx.emailAsUsername = loginSession.getRealm().isRegistrationEmailAsUsername();
+ serializedCtx.emailAsUsername = authSession.getRealm().isRegistrationEmailAsUsername();
return serializedCtx;
} catch (IOException ioe) {
throw new RuntimeException(ioe);
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/AbstractUsernameFormAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/AbstractUsernameFormAuthenticator.java
index fc73e18..a0f13bc 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/browser/AbstractUsernameFormAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/AbstractUsernameFormAuthenticator.java
@@ -126,7 +126,7 @@ public abstract class AbstractUsernameFormAuthenticator extends AbstractFormAuth
username = username.trim();
context.getEvent().detail(Details.USERNAME, username);
- context.getLoginSession().setNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME, username);
+ context.getAuthenticationSession().setAuthNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME, username);
UserModel user = null;
try {
@@ -159,10 +159,10 @@ public abstract class AbstractUsernameFormAuthenticator extends AbstractFormAuth
String rememberMe = inputData.getFirst("rememberMe");
boolean remember = rememberMe != null && rememberMe.equalsIgnoreCase("on");
if (remember) {
- context.getLoginSession().setNote(Details.REMEMBER_ME, "true");
+ context.getAuthenticationSession().setAuthNote(Details.REMEMBER_ME, "true");
context.getEvent().detail(Details.REMEMBER_ME, "true");
} else {
- context.getLoginSession().removeNote(Details.REMEMBER_ME);
+ context.getAuthenticationSession().removeAuthNote(Details.REMEMBER_ME);
}
context.setUser(user);
return true;
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/CookieAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/CookieAuthenticator.java
index d1c22f5..73c92cf 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/browser/CookieAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/CookieAuthenticator.java
@@ -19,13 +19,12 @@ package org.keycloak.authentication.authenticators.browser;
import org.keycloak.authentication.AuthenticationFlowContext;
import org.keycloak.authentication.Authenticator;
-import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.protocol.LoginProtocol;
import org.keycloak.services.managers.AuthenticationManager;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -45,7 +44,7 @@ public class CookieAuthenticator implements Authenticator {
if (authResult == null) {
context.attempted();
} else {
- LoginSessionModel clientSession = context.getLoginSession();
+ AuthenticationSessionModel clientSession = context.getAuthenticationSession();
LoginProtocol protocol = context.getSession().getProvider(LoginProtocol.class, clientSession.getProtocol());
// Cookie re-authentication is skipped if re-authentication is required
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/IdentityProviderAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/IdentityProviderAuthenticator.java
index 8cfd714..cb31e8d 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/browser/IdentityProviderAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/IdentityProviderAuthenticator.java
@@ -63,7 +63,7 @@ public class IdentityProviderAuthenticator implements Authenticator {
List<IdentityProviderModel> identityProviders = context.getRealm().getIdentityProviders();
for (IdentityProviderModel identityProvider : identityProviders) {
if (identityProvider.isEnabled() && providerId.equals(identityProvider.getAlias())) {
- String accessCode = new ClientSessionCode<>(context.getSession(), context.getRealm(), context.getLoginSession()).getCode();
+ String accessCode = new ClientSessionCode<>(context.getSession(), context.getRealm(), context.getAuthenticationSession()).getCode();
Response response = Response.seeOther(
Urls.identityProviderAuthnRequest(context.getUriInfo().getBaseUri(), providerId, context.getRealm().getName(), accessCode))
.build();
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/ScriptBasedAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/ScriptBasedAuthenticator.java
index 1a90b59..5e0851a 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/browser/ScriptBasedAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/ScriptBasedAuthenticator.java
@@ -160,7 +160,7 @@ public class ScriptBasedAuthenticator implements Authenticator {
bindings.put("user", context.getUser());
bindings.put("session", context.getSession());
bindings.put("httpRequest", context.getHttpRequest());
- bindings.put("clientSession", context.getLoginSession());
+ bindings.put("clientSession", context.getAuthenticationSession());
bindings.put("LOG", LOGGER);
});
}
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoAuthenticator.java
index c909921..6b72686 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/SpnegoAuthenticator.java
@@ -30,7 +30,6 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
-import org.keycloak.services.ServicesLogger;
import org.keycloak.services.messages.Messages;
import javax.ws.rs.core.HttpHeaders;
@@ -98,7 +97,7 @@ public class SpnegoAuthenticator extends AbstractUsernameFormAuthenticator imple
context.setUser(output.getAuthenticatedUser());
if (output.getState() != null && !output.getState().isEmpty()) {
for (Map.Entry<String, String> entry : output.getState().entrySet()) {
- context.getLoginSession().setUserSessionNote(entry.getKey(), entry.getValue());
+ context.getAuthenticationSession().setUserSessionNote(entry.getKey(), entry.getValue());
}
}
context.success();
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/UsernamePasswordForm.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/UsernamePasswordForm.java
index cde0cb3..eaa95bb 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/browser/UsernamePasswordForm.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/UsernamePasswordForm.java
@@ -59,7 +59,7 @@ public class UsernamePasswordForm extends AbstractUsernameFormAuthenticator impl
@Override
public void authenticate(AuthenticationFlowContext context) {
MultivaluedMap<String, String> formData = new MultivaluedMapImpl<>();
- String loginHint = context.getLoginSession().getNote(OIDCLoginProtocol.LOGIN_HINT_PARAM);
+ String loginHint = context.getAuthenticationSession().getNote(OIDCLoginProtocol.LOGIN_HINT_PARAM);
String rememberMeUsername = AuthenticationManager.getRememberMeUsername(context.getRealm(), context.getHttpRequest().getHttpHeaders());
@@ -72,7 +72,7 @@ public class UsernamePasswordForm extends AbstractUsernameFormAuthenticator impl
}
}
Response challengeResponse = challenge(context, formData);
- context.getLoginSession().setNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION, context.getExecution().getId());
+ context.getAuthenticationSession().setAuthNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION, context.getExecution().getId());
context.challenge(challengeResponse);
}
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidateUsername.java b/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidateUsername.java
index 409618f..a1cbbe5 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidateUsername.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidateUsername.java
@@ -55,7 +55,7 @@ public class ValidateUsername extends AbstractDirectGrantAuthenticator {
return;
}
context.getEvent().detail(Details.USERNAME, username);
- context.getLoginSession().setNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME, username);
+ context.getAuthenticationSession().setAuthNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME, username);
UserModel user = null;
try {
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetCredentialChooseUser.java b/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetCredentialChooseUser.java
index 9604504..4f022a0 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetCredentialChooseUser.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetCredentialChooseUser.java
@@ -34,7 +34,6 @@ import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.provider.ProviderConfigProperty;
-import org.keycloak.services.ServicesLogger;
import org.keycloak.services.messages.Messages;
import javax.ws.rs.core.MultivaluedMap;
@@ -53,9 +52,9 @@ public class ResetCredentialChooseUser implements Authenticator, AuthenticatorFa
@Override
public void authenticate(AuthenticationFlowContext context) {
- String existingUserId = context.getLoginSession().getNote(AbstractIdpAuthenticator.EXISTING_USER_INFO);
+ String existingUserId = context.getAuthenticationSession().getAuthNote(AbstractIdpAuthenticator.EXISTING_USER_INFO);
if (existingUserId != null) {
- UserModel existingUser = AbstractIdpAuthenticator.getExistingUser(context.getSession(), context.getRealm(), context.getLoginSession());
+ UserModel existingUser = AbstractIdpAuthenticator.getExistingUser(context.getSession(), context.getRealm(), context.getAuthenticationSession());
logger.debugf("Forget-password triggered when reauthenticating user after first broker login. Skipping reset-credential-choose-user screen and using user '%s' ", existingUser.getUsername());
context.setUser(existingUser);
@@ -89,7 +88,7 @@ public class ResetCredentialChooseUser implements Authenticator, AuthenticatorFa
user = context.getSession().users().getUserByEmail(username, realm);
}
- context.getLoginSession().setNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME, username);
+ context.getAuthenticationSession().setAuthNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME, username);
// we don't want people guessing usernames, so if there is a problem, just continue, but don't set the user
// a null user will notify further executions, that this was a failure.
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetCredentialEmail.java b/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetCredentialEmail.java
index 8f21ddf..462b5d2 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetCredentialEmail.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetCredentialEmail.java
@@ -36,6 +36,7 @@ import org.keycloak.provider.ProviderConfigProperty;
import org.keycloak.services.ServicesLogger;
import org.keycloak.services.messages.Messages;
import org.keycloak.services.resources.LoginActionsService;
+import org.keycloak.sessions.AuthenticationSessionModel;
import java.util.*;
import javax.ws.rs.core.Response;
@@ -52,10 +53,8 @@ public class ResetCredentialEmail implements Authenticator, AuthenticatorFactory
@Override
public void authenticate(AuthenticationFlowContext context) {
- /*LoginActionsService.createActionCookie(context.getRealm(), context.getUriInfo(), context.getConnection(), context.getClientSession().getId());
-
UserModel user = context.getUser();
- String username = context.getClientSession().getNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME);
+ String username = context.getAuthenticationSession().getAuthNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME);
// we don't want people guessing usernames, so if there was a problem obtaining the user, the user will be null.
// just reset login for with a success message
@@ -84,10 +83,10 @@ public class ResetCredentialEmail implements Authenticator, AuthenticatorFactory
Long lastCreatedPassword = password == null ? null : password.getCreatedDate();
// We send the secret in the email in a link as a query param.
- ResetCredentialsActionToken token = new ResetCredentialsActionToken(user.getId(), absoluteExpirationInSecs, null, lastCreatedPassword, context.getClientSession());
+ ResetCredentialsActionToken token = new ResetCredentialsActionToken(user.getId(), absoluteExpirationInSecs, null, lastCreatedPassword, context.getAuthenticationSession());
KeycloakSession keycloakSession = context.getSession();
String link = UriBuilder
- .fromUri(context.getActionUrl())
+ .fromUri(context.getRefreshExecutionUrl())
.queryParam(Constants.KEY, token.serialize(keycloakSession, context.getRealm(), context.getUriInfo()))
.build()
.toString();
@@ -98,7 +97,7 @@ public class ResetCredentialEmail implements Authenticator, AuthenticatorFactory
event.clone().event(EventType.SEND_RESET_PASSWORD)
.user(user)
.detail(Details.USERNAME, username)
- .detail(Details.EMAIL, user.getEmail()).detail(Details.CODE_ID, context.getClientSession().getId()).success();
+ .detail(Details.EMAIL, user.getEmail()).detail(Details.CODE_ID, context.getAuthenticationSession().getId()).success();
context.forkWithSuccessMessage(new FormMessage(Messages.EMAIL_SENT));
} catch (EmailException e) {
event.clone().event(EventType.SEND_RESET_PASSWORD)
@@ -110,12 +109,11 @@ public class ResetCredentialEmail implements Authenticator, AuthenticatorFactory
.setError(Messages.EMAIL_SENT_ERROR)
.createErrorPage();
context.failure(AuthenticationFlowError.INTERNAL_ERROR, challenge);
- }*/
+ }
}
@Override
public void action(AuthenticationFlowContext context) {
- /*
KeycloakSession keycloakSession = context.getSession();
String actionTokenString = context.getUriInfo().getQueryParameters().getFirst(Constants.KEY);
ResetCredentialsActionToken tokenFromMail = null;
@@ -147,10 +145,10 @@ public class ResetCredentialEmail implements Authenticator, AuthenticatorFactory
Long lastCreatedPasswordMail = tokenFromMail.getLastChangedPasswordTimestamp();
Long lastCreatedPasswordFromStore = password == null ? null : password.getCreatedDate();
- String clientSessionId = tokenFromMail.getClientSessionId();
- ClientSessionModel clientSession = clientSessionId == null ? null : keycloakSession.sessions().getClientSession(clientSessionId);
+ String authenticationSessionId = tokenFromMail.getAuthenticationSessionId();
+ AuthenticationSessionModel authenticationSession = authenticationSessionId == null ? null : keycloakSession.authenticationSessions().getAuthenticationSession(context.getRealm(), authenticationSessionId);
- if (clientSession == null
+ if (authenticationSession == null
|| ! Objects.equals(lastCreatedPasswordMail, lastCreatedPasswordFromStore)
|| ! Objects.equals(userId, context.getUser().getId())) {
context.getEvent()
@@ -167,7 +165,7 @@ public class ResetCredentialEmail implements Authenticator, AuthenticatorFactory
// We now know email is valid, so set it to valid.
context.getUser().setEmailVerified(true);
- context.success();*/
+ context.success();
}
@Override
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetOTP.java b/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetOTP.java
index 7dcf829..4c1fdad 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetOTP.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetOTP.java
@@ -33,7 +33,7 @@ public class ResetOTP extends AbstractSetRequiredActionAuthenticator {
if (context.getExecution().isRequired() ||
(context.getExecution().isOptional() &&
configuredFor(context))) {
- context.getLoginSession().addRequiredAction(UserModel.RequiredAction.CONFIGURE_TOTP);
+ context.getAuthenticationSession().addRequiredAction(UserModel.RequiredAction.CONFIGURE_TOTP);
}
context.success();
}
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetPassword.java b/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetPassword.java
index 9c0fdab..68b8bfc 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetPassword.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetPassword.java
@@ -20,8 +20,6 @@ package org.keycloak.authentication.authenticators.resetcred;
import org.keycloak.authentication.AuthenticationFlowContext;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
-import org.keycloak.services.managers.AuthenticationManager;
-import org.keycloak.services.resources.LoginActionsService;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -33,15 +31,10 @@ public class ResetPassword extends AbstractSetRequiredActionAuthenticator {
@Override
public void authenticate(AuthenticationFlowContext context) {
- String actionCookie = LoginActionsService.getActionCookie(context.getSession().getContext().getRequestHeaders(), context.getRealm(), context.getUriInfo(), context.getConnection());
- if (actionCookie == null || !actionCookie.equals(context.getLoginSession().getId())) {
- context.getLoginSession().setNote(AuthenticationManager.END_AFTER_REQUIRED_ACTIONS, "true");
- }
-
if (context.getExecution().isRequired() ||
(context.getExecution().isOptional() &&
configuredFor(context))) {
- context.getLoginSession().addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
+ context.getAuthenticationSession().addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
}
context.success();
}
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/x509/ValidateX509CertificateUsername.java b/services/src/main/java/org/keycloak/authentication/authenticators/x509/ValidateX509CertificateUsername.java
index e0860fa..46f800e 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/x509/ValidateX509CertificateUsername.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/x509/ValidateX509CertificateUsername.java
@@ -92,7 +92,7 @@ public class ValidateX509CertificateUsername extends AbstractX509ClientCertifica
UserModel user;
try {
context.getEvent().detail(Details.USERNAME, userIdentity.toString());
- context.getClientSession().setNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME, userIdentity.toString());
+ context.getAuthenticationSession().setNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME, userIdentity.toString());
user = getUserIdentityToModelMapper(config).find(context, userIdentity);
}
catch(ModelDuplicateException e) {
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/x509/X509ClientCertificateAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/x509/X509ClientCertificateAuthenticator.java
index 21e67ec..01345ba 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/x509/X509ClientCertificateAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/x509/X509ClientCertificateAuthenticator.java
@@ -111,7 +111,7 @@ public class X509ClientCertificateAuthenticator extends AbstractX509ClientCertif
UserModel user;
try {
context.getEvent().detail(Details.USERNAME, userIdentity.toString());
- context.getClientSession().setNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME, userIdentity.toString());
+ context.getAuthenticationSession().setAuthNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME, userIdentity.toString());
user = getUserIdentityToModelMapper(config).find(context, userIdentity);
}
catch(ModelDuplicateException e) {
@@ -166,7 +166,7 @@ public class X509ClientCertificateAuthenticator extends AbstractX509ClientCertif
// to call the method "challenge" results in a wrong/unexpected behavior.
// The question is whether calling "forceChallenge" here is ok from
// the design viewpoint?
- context.getClientSession().setNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION, context.getExecution().getId());
+ context.getAuthenticationSession().setAuthNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION, context.getExecution().getId());
context.forceChallenge(createSuccessResponse(context, certs[0].getSubjectDN().getName()));
// Do not set the flow status yet, we want to display a form to let users
// choose whether to accept the identity from certificate or to specify username/password explicitly
diff --git a/services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java b/services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java
index d87301f..c8ec6b2 100755
--- a/services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java
+++ b/services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java
@@ -51,7 +51,7 @@ public class DefaultAuthenticationFlow implements AuthenticationFlow {
protected boolean isProcessed(AuthenticationExecutionModel model) {
if (model.isDisabled()) return true;
- ClientSessionModel.ExecutionStatus status = processor.getLoginSession().getExecutionStatus().get(model.getId());
+ ClientSessionModel.ExecutionStatus status = processor.getAuthenticationSession().getExecutionStatus().get(model.getId());
if (status == null) return false;
return status == ClientSessionModel.ExecutionStatus.SUCCESS || status == ClientSessionModel.ExecutionStatus.SKIPPED
|| status == ClientSessionModel.ExecutionStatus.ATTEMPTED
@@ -75,7 +75,7 @@ public class DefaultAuthenticationFlow implements AuthenticationFlow {
AuthenticationFlow authenticationFlow = processor.createFlowExecution(model.getFlowId(), model);
Response flowChallenge = authenticationFlow.processAction(actionExecution);
if (flowChallenge == null) {
- processor.getLoginSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SUCCESS);
+ processor.getAuthenticationSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SUCCESS);
if (model.isAlternative()) alternativeSuccessful = true;
return processFlow();
} else {
@@ -90,9 +90,9 @@ public class DefaultAuthenticationFlow implements AuthenticationFlow {
AuthenticationProcessor.Result result = processor.createAuthenticatorContext(model, authenticator, executions);
logger.debugv("action: {0}", model.getAuthenticator());
authenticator.action(result);
- Response response = processResult(result);
+ Response response = processResult(result, true);
if (response == null) {
- processor.getLoginSession().removeNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION);
+ processor.getAuthenticationSession().removeAuthNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION);
if (result.status == FlowStatus.SUCCESS) {
// we do this so that flow can redirect to a non-action URL
processor.setActionSuccessful();
@@ -119,7 +119,7 @@ public class DefaultAuthenticationFlow implements AuthenticationFlow {
}
if (model.isAlternative() && alternativeSuccessful) {
logger.debug("Skip alternative execution");
- processor.getLoginSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SKIPPED);
+ processor.getAuthenticationSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SKIPPED);
continue;
}
if (model.isAuthenticatorFlow()) {
@@ -127,7 +127,7 @@ public class DefaultAuthenticationFlow implements AuthenticationFlow {
AuthenticationFlow authenticationFlow = processor.createFlowExecution(model.getFlowId(), model);
Response flowChallenge = authenticationFlow.processFlow();
if (flowChallenge == null) {
- processor.getLoginSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SUCCESS);
+ processor.getAuthenticationSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SUCCESS);
if (model.isAlternative()) alternativeSuccessful = true;
continue;
} else {
@@ -135,13 +135,13 @@ public class DefaultAuthenticationFlow implements AuthenticationFlow {
alternativeChallenge = flowChallenge;
challengedAlternativeExecution = model;
} else if (model.isRequired()) {
- processor.getLoginSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
+ processor.getAuthenticationSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
return flowChallenge;
} else if (model.isOptional()) {
- processor.getLoginSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SKIPPED);
+ processor.getAuthenticationSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SKIPPED);
continue;
} else {
- processor.getLoginSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SKIPPED);
+ processor.getAuthenticationSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SKIPPED);
continue;
}
return flowChallenge;
@@ -154,11 +154,11 @@ public class DefaultAuthenticationFlow implements AuthenticationFlow {
}
Authenticator authenticator = factory.create(processor.getSession());
logger.debugv("authenticator: {0}", factory.getId());
- UserModel authUser = processor.getLoginSession().getAuthenticatedUser();
+ UserModel authUser = processor.getAuthenticationSession().getAuthenticatedUser();
if (authenticator.requiresUser() && authUser == null) {
if (alternativeChallenge != null) {
- processor.getLoginSession().setExecutionStatus(challengedAlternativeExecution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
+ processor.getAuthenticationSession().setExecutionStatus(challengedAlternativeExecution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
return alternativeChallenge;
}
throw new AuthenticationFlowException("authenticator: " + factory.getId(), AuthenticationFlowError.UNKNOWN_USER);
@@ -170,14 +170,14 @@ public class DefaultAuthenticationFlow implements AuthenticationFlow {
if (model.isRequired()) {
if (factory.isUserSetupAllowed()) {
logger.debugv("authenticator SETUP_REQUIRED: {0}", factory.getId());
- processor.getLoginSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SETUP_REQUIRED);
- authenticator.setRequiredActions(processor.getSession(), processor.getRealm(), processor.getLoginSession().getAuthenticatedUser());
+ processor.getAuthenticationSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SETUP_REQUIRED);
+ authenticator.setRequiredActions(processor.getSession(), processor.getRealm(), processor.getAuthenticationSession().getAuthenticatedUser());
continue;
} else {
throw new AuthenticationFlowException(AuthenticationFlowError.CREDENTIAL_SETUP_REQUIRED);
}
} else if (model.isOptional()) {
- processor.getLoginSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SKIPPED);
+ processor.getAuthenticationSession().setExecutionStatus(model.getId(), ClientSessionModel.ExecutionStatus.SKIPPED);
continue;
}
}
@@ -189,69 +189,76 @@ public class DefaultAuthenticationFlow implements AuthenticationFlow {
AuthenticationProcessor.Result context = processor.createAuthenticatorContext(model, authenticator, executions);
logger.debug("invoke authenticator.authenticate");
authenticator.authenticate(context);
- Response response = processResult(context);
+ Response response = processResult(context, false);
if (response != null) return response;
}
return null;
}
- public Response processResult(AuthenticationProcessor.Result result) {
+ public Response processResult(AuthenticationProcessor.Result result, boolean isAction) {
AuthenticationExecutionModel execution = result.getExecution();
FlowStatus status = result.getStatus();
switch (status) {
case SUCCESS:
logger.debugv("authenticator SUCCESS: {0}", execution.getAuthenticator());
- processor.getLoginSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.SUCCESS);
+ processor.getAuthenticationSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.SUCCESS);
+
+ // We just do another GET to ensure that page refresh will work
+ if (isAction) {
+ processor.getAuthenticationSession().removeAuthNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION);
+ return processor.redirectToFlow(execution.getId());
+ }
+
if (execution.isAlternative()) alternativeSuccessful = true;
return null;
case FAILED:
logger.debugv("authenticator FAILED: {0}", execution.getAuthenticator());
processor.logFailure();
- processor.getLoginSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.FAILED);
+ processor.getAuthenticationSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.FAILED);
if (result.getChallenge() != null) {
return sendChallenge(result, execution);
}
throw new AuthenticationFlowException(result.getError());
case FORK:
logger.debugv("reset browser login from authenticator: {0}", execution.getAuthenticator());
- processor.getLoginSession().setNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION, execution.getId());
+ processor.getAuthenticationSession().setAuthNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION, execution.getId());
throw new ForkFlowException(result.getSuccessMessage(), result.getErrorMessage());
case FORCE_CHALLENGE:
- processor.getLoginSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
+ processor.getAuthenticationSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
return sendChallenge(result, execution);
case CHALLENGE:
logger.debugv("authenticator CHALLENGE: {0}", execution.getAuthenticator());
if (execution.isRequired()) {
- processor.getLoginSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
+ processor.getAuthenticationSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
return sendChallenge(result, execution);
}
- UserModel authenticatedUser = processor.getLoginSession().getAuthenticatedUser();
+ UserModel authenticatedUser = processor.getAuthenticationSession().getAuthenticatedUser();
if (execution.isOptional() && authenticatedUser != null && result.getAuthenticator().configuredFor(processor.getSession(), processor.getRealm(), authenticatedUser)) {
- processor.getLoginSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
+ processor.getAuthenticationSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
return sendChallenge(result, execution);
}
if (execution.isAlternative()) {
alternativeChallenge = result.getChallenge();
challengedAlternativeExecution = execution;
} else {
- processor.getLoginSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.SKIPPED);
+ processor.getAuthenticationSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.SKIPPED);
}
return null;
case FAILURE_CHALLENGE:
logger.debugv("authenticator FAILURE_CHALLENGE: {0}", execution.getAuthenticator());
processor.logFailure();
- processor.getLoginSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
+ processor.getAuthenticationSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.CHALLENGED);
return sendChallenge(result, execution);
case ATTEMPTED:
logger.debugv("authenticator ATTEMPTED: {0}", execution.getAuthenticator());
if (execution.getRequirement() == AuthenticationExecutionModel.Requirement.REQUIRED) {
throw new AuthenticationFlowException(AuthenticationFlowError.INVALID_CREDENTIALS);
}
- processor.getLoginSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.ATTEMPTED);
+ processor.getAuthenticationSession().setExecutionStatus(execution.getId(), ClientSessionModel.ExecutionStatus.ATTEMPTED);
return null;
case FLOW_RESET:
- AuthenticationProcessor.resetFlow(processor.getLoginSession());
+ AuthenticationProcessor.resetFlow(processor.getAuthenticationSession());
return processor.authenticate();
default:
logger.debugv("authenticator INTERNAL_ERROR: {0}", execution.getAuthenticator());
@@ -261,7 +268,7 @@ public class DefaultAuthenticationFlow implements AuthenticationFlow {
}
public Response sendChallenge(AuthenticationProcessor.Result result, AuthenticationExecutionModel execution) {
- processor.getLoginSession().setNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION, execution.getId());
+ processor.getAuthenticationSession().setAuthNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION, execution.getId());
return result.getChallenge();
}
diff --git a/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java b/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java
index b1d29f1..17898f4 100755
--- a/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java
+++ b/services/src/main/java/org/keycloak/authentication/FormAuthenticationFlow.java
@@ -30,7 +30,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.FormMessage;
import org.keycloak.services.resources.LoginActionsService;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
@@ -94,7 +94,7 @@ public class FormAuthenticationFlow implements AuthenticationFlow {
@Override
public UserModel getUser() {
- return getLoginSession().getAuthenticatedUser();
+ return getAuthenticationSession().getAuthenticatedUser();
}
@Override
@@ -108,8 +108,8 @@ public class FormAuthenticationFlow implements AuthenticationFlow {
}
@Override
- public LoginSessionModel getLoginSession() {
- return processor.getLoginSession();
+ public AuthenticationSessionModel getAuthenticationSession() {
+ return processor.getAuthenticationSession();
}
@Override
@@ -179,7 +179,7 @@ public class FormAuthenticationFlow implements AuthenticationFlow {
FormActionFactory factory = (FormActionFactory)processor.getSession().getKeycloakSessionFactory().getProviderFactory(FormAction.class, formActionExecution.getAuthenticator());
FormAction action = factory.create(processor.getSession());
- UserModel authUser = processor.getLoginSession().getAuthenticatedUser();
+ UserModel authUser = processor.getAuthenticationSession().getAuthenticatedUser();
if (action.requiresUser() && authUser == null) {
throw new AuthenticationFlowException("form action: " + formExecution.getAuthenticator() + " requires user", AuthenticationFlowError.UNKNOWN_USER);
}
@@ -236,14 +236,14 @@ public class FormAuthenticationFlow implements AuthenticationFlow {
}
// set status and required actions only if form is fully successful
for (Map.Entry<String, ClientSessionModel.ExecutionStatus> entry : executionStatus.entrySet()) {
- processor.getLoginSession().setExecutionStatus(entry.getKey(), entry.getValue());
+ processor.getAuthenticationSession().setExecutionStatus(entry.getKey(), entry.getValue());
}
for (FormAction action : requiredActions) {
- action.setRequiredActions(processor.getSession(), processor.getRealm(), processor.getLoginSession().getAuthenticatedUser());
+ action.setRequiredActions(processor.getSession(), processor.getRealm(), processor.getAuthenticationSession().getAuthenticatedUser());
}
- processor.getLoginSession().setExecutionStatus(actionExecution, ClientSessionModel.ExecutionStatus.SUCCESS);
- processor.getLoginSession().removeNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION);
+ processor.getAuthenticationSession().setExecutionStatus(actionExecution, ClientSessionModel.ExecutionStatus.SUCCESS);
+ processor.getAuthenticationSession().removeAuthNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION);
processor.setActionSuccessful();
return null;
}
@@ -263,7 +263,7 @@ public class FormAuthenticationFlow implements AuthenticationFlow {
public Response renderForm(MultivaluedMap<String, String> formData, List<FormMessage> errors) {
String executionId = formExecution.getId();
- processor.getLoginSession().setNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION, executionId);
+ processor.getAuthenticationSession().setAuthNote(AuthenticationProcessor.CURRENT_AUTHENTICATION_EXECUTION, executionId);
String code = processor.generateCode();
URI actionUrl = getActionUrl(executionId, code);
LoginFormsProvider form = processor.getSession().getProvider(LoginFormsProvider.class)
diff --git a/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java b/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java
index ddb42be..ad13212 100755
--- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java
+++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationUserCreation.java
@@ -134,16 +134,16 @@ public class RegistrationUserCreation implements FormAction, FormActionFactory {
user.setEnabled(true);
user.setEmail(email);
- context.getLoginSession().setNote(OIDCLoginProtocol.LOGIN_HINT_PARAM, username);
+ context.getAuthenticationSession().setNote(OIDCLoginProtocol.LOGIN_HINT_PARAM, username);
AttributeFormDataProcessor.process(formData, context.getRealm(), user);
context.setUser(user);
context.getEvent().user(user);
context.getEvent().success();
context.newEvent().event(EventType.LOGIN);
- context.getEvent().client(context.getLoginSession().getClient().getClientId())
- .detail(Details.REDIRECT_URI, context.getLoginSession().getRedirectUri())
- .detail(Details.AUTH_METHOD, context.getLoginSession().getProtocol());
- String authType = context.getLoginSession().getNote(Details.AUTH_TYPE);
+ context.getEvent().client(context.getAuthenticationSession().getClient().getClientId())
+ .detail(Details.REDIRECT_URI, context.getAuthenticationSession().getRedirectUri())
+ .detail(Details.AUTH_METHOD, context.getAuthenticationSession().getProtocol());
+ String authType = context.getAuthenticationSession().getAuthNote(Details.AUTH_TYPE);
if (authType != null) {
context.getEvent().detail(Details.AUTH_TYPE, authType);
}
diff --git a/services/src/main/java/org/keycloak/authentication/RequiredActionContextResult.java b/services/src/main/java/org/keycloak/authentication/RequiredActionContextResult.java
index fd60a9d..87b3403 100755
--- a/services/src/main/java/org/keycloak/authentication/RequiredActionContextResult.java
+++ b/services/src/main/java/org/keycloak/authentication/RequiredActionContextResult.java
@@ -28,7 +28,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.resources.LoginActionsService;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
@@ -39,7 +39,7 @@ import java.net.URI;
* @version $Revision: 1 $
*/
public class RequiredActionContextResult implements RequiredActionContext {
- protected LoginSessionModel loginSession;
+ protected AuthenticationSessionModel authenticationSession;
protected RealmModel realm;
protected EventBuilder eventBuilder;
protected KeycloakSession session;
@@ -49,11 +49,11 @@ public class RequiredActionContextResult implements RequiredActionContext {
protected UserModel user;
protected RequiredActionFactory factory;
- public RequiredActionContextResult(LoginSessionModel loginSession,
+ public RequiredActionContextResult(AuthenticationSessionModel authSession,
RealmModel realm, EventBuilder eventBuilder, KeycloakSession session,
HttpRequest httpRequest,
UserModel user, RequiredActionFactory factory) {
- this.loginSession = loginSession;
+ this.authenticationSession = authSession;
this.realm = realm;
this.eventBuilder = eventBuilder;
this.session = session;
@@ -78,8 +78,8 @@ public class RequiredActionContextResult implements RequiredActionContext {
}
@Override
- public LoginSessionModel getLoginSession() {
- return loginSession;
+ public AuthenticationSessionModel getAuthenticationSession() {
+ return authenticationSession;
}
@Override
@@ -134,14 +134,14 @@ public class RequiredActionContextResult implements RequiredActionContext {
public URI getActionUrl(String code) {
return LoginActionsService.requiredActionProcessor(getUriInfo())
.queryParam(OAuth2Constants.CODE, code)
- .queryParam("action", factory.getId())
+ .queryParam("execution", factory.getId())
.build(getRealm().getName());
}
@Override
public String generateCode() {
- ClientSessionCode<LoginSessionModel> accessCode = new ClientSessionCode<>(session, getRealm(), getLoginSession());
- loginSession.setTimestamp(Time.currentTime());
+ ClientSessionCode<AuthenticationSessionModel> accessCode = new ClientSessionCode<>(session, getRealm(), getAuthenticationSession());
+ authenticationSession.setTimestamp(Time.currentTime());
return accessCode.getCode();
}
diff --git a/services/src/main/java/org/keycloak/authentication/requiredactions/UpdatePassword.java b/services/src/main/java/org/keycloak/authentication/requiredactions/UpdatePassword.java
index 9984e82..5a0e5bf 100755
--- a/services/src/main/java/org/keycloak/authentication/requiredactions/UpdatePassword.java
+++ b/services/src/main/java/org/keycloak/authentication/requiredactions/UpdatePassword.java
@@ -88,8 +88,8 @@ public class UpdatePassword implements RequiredActionProvider, RequiredActionFac
String passwordConfirm = formData.getFirst("password-confirm");
EventBuilder errorEvent = event.clone().event(EventType.UPDATE_PASSWORD_ERROR)
- .client(context.getLoginSession().getClient())
- .user(context.getLoginSession().getAuthenticatedUser());
+ .client(context.getAuthenticationSession().getClient())
+ .user(context.getAuthenticationSession().getAuthenticatedUser());
if (Validation.isBlank(passwordNew)) {
Response challenge = context.form()
diff --git a/services/src/main/java/org/keycloak/authentication/ResetCredentialsActionToken.java b/services/src/main/java/org/keycloak/authentication/ResetCredentialsActionToken.java
index ef92770..4018212 100644
--- a/services/src/main/java/org/keycloak/authentication/ResetCredentialsActionToken.java
+++ b/services/src/main/java/org/keycloak/authentication/ResetCredentialsActionToken.java
@@ -23,6 +23,7 @@ import org.keycloak.common.util.Time;
import org.keycloak.jose.jws.*;
import org.keycloak.models.*;
import org.keycloak.services.Urls;
+import org.keycloak.sessions.AuthenticationSessionModel;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Map;
@@ -42,47 +43,47 @@ public class ResetCredentialsActionToken extends DefaultActionToken {
private static final Logger LOG = Logger.getLogger(ResetCredentialsActionToken.class);
private static final String RESET_CREDENTIALS_ACTION = "reset-credentials";
- public static final String NOTE_CLIENT_SESSION_ID = "clientSessionId";
- private static final String JSON_FIELD_CLIENT_SESSION_ID = "csid";
+ public static final String NOTE_AUTHENTICATION_SESSION_ID = "clientSessionId";
+ private static final String JSON_FIELD_AUTHENTICATION_SESSION_ID = "asid";
private static final String JSON_FIELD_LAST_CHANGE_PASSWORD_TIMESTAMP = "lcpt";
@JsonIgnore
- private ClientSessionModel clientSession;
+ private AuthenticationSessionModel authenticationSession;
@JsonProperty(value = JSON_FIELD_LAST_CHANGE_PASSWORD_TIMESTAMP)
private Long lastChangedPasswordTimestamp;
- public ResetCredentialsActionToken(String userId, int absoluteExpirationInSecs, UUID actionVerificationNonce, Long lastChangedPasswordTimestamp, String clientSessionId) {
+ public ResetCredentialsActionToken(String userId, int absoluteExpirationInSecs, UUID actionVerificationNonce, Long lastChangedPasswordTimestamp, String authenticationSessionId) {
super(userId, RESET_CREDENTIALS_ACTION, absoluteExpirationInSecs, actionVerificationNonce);
- setNote(NOTE_CLIENT_SESSION_ID, clientSessionId);
+ setNote(NOTE_AUTHENTICATION_SESSION_ID, authenticationSessionId);
this.lastChangedPasswordTimestamp = lastChangedPasswordTimestamp;
}
- public ResetCredentialsActionToken(String userId, int absoluteExpirationInSecs, UUID actionVerificationNonce, Long lastChangedPasswordTimestamp, ClientSessionModel clientSession) {
- this(userId, absoluteExpirationInSecs, actionVerificationNonce, lastChangedPasswordTimestamp, clientSession == null ? null : clientSession.getId());
- this.clientSession = clientSession;
+ public ResetCredentialsActionToken(String userId, int absoluteExpirationInSecs, UUID actionVerificationNonce, Long lastChangedPasswordTimestamp, AuthenticationSessionModel authenticationSession) {
+ this(userId, absoluteExpirationInSecs, actionVerificationNonce, lastChangedPasswordTimestamp, authenticationSession == null ? null : authenticationSession.getId());
+ this.authenticationSession = authenticationSession;
}
private ResetCredentialsActionToken() {
super(null, null, -1, null);
}
- public ClientSessionModel getClientSession() {
- return this.clientSession;
+ public AuthenticationSessionModel getAuthenticationSession() {
+ return this.authenticationSession;
}
- public void setClientSession(ClientSessionModel clientSession) {
- this.clientSession = clientSession;
- setClientSessionId(clientSession == null ? null : clientSession.getId());
+ public void setAuthenticationSession(AuthenticationSessionModel authenticationSession) {
+ this.authenticationSession = authenticationSession;
+ setAuthenticationSessionId(authenticationSession == null ? null : authenticationSession.getId());
}
- @JsonProperty(value = JSON_FIELD_CLIENT_SESSION_ID)
- public String getClientSessionId() {
- return getNote(NOTE_CLIENT_SESSION_ID);
+ @JsonProperty(value = JSON_FIELD_AUTHENTICATION_SESSION_ID)
+ public String getAuthenticationSessionId() {
+ return getNote(NOTE_AUTHENTICATION_SESSION_ID);
}
- public void setClientSessionId(String clientSessionId) {
- setNote(NOTE_CLIENT_SESSION_ID, clientSessionId);
+ public void setAuthenticationSessionId(String authenticationSessionId) {
+ setNote(NOTE_AUTHENTICATION_SESSION_ID, authenticationSessionId);
}
public Long getLastChangedPasswordTimestamp() {
@@ -97,8 +98,8 @@ public class ResetCredentialsActionToken extends DefaultActionToken {
@JsonIgnore
public Map<String, String> getNotes() {
Map<String, String> res = super.getNotes();
- if (this.clientSession != null) {
- res.put(NOTE_CLIENT_SESSION_ID, getNote(NOTE_CLIENT_SESSION_ID));
+ if (this.authenticationSession != null) {
+ res.put(NOTE_AUTHENTICATION_SESSION_ID, getNote(NOTE_AUTHENTICATION_SESSION_ID));
}
return res;
}
diff --git a/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java b/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java
index 88d8594..8a7ea61 100644
--- a/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java
+++ b/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java
@@ -38,7 +38,7 @@ import javax.ws.rs.core.Response;
import org.jboss.resteasy.spi.HttpRequest;
import org.keycloak.authorization.AuthorizationProvider;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.authorization.util.Permissions;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.representations.idm.authorization.PolicyEvaluationRequest;
import org.keycloak.authorization.admin.representation.PolicyEvaluationResponseBuilder;
@@ -54,7 +54,7 @@ import org.keycloak.authorization.policy.evaluation.EvaluationContext;
import org.keycloak.authorization.policy.evaluation.Result;
import org.keycloak.authorization.store.ScopeStore;
import org.keycloak.authorization.store.StoreFactory;
-import org.keycloak.authorization.util.Permissions;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
@@ -67,7 +67,7 @@ import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ScopeRepresentation;
import org.keycloak.services.Urls;
import org.keycloak.services.resources.admin.RealmAuth;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
/**
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
@@ -215,7 +215,7 @@ public class PolicyEvaluationService {
String subject = representation.getUserId();
- ClientLoginSessionModel clientSession = null;
+ AuthenticatedClientSessionModel clientSession = null;
UserSessionModel userSession = null;
if (subject != null) {
UserModel userModel = keycloakSession.users().getUserById(subject, realm);
@@ -229,11 +229,11 @@ public class PolicyEvaluationService {
if (clientId != null) {
ClientModel clientModel = realm.getClientById(clientId);
- LoginSessionModel loginSession = keycloakSession.loginSessions().createLoginSession(realm, clientModel, false);
- loginSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
+ AuthenticationSessionModel authSession = keycloakSession.authenticationSessions().createAuthenticationSession(realm, clientModel, false);
+ authSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
userSession = keycloakSession.sessions().createUserSession(realm, userModel, userModel.getUsername(), "127.0.0.1", "passwd", false, null, null);
- new TokenManager().attachLoginSession(keycloakSession, userSession, loginSession);
+ clientSession = new TokenManager().attachAuthenticationSession(keycloakSession, userSession, authSession);
Set<RoleModel> requestedRoles = new HashSet<>();
for (String roleId : clientSession.getRoles()) {
diff --git a/services/src/main/java/org/keycloak/broker/provider/HardcodedUserSessionAttributeMapper.java b/services/src/main/java/org/keycloak/broker/provider/HardcodedUserSessionAttributeMapper.java
index 8409206..1b91f56 100755
--- a/services/src/main/java/org/keycloak/broker/provider/HardcodedUserSessionAttributeMapper.java
+++ b/services/src/main/java/org/keycloak/broker/provider/HardcodedUserSessionAttributeMapper.java
@@ -87,14 +87,14 @@ public class HardcodedUserSessionAttributeMapper extends AbstractIdentityProvide
public void preprocessFederatedIdentity(KeycloakSession session, RealmModel realm, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
String attribute = mapperModel.getConfig().get(ATTRIBUTE);
String attributeValue = mapperModel.getConfig().get(ATTRIBUTE_VALUE);
- context.getLoginSession().setUserSessionNote(attribute, attributeValue);
+ context.getAuthenticationSession().setUserSessionNote(attribute, attributeValue);
}
@Override
public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
String attribute = mapperModel.getConfig().get(ATTRIBUTE);
String attributeValue = mapperModel.getConfig().get(ATTRIBUTE_VALUE);
- context.getLoginSession().setUserSessionNote(attribute, attributeValue);
+ context.getAuthenticationSession().setUserSessionNote(attribute, attributeValue);
}
@Override
diff --git a/services/src/main/java/org/keycloak/forms/login/freemarker/FreeMarkerLoginFormsProvider.java b/services/src/main/java/org/keycloak/forms/login/freemarker/FreeMarkerLoginFormsProvider.java
index b1c0872..b7e6679 100755
--- a/services/src/main/java/org/keycloak/forms/login/freemarker/FreeMarkerLoginFormsProvider.java
+++ b/services/src/main/java/org/keycloak/forms/login/freemarker/FreeMarkerLoginFormsProvider.java
@@ -46,7 +46,7 @@ import org.keycloak.models.UserModel;
import org.keycloak.models.utils.FormMessage;
import org.keycloak.services.Urls;
import org.keycloak.services.messages.Messages;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
import org.keycloak.theme.BrowserSecurityHeaderSetup;
import org.keycloak.theme.FreeMarkerException;
import org.keycloak.theme.FreeMarkerUtil;
@@ -102,7 +102,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
private UserModel user;
- private LoginSessionModel loginSession;
+ private AuthenticationSessionModel authenticationSession;
private final Map<String, Object> attributes = new HashMap<String, Object>();
public FreeMarkerLoginFormsProvider(KeycloakSession session, FreeMarkerUtil freeMarker) {
@@ -141,11 +141,11 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
page = LoginFormsPages.LOGIN_UPDATE_PASSWORD;
break;
case VERIFY_EMAIL:
- // TODO:mposolda It should be also clientSession (actionTicket) involved here. Not just loginSession
+ // TODO:mposolda It should be also clientSession (actionTicket) involved here. Not just authSession
/*try {
UriBuilder builder = Urls.loginActionEmailVerificationBuilder(uriInfo.getBaseUri());
builder.queryParam(OAuth2Constants.CODE, accessCode);
- builder.queryParam(Constants.KEY, loginSession.getNote(Constants.VERIFY_EMAIL_KEY));
+ builder.queryParam(Constants.KEY, authSession.getNote(Constants.VERIFY_EMAIL_KEY));
String link = builder.build(realm.getName()).toString();
long expiration = TimeUnit.SECONDS.toMinutes(realm.getAccessCodeLifespanUserAction());
@@ -187,10 +187,6 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
uriBuilder.replaceQueryParam(k, objects);
}
- if (accessCode != null) {
- uriBuilder.replaceQueryParam(OAuth2Constants.CODE, accessCode);
- }
-
ThemeProvider themeProvider = session.getProvider(ThemeProvider.class, "extending");
Theme theme;
try {
@@ -464,6 +460,11 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
}
@Override
+ public Response createLoginExpiredPage() {
+ return createResponse(LoginFormsPages.LOGIN_PAGE_EXPIRED);
+ }
+
+ @Override
public Response createIdpLinkEmailPage() {
BrokeredIdentityContext brokerContext = (BrokeredIdentityContext) this.attributes.get(IDENTITY_PROVIDER_BROKER_CONTEXT);
String idpAlias = brokerContext.getIdpConfig().getAlias();
@@ -589,8 +590,8 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
}
@Override
- public LoginFormsProvider setLoginSession(LoginSessionModel loginSession) {
- this.loginSession = loginSession;
+ public LoginFormsProvider setAuthenticationSession(AuthenticationSessionModel authSession) {
+ this.authenticationSession = authSession;
return this;
}
diff --git a/services/src/main/java/org/keycloak/forms/login/freemarker/model/UrlBean.java b/services/src/main/java/org/keycloak/forms/login/freemarker/model/UrlBean.java
index a622c22..9b3a9f3 100755
--- a/services/src/main/java/org/keycloak/forms/login/freemarker/model/UrlBean.java
+++ b/services/src/main/java/org/keycloak/forms/login/freemarker/model/UrlBean.java
@@ -50,6 +50,10 @@ public class UrlBean {
return Urls.realmLoginPage(baseURI, realm).toString();
}
+ public String getLoginRestartFlowUrl() {
+ return Urls.realmLoginRestartPage(baseURI, realm).toString();
+ }
+
public String getRegistrationAction() {
if (this.actionuri != null) {
return this.actionuri.toString();
diff --git a/services/src/main/java/org/keycloak/forms/login/freemarker/Templates.java b/services/src/main/java/org/keycloak/forms/login/freemarker/Templates.java
index e28c627..f2a9d75 100755
--- a/services/src/main/java/org/keycloak/forms/login/freemarker/Templates.java
+++ b/services/src/main/java/org/keycloak/forms/login/freemarker/Templates.java
@@ -54,6 +54,8 @@ public class Templates {
return "login-update-profile.ftl";
case CODE:
return "code.ftl";
+ case LOGIN_PAGE_EXPIRED:
+ return "login-page-expired.ftl";
default:
throw new IllegalArgumentException();
}
diff --git a/services/src/main/java/org/keycloak/protocol/AuthorizationEndpointBase.java b/services/src/main/java/org/keycloak/protocol/AuthorizationEndpointBase.java
index f0387e8..e81e9e5 100755
--- a/services/src/main/java/org/keycloak/protocol/AuthorizationEndpointBase.java
+++ b/services/src/main/java/org/keycloak/protocol/AuthorizationEndpointBase.java
@@ -23,14 +23,12 @@ import org.keycloak.common.ClientConnection;
import org.keycloak.events.Details;
import org.keycloak.events.EventBuilder;
import org.keycloak.models.AuthenticationFlowModel;
-import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.protocol.LoginProtocol.Error;
-import org.keycloak.services.ServicesLogger;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.resources.LoginActionsService;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
@@ -64,9 +62,9 @@ public abstract class AuthorizationEndpointBase {
this.event = event;
}
- protected AuthenticationProcessor createProcessor(LoginSessionModel loginSession, String flowId, String flowPath) {
+ protected AuthenticationProcessor createProcessor(AuthenticationSessionModel authSession, String flowId, String flowPath) {
AuthenticationProcessor processor = new AuthenticationProcessor();
- processor.setLoginSession(loginSession)
+ processor.setAuthenticationSession(authSession)
.setFlowPath(flowPath)
.setFlowId(flowId)
.setBrowserFlow(true)
@@ -76,23 +74,26 @@ public abstract class AuthorizationEndpointBase {
.setSession(session)
.setUriInfo(uriInfo)
.setRequest(request);
+
+ authSession.setAuthNote(AuthenticationProcessor.CURRENT_FLOW_PATH, flowPath);
+
return processor;
}
/**
* Common method to handle browser authentication request in protocols unified way.
*
- * @param loginSession for current request
+ * @param authSession for current request
* @param protocol handler for protocol used to initiate login
* @param isPassive set to true if login should be passive (without login screen shown)
* @param redirectToAuthentication if true redirect to flow url. If initial call to protocol is a POST, you probably want to do this. This is so we can disable the back button on browser
* @return response to be returned to the browser
*/
- protected Response handleBrowserAuthenticationRequest(LoginSessionModel loginSession, LoginProtocol protocol, boolean isPassive, boolean redirectToAuthentication) {
+ protected Response handleBrowserAuthenticationRequest(AuthenticationSessionModel authSession, LoginProtocol protocol, boolean isPassive, boolean redirectToAuthentication) {
AuthenticationFlowModel flow = getAuthenticationFlow();
String flowId = flow.getId();
- AuthenticationProcessor processor = createProcessor(loginSession, flowId, LoginActionsService.AUTHENTICATE_PATH);
- event.detail(Details.CODE_ID, loginSession.getId());
+ AuthenticationProcessor processor = createProcessor(authSession, flowId, LoginActionsService.AUTHENTICATE_PATH);
+ event.detail(Details.CODE_ID, authSession.getId());
if (isPassive) {
// OIDC prompt == NONE or SAML 2 IsPassive flag
// This means that client is just checking if the user is already completely logged in.
@@ -101,13 +102,16 @@ public abstract class AuthorizationEndpointBase {
if (processor.authenticateOnly() == null) {
// processor.attachSession();
} else {
- Response response = protocol.sendError(loginSession, Error.PASSIVE_LOGIN_REQUIRED);
- session.loginSessions().removeLoginSession(realm, loginSession);
+ Response response = protocol.sendError(authSession, Error.PASSIVE_LOGIN_REQUIRED);
+ session.authenticationSessions().removeAuthenticationSession(realm, authSession);
return response;
}
+
+ AuthenticationManager.setRolesAndMappersInSession(authSession);
+
if (processor.isActionRequired()) {
- Response response = protocol.sendError(loginSession, Error.PASSIVE_INTERACTION_REQUIRED);
- session.loginSessions().removeLoginSession(realm, loginSession);
+ Response response = protocol.sendError(authSession, Error.PASSIVE_INTERACTION_REQUIRED);
+ session.authenticationSessions().removeAuthenticationSession(realm, authSession);
return response;
}
@@ -119,10 +123,9 @@ public abstract class AuthorizationEndpointBase {
return processor.finishAuthentication(protocol);
} else {
try {
- // TODO: Check if this is required...
- RestartLoginCookie.setRestartCookie(session, realm, clientConnection, uriInfo, loginSession);
+ RestartLoginCookie.setRestartCookie(session, realm, clientConnection, uriInfo, authSession);
if (redirectToAuthentication) {
- return processor.redirectToFlow();
+ return processor.redirectToFlow(null);
}
return processor.authenticate();
} catch (Exception e) {
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
index 3a41f92..6691712 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
@@ -44,7 +44,7 @@ import org.keycloak.services.Urls;
import org.keycloak.services.messages.Messages;
import org.keycloak.services.resources.LoginActionsService;
import org.keycloak.services.util.CacheControlUtil;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
import org.keycloak.util.TokenUtil;
import javax.ws.rs.GET;
@@ -64,10 +64,10 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
public static final String CODE_AUTH_TYPE = "code";
/**
- * Prefix used to store additional HTTP GET params from original client request into {@link LoginSessionModel} note to be available later in Authenticators, RequiredActions etc. Prefix is used to
+ * Prefix used to store additional HTTP GET params from original client request into {@link AuthenticationSessionModel} note to be available later in Authenticators, RequiredActions etc. Prefix is used to
* prevent collisions with internally used notes.
*
- * @see LoginSessionModel#getNote(String)
+ * @see AuthenticationSessionModel#getNote(String)
*/
public static final String LOGIN_SESSION_NOTE_ADDITIONAL_REQ_PARAMS_PREFIX = "client_request_param_";
@@ -79,7 +79,7 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
}
private ClientModel client;
- private LoginSessionModel loginSession;
+ private AuthenticationSessionModel authenticationSession;
private Action action;
private OIDCResponseType parsedResponseType;
@@ -359,22 +359,22 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
}
private void createLoginSession() {
- loginSession = session.loginSessions().createLoginSession(realm, client, true);
- loginSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
- loginSession.setRedirectUri(redirectUri);
- loginSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
- loginSession.setNote(OIDCLoginProtocol.RESPONSE_TYPE_PARAM, request.getResponseType());
- loginSession.setNote(OIDCLoginProtocol.REDIRECT_URI_PARAM, request.getRedirectUriParam());
- loginSession.setNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()));
-
- if (request.getState() != null) loginSession.setNote(OIDCLoginProtocol.STATE_PARAM, request.getState());
- if (request.getNonce() != null) loginSession.setNote(OIDCLoginProtocol.NONCE_PARAM, request.getNonce());
- if (request.getMaxAge() != null) loginSession.setNote(OIDCLoginProtocol.MAX_AGE_PARAM, String.valueOf(request.getMaxAge()));
- if (request.getScope() != null) loginSession.setNote(OIDCLoginProtocol.SCOPE_PARAM, request.getScope());
- if (request.getLoginHint() != null) loginSession.setNote(OIDCLoginProtocol.LOGIN_HINT_PARAM, request.getLoginHint());
- if (request.getPrompt() != null) loginSession.setNote(OIDCLoginProtocol.PROMPT_PARAM, request.getPrompt());
- if (request.getIdpHint() != null) loginSession.setNote(AdapterConstants.KC_IDP_HINT, request.getIdpHint());
- if (request.getResponseMode() != null) loginSession.setNote(OIDCLoginProtocol.RESPONSE_MODE_PARAM, request.getResponseMode());
+ authenticationSession = session.authenticationSessions().createAuthenticationSession(realm, client, true);
+ authenticationSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
+ authenticationSession.setRedirectUri(redirectUri);
+ authenticationSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
+ authenticationSession.setNote(OIDCLoginProtocol.RESPONSE_TYPE_PARAM, request.getResponseType());
+ authenticationSession.setNote(OIDCLoginProtocol.REDIRECT_URI_PARAM, request.getRedirectUriParam());
+ authenticationSession.setNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()));
+
+ if (request.getState() != null) authenticationSession.setNote(OIDCLoginProtocol.STATE_PARAM, request.getState());
+ if (request.getNonce() != null) authenticationSession.setNote(OIDCLoginProtocol.NONCE_PARAM, request.getNonce());
+ if (request.getMaxAge() != null) authenticationSession.setNote(OIDCLoginProtocol.MAX_AGE_PARAM, String.valueOf(request.getMaxAge()));
+ if (request.getScope() != null) authenticationSession.setNote(OIDCLoginProtocol.SCOPE_PARAM, request.getScope());
+ if (request.getLoginHint() != null) authenticationSession.setNote(OIDCLoginProtocol.LOGIN_HINT_PARAM, request.getLoginHint());
+ if (request.getPrompt() != null) authenticationSession.setNote(OIDCLoginProtocol.PROMPT_PARAM, request.getPrompt());
+ if (request.getIdpHint() != null) authenticationSession.setNote(AdapterConstants.KC_IDP_HINT, request.getIdpHint());
+ if (request.getResponseMode() != null) authenticationSession.setNote(OIDCLoginProtocol.RESPONSE_MODE_PARAM, request.getResponseMode());
// https://tools.ietf.org/html/rfc7636#section-4
if (request.getCodeChallenge() != null) loginSession.setNote(OIDCLoginProtocol.CODE_CHALLENGE_PARAM, request.getCodeChallenge());
@@ -386,16 +386,16 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
if (request.getAdditionalReqParams() != null) {
for (String paramName : request.getAdditionalReqParams().keySet()) {
- loginSession.setNote(LOGIN_SESSION_NOTE_ADDITIONAL_REQ_PARAMS_PREFIX + paramName, request.getAdditionalReqParams().get(paramName));
+ authenticationSession.setNote(LOGIN_SESSION_NOTE_ADDITIONAL_REQ_PARAMS_PREFIX + paramName, request.getAdditionalReqParams().get(paramName));
}
}
}
private Response buildAuthorizationCodeAuthorizationResponse() {
this.event.event(EventType.LOGIN);
- loginSession.setNote(Details.AUTH_TYPE, CODE_AUTH_TYPE);
+ authenticationSession.setAuthNote(Details.AUTH_TYPE, CODE_AUTH_TYPE);
- return handleBrowserAuthenticationRequest(loginSession, new OIDCLoginProtocol(session, realm, uriInfo, headers, event), TokenUtil.hasPrompt(request.getPrompt(), OIDCLoginProtocol.PROMPT_VALUE_NONE), false);
+ return handleBrowserAuthenticationRequest(authenticationSession, new OIDCLoginProtocol(session, realm, uriInfo, headers, event), TokenUtil.hasPrompt(request.getPrompt(), OIDCLoginProtocol.PROMPT_VALUE_NONE), false);
}
private Response buildRegister() {
@@ -404,7 +404,7 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
AuthenticationFlowModel flow = realm.getRegistrationFlow();
String flowId = flow.getId();
- AuthenticationProcessor processor = createProcessor(loginSession, flowId, LoginActionsService.REGISTRATION_PATH);
+ AuthenticationProcessor processor = createProcessor(authenticationSession, flowId, LoginActionsService.REGISTRATION_PATH);
return processor.authenticate();
}
@@ -415,7 +415,7 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
AuthenticationFlowModel flow = realm.getResetCredentialsFlow();
String flowId = flow.getId();
- AuthenticationProcessor processor = createProcessor(loginSession, flowId, LoginActionsService.RESET_CREDENTIALS_PATH);
+ AuthenticationProcessor processor = createProcessor(authenticationSession, flowId, LoginActionsService.RESET_CREDENTIALS_PATH);
return processor.authenticate();
}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
index e308bc9..2a6c2dc 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
@@ -32,7 +32,7 @@ import org.keycloak.events.Errors;
import org.keycloak.events.EventBuilder;
import org.keycloak.events.EventType;
import org.keycloak.models.AuthenticationFlowModel;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
@@ -51,7 +51,7 @@ import org.keycloak.services.managers.ClientManager;
import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.resources.Cors;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.POST;
@@ -174,6 +174,8 @@ public class TokenEndpoint {
if (client.isBearerOnly()) {
throw new ErrorResponseException(OAuthErrorException.INVALID_CLIENT, "Bearer-only not allowed", Response.Status.BAD_REQUEST);
}
+
+
}
private void checkGrantType() {
@@ -207,8 +209,8 @@ public class TokenEndpoint {
throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Missing parameter: " + OAuth2Constants.CODE, Response.Status.BAD_REQUEST);
}
- ClientSessionCode.ParseResult<ClientLoginSessionModel> parseResult = ClientSessionCode.parseResult(code, session, realm, ClientLoginSessionModel.class);
- if (parseResult.isLoginSessionNotFound() || parseResult.isIllegalHash()) {
+ ClientSessionCode.ParseResult<AuthenticatedClientSessionModel> parseResult = ClientSessionCode.parseResult(code, session, realm, AuthenticatedClientSessionModel.class);
+ if (parseResult.isAuthSessionNotFound() || parseResult.isIllegalHash()) {
String[] parts = code.split("\\.");
if (parts.length == 2) {
event.detail(Details.CODE_ID, parts[1]);
@@ -216,20 +218,18 @@ public class TokenEndpoint {
event.error(Errors.INVALID_CODE);
// Attempt to use same code twice should invalidate existing clientSession
- ClientLoginSessionModel clientSession = parseResult.getClientSession();
+ AuthenticatedClientSessionModel clientSession = parseResult.getClientSession();
if (clientSession != null) {
- UserSessionModel userSession = clientSession.getUserSession();
- String clientUUID = clientSession.getClient().getId();
- userSession.getClientLoginSessions().remove(clientUUID);
+ clientSession.setUserSession(null);
}
throw new ErrorResponseException(OAuthErrorException.INVALID_GRANT, "Code not valid", Response.Status.BAD_REQUEST);
}
- ClientLoginSessionModel clientSession = parseResult.getClientSession();
+ AuthenticatedClientSessionModel clientSession = parseResult.getClientSession();
event.detail(Details.CODE_ID, clientSession.getId());
- if (!parseResult.getCode().isValid(ClientLoginSessionModel.Action.CODE_TO_TOKEN.name(), ClientSessionCode.ActionType.CLIENT)) {
+ if (!parseResult.getCode().isValid(AuthenticatedClientSessionModel.Action.CODE_TO_TOKEN.name(), ClientSessionCode.ActionType.CLIENT)) {
event.error(Errors.INVALID_CODE);
throw new ErrorResponseException(OAuthErrorException.INVALID_GRANT, "Code is expired", Response.Status.BAD_REQUEST);
}
@@ -362,7 +362,7 @@ public class TokenEndpoint {
if (!result.isOfflineToken()) {
UserSessionModel userSession = session.sessions().getUserSession(realm, res.getSessionState());
- ClientLoginSessionModel clientSession = userSession.getClientLoginSessions().get(client.getId());
+ AuthenticatedClientSessionModel clientSession = userSession.getAuthenticatedClientSessions().get(client.getId());
updateClientSession(clientSession);
updateUserSessionFromClientAuth(userSession);
}
@@ -377,7 +377,7 @@ public class TokenEndpoint {
return Cors.add(request, Response.ok(res, MediaType.APPLICATION_JSON_TYPE)).auth().allowedOrigins(uriInfo, client).allowedMethods("POST").exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build();
}
- private void updateClientSession(ClientLoginSessionModel clientSession) {
+ private void updateClientSession(AuthenticatedClientSessionModel clientSession) {
if(clientSession == null) {
ServicesLogger.LOGGER.clientSessionNull();
@@ -416,16 +416,16 @@ public class TokenEndpoint {
}
String scope = formParams.getFirst(OAuth2Constants.SCOPE);
- LoginSessionModel loginSession = session.loginSessions().createLoginSession(realm, client, false);
- loginSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
- loginSession.setAction(ClientLoginSessionModel.Action.AUTHENTICATE.name());
- loginSession.setNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()));
- loginSession.setNote(OIDCLoginProtocol.SCOPE_PARAM, scope);
+ AuthenticationSessionModel authSession = session.authenticationSessions().createAuthenticationSession(realm, client, false);
+ authSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
+ authSession.setAction(AuthenticatedClientSessionModel.Action.AUTHENTICATE.name());
+ authSession.setNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()));
+ authSession.setNote(OIDCLoginProtocol.SCOPE_PARAM, scope);
AuthenticationFlowModel flow = realm.getDirectGrantFlow();
String flowId = flow.getId();
AuthenticationProcessor processor = new AuthenticationProcessor();
- processor.setLoginSession(loginSession)
+ processor.setAuthenticationSession(authSession)
.setFlowId(flowId)
.setConnection(clientConnection)
.setEventBuilder(event)
@@ -436,13 +436,13 @@ public class TokenEndpoint {
Response challenge = processor.authenticateOnly();
if (challenge != null) return challenge;
processor.evaluateRequiredActionTriggers();
- UserModel user = loginSession.getAuthenticatedUser();
+ UserModel user = authSession.getAuthenticatedUser();
if (user.getRequiredActions() != null && user.getRequiredActions().size() > 0) {
event.error(Errors.RESOLVE_REQUIRED_ACTIONS);
throw new ErrorResponseException(OAuthErrorException.INVALID_GRANT, "Account is not fully set up", Response.Status.BAD_REQUEST);
}
- ClientLoginSessionModel clientSession = processor.attachSession();
+ AuthenticatedClientSessionModel clientSession = processor.attachSession();
UserSessionModel userSession = processor.getUserSession();
updateUserSessionFromClientAuth(userSession);
@@ -492,15 +492,15 @@ public class TokenEndpoint {
String scope = formParams.getFirst(OAuth2Constants.SCOPE);
- LoginSessionModel loginSession = session.loginSessions().createLoginSession(realm, client, false);
- loginSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
- loginSession.setNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()));
- loginSession.setNote(OIDCLoginProtocol.SCOPE_PARAM, scope);
+ AuthenticationSessionModel authSession = session.authenticationSessions().createAuthenticationSession(realm, client, false);
+ authSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
+ authSession.setNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()));
+ authSession.setNote(OIDCLoginProtocol.SCOPE_PARAM, scope);
UserSessionModel userSession = session.sessions().createUserSession(realm, clientUser, clientUsername, clientConnection.getRemoteAddr(), ServiceAccountConstants.CLIENT_AUTH, false, null, null);
event.session(userSession);
- ClientLoginSessionModel clientSession = TokenManager.attachLoginSession(session, userSession, loginSession);
+ AuthenticatedClientSessionModel clientSession = TokenManager.attachAuthenticationSession(session, userSession, authSession);
// Notes about client details
userSession.setNote(ServiceAccountConstants.CLIENT_ID, client.getClientId());
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java
index 763da1e..f2d6f60 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java
@@ -29,7 +29,7 @@ import org.keycloak.events.EventBuilder;
import org.keycloak.events.EventType;
import org.keycloak.jose.jws.Algorithm;
import org.keycloak.jose.jws.JWSBuilder;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.KeycloakSession;
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/AbstractOIDCProtocolMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/AbstractOIDCProtocolMapper.java
index d439343..d267f91 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/AbstractOIDCProtocolMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/AbstractOIDCProtocolMapper.java
@@ -18,7 +18,7 @@
package org.keycloak.protocol.oidc.mappers;
import org.keycloak.Config;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.ProtocolMapperModel;
@@ -61,7 +61,7 @@ public abstract class AbstractOIDCProtocolMapper implements ProtocolMapper {
}
public AccessToken transformUserInfoToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
- UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
if (!OIDCAttributeMapperHelper.includeInUserInfo(mappingModel)) {
return token;
@@ -72,7 +72,7 @@ public abstract class AbstractOIDCProtocolMapper implements ProtocolMapper {
}
public AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
- UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
if (!OIDCAttributeMapperHelper.includeInAccessToken(mappingModel)){
return token;
@@ -83,7 +83,7 @@ public abstract class AbstractOIDCProtocolMapper implements ProtocolMapper {
}
public IDToken transformIDToken(IDToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
- UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
if (!OIDCAttributeMapperHelper.includeInIDToken(mappingModel)){
return token;
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/AbstractPairwiseSubMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/AbstractPairwiseSubMapper.java
index 4b8b1f3..09b39c4 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/AbstractPairwiseSubMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/AbstractPairwiseSubMapper.java
@@ -1,6 +1,6 @@
package org.keycloak.protocol.oidc.mappers;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperContainerModel;
@@ -64,19 +64,19 @@ public abstract class AbstractPairwiseSubMapper extends AbstractOIDCProtocolMapp
}
@Override
- public final IDToken transformIDToken(IDToken token, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ public final IDToken transformIDToken(IDToken token, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
setSubject(token, generateSub(mappingModel, getSectorIdentifier(clientSession.getClient(), mappingModel), userSession.getUser().getId()));
return token;
}
@Override
- public final AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ public final AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
setSubject(token, generateSub(mappingModel, getSectorIdentifier(clientSession.getClient(), mappingModel), userSession.getUser().getId()));
return token;
}
@Override
- public final AccessToken transformUserInfoToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ public final AccessToken transformUserInfoToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
setSubject(token, generateSub(mappingModel, getSectorIdentifier(clientSession.getClient(), mappingModel), userSession.getUser().getId()));
return token;
}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedRole.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedRole.java
index 7ebb435..19ff925 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedRole.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedRole.java
@@ -17,7 +17,7 @@
package org.keycloak.protocol.oidc.mappers;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.UserSessionModel;
@@ -82,7 +82,7 @@ public class HardcodedRole extends AbstractOIDCProtocolMapper implements OIDCAcc
@Override
public AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
- UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
String role = mappingModel.getConfig().get(ROLE_CONFIG);
String[] scopedRole = KeycloakModelUtils.parseRole(role);
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAccessTokenMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAccessTokenMapper.java
index 387ef5c..e7e0b7b 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAccessTokenMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAccessTokenMapper.java
@@ -17,7 +17,7 @@
package org.keycloak.protocol.oidc.mappers;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.UserSessionModel;
@@ -30,5 +30,5 @@ import org.keycloak.representations.AccessToken;
public interface OIDCAccessTokenMapper {
AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
- UserSessionModel userSession, ClientLoginSessionModel clientSession);
+ UserSessionModel userSession, AuthenticatedClientSessionModel clientSession);
}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCIDTokenMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCIDTokenMapper.java
index ca80ed5..54f380b 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCIDTokenMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCIDTokenMapper.java
@@ -17,7 +17,7 @@
package org.keycloak.protocol.oidc.mappers;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.UserSessionModel;
@@ -30,5 +30,5 @@ import org.keycloak.representations.IDToken;
public interface OIDCIDTokenMapper {
IDToken transformIDToken(IDToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
- UserSessionModel userSession, ClientLoginSessionModel clientSession);
+ UserSessionModel userSession, AuthenticatedClientSessionModel clientSession);
}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/RoleNameMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/RoleNameMapper.java
index c910400..d41063b 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/RoleNameMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/RoleNameMapper.java
@@ -17,7 +17,7 @@
package org.keycloak.protocol.oidc.mappers;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.UserSessionModel;
@@ -89,7 +89,7 @@ public class RoleNameMapper extends AbstractOIDCProtocolMapper implements OIDCAc
@Override
public AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
- UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
String role = mappingModel.getConfig().get(ROLE_CONFIG);
String newName = mappingModel.getConfig().get(NEW_ROLE_NAME);
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserInfoTokenMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserInfoTokenMapper.java
index af5084c..e1fc17e 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserInfoTokenMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserInfoTokenMapper.java
@@ -17,7 +17,7 @@
package org.keycloak.protocol.oidc.mappers;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.UserSessionModel;
@@ -29,5 +29,5 @@ import org.keycloak.representations.AccessToken;
public interface UserInfoTokenMapper {
AccessToken transformUserInfoToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
- UserSessionModel userSession, ClientLoginSessionModel clientSession);
+ UserSessionModel userSession, AuthenticatedClientSessionModel clientSession);
}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
index 5dd0433..59b7835 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
@@ -23,7 +23,7 @@ import org.keycloak.common.util.Time;
import org.keycloak.events.Details;
import org.keycloak.events.EventBuilder;
import org.keycloak.events.EventType;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
@@ -39,7 +39,7 @@ import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.managers.ResourceAdminManager;
import org.keycloak.sessions.CommonClientSessionModel;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
import org.keycloak.util.TokenUtil;
import javax.ws.rs.core.HttpHeaders;
@@ -171,8 +171,8 @@ public class OIDCLoginProtocol implements LoginProtocol {
@Override
- public Response authenticated(UserSessionModel userSession, ClientSessionCode<ClientLoginSessionModel> accessCode) {
- ClientLoginSessionModel clientSession = accessCode.getClientSession();
+ public Response authenticated(UserSessionModel userSession, ClientSessionCode<AuthenticatedClientSessionModel> accessCode) {
+ AuthenticatedClientSessionModel clientSession = accessCode.getClientSession();
setupResponseTypeAndMode(clientSession);
String redirect = clientSession.getRedirectUri();
@@ -229,15 +229,15 @@ public class OIDCLoginProtocol implements LoginProtocol {
@Override
- public Response sendError(LoginSessionModel loginSession, Error error) {
- setupResponseTypeAndMode(loginSession);
+ public Response sendError(AuthenticationSessionModel authSession, Error error) {
+ setupResponseTypeAndMode(authSession);
- String redirect = loginSession.getRedirectUri();
- String state = loginSession.getNote(OIDCLoginProtocol.STATE_PARAM);
+ String redirect = authSession.getRedirectUri();
+ String state = authSession.getNote(OIDCLoginProtocol.STATE_PARAM);
OIDCRedirectUriBuilder redirectUri = OIDCRedirectUriBuilder.fromUri(redirect, responseMode).addParam(OAuth2Constants.ERROR, translateError(error));
if (state != null)
redirectUri.addParam(OAuth2Constants.STATE, state);
- session.loginSessions().removeLoginSession(realm, loginSession);
+ session.authenticationSessions().removeAuthenticationSession(realm, authSession);
RestartLoginCookie.expireRestartCookie(realm, session.getContext().getConnection(), uriInfo);
return redirectUri.build();
}
@@ -258,13 +258,13 @@ public class OIDCLoginProtocol implements LoginProtocol {
}
@Override
- public void backchannelLogout(UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ public void backchannelLogout(UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
ClientModel client = clientSession.getClient();
new ResourceAdminManager(session).logoutClientSession(uriInfo.getRequestUri(), realm, client, clientSession);
}
@Override
- public Response frontchannelLogout(UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ public Response frontchannelLogout(UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
// todo oidc redirect support
throw new RuntimeException("NOT IMPLEMENTED");
}
@@ -291,18 +291,18 @@ public class OIDCLoginProtocol implements LoginProtocol {
@Override
- public boolean requireReauthentication(UserSessionModel userSession, LoginSessionModel loginSession) {
- return isPromptLogin(loginSession) || isAuthTimeExpired(userSession, loginSession);
+ public boolean requireReauthentication(UserSessionModel userSession, AuthenticationSessionModel authSession) {
+ return isPromptLogin(authSession) || isAuthTimeExpired(userSession, authSession);
}
- protected boolean isPromptLogin(LoginSessionModel loginSession) {
- String prompt = loginSession.getNote(OIDCLoginProtocol.PROMPT_PARAM);
+ protected boolean isPromptLogin(AuthenticationSessionModel authSession) {
+ String prompt = authSession.getNote(OIDCLoginProtocol.PROMPT_PARAM);
return TokenUtil.hasPrompt(prompt, OIDCLoginProtocol.PROMPT_VALUE_LOGIN);
}
- protected boolean isAuthTimeExpired(UserSessionModel userSession, LoginSessionModel loginSession) {
+ protected boolean isAuthTimeExpired(UserSessionModel userSession, AuthenticationSessionModel authSession) {
String authTime = userSession.getNote(AuthenticationManager.AUTH_TIME);
- String maxAge = loginSession.getNote(OIDCLoginProtocol.MAX_AGE_PARAM);
+ String maxAge = authSession.getNote(OIDCLoginProtocol.MAX_AGE_PARAM);
if (maxAge == null) {
return false;
}
@@ -312,7 +312,7 @@ public class OIDCLoginProtocol implements LoginProtocol {
if (authTimeInt + maxAgeInt < Time.currentTime()) {
logger.debugf("Authentication time is expired, needs to reauthenticate. userSession=%s, clientId=%s, maxAge=%d, authTime=%d", userSession.getId(),
- loginSession.getClient().getId(), maxAgeInt, authTimeInt);
+ authSession.getClient().getId(), maxAgeInt, authTimeInt);
return true;
}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
index 49a47a1..cd7c65c 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
@@ -31,9 +31,8 @@ import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.JWSInputException;
import org.keycloak.jose.jws.crypto.HashProvider;
import org.keycloak.jose.jws.crypto.RSAProvider;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
-import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.ClientTemplateModel;
import org.keycloak.models.GroupModel;
import org.keycloak.models.KeyManager;
@@ -60,7 +59,7 @@ import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.managers.UserSessionManager;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
import org.keycloak.util.TokenUtil;
import org.keycloak.common.util.Time;
@@ -108,10 +107,10 @@ public class TokenManager {
public static class TokenValidation {
public final UserModel user;
public final UserSessionModel userSession;
- public final ClientLoginSessionModel clientSession;
+ public final AuthenticatedClientSessionModel clientSession;
public final AccessToken newToken;
- public TokenValidation(UserModel user, UserSessionModel userSession, ClientLoginSessionModel clientSession, AccessToken newToken) {
+ public TokenValidation(UserModel user, UserSessionModel userSession, AuthenticatedClientSessionModel clientSession, AccessToken newToken) {
this.user = user;
this.userSession = userSession;
this.clientSession = clientSession;
@@ -157,7 +156,7 @@ public class TokenManager {
}
ClientModel client = session.getContext().getClient();
- ClientLoginSessionModel clientSession = userSession.getClientLoginSessions().get(client.getId());
+ AuthenticatedClientSessionModel clientSession = userSession.getAuthenticatedClientSessions().get(client.getId());
if (!client.getClientId().equals(oldToken.getIssuedFor())) {
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Unmatching clients", "Unmatching clients");
@@ -218,7 +217,7 @@ public class TokenManager {
return false;
}
- ClientLoginSessionModel clientSession = userSession.getClientLoginSessions().get(client.getId());
+ AuthenticatedClientSessionModel clientSession = userSession.getAuthenticatedClientSessions().get(client.getId());
if (clientSession == null) {
return false;
>>>>>>> KEYCLOAK-4626 AuthenticationSessions: start
@@ -346,7 +345,7 @@ public class TokenManager {
}
public AccessToken createClientAccessToken(KeycloakSession session, Set<RoleModel> requestedRoles, RealmModel realm, ClientModel client, UserModel user, UserSessionModel userSession,
- ClientLoginSessionModel clientSession) {
+ AuthenticatedClientSessionModel clientSession) {
AccessToken token = initToken(realm, client, user, userSession, clientSession, session.getContext().getUri());
for (RoleModel role : requestedRoles) {
addComposites(token, role);
@@ -355,68 +354,45 @@ public class TokenManager {
return token;
}
- public static ClientLoginSessionModel attachLoginSession(KeycloakSession session, UserSessionModel userSession, LoginSessionModel loginSession) {
- UserModel user = userSession.getUser();
- ClientModel client = loginSession.getClient();
- ClientLoginSessionModel clientSession = session.sessions().createClientSession(userSession.getRealm(), client, userSession);
-
- Set<String> requestedRoles = new HashSet<String>();
- // todo scope param protocol independent
- String scopeParam = loginSession.getNote(OAuth2Constants.SCOPE);
- for (RoleModel r : TokenManager.getAccess(scopeParam, true, client, user)) {
- requestedRoles.add(r.getId());
- }
- clientSession.setRoles(requestedRoles);
-
- Set<String> requestedProtocolMappers = new HashSet<String>();
- ClientTemplateModel clientTemplate = client.getClientTemplate();
- if (clientTemplate != null && client.useTemplateMappers()) {
- for (ProtocolMapperModel protocolMapper : clientTemplate.getProtocolMappers()) {
- if (protocolMapper.getProtocol().equals(loginSession.getProtocol())) {
- requestedProtocolMappers.add(protocolMapper.getId());
- }
- }
- }
- for (ProtocolMapperModel protocolMapper : client.getProtocolMappers()) {
- if (protocolMapper.getProtocol().equals(loginSession.getProtocol())) {
- requestedProtocolMappers.add(protocolMapper.getId());
- }
- }
- clientSession.setProtocolMappers(requestedProtocolMappers);
+ public static AuthenticatedClientSessionModel attachAuthenticationSession(KeycloakSession session, UserSessionModel userSession, AuthenticationSessionModel authSession) {
+ ClientModel client = authSession.getClient();
+
+ AuthenticatedClientSessionModel clientSession = session.sessions().createClientSession(userSession.getRealm(), client, userSession);
+ clientSession.setRedirectUri(authSession.getRedirectUri());
+ clientSession.setProtocol(authSession.getProtocol());
- Map<String, String> transferredNotes = loginSession.getNotes();
+ clientSession.setRoles(authSession.getRoles());
+ clientSession.setProtocolMappers(authSession.getProtocolMappers());
+
+ Map<String, String> transferredNotes = authSession.getNotes();
for (Map.Entry<String, String> entry : transferredNotes.entrySet()) {
clientSession.setNote(entry.getKey(), entry.getValue());
}
- Map<String, String> transferredUserSessionNotes = loginSession.getUserSessionNotes();
+ Map<String, String> transferredUserSessionNotes = authSession.getUserSessionNotes();
for (Map.Entry<String, String> entry : transferredUserSessionNotes.entrySet()) {
userSession.setNote(entry.getKey(), entry.getValue());
}
clientSession.setTimestamp(Time.currentTime());
- userSession.getClientLoginSessions().put(client.getId(), clientSession);
-
- // Remove login session now
- session.loginSessions().removeLoginSession(userSession.getRealm(), loginSession);
+ // Remove authentication session now
+ session.authenticationSessions().removeAuthenticationSession(userSession.getRealm(), authSession);
return clientSession;
}
- public static void dettachClientSession(UserSessionProvider sessions, RealmModel realm, ClientLoginSessionModel clientSession) {
+ public static void dettachClientSession(UserSessionProvider sessions, RealmModel realm, AuthenticatedClientSessionModel clientSession) {
UserSessionModel userSession = clientSession.getUserSession();
if (userSession == null) {
return;
}
clientSession.setUserSession(null);
- clientSession.setRoles(null);
- clientSession.setProtocolMappers(null);
- if (userSession.getClientSessions().isEmpty()) {
+ if (userSession.getAuthenticatedClientSessions().isEmpty()) {
sessions.removeUserSession(realm, userSession);
}
}
@@ -550,7 +526,7 @@ public class TokenManager {
}
public AccessToken transformAccessToken(KeycloakSession session, AccessToken token, RealmModel realm, ClientModel client, UserModel user,
- UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
Set<ProtocolMapperModel> mappings = ClientSessionCode.getRequestedProtocolMappers(clientSession.getProtocolMappers(), client);
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
for (ProtocolMapperModel mapping : mappings) {
@@ -565,7 +541,7 @@ public class TokenManager {
}
public AccessToken transformUserInfoAccessToken(KeycloakSession session, AccessToken token, RealmModel realm, ClientModel client, UserModel user,
- UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
Set<ProtocolMapperModel> mappings = ClientSessionCode.getRequestedProtocolMappers(clientSession.getProtocolMappers(), client);
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
for (ProtocolMapperModel mapping : mappings) {
@@ -580,7 +556,7 @@ public class TokenManager {
}
public void transformIDToken(KeycloakSession session, IDToken token, RealmModel realm, ClientModel client, UserModel user,
- UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
Set<ProtocolMapperModel> mappings = ClientSessionCode.getRequestedProtocolMappers(clientSession.getProtocolMappers(), client);
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
for (ProtocolMapperModel mapping : mappings) {
@@ -592,7 +568,7 @@ public class TokenManager {
}
}
- protected AccessToken initToken(RealmModel realm, ClientModel client, UserModel user, UserSessionModel session, ClientLoginSessionModel clientSession, UriInfo uriInfo) {
+ protected AccessToken initToken(RealmModel realm, ClientModel client, UserModel user, UserSessionModel session, AuthenticatedClientSessionModel clientSession, UriInfo uriInfo) {
AccessToken token = new AccessToken();
token.clientSession(clientSession.getId());
token.id(KeycloakModelUtils.generateId());
@@ -628,7 +604,7 @@ public class TokenManager {
return token;
}
- private int getTokenLifespan(RealmModel realm, ClientLoginSessionModel clientSession) {
+ private int getTokenLifespan(RealmModel realm, AuthenticatedClientSessionModel clientSession) {
boolean implicitFlow = false;
String responseType = clientSession.getNote(OIDCLoginProtocol.RESPONSE_TYPE_PARAM);
if (responseType != null) {
@@ -670,7 +646,7 @@ public class TokenManager {
return new JWSBuilder().type(JWT).kid(activeRsaKey.getKid()).jsonContent(token).sign(jwsAlgorithm, activeRsaKey.getPrivateKey());
}
- public AccessTokenResponseBuilder responseBuilder(RealmModel realm, ClientModel client, EventBuilder event, KeycloakSession session, UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ public AccessTokenResponseBuilder responseBuilder(RealmModel realm, ClientModel client, EventBuilder event, KeycloakSession session, UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
return new AccessTokenResponseBuilder(realm, client, event, session, userSession, clientSession);
}
@@ -680,7 +656,7 @@ public class TokenManager {
EventBuilder event;
KeycloakSession session;
UserSessionModel userSession;
- ClientLoginSessionModel clientSession;
+ AuthenticatedClientSessionModel clientSession;
AccessToken accessToken;
RefreshToken refreshToken;
@@ -689,7 +665,7 @@ public class TokenManager {
boolean generateAccessTokenHash = false;
String codeHash;
- public AccessTokenResponseBuilder(RealmModel realm, ClientModel client, EventBuilder event, KeycloakSession session, UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ public AccessTokenResponseBuilder(RealmModel realm, ClientModel client, EventBuilder event, KeycloakSession session, UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
this.realm = realm;
this.client = client;
this.event = event;
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java b/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java
index 6e4498e..ffff19c 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java
@@ -53,6 +53,8 @@ public class AuthorizeClientUtil {
throw new ErrorResponseException("invalid_client", "Client authentication ended, but client is null", Response.Status.BAD_REQUEST);
}
+ session.getContext().setClient(client);
+
return new ClientAuthResult(client, processor.getClientAuthAttributes());
}
diff --git a/services/src/main/java/org/keycloak/protocol/RestartLoginCookie.java b/services/src/main/java/org/keycloak/protocol/RestartLoginCookie.java
index 109f2c9..22d764d 100644
--- a/services/src/main/java/org/keycloak/protocol/RestartLoginCookie.java
+++ b/services/src/main/java/org/keycloak/protocol/RestartLoginCookie.java
@@ -23,20 +23,17 @@ import org.keycloak.common.ClientConnection;
import org.keycloak.jose.jws.JWSBuilder;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.crypto.HMACProvider;
-import org.keycloak.jose.jws.crypto.RSAProvider;
import org.keycloak.models.ClientModel;
-import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.KeyManager;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.util.CookieHelper;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
import javax.crypto.SecretKey;
import javax.ws.rs.core.Cookie;
import javax.ws.rs.core.UriInfo;
-import java.security.PublicKey;
import java.util.HashMap;
import java.util.Map;
@@ -51,7 +48,7 @@ public class RestartLoginCookie {
private static final Logger logger = Logger.getLogger(RestartLoginCookie.class);
public static final String KC_RESTART = "KC_RESTART";
@JsonProperty("cs")
- protected String clientSession;
+ protected String authenticationSession;
@JsonProperty("cid")
protected String clientId;
@@ -68,12 +65,12 @@ public class RestartLoginCookie {
@JsonProperty("notes")
protected Map<String, String> notes = new HashMap<>();
- public String getClientSession() {
- return clientSession;
+ public String getAuthenticationSession() {
+ return authenticationSession;
}
- public void setClientSession(String clientSession) {
- this.clientSession = clientSession;
+ public void setAuthenticationSession(String authenticationSession) {
+ this.authenticationSession = authenticationSession;
}
public Map<String, String> getNotes() {
@@ -126,19 +123,19 @@ public class RestartLoginCookie {
public RestartLoginCookie() {
}
- public RestartLoginCookie(LoginSessionModel clientSession) {
+ public RestartLoginCookie(AuthenticationSessionModel clientSession) {
this.action = clientSession.getAction();
this.clientId = clientSession.getClient().getClientId();
this.authMethod = clientSession.getProtocol();
this.redirectUri = clientSession.getRedirectUri();
- this.clientSession = clientSession.getId();
+ this.authenticationSession = clientSession.getId();
for (Map.Entry<String, String> entry : clientSession.getNotes().entrySet()) {
notes.put(entry.getKey(), entry.getValue());
}
}
- public static void setRestartCookie(KeycloakSession session, RealmModel realm, ClientConnection connection, UriInfo uriInfo, LoginSessionModel loginSession) {
- RestartLoginCookie restart = new RestartLoginCookie(loginSession);
+ public static void setRestartCookie(KeycloakSession session, RealmModel realm, ClientConnection connection, UriInfo uriInfo, AuthenticationSessionModel authSession) {
+ RestartLoginCookie restart = new RestartLoginCookie(authSession);
String encoded = restart.encode(session, realm);
String path = AuthenticationManager.getRealmCookiePath(realm, uriInfo);
boolean secureOnly = realm.getSslRequired().isRequired(connection);
@@ -151,14 +148,12 @@ public class RestartLoginCookie {
CookieHelper.addCookie(KC_RESTART, "", path, null, null, 0, secureOnly, true);
}
- // TODO:mposolda
- /*
- public static ClientSessionModel restartSession(KeycloakSession session, RealmModel realm, String code) throws Exception {
- String[] parts = code.split("\\.");
- return restartSessionByClientSession(session, realm, parts[1]);
+
+ public static AuthenticationSessionModel restartSession(KeycloakSession session, RealmModel realm) throws Exception {
+ return restartSessionByClientSession(session, realm);
}
- public static ClientSessionModel restartSessionByClientSession(KeycloakSession session, RealmModel realm, String clientSessionId) throws Exception {
+ private static AuthenticationSessionModel restartSessionByClientSession(KeycloakSession session, RealmModel realm) throws Exception {
Cookie cook = session.getContext().getRequestHeaders().getCookies().get(KC_RESTART);
if (cook == null) {
logger.debug("KC_RESTART cookie doesn't exist");
@@ -172,22 +167,18 @@ public class RestartLoginCookie {
return null;
}
RestartLoginCookie cookie = input.readJsonContent(RestartLoginCookie.class);
- if (!clientSessionId.equals(cookie.getClientSession())) {
- logger.debug("RestartLoginCookie clientSession does not match code's clientSession");
- return null;
- }
ClientModel client = realm.getClientByClientId(cookie.getClientId());
if (client == null) return null;
- ClientSessionModel clientSession = session.sessions().createClientSession(realm, client);
- clientSession.setAuthMethod(cookie.getAuthMethod());
- clientSession.setRedirectUri(cookie.getRedirectUri());
- clientSession.setAction(cookie.getAction());
+ AuthenticationSessionModel authSession = session.authenticationSessions().createAuthenticationSession(realm, client, true);
+ authSession.setProtocol(cookie.getAuthMethod());
+ authSession.setRedirectUri(cookie.getRedirectUri());
+ authSession.setAction(cookie.getAction());
for (Map.Entry<String, String> entry : cookie.getNotes().entrySet()) {
- clientSession.setNote(entry.getKey(), entry.getValue());
+ authSession.setNote(entry.getKey(), entry.getValue());
}
- return clientSession;
- }*/
+ return authSession;
+ }
}
diff --git a/services/src/main/java/org/keycloak/protocol/saml/mappers/GroupMembershipMapper.java b/services/src/main/java/org/keycloak/protocol/saml/mappers/GroupMembershipMapper.java
index 3ffdec4..d193ee3 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/mappers/GroupMembershipMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/mappers/GroupMembershipMapper.java
@@ -19,7 +19,7 @@ package org.keycloak.protocol.saml.mappers;
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
import org.keycloak.dom.saml.v2.assertion.AttributeType;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
@@ -117,7 +117,7 @@ public class GroupMembershipMapper extends AbstractSAMLProtocolMapper implements
@Override
- public void transformAttributeStatement(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ public void transformAttributeStatement(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
String single = mappingModel.getConfig().get(SINGLE_GROUP_ATTRIBUTE);
boolean singleAttribute = Boolean.parseBoolean(single);
diff --git a/services/src/main/java/org/keycloak/protocol/saml/mappers/HardcodedAttributeMapper.java b/services/src/main/java/org/keycloak/protocol/saml/mappers/HardcodedAttributeMapper.java
index 7909209..43c0241 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/mappers/HardcodedAttributeMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/mappers/HardcodedAttributeMapper.java
@@ -18,7 +18,7 @@
package org.keycloak.protocol.saml.mappers;
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.UserSessionModel;
@@ -76,7 +76,7 @@ public class HardcodedAttributeMapper extends AbstractSAMLProtocolMapper impleme
}
@Override
- public void transformAttributeStatement(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ public void transformAttributeStatement(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
String attributeValue = mappingModel.getConfig().get(ATTRIBUTE_VALUE);
AttributeStatementHelper.addAttribute(attributeStatement, mappingModel, attributeValue);
diff --git a/services/src/main/java/org/keycloak/protocol/saml/mappers/RoleListMapper.java b/services/src/main/java/org/keycloak/protocol/saml/mappers/RoleListMapper.java
index 169f25a..3227350 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/mappers/RoleListMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/mappers/RoleListMapper.java
@@ -19,7 +19,7 @@ package org.keycloak.protocol.saml.mappers;
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
import org.keycloak.dom.saml.v2.assertion.AttributeType;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.ProtocolMapperModel;
@@ -111,7 +111,7 @@ public class RoleListMapper extends AbstractSAMLProtocolMapper implements SAMLRo
}
@Override
- public void mapRoles(AttributeStatementType roleAttributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ public void mapRoles(AttributeStatementType roleAttributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
String single = mappingModel.getConfig().get(SINGLE_ROLE_ATTRIBUTE);
boolean singleAttribute = Boolean.parseBoolean(single);
diff --git a/services/src/main/java/org/keycloak/protocol/saml/mappers/SAMLAttributeStatementMapper.java b/services/src/main/java/org/keycloak/protocol/saml/mappers/SAMLAttributeStatementMapper.java
index 8e33f92..a26b0e0 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/mappers/SAMLAttributeStatementMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/mappers/SAMLAttributeStatementMapper.java
@@ -18,7 +18,7 @@
package org.keycloak.protocol.saml.mappers;
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.UserSessionModel;
@@ -30,5 +30,5 @@ import org.keycloak.models.UserSessionModel;
public interface SAMLAttributeStatementMapper {
void transformAttributeStatement(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session,
- UserSessionModel userSession, ClientLoginSessionModel clientSession);
+ UserSessionModel userSession, AuthenticatedClientSessionModel clientSession);
}
diff --git a/services/src/main/java/org/keycloak/protocol/saml/mappers/SAMLLoginResponseMapper.java b/services/src/main/java/org/keycloak/protocol/saml/mappers/SAMLLoginResponseMapper.java
index 329f1ac..1f962fe 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/mappers/SAMLLoginResponseMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/mappers/SAMLLoginResponseMapper.java
@@ -18,7 +18,7 @@
package org.keycloak.protocol.saml.mappers;
import org.keycloak.dom.saml.v2.protocol.ResponseType;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.UserSessionModel;
@@ -30,5 +30,5 @@ import org.keycloak.models.UserSessionModel;
public interface SAMLLoginResponseMapper {
ResponseType transformLoginResponse(ResponseType response, ProtocolMapperModel mappingModel, KeycloakSession session,
- UserSessionModel userSession, ClientLoginSessionModel clientSession);
+ UserSessionModel userSession, AuthenticatedClientSessionModel clientSession);
}
diff --git a/services/src/main/java/org/keycloak/protocol/saml/mappers/SAMLRoleListMapper.java b/services/src/main/java/org/keycloak/protocol/saml/mappers/SAMLRoleListMapper.java
index e74c79f..991c223 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/mappers/SAMLRoleListMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/mappers/SAMLRoleListMapper.java
@@ -18,7 +18,7 @@
package org.keycloak.protocol.saml.mappers;
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.UserSessionModel;
@@ -30,5 +30,5 @@ import org.keycloak.models.UserSessionModel;
public interface SAMLRoleListMapper {
void mapRoles(AttributeStatementType roleAttributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session,
- UserSessionModel userSession, ClientLoginSessionModel clientSession);
+ UserSessionModel userSession, AuthenticatedClientSessionModel clientSession);
}
diff --git a/services/src/main/java/org/keycloak/protocol/saml/mappers/UserAttributeStatementMapper.java b/services/src/main/java/org/keycloak/protocol/saml/mappers/UserAttributeStatementMapper.java
index 661c9b6..2579af1 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/mappers/UserAttributeStatementMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/mappers/UserAttributeStatementMapper.java
@@ -18,7 +18,7 @@
package org.keycloak.protocol.saml.mappers;
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.UserModel;
@@ -77,7 +77,7 @@ public class UserAttributeStatementMapper extends AbstractSAMLProtocolMapper imp
}
@Override
- public void transformAttributeStatement(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ public void transformAttributeStatement(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
UserModel user = userSession.getUser();
String attributeName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_ATTRIBUTE);
List<String> attributeValues = KeycloakModelUtils.resolveAttribute(user, attributeName);
diff --git a/services/src/main/java/org/keycloak/protocol/saml/mappers/UserPropertyAttributeStatementMapper.java b/services/src/main/java/org/keycloak/protocol/saml/mappers/UserPropertyAttributeStatementMapper.java
index adfc9aa..1d7d038 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/mappers/UserPropertyAttributeStatementMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/mappers/UserPropertyAttributeStatementMapper.java
@@ -18,7 +18,7 @@
package org.keycloak.protocol.saml.mappers;
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.UserModel;
@@ -76,7 +76,7 @@ public class UserPropertyAttributeStatementMapper extends AbstractSAMLProtocolMa
}
@Override
- public void transformAttributeStatement(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ public void transformAttributeStatement(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
UserModel user = userSession.getUser();
String propertyName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_ATTRIBUTE);
String propertyValue = ProtocolMapperUtils.getUserModelValue(user, propertyName);
diff --git a/services/src/main/java/org/keycloak/protocol/saml/mappers/UserSessionNoteStatementMapper.java b/services/src/main/java/org/keycloak/protocol/saml/mappers/UserSessionNoteStatementMapper.java
index d633e2c..b4b24b5 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/mappers/UserSessionNoteStatementMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/mappers/UserSessionNoteStatementMapper.java
@@ -18,7 +18,7 @@
package org.keycloak.protocol.saml.mappers;
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.UserSessionModel;
@@ -74,7 +74,7 @@ public class UserSessionNoteStatementMapper extends AbstractSAMLProtocolMapper i
}
@Override
- public void transformAttributeStatement(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ public void transformAttributeStatement(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
String note = mappingModel.getConfig().get("note");
String value = userSession.getNote(note);
if (value == null) return;
diff --git a/services/src/main/java/org/keycloak/protocol/saml/profile/ecp/authenticator/HttpBasicAuthenticator.java b/services/src/main/java/org/keycloak/protocol/saml/profile/ecp/authenticator/HttpBasicAuthenticator.java
index 81496fc..f21eff3 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/profile/ecp/authenticator/HttpBasicAuthenticator.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/profile/ecp/authenticator/HttpBasicAuthenticator.java
@@ -104,7 +104,7 @@ public class HttpBasicAuthenticator implements AuthenticatorFactory {
boolean valid = context.getSession().userCredentialManager().isValid(realm, user, UserCredentialModel.password(password));
if (valid) {
- context.getLoginSession().setAuthenticatedUser(user);
+ context.getAuthenticationSession().setAuthenticatedUser(user);
context.success();
} else {
context.getEvent().user(user);
diff --git a/services/src/main/java/org/keycloak/protocol/saml/profile/ecp/SamlEcpProfileService.java b/services/src/main/java/org/keycloak/protocol/saml/profile/ecp/SamlEcpProfileService.java
index f578f3d..b90a165 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/profile/ecp/SamlEcpProfileService.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/profile/ecp/SamlEcpProfileService.java
@@ -20,7 +20,7 @@ package org.keycloak.protocol.saml.profile.ecp;
import org.keycloak.dom.saml.v2.protocol.AuthnRequestType;
import org.keycloak.events.EventBuilder;
import org.keycloak.models.AuthenticationFlowModel;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserSessionModel;
@@ -35,7 +35,7 @@ import org.keycloak.saml.common.constants.JBossSAMLConstants;
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
import org.keycloak.saml.common.exceptions.ConfigurationException;
import org.keycloak.saml.common.exceptions.ProcessingException;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
import org.w3c.dom.Document;
import javax.ws.rs.core.Response;
@@ -86,15 +86,15 @@ public class SamlEcpProfileService extends SamlService {
}
@Override
- protected Response newBrowserAuthentication(LoginSessionModel loginSession, boolean isPassive, boolean redirectToAuthentication, SamlProtocol samlProtocol) {
- return super.newBrowserAuthentication(loginSession, isPassive, redirectToAuthentication, createEcpSamlProtocol());
+ protected Response newBrowserAuthentication(AuthenticationSessionModel authSession, boolean isPassive, boolean redirectToAuthentication, SamlProtocol samlProtocol) {
+ return super.newBrowserAuthentication(authSession, isPassive, redirectToAuthentication, createEcpSamlProtocol());
}
private SamlProtocol createEcpSamlProtocol() {
return new SamlProtocol() {
// method created to send a SOAP Binding response instead of a HTTP POST response
@Override
- protected Response buildAuthenticatedResponse(ClientLoginSessionModel clientSession, String redirectUri, Document samlDocument, JaxrsSAML2BindingBuilder bindingBuilder) throws ConfigurationException, ProcessingException, IOException {
+ protected Response buildAuthenticatedResponse(AuthenticatedClientSessionModel clientSession, String redirectUri, Document samlDocument, JaxrsSAML2BindingBuilder bindingBuilder) throws ConfigurationException, ProcessingException, IOException {
Document document = bindingBuilder.postBinding(samlDocument).getDocument();
try {
@@ -114,7 +114,7 @@ public class SamlEcpProfileService extends SamlService {
}
}
- private void createRequestAuthenticatedHeader(ClientLoginSessionModel clientSession, Soap.SoapMessageBuilder messageBuilder) {
+ private void createRequestAuthenticatedHeader(AuthenticatedClientSessionModel clientSession, Soap.SoapMessageBuilder messageBuilder) {
ClientModel client = clientSession.getClient();
if ("true".equals(client.getAttribute(SamlConfigAttributes.SAML_CLIENT_SIGNATURE_ATTRIBUTE))) {
@@ -134,7 +134,7 @@ public class SamlEcpProfileService extends SamlService {
}
@Override
- protected Response buildErrorResponse(LoginSessionModel clientSession, JaxrsSAML2BindingBuilder binding, Document document) throws ConfigurationException, ProcessingException, IOException {
+ protected Response buildErrorResponse(AuthenticationSessionModel authSession, JaxrsSAML2BindingBuilder binding, Document document) throws ConfigurationException, ProcessingException, IOException {
return Soap.createMessage().addToBody(document).build();
}
diff --git a/services/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java b/services/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
index 04da54a..db43a75 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
@@ -30,7 +30,7 @@ import org.keycloak.dom.saml.v2.assertion.AssertionType;
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
import org.keycloak.dom.saml.v2.protocol.ResponseType;
import org.keycloak.events.EventBuilder;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeyManager;
import org.keycloak.models.KeycloakSession;
@@ -40,6 +40,7 @@ import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.protocol.LoginProtocol;
import org.keycloak.protocol.ProtocolMapper;
+import org.keycloak.protocol.RestartLoginCookie;
import org.keycloak.protocol.saml.mappers.SAMLAttributeStatementMapper;
import org.keycloak.protocol.saml.mappers.SAMLLoginResponseMapper;
import org.keycloak.protocol.saml.mappers.SAMLRoleListMapper;
@@ -61,7 +62,7 @@ import org.keycloak.services.managers.ResourceAdminManager;
import org.keycloak.services.messages.Messages;
import org.keycloak.services.resources.RealmsResource;
import org.keycloak.sessions.CommonClientSessionModel;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
import org.w3c.dom.Document;
import javax.ws.rs.core.HttpHeaders;
@@ -157,9 +158,9 @@ public class SamlProtocol implements LoginProtocol {
}
@Override
- public Response sendError(LoginSessionModel loginSession, Error error) {
+ public Response sendError(AuthenticationSessionModel authSession, Error error) {
try {
- ClientModel client = loginSession.getClient();
+ ClientModel client = authSession.getClient();
if ("true".equals(client.getAttribute(SAML_IDP_INITIATED_LOGIN))) {
if (error == Error.CANCELLED_BY_USER) {
@@ -174,9 +175,9 @@ public class SamlProtocol implements LoginProtocol {
return ErrorPage.error(session, translateErrorToIdpInitiatedErrorMessage(error));
}
} else {
- SAML2ErrorResponseBuilder builder = new SAML2ErrorResponseBuilder().destination(loginSession.getRedirectUri()).issuer(getResponseIssuer(realm)).status(translateErrorToSAMLStatus(error).get());
+ SAML2ErrorResponseBuilder builder = new SAML2ErrorResponseBuilder().destination(authSession.getRedirectUri()).issuer(getResponseIssuer(realm)).status(translateErrorToSAMLStatus(error).get());
try {
- JaxrsSAML2BindingBuilder binding = new JaxrsSAML2BindingBuilder().relayState(loginSession.getNote(GeneralConstants.RELAY_STATE));
+ JaxrsSAML2BindingBuilder binding = new JaxrsSAML2BindingBuilder().relayState(authSession.getNote(GeneralConstants.RELAY_STATE));
SamlClient samlClient = new SamlClient(client);
KeyManager keyManager = session.keys();
if (samlClient.requiresRealmSignature()) {
@@ -199,23 +200,22 @@ public class SamlProtocol implements LoginProtocol {
binding.encrypt(publicKey);
}
Document document = builder.buildDocument();
- return buildErrorResponse(loginSession, binding, document);
+ return buildErrorResponse(authSession, binding, document);
} catch (Exception e) {
return ErrorPage.error(session, Messages.FAILED_TO_PROCESS_RESPONSE);
}
}
} finally {
- // TODO:mposolda
- //RestartLoginCookie.expireRestartCookie(realm, session.getContext().getConnection(), uriInfo);
- session.loginSessions().removeLoginSession(realm, loginSession);
+ RestartLoginCookie.expireRestartCookie(realm, session.getContext().getConnection(), uriInfo);
+ session.authenticationSessions().removeAuthenticationSession(realm, authSession);
}
}
- protected Response buildErrorResponse(LoginSessionModel loginSession, JaxrsSAML2BindingBuilder binding, Document document) throws ConfigurationException, ProcessingException, IOException {
- if (isPostBinding(loginSession)) {
- return binding.postBinding(document).response(loginSession.getRedirectUri());
+ protected Response buildErrorResponse(AuthenticationSessionModel authSession, JaxrsSAML2BindingBuilder binding, Document document) throws ConfigurationException, ProcessingException, IOException {
+ if (isPostBinding(authSession)) {
+ return binding.postBinding(document).response(authSession.getRedirectUri());
} else {
- return binding.redirectBinding(document).response(loginSession.getRedirectUri());
+ return binding.redirectBinding(document).response(authSession.getRedirectUri());
}
}
@@ -250,10 +250,10 @@ public class SamlProtocol implements LoginProtocol {
return RealmsResource.realmBaseUrl(uriInfo).build(realm.getName()).toString();
}
- protected boolean isPostBinding(CommonClientSessionModel loginSession) {
- ClientModel client = loginSession.getClient();
+ protected boolean isPostBinding(CommonClientSessionModel authSession) {
+ ClientModel client = authSession.getClient();
SamlClient samlClient = new SamlClient(client);
- return SamlProtocol.SAML_POST_BINDING.equals(loginSession.getNote(SamlProtocol.SAML_BINDING)) || samlClient.forcePostBinding();
+ return SamlProtocol.SAML_POST_BINDING.equals(authSession.getNote(SamlProtocol.SAML_BINDING)) || samlClient.forcePostBinding();
}
public static boolean isLogoutPostBindingForInitiator(UserSessionModel session) {
@@ -261,7 +261,7 @@ public class SamlProtocol implements LoginProtocol {
return SamlProtocol.SAML_POST_BINDING.equals(note);
}
- protected boolean isLogoutPostBindingForClient(ClientLoginSessionModel clientSession) {
+ protected boolean isLogoutPostBindingForClient(AuthenticatedClientSessionModel clientSession) {
ClientModel client = clientSession.getClient();
SamlClient samlClient = new SamlClient(client);
String logoutPostUrl = client.getAttribute(SAML_SINGLE_LOGOUT_SERVICE_URL_POST_ATTRIBUTE);
@@ -353,8 +353,8 @@ public class SamlProtocol implements LoginProtocol {
}
@Override
- public Response authenticated(UserSessionModel userSession, ClientSessionCode<ClientLoginSessionModel> accessCode) {
- ClientLoginSessionModel clientSession = accessCode.getClientSession();
+ public Response authenticated(UserSessionModel userSession, ClientSessionCode<AuthenticatedClientSessionModel> accessCode) {
+ AuthenticatedClientSessionModel clientSession = accessCode.getClientSession();
ClientModel client = clientSession.getClient();
SamlClient samlClient = new SamlClient(client);
String requestID = clientSession.getNote(SAML_REQUEST_ID);
@@ -462,7 +462,7 @@ public class SamlProtocol implements LoginProtocol {
}
}
- protected Response buildAuthenticatedResponse(ClientLoginSessionModel clientSession, String redirectUri, Document samlDocument, JaxrsSAML2BindingBuilder bindingBuilder) throws ConfigurationException, ProcessingException, IOException {
+ protected Response buildAuthenticatedResponse(AuthenticatedClientSessionModel clientSession, String redirectUri, Document samlDocument, JaxrsSAML2BindingBuilder bindingBuilder) throws ConfigurationException, ProcessingException, IOException {
if (isPostBinding(clientSession)) {
return bindingBuilder.postBinding(samlDocument).response(redirectUri);
} else {
@@ -481,7 +481,7 @@ public class SamlProtocol implements LoginProtocol {
}
public AttributeStatementType populateAttributeStatements(List<ProtocolMapperProcessor<SAMLAttributeStatementMapper>> attributeStatementMappers, KeycloakSession session, UserSessionModel userSession,
- ClientLoginSessionModel clientSession) {
+ AuthenticatedClientSessionModel clientSession) {
AttributeStatementType attributeStatement = new AttributeStatementType();
for (ProtocolMapperProcessor<SAMLAttributeStatementMapper> processor : attributeStatementMappers) {
processor.mapper.transformAttributeStatement(attributeStatement, processor.model, session, userSession, clientSession);
@@ -490,14 +490,14 @@ public class SamlProtocol implements LoginProtocol {
return attributeStatement;
}
- public ResponseType transformLoginResponse(List<ProtocolMapperProcessor<SAMLLoginResponseMapper>> mappers, ResponseType response, KeycloakSession session, UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ public ResponseType transformLoginResponse(List<ProtocolMapperProcessor<SAMLLoginResponseMapper>> mappers, ResponseType response, KeycloakSession session, UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
for (ProtocolMapperProcessor<SAMLLoginResponseMapper> processor : mappers) {
response = processor.mapper.transformLoginResponse(response, processor.model, session, userSession, clientSession);
}
return response;
}
- public void populateRoles(ProtocolMapperProcessor<SAMLRoleListMapper> roleListMapper, KeycloakSession session, UserSessionModel userSession, ClientLoginSessionModel clientSession,
+ public void populateRoles(ProtocolMapperProcessor<SAMLRoleListMapper> roleListMapper, KeycloakSession session, UserSessionModel userSession, AuthenticatedClientSessionModel clientSession,
final AttributeStatementType existingAttributeStatement) {
if (roleListMapper == null)
return;
@@ -520,7 +520,7 @@ public class SamlProtocol implements LoginProtocol {
}
@Override
- public Response frontchannelLogout(UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ public Response frontchannelLogout(UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
ClientModel client = clientSession.getClient();
SamlClient samlClient = new SamlClient(client);
try {
@@ -615,7 +615,7 @@ public class SamlProtocol implements LoginProtocol {
}
@Override
- public void backchannelLogout(UserSessionModel userSession, ClientLoginSessionModel clientSession) {
+ public void backchannelLogout(UserSessionModel userSession, AuthenticatedClientSessionModel clientSession) {
ClientModel client = clientSession.getClient();
SamlClient samlClient = new SamlClient(client);
String logoutUrl = getLogoutServiceUrl(uriInfo, client, SAML_POST_BINDING);
@@ -674,7 +674,7 @@ public class SamlProtocol implements LoginProtocol {
}
- protected SAML2LogoutRequestBuilder createLogoutRequest(String logoutUrl, ClientLoginSessionModel clientSession, ClientModel client) {
+ protected SAML2LogoutRequestBuilder createLogoutRequest(String logoutUrl, AuthenticatedClientSessionModel clientSession, ClientModel client) {
// build userPrincipal with subject used at login
SAML2LogoutRequestBuilder logoutBuilder = new SAML2LogoutRequestBuilder().assertionExpiration(realm.getAccessCodeLifespan()).issuer(getResponseIssuer(realm)).sessionIndex(clientSession.getId())
.userPrincipal(clientSession.getNote(SAML_NAME_ID), clientSession.getNote(SAML_NAME_ID_FORMAT)).destination(logoutUrl);
@@ -682,7 +682,7 @@ public class SamlProtocol implements LoginProtocol {
}
@Override
- public boolean requireReauthentication(UserSessionModel userSession, LoginSessionModel clientSession) {
+ public boolean requireReauthentication(UserSessionModel userSession, AuthenticationSessionModel authSession) {
// Not yet supported
return false;
}
diff --git a/services/src/main/java/org/keycloak/protocol/saml/SamlService.java b/services/src/main/java/org/keycloak/protocol/saml/SamlService.java
index 83445a6..29daf1e 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/SamlService.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/SamlService.java
@@ -86,7 +86,7 @@ import org.keycloak.rotation.HardcodedKeyLocator;
import org.keycloak.rotation.KeyLocator;
import org.keycloak.saml.SPMetadataDescriptor;
import org.keycloak.saml.processing.core.util.KeycloakKeySamlExtensionGenerator;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
/**
* Resource class for the oauth/openid connect token service
@@ -271,13 +271,13 @@ public class SamlService extends AuthorizationEndpointBase {
return ErrorPage.error(session, Messages.INVALID_REDIRECT_URI);
}
- LoginSessionModel loginSession = session.loginSessions().createLoginSession(realm, client, true);
- loginSession.setProtocol(SamlProtocol.LOGIN_PROTOCOL);
- loginSession.setRedirectUri(redirect);
- loginSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
- loginSession.setNote(SamlProtocol.SAML_BINDING, bindingType);
- loginSession.setNote(GeneralConstants.RELAY_STATE, relayState);
- loginSession.setNote(SamlProtocol.SAML_REQUEST_ID, requestAbstractType.getID());
+ AuthenticationSessionModel authSession = session.authenticationSessions().createAuthenticationSession(realm, client, true);
+ authSession.setProtocol(SamlProtocol.LOGIN_PROTOCOL);
+ authSession.setRedirectUri(redirect);
+ authSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
+ authSession.setNote(SamlProtocol.SAML_BINDING, bindingType);
+ authSession.setNote(GeneralConstants.RELAY_STATE, relayState);
+ authSession.setNote(SamlProtocol.SAML_REQUEST_ID, requestAbstractType.getID());
// Handle NameIDPolicy from SP
NameIDPolicyType nameIdPolicy = requestAbstractType.getNameIDPolicy();
@@ -286,7 +286,7 @@ public class SamlService extends AuthorizationEndpointBase {
String nameIdFormat = nameIdFormatUri.toString();
// TODO: Handle AllowCreate too, relevant for persistent NameID.
if (isSupportedNameIdFormat(nameIdFormat)) {
- loginSession.setNote(GeneralConstants.NAMEID_FORMAT, nameIdFormat);
+ authSession.setNote(GeneralConstants.NAMEID_FORMAT, nameIdFormat);
} else {
event.detail(Details.REASON, "unsupported_nameid_format");
event.error(Errors.INVALID_SAML_AUTHN_REQUEST);
@@ -302,13 +302,13 @@ public class SamlService extends AuthorizationEndpointBase {
BaseIDAbstractType baseID = subject.getSubType().getBaseID();
if (baseID != null && baseID instanceof NameIDType) {
NameIDType nameID = (NameIDType) baseID;
- loginSession.setNote(OIDCLoginProtocol.LOGIN_HINT_PARAM, nameID.getValue());
+ authSession.setNote(OIDCLoginProtocol.LOGIN_HINT_PARAM, nameID.getValue());
}
}
}
- return newBrowserAuthentication(loginSession, requestAbstractType.isIsPassive(), redirectToAuthentication);
+ return newBrowserAuthentication(authSession, requestAbstractType.isIsPassive(), redirectToAuthentication);
}
protected String getBindingType(AuthnRequestType requestAbstractType) {
@@ -519,13 +519,13 @@ public class SamlService extends AuthorizationEndpointBase {
}
- protected Response newBrowserAuthentication(LoginSessionModel loginSession, boolean isPassive, boolean redirectToAuthentication) {
+ protected Response newBrowserAuthentication(AuthenticationSessionModel authSession, boolean isPassive, boolean redirectToAuthentication) {
SamlProtocol samlProtocol = new SamlProtocol().setEventBuilder(event).setHttpHeaders(headers).setRealm(realm).setSession(session).setUriInfo(uriInfo);
- return newBrowserAuthentication(loginSession, isPassive, redirectToAuthentication, samlProtocol);
+ return newBrowserAuthentication(authSession, isPassive, redirectToAuthentication, samlProtocol);
}
- protected Response newBrowserAuthentication(LoginSessionModel loginSession, boolean isPassive, boolean redirectToAuthentication, SamlProtocol samlProtocol) {
- return handleBrowserAuthenticationRequest(loginSession, samlProtocol, isPassive, redirectToAuthentication);
+ protected Response newBrowserAuthentication(AuthenticationSessionModel authSession, boolean isPassive, boolean redirectToAuthentication, SamlProtocol samlProtocol) {
+ return handleBrowserAuthenticationRequest(authSession, samlProtocol, isPassive, redirectToAuthentication);
}
/**
@@ -616,9 +616,9 @@ public class SamlService extends AuthorizationEndpointBase {
return ErrorPage.error(session, Messages.INVALID_REDIRECT_URI);
}
- LoginSessionModel loginSession = createLoginSessionForIdpInitiatedSso(this.session, this.realm, client, relayState);
+ AuthenticationSessionModel authSession = createLoginSessionForIdpInitiatedSso(this.session, this.realm, client, relayState);
- return newBrowserAuthentication(loginSession, false, false);
+ return newBrowserAuthentication(authSession, false, false);
}
/**
@@ -632,7 +632,7 @@ public class SamlService extends AuthorizationEndpointBase {
* @param relayState Optional relay state - free field as per SAML specification
* @return
*/
- public static LoginSessionModel createLoginSessionForIdpInitiatedSso(KeycloakSession session, RealmModel realm, ClientModel client, String relayState) {
+ public static AuthenticationSessionModel createLoginSessionForIdpInitiatedSso(KeycloakSession session, RealmModel realm, ClientModel client, String relayState) {
String bindingType = SamlProtocol.SAML_POST_BINDING;
if (client.getManagementUrl() == null && client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_POST_ATTRIBUTE) == null && client.getAttribute(SamlProtocol.SAML_ASSERTION_CONSUMER_URL_REDIRECT_ATTRIBUTE) != null) {
bindingType = SamlProtocol.SAML_REDIRECT_BINDING;
@@ -648,21 +648,21 @@ public class SamlService extends AuthorizationEndpointBase {
redirect = client.getManagementUrl();
}
- LoginSessionModel loginSession = session.loginSessions().createLoginSession(realm, client, true);
- loginSession.setProtocol(SamlProtocol.LOGIN_PROTOCOL);
- loginSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
- loginSession.setNote(SamlProtocol.SAML_BINDING, SamlProtocol.SAML_POST_BINDING);
- loginSession.setNote(SamlProtocol.SAML_IDP_INITIATED_LOGIN, "true");
- loginSession.setRedirectUri(redirect);
+ AuthenticationSessionModel authSession = session.authenticationSessions().createAuthenticationSession(realm, client, true);
+ authSession.setProtocol(SamlProtocol.LOGIN_PROTOCOL);
+ authSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
+ authSession.setNote(SamlProtocol.SAML_BINDING, SamlProtocol.SAML_POST_BINDING);
+ authSession.setNote(SamlProtocol.SAML_IDP_INITIATED_LOGIN, "true");
+ authSession.setRedirectUri(redirect);
if (relayState == null) {
relayState = client.getAttribute(SamlProtocol.SAML_IDP_INITIATED_SSO_RELAY_STATE);
}
if (relayState != null && !relayState.trim().equals("")) {
- loginSession.setNote(GeneralConstants.RELAY_STATE, relayState);
+ authSession.setNote(GeneralConstants.RELAY_STATE, relayState);
}
- return loginSession;
+ return authSession;
}
@POST
diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java
index 7d45f15..67cce1f 100644
--- a/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java
+++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java
@@ -33,7 +33,7 @@ import org.keycloak.models.cache.CacheRealmProvider;
import org.keycloak.models.cache.UserCache;
import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderFactory;
-import org.keycloak.sessions.LoginSessionProvider;
+import org.keycloak.sessions.AuthenticationSessionProvider;
import org.keycloak.storage.UserStorageManager;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
@@ -58,7 +58,7 @@ public class DefaultKeycloakSession implements KeycloakSession {
private UserStorageManager userStorageManager;
private UserCredentialStoreManager userCredentialStorageManager;
private UserSessionProvider sessionProvider;
- private LoginSessionProvider loginSessionProvider;
+ private AuthenticationSessionProvider authenticationSessionProvider;
private UserFederatedStorageProvider userFederatedStorageProvider;
private KeycloakContext context;
private KeyManager keyManager;
@@ -238,11 +238,11 @@ public class DefaultKeycloakSession implements KeycloakSession {
}
@Override
- public LoginSessionProvider loginSessions() {
- if (loginSessionProvider == null) {
- loginSessionProvider = getProvider(LoginSessionProvider.class);
+ public AuthenticationSessionProvider authenticationSessions() {
+ if (authenticationSessionProvider == null) {
+ authenticationSessionProvider = getProvider(AuthenticationSessionProvider.class);
}
- return loginSessionProvider;
+ return authenticationSessionProvider;
}
@Override
diff --git a/services/src/main/java/org/keycloak/services/managers/Auth.java b/services/src/main/java/org/keycloak/services/managers/Auth.java
index 2ac7584..8b6086e 100755
--- a/services/src/main/java/org/keycloak/services/managers/Auth.java
+++ b/services/src/main/java/org/keycloak/services/managers/Auth.java
@@ -17,9 +17,8 @@
package org.keycloak.services.managers;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
-import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
@@ -36,7 +35,7 @@ public class Auth {
private final UserModel user;
private final ClientModel client;
private final UserSessionModel session;
- private ClientLoginSessionModel clientSession;
+ private AuthenticatedClientSessionModel clientSession;
public Auth(RealmModel realm, AccessToken token, UserModel user, ClientModel client, UserSessionModel session, boolean cookie) {
this.cookie = cookie;
@@ -72,11 +71,11 @@ public class Auth {
return session;
}
- public ClientLoginSessionModel getClientSession() {
+ public AuthenticatedClientSessionModel getClientSession() {
return clientSession;
}
- public void setClientSession(ClientLoginSessionModel clientSession) {
+ public void setClientSession(AuthenticatedClientSessionModel clientSession) {
this.clientSession = clientSession;
}
diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
index e460a1d..3c68370 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -19,6 +19,7 @@ package org.keycloak.services.managers;
import org.jboss.logging.Logger;
import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
import org.jboss.resteasy.spi.HttpRequest;
+import org.keycloak.OAuth2Constants;
import org.keycloak.TokenVerifier;
import org.keycloak.authentication.AuthenticationProcessor;
import org.keycloak.authentication.RequiredActionContext;
@@ -36,8 +37,9 @@ import org.keycloak.events.EventType;
import org.keycloak.forms.login.LoginFormsProvider;
import org.keycloak.jose.jws.AlgorithmType;
import org.keycloak.jose.jws.JWSBuilder;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientTemplateModel;
import org.keycloak.models.KeyManager;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
@@ -59,7 +61,7 @@ import org.keycloak.services.resources.IdentityBrokerService;
import org.keycloak.services.resources.RealmsResource;
import org.keycloak.services.util.CookieHelper;
import org.keycloak.services.util.P3PHelper;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
import javax.crypto.SecretKey;
import javax.ws.rs.core.Cookie;
@@ -71,6 +73,7 @@ import javax.ws.rs.core.UriInfo;
import java.net.URI;
import java.security.PublicKey;
import java.util.Collection;
+import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@@ -165,7 +168,7 @@ public class AuthenticationManager {
logger.debugv("Logging out: {0} ({1})", user.getUsername(), userSession.getId());
expireUserSessionCookie(session, userSession, realm, uriInfo, headers, connection);
- for (ClientLoginSessionModel clientSession : userSession.getClientLoginSessions().values()) {
+ for (AuthenticatedClientSessionModel clientSession : userSession.getAuthenticatedClientSessions().values()) {
backchannelLogoutClientSession(session, realm, clientSession, userSession, uriInfo, headers);
}
if (logoutBroker) {
@@ -183,9 +186,9 @@ public class AuthenticationManager {
session.sessions().removeUserSession(realm, userSession);
}
- public static void backchannelLogoutClientSession(KeycloakSession session, RealmModel realm, ClientLoginSessionModel clientSession, UserSessionModel userSession, UriInfo uriInfo, HttpHeaders headers) {
+ public static void backchannelLogoutClientSession(KeycloakSession session, RealmModel realm, AuthenticatedClientSessionModel clientSession, UserSessionModel userSession, UriInfo uriInfo, HttpHeaders headers) {
ClientModel client = clientSession.getClient();
- if (!client.isFrontchannelLogout() && !ClientLoginSessionModel.Action.LOGGED_OUT.name().equals(clientSession.getAction())) {
+ if (!client.isFrontchannelLogout() && !AuthenticatedClientSessionModel.Action.LOGGED_OUT.name().equals(clientSession.getAction())) {
String authMethod = clientSession.getProtocol();
if (authMethod == null) return; // must be a keycloak service like account
LoginProtocol protocol = session.getProvider(LoginProtocol.class, authMethod);
@@ -193,7 +196,7 @@ public class AuthenticationManager {
.setHttpHeaders(headers)
.setUriInfo(uriInfo);
protocol.backchannelLogout(userSession, clientSession);
- clientSession.setAction(ClientLoginSessionModel.Action.LOGGED_OUT.name());
+ clientSession.setAction(AuthenticatedClientSessionModel.Action.LOGGED_OUT.name());
}
}
@@ -204,8 +207,8 @@ public class AuthenticationManager {
List<UserSessionModel> userSessions = session.sessions().getUserSessions(realm, user);
for (UserSessionModel userSession : userSessions) {
- Collection<ClientLoginSessionModel> clientSessions = userSession.getClientLoginSessions().values();
- for (ClientLoginSessionModel clientSession : clientSessions) {
+ Collection<AuthenticatedClientSessionModel> clientSessions = userSession.getAuthenticatedClientSessions().values();
+ for (AuthenticatedClientSessionModel clientSession : clientSessions) {
if (clientSession.getClient().getId().equals(clientId)) {
AuthenticationManager.backchannelLogoutClientSession(session, realm, clientSession, userSession, uriInfo, headers);
TokenManager.dettachClientSession(session.sessions(), realm, clientSession);
@@ -222,10 +225,10 @@ public class AuthenticationManager {
if (userSession.getState() != UserSessionModel.State.LOGGING_OUT) {
userSession.setState(UserSessionModel.State.LOGGING_OUT);
}
- List<ClientLoginSessionModel> redirectClients = new LinkedList<>();
- for (ClientLoginSessionModel clientSession : userSession.getClientLoginSessions().values()) {
+ List<AuthenticatedClientSessionModel> redirectClients = new LinkedList<>();
+ for (AuthenticatedClientSessionModel clientSession : userSession.getAuthenticatedClientSessions().values()) {
ClientModel client = clientSession.getClient();
- if (ClientLoginSessionModel.Action.LOGGED_OUT.name().equals(clientSession.getAction())) continue;
+ if (AuthenticatedClientSessionModel.Action.LOGGED_OUT.name().equals(clientSession.getAction())) continue;
if (client.isFrontchannelLogout()) {
String authMethod = clientSession.getProtocol();
if (authMethod == null) continue; // must be a keycloak service like account
@@ -240,21 +243,21 @@ public class AuthenticationManager {
try {
logger.debugv("backchannel logout to: {0}", client.getClientId());
protocol.backchannelLogout(userSession, clientSession);
- clientSession.setAction(ClientLoginSessionModel.Action.LOGGED_OUT.name());
+ clientSession.setAction(AuthenticatedClientSessionModel.Action.LOGGED_OUT.name());
} catch (Exception e) {
ServicesLogger.LOGGER.failedToLogoutClient(e);
}
}
}
- for (ClientLoginSessionModel nextRedirectClient : redirectClients) {
+ for (AuthenticatedClientSessionModel nextRedirectClient : redirectClients) {
String authMethod = nextRedirectClient.getProtocol();
LoginProtocol protocol = session.getProvider(LoginProtocol.class, authMethod);
protocol.setRealm(realm)
.setHttpHeaders(headers)
.setUriInfo(uriInfo);
// setting this to logged out cuz I"m not sure protocols can always verify that the client was logged out or not
- nextRedirectClient.setAction(ClientLoginSessionModel.Action.LOGGED_OUT.name());
+ nextRedirectClient.setAction(AuthenticatedClientSessionModel.Action.LOGGED_OUT.name());
try {
logger.debugv("frontchannel logout to: {0}", nextRedirectClient.getClient().getClientId());
Response response = protocol.frontchannelLogout(userSession, nextRedirectClient);
@@ -417,7 +420,7 @@ public class AuthenticationManager {
public static Response redirectAfterSuccessfulFlow(KeycloakSession session, RealmModel realm, UserSessionModel userSession,
- ClientLoginSessionModel clientSession,
+ AuthenticatedClientSessionModel clientSession,
HttpRequest request, UriInfo uriInfo, ClientConnection clientConnection,
EventBuilder event, String protocol) {
LoginProtocol protocolImpl = session.getProvider(LoginProtocol.class, protocol);
@@ -425,12 +428,12 @@ public class AuthenticationManager {
.setHttpHeaders(request.getHttpHeaders())
.setUriInfo(uriInfo)
.setEventBuilder(event);
- return redirectAfterSuccessfulFlow(session, realm, userSession, clientSession, request, uriInfo, clientConnection, event, protocol);
+ return redirectAfterSuccessfulFlow(session, realm, userSession, clientSession, request, uriInfo, clientConnection, event, protocolImpl);
}
public static Response redirectAfterSuccessfulFlow(KeycloakSession session, RealmModel realm, UserSessionModel userSession,
- ClientLoginSessionModel clientSession,
+ AuthenticatedClientSessionModel clientSession,
HttpRequest request, UriInfo uriInfo, ClientConnection clientConnection,
EventBuilder event, LoginProtocol protocol) {
Cookie sessionCookie = request.getHttpHeaders().getCookies().get(AuthenticationManager.KEYCLOAK_SESSION_COOKIE);
@@ -471,29 +474,29 @@ public class AuthenticationManager {
}
- public static boolean isSSOAuthentication(ClientLoginSessionModel clientSession) {
+ public static boolean isSSOAuthentication(AuthenticatedClientSessionModel clientSession) {
String ssoAuth = clientSession.getNote(SSO_AUTH);
return Boolean.parseBoolean(ssoAuth);
}
- public static Response nextActionAfterAuthentication(KeycloakSession session, LoginSessionModel loginSession,
+ public static Response nextActionAfterAuthentication(KeycloakSession session, AuthenticationSessionModel authSession,
ClientConnection clientConnection,
HttpRequest request, UriInfo uriInfo, EventBuilder event) {
- Response requiredAction = actionRequired(session, loginSession, clientConnection, request, uriInfo, event);
+ Response requiredAction = actionRequired(session, authSession, clientConnection, request, uriInfo, event);
if (requiredAction != null) return requiredAction;
- return finishedRequiredActions(session, loginSession, clientConnection, request, uriInfo, event);
+ return finishedRequiredActions(session, authSession, clientConnection, request, uriInfo, event);
}
- public static Response finishedRequiredActions(KeycloakSession session, LoginSessionModel loginSession,
+ public static Response finishedRequiredActions(KeycloakSession session, AuthenticationSessionModel authSession,
ClientConnection clientConnection, HttpRequest request, UriInfo uriInfo, EventBuilder event) {
- if (loginSession.getNote(END_AFTER_REQUIRED_ACTIONS) != null) {
+ if (authSession.getAuthNote(END_AFTER_REQUIRED_ACTIONS) != null) {
LoginFormsProvider infoPage = session.getProvider(LoginFormsProvider.class)
.setSuccess(Messages.ACCOUNT_UPDATED);
- if (loginSession.getNote(SET_REDIRECT_URI_AFTER_REQUIRED_ACTIONS) != null) {
- if (loginSession.getRedirectUri() != null) {
- infoPage.setAttribute("pageRedirectUri", loginSession.getRedirectUri());
+ if (authSession.getAuthNote(SET_REDIRECT_URI_AFTER_REQUIRED_ACTIONS) != null) {
+ if (authSession.getRedirectUri() != null) {
+ infoPage.setAttribute("pageRedirectUri", authSession.getRedirectUri());
}
} else {
@@ -504,29 +507,32 @@ public class AuthenticationManager {
return response;
}
- event.success();
- RealmModel realm = loginSession.getRealm();
+ RealmModel realm = authSession.getRealm();
+
+ AuthenticatedClientSessionModel clientSession = AuthenticationProcessor.attachSession(authSession, null, session, realm, clientConnection, event);
- ClientLoginSessionModel clientSession = AuthenticationProcessor.attachSession(loginSession, null, session, realm, clientConnection, event);
- return redirectAfterSuccessfulFlow(session, realm , clientSession.getUserSession(), clientSession, request, uriInfo, clientConnection, event, loginSession.getProtocol());
+ event.event(EventType.LOGIN);
+ event.session(clientSession.getUserSession());
+ event.success();
+ return redirectAfterSuccessfulFlow(session, realm, clientSession.getUserSession(), clientSession, request, uriInfo, clientConnection, event, authSession.getProtocol());
}
- public static boolean isActionRequired(final KeycloakSession session, final LoginSessionModel loginSession,
+ public static boolean isActionRequired(final KeycloakSession session, final AuthenticationSessionModel authSession,
final ClientConnection clientConnection,
final HttpRequest request, final UriInfo uriInfo, final EventBuilder event) {
- final RealmModel realm = loginSession.getRealm();
- final UserModel user = loginSession.getAuthenticatedUser();
- final ClientModel client = loginSession.getClient();
+ final RealmModel realm = authSession.getRealm();
+ final UserModel user = authSession.getAuthenticatedUser();
+ final ClientModel client = authSession.getClient();
- evaluateRequiredActionTriggers(session, loginSession, clientConnection, request, uriInfo, event, realm, user);
+ evaluateRequiredActionTriggers(session, authSession, clientConnection, request, uriInfo, event, realm, user);
- if (!user.getRequiredActions().isEmpty() || !loginSession.getRequiredActions().isEmpty()) return true;
+ if (!user.getRequiredActions().isEmpty() || !authSession.getRequiredActions().isEmpty()) return true;
if (client.isConsentRequired()) {
UserConsentModel grantedConsent = session.users().getConsentByClient(realm, user.getId(), client.getId());
- ClientSessionCode<LoginSessionModel> accessCode = new ClientSessionCode<>(session, realm, loginSession);
+ ClientSessionCode<AuthenticationSessionModel> accessCode = new ClientSessionCode<>(session, realm, authSession);
for (RoleModel r : accessCode.getRequestedRoles()) {
// Consent already granted by user
@@ -553,27 +559,27 @@ public class AuthenticationManager {
}
- public static Response actionRequired(final KeycloakSession session, final LoginSessionModel loginSession,
+ public static Response actionRequired(final KeycloakSession session, final AuthenticationSessionModel authSession,
final ClientConnection clientConnection,
final HttpRequest request, final UriInfo uriInfo, final EventBuilder event) {
- final RealmModel realm = loginSession.getRealm();
- final UserModel user = loginSession.getAuthenticatedUser();
- final ClientModel client = loginSession.getClient();
+ final RealmModel realm = authSession.getRealm();
+ final UserModel user = authSession.getAuthenticatedUser();
+ final ClientModel client = authSession.getClient();
- evaluateRequiredActionTriggers(session, loginSession, clientConnection, request, uriInfo, event, realm, user);
+ evaluateRequiredActionTriggers(session, authSession, clientConnection, request, uriInfo, event, realm, user);
logger.debugv("processAccessCode: go to oauth page?: {0}", client.isConsentRequired());
- event.detail(Details.CODE_ID, loginSession.getId());
+ event.detail(Details.CODE_ID, authSession.getId());
Set<String> requiredActions = user.getRequiredActions();
- Response action = executionActions(session, loginSession, request, event, realm, user, requiredActions);
+ Response action = executionActions(session, authSession, request, event, realm, user, requiredActions);
if (action != null) return action;
// executionActions() method should remove any duplicate actions that might be in the clientSession
- requiredActions = loginSession.getRequiredActions();
- action = executionActions(session, loginSession, request, event, realm, user, requiredActions);
+ requiredActions = authSession.getRequiredActions();
+ action = executionActions(session, authSession, request, event, realm, user, requiredActions);
if (action != null) return action;
if (client.isConsentRequired()) {
@@ -582,7 +588,7 @@ public class AuthenticationManager {
List<RoleModel> realmRoles = new LinkedList<>();
MultivaluedMap<String, RoleModel> resourceRoles = new MultivaluedMapImpl<>();
- ClientSessionCode<LoginSessionModel> accessCode = new ClientSessionCode<>(session, realm, loginSession);
+ ClientSessionCode<AuthenticationSessionModel> accessCode = new ClientSessionCode<>(session, realm, authSession);
for (RoleModel r : accessCode.getRequestedRoles()) {
// Consent already granted by user
@@ -610,8 +616,8 @@ public class AuthenticationManager {
if (realmRoles.size() > 0 || resourceRoles.size() > 0 || protocolMappers.size() > 0) {
accessCode.
- setAction(ClientLoginSessionModel.Action.REQUIRED_ACTIONS.name());
- loginSession.setNote(CURRENT_REQUIRED_ACTION, ClientLoginSessionModel.Action.OAUTH_GRANT.name());
+ setAction(AuthenticatedClientSessionModel.Action.REQUIRED_ACTIONS.name());
+ authSession.setAuthNote(CURRENT_REQUIRED_ACTION, AuthenticatedClientSessionModel.Action.OAUTH_GRANT.name());
return session.getProvider(LoginFormsProvider.class)
.setClientSessionCode(accessCode.getCode())
@@ -628,7 +634,38 @@ public class AuthenticationManager {
}
- protected static Response executionActions(KeycloakSession session, LoginSessionModel loginSession,
+
+ public static void setRolesAndMappersInSession(AuthenticationSessionModel authSession) {
+ ClientModel client = authSession.getClient();
+ UserModel user = authSession.getAuthenticatedUser();
+
+ Set<String> requestedRoles = new HashSet<String>();
+ // todo scope param protocol independent
+ String scopeParam = authSession.getNote(OAuth2Constants.SCOPE);
+ for (RoleModel r : TokenManager.getAccess(scopeParam, true, client, user)) {
+ requestedRoles.add(r.getId());
+ }
+ authSession.setRoles(requestedRoles);
+
+ Set<String> requestedProtocolMappers = new HashSet<String>();
+ ClientTemplateModel clientTemplate = client.getClientTemplate();
+ if (clientTemplate != null && client.useTemplateMappers()) {
+ for (ProtocolMapperModel protocolMapper : clientTemplate.getProtocolMappers()) {
+ if (protocolMapper.getProtocol().equals(authSession.getProtocol())) {
+ requestedProtocolMappers.add(protocolMapper.getId());
+ }
+ }
+
+ }
+ for (ProtocolMapperModel protocolMapper : client.getProtocolMappers()) {
+ if (protocolMapper.getProtocol().equals(authSession.getProtocol())) {
+ requestedProtocolMappers.add(protocolMapper.getId());
+ }
+ }
+ authSession.setProtocolMappers(requestedProtocolMappers);
+ }
+
+ protected static Response executionActions(KeycloakSession session, AuthenticationSessionModel authSession,
HttpRequest request, EventBuilder event, RealmModel realm, UserModel user,
Set<String> requiredActions) {
for (String action : requiredActions) {
@@ -646,34 +683,34 @@ public class AuthenticationManager {
throw new RuntimeException("Unable to find factory for Required Action: " + model.getProviderId() + " did you forget to declare it in a META-INF/services file?");
}
RequiredActionProvider actionProvider = factory.create(session);
- RequiredActionContextResult context = new RequiredActionContextResult(loginSession, realm, event, session, request, user, factory);
+ RequiredActionContextResult context = new RequiredActionContextResult(authSession, realm, event, session, request, user, factory);
actionProvider.requiredActionChallenge(context);
if (context.getStatus() == RequiredActionContext.Status.FAILURE) {
- LoginProtocol protocol = context.getSession().getProvider(LoginProtocol.class, context.getLoginSession().getProtocol());
+ LoginProtocol protocol = context.getSession().getProvider(LoginProtocol.class, context.getAuthenticationSession().getProtocol());
protocol.setRealm(context.getRealm())
.setHttpHeaders(context.getHttpRequest().getHttpHeaders())
.setUriInfo(context.getUriInfo())
.setEventBuilder(event);
- Response response = protocol.sendError(context.getLoginSession(), Error.CONSENT_DENIED);
+ Response response = protocol.sendError(context.getAuthenticationSession(), Error.CONSENT_DENIED);
event.error(Errors.REJECTED_BY_USER);
return response;
}
else if (context.getStatus() == RequiredActionContext.Status.CHALLENGE) {
- loginSession.setNote(CURRENT_REQUIRED_ACTION, model.getProviderId());
+ authSession.setAuthNote(CURRENT_REQUIRED_ACTION, model.getProviderId());
return context.getChallenge();
}
else if (context.getStatus() == RequiredActionContext.Status.SUCCESS) {
event.clone().event(EventType.CUSTOM_REQUIRED_ACTION).detail(Details.CUSTOM_REQUIRED_ACTION, factory.getId()).success();
// don't have to perform the same action twice, so remove it from both the user and session required actions
- loginSession.getAuthenticatedUser().removeRequiredAction(factory.getId());
- loginSession.removeRequiredAction(factory.getId());
+ authSession.getAuthenticatedUser().removeRequiredAction(factory.getId());
+ authSession.removeRequiredAction(factory.getId());
}
}
return null;
}
- public static void evaluateRequiredActionTriggers(final KeycloakSession session, final LoginSessionModel loginSession, final ClientConnection clientConnection, final HttpRequest request, final UriInfo uriInfo, final EventBuilder event, final RealmModel realm, final UserModel user) {
+ public static void evaluateRequiredActionTriggers(final KeycloakSession session, final AuthenticationSessionModel authSession, final ClientConnection clientConnection, final HttpRequest request, final UriInfo uriInfo, final EventBuilder event, final RealmModel realm, final UserModel user) {
// see if any required actions need triggering, i.e. an expired password
for (RequiredActionProviderModel model : realm.getRequiredActionProviders()) {
@@ -683,7 +720,7 @@ public class AuthenticationManager {
throw new RuntimeException("Unable to find factory for Required Action: " + model.getProviderId() + " did you forget to declare it in a META-INF/services file?");
}
RequiredActionProvider provider = factory.create(session);
- RequiredActionContextResult result = new RequiredActionContextResult(loginSession, realm, event, session, request, user, factory) {
+ RequiredActionContextResult result = new RequiredActionContextResult(authSession, realm, event, session, request, user, factory) {
@Override
public void challenge(Response response) {
throw new RuntimeException("Not allowed to call challenge() within evaluateTriggers()");
diff --git a/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java b/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
index baf7ead..9aa4b69 100755
--- a/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
@@ -24,7 +24,7 @@ import org.keycloak.common.util.StringPropertyReplacer;
import org.keycloak.common.util.Time;
import org.keycloak.connections.httpclient.HttpClientProvider;
import org.keycloak.constants.AdapterConstants;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
@@ -113,7 +113,7 @@ public class ResourceAdminManager {
protected void logoutUserSessions(URI requestUri, RealmModel realm, List<UserSessionModel> userSessions) {
// Map from "app" to clientSessions for this app
- MultivaluedHashMap<String, ClientLoginSessionModel> clientSessions = new MultivaluedHashMap<>();
+ MultivaluedHashMap<String, AuthenticatedClientSessionModel> clientSessions = new MultivaluedHashMap<>();
for (UserSessionModel userSession : userSessions) {
putClientSessions(clientSessions, userSession);
}
@@ -121,7 +121,7 @@ public class ResourceAdminManager {
logger.debugv("logging out {0} resources ", clientSessions.size());
//logger.infov("logging out resources: {0}", clientSessions);
- for (Map.Entry<String, List<ClientLoginSessionModel>> entry : clientSessions.entrySet()) {
+ for (Map.Entry<String, List<AuthenticatedClientSessionModel>> entry : clientSessions.entrySet()) {
if (entry.getValue().size() == 0) {
continue;
}
@@ -129,18 +129,18 @@ public class ResourceAdminManager {
}
}
- private void putClientSessions(MultivaluedHashMap<String, ClientLoginSessionModel> clientSessions, UserSessionModel userSession) {
- for (Map.Entry<String, ClientLoginSessionModel> entry : userSession.getClientLoginSessions().entrySet()) {
+ private void putClientSessions(MultivaluedHashMap<String, AuthenticatedClientSessionModel> clientSessions, UserSessionModel userSession) {
+ for (Map.Entry<String, AuthenticatedClientSessionModel> entry : userSession.getAuthenticatedClientSessions().entrySet()) {
clientSessions.add(entry.getKey(), entry.getValue());
}
}
public void logoutUserFromClient(URI requestUri, RealmModel realm, ClientModel resource, UserModel user) {
List<UserSessionModel> userSessions = session.sessions().getUserSessions(realm, user);
- List<ClientLoginSessionModel> ourAppClientSessions = new LinkedList<>();
+ List<AuthenticatedClientSessionModel> ourAppClientSessions = new LinkedList<>();
if (userSessions != null) {
for (UserSessionModel userSession : userSessions) {
- ClientLoginSessionModel clientSession = userSession.getClientLoginSessions().get(resource.getId());
+ AuthenticatedClientSessionModel clientSession = userSession.getAuthenticatedClientSessions().get(resource.getId());
if (clientSession != null) {
ourAppClientSessions.add(clientSession);
}
@@ -150,11 +150,11 @@ public class ResourceAdminManager {
logoutClientSessions(requestUri, realm, resource, ourAppClientSessions);
}
- public boolean logoutClientSession(URI requestUri, RealmModel realm, ClientModel resource, ClientLoginSessionModel clientSession) {
+ public boolean logoutClientSession(URI requestUri, RealmModel realm, ClientModel resource, AuthenticatedClientSessionModel clientSession) {
return logoutClientSessions(requestUri, realm, resource, Arrays.asList(clientSession));
}
- protected boolean logoutClientSessions(URI requestUri, RealmModel realm, ClientModel resource, List<ClientLoginSessionModel> clientSessions) {
+ protected boolean logoutClientSessions(URI requestUri, RealmModel realm, ClientModel resource, List<AuthenticatedClientSessionModel> clientSessions) {
String managementUrl = getManagementUrl(requestUri, resource);
if (managementUrl != null) {
@@ -163,7 +163,7 @@ public class ResourceAdminManager {
List<String> userSessions = new LinkedList<>();
if (clientSessions != null && clientSessions.size() > 0) {
adapterSessionIds = new MultivaluedHashMap<String, String>();
- for (ClientLoginSessionModel clientSession : clientSessions) {
+ for (AuthenticatedClientSessionModel clientSession : clientSessions) {
String adapterSessionId = clientSession.getNote(AdapterConstants.CLIENT_SESSION_STATE);
if (adapterSessionId != null) {
String host = clientSession.getNote(AdapterConstants.CLIENT_SESSION_HOST);
diff --git a/services/src/main/java/org/keycloak/services/managers/UserSessionManager.java b/services/src/main/java/org/keycloak/services/managers/UserSessionManager.java
index a70c6f6..4528575 100644
--- a/services/src/main/java/org/keycloak/services/managers/UserSessionManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/UserSessionManager.java
@@ -18,7 +18,7 @@ package org.keycloak.services.managers;
import org.jboss.logging.Logger;
import org.keycloak.common.util.Time;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
@@ -50,7 +50,7 @@ public class UserSessionManager {
this.persister = session.getProvider(UserSessionPersisterProvider.class);
}
- public void createOrUpdateOfflineSession(ClientLoginSessionModel clientSession, UserSessionModel userSession) {
+ public void createOrUpdateOfflineSession(AuthenticatedClientSessionModel clientSession, UserSessionModel userSession) {
UserModel user = userSession.getUser();
// Create and persist offline userSession if we don't have one
@@ -63,7 +63,7 @@ public class UserSessionManager {
}
// Create and persist clientSession
- ClientLoginSessionModel offlineClientSession = offlineUserSession.getClientLoginSessions().get(clientSession.getClient().getId());
+ AuthenticatedClientSessionModel offlineClientSession = offlineUserSession.getAuthenticatedClientSessions().get(clientSession.getClient().getId());
if (offlineClientSession == null) {
createOfflineClientSession(user, clientSession, offlineUserSession);
}
@@ -78,7 +78,7 @@ public class UserSessionManager {
List<UserSessionModel> userSessions = kcSession.sessions().getOfflineUserSessions(realm, user);
Set<ClientModel> clients = new HashSet<>();
for (UserSessionModel userSession : userSessions) {
- Set<String> clientIds = userSession.getClientLoginSessions().keySet();
+ Set<String> clientIds = userSession.getAuthenticatedClientSessions().keySet();
for (String clientUUID : clientIds) {
ClientModel client = realm.getClientById(clientUUID);
clients.add(client);
@@ -97,14 +97,14 @@ public class UserSessionManager {
List<UserSessionModel> userSessions = kcSession.sessions().getOfflineUserSessions(realm, user);
boolean anyRemoved = false;
for (UserSessionModel userSession : userSessions) {
- ClientLoginSessionModel clientSession = userSession.getClientLoginSessions().get(client.getId());
+ AuthenticatedClientSessionModel clientSession = userSession.getAuthenticatedClientSessions().get(client.getId());
if (clientSession != null) {
if (logger.isTraceEnabled()) {
logger.tracef("Removing existing offline token for user '%s' and client '%s' .",
user.getUsername(), client.getClientId());
}
- userSession.getClientLoginSessions().remove(client.getClientId());
+ userSession.getAuthenticatedClientSessions().remove(client.getClientId());
persister.removeClientSession(clientSession.getId(), true);
checkOfflineUserSessionHasClientSessions(realm, user, userSession);
anyRemoved = true;
@@ -122,7 +122,7 @@ public class UserSessionManager {
persister.removeUserSession(userSession.getId(), true);
}
- public boolean isOfflineTokenAllowed(ClientLoginSessionModel clientSession) {
+ public boolean isOfflineTokenAllowed(AuthenticatedClientSessionModel clientSession) {
RoleModel offlineAccessRole = clientSession.getRealm().getRole(Constants.OFFLINE_ACCESS_ROLE);
if (offlineAccessRole == null) {
ServicesLogger.LOGGER.roleNotInRealm(Constants.OFFLINE_ACCESS_ROLE);
@@ -142,20 +142,20 @@ public class UserSessionManager {
return offlineUserSession;
}
- private void createOfflineClientSession(UserModel user, ClientLoginSessionModel clientSession, UserSessionModel offlineUserSession) {
+ private void createOfflineClientSession(UserModel user, AuthenticatedClientSessionModel clientSession, UserSessionModel offlineUserSession) {
if (logger.isTraceEnabled()) {
logger.tracef("Creating new offline token client session. ClientSessionId: '%s', UserSessionID: '%s' , Username: '%s', Client: '%s'" ,
clientSession.getId(), offlineUserSession.getId(), user.getUsername(), clientSession.getClient().getClientId());
}
- ClientLoginSessionModel offlineClientSession = kcSession.sessions().createOfflineClientSession(clientSession);
- offlineUserSession.getClientLoginSessions().put(clientSession.getClient().getId(), offlineClientSession);
+ AuthenticatedClientSessionModel offlineClientSession = kcSession.sessions().createOfflineClientSession(clientSession);
+ offlineUserSession.getAuthenticatedClientSessions().put(clientSession.getClient().getId(), offlineClientSession);
persister.createClientSession(offlineUserSession, clientSession, true);
}
// Check if userSession has any offline clientSessions attached to it. Remove userSession if not
private void checkOfflineUserSessionHasClientSessions(RealmModel realm, UserModel user, UserSessionModel userSession) {
- if (userSession.getClientLoginSessions().size() > 0) {
+ if (userSession.getAuthenticatedClientSessions().size() > 0) {
return;
}
diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java
index f4737ad..1894686 100755
--- a/services/src/main/java/org/keycloak/services/resources/AccountService.java
+++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java
@@ -30,9 +30,8 @@ import org.keycloak.forms.account.AccountPages;
import org.keycloak.forms.account.AccountProvider;
import org.keycloak.forms.login.LoginFormsProvider;
import org.keycloak.models.AccountRoles;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
-import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession;
@@ -45,7 +44,6 @@ import org.keycloak.models.UserSessionModel;
import org.keycloak.models.utils.CredentialValidation;
import org.keycloak.models.utils.FormMessage;
import org.keycloak.models.utils.ModelToRepresentation;
-import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.protocol.oidc.utils.RedirectUtils;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.ForbiddenException;
@@ -54,7 +52,6 @@ import org.keycloak.services.Urls;
import org.keycloak.services.managers.AppAuthManager;
import org.keycloak.services.managers.Auth;
import org.keycloak.services.managers.AuthenticationManager;
-import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.managers.UserSessionManager;
import org.keycloak.services.messages.Messages;
import org.keycloak.services.util.ResolveRelative;
@@ -68,13 +65,12 @@ import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
-import javax.ws.rs.core.Variant;
+
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -165,12 +161,11 @@ public class AccountService extends AbstractSecuredLocalService {
if (authResult != null) {
UserSessionModel userSession = authResult.getSession();
if (userSession != null) {
- boolean associated = userSession.getClientLoginSessions().get(client.getId()) != null;
- if (!associated) {
- ClientLoginSessionModel clientSession = session.sessions().createClientSession(userSession.getRealm(), client, userSession);
- clientSession.setUserSession(userSession);
- auth.setClientSession(clientSession);
+ AuthenticatedClientSessionModel clientSession = userSession.getAuthenticatedClientSessions().get(client.getId());
+ if (clientSession == null) {
+ clientSession = session.sessions().createClientSession(userSession.getRealm(), client, userSession);
}
+ auth.setClientSession(clientSession);
}
account.setUser(auth.getUser());
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
index d745213..c04b99e 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
@@ -24,18 +24,14 @@ import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.authentication.RequiredActionProvider;
import org.keycloak.common.ClientConnection;
import org.keycloak.common.Profile;
-import org.keycloak.common.util.Time;
import org.keycloak.credential.CredentialModel;
-import org.keycloak.email.EmailException;
-import org.keycloak.email.EmailTemplateProvider;
import org.keycloak.events.Details;
import org.keycloak.events.EventBuilder;
import org.keycloak.events.EventType;
import org.keycloak.events.admin.OperationType;
import org.keycloak.events.admin.ResourceType;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
-import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.Constants;
import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.GroupModel;
@@ -49,11 +45,8 @@ import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserLoginFailureModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
-import org.keycloak.models.credential.PasswordUserCredentialModel;
import org.keycloak.models.utils.ModelToRepresentation;
-import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
-import org.keycloak.protocol.oidc.utils.RedirectUtils;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.FederatedIdentityRepresentation;
@@ -63,11 +56,8 @@ import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.idm.UserSessionRepresentation;
import org.keycloak.services.ErrorResponse;
import org.keycloak.services.ErrorResponseException;
-import org.keycloak.services.ServicesLogger;
-import org.keycloak.services.Urls;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.BruteForceProtector;
-import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.models.UserManager;
import org.keycloak.services.managers.UserSessionManager;
import org.keycloak.services.resources.AccountService;
@@ -84,13 +74,11 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
-import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
-import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import java.net.URI;
import java.text.MessageFormat;
@@ -103,7 +91,6 @@ import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
-import java.util.concurrent.TimeUnit;
/**
* Base resource for managing users
@@ -414,7 +401,7 @@ public class UsersResource {
UserSessionRepresentation rep = ModelToRepresentation.toRepresentation(session);
// Update lastSessionRefresh with the timestamp from clientSession
- ClientLoginSessionModel clientSession = session.getClientLoginSessions().get(clientId);
+ AuthenticatedClientSessionModel clientSession = session.getAuthenticatedClientSessions().get(clientId);
// Skip if userSession is not for this client
if (clientSession == null) {
diff --git a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
index 9dd9f95..7492285 100755
--- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
+++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
@@ -16,101 +16,19 @@
*/
package org.keycloak.services.resources;
-import org.jboss.logging.Logger;
-import org.jboss.resteasy.annotations.cache.NoCache;
-import org.jboss.resteasy.spi.HttpRequest;
-import org.jboss.resteasy.spi.ResteasyProviderFactory;
-
-import org.keycloak.OAuth2Constants;
-import org.keycloak.authentication.AuthenticationProcessor;
-import org.keycloak.authentication.authenticators.broker.AbstractIdpAuthenticator;
-import org.keycloak.authentication.authenticators.broker.util.PostBrokerLoginConstants;
-import org.keycloak.authentication.authenticators.broker.util.SerializedBrokeredIdentityContext;
-import org.keycloak.broker.provider.AuthenticationRequest;
-import org.keycloak.broker.provider.BrokeredIdentityContext;
import org.keycloak.broker.provider.IdentityBrokerException;
import org.keycloak.broker.provider.IdentityProvider;
import org.keycloak.broker.provider.IdentityProviderFactory;
-import org.keycloak.broker.provider.IdentityProviderMapper;
-import org.keycloak.broker.saml.SAMLEndpoint;
import org.keycloak.broker.social.SocialIdentityProvider;
-import org.keycloak.common.ClientConnection;
-import org.keycloak.common.util.Base64Url;
-import org.keycloak.common.util.ObjectUtil;
-import org.keycloak.common.util.Time;
-import org.keycloak.common.util.UriUtils;
-import org.keycloak.events.Details;
-import org.keycloak.events.Errors;
-import org.keycloak.events.EventBuilder;
-import org.keycloak.events.EventType;
-import org.keycloak.forms.login.LoginFormsProvider;
-import org.keycloak.models.AuthenticationFlowModel;
-import org.keycloak.models.ClientLoginSessionModel;
-import org.keycloak.models.ClientModel;
-import org.keycloak.models.ClientSessionModel;
-import org.keycloak.models.Constants;
-import org.keycloak.models.FederatedIdentityModel;
-import org.keycloak.models.IdentityProviderMapperModel;
import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.RealmModel;
-import org.keycloak.models.RoleModel;
-import org.keycloak.models.UserModel;
-import org.keycloak.models.UserSessionModel;
-import org.keycloak.models.utils.FormMessage;
-import org.keycloak.protocol.oidc.OIDCLoginProtocol;
-import org.keycloak.protocol.oidc.TokenManager;
-import org.keycloak.protocol.oidc.utils.RedirectUtils;
-import org.keycloak.protocol.saml.SamlProtocol;
-import org.keycloak.protocol.saml.SamlService;
import org.keycloak.provider.ProviderFactory;
-import org.keycloak.representations.AccessToken;
-import org.keycloak.services.ErrorPage;
-import org.keycloak.services.ErrorPageException;
-import org.keycloak.services.ErrorResponse;
-import org.keycloak.services.ServicesLogger;
-import org.keycloak.services.Urls;
-import org.keycloak.services.managers.AppAuthManager;
-import org.keycloak.services.managers.AuthenticationManager;
-import org.keycloak.services.managers.AuthenticationManager.AuthResult;
-import org.keycloak.services.managers.BruteForceProtector;
-import org.keycloak.services.managers.ClientSessionCode;
-import org.keycloak.services.messages.Messages;
-import org.keycloak.services.util.CacheControlUtil;
-import org.keycloak.services.validation.Validation;
-import org.keycloak.sessions.LoginSessionModel;
-import org.keycloak.util.JsonSerialization;
-import javax.ws.rs.GET;
-import javax.ws.rs.OPTIONS;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.Status;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
-import java.io.IOException;
-import java.net.URI;
-import java.nio.charset.StandardCharsets;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.UUID;
-
-import static org.keycloak.models.AccountRoles.MANAGE_ACCOUNT;
-import static org.keycloak.models.AccountRoles.MANAGE_ACCOUNT_LINKS;
-import static org.keycloak.models.Constants.ACCOUNT_MANAGEMENT_CLIENT_ID;
/**
* <p></p>
@@ -246,7 +164,7 @@ public class IdentityBrokerService {
//
//
// ClientLoginSessionModel clientSession = null;
-// for (ClientLoginSessionModel cs : cookieResult.getSession().getClientLoginSessions().values()) {
+// for (ClientLoginSessionModel cs : cookieResult.getSession().getAuthenticatedClientSessions().values()) {
// if (cs.getClient().getClientId().equals(clientId)) {
// byte[] decoded = Base64Url.decode(hash);
// MessageDigest md = null;
@@ -298,7 +216,7 @@ public class IdentityBrokerService {
// }
//
//
-// // TODO: Create LoginSessionModel and Login cookie and set the state inside. See my notes document
+// // TODO: Create AuthenticationSessionModel and Login cookie and set the state inside. See my notes document
// ClientSessionCode clientSessionCode = new ClientSessionCode(session, realmModel, clientSession);
// clientSessionCode.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
// clientSessionCode.getCode();
@@ -487,10 +405,10 @@ public class IdentityBrokerService {
// context.setToken(null);
// }
//
-// LoginSessionModel loginSession = clientCode.getClientSession();
-// context.setLoginSession(loginSession);
+// AuthenticationSessionModel authSession = clientCode.getClientSession();
+// context.setAuthenticationSession(authenticationSession);
//
-// session.getContext().setClient(loginSession.getClient());
+// session.getContext().setClient(authenticationSession.getClient());
//
// context.getIdp().preprocessFederatedIdentity(session, realmModel, context);
// Set<IdentityProviderMapperModel> mappers = realmModel.getIdentityProviderMappersByAlias(context.getIdpConfig().getAlias());
@@ -506,13 +424,13 @@ public class IdentityBrokerService {
// context.getUsername(), context.getToken());
//
// this.event.event(EventType.IDENTITY_PROVIDER_LOGIN)
-// .detail(Details.REDIRECT_URI, loginSession.getRedirectUri())
+// .detail(Details.REDIRECT_URI, authenticationSession.getRedirectUri())
// .detail(Details.IDENTITY_PROVIDER_USERNAME, context.getUsername());
//
// UserModel federatedUser = this.session.users().getUserByFederatedIdentity(federatedIdentityModel, this.realmModel);
//
// // Check if federatedUser is already authenticated (this means linking social into existing federatedUser account)
-// if (loginSession.getUserSession() != null) {
+// if (authenticationSession.getUserSession() != null) {
// return performAccountLinking(clientSession, context, federatedIdentityModel, federatedUser);
// }
//
@@ -701,30 +619,30 @@ public class IdentityBrokerService {
// if (parsedCode.response != null) {
// return parsedCode.response;
// }
-// LoginSessionModel loginSession = parsedCode.clientSessionCode.getClientSession();
+// AuthenticationSessionModel authenticationSession = parsedCode.clientSessionCode.getClientSession();
//
// try {
-// SerializedBrokeredIdentityContext serializedCtx = SerializedBrokeredIdentityContext.readFromLoginSession(loginSession, PostBrokerLoginConstants.PBL_BROKERED_IDENTITY_CONTEXT);
+// SerializedBrokeredIdentityContext serializedCtx = SerializedBrokeredIdentityContext.readFromLoginSession(authenticationSession, PostBrokerLoginConstants.PBL_BROKERED_IDENTITY_CONTEXT);
// if (serializedCtx == null) {
// throw new IdentityBrokerException("Not found serialized context in clientSession. Note " + PostBrokerLoginConstants.PBL_BROKERED_IDENTITY_CONTEXT + " was null");
// }
-// BrokeredIdentityContext context = serializedCtx.deserialize(session, loginSession);
+// BrokeredIdentityContext context = serializedCtx.deserialize(session, authenticationSession);
//
-// String wasFirstBrokerLoginNote = loginSession.getNote(PostBrokerLoginConstants.PBL_AFTER_FIRST_BROKER_LOGIN);
+// String wasFirstBrokerLoginNote = authenticationSession.getNote(PostBrokerLoginConstants.PBL_AFTER_FIRST_BROKER_LOGIN);
// boolean wasFirstBrokerLogin = Boolean.parseBoolean(wasFirstBrokerLoginNote);
//
// // Ensure the post-broker-login flow was successfully finished
// String authStateNoteKey = PostBrokerLoginConstants.PBL_AUTH_STATE_PREFIX + context.getIdpConfig().getAlias();
-// String authState = loginSession.getNote(authStateNoteKey);
+// String authState = authenticationSession.getNote(authStateNoteKey);
// if (!Boolean.parseBoolean(authState)) {
// throw new IdentityBrokerException("Invalid request. Not found the flag that post-broker-login flow was finished");
// }
//
// // remove notes
-// loginSession.removeNote(PostBrokerLoginConstants.PBL_BROKERED_IDENTITY_CONTEXT);
-// loginSession.removeNote(PostBrokerLoginConstants.PBL_AFTER_FIRST_BROKER_LOGIN);
+// authenticationSession.removeNote(PostBrokerLoginConstants.PBL_BROKERED_IDENTITY_CONTEXT);
+// authenticationSession.removeNote(PostBrokerLoginConstants.PBL_AFTER_FIRST_BROKER_LOGIN);
//
-// return afterPostBrokerLoginFlowSuccess(loginSession, context, wasFirstBrokerLogin, parsedCode.clientSessionCode);
+// return afterPostBrokerLoginFlowSuccess(authenticationSession, context, wasFirstBrokerLogin, parsedCode.clientSessionCode);
// } catch (IdentityBrokerException e) {
// return redirectToErrorPage(Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR, e);
// }
@@ -903,12 +821,12 @@ public class IdentityBrokerService {
// }
//
// private ParsedCodeContext parseClientSessionCode(String code) {
-// ClientSessionCode<LoginSessionModel> clientCode = ClientSessionCode.parse(code, this.session, this.realmModel, LoginSessionModel.class);
+// ClientSessionCode<LoginSessionModel> clientCode = ClientSessionCode.parse(code, this.session, this.realmModel, AuthenticationSessionModel.class);
//
// if (clientCode != null) {
-// LoginSessionModel loginSession = clientCode.getClientSession();
+// AuthenticationSessionModel authenticationSession = clientCode.getClientSession();
//
-// ClientModel client = loginSession.getClient();
+// ClientModel client = authenticationSession.getClient();
//
// if (client != null) {
//
@@ -917,7 +835,7 @@ public class IdentityBrokerService {
// this.session.getContext().setClient(client);
//
// if (!clientCode.isValid(AUTHENTICATE.name(), ClientSessionCode.ActionType.LOGIN)) {
-// logger.debugf("Authorization code is not valid. Client session ID: %s, Client session's action: %s", loginSession.getId(), loginSession.getAction());
+// logger.debugf("Authorization code is not valid. Client session ID: %s, Client session's action: %s", authenticationSession.getId(), authenticationSession.getAction());
//
// // Check if error happened during login or during linking from account management
// Response accountManagementFailedLinking = checkAccountManagementFailedLinking(clientCode.getClientSession(), Messages.STALE_CODE_ACCOUNT);
@@ -966,7 +884,7 @@ public class IdentityBrokerService {
// return ParsedCodeContext.clientSessionCode(new ClientSessionCode(session, this.realmModel, clientSession));
// }
//
-// private Response checkAccountManagementFailedLinking(LoginSessionModel loginSession, String error, Object... parameters) {
+// private Response checkAccountManagementFailedLinking(LoginSessionModel authenticationSession, String error, Object... parameters) {
// if (clientSession.getUserSession() != null && clientSession.getClient() != null && clientSession.getClient().getClientId().equals(ACCOUNT_MANAGEMENT_CLIENT_ID)) {
//
// this.event.event(EventType.FEDERATED_IDENTITY_LINK);
@@ -981,11 +899,11 @@ public class IdentityBrokerService {
// }
//
// private AuthenticationRequest createAuthenticationRequest(String providerId, ClientSessionCode<LoginSessionModel> clientSessionCode) {
-// LoginSessionModel loginSession = null;
+// AuthenticationSessionModel authenticationSession = null;
// String relayState = null;
//
// if (clientSessionCode != null) {
-// loginSession = clientSessionCode.getClientSession();
+// authenticationSession = clientSessionCode.getClientSession();
// relayState = clientSessionCode.getCode();
// }
//
diff --git a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
index 9633212..5033395 100755
--- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
+++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
@@ -31,6 +31,7 @@ import org.keycloak.authentication.authenticators.broker.AbstractIdpAuthenticato
import org.keycloak.authentication.authenticators.browser.AbstractUsernameFormAuthenticator;
import org.keycloak.common.ClientConnection;
import org.keycloak.common.VerificationException;
+import org.keycloak.common.util.ObjectUtil;
import org.keycloak.common.util.Time;
import org.keycloak.events.Details;
import org.keycloak.events.Errors;
@@ -38,7 +39,7 @@ import org.keycloak.events.EventBuilder;
import org.keycloak.events.EventType;
import org.keycloak.forms.login.LoginFormsProvider;
import org.keycloak.models.AuthenticationFlowModel;
-import org.keycloak.models.ClientLoginSessionModel;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.Constants;
@@ -48,7 +49,6 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserConsentModel;
import org.keycloak.models.UserModel;
-import org.keycloak.models.UserSessionModel;
import org.keycloak.models.utils.FormMessage;
import org.keycloak.protocol.LoginProtocol;
import org.keycloak.protocol.LoginProtocol.Error;
@@ -63,12 +63,10 @@ import org.keycloak.services.Urls;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.managers.ClientSessionCode.ActionType;
-import org.keycloak.services.managers.ClientSessionCode.ParseResult;
import org.keycloak.services.messages.Messages;
import org.keycloak.services.util.CacheControlUtil;
import org.keycloak.services.util.CookieHelper;
-import org.keycloak.sessions.CommonClientSessionModel;
-import org.keycloak.sessions.LoginSessionModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
@@ -102,7 +100,6 @@ public class LoginActionsService {
public static final String REQUIRED_ACTION = "required-action";
public static final String FIRST_BROKER_LOGIN_PATH = "first-broker-login";
public static final String POST_BROKER_LOGIN_PATH = "post-broker-login";
- public static final String LAST_PROCESSED_CODE = "last_processed_code";
private RealmModel realm;
@@ -169,28 +166,33 @@ public class LoginActionsService {
}
}
- private <C extends CommonClientSessionModel> SessionCodeChecks<C> checksForCode(String code, Class<C> expectedClazz) {
- SessionCodeChecks<C> res = new SessionCodeChecks<>(code, expectedClazz);
+ private SessionCodeChecks checksForCode(String code, String execution, String flowPath, boolean wantsRestartSession) {
+ SessionCodeChecks res = new SessionCodeChecks(code, execution, flowPath, wantsRestartSession);
res.initialVerifyCode();
return res;
}
- private class SessionCodeChecks<C extends CommonClientSessionModel> {
- ClientSessionCode<C> clientCode;
+ private class SessionCodeChecks {
+ ClientSessionCode<AuthenticationSessionModel> clientCode;
Response response;
- ClientSessionCode.ParseResult<C> result;
- Class<C> expectedClazz;
+ ClientSessionCode.ParseResult<AuthenticationSessionModel> result;
+ private boolean actionRequest;
private final String code;
+ private final String execution;
+ private final String flowPath;
+ private final boolean wantsRestartSession;
- public SessionCodeChecks(String code, Class<C> expectedClazz) {
+ public SessionCodeChecks(String code, String execution, String flowPath, boolean wantsRestartSession) {
this.code = code;
- this.expectedClazz = expectedClazz;
+ this.execution = execution;
+ this.flowPath = flowPath;
+ this.wantsRestartSession = wantsRestartSession;
}
- public C getClientSession() {
+ public AuthenticationSessionModel getAuthenticationSession() {
return clientCode == null ? null : clientCode.getClientSession();
}
@@ -209,9 +211,11 @@ public class LoginActionsService {
}
if (!clientCode.isValidAction(requiredAction)) {
- C clientSession = getClientSession();
- if (ClientSessionModel.Action.REQUIRED_ACTIONS.name().equals(clientSession.getAction())) {
- response = redirectToRequiredActions(code);
+ AuthenticationSessionModel authSession = getAuthenticationSession();
+ if (ClientSessionModel.Action.REQUIRED_ACTIONS.name().equals(authSession.getAction())) {
+ // TODO:mposolda debug or trace
+ logger.info("Incorrect flow '%s' . User authenticated already. Trying requiredActions now.");
+ response = AuthenticationManager.nextActionAfterAuthentication(session, authSession, clientConnection, request, uriInfo, event);
return false;
} // TODO:mposolda
/*else if (clientSession.getUserSession() != null && clientSession.getUserSession().getState() == UserSessionModel.State.LOGGED_IN) {
@@ -234,19 +238,19 @@ public class LoginActionsService {
}
private void invalidAction() {
- event.client(getClientSession().getClient());
+ event.client(getAuthenticationSession().getClient());
event.error(Errors.INVALID_CODE);
response = ErrorPage.error(session, Messages.INVALID_CODE);
}
private boolean isActionActive(ClientSessionCode.ActionType actionType) {
if (!clientCode.isActionActive(actionType)) {
- event.client(getClientSession().getClient());
+ event.client(getAuthenticationSession().getClient());
event.clone().error(Errors.EXPIRED_CODE);
- if (getClientSession().getAction().equals(ClientSessionModel.Action.AUTHENTICATE.name())) {
- LoginSessionModel loginSession = (LoginSessionModel) getClientSession();
- AuthenticationProcessor.resetFlow(loginSession);
- response = processAuthentication(null, loginSession, Messages.LOGIN_TIMEOUT);
+ if (getAuthenticationSession().getAction().equals(ClientSessionModel.Action.AUTHENTICATE.name())) {
+ AuthenticationSessionModel authSession = getAuthenticationSession();
+ AuthenticationProcessor.resetFlow(authSession);
+ response = processAuthentication(false, null, authSession, Messages.LOGIN_TIMEOUT);
return false;
}
response = ErrorPage.error(session, Messages.EXPIRED_CODE);
@@ -256,6 +260,7 @@ public class LoginActionsService {
}
private boolean initialVerifyCode() {
+ // Basic realm checks
if (!checkSsl()) {
event.error(Errors.SSL_REQUIRED);
response = ErrorPage.error(session, Messages.HTTPS_REQUIRED);
@@ -266,52 +271,100 @@ public class LoginActionsService {
response = ErrorPage.error(session, Messages.REALM_NOT_ENABLED);
return false;
}
- result = ClientSessionCode.parseResult(code, session, realm, expectedClazz);
- clientCode = result.getCode();
- if (clientCode == null) {
- if (result.isLoginSessionNotFound()) { // timeout or loginSession already logged
- // TODO:mposolda
- /*
- try {
- ClientSessionModel clientSession = RestartLoginCookie.restartSession(session, realm, code);
- if (clientSession != null) {
- event.clone().detail(Details.RESTART_AFTER_TIMEOUT, "true").error(Errors.EXPIRED_CODE);
- response = processFlow(null, clientSession, AUTHENTICATE_PATH, realm.getBrowserFlow(), Messages.LOGIN_TIMEOUT, new AuthenticationProcessor());
- return false;
- }
- } catch (Exception e) {
- ServicesLogger.LOGGER.failedToParseRestartLoginCookie(e);
- }*/
- }
- event.error(Errors.INVALID_CODE);
- response = ErrorPage.error(session, Messages.INVALID_CODE);
+
+ // authenticationSession retrieve and check if we need session restart
+ AuthenticationSessionModel authSession = ClientSessionCode.getClientSession(code, session, realm, AuthenticationSessionModel.class);
+ if (authSession == null) {
+ response = restartAuthenticationSession(false);
return false;
}
-
- C clientSession = getClientSession();
- if (clientSession == null) {
- event.error(Errors.INVALID_CODE);
- response = ErrorPage.error(session, Messages.INVALID_CODE);
+ if (wantsRestartSession) {
+ response = restartAuthenticationSession(true);
return false;
}
- event.detail(Details.CODE_ID, clientSession.getId());
- ClientModel client = clientSession.getClient();
+
+ // Client checks
+ event.detail(Details.CODE_ID, authSession.getId());
+ ClientModel client = authSession.getClient();
if (client == null) {
event.error(Errors.CLIENT_NOT_FOUND);
response = ErrorPage.error(session, Messages.UNKNOWN_LOGIN_REQUESTER);
- // TODO:mposolda
- //session.sessions().removeClientSession(realm, clientSession);
+ clientCode.removeExpiredClientSession();
return false;
}
if (!client.isEnabled()) {
- event.error(Errors.CLIENT_NOT_FOUND);
+ event.error(Errors.CLIENT_DISABLED);
response = ErrorPage.error(session, Messages.LOGIN_REQUESTER_NOT_ENABLED);
- // TODO:mposolda
- //session.sessions().removeClientSession(realm, clientSession);
+ clientCode.removeExpiredClientSession();
return false;
}
session.getContext().setClient(client);
- return true;
+
+
+ // Check if it's action or not
+ if (code == null) {
+ String lastExecFromSession = authSession.getAuthNote(AuthenticationProcessor.LAST_PROCESSED_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.infof("Transition between flows! Current flow: %s, Previous flow: %s", flowPath, lastFlow);
+
+ if (lastFlow == null || isFlowTransitionAllowed(lastFlow)) {
+ authSession.setAuthNote(AuthenticationProcessor.CURRENT_FLOW_PATH, flowPath);
+ authSession.removeAuthNote(AuthenticationProcessor.LAST_PROCESSED_EXECUTION);
+ lastExecFromSession = null;
+ }
+ }
+
+ if (ObjectUtil.isEqualOrBothNull(execution, lastExecFromSession)) {
+ // Allow refresh of previous page
+ clientCode = new ClientSessionCode<>(session, realm, authSession);
+ actionRequest = false;
+ return true;
+ } else {
+ logger.info("Redirecting to page expired page.");
+ response = showPageExpired(flowPath, authSession);
+ return false;
+ }
+ } else {
+ result = ClientSessionCode.parseResult(code, session, realm, AuthenticationSessionModel.class);
+ 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.LAST_PROCESSED_EXECUTION))) {
+ String latestFlowPath = authSession.getAuthNote(AuthenticationProcessor.CURRENT_FLOW_PATH);
+ URI redirectUri = getLastExecutionUrl(latestFlowPath, execution);
+ logger.infof("Invalid action code, but execution matches. So just redirecting to %s", redirectUri);
+ response = Response.status(Response.Status.FOUND).location(redirectUri).build();
+ } else {
+ response = showPageExpired(flowPath, authSession);
+ }
+ return false;
+ }
+
+
+ actionRequest = true;
+ authSession.setAuthNote(AuthenticationProcessor.LAST_PROCESSED_EXECUTION, execution);
+ return true;
+ }
+ }
+
+ private boolean isFlowTransitionAllowed(String lastFlow) {
+ if (flowPath.equals(AUTHENTICATE_PATH) && (lastFlow.equals(REGISTRATION_PATH) || lastFlow.equals(RESET_CREDENTIALS_PATH))) {
+ return true;
+ }
+
+ if (flowPath.equals(REGISTRATION_PATH) && (lastFlow.equals(AUTHENTICATE_PATH))) {
+ return true;
+ }
+
+ if (flowPath.equals(RESET_CREDENTIALS_PATH) && (lastFlow.equals(AUTHENTICATE_PATH))) {
+ return true;
+ }
+
+ return false;
}
public boolean verifyRequiredAction(String executedAction) {
@@ -322,23 +375,73 @@ public class LoginActionsService {
if (!isValidAction(ClientSessionModel.Action.REQUIRED_ACTIONS.name())) return false;
if (!isActionActive(ClientSessionCode.ActionType.USER)) return false;
- final LoginSessionModel loginSession = (LoginSessionModel) getClientSession();
+ final AuthenticationSessionModel authSession = getAuthenticationSession();
- if (executedAction == null) { // do next required action only if user is already authenticated
- initLoginEvent(loginSession);
- event.event(EventType.LOGIN);
- response = AuthenticationManager.nextActionAfterAuthentication(session, loginSession, clientConnection, request, uriInfo, event);
- return false;
+ if (actionRequest) {
+ String currentRequiredAction = authSession.getAuthNote(AuthenticationManager.CURRENT_REQUIRED_ACTION);
+ if (executedAction == null || !executedAction.equals(currentRequiredAction)) {
+ logger.debug("required action doesn't match current required action");
+ authSession.removeAuthNote(AuthenticationManager.CURRENT_REQUIRED_ACTION);
+ response = redirectToRequiredActions(currentRequiredAction, authSession);
+ return false;
+ }
}
+ return true;
+ }
+ }
- if (!executedAction.equals(loginSession.getNote(AuthenticationManager.CURRENT_REQUIRED_ACTION))) {
- logger.debug("required action doesn't match current required action");
- loginSession.removeNote(AuthenticationManager.CURRENT_REQUIRED_ACTION);
- response = redirectToRequiredActions(code);
- return false;
+
+ protected Response restartAuthenticationSession(boolean managedRestart) {
+ logger.infof("Login restart requested or authentication session not found. Trying to restart from cookie. Managed restart: %s", managedRestart);
+ AuthenticationSessionModel authSession = null;
+ try {
+ authSession = RestartLoginCookie.restartSession(session, realm);
+ } catch (Exception e) {
+ ServicesLogger.LOGGER.failedToParseRestartLoginCookie(e);
+ }
+
+ if (authSession != null) {
+
+ event.clone();
+
+ String warningMessage = null;
+ if (managedRestart) {
+ event.detail(Details.RESTART_REQUESTED, "true");
+ } else {
+ event.detail(Details.RESTART_AFTER_TIMEOUT, "true");
+ warningMessage = Messages.LOGIN_TIMEOUT;
}
- return true;
+
+ event.error(Errors.EXPIRED_CODE);
+ return processFlow(false, null, authSession, AUTHENTICATE_PATH, realm.getBrowserFlow(), warningMessage, new AuthenticationProcessor());
+ } else {
+ event.error(Errors.INVALID_CODE);
+ return ErrorPage.error(session, Messages.INVALID_CODE);
+ }
+ }
+
+
+ protected Response showPageExpired(String flowPath, AuthenticationSessionModel authSession) {
+ String executionId = authSession==null ? null : authSession.getAuthNote(AuthenticationProcessor.LAST_PROCESSED_EXECUTION);
+ String latestFlowPath = authSession==null ? flowPath : authSession.getAuthNote(AuthenticationProcessor.CURRENT_FLOW_PATH);
+ URI lastStepUrl = getLastExecutionUrl(latestFlowPath, executionId);
+
+ logger.infof("Redirecting to 'page expired' now. Will use URL: %s", lastStepUrl);
+
+ return session.getProvider(LoginFormsProvider.class)
+ .setActionUri(lastStepUrl)
+ .createLoginExpiredPage();
+ }
+
+
+ protected URI getLastExecutionUrl(String flowPath, String executionId) {
+ UriBuilder uriBuilder = LoginActionsService.loginActionsBaseUrl(uriInfo)
+ .path(flowPath);
+
+ if (executionId != null) {
+ uriBuilder.queryParam("execution", executionId);
}
+ return uriBuilder.build(realm.getName());
}
/**
@@ -350,33 +453,29 @@ public class LoginActionsService {
@Path(AUTHENTICATE_PATH)
@GET
public Response authenticate(@QueryParam("code") String code,
- @QueryParam("execution") String execution) {
+ @QueryParam("execution") String execution,
+ @QueryParam("restart") String restart) {
event.event(EventType.LOGIN);
- LoginSessionModel loginSession = ClientSessionCode.getClientSession(code, session, realm, LoginSessionModel.class);
- if (loginSession != null && code.equals(loginSession.getNote(LAST_PROCESSED_CODE))) {
- // Allow refresh of previous page
- } else {
- SessionCodeChecks<LoginSessionModel> checks = checksForCode(code, LoginSessionModel.class);
- if (!checks.verifyCode(ClientSessionModel.Action.AUTHENTICATE.name(), ClientSessionCode.ActionType.LOGIN)) {
- return checks.response;
- }
+ boolean wantsSessionRestart = Boolean.parseBoolean(restart);
- ClientSessionCode<LoginSessionModel> clientSessionCode = checks.clientCode;
- loginSession = clientSessionCode.getClientSession();
+ SessionCodeChecks checks = checksForCode(code, execution, AUTHENTICATE_PATH, wantsSessionRestart);
+ if (!checks.verifyCode(ClientSessionModel.Action.AUTHENTICATE.name(), ClientSessionCode.ActionType.LOGIN)) {
+ return checks.response;
}
- event.detail(Details.CODE_ID, code);
- loginSession.setNote(LAST_PROCESSED_CODE, code);
- return processAuthentication(execution, loginSession, null);
+ AuthenticationSessionModel authSession = checks.getAuthenticationSession();
+ boolean actionRequest = checks.actionRequest;
+
+ return processAuthentication(actionRequest, execution, authSession, null);
}
- protected Response processAuthentication(String execution, LoginSessionModel loginSession, String errorMessage) {
- return processFlow(execution, loginSession, AUTHENTICATE_PATH, realm.getBrowserFlow(), errorMessage, new AuthenticationProcessor());
+ protected Response processAuthentication(boolean action, String execution, AuthenticationSessionModel authSession, String errorMessage) {
+ return processFlow(action, execution, authSession, AUTHENTICATE_PATH, realm.getBrowserFlow(), errorMessage, new AuthenticationProcessor());
}
- protected Response processFlow(String execution, LoginSessionModel loginSession, String flowPath, AuthenticationFlowModel flow, String errorMessage, AuthenticationProcessor processor) {
- processor.setLoginSession(loginSession)
+ protected Response processFlow(boolean action, String execution, AuthenticationSessionModel authSession, String flowPath, AuthenticationFlowModel flow, String errorMessage, AuthenticationProcessor processor) {
+ processor.setAuthenticationSession(authSession)
.setFlowPath(flowPath)
.setBrowserFlow(true)
.setFlowId(flow.getId())
@@ -389,7 +488,7 @@ public class LoginActionsService {
if (errorMessage != null) processor.setForwardedErrorMessage(new FormMessage(null, errorMessage));
try {
- if (execution != null) {
+ if (action) {
return processor.authenticationAction(execution);
} else {
return processor.authenticate();
@@ -409,33 +508,14 @@ public class LoginActionsService {
@POST
public Response authenticateForm(@QueryParam("code") String code,
@QueryParam("execution") String execution) {
- event.event(EventType.LOGIN);
-
- LoginSessionModel loginSession = ClientSessionCode.getClientSession(code, session, realm, LoginSessionModel.class);
- if (loginSession != null && code.equals(loginSession.getNote(LAST_PROCESSED_CODE))) {
- // Post already processed (refresh) - ignore form post and return next form
- request.getFormParameters().clear();
- return authenticate(code, null);
- }
-
- SessionCodeChecks<LoginSessionModel> checks = checksForCode(code, LoginSessionModel.class);
- if (!checks.verifyCode(ClientSessionModel.Action.AUTHENTICATE.name(), ClientSessionCode.ActionType.LOGIN)) {
- return checks.response;
- }
- final ClientSessionCode<LoginSessionModel> clientCode = checks.clientCode;
- loginSession = clientCode.getClientSession();
- loginSession.setNote(LAST_PROCESSED_CODE, code);
-
- return processAuthentication(execution, loginSession, null);
+ return authenticate(code, execution, null);
}
@Path(RESET_CREDENTIALS_PATH)
@POST
public Response resetCredentialsPOST(@QueryParam("code") String code,
@QueryParam("execution") String execution) {
- // TODO:mposolda
- //return resetCredentials(code, execution);
- return null;
+ return resetCredentials(code, execution);
}
private boolean isSslUsed(JsonWebToken t) throws VerificationException {
@@ -456,7 +536,7 @@ public class LoginActionsService {
private boolean isResetCredentialsAllowed(ResetCredentialsActionToken t) throws VerificationException {
if (!realm.isResetPasswordAllowed()) {
- event.client(t.getClientSession().getClient());
+ event.client(t.getAuthenticationSession().getClient());
event.error(Errors.NOT_ALLOWED);
throw new LoginActionsServiceException(ErrorPage.error(session, Messages.RESET_CREDENTIAL_NOT_ALLOWED));
}
@@ -464,52 +544,59 @@ public class LoginActionsService {
}
private boolean canResolveClientSession(ResetCredentialsActionToken t) throws VerificationException {
- // TODO:mposolda
- /*
- String clientSessionId = t == null ? null : t.getNote(ResetCredentialsActionToken.NOTE_CLIENT_SESSION_ID);
+ String authSessionId = t == null ? null : t.getAuthenticationSessionId();
- if (t == null || clientSessionId == null) {
+ if (t == null || authSessionId == null) {
event.error(Errors.INVALID_CODE);
throw new LoginActionsServiceException(ErrorPage.error(session, Messages.INVALID_CODE));
}
- ClientSessionModel clientSession = session.sessions().getClientSession(clientSessionId);
- t.setClientSession(clientSession);
+ AuthenticationSessionModel authSession = session.authenticationSessions().getAuthenticationSession(realm, authSessionId);
+ t.setAuthenticationSession(authSession);
- if (clientSession == null) { // timeout
+ if (authSession == null) { // timeout or logged-already
try {
- clientSession = RestartLoginCookie.restartSessionByClientSession(session, realm, clientSessionId);
+ // Check if we are logged-already (it means userSession with same ID already exists). If yes, just showing the INFO or ERROR that user is already authenticated
+ // TODO:mposolda
+
+ // If not, try to restart authSession from the cookie
+ AuthenticationSessionModel restartedAuthSession = RestartLoginCookie.restartSession(session, realm);
+
+ // IDs must match with the ID from cookie
+ if (restartedAuthSession!=null && restartedAuthSession.getId().equals(authSessionId)) {
+ authSession = restartedAuthSession;
+ }
} catch (Exception e) {
ServicesLogger.LOGGER.failedToParseRestartLoginCookie(e);
}
- if (clientSession != null) {
+ if (authSession != null) {
event.clone().detail(Details.RESTART_AFTER_TIMEOUT, "true").error(Errors.EXPIRED_CODE);
- throw new LoginActionsServiceException(processFlow(null, clientSession, AUTHENTICATE_PATH, realm.getBrowserFlow(), Messages.LOGIN_TIMEOUT, new AuthenticationProcessor()));
+ throw new LoginActionsServiceException(processFlow(false, null, authSession, AUTHENTICATE_PATH, realm.getBrowserFlow(), Messages.LOGIN_TIMEOUT, new AuthenticationProcessor()));
}
}
- if (clientSession == null) {
+ if (authSession == null) {
event.error(Errors.INVALID_CODE);
throw new LoginActionsServiceException(ErrorPage.error(session, Messages.INVALID_CODE));
}
- event.detail(Details.CODE_ID, clientSession.getId());*/
+ event.detail(Details.CODE_ID, authSession.getId());
return true;
}
private boolean canResolveClient(ResetCredentialsActionToken t) throws VerificationException {
- ClientModel client = t.getClientSession().getClient();
+ ClientModel client = t.getAuthenticationSession().getClient();
if (client == null) {
event.error(Errors.CLIENT_NOT_FOUND);
- session.sessions().removeClientSession(realm, t.getClientSession());
+ session.authenticationSessions().removeAuthenticationSession(realm, t.getAuthenticationSession());
throw new LoginActionsServiceException(ErrorPage.error(session, Messages.UNKNOWN_LOGIN_REQUESTER));
}
if (! client.isEnabled()) {
event.error(Errors.CLIENT_NOT_FOUND);
- session.sessions().removeClientSession(realm, t.getClientSession());
+ session.authenticationSessions().removeAuthenticationSession(realm, t.getAuthenticationSession());
throw new LoginActionsServiceException(ErrorPage.error(session, Messages.LOGIN_REQUESTER_NOT_ENABLED));
}
session.getContext().setClient(client);
@@ -527,20 +614,22 @@ public class LoginActionsService {
@Override
public boolean test(ResetCredentialsActionToken t) throws VerificationException {
- ClientSessionModel clientSession = t.getClientSession();
- if (! Objects.equals(clientSession.getAction(), this.requiredAction)) {
+ AuthenticationSessionModel authSession = t.getAuthenticationSession();
+ if (! Objects.equals(authSession.getAction(), this.requiredAction)) {
- if (ClientSessionModel.Action.REQUIRED_ACTIONS.name().equals(clientSession.getAction())) {
+ if (ClientSessionModel.Action.REQUIRED_ACTIONS.name().equals(authSession.getAction())) {
// TODO: Once login tokens would be implemented, this would have to be rewritten
// String code = clientSession.getNote(ClientSessionCode.ACTIVE_CODE) + "." + clientSession.getId();
- String code = clientSession.getNote("active_code") + "." + clientSession.getId();
- throw new LoginActionsServiceException(redirectToRequiredActions(code));
- } else if (clientSession.getUserSession() != null && clientSession.getUserSession().getState() == UserSessionModel.State.LOGGED_IN) {
+ //String code = clientSession.getNote("active_code") + "." + clientSession.getId();
+ throw new LoginActionsServiceException(redirectToRequiredActions(null, authSession));
+ }
+ // TODO:mposolda Similar stuff is in SessionCodeChecks as well. The case when authSession is already logged should be handled similarly
+ /*else if (clientSession.getUserSession() != null && clientSession.getUserSession().getState() == UserSessionModel.State.LOGGED_IN) {
throw new LoginActionsServiceException(
session.getProvider(LoginFormsProvider.class)
.setSuccess(Messages.ALREADY_LOGGED_IN)
.createInfoPage());
- }
+ }*/
}
return true;
@@ -556,17 +645,16 @@ public class LoginActionsService {
@Override
public boolean test(ResetCredentialsActionToken t) throws VerificationException {
- int timestamp = t.getClientSession().getTimestamp();
+ int timestamp = t.getAuthenticationSession().getTimestamp();
if (! isActionActive(actionType, timestamp)) {
- event.client(t.getClientSession().getClient());
+ event.client(t.getAuthenticationSession().getClient());
event.clone().error(Errors.EXPIRED_CODE);
- if (t.getClientSession().getAction().equals(ClientSessionModel.Action.AUTHENTICATE.name())) {
- // TODO:mposolda incompatible types
- LoginSessionModel loginSession = (LoginSessionModel) t.getClientSession();
+ if (t.getAuthenticationSession().getAction().equals(ClientSessionModel.Action.AUTHENTICATE.name())) {
+ AuthenticationSessionModel authSession = t.getAuthenticationSession();
- AuthenticationProcessor.resetFlow(loginSession);
- throw new LoginActionsServiceException(processAuthentication(null, loginSession, Messages.LOGIN_TIMEOUT));
+ AuthenticationProcessor.resetFlow(authSession);
+ throw new LoginActionsServiceException(processAuthentication(false, null, authSession, Messages.LOGIN_TIMEOUT));
}
throw new LoginActionsServiceException(ErrorPage.error(session, Messages.EXPIRED_CODE));
@@ -608,8 +696,15 @@ public class LoginActionsService {
public Response resetCredentialsGET(@QueryParam("code") String code,
@QueryParam("execution") String execution,
@QueryParam("key") String key) {
+ if (code != null && key != null) {
+ // TODO:mposolda better handling of error
+ throw new IllegalStateException("Illegal state");
+ }
+
+ AuthenticationSessionModel authSession = session.authenticationSessions().getCurrentAuthenticationSession(realm);
+
// we allow applications to link to reset credentials without going through OAuth or SAML handshakes
- if (code == null && key == null) {
+ if (authSession == null && key == null) {
if (!realm.isResetPasswordAllowed()) {
event.event(EventType.RESET_PASSWORD);
event.error(Errors.NOT_ALLOWED);
@@ -618,24 +713,25 @@ public class LoginActionsService {
}
// set up the account service as the endpoint to call.
ClientModel client = realm.getClientByClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID);
- ClientSessionModel clientSession = session.sessions().createClientSession(realm, client);
- clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
- //clientSession.setNote(AuthenticationManager.END_AFTER_REQUIRED_ACTIONS, "true");
- clientSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
+ authSession = session.authenticationSessions().createAuthenticationSession(realm, client, true);
+ authSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
+ //authSession.setNote(AuthenticationManager.END_AFTER_REQUIRED_ACTIONS, "true");
+ authSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
String redirectUri = Urls.accountBase(uriInfo.getBaseUri()).path("/").build(realm.getName()).toString();
- clientSession.setRedirectUri(redirectUri);
- clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
- clientSession.setNote(OIDCLoginProtocol.RESPONSE_TYPE_PARAM, OAuth2Constants.CODE);
- clientSession.setNote(OIDCLoginProtocol.REDIRECT_URI_PARAM, redirectUri);
- clientSession.setNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()));
- return processResetCredentials(null, clientSession, null);
+ authSession.setRedirectUri(redirectUri);
+ authSession.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
+ authSession.setNote(OIDCLoginProtocol.RESPONSE_TYPE_PARAM, OAuth2Constants.CODE);
+ authSession.setNote(OIDCLoginProtocol.REDIRECT_URI_PARAM, redirectUri);
+ authSession.setNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()));
+ return processResetCredentials(false, null, authSession, null);
}
if (key != null) {
try {
ResetCredentialsActionToken token = ResetCredentialsActionToken.deserialize(
session, realm, session.getContext().getUri(), key);
- return resetCredentials(code, token, execution);
+
+ return resetCredentials(token, execution);
} catch (VerificationException ex) {
event.event(EventType.RESET_PASSWORD)
.detail(Details.REASON, ex.getMessage())
@@ -649,32 +745,30 @@ public class LoginActionsService {
/**
- * @deprecated In favor of {@link #resetCredentials(String, org.keycloak.authentication.ResetCredentialsActionToken, java.lang.String)}
+ * @deprecated In favor of {@link #resetCredentials(org.keycloak.authentication.ResetCredentialsActionToken, java.lang.String)}
* @param code
* @param execution
* @return
*/
protected Response resetCredentials(String code, String execution) {
event.event(EventType.RESET_PASSWORD);
- SessionCodeChecks<LoginSessionModel> checks = checksForCode(code, LoginSessionModel.class);
+ SessionCodeChecks checks = checksForCode(code, execution, RESET_CREDENTIALS_PATH, false);
if (!checks.verifyCode(ClientSessionModel.Action.AUTHENTICATE.name(), ClientSessionCode.ActionType.USER)) {
return checks.response;
}
- final LoginSessionModel clientSession = checks.getClientSession();
+ final AuthenticationSessionModel authSession = checks.getAuthenticationSession();
if (!realm.isResetPasswordAllowed()) {
- event.client(clientSession.getClient());
+ event.client(authSession.getClient());
event.error(Errors.NOT_ALLOWED);
return ErrorPage.error(session, Messages.RESET_CREDENTIAL_NOT_ALLOWED);
}
- // TODO:mposolda
- //return processResetCredentials(execution, clientSession, null);
- return null;
+ return processResetCredentials(checks.actionRequest, execution, authSession, null);
}
- protected Response resetCredentials(String code, ResetCredentialsActionToken token, String execution) {
+ protected Response resetCredentials(ResetCredentialsActionToken token, String execution) {
event.event(EventType.RESET_PASSWORD);
if (token == null) {
@@ -712,43 +806,100 @@ public class LoginActionsService {
return ErrorPage.error(session, Messages.RESET_CREDENTIAL_NOT_ALLOWED);
}
- final ClientSessionModel clientSession = token.getClientSession();
+ final AuthenticationSessionModel authSession = token.getAuthenticationSession();
+
+ // Verify if action is processed in same browser.
+ if (!isSameBrowser(authSession)) {
+ logger.infof("Action request processed in different browser!");
+
+ // TODO:mposolda improve this. The code should be merged with the InfinispanLoginSessionProvider code and rather extracted from the infinispan provider
+ setAuthSessionCookie(authSession.getId());
- return processResetCredentials(execution, clientSession, null);
+ authSession.setAuthNote(AuthenticationManager.END_AFTER_REQUIRED_ACTIONS, "true");
+ }
+
+ return processResetCredentials(true, execution, authSession, null);
}
- protected Response processResetCredentials(String execution, ClientSessionModel clientSession, String errorMessage) {
- // TODO:mposolda
- /*
+
+ // Verify if action is processed in same browser.
+ private boolean isSameBrowser(AuthenticationSessionModel actionTokenSession) {
+ String cookieSessionId = session.authenticationSessions().getCurrentAuthenticationSessionId(realm);
+
+ if (cookieSessionId == null) {
+ return false;
+ }
+
+ if (actionTokenSession.getId().equals(cookieSessionId)) {
+ return true;
+ }
+
+ // Chance that cookie session was "forked" in browser from some other session
+ AuthenticationSessionModel forkedSession = session.authenticationSessions().getAuthenticationSession(realm, cookieSessionId);
+ if (forkedSession == null) {
+ return false;
+ }
+
+ String parentSessionId = forkedSession.getAuthNote(AuthenticationProcessor.FORKED_FROM);
+ if (parentSessionId == null) {
+ return false;
+ }
+
+ if (actionTokenSession.getId().equals(parentSessionId)) {
+ // It's the the correct browser. Let's remove forked session as we won't continue from the login form (browser flow) but from the resetCredentials flow
+ session.authenticationSessions().removeAuthenticationSession(realm, forkedSession);
+ logger.infof("Removed forked session: %s", forkedSession.getId());
+
+ // Refresh browser cookie
+ setAuthSessionCookie(parentSessionId);
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ // TODO:mposolda improve this. The code should be merged with the InfinispanLoginSessionProvider code and rather extracted from the infinispan provider
+ private void setAuthSessionCookie(String authSessionId) {
+ logger.infof("Set browser cookie to %s", authSessionId);
+
+ String cookiePath = CookieHelper.getRealmCookiePath(realm);
+ boolean sslRequired = realm.getSslRequired().isRequired(session.getContext().getConnection());
+ CookieHelper.addCookie("AUTH_SESSION_ID", authSessionId, cookiePath, null, null, -1, sslRequired, true);
+ }
+
+
+
+ protected Response processResetCredentials(boolean actionRequest, String execution, AuthenticationSessionModel authSession, String errorMessage) {
AuthenticationProcessor authProcessor = new AuthenticationProcessor() {
@Override
protected Response authenticationComplete() {
- boolean firstBrokerLoginInProgress = (clientSession.getNote(AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE) != null);
+ boolean firstBrokerLoginInProgress = (authenticationSession.getAuthNote(AbstractIdpAuthenticator.BROKERED_CONTEXT_NOTE) != null);
if (firstBrokerLoginInProgress) {
- UserModel linkingUser = AbstractIdpAuthenticator.getExistingUser(session, realm, clientSession);
- if (!linkingUser.getId().equals(clientSession.getAuthenticatedUser().getId())) {
- return ErrorPage.error(session, Messages.IDENTITY_PROVIDER_DIFFERENT_USER_MESSAGE, clientSession.getAuthenticatedUser().getUsername(), linkingUser.getUsername());
+ UserModel linkingUser = AbstractIdpAuthenticator.getExistingUser(session, realm, authenticationSession);
+ if (!linkingUser.getId().equals(authenticationSession.getAuthenticatedUser().getId())) {
+ return ErrorPage.error(session, Messages.IDENTITY_PROVIDER_DIFFERENT_USER_MESSAGE, authenticationSession.getAuthenticatedUser().getUsername(), linkingUser.getUsername());
}
logger.debugf("Forget-password flow finished when authenticated user '%s' after first broker login.", linkingUser.getUsername());
- return redirectToAfterBrokerLoginEndpoint(clientSession, true);
+ // TODO:mposolda Isn't this a bug that we redirect to 'afterBrokerLoginEndpoint' without rather continue with firstBrokerLogin and other authenticators like OTP?
+ //return redirectToAfterBrokerLoginEndpoint(authSession, true);
+ return null;
} else {
return super.authenticationComplete();
}
}
};
- return processFlow(execution, clientSession, RESET_CREDENTIALS_PATH, realm.getResetCredentialsFlow(), errorMessage, authProcessor);
- */
- return null;
+ return processFlow(actionRequest, execution, authSession, RESET_CREDENTIALS_PATH, realm.getResetCredentialsFlow(), errorMessage, authProcessor);
}
- protected Response processRegistration(String execution, LoginSessionModel loginSession, String errorMessage) {
- return processFlow(execution, loginSession, REGISTRATION_PATH, realm.getRegistrationFlow(), errorMessage, new AuthenticationProcessor());
+ protected Response processRegistration(boolean action, String execution, AuthenticationSessionModel authSession, String errorMessage) {
+ return processFlow(action, execution, authSession, REGISTRATION_PATH, realm.getRegistrationFlow(), errorMessage, new AuthenticationProcessor());
}
@@ -762,24 +913,7 @@ public class LoginActionsService {
@GET
public Response registerPage(@QueryParam("code") String code,
@QueryParam("execution") String execution) {
- event.event(EventType.REGISTER);
- if (!realm.isRegistrationAllowed()) {
- event.error(Errors.REGISTRATION_DISABLED);
- return ErrorPage.error(session, Messages.REGISTRATION_NOT_ALLOWED);
- }
-
- SessionCodeChecks<LoginSessionModel> checks = checksForCode(code, LoginSessionModel.class);
- if (!checks.verifyCode(ClientSessionModel.Action.AUTHENTICATE.name(), ClientSessionCode.ActionType.LOGIN)) {
- return checks.response;
- }
- event.detail(Details.CODE_ID, code);
- ClientSessionCode<LoginSessionModel> clientSessionCode = checks.clientCode;
- LoginSessionModel clientSession = clientSessionCode.getClientSession();
-
-
- AuthenticationManager.expireIdentityCookie(realm, uriInfo, clientConnection);
-
- return processRegistration(execution, clientSession, null);
+ return registerRequest(code, execution, false);
}
@@ -793,20 +927,31 @@ public class LoginActionsService {
@POST
public Response processRegister(@QueryParam("code") String code,
@QueryParam("execution") String execution) {
+ return registerRequest(code, execution, true);
+ }
+
+
+ private Response registerRequest(String code, String execution, boolean isPostRequest) {
event.event(EventType.REGISTER);
if (!realm.isRegistrationAllowed()) {
event.error(Errors.REGISTRATION_DISABLED);
return ErrorPage.error(session, Messages.REGISTRATION_NOT_ALLOWED);
}
- SessionCodeChecks checks = checksForCode(code, LoginSessionModel.class);
+
+ SessionCodeChecks checks = checksForCode(code, execution, REGISTRATION_PATH, false);
if (!checks.verifyCode(ClientSessionModel.Action.AUTHENTICATE.name(), ClientSessionCode.ActionType.LOGIN)) {
return checks.response;
}
+ ClientSessionCode<AuthenticationSessionModel> clientSessionCode = checks.clientCode;
+ AuthenticationSessionModel clientSession = clientSessionCode.getClientSession();
+
+ // TODO:mposolda any consequences to do this for POST request too?
+ if (!isPostRequest) {
+ AuthenticationManager.expireIdentityCookie(realm, uriInfo, clientConnection);
+ }
- ClientSessionCode<LoginSessionModel> clientCode = checks.clientCode;
- LoginSessionModel loginSession = clientCode.getClientSession();
- return processRegistration(execution, loginSession, null);
+ return processRegistration(checks.actionRequest, execution, clientSession, null);
}
// TODO:mposolda broker login
@@ -917,27 +1062,27 @@ public class LoginActionsService {
public Response processConsent(final MultivaluedMap<String, String> formData) {
event.event(EventType.LOGIN);
String code = formData.getFirst("code");
- SessionCodeChecks<LoginSessionModel> checks = checksForCode(code, LoginSessionModel.class);
+ SessionCodeChecks checks = checksForCode(code, null, REQUIRED_ACTION, false);
if (!checks.verifyRequiredAction(ClientSessionModel.Action.OAUTH_GRANT.name())) {
return checks.response;
}
- ClientSessionCode<LoginSessionModel> accessCode = checks.clientCode;
- LoginSessionModel loginSession = accessCode.getClientSession();
+ ClientSessionCode<AuthenticationSessionModel> accessCode = checks.clientCode;
+ AuthenticationSessionModel authSession = accessCode.getClientSession();
- initLoginEvent(loginSession);
+ initLoginEvent(authSession);
- UserModel user = loginSession.getAuthenticatedUser();
- ClientModel client = loginSession.getClient();
+ UserModel user = authSession.getAuthenticatedUser();
+ ClientModel client = authSession.getClient();
if (formData.containsKey("cancel")) {
- LoginProtocol protocol = session.getProvider(LoginProtocol.class, loginSession.getProtocol());
+ LoginProtocol protocol = session.getProvider(LoginProtocol.class, authSession.getProtocol());
protocol.setRealm(realm)
.setHttpHeaders(headers)
.setUriInfo(uriInfo)
.setEventBuilder(event);
- Response response = protocol.sendError(loginSession, Error.CONSENT_DENIED);
+ Response response = protocol.sendError(authSession, Error.CONSENT_DENIED);
event.error(Errors.REJECTED_BY_USER);
return response;
}
@@ -961,8 +1106,8 @@ public class LoginActionsService {
event.success();
// TODO:mposolda So assume that requiredActions were already done in this stage. Doublecheck...
- ClientLoginSessionModel clientSession = AuthenticationProcessor.attachSession(loginSession, null, session, realm, clientConnection, event);
- return AuthenticationManager.redirectAfterSuccessfulFlow(session, realm, clientSession.getUserSession(), clientSession, request, uriInfo, clientConnection, event, loginSession.getProtocol());
+ AuthenticatedClientSessionModel clientSession = AuthenticationProcessor.attachSession(authSession, null, session, realm, clientConnection, event);
+ return AuthenticationManager.redirectAfterSuccessfulFlow(session, realm, clientSession.getUserSession(), clientSession, request, uriInfo, clientConnection, event, authSession.getProtocol());
}
@Path("email-verification")
@@ -1040,7 +1185,7 @@ public class LoginActionsService {
return session.getProvider(LoginFormsProvider.class)
.setClientSessionCode(accessCode.getCode())
- .setClientSession(clientSession)
+ .setAuthenticationSession(clientSession)
.setUser(userSession.getUser())
.createResponse(RequiredAction.VERIFY_EMAIL);
}*/
@@ -1092,57 +1237,38 @@ public class LoginActionsService {
CookieHelper.addCookie(ACTION_COOKIE, sessionId, AuthenticationManager.getRealmCookiePath(realm, uriInfo), null, null, -1, realm.getSslRequired().isRequired(clientConnection), true);
}
- private void initEvent(ClientSessionModel clientSession) {
- UserSessionModel userSession = clientSession.getUserSession();
-
- String responseType = clientSession.getNote(OIDCLoginProtocol.RESPONSE_TYPE_PARAM);
- if (responseType == null) {
- responseType = "code";
- }
- String respMode = clientSession.getNote(OIDCLoginProtocol.RESPONSE_MODE_PARAM);
- OIDCResponseMode responseMode = OIDCResponseMode.parse(respMode, OIDCResponseType.parse(responseType));
-
- event.event(EventType.LOGIN).client(clientSession.getClient())
- .user(userSession.getUser())
- .session(userSession.getId())
- .detail(Details.CODE_ID, clientSession.getId())
- .detail(Details.REDIRECT_URI, clientSession.getRedirectUri())
- .detail(Details.USERNAME, clientSession.getNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME))
- .detail(Details.AUTH_METHOD, userSession.getAuthMethod())
- .detail(Details.USERNAME, userSession.getLoginUsername())
- .detail(Details.RESPONSE_TYPE, responseType)
- .detail(Details.RESPONSE_MODE, responseMode.toString().toLowerCase())
- .detail(Details.IDENTITY_PROVIDER, userSession.getNote(Details.IDENTITY_PROVIDER))
- .detail(Details.IDENTITY_PROVIDER_USERNAME, userSession.getNote(Details.IDENTITY_PROVIDER_USERNAME));
-
- if (userSession.isRememberMe()) {
- event.detail(Details.REMEMBER_ME, "true");
- }
- }
-
- private void initLoginEvent(LoginSessionModel loginSession) {
- String responseType = loginSession.getNote(OIDCLoginProtocol.RESPONSE_TYPE_PARAM);
+ private void initLoginEvent(AuthenticationSessionModel authSession) {
+ String responseType = authSession.getNote(OIDCLoginProtocol.RESPONSE_TYPE_PARAM);
if (responseType == null) {
responseType = "code";
}
- String respMode = loginSession.getNote(OIDCLoginProtocol.RESPONSE_MODE_PARAM);
+ String respMode = authSession.getNote(OIDCLoginProtocol.RESPONSE_MODE_PARAM);
OIDCResponseMode responseMode = OIDCResponseMode.parse(respMode, OIDCResponseType.parse(responseType));
- event.event(EventType.LOGIN).client(loginSession.getClient())
- .detail(Details.CODE_ID, loginSession.getId())
- .detail(Details.REDIRECT_URI, loginSession.getRedirectUri())
- .detail(Details.AUTH_METHOD, loginSession.getProtocol())
+ event.event(EventType.LOGIN).client(authSession.getClient())
+ .detail(Details.CODE_ID, authSession.getId())
+ .detail(Details.REDIRECT_URI, authSession.getRedirectUri())
+ .detail(Details.AUTH_METHOD, authSession.getProtocol())
.detail(Details.RESPONSE_TYPE, responseType)
.detail(Details.RESPONSE_MODE, responseMode.toString().toLowerCase());
- UserModel authenticatedUser = loginSession.getAuthenticatedUser();
+ UserModel authenticatedUser = authSession.getAuthenticatedUser();
if (authenticatedUser != null) {
event.user(authenticatedUser)
.detail(Details.USERNAME, authenticatedUser.getUsername());
- } else {
- event.detail(Details.USERNAME, loginSession.getNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME));
}
+ String attemptedUsername = authSession.getAuthNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME);
+ if (attemptedUsername != null) {
+ event.detail(Details.USERNAME, attemptedUsername);
+ }
+
+ String rememberMe = authSession.getAuthNote(Details.REMEMBER_ME);
+ if (rememberMe==null || !rememberMe.equalsIgnoreCase("true")) {
+ rememberMe = "false";
+ }
+ event.detail(Details.REMEMBER_ME, rememberMe);
+
// TODO:mposolda Fix if this is called at firstBroker or postBroker login
/*
.detail(Details.IDENTITY_PROVIDER, userSession.getNote(Details.IDENTITY_PROVIDER))
@@ -1153,32 +1279,33 @@ public class LoginActionsService {
@Path(REQUIRED_ACTION)
@POST
public Response requiredActionPOST(@QueryParam("code") final String code,
- @QueryParam("action") String action) {
+ @QueryParam("execution") String action) {
return processRequireAction(code, action);
-
-
-
}
@Path(REQUIRED_ACTION)
@GET
public Response requiredActionGET(@QueryParam("code") final String code,
- @QueryParam("action") String action) {
+ @QueryParam("execution") String action) {
return processRequireAction(code, action);
}
private Response processRequireAction(final String code, String action) {
- // TODO:mposolda
- /*
- event.event(EventType.CUSTOM_REQUIRED_ACTION);
- event.detail(Details.CUSTOM_REQUIRED_ACTION, action);
- SessionCodeChecks checks = checksForCode(code);
+ SessionCodeChecks checks = checksForCode(code, action, REQUIRED_ACTION, false);
if (!checks.verifyRequiredAction(action)) {
return checks.response;
}
- final ClientSessionModel clientSession = checks.getClientSession();
- final UserSessionModel userSession = clientSession.getUserSession();
+ AuthenticationSessionModel authSession = checks.getAuthenticationSession();
+ if (!checks.actionRequest) {
+ initLoginEvent(authSession);
+ event.event(EventType.CUSTOM_REQUIRED_ACTION);
+ return AuthenticationManager.nextActionAfterAuthentication(session, authSession, clientConnection, request, uriInfo, event);
+ }
+
+ initLoginEvent(authSession);
+ event.event(EventType.CUSTOM_REQUIRED_ACTION);
+ event.detail(Details.CUSTOM_REQUIRED_ACTION, action);
RequiredActionFactory factory = (RequiredActionFactory)session.getKeycloakSessionFactory().getProviderFactory(RequiredActionProvider.class, action);
if (factory == null) {
@@ -1188,11 +1315,7 @@ public class LoginActionsService {
}
RequiredActionProvider provider = factory.create(session);
- initEvent(clientSession);
- event.event(EventType.CUSTOM_REQUIRED_ACTION);
-
-
- RequiredActionContextResult context = new RequiredActionContextResult(userSession, clientSession, realm, event, session, request, userSession.getUser(), factory) {
+ RequiredActionContextResult context = new RequiredActionContextResult(authSession, realm, event, session, request, authSession.getAuthenticatedUser(), factory) {
@Override
public void ignore() {
throw new RuntimeException("Cannot call ignore within processAction()");
@@ -1201,46 +1324,44 @@ public class LoginActionsService {
provider.processAction(context);
if (context.getStatus() == RequiredActionContext.Status.SUCCESS) {
event.clone().success();
- initEvent(clientSession);
+ initLoginEvent(authSession);
event.event(EventType.LOGIN);
- clientSession.removeRequiredAction(factory.getId());
- userSession.getUser().removeRequiredAction(factory.getId());
- clientSession.removeNote(AuthenticationManager.CURRENT_REQUIRED_ACTION);
-
- if (AuthenticationManager.isActionRequired(session, userSession, clientSession, clientConnection, request, uriInfo, event)) {
- // redirect to a generic code URI so that browser refresh will work
- return redirectToRequiredActions(checks.clientCode.getCode());
- } else {
- return AuthenticationManager.finishedRequiredActions(session, userSession, clientSession, clientConnection, request, uriInfo, event);
+ authSession.removeRequiredAction(factory.getId());
+ authSession.getAuthenticatedUser().removeRequiredAction(factory.getId());
+ authSession.removeAuthNote(AuthenticationManager.CURRENT_REQUIRED_ACTION);
- }
+ return redirectToRequiredActions(action, authSession);
}
if (context.getStatus() == RequiredActionContext.Status.CHALLENGE) {
return context.getChallenge();
}
if (context.getStatus() == RequiredActionContext.Status.FAILURE) {
- LoginProtocol protocol = context.getSession().getProvider(LoginProtocol.class, context.getClientSession().getAuthMethod());
+ LoginProtocol protocol = context.getSession().getProvider(LoginProtocol.class, authSession.getProtocol());
protocol.setRealm(context.getRealm())
.setHttpHeaders(context.getHttpRequest().getHttpHeaders())
.setUriInfo(context.getUriInfo())
.setEventBuilder(event);
event.detail(Details.CUSTOM_REQUIRED_ACTION, action);
- Response response = protocol.sendError(context.getClientSession(), Error.CONSENT_DENIED);
+ Response response = protocol.sendError(authSession, Error.CONSENT_DENIED);
event.error(Errors.REJECTED_BY_USER);
return response;
}
throw new RuntimeException("Unreachable");
- */
- return null;
}
- private Response redirectToRequiredActions(String code) {
- URI redirect = LoginActionsService.loginActionsBaseUrl(uriInfo)
- .path(LoginActionsService.REQUIRED_ACTION)
- .queryParam(OAuth2Constants.CODE, code).build(realm.getName());
+ private Response redirectToRequiredActions(String action, AuthenticationSessionModel authSession) {
+ authSession.setAuthNote(AuthenticationProcessor.LAST_PROCESSED_EXECUTION, action);
+
+ UriBuilder uriBuilder = LoginActionsService.loginActionsBaseUrl(uriInfo)
+ .path(LoginActionsService.REQUIRED_ACTION);
+
+ if (action != null) {
+ uriBuilder.queryParam("execution", action);
+ }
+ URI redirect = uriBuilder.build(realm.getName());
return Response.status(302).location(redirect).build();
}
diff --git a/services/src/main/java/org/keycloak/services/Urls.java b/services/src/main/java/org/keycloak/services/Urls.java
index 21eb047..8735cc8 100755
--- a/services/src/main/java/org/keycloak/services/Urls.java
+++ b/services/src/main/java/org/keycloak/services/Urls.java
@@ -206,6 +206,12 @@ public class Urls {
return loginActionsBase(baseUri).path(LoginActionsService.class, "authenticate").build(realmName);
}
+ public static URI realmLoginRestartPage(URI baseUri, String realmId) {
+ return loginActionsBase(baseUri).path(LoginActionsService.class, "authenticate")
+ .queryParam("restart", "true")
+ .build(realmId);
+ }
+
private static UriBuilder realmLogout(URI baseUri) {
return tokenBase(baseUri).path(OIDCLoginProtocolService.class, "logout");
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/AuthenticationSessionProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/AuthenticationSessionProviderTest.java
new file mode 100644
index 0000000..e747683
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/AuthenticationSessionProviderTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.model;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserManager;
+import org.keycloak.models.UserModel;
+import org.keycloak.sessions.AuthenticationSessionModel;
+import org.keycloak.testsuite.rule.KeycloakRule;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class AuthenticationSessionProviderTest {
+
+ @ClassRule
+ public static KeycloakRule kc = new KeycloakRule();
+
+ private KeycloakSession session;
+ private RealmModel realm;
+
+ @Before
+ public void before() {
+ session = kc.startSession();
+ realm = session.realms().getRealm("test");
+ session.users().addUser(realm, "user1").setEmail("user1@localhost");
+ session.users().addUser(realm, "user2").setEmail("user2@localhost");
+ }
+
+ @After
+ public void after() {
+ resetSession();
+ session.sessions().removeUserSessions(realm);
+ UserModel user1 = session.users().getUserByUsername("user1", realm);
+ UserModel user2 = session.users().getUserByUsername("user2", realm);
+
+ UserManager um = new UserManager(session);
+ if (user1 != null) {
+ um.removeUser(realm, user1);
+ }
+ if (user2 != null) {
+ um.removeUser(realm, user2);
+ }
+ kc.stopSession(session, true);
+ }
+
+ private void resetSession() {
+ kc.stopSession(session, true);
+ session = kc.startSession();
+ realm = session.realms().getRealm("test");
+ }
+
+ @Test
+ public void testLoginSessionsCRUD() {
+ ClientModel client1 = realm.getClientByClientId("test-app");
+ UserModel user1 = session.users().getUserByUsername("user1", realm);
+
+ AuthenticationSessionModel authSession = session.authenticationSessions().createAuthenticationSession(realm, client1, false);
+
+ authSession.setAction("foo");
+ authSession.setTimestamp(100);
+
+ resetSession();
+
+ // Ensure session is here
+ authSession = session.authenticationSessions().getAuthenticationSession(realm, authSession.getId());
+ testLoginSession(authSession, client1.getId(), null, "foo", 100);
+
+ // Update and commit
+ authSession.setAction("foo-updated");
+ authSession.setTimestamp(200);
+ authSession.setAuthenticatedUser(session.users().getUserByUsername("user1", realm));
+
+ resetSession();
+
+ // Ensure session was updated
+ authSession = session.authenticationSessions().getAuthenticationSession(realm, authSession.getId());
+ testLoginSession(authSession, client1.getId(), user1.getId(), "foo-updated", 200);
+
+ // Remove and commit
+ session.authenticationSessions().removeAuthenticationSession(realm, authSession);
+
+ resetSession();
+
+ // Ensure session was removed
+ Assert.assertNull(session.authenticationSessions().getAuthenticationSession(realm, authSession.getId()));
+
+ }
+
+ private void testLoginSession(AuthenticationSessionModel authSession, String expectedClientId, String expectedUserId, String expectedAction, int expectedTimestamp) {
+ Assert.assertEquals(expectedClientId, authSession.getClient().getId());
+ if (expectedUserId == null) {
+ Assert.assertNull(authSession.getAuthenticatedUser());
+ } else {
+ Assert.assertEquals(expectedUserId, authSession.getAuthenticatedUser().getId());
+ }
+ Assert.assertEquals(expectedAction, authSession.getAction());
+ Assert.assertEquals(expectedTimestamp, authSession.getTimestamp());
+ }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java
index 534bff3..4e13b30 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java
@@ -23,6 +23,7 @@ import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.keycloak.common.util.Time;
+import org.keycloak.models.AuthenticatedClientSessionModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.KeycloakSession;
@@ -38,6 +39,7 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import static org.junit.Assert.assertArrayEquals;
@@ -52,577 +54,648 @@ import static org.junit.Assert.assertTrue;
*/
public class UserSessionProviderTest {
- // TODO:mposolda
-//
-// @ClassRule
-// public static KeycloakRule kc = new KeycloakRule();
-//
-// private KeycloakSession session;
-// private RealmModel realm;
-//
-// @Before
-// public void before() {
-// session = kc.startSession();
-// realm = session.realms().getRealm("test");
-// session.users().addUser(realm, "user1").setEmail("user1@localhost");
-// session.users().addUser(realm, "user2").setEmail("user2@localhost");
-// }
-//
-// @After
-// public void after() {
-// resetSession();
-// session.sessions().removeUserSessions(realm);
-// UserModel user1 = session.users().getUserByUsername("user1", realm);
-// UserModel user2 = session.users().getUserByUsername("user2", realm);
-//
-// UserManager um = new UserManager(session);
-// if (user1 != null) {
-// um.removeUser(realm, user1);
-// }
-// if (user2 != null) {
-// um.removeUser(realm, user2);
-// }
-// kc.stopSession(session, true);
-// }
-//
-// @Test
-// public void testCreateSessions() {
-// int started = Time.currentTime();
-// UserSessionModel[] sessions = createSessions();
-//
-// assertSession(session.sessions().getUserSession(realm, sessions[0].getId()), session.users().getUserByUsername("user1", realm), "127.0.0.1", started, started, "test-app", "third-party");
-// assertSession(session.sessions().getUserSession(realm, sessions[1].getId()), session.users().getUserByUsername("user1", realm), "127.0.0.2", started, started, "test-app");
-// assertSession(session.sessions().getUserSession(realm, sessions[2].getId()), session.users().getUserByUsername("user2", realm), "127.0.0.3", started, started, "test-app");
-// }
-//
-// @Test
-// public void testUpdateSession() {
-// UserSessionModel[] sessions = createSessions();
-// session.sessions().getUserSession(realm, sessions[0].getId()).setLastSessionRefresh(1000);
-//
-// resetSession();
-//
-// assertEquals(1000, session.sessions().getUserSession(realm, sessions[0].getId()).getLastSessionRefresh());
-// }
-//
-// @Test
-// public void testCreateClientSession() {
-// UserSessionModel[] sessions = createSessions();
-//
-// List<ClientSessionModel> clientSessions = session.sessions().getUserSession(realm, sessions[0].getId()).getClientSessions();
-// assertEquals(2, clientSessions.size());
-//
-// String client1 = realm.getClientByClientId("test-app").getId();
-//
-// ClientSessionModel session1;
-//
-// if (clientSessions.get(0).getClient().getId().equals(client1)) {
-// session1 = clientSessions.get(0);
-// } else {
-// session1 = clientSessions.get(1);
-// }
-//
-// assertEquals(null, session1.getAction());
-// assertEquals(realm.getClientByClientId("test-app").getClientId(), session1.getClient().getClientId());
-// assertEquals(sessions[0].getId(), session1.getUserSession().getId());
-// assertEquals("http://redirect", session1.getRedirectUri());
-// assertEquals("state", session1.getNote(OIDCLoginProtocol.STATE_PARAM));
-// assertEquals(2, session1.getRoles().size());
-// assertTrue(session1.getRoles().contains("one"));
-// assertTrue(session1.getRoles().contains("two"));
-// assertEquals(2, session1.getProtocolMappers().size());
-// assertTrue(session1.getProtocolMappers().contains("mapper-one"));
-// assertTrue(session1.getProtocolMappers().contains("mapper-two"));
-// }
-//
-// @Test
-// public void testUpdateClientSession() {
-// UserSessionModel[] sessions = createSessions();
-//
-// String id = sessions[0].getClientSessions().get(0).getId();
-//
-// ClientSessionModel clientSession = session.sessions().getClientSession(realm, id);
-//
-// int time = clientSession.getTimestamp();
-// assertEquals(null, clientSession.getAction());
-//
-// clientSession.setAction(ClientSessionModel.Action.CODE_TO_TOKEN.name());
-// clientSession.setTimestamp(time + 10);
-//
-// kc.stopSession(session, true);
-// session = kc.startSession();
-//
-// ClientSessionModel updated = session.sessions().getClientSession(realm, id);
-// assertEquals(ClientSessionModel.Action.CODE_TO_TOKEN.name(), updated.getAction());
-// assertEquals(time + 10, updated.getTimestamp());
-// }
-//
-// @Test
-// public void testGetUserSessions() {
-// UserSessionModel[] sessions = createSessions();
-//
-// assertSessions(session.sessions().getUserSessions(realm, session.users().getUserByUsername("user1", realm)), sessions[0], sessions[1]);
-// assertSessions(session.sessions().getUserSessions(realm, session.users().getUserByUsername("user2", realm)), sessions[2]);
-// }
-//
-// @Test
-// public void testRemoveUserSessionsByUser() {
-// UserSessionModel[] sessions = createSessions();
-//
-// List<String> clientSessionsRemoved = new LinkedList<String>();
-// List<String> clientSessionsKept = new LinkedList<String>();
-// for (UserSessionModel s : sessions) {
-// s = session.sessions().getUserSession(realm, s.getId());
-//
-// for (ClientSessionModel c : s.getClientSessions()) {
-// if (c.getUserSession().getUser().getUsername().equals("user1")) {
-// clientSessionsRemoved.add(c.getId());
-// } else {
-// clientSessionsKept.add(c.getId());
-// }
-// }
-// }
-//
-// session.sessions().removeUserSessions(realm, session.users().getUserByUsername("user1", realm));
-// resetSession();
-//
-// assertTrue(session.sessions().getUserSessions(realm, session.users().getUserByUsername("user1", realm)).isEmpty());
-// assertFalse(session.sessions().getUserSessions(realm, session.users().getUserByUsername("user2", realm)).isEmpty());
-//
-// for (String c : clientSessionsRemoved) {
-// assertNull(session.sessions().getClientSession(realm, c));
-// }
-// for (String c : clientSessionsKept) {
-// assertNotNull(session.sessions().getClientSession(realm, c));
-// }
-// }
-//
-// @Test
-// public void testRemoveUserSession() {
-// UserSessionModel userSession = createSessions()[0];
-//
-// List<String> clientSessionsRemoved = new LinkedList<String>();
-// for (ClientSessionModel c : userSession.getClientSessions()) {
-// clientSessionsRemoved.add(c.getId());
-// }
-//
-// session.sessions().removeUserSession(realm, userSession);
-// resetSession();
-//
-// assertNull(session.sessions().getUserSession(realm, userSession.getId()));
-// for (String c : clientSessionsRemoved) {
-// assertNull(session.sessions().getClientSession(realm, c));
-// }
-// }
-//
-// @Test
-// public void testRemoveUserSessionsByRealm() {
-// UserSessionModel[] sessions = createSessions();
-//
-// List<ClientSessionModel> clientSessions = new LinkedList<ClientSessionModel>();
-// for (UserSessionModel s : sessions) {
-// clientSessions.addAll(s.getClientSessions());
-// }
-//
-// session.sessions().removeUserSessions(realm);
-// resetSession();
-//
-// assertTrue(session.sessions().getUserSessions(realm, session.users().getUserByUsername("user1", realm)).isEmpty());
-// assertTrue(session.sessions().getUserSessions(realm, session.users().getUserByUsername("user2", realm)).isEmpty());
-//
-// for (ClientSessionModel c : clientSessions) {
-// assertNull(session.sessions().getClientSession(realm, c.getId()));
-// }
-// }
-//
-// @Test
-// public void testOnClientRemoved() {
-// UserSessionModel[] sessions = createSessions();
-//
-// List<String> clientSessionsRemoved = new LinkedList<String>();
-// List<String> clientSessionsKept = new LinkedList<String>();
-// for (UserSessionModel s : sessions) {
-// s = session.sessions().getUserSession(realm, s.getId());
-// for (ClientSessionModel c : s.getClientSessions()) {
-// if (c.getClient().getClientId().equals("third-party")) {
-// clientSessionsRemoved.add(c.getId());
-// } else {
-// clientSessionsKept.add(c.getId());
-// }
-// }
-// }
-//
-// session.sessions().onClientRemoved(realm, realm.getClientByClientId("third-party"));
-// resetSession();
-//
-// for (String c : clientSessionsRemoved) {
-// assertNull(session.sessions().getClientSession(realm, c));
-// }
-// for (String c : clientSessionsKept) {
-// assertNotNull(session.sessions().getClientSession(realm, c));
-// }
-//
-// session.sessions().onClientRemoved(realm, realm.getClientByClientId("test-app"));
-// resetSession();
-//
-// for (String c : clientSessionsRemoved) {
-// assertNull(session.sessions().getClientSession(realm, c));
-// }
-// for (String c : clientSessionsKept) {
-// assertNull(session.sessions().getClientSession(realm, c));
-// }
-// }
-//
-// @Test
-// public void testRemoveUserSessionsByExpired() {
-// session.sessions().getUserSessions(realm, session.users().getUserByUsername("user1", realm));
-// ClientModel client = realm.getClientByClientId("test-app");
-//
-// try {
-// Set<String> expired = new HashSet<String>();
-// Set<String> expiredClientSessions = new HashSet<String>();
-//
-// Time.setOffset(-(realm.getSsoSessionMaxLifespan() + 1));
-// expired.add(session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.1", "form", true, null, null).getId());
-// expiredClientSessions.add(session.sessions().createClientSession(realm, client).getId());
-//
-// Time.setOffset(0);
-// UserSessionModel s = session.sessions().createUserSession(realm, session.users().getUserByUsername("user2", realm), "user2", "127.0.0.1", "form", true, null, null);
-// //s.setLastSessionRefresh(Time.currentTime() - (realm.getSsoSessionIdleTimeout() + 1));
-// s.setLastSessionRefresh(0);
-// expired.add(s.getId());
-//
-// ClientSessionModel clSession = session.sessions().createClientSession(realm, client);
-// clSession.setUserSession(s);
-// expiredClientSessions.add(clSession.getId());
-//
-// Set<String> valid = new HashSet<String>();
-// Set<String> validClientSessions = new HashSet<String>();
-//
-// valid.add(session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.1", "form", true, null, null).getId());
-// validClientSessions.add(session.sessions().createClientSession(realm, client).getId());
-//
-// resetSession();
-//
-// session.sessions().removeExpired(realm);
-// resetSession();
-//
-// for (String e : expired) {
-// assertNull(session.sessions().getUserSession(realm, e));
-// }
-// for (String e : expiredClientSessions) {
-// assertNull(session.sessions().getClientSession(realm, e));
-// }
-//
-// for (String v : valid) {
-// assertNotNull(session.sessions().getUserSession(realm, v));
-// }
-// for (String e : validClientSessions) {
-// assertNotNull(session.sessions().getClientSession(realm, e));
-// }
-// } finally {
-// Time.setOffset(0);
-// }
-// }
-//
-// @Test
-// public void testExpireDetachedClientSessions() {
-// try {
-// realm.setAccessCodeLifespan(10);
-// realm.setAccessCodeLifespanUserAction(10);
-// realm.setAccessCodeLifespanLogin(30);
-//
-// // Login lifespan is largest
-// String clientSessionId = session.sessions().createClientSession(realm, realm.getClientByClientId("test-app")).getId();
-// resetSession();
-//
-// Time.setOffset(25);
-// session.sessions().removeExpired(realm);
-// resetSession();
-//
-// assertNotNull(session.sessions().getClientSession(clientSessionId));
-//
-// Time.setOffset(35);
-// session.sessions().removeExpired(realm);
-// resetSession();
-//
-// assertNull(session.sessions().getClientSession(clientSessionId));
-//
-// // User action is largest
-// realm.setAccessCodeLifespanUserAction(40);
-//
-// Time.setOffset(0);
-// clientSessionId = session.sessions().createClientSession(realm, realm.getClientByClientId("test-app")).getId();
-// resetSession();
-//
-// Time.setOffset(35);
-// session.sessions().removeExpired(realm);
-// resetSession();
-//
-// assertNotNull(session.sessions().getClientSession(clientSessionId));
-//
-// Time.setOffset(45);
-// session.sessions().removeExpired(realm);
-// resetSession();
-//
-// assertNull(session.sessions().getClientSession(clientSessionId));
-//
-// // Access code is largest
-// realm.setAccessCodeLifespan(50);
-//
-// Time.setOffset(0);
-// clientSessionId = session.sessions().createClientSession(realm, realm.getClientByClientId("test-app")).getId();
-// resetSession();
-//
-// Time.setOffset(45);
-// session.sessions().removeExpired(realm);
-// resetSession();
-//
-// assertNotNull(session.sessions().getClientSession(clientSessionId));
-//
-// Time.setOffset(55);
-// session.sessions().removeExpired(realm);
-// resetSession();
-//
-// assertNull(session.sessions().getClientSession(clientSessionId));
-// } finally {
-// Time.setOffset(0);
-//
-// realm.setAccessCodeLifespan(60);
-// realm.setAccessCodeLifespanUserAction(300);
-// realm.setAccessCodeLifespanLogin(1800);
-//
-// }
-// }
-//
-// // KEYCLOAK-2508
-// @Test
-// public void testRemovingExpiredSession() {
-// UserSessionModel[] sessions = createSessions();
-// try {
-// Time.setOffset(3600000);
-// UserSessionModel userSession = sessions[0];
-// RealmModel realm = userSession.getRealm();
-// session.sessions().removeExpired(realm);
-//
-// resetSession();
-//
-// // Assert no exception is thrown here
-// session.sessions().removeUserSession(realm, userSession);
-// } finally {
-// Time.setOffset(0);
-// }
-// }
-//
-// @Test
-// public void testGetByClient() {
-// UserSessionModel[] sessions = createSessions();
-//
-// assertSessions(session.sessions().getUserSessions(realm, realm.getClientByClientId("test-app")), sessions[0], sessions[1], sessions[2]);
-// assertSessions(session.sessions().getUserSessions(realm, realm.getClientByClientId("third-party")), sessions[0]);
-// }
-//
-// @Test
-// public void testGetByClientPaginated() {
-// try {
-// for (int i = 0; i < 25; i++) {
-// Time.setOffset(i);
-// UserSessionModel userSession = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0." + i, "form", false, null, null);
-// ClientSessionModel clientSession = session.sessions().createClientSession(realm, realm.getClientByClientId("test-app"));
-// clientSession.setUserSession(userSession);
-// clientSession.setRedirectUri("http://redirect");
-// clientSession.setRoles(new HashSet<String>());
-// clientSession.setNote(OIDCLoginProtocol.STATE_PARAM, "state");
-// clientSession.setTimestamp(userSession.getStarted());
-// }
-// } finally {
-// Time.setOffset(0);
-// }
-//
-// resetSession();
-//
-// assertPaginatedSession(realm, realm.getClientByClientId("test-app"), 0, 1, 1);
-// assertPaginatedSession(realm, realm.getClientByClientId("test-app"), 0, 10, 10);
-// assertPaginatedSession(realm, realm.getClientByClientId("test-app"), 10, 10, 10);
-// assertPaginatedSession(realm, realm.getClientByClientId("test-app"), 20, 10, 5);
-// assertPaginatedSession(realm, realm.getClientByClientId("test-app"), 30, 10, 0);
-// }
-//
-// @Test
-// public void testCreateAndGetInSameTransaction() {
-// UserSessionModel userSession = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.2", "form", true, null, null);
-// ClientSessionModel clientSession = createClientSession(realm.getClientByClientId("test-app"), userSession, "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
-//
-// Assert.assertNotNull(session.sessions().getUserSession(realm, userSession.getId()));
-// Assert.assertNotNull(session.sessions().getClientSession(realm, clientSession.getId()));
-//
-// Assert.assertEquals(userSession.getId(), clientSession.getUserSession().getId());
-// Assert.assertEquals(1, userSession.getClientSessions().size());
-// Assert.assertEquals(clientSession.getId(), userSession.getClientSessions().get(0).getId());
-// }
-//
-// private void assertPaginatedSession(RealmModel realm, ClientModel client, int start, int max, int expectedSize) {
-// List<UserSessionModel> sessions = session.sessions().getUserSessions(realm, client, start, max);
-// String[] actualIps = new String[sessions.size()];
-// for (int i = 0; i < actualIps.length; i++) {
-// actualIps[i] = sessions.get(i).getIpAddress();
-// }
-//
-// String[] expectedIps = new String[expectedSize];
-// for (int i = 0; i < expectedSize; i++) {
-// expectedIps[i] = "127.0.0." + (i + start);
-// }
-//
-// assertArrayEquals(expectedIps, actualIps);
-// }
-//
-// @Test
-// public void testGetCountByClient() {
-// createSessions();
-//
-// assertEquals(3, session.sessions().getActiveUserSessions(realm, realm.getClientByClientId("test-app")));
-// assertEquals(1, session.sessions().getActiveUserSessions(realm, realm.getClientByClientId("third-party")));
-// }
-//
-// @Test
-// public void loginFailures() {
-// UserLoginFailureModel failure1 = session.sessions().addUserLoginFailure(realm, "user1");
-// failure1.incrementFailures();
-//
-// UserLoginFailureModel failure2 = session.sessions().addUserLoginFailure(realm, "user2");
-// failure2.incrementFailures();
-// failure2.incrementFailures();
-//
-// resetSession();
-//
-// failure1 = session.sessions().getUserLoginFailure(realm, "user1");
-// assertEquals(1, failure1.getNumFailures());
-//
-// failure2 = session.sessions().getUserLoginFailure(realm, "user2");
-// assertEquals(2, failure2.getNumFailures());
-//
-// resetSession();
-//
-// failure1 = session.sessions().getUserLoginFailure(realm, "user1");
-// failure1.clearFailures();
-//
-// resetSession();
-//
-// failure1 = session.sessions().getUserLoginFailure(realm, "user1");
-// assertEquals(0, failure1.getNumFailures());
-//
-// session.sessions().removeUserLoginFailure(realm, "user1");
-//
-// resetSession();
-//
-// assertNull(session.sessions().getUserLoginFailure(realm, "user1"));
-//
-// session.sessions().removeAllUserLoginFailures(realm);
-//
-// resetSession();
-//
-// assertNull(session.sessions().getUserLoginFailure(realm, "user2"));
-// }
-//
-// @Test
-// public void testOnUserRemoved() {
-// createSessions();
-//
-// session.sessions().addUserLoginFailure(realm, "user1");
-// session.sessions().addUserLoginFailure(realm, "user1@localhost");
-// session.sessions().addUserLoginFailure(realm, "user2");
-//
-// resetSession();
-//
-// UserModel user1 = session.users().getUserByUsername("user1", realm);
-// new UserManager(session).removeUser(realm, user1);
-//
-// resetSession();
-//
-// assertTrue(session.sessions().getUserSessions(realm, user1).isEmpty());
-// assertFalse(session.sessions().getUserSessions(realm, session.users().getUserByUsername("user2", realm)).isEmpty());
-//
-// assertNull(session.sessions().getUserLoginFailure(realm, "user1"));
-// assertNull(session.sessions().getUserLoginFailure(realm, "user1@localhost"));
-// assertNotNull(session.sessions().getUserLoginFailure(realm, "user2"));
-// }
-//
-// private ClientSessionModel createClientSession(ClientModel client, UserSessionModel userSession, String redirect, String state, Set<String> roles, Set<String> protocolMappers) {
-// ClientSessionModel clientSession = session.sessions().createClientSession(realm, client);
-// if (userSession != null) clientSession.setUserSession(userSession);
-// clientSession.setRedirectUri(redirect);
-// if (state != null) clientSession.setNote(OIDCLoginProtocol.STATE_PARAM, state);
-// if (roles != null) clientSession.setRoles(roles);
-// if (protocolMappers != null) clientSession.setProtocolMappers(protocolMappers);
-// return clientSession;
-// }
-//
-// private UserSessionModel[] createSessions() {
-// UserSessionModel[] sessions = new UserSessionModel[3];
-// sessions[0] = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.1", "form", true, null, null);
-//
-// Set<String> roles = new HashSet<String>();
-// roles.add("one");
-// roles.add("two");
-//
-// Set<String> protocolMappers = new HashSet<String>();
-// protocolMappers.add("mapper-one");
-// protocolMappers.add("mapper-two");
-//
-// createClientSession(realm.getClientByClientId("test-app"), sessions[0], "http://redirect", "state", roles, protocolMappers);
-// createClientSession(realm.getClientByClientId("third-party"), sessions[0], "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
-//
-// sessions[1] = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.2", "form", true, null, null);
-// createClientSession(realm.getClientByClientId("test-app"), sessions[1], "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
-//
-// sessions[2] = session.sessions().createUserSession(realm, session.users().getUserByUsername("user2", realm), "user2", "127.0.0.3", "form", true, null, null);
-// createClientSession(realm.getClientByClientId("test-app"), sessions[2], "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
-//
-// resetSession();
-//
-// return sessions;
-// }
-//
-// private void resetSession() {
-// kc.stopSession(session, true);
-// session = kc.startSession();
-// realm = session.realms().getRealm("test");
-// }
-//
-// public static void assertSessions(List<UserSessionModel> actualSessions, UserSessionModel... expectedSessions) {
-// String[] expected = new String[expectedSessions.length];
-// for (int i = 0; i < expected.length; i++) {
-// expected[i] = expectedSessions[i].getId();
-// }
-//
-// String[] actual = new String[actualSessions.size()];
-// for (int i = 0; i < actual.length; i++) {
-// actual[i] = actualSessions.get(i).getId();
-// }
-//
-// Arrays.sort(expected);
-// Arrays.sort(actual);
-//
-// assertArrayEquals(expected, actual);
-// }
-//
-// public static void assertSession(UserSessionModel session, UserModel user, String ipAddress, int started, int lastRefresh, String... clients) {
-// assertEquals(user.getId(), session.getUser().getId());
-// assertEquals(ipAddress, session.getIpAddress());
-// assertEquals(user.getUsername(), session.getLoginUsername());
-// assertEquals("form", session.getAuthMethod());
-// assertEquals(true, session.isRememberMe());
-// assertTrue(session.getStarted() >= started - 1 && session.getStarted() <= started + 1);
-// assertTrue(session.getLastSessionRefresh() >= lastRefresh - 1 && session.getLastSessionRefresh() <= lastRefresh + 1);
-//
-// String[] actualClients = new String[session.getClientSessions().size()];
-// for (int i = 0; i < actualClients.length; i++) {
-// actualClients[i] = session.getClientSessions().get(i).getClient().getClientId();
-// }
-//
-// Arrays.sort(clients);
-// Arrays.sort(actualClients);
-//
-// assertArrayEquals(clients, actualClients);
-// }
+ @ClassRule
+ public static KeycloakRule kc = new KeycloakRule();
+
+ private KeycloakSession session;
+ private RealmModel realm;
+
+ @Before
+ public void before() {
+ session = kc.startSession();
+ realm = session.realms().getRealm("test");
+ session.users().addUser(realm, "user1").setEmail("user1@localhost");
+ session.users().addUser(realm, "user2").setEmail("user2@localhost");
+ }
+
+ @After
+ public void after() {
+ resetSession();
+ session.sessions().removeUserSessions(realm);
+ UserModel user1 = session.users().getUserByUsername("user1", realm);
+ UserModel user2 = session.users().getUserByUsername("user2", realm);
+
+ UserManager um = new UserManager(session);
+ if (user1 != null) {
+ um.removeUser(realm, user1);
+ }
+ if (user2 != null) {
+ um.removeUser(realm, user2);
+ }
+ kc.stopSession(session, true);
+ }
+
+ @Test
+ public void testCreateSessions() {
+ int started = Time.currentTime();
+ UserSessionModel[] sessions = createSessions();
+
+ assertSession(session.sessions().getUserSession(realm, sessions[0].getId()), session.users().getUserByUsername("user1", realm), "127.0.0.1", started, started, "test-app", "third-party");
+ assertSession(session.sessions().getUserSession(realm, sessions[1].getId()), session.users().getUserByUsername("user1", realm), "127.0.0.2", started, started, "test-app");
+ assertSession(session.sessions().getUserSession(realm, sessions[2].getId()), session.users().getUserByUsername("user2", realm), "127.0.0.3", started, started, "test-app");
+ }
+
+ @Test
+ public void testUpdateSession() {
+ UserSessionModel[] sessions = createSessions();
+ session.sessions().getUserSession(realm, sessions[0].getId()).setLastSessionRefresh(1000);
+
+ resetSession();
+
+ assertEquals(1000, session.sessions().getUserSession(realm, sessions[0].getId()).getLastSessionRefresh());
+ }
+
+ @Test
+ public void testCreateClientSession() {
+ UserSessionModel[] sessions = createSessions();
+
+ List<ClientSessionModel> clientSessions = session.sessions().getUserSession(realm, sessions[0].getId()).getClientSessions();
+ assertEquals(2, clientSessions.size());
+
+ String client1 = realm.getClientByClientId("test-app").getId();
+
+ ClientSessionModel session1;
+
+ if (clientSessions.get(0).getClient().getId().equals(client1)) {
+ session1 = clientSessions.get(0);
+ } else {
+ session1 = clientSessions.get(1);
+ }
+
+ assertEquals(null, session1.getAction());
+ assertEquals(realm.getClientByClientId("test-app").getClientId(), session1.getClient().getClientId());
+ assertEquals(sessions[0].getId(), session1.getUserSession().getId());
+ assertEquals("http://redirect", session1.getRedirectUri());
+ assertEquals("state", session1.getNote(OIDCLoginProtocol.STATE_PARAM));
+ assertEquals(2, session1.getRoles().size());
+ assertTrue(session1.getRoles().contains("one"));
+ assertTrue(session1.getRoles().contains("two"));
+ assertEquals(2, session1.getProtocolMappers().size());
+ assertTrue(session1.getProtocolMappers().contains("mapper-one"));
+ assertTrue(session1.getProtocolMappers().contains("mapper-two"));
+ }
+
+ @Test
+ public void testUpdateClientSession() {
+ UserSessionModel[] sessions = createSessions();
+
+ String id = sessions[0].getClientSessions().get(0).getId();
+
+ ClientSessionModel clientSession = session.sessions().getClientSession(realm, id);
+
+ int time = clientSession.getTimestamp();
+ assertEquals(null, clientSession.getAction());
+
+ clientSession.setAction(ClientSessionModel.Action.CODE_TO_TOKEN.name());
+ clientSession.setTimestamp(time + 10);
+
+ kc.stopSession(session, true);
+ session = kc.startSession();
+
+ ClientSessionModel updated = session.sessions().getClientSession(realm, id);
+ assertEquals(ClientSessionModel.Action.CODE_TO_TOKEN.name(), updated.getAction());
+ assertEquals(time + 10, updated.getTimestamp());
+ }
+
+ @Test
+ public void testGetUserSessions() {
+ UserSessionModel[] sessions = createSessions();
+
+ assertSessions(session.sessions().getUserSessions(realm, session.users().getUserByUsername("user1", realm)), sessions[0], sessions[1]);
+ assertSessions(session.sessions().getUserSessions(realm, session.users().getUserByUsername("user2", realm)), sessions[2]);
+ }
+
+ @Test
+ public void testRemoveUserSessionsByUser() {
+ UserSessionModel[] sessions = createSessions();
+
+ List<String> clientSessionsRemoved = new LinkedList<String>();
+ List<String> clientSessionsKept = new LinkedList<String>();
+ for (UserSessionModel s : sessions) {
+ s = session.sessions().getUserSession(realm, s.getId());
+
+ for (ClientSessionModel c : s.getClientSessions()) {
+ if (c.getUserSession().getUser().getUsername().equals("user1")) {
+ clientSessionsRemoved.add(c.getId());
+ } else {
+ clientSessionsKept.add(c.getId());
+ }
+ }
+ }
+
+ session.sessions().removeUserSessions(realm, session.users().getUserByUsername("user1", realm));
+ resetSession();
+
+ assertTrue(session.sessions().getUserSessions(realm, session.users().getUserByUsername("user1", realm)).isEmpty());
+ assertFalse(session.sessions().getUserSessions(realm, session.users().getUserByUsername("user2", realm)).isEmpty());
+
+ for (String c : clientSessionsRemoved) {
+ assertNull(session.sessions().getClientSession(realm, c));
+ }
+ for (String c : clientSessionsKept) {
+ assertNotNull(session.sessions().getClientSession(realm, c));
+ }
+ }
+
+ @Test
+ public void testRemoveUserSession() {
+ UserSessionModel userSession = createSessions()[0];
+
+ List<String> clientSessionsRemoved = new LinkedList<String>();
+ for (ClientSessionModel c : userSession.getClientSessions()) {
+ clientSessionsRemoved.add(c.getId());
+ }
+
+ session.sessions().removeUserSession(realm, userSession);
+ resetSession();
+
+ assertNull(session.sessions().getUserSession(realm, userSession.getId()));
+ for (String c : clientSessionsRemoved) {
+ assertNull(session.sessions().getClientSession(realm, c));
+ }
+ }
+
+ @Test
+ public void testRemoveUserSessionsByRealm() {
+ UserSessionModel[] sessions = createSessions();
+
+ List<ClientSessionModel> clientSessions = new LinkedList<ClientSessionModel>();
+ for (UserSessionModel s : sessions) {
+ clientSessions.addAll(s.getClientSessions());
+ }
+
+ session.sessions().removeUserSessions(realm);
+ resetSession();
+
+ assertTrue(session.sessions().getUserSessions(realm, session.users().getUserByUsername("user1", realm)).isEmpty());
+ assertTrue(session.sessions().getUserSessions(realm, session.users().getUserByUsername("user2", realm)).isEmpty());
+
+ for (ClientSessionModel c : clientSessions) {
+ assertNull(session.sessions().getClientSession(realm, c.getId()));
+ }
+ }
+
+ @Test
+ public void testOnClientRemoved() {
+ UserSessionModel[] sessions = createSessions();
+
+ List<String> clientSessionsRemoved = new LinkedList<String>();
+ List<String> clientSessionsKept = new LinkedList<String>();
+ for (UserSessionModel s : sessions) {
+ s = session.sessions().getUserSession(realm, s.getId());
+ for (ClientSessionModel c : s.getClientSessions()) {
+ if (c.getClient().getClientId().equals("third-party")) {
+ clientSessionsRemoved.add(c.getId());
+ } else {
+ clientSessionsKept.add(c.getId());
+ }
+ }
+ }
+
+ session.sessions().onClientRemoved(realm, realm.getClientByClientId("third-party"));
+ resetSession();
+
+ for (String c : clientSessionsRemoved) {
+ assertNull(session.sessions().getClientSession(realm, c));
+ }
+ for (String c : clientSessionsKept) {
+ assertNotNull(session.sessions().getClientSession(realm, c));
+ }
+
+ session.sessions().onClientRemoved(realm, realm.getClientByClientId("test-app"));
+ resetSession();
+
+ for (String c : clientSessionsRemoved) {
+ assertNull(session.sessions().getClientSession(realm, c));
+ }
+ for (String c : clientSessionsKept) {
+ assertNull(session.sessions().getClientSession(realm, c));
+ }
+ }
+
+ @Test
+ public void testRemoveUserSessionsByExpired() {
+ session.sessions().getUserSessions(realm, session.users().getUserByUsername("user1", realm));
+ ClientModel client = realm.getClientByClientId("test-app");
+
+ try {
+ Set<String> expired = new HashSet<String>();
+ Set<String> expiredClientSessions = new HashSet<String>();
+
+ Time.setOffset(-(realm.getSsoSessionMaxLifespan() + 1));
+ expired.add(session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.1", "form", true, null, null).getId());
+ expiredClientSessions.add(session.sessions().createClientSession(realm, client).getId());
+
+ Time.setOffset(0);
+ UserSessionModel s = session.sessions().createUserSession(realm, session.users().getUserByUsername("user2", realm), "user2", "127.0.0.1", "form", true, null, null);
+ //s.setLastSessionRefresh(Time.currentTime() - (realm.getSsoSessionIdleTimeout() + 1));
+ s.setLastSessionRefresh(0);
+ expired.add(s.getId());
+
+ ClientSessionModel clSession = session.sessions().createClientSession(realm, client);
+ clSession.setUserSession(s);
+ expiredClientSessions.add(clSession.getId());
+
+ Set<String> valid = new HashSet<String>();
+ Set<String> validClientSessions = new HashSet<String>();
+
+ valid.add(session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.1", "form", true, null, null).getId());
+ validClientSessions.add(session.sessions().createClientSession(realm, client).getId());
+
+ resetSession();
+
+ session.sessions().removeExpired(realm);
+ resetSession();
+
+ for (String e : expired) {
+ assertNull(session.sessions().getUserSession(realm, e));
+ }
+ for (String e : expiredClientSessions) {
+ assertNull(session.sessions().getClientSession(realm, e));
+ }
+
+ for (String v : valid) {
+ assertNotNull(session.sessions().getUserSession(realm, v));
+ }
+ for (String e : validClientSessions) {
+ assertNotNull(session.sessions().getClientSession(realm, e));
+ }
+ } finally {
+ Time.setOffset(0);
+ }
+ }
+
+ @Test
+ public void testExpireDetachedClientSessions() {
+ try {
+ realm.setAccessCodeLifespan(10);
+ realm.setAccessCodeLifespanUserAction(10);
+ realm.setAccessCodeLifespanLogin(30);
+
+ // Login lifespan is largest
+ String clientSessionId = session.sessions().createClientSession(realm, realm.getClientByClientId("test-app")).getId();
+ resetSession();
+
+ Time.setOffset(25);
+ session.sessions().removeExpired(realm);
+ resetSession();
+
+ assertNotNull(session.sessions().getClientSession(clientSessionId));
+
+ Time.setOffset(35);
+ session.sessions().removeExpired(realm);
+ resetSession();
+
+ assertNull(session.sessions().getClientSession(clientSessionId));
+
+ // User action is largest
+ realm.setAccessCodeLifespanUserAction(40);
+
+ Time.setOffset(0);
+ clientSessionId = session.sessions().createClientSession(realm, realm.getClientByClientId("test-app")).getId();
+ resetSession();
+
+ Time.setOffset(35);
+ session.sessions().removeExpired(realm);
+ resetSession();
+
+ assertNotNull(session.sessions().getClientSession(clientSessionId));
+
+ Time.setOffset(45);
+ session.sessions().removeExpired(realm);
+ resetSession();
+
+ assertNull(session.sessions().getClientSession(clientSessionId));
+
+ // Access code is largest
+ realm.setAccessCodeLifespan(50);
+
+ Time.setOffset(0);
+ clientSessionId = session.sessions().createClientSession(realm, realm.getClientByClientId("test-app")).getId();
+ resetSession();
+
+ Time.setOffset(45);
+ session.sessions().removeExpired(realm);
+ resetSession();
+
+ assertNotNull(session.sessions().getClientSession(clientSessionId));
+
+ Time.setOffset(55);
+ session.sessions().removeExpired(realm);
+ resetSession();
+
+ assertNull(session.sessions().getClientSession(clientSessionId));
+ } finally {
+ Time.setOffset(0);
+
+ realm.setAccessCodeLifespan(60);
+ realm.setAccessCodeLifespanUserAction(300);
+ realm.setAccessCodeLifespanLogin(1800);
+
+ }
+ }
+
+ // KEYCLOAK-2508
+ @Test
+ public void testRemovingExpiredSession() {
+ UserSessionModel[] sessions = createSessions();
+ try {
+ Time.setOffset(3600000);
+ UserSessionModel userSession = sessions[0];
+ RealmModel realm = userSession.getRealm();
+ session.sessions().removeExpired(realm);
+
+ resetSession();
+
+ // Assert no exception is thrown here
+ session.sessions().removeUserSession(realm, userSession);
+ } finally {
+ Time.setOffset(0);
+ }
+ }
+
+ @Test
+ public void testGetByClient() {
+ UserSessionModel[] sessions = createSessions();
+
+ assertSessions(session.sessions().getUserSessions(realm, realm.getClientByClientId("test-app")), sessions[0], sessions[1], sessions[2]);
+ assertSessions(session.sessions().getUserSessions(realm, realm.getClientByClientId("third-party")), sessions[0]);
+ }
+
+ @Test
+ public void testGetByClientPaginated() {
+ try {
+ for (int i = 0; i < 25; i++) {
+ Time.setOffset(i);
+ UserSessionModel userSession = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0." + i, "form", false, null, null);
+ ClientSessionModel clientSession = session.sessions().createClientSession(realm, realm.getClientByClientId("test-app"));
+ clientSession.setUserSession(userSession);
+ clientSession.setRedirectUri("http://redirect");
+ clientSession.setRoles(new HashSet<String>());
+ clientSession.setNote(OIDCLoginProtocol.STATE_PARAM, "state");
+ clientSession.setTimestamp(userSession.getStarted());
+ }
+ } finally {
+ Time.setOffset(0);
+ }
+
+ resetSession();
+
+ assertPaginatedSession(realm, realm.getClientByClientId("test-app"), 0, 1, 1);
+ assertPaginatedSession(realm, realm.getClientByClientId("test-app"), 0, 10, 10);
+ assertPaginatedSession(realm, realm.getClientByClientId("test-app"), 10, 10, 10);
+ assertPaginatedSession(realm, realm.getClientByClientId("test-app"), 20, 10, 5);
+ assertPaginatedSession(realm, realm.getClientByClientId("test-app"), 30, 10, 0);
+ }
+
+ @Test
+ public void testCreateAndGetInSameTransaction() {
+ UserSessionModel userSession = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.2", "form", true, null, null);
+ ClientSessionModel clientSession = createClientSession(realm.getClientByClientId("test-app"), userSession, "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
+
+ Assert.assertNotNull(session.sessions().getUserSession(realm, userSession.getId()));
+ Assert.assertNotNull(session.sessions().getClientSession(realm, clientSession.getId()));
+
+ Assert.assertEquals(userSession.getId(), clientSession.getUserSession().getId());
+ Assert.assertEquals(1, userSession.getClientSessions().size());
+ Assert.assertEquals(clientSession.getId(), userSession.getClientSessions().get(0).getId());
+ }
+
+ @Test
+ public void testClientLoginSessions() {
+ UserSessionModel userSession = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.2", "form", true, null, null);
+
+ ClientModel client1 = realm.getClientByClientId("test-app");
+ ClientModel client2 = realm.getClientByClientId("third-party");
+
+ // Create client1 session
+ AuthenticatedClientSessionModel clientSession1 = session.sessions().createClientSession(realm, client1, userSession);
+ clientSession1.setAction("foo1");
+ clientSession1.setTimestamp(100);
+
+ // Create client2 session
+ AuthenticatedClientSessionModel clientSession2 = session.sessions().createClientSession(realm, client2, userSession);
+ clientSession2.setAction("foo2");
+ clientSession2.setTimestamp(200);
+
+ // commit
+ resetSession();
+
+ // Ensure sessions are here
+ userSession = session.sessions().getUserSession(realm, userSession.getId());
+ Map<String, AuthenticatedClientSessionModel> clientSessions = userSession.getAuthenticatedClientSessions();
+ Assert.assertEquals(2, clientSessions.size());
+ testClientLoginSession(clientSessions.get(client1.getId()), "test-app", userSession.getId(), "foo1", 100);
+ testClientLoginSession(clientSessions.get(client2.getId()), "third-party", userSession.getId(), "foo2", 200);
+
+ // Update session1
+ clientSessions.get(client1.getId()).setAction("foo1-updated");
+
+ // commit
+ resetSession();
+
+ // Ensure updated
+ userSession = session.sessions().getUserSession(realm, userSession.getId());
+ clientSessions = userSession.getAuthenticatedClientSessions();
+ testClientLoginSession(clientSessions.get(client1.getId()), "test-app", userSession.getId(), "foo1-updated", 100);
+
+ // Rewrite session2
+ clientSession2 = session.sessions().createClientSession(realm, client2, userSession);
+ clientSession2.setAction("foo2-rewrited");
+ clientSession2.setTimestamp(300);
+
+ // commit
+ resetSession();
+
+ // Ensure updated
+ userSession = session.sessions().getUserSession(realm, userSession.getId());
+ clientSessions = userSession.getAuthenticatedClientSessions();
+ Assert.assertEquals(2, clientSessions.size());
+ testClientLoginSession(clientSessions.get(client1.getId()), "test-app", userSession.getId(), "foo1-updated", 100);
+ testClientLoginSession(clientSessions.get(client2.getId()), "third-party", userSession.getId(), "foo2-rewrited", 300);
+
+ // remove session
+ clientSession1 = userSession.getAuthenticatedClientSessions().get(client1.getId());
+ clientSession1.setUserSession(null);
+
+ // Commit and ensure removed
+ resetSession();
+
+ userSession = session.sessions().getUserSession(realm, userSession.getId());
+ clientSessions = userSession.getAuthenticatedClientSessions();
+ Assert.assertEquals(1, clientSessions.size());
+ Assert.assertNull(clientSessions.get(client1.getId()));
+ }
+
+ private void testClientLoginSession(AuthenticatedClientSessionModel clientLoginSession, String expectedClientId, String expectedUserSessionId, String expectedAction, int expectedTimestamp) {
+ Assert.assertEquals(expectedClientId, clientLoginSession.getClient().getClientId());
+ Assert.assertEquals(expectedUserSessionId, clientLoginSession.getUserSession().getId());
+ Assert.assertEquals(expectedAction, clientLoginSession.getAction());
+ Assert.assertEquals(expectedTimestamp, clientLoginSession.getTimestamp());
+ }
+
+ private void assertPaginatedSession(RealmModel realm, ClientModel client, int start, int max, int expectedSize) {
+ List<UserSessionModel> sessions = session.sessions().getUserSessions(realm, client, start, max);
+ String[] actualIps = new String[sessions.size()];
+ for (int i = 0; i < actualIps.length; i++) {
+ actualIps[i] = sessions.get(i).getIpAddress();
+ }
+
+ String[] expectedIps = new String[expectedSize];
+ for (int i = 0; i < expectedSize; i++) {
+ expectedIps[i] = "127.0.0." + (i + start);
+ }
+
+ assertArrayEquals(expectedIps, actualIps);
+ }
+
+ @Test
+ public void testGetCountByClient() {
+ createSessions();
+
+ assertEquals(3, session.sessions().getActiveUserSessions(realm, realm.getClientByClientId("test-app")));
+ assertEquals(1, session.sessions().getActiveUserSessions(realm, realm.getClientByClientId("third-party")));
+ }
+
+ @Test
+ public void loginFailures() {
+ UserLoginFailureModel failure1 = session.sessions().addUserLoginFailure(realm, "user1");
+ failure1.incrementFailures();
+
+ UserLoginFailureModel failure2 = session.sessions().addUserLoginFailure(realm, "user2");
+ failure2.incrementFailures();
+ failure2.incrementFailures();
+
+ resetSession();
+
+ failure1 = session.sessions().getUserLoginFailure(realm, "user1");
+ assertEquals(1, failure1.getNumFailures());
+
+ failure2 = session.sessions().getUserLoginFailure(realm, "user2");
+ assertEquals(2, failure2.getNumFailures());
+
+ resetSession();
+
+ failure1 = session.sessions().getUserLoginFailure(realm, "user1");
+ failure1.clearFailures();
+
+ resetSession();
+
+ failure1 = session.sessions().getUserLoginFailure(realm, "user1");
+ assertEquals(0, failure1.getNumFailures());
+
+ session.sessions().removeUserLoginFailure(realm, "user1");
+
+ resetSession();
+
+ assertNull(session.sessions().getUserLoginFailure(realm, "user1"));
+
+ session.sessions().removeAllUserLoginFailures(realm);
+
+ resetSession();
+
+ assertNull(session.sessions().getUserLoginFailure(realm, "user2"));
+ }
+
+ @Test
+ public void testOnUserRemoved() {
+ createSessions();
+
+ session.sessions().addUserLoginFailure(realm, "user1");
+ session.sessions().addUserLoginFailure(realm, "user1@localhost");
+ session.sessions().addUserLoginFailure(realm, "user2");
+
+ resetSession();
+
+ UserModel user1 = session.users().getUserByUsername("user1", realm);
+ new UserManager(session).removeUser(realm, user1);
+
+ resetSession();
+
+ assertTrue(session.sessions().getUserSessions(realm, user1).isEmpty());
+ assertFalse(session.sessions().getUserSessions(realm, session.users().getUserByUsername("user2", realm)).isEmpty());
+
+ assertNull(session.sessions().getUserLoginFailure(realm, "user1"));
+ assertNull(session.sessions().getUserLoginFailure(realm, "user1@localhost"));
+ assertNotNull(session.sessions().getUserLoginFailure(realm, "user2"));
+ }
+
+ private ClientSessionModel createClientSession(ClientModel client, UserSessionModel userSession, String redirect, String state, Set<String> roles, Set<String> protocolMappers) {
+ ClientSessionModel clientSession = session.sessions().createClientSession(realm, client);
+ if (userSession != null) clientSession.setUserSession(userSession);
+ clientSession.setRedirectUri(redirect);
+ if (state != null) clientSession.setNote(OIDCLoginProtocol.STATE_PARAM, state);
+ if (roles != null) clientSession.setRoles(roles);
+ if (protocolMappers != null) clientSession.setProtocolMappers(protocolMappers);
+ return clientSession;
+ }
+
+ private UserSessionModel[] createSessions() {
+ UserSessionModel[] sessions = new UserSessionModel[3];
+ sessions[0] = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.1", "form", true, null, null);
+
+ Set<String> roles = new HashSet<String>();
+ roles.add("one");
+ roles.add("two");
+
+ Set<String> protocolMappers = new HashSet<String>();
+ protocolMappers.add("mapper-one");
+ protocolMappers.add("mapper-two");
+
+ createClientSession(realm.getClientByClientId("test-app"), sessions[0], "http://redirect", "state", roles, protocolMappers);
+ createClientSession(realm.getClientByClientId("third-party"), sessions[0], "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
+
+ sessions[1] = session.sessions().createUserSession(realm, session.users().getUserByUsername("user1", realm), "user1", "127.0.0.2", "form", true, null, null);
+ createClientSession(realm.getClientByClientId("test-app"), sessions[1], "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
+
+ sessions[2] = session.sessions().createUserSession(realm, session.users().getUserByUsername("user2", realm), "user2", "127.0.0.3", "form", true, null, null);
+ createClientSession(realm.getClientByClientId("test-app"), sessions[2], "http://redirect", "state", new HashSet<String>(), new HashSet<String>());
+
+ resetSession();
+
+ return sessions;
+ }
+
+ private void resetSession() {
+ kc.stopSession(session, true);
+ session = kc.startSession();
+ realm = session.realms().getRealm("test");
+ }
+
+ public static void assertSessions(List<UserSessionModel> actualSessions, UserSessionModel... expectedSessions) {
+ String[] expected = new String[expectedSessions.length];
+ for (int i = 0; i < expected.length; i++) {
+ expected[i] = expectedSessions[i].getId();
+ }
+
+ String[] actual = new String[actualSessions.size()];
+ for (int i = 0; i < actual.length; i++) {
+ actual[i] = actualSessions.get(i).getId();
+ }
+
+ Arrays.sort(expected);
+ Arrays.sort(actual);
+
+ assertArrayEquals(expected, actual);
+ }
+
+ public static void assertSession(UserSessionModel session, UserModel user, String ipAddress, int started, int lastRefresh, String... clients) {
+ assertEquals(user.getId(), session.getUser().getId());
+ assertEquals(ipAddress, session.getIpAddress());
+ assertEquals(user.getUsername(), session.getLoginUsername());
+ assertEquals("form", session.getAuthMethod());
+ assertEquals(true, session.isRememberMe());
+ assertTrue(session.getStarted() >= started - 1 && session.getStarted() <= started + 1);
+ assertTrue(session.getLastSessionRefresh() >= lastRefresh - 1 && session.getLastSessionRefresh() <= lastRefresh + 1);
+
+ String[] actualClients = new String[session.getClientSessions().size()];
+ for (int i = 0; i < actualClients.length; i++) {
+ actualClients[i] = session.getClientSessions().get(i).getClient().getClientId();
+ }
+
+ Arrays.sort(clients);
+ Arrays.sort(actualClients);
+
+ assertArrayEquals(clients, actualClients);
+ }
}
diff --git a/testsuite/integration-arquillian/HOW-TO-RUN.md b/testsuite/integration-arquillian/HOW-TO-RUN.md
index 1c519b1..35e4be8 100644
--- a/testsuite/integration-arquillian/HOW-TO-RUN.md
+++ b/testsuite/integration-arquillian/HOW-TO-RUN.md
@@ -22,7 +22,7 @@ Adding this system property when running any test:
-Darquillian.debug=true
will add lots of info to the log. Especially about:
-* The test method names, which will be executed for each test class, will be written at the proper running order to the log at the beginning of each test (done by KcArquillian class).
+* The test method names, which will be executed for each test class, will be written at the proper running order to the log at the beginning of each test class(done by KcArquillian class).
* All the triggered arquillian lifecycle events and executed observers listening to those events will be written to the log
* The bootstrap of WebDriver will be unlimited. By default there is just 1 minute timeout and test is cancelled when WebDriver is not bootstrapped within it.
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/forms/PassThroughRegistration.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/forms/PassThroughRegistration.java
index b600c14..74906bd 100755
--- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/forms/PassThroughRegistration.java
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/forms/PassThroughRegistration.java
@@ -52,15 +52,15 @@ public class PassThroughRegistration implements Authenticator, AuthenticatorFact
user.setEnabled(true);
user.setEmail(email);
- context.getLoginSession().setNote(OIDCLoginProtocol.LOGIN_HINT_PARAM, username);
+ context.getAuthenticationSession().setNote(OIDCLoginProtocol.LOGIN_HINT_PARAM, username);
context.setUser(user);
context.getEvent().user(user);
context.getEvent().success();
context.newEvent().event(EventType.LOGIN);
- context.getEvent().client(context.getLoginSession().getClient().getClientId())
- .detail(Details.REDIRECT_URI, context.getLoginSession().getRedirectUri())
- .detail(Details.AUTH_METHOD, context.getLoginSession().getProtocol());
- String authType = context.getLoginSession().getNote(Details.AUTH_TYPE);
+ context.getEvent().client(context.getAuthenticationSession().getClient().getClientId())
+ .detail(Details.REDIRECT_URI, context.getAuthenticationSession().getRedirectUri())
+ .detail(Details.AUTH_METHOD, context.getAuthenticationSession().getProtocol());
+ String authType = context.getAuthenticationSession().getAuthNote(Details.AUTH_TYPE);
if (authType != null) {
context.getEvent().detail(Details.AUTH_TYPE, authType);
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AssertEvents.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AssertEvents.java
index 4445de9..eaf5ab5 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AssertEvents.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AssertEvents.java
@@ -20,6 +20,7 @@ package org.keycloak.testsuite;
import org.hamcrest.CoreMatchers;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
+import org.hamcrest.Matchers;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Assert;
import org.junit.rules.TestRule;
@@ -88,7 +89,7 @@ public class AssertEvents implements TestRule {
}
public ExpectedEvent expectRequiredAction(EventType event) {
- return expectLogin().event(event).removeDetail(Details.CONSENT).session(isUUID());
+ return expectLogin().event(event).removeDetail(Details.CONSENT).session(Matchers.isEmptyOrNullString());
}
public ExpectedEvent expectLogin() {
@@ -120,9 +121,9 @@ public class AssertEvents implements TestRule {
.session(isUUID());
}
+ // TODO:mposolda codeId is not needed anymore
public ExpectedEvent expectCodeToToken(String codeId, String sessionId) {
return expect(EventType.CODE_TO_TOKEN)
- .detail(Details.CODE_ID, codeId)
.detail(Details.TOKEN_ID, isUUID())
.detail(Details.REFRESH_TOKEN_ID, isUUID())
.detail(Details.REFRESH_TOKEN_TYPE, TokenUtil.TOKEN_TYPE_REFRESH)
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
index 201a625..787db5b 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
@@ -142,15 +142,15 @@ public class ResetPasswordTest extends AbstractTestRealmKeycloakTest {
updatePasswordPage.changePassword("resetPassword", "resetPassword");
- String sessionId = events.expectRequiredAction(EventType.UPDATE_PASSWORD)
- .detail(Details.REDIRECT_URI, oauth.AUTH_SERVER_ROOT + "/realms/test/account/")
+ events.expectRequiredAction(EventType.UPDATE_PASSWORD)
+ .detail(Details.REDIRECT_URI, oauth.AUTH_SERVER_ROOT + "/realms/test/account/")
.client("account")
- .user(userId).detail(Details.USERNAME, username).assertEvent().getSessionId();
+ .user(userId).detail(Details.USERNAME, username).assertEvent();
- events.expectLogin().user(userId).detail(Details.USERNAME, username)
+ String sessionId = events.expectLogin().user(userId).detail(Details.USERNAME, username)
.detail(Details.REDIRECT_URI, oauth.AUTH_SERVER_ROOT + "/realms/test/account/")
.client("account")
- .session(sessionId).assertEvent();
+ .assertEvent().getSessionId();
oauth.openLogout();
@@ -246,11 +246,11 @@ public class ResetPasswordTest extends AbstractTestRealmKeycloakTest {
updatePasswordPage.changePassword(password, password);
- String sessionId = events.expectRequiredAction(EventType.UPDATE_PASSWORD).user(userId).detail(Details.USERNAME, username.trim()).assertEvent().getSessionId();
+ events.expectRequiredAction(EventType.UPDATE_PASSWORD).user(userId).detail(Details.USERNAME, username.trim()).assertEvent();
assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
- events.expectLogin().user(userId).detail(Details.USERNAME, username.trim()).session(sessionId).assertEvent();
+ String sessionId = events.expectLogin().user(userId).detail(Details.USERNAME, username.trim()).assertEvent().getSessionId();
oauth.openLogout();
@@ -513,11 +513,11 @@ public class ResetPasswordTest extends AbstractTestRealmKeycloakTest {
updatePasswordPage.changePassword("resetPasswordWithPasswordPolicy", "resetPasswordWithPasswordPolicy");
- String sessionId = events.expectRequiredAction(EventType.UPDATE_PASSWORD).user(userId).detail(Details.USERNAME, "login-test").assertEvent().getSessionId();
+ events.expectRequiredAction(EventType.UPDATE_PASSWORD).user(userId).detail(Details.USERNAME, "login-test").assertEvent().getSessionId();
assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
- events.expectLogin().user(userId).detail(Details.USERNAME, "login-test").session(sessionId).assertEvent();
+ String sessionId = events.expectLogin().user(userId).detail(Details.USERNAME, "login-test").assertEvent().getSessionId();
oauth.openLogout();
diff --git a/themes/src/main/resources/theme/base/login/login-page-expired.ftl b/themes/src/main/resources/theme/base/login/login-page-expired.ftl
new file mode 100644
index 0000000..5812f31
--- /dev/null
+++ b/themes/src/main/resources/theme/base/login/login-page-expired.ftl
@@ -0,0 +1,12 @@
+<#import "template.ftl" as layout>
+<@layout.registrationLayout; section>
+ <#if section = "title">
+ ${msg("pageExpiredTitle")}
+ <#elseif section = "header">
+ ${msg("pageExpiredTitle")}
+ <#elseif section = "form">
+ <p id="instruction1" class="instruction">
+ ${msg("pageExpiredMsg1")} <a href="${url.loginRestartFlowUrl}">${msg("doClickHere")}</a> . ${msg("pageExpiredMsg2")} <a href="${url.loginAction}">${msg("doClickHere")}</a> .
+ </p>
+ </#if>
+</@layout.registrationLayout>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/login/messages/messages_en.properties b/themes/src/main/resources/theme/base/login/messages/messages_en.properties
index 6c168ae..994caa7 100755
--- a/themes/src/main/resources/theme/base/login/messages/messages_en.properties
+++ b/themes/src/main/resources/theme/base/login/messages/messages_en.properties
@@ -90,6 +90,10 @@ emailInstruction=Enter your username or email address and we will send you instr
copyCodeInstruction=Please copy this code and paste it into your application:
+pageExpiredTitle=Page has expired
+pageExpiredMsg1=To restart the login process
+pageExpiredMsg2=To continue the login process
+
personalInfo=Personal Info:
role_admin=Admin
role_realm-admin=Realm Admin