KEYCLOAK-5938 Authentication sessions: Support for logins of multiple tabs of same client
This commit is contained in:
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);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user