KEYCLOAK-5938 Authentication sessions: Support for logins of multiple tabs of same client

This commit is contained in:
mposolda authored and Marek Posolda committed 2017-12-12 08:01:02 +01:00
1 parent c3855510ef
commit 63efee6e15
57 files changed
+905 -567

No files matched your search

@@ -0,0 +1,79 @@
/*
* Copyright 2017 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.sessions;
import java.util.regex.Pattern;
/**
* Allow to encode compound string to fully lookup authenticationSessionModel
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class AuthenticationSessionCompoundId {
private static final Pattern DOT = Pattern.compile("\\.");
public static AuthenticationSessionCompoundId fromAuthSession(AuthenticationSessionModel authSession) {
return decoded(authSession.getParentSession().getId(), authSession.getTabId(), authSession.getClient().getId());
}
public static AuthenticationSessionCompoundId decoded(String rootAuthSessionId, String tabId, String clientUUID) {
String encodedId = rootAuthSessionId + "." + tabId + "." + clientUUID;
return new AuthenticationSessionCompoundId(rootAuthSessionId, tabId, clientUUID, encodedId);
}
public static AuthenticationSessionCompoundId encoded(String encodedId) {
String[] decoded = DOT.split(encodedId, 3);
String rootAuthSessionId =(decoded.length > 0) ? decoded[0] : null;
String tabId = (decoded.length > 1) ? decoded[1] : null;
String clientUUID = (decoded.length > 2) ? decoded[2] : null;
return new AuthenticationSessionCompoundId(rootAuthSessionId, tabId, clientUUID, encodedId);
}
private final String rootSessionId;
private final String tabId;
private final String clientUUID;
private final String encodedId;
public AuthenticationSessionCompoundId(String rootSessionId, String tabId, String clientUUID, String encodedId) {
this.rootSessionId = rootSessionId;
this.tabId = tabId;
this.clientUUID = clientUUID;
this.encodedId = encodedId;
}
public String getRootSessionId() {
return rootSessionId;
}
public String getTabId() {
return tabId;
}
public String getClientUUID() {
return clientUUID;
}
public String getEncodedId() {
return encodedId;
}
}
@@ -24,12 +24,19 @@ import org.keycloak.models.ClientModel;
import org.keycloak.models.UserModel;
/**
* Using class for now to avoid many updates among implementations
* Represents the state of the authentication. If the login is requested from different tabs of same browser, every browser
* tab has it's own state of the authentication. So there is separate AuthenticationSessionModel for every tab. Whole browser
* is represented by {@link RootAuthenticationSessionModel}
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public interface AuthenticationSessionModel extends CommonClientSessionModel {
/**
* @return ID of this subsession (in other words, usually browser tab). For lookup the AuthenticationSessionModel, you need:
* ID of rootSession (parent), client UUID and tabId. For lookup the ID of the parent, use {@link #getParentSession().getId()}
*/
String getTabId();
RootAuthenticationSessionModel getParentSession();
@@ -47,10 +47,10 @@ public interface AuthenticationSessionProvider extends Provider {
* Requests update of authNotes of a root authentication session that is not owned
* by this instance but might exist somewhere in the cluster.
*
* @param authSessionId
* @param compoundId
* @param authNotesFragment Map with authNote values. Auth note is removed if the corresponding value in the map is {@code null}.
*/
void updateNonlocalSessionAuthNotes(String authSessionId, ClientModel client, Map<String, String> authNotesFragment);
void updateNonlocalSessionAuthNotes(AuthenticationSessionCompoundId compoundId, Map<String, String> authNotesFragment);
}
@@ -38,16 +38,16 @@ public interface RootAuthenticationSessionModel {
/**
* Key is client UUID, Value is AuthenticationSessionModel for particular client
* Key is tabId, Value is AuthenticationSessionModel.
* @return authentication sessions or empty map if no authenticationSessions presents. Never return null.
*/
Map<String, AuthenticationSessionModel> getAuthenticationSessions();
/**
* @return authentication session for particular client or null if it doesn't yet exists.
* @return authentication session for particular client and tab or null if it doesn't yet exists.
*/
AuthenticationSessionModel getAuthenticationSession(ClientModel client);
AuthenticationSessionModel getAuthenticationSession(ClientModel client, String tabId);
/**