From 5c1a8d401da65d8b05861237863deb85bbdf9d79 Mon Sep 17 00:00:00 2001 From: Alexander Schwartz Date: Wed, 6 Apr 2022 14:41:17 +0200 Subject: [PATCH] Store time as seconds as a long in map store This avoids overflowing the value in 2038. Closes #10960 --- .../HotRodAuthenticationSessionEntity.java | 2 +- ...HotRodRootAuthenticationSessionEntity.java | 2 +- .../hotRod/client/HotRodClientEntity.java | 2 +- .../HotRodUserLoginFailureEntity.java | 2 +- .../hotRod/realm/HotRodRealmEntity.java | 2 +- .../HotRodClientInitialAccessEntity.java | 4 +- .../storage/hotRod/user/HotRodUserEntity.java | 2 +- .../JpaAuthenticationSessionEntity.java | 4 +- .../JpaRootAuthenticationSessionEntity.java | 8 +-- .../jpa/client/entity/JpaClientEntity.java | 4 +- .../jpa-auth-sessions-changelog-1.xml | 2 +- .../MapAuthenticationSessionEntity.java | 4 +- .../MapRootAuthenticationSessionAdapter.java | 13 +++-- .../MapRootAuthenticationSessionEntity.java | 4 +- .../MapRootAuthenticationSessionProvider.java | 3 +- .../models/map/client/MapClientAdapter.java | 7 ++- .../models/map/client/MapClientEntity.java | 4 +- .../models/map/client/MapClientProvider.java | 22 ++++++-- .../map/client/MapClientProviderFactory.java | 2 +- .../models/map/common/TimeAdapter.java | 55 +++++++++++++++++++ .../MapUserLoginFailureAdapter.java | 7 ++- .../MapUserLoginFailureEntity.java | 4 +- .../models/map/realm/MapRealmAdapter.java | 7 ++- .../models/map/realm/MapRealmEntity.java | 4 +- .../entity/MapClientInitialAccessEntity.java | 21 +++---- .../models/map/user/MapUserEntity.java | 4 +- .../models/map/user/MapUserProvider.java | 7 ++- .../MapAuthenticatedClientSessionAdapter.java | 7 ++- .../MapAuthenticatedClientSessionEntity.java | 6 +- .../userSession/MapUserSessionAdapter.java | 16 +++--- .../map/userSession/MapUserSessionEntity.java | 11 ++-- .../userSession/MapUserSessionProvider.java | 25 +++++---- .../map/userSession/SessionExpiration.java | 8 +-- .../models/map/common/TimeAdapterTest.java | 43 +++++++++++++++ 34 files changed, 218 insertions(+), 100 deletions(-) create mode 100644 model/map/src/main/java/org/keycloak/models/map/common/TimeAdapter.java create mode 100644 model/map/src/test/java/org/keycloak/models/map/common/TimeAdapterTest.java diff --git a/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/authSession/HotRodAuthenticationSessionEntity.java b/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/authSession/HotRodAuthenticationSessionEntity.java index 9ef3ec8853f..07388d80b21 100644 --- a/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/authSession/HotRodAuthenticationSessionEntity.java +++ b/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/authSession/HotRodAuthenticationSessionEntity.java @@ -49,7 +49,7 @@ public class HotRodAuthenticationSessionEntity extends AbstractHotRodEntity { public String authUserId; @ProtoField(number = 4) - public Integer timestamp; + public Long timestamp; @ProtoField(number = 5) public String redirectUri; diff --git a/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/authSession/HotRodRootAuthenticationSessionEntity.java b/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/authSession/HotRodRootAuthenticationSessionEntity.java index 31e25d20d6b..5bc159c3743 100644 --- a/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/authSession/HotRodRootAuthenticationSessionEntity.java +++ b/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/authSession/HotRodRootAuthenticationSessionEntity.java @@ -49,7 +49,7 @@ public class HotRodRootAuthenticationSessionEntity extends AbstractHotRodEntity public String realmId; @ProtoField(number = 4) - public Integer timestamp; + public Long timestamp; @ProtoDoc("@Field(index = Index.YES, store = Store.YES)") @ProtoField(number = 5) diff --git a/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/client/HotRodClientEntity.java b/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/client/HotRodClientEntity.java index 212982f4614..f0d28f670ed 100644 --- a/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/client/HotRodClientEntity.java +++ b/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/client/HotRodClientEntity.java @@ -108,7 +108,7 @@ public class HotRodClientEntity extends AbstractHotRodEntity { public Boolean frontchannelLogout; @ProtoField(number = 20) - public Integer notBefore; + public Long notBefore; @ProtoField(number = 21) public Set scope; diff --git a/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/loginFailure/HotRodUserLoginFailureEntity.java b/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/loginFailure/HotRodUserLoginFailureEntity.java index 9d5ea5a99e6..51b0e30e3a9 100644 --- a/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/loginFailure/HotRodUserLoginFailureEntity.java +++ b/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/loginFailure/HotRodUserLoginFailureEntity.java @@ -46,7 +46,7 @@ public class HotRodUserLoginFailureEntity extends AbstractHotRodEntity { public String userId; @ProtoField(number = 5) - public Integer failedLoginNotBefore; + public Long failedLoginNotBefore; @ProtoField(number = 6) public Integer numFailures; diff --git a/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/realm/HotRodRealmEntity.java b/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/realm/HotRodRealmEntity.java index 571809fa8b0..d853c4e4593 100644 --- a/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/realm/HotRodRealmEntity.java +++ b/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/realm/HotRodRealmEntity.java @@ -133,7 +133,7 @@ public class HotRodRealmEntity extends AbstractHotRodEntity { @ProtoField(number = 29) public Integer clientSessionMaxLifespan; @ProtoField(number = 30) - public Integer notBefore; + public Long notBefore; @ProtoField(number = 31) public Integer offlineSessionIdleTimeout; @ProtoField(number = 32) diff --git a/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/realm/entity/HotRodClientInitialAccessEntity.java b/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/realm/entity/HotRodClientInitialAccessEntity.java index e0bc4d63b58..1f3f166e10e 100644 --- a/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/realm/entity/HotRodClientInitialAccessEntity.java +++ b/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/realm/entity/HotRodClientInitialAccessEntity.java @@ -13,11 +13,11 @@ public class HotRodClientInitialAccessEntity extends AbstractHotRodEntity { @ProtoField(number = 2) public Integer count; @ProtoField(number = 3) - public Integer expiration; + public Long expiration; @ProtoField(number = 4) public Integer remainingCount; @ProtoField(number = 5) - public Integer timestamp; + public Long timestamp; @Override public boolean equals(Object o) { return HotRodClientInitialAccessEntityDelegate.entityEquals(this, o); diff --git a/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/user/HotRodUserEntity.java b/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/user/HotRodUserEntity.java index 1dd02198926..c08740d57be 100644 --- a/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/user/HotRodUserEntity.java +++ b/model/map-hot-rod/src/main/java/org/keycloak/models/map/storage/hotRod/user/HotRodUserEntity.java @@ -153,7 +153,7 @@ public class HotRodUserEntity extends AbstractHotRodEntity { public String serviceAccountClientLink; @ProtoField(number = 21) - public Integer notBefore; + public Long notBefore; public static abstract class AbstractHotRodUserEntityDelegate extends UpdatableHotRodEntityDelegateImpl implements MapUserEntity { diff --git a/model/map-jpa/src/main/java/org/keycloak/models/map/storage/jpa/authSession/entity/JpaAuthenticationSessionEntity.java b/model/map-jpa/src/main/java/org/keycloak/models/map/storage/jpa/authSession/entity/JpaAuthenticationSessionEntity.java index f7cffe510fe..f34f7a9ce3f 100644 --- a/model/map-jpa/src/main/java/org/keycloak/models/map/storage/jpa/authSession/entity/JpaAuthenticationSessionEntity.java +++ b/model/map-jpa/src/main/java/org/keycloak/models/map/storage/jpa/authSession/entity/JpaAuthenticationSessionEntity.java @@ -153,12 +153,12 @@ public class JpaAuthenticationSessionEntity extends UpdatableEntity.Impl impleme } @Override - public Integer getTimestamp() { + public Long getTimestamp() { return metadata.getTimestamp(); } @Override - public void setTimestamp(Integer timestamp) { + public void setTimestamp(Long timestamp) { metadata.setTimestamp(timestamp); } diff --git a/model/map-jpa/src/main/java/org/keycloak/models/map/storage/jpa/authSession/entity/JpaRootAuthenticationSessionEntity.java b/model/map-jpa/src/main/java/org/keycloak/models/map/storage/jpa/authSession/entity/JpaRootAuthenticationSessionEntity.java index bb95cd6792c..40f41bec7e7 100644 --- a/model/map-jpa/src/main/java/org/keycloak/models/map/storage/jpa/authSession/entity/JpaRootAuthenticationSessionEntity.java +++ b/model/map-jpa/src/main/java/org/keycloak/models/map/storage/jpa/authSession/entity/JpaRootAuthenticationSessionEntity.java @@ -78,7 +78,7 @@ public class JpaRootAuthenticationSessionEntity extends AbstractRootAuthenticati @Column(insertable = false, updatable = false) @Basic(fetch = FetchType.LAZY) - private Integer timestamp; + private Long timestamp; @Column(insertable = false, updatable = false) @Basic(fetch = FetchType.LAZY) @@ -102,7 +102,7 @@ public class JpaRootAuthenticationSessionEntity extends AbstractRootAuthenticati * Used by hibernate when calling cb.construct from read(QueryParameters) method. * It is used to select root auth session without metadata(json) field. */ - public JpaRootAuthenticationSessionEntity(UUID id, Integer entityVersion, String realmId, Integer timestamp, Long expiration) { + public JpaRootAuthenticationSessionEntity(UUID id, Integer entityVersion, String realmId, Long timestamp, Long expiration) { this.id = id; this.entityVersion = entityVersion; this.realmId = realmId; @@ -158,13 +158,13 @@ public class JpaRootAuthenticationSessionEntity extends AbstractRootAuthenticati } @Override - public Integer getTimestamp() { + public Long getTimestamp() { if (isMetadataInitialized()) return metadata.getTimestamp(); return timestamp; } @Override - public void setTimestamp(Integer timestamp) { + public void setTimestamp(Long timestamp) { metadata.setTimestamp(timestamp); } diff --git a/model/map-jpa/src/main/java/org/keycloak/models/map/storage/jpa/client/entity/JpaClientEntity.java b/model/map-jpa/src/main/java/org/keycloak/models/map/storage/jpa/client/entity/JpaClientEntity.java index 309f0919cd2..572bfbc16bb 100644 --- a/model/map-jpa/src/main/java/org/keycloak/models/map/storage/jpa/client/entity/JpaClientEntity.java +++ b/model/map-jpa/src/main/java/org/keycloak/models/map/storage/jpa/client/entity/JpaClientEntity.java @@ -363,12 +363,12 @@ public class JpaClientEntity extends AbstractClientEntity implements JpaRootVers } @Override - public Integer getNotBefore() { + public Long getNotBefore() { return metadata.getNotBefore(); } @Override - public void setNotBefore(Integer notBefore) { + public void setNotBefore(Long notBefore) { metadata.setNotBefore(notBefore); } diff --git a/model/map-jpa/src/main/resources/META-INF/auth-sessions/jpa-auth-sessions-changelog-1.xml b/model/map-jpa/src/main/resources/META-INF/auth-sessions/jpa-auth-sessions-changelog-1.xml index 1a3bbfe484f..a697746e0cd 100644 --- a/model/map-jpa/src/main/resources/META-INF/auth-sessions/jpa-auth-sessions-changelog-1.xml +++ b/model/map-jpa/src/main/resources/META-INF/auth-sessions/jpa-auth-sessions-changelog-1.xml @@ -37,7 +37,7 @@ limitations under the License. - + diff --git a/model/map/src/main/java/org/keycloak/models/map/authSession/MapAuthenticationSessionEntity.java b/model/map/src/main/java/org/keycloak/models/map/authSession/MapAuthenticationSessionEntity.java index 1adcb9aa84c..49c6f9185d7 100644 --- a/model/map/src/main/java/org/keycloak/models/map/authSession/MapAuthenticationSessionEntity.java +++ b/model/map/src/main/java/org/keycloak/models/map/authSession/MapAuthenticationSessionEntity.java @@ -44,8 +44,8 @@ public interface MapAuthenticationSessionEntity extends UpdatableEntity { String getAuthUserId(); void setAuthUserId(String authUserId); - Integer getTimestamp(); - void setTimestamp(Integer timestamp); + Long getTimestamp(); + void setTimestamp(Long timestamp); String getRedirectUri(); void setRedirectUri(String redirectUri); diff --git a/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionAdapter.java b/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionAdapter.java index 1424dfdeda2..b2d95d0743e 100644 --- a/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionAdapter.java +++ b/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionAdapter.java @@ -22,6 +22,7 @@ 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.map.common.TimeAdapter; import org.keycloak.models.utils.SessionExpiration; import org.keycloak.sessions.AuthenticationSessionModel; @@ -52,12 +53,12 @@ public class MapRootAuthenticationSessionAdapter extends AbstractRootAuthenticat @Override public int getTimestamp() { - return entity.getTimestamp(); + return TimeAdapter.fromLongWithTimeInSecondsToIntegerWithTimeInSeconds(entity.getTimestamp()); } @Override public void setTimestamp(int timestamp) { - entity.setTimestamp(timestamp); + entity.setTimestamp(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(timestamp)); entity.setExpiration(SessionExpiration.getAuthSessionExpiration(realm, timestamp)); } @@ -84,14 +85,14 @@ public class MapRootAuthenticationSessionAdapter extends AbstractRootAuthenticat authSessionEntity.setClientUUID(client.getId()); int timestamp = Time.currentTime(); - authSessionEntity.setTimestamp(timestamp); + authSessionEntity.setTimestamp(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(timestamp)); String tabId = generateTabId(); authSessionEntity.setTabId(tabId); entity.addAuthenticationSession(authSessionEntity); // Update our timestamp when adding new authenticationSession - entity.setTimestamp(timestamp); + entity.setTimestamp(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(timestamp)); entity.setExpiration(SessionExpiration.getAuthSessionExpiration(realm, timestamp)); return entity.getAuthenticationSession(tabId).map(this::toAdapter).map(this::setAuthContext).orElse(null); @@ -105,7 +106,7 @@ public class MapRootAuthenticationSessionAdapter extends AbstractRootAuthenticat session.authenticationSessions().removeRootAuthenticationSession(realm, this); } else { int timestamp = Time.currentTime(); - entity.setTimestamp(timestamp); + entity.setTimestamp(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(timestamp)); entity.setExpiration(SessionExpiration.getAuthSessionExpiration(realm, timestamp)); } } @@ -115,7 +116,7 @@ public class MapRootAuthenticationSessionAdapter extends AbstractRootAuthenticat public void restartSession(RealmModel realm) { entity.setAuthenticationSessions(null); int timestamp = Time.currentTime(); - entity.setTimestamp(timestamp); + entity.setTimestamp(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(timestamp)); entity.setExpiration(SessionExpiration.getAuthSessionExpiration(realm, timestamp)); } diff --git a/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionEntity.java b/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionEntity.java index 1be52ccd8fa..683c9a60041 100644 --- a/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionEntity.java +++ b/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionEntity.java @@ -84,8 +84,8 @@ public interface MapRootAuthenticationSessionEntity extends AbstractEntity, Upda String getRealmId(); void setRealmId(String realmId); - Integer getTimestamp(); - void setTimestamp(Integer timestamp); + Long getTimestamp(); + void setTimestamp(Long timestamp); Long getExpiration(); void setExpiration(Long expiration); diff --git a/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionProvider.java b/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionProvider.java index 1a834a56ceb..1a2ee526296 100644 --- a/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionProvider.java +++ b/model/map/src/main/java/org/keycloak/models/map/authSession/MapRootAuthenticationSessionProvider.java @@ -23,6 +23,7 @@ import org.keycloak.models.ClientModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.ModelDuplicateException; import org.keycloak.models.RealmModel; +import org.keycloak.models.map.common.TimeAdapter; import org.keycloak.models.map.storage.MapKeycloakTransaction; import org.keycloak.models.map.storage.MapStorage; import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator; @@ -99,7 +100,7 @@ public class MapRootAuthenticationSessionProvider implements AuthenticationSessi entity.setId(id); entity.setRealmId(realm.getId()); int timestamp = Time.currentTime(); - entity.setTimestamp(timestamp); + entity.setTimestamp(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(timestamp)); entity.setExpiration(SessionExpiration.getAuthSessionExpiration(realm, timestamp)); if (id != null && tx.read(id) != null) { diff --git a/model/map/src/main/java/org/keycloak/models/map/client/MapClientAdapter.java b/model/map/src/main/java/org/keycloak/models/map/client/MapClientAdapter.java index 55b3961a111..f1636f79ad6 100644 --- a/model/map/src/main/java/org/keycloak/models/map/client/MapClientAdapter.java +++ b/model/map/src/main/java/org/keycloak/models/map/client/MapClientAdapter.java @@ -22,6 +22,7 @@ import org.keycloak.models.KeycloakSession; import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.RealmModel; import org.keycloak.models.RoleModel; +import org.keycloak.models.map.common.TimeAdapter; import org.keycloak.models.utils.KeycloakModelUtils; import java.security.MessageDigest; import java.util.Collection; @@ -418,13 +419,13 @@ public abstract class MapClientAdapter extends AbstractClientModel tx; - private final ConcurrentMap> clientRegisteredNodesStore; + private final ConcurrentMap> clientRegisteredNodesStore; - public MapClientProvider(KeycloakSession session, MapStorage clientStore, ConcurrentMap> clientRegisteredNodesStore) { + public MapClientProvider(KeycloakSession session, MapStorage clientStore, ConcurrentMap> clientRegisteredNodesStore) { this.session = session; this.clientRegisteredNodesStore = clientRegisteredNodesStore; this.tx = clientStore.createTransaction(session); @@ -92,18 +95,25 @@ public class MapClientProvider implements ClientProvider { /** This is runtime information and should have never been part of the adapter */ @Override public Map getRegisteredNodes() { - return clientRegisteredNodesStore.computeIfAbsent(entity.getId(), k -> new ConcurrentHashMap<>()); + return Collections.unmodifiableMap(getMapForEntity() + .entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> TimeAdapter.fromLongWithTimeInSecondsToIntegerWithTimeInSeconds(e.getValue()))) + ); } @Override public void registerNode(String nodeHost, int registrationTime) { - Map value = getRegisteredNodes(); - value.put(nodeHost, registrationTime); + getMapForEntity().put(nodeHost, TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(registrationTime)); } @Override public void unregisterNode(String nodeHost) { - getRegisteredNodes().remove(nodeHost); + getMapForEntity().remove(nodeHost); + } + + private ConcurrentMap getMapForEntity() { + return clientRegisteredNodesStore.computeIfAbsent(entity.getId(), k -> new ConcurrentHashMap<>()); } }; diff --git a/model/map/src/main/java/org/keycloak/models/map/client/MapClientProviderFactory.java b/model/map/src/main/java/org/keycloak/models/map/client/MapClientProviderFactory.java index a82c1985f34..af6a64be4b3 100644 --- a/model/map/src/main/java/org/keycloak/models/map/client/MapClientProviderFactory.java +++ b/model/map/src/main/java/org/keycloak/models/map/client/MapClientProviderFactory.java @@ -37,7 +37,7 @@ import java.util.concurrent.ConcurrentMap; */ public class MapClientProviderFactory extends AbstractMapProviderFactory implements ClientProviderFactory, ProviderEventListener { - private final ConcurrentHashMap> REGISTERED_NODES_STORE = new ConcurrentHashMap<>(); + private final ConcurrentHashMap> REGISTERED_NODES_STORE = new ConcurrentHashMap<>(); private Runnable onClose; diff --git a/model/map/src/main/java/org/keycloak/models/map/common/TimeAdapter.java b/model/map/src/main/java/org/keycloak/models/map/common/TimeAdapter.java new file mode 100644 index 00000000000..563b16ce1c1 --- /dev/null +++ b/model/map/src/main/java/org/keycloak/models/map/common/TimeAdapter.java @@ -0,0 +1,55 @@ +/* + * Copyright 2022. 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.map.common; + +import org.jboss.logging.Logger; + +/** + * Wrapper for adapters around handling time in seconds. + * + * Will be removed once #11053 has been implemented. + + * @author Alexander Schwartz + */ +public class TimeAdapter { + private static final Logger LOG = Logger.getLogger(TimeAdapter.class); + + /** + * Wrapper to all unsafe downgrading from a Long to an Integer while Keycloak core still handles all time since 1970 as seconds as integers. + * This is safer to use than downgrading in several places as that might be missed once the Core starts to use longs as timestamps as well. + * Simplify/remove once #11053 has been implemented. + */ + + public static int fromLongWithTimeInSecondsToIntegerWithTimeInSeconds(Long timestamp) { + if (timestamp > Integer.MAX_VALUE) { + LOG.warn("Trimmed time value found in the map store; value too large and not supported in core"); + return Integer.MAX_VALUE; + } else { + return timestamp.intValue(); + } + } + + /** + * Wrapper to all upgrading from an Integer to a Long while Keycloak core still handles all time seconds since 1970 as seconds as integers. + * This is safer to use and remove once the Core starts to use longs as timestamps as well. + * Simplify/remove once #11053 has been implemented. + */ + public static long fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(int timestamp) { + return timestamp; + } +} diff --git a/model/map/src/main/java/org/keycloak/models/map/loginFailure/MapUserLoginFailureAdapter.java b/model/map/src/main/java/org/keycloak/models/map/loginFailure/MapUserLoginFailureAdapter.java index e9a66da6fa8..3b9d75d51db 100644 --- a/model/map/src/main/java/org/keycloak/models/map/loginFailure/MapUserLoginFailureAdapter.java +++ b/model/map/src/main/java/org/keycloak/models/map/loginFailure/MapUserLoginFailureAdapter.java @@ -18,6 +18,7 @@ package org.keycloak.models.map.loginFailure; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; +import org.keycloak.models.map.common.TimeAdapter; /** * @author Martin Kanis @@ -39,13 +40,13 @@ public class MapUserLoginFailureAdapter extends AbstractUserLoginFailureModel implemen @Override public int getNotBefore() { - Integer i = entity.getNotBefore(); - return i == null ? 0 : i; + Long notBefore = entity.getNotBefore(); + return notBefore == null ? 0 : TimeAdapter.fromLongWithTimeInSecondsToIntegerWithTimeInSeconds(notBefore); } @Override public void setNotBefore(int notBefore) { - entity.setNotBefore(notBefore); + entity.setNotBefore(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(notBefore)); } @Override diff --git a/model/map/src/main/java/org/keycloak/models/map/realm/MapRealmEntity.java b/model/map/src/main/java/org/keycloak/models/map/realm/MapRealmEntity.java index 3074b311f75..b56ddfb7020 100644 --- a/model/map/src/main/java/org/keycloak/models/map/realm/MapRealmEntity.java +++ b/model/map/src/main/java/org/keycloak/models/map/realm/MapRealmEntity.java @@ -332,8 +332,8 @@ public interface MapRealmEntity extends UpdatableEntity, AbstractEntity, EntityW Integer getAccessCodeLifespanLogin(); void setAccessCodeLifespanLogin(Integer accessCodeLifespanLogin); - Integer getNotBefore(); - void setNotBefore(Integer notBefore); + Long getNotBefore(); + void setNotBefore(Long notBefore); Integer getClientSessionIdleTimeout(); void setClientSessionIdleTimeout(Integer clientSessionIdleTimeout); diff --git a/model/map/src/main/java/org/keycloak/models/map/realm/entity/MapClientInitialAccessEntity.java b/model/map/src/main/java/org/keycloak/models/map/realm/entity/MapClientInitialAccessEntity.java index 95e604a8a5b..dfb26c4be11 100644 --- a/model/map/src/main/java/org/keycloak/models/map/realm/entity/MapClientInitialAccessEntity.java +++ b/model/map/src/main/java/org/keycloak/models/map/realm/entity/MapClientInitialAccessEntity.java @@ -19,6 +19,7 @@ package org.keycloak.models.map.realm.entity; import org.keycloak.common.util.Time; import org.keycloak.models.ClientInitialAccessModel; +import org.keycloak.models.map.common.TimeAdapter; import org.keycloak.models.map.annotations.GenerateEntityImplementations; import org.keycloak.models.map.common.AbstractEntity; import org.keycloak.models.map.common.DeepCloner; @@ -33,8 +34,8 @@ public interface MapClientInitialAccessEntity extends UpdatableEntity, AbstractE MapClientInitialAccessEntity entity = new MapClientInitialAccessEntityImpl(); entity.setId(KeycloakModelUtils.generateId()); - entity.setTimestamp(currentTime); - entity.setExpiration(expiration); + entity.setTimestamp(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(currentTime)); + entity.setExpiration(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(expiration)); entity.setCount(count); entity.setRemainingCount(count); return entity; @@ -44,10 +45,10 @@ public interface MapClientInitialAccessEntity extends UpdatableEntity, AbstractE if (entity == null) return null; ClientInitialAccessModel model = new ClientInitialAccessModel(); model.setId(entity.getId()); - Integer timestamp = entity.getTimestamp(); - model.setTimestamp(timestamp == null ? 0 : timestamp); - Integer expiration = entity.getExpiration(); - model.setExpiration(expiration == null ? 0 : expiration); + Long timestamp = entity.getTimestamp(); + model.setTimestamp(timestamp == null ? 0 : TimeAdapter.fromLongWithTimeInSecondsToIntegerWithTimeInSeconds(timestamp)); + Long expiration = entity.getExpiration(); + model.setExpiration(expiration == null ? 0 : TimeAdapter.fromLongWithTimeInSecondsToIntegerWithTimeInSeconds(expiration)); Integer count = entity.getCount(); model.setCount(count == null ? 0 : count); Integer remainingCount = entity.getRemainingCount(); @@ -55,11 +56,11 @@ public interface MapClientInitialAccessEntity extends UpdatableEntity, AbstractE return model; } - Integer getTimestamp(); - void setTimestamp(Integer timestamp); + Long getTimestamp(); + void setTimestamp(Long timestamp); - Integer getExpiration(); - void setExpiration(Integer expiration); + Long getExpiration(); + void setExpiration(Long expiration); Integer getCount(); void setCount(Integer count); diff --git a/model/map/src/main/java/org/keycloak/models/map/user/MapUserEntity.java b/model/map/src/main/java/org/keycloak/models/map/user/MapUserEntity.java index 0872905d35d..b1a162fe5b1 100644 --- a/model/map/src/main/java/org/keycloak/models/map/user/MapUserEntity.java +++ b/model/map/src/main/java/org/keycloak/models/map/user/MapUserEntity.java @@ -244,6 +244,6 @@ public interface MapUserEntity extends UpdatableEntity, AbstractEntity, EntityWi String getServiceAccountClientLink(); void setServiceAccountClientLink(String serviceAccountClientLink); - Integer getNotBefore(); - void setNotBefore(Integer notBefore); + Long getNotBefore(); + void setNotBefore(Long notBefore); } diff --git a/model/map/src/main/java/org/keycloak/models/map/user/MapUserProvider.java b/model/map/src/main/java/org/keycloak/models/map/user/MapUserProvider.java index 04496952db6..c510a177c1e 100644 --- a/model/map/src/main/java/org/keycloak/models/map/user/MapUserProvider.java +++ b/model/map/src/main/java/org/keycloak/models/map/user/MapUserProvider.java @@ -41,6 +41,7 @@ import org.keycloak.models.UserConsentModel; import org.keycloak.models.UserModel; import org.keycloak.models.UserModel.SearchableFields; import org.keycloak.models.UserProvider; +import org.keycloak.models.map.common.TimeAdapter; import org.keycloak.models.map.storage.MapKeycloakTransaction; import org.keycloak.models.map.storage.MapStorage; import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator; @@ -278,17 +279,17 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor @Override public void setNotBeforeForUser(RealmModel realm, UserModel user, int notBefore) { LOG.tracef("setNotBeforeForUser(%s, %s, %d)%s", realm, user.getId(), notBefore, getShortStackTrace()); - getEntityByIdOrThrow(realm, user.getId()).setNotBefore(notBefore); + getEntityByIdOrThrow(realm, user.getId()).setNotBefore(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(notBefore)); } @Override public int getNotBeforeOfUser(RealmModel realm, UserModel user) { LOG.tracef("getNotBeforeOfUser(%s, %s)%s", realm, user.getId(), getShortStackTrace()); - Integer notBefore = getEntityById(realm, user.getId()) + Long notBefore = getEntityById(realm, user.getId()) .orElseThrow(this::userDoesntExistException) .getNotBefore(); - return notBefore == null ? 0 : notBefore; + return notBefore == null ? 0 : TimeAdapter.fromLongWithTimeInSecondsToIntegerWithTimeInSeconds(notBefore); } @Override diff --git a/model/map/src/main/java/org/keycloak/models/map/userSession/MapAuthenticatedClientSessionAdapter.java b/model/map/src/main/java/org/keycloak/models/map/userSession/MapAuthenticatedClientSessionAdapter.java index e4936019adb..e03f767b27a 100644 --- a/model/map/src/main/java/org/keycloak/models/map/userSession/MapAuthenticatedClientSessionAdapter.java +++ b/model/map/src/main/java/org/keycloak/models/map/userSession/MapAuthenticatedClientSessionAdapter.java @@ -20,6 +20,7 @@ import org.keycloak.models.ClientModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.UserSessionModel; +import org.keycloak.models.map.common.TimeAdapter; import java.util.Collections; import java.util.Map; @@ -41,13 +42,13 @@ public abstract class MapAuthenticatedClientSessionAdapter extends AbstractAuthe @Override public int getTimestamp() { - Integer timestamp = entity.getTimestamp(); - return timestamp != null ? timestamp : 0; + Long timestamp = entity.getTimestamp(); + return timestamp != null ? TimeAdapter.fromLongWithTimeInSecondsToIntegerWithTimeInSeconds(timestamp) : 0; } @Override public void setTimestamp(int timestamp) { - entity.setTimestamp(timestamp); + entity.setTimestamp(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(timestamp)); } @Override diff --git a/model/map/src/main/java/org/keycloak/models/map/userSession/MapAuthenticatedClientSessionEntity.java b/model/map/src/main/java/org/keycloak/models/map/userSession/MapAuthenticatedClientSessionEntity.java index bd6e5633f77..437c201622b 100644 --- a/model/map/src/main/java/org/keycloak/models/map/userSession/MapAuthenticatedClientSessionEntity.java +++ b/model/map/src/main/java/org/keycloak/models/map/userSession/MapAuthenticatedClientSessionEntity.java @@ -32,7 +32,7 @@ import java.util.Map; @DeepCloner.Root public interface MapAuthenticatedClientSessionEntity extends AbstractEntity, UpdatableEntity { - public abstract class AbstractAuthenticatedClientSessionEntity extends UpdatableEntity.Impl implements MapAuthenticatedClientSessionEntity { + abstract class AbstractAuthenticatedClientSessionEntity extends UpdatableEntity.Impl implements MapAuthenticatedClientSessionEntity { private String id; @@ -64,8 +64,8 @@ public interface MapAuthenticatedClientSessionEntity extends AbstractEntity, Upd String getRedirectUri(); void setRedirectUri(String redirectUri); - Integer getTimestamp(); - void setTimestamp(Integer timestamp); + Long getTimestamp(); + void setTimestamp(Long timestamp); Long getExpiration(); void setExpiration(Long expiration); diff --git a/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionAdapter.java b/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionAdapter.java index 6fa34c32ca9..2471ed83d96 100644 --- a/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionAdapter.java +++ b/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionAdapter.java @@ -24,6 +24,8 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; +import org.keycloak.models.map.common.TimeAdapter; + import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; @@ -89,19 +91,19 @@ public abstract class MapUserSessionAdapter extends AbstractUserSessionModel { @Override public int getStarted() { - Integer started = entity.getStarted(); - return started != null ? started : 0; + Long started = entity.getStarted(); + return started != null ? TimeAdapter.fromLongWithTimeInSecondsToIntegerWithTimeInSeconds(started) : 0; } @Override public int getLastSessionRefresh() { - Integer lastSessionRefresh = entity.getLastSessionRefresh(); - return lastSessionRefresh != null ? lastSessionRefresh : 0; + Long lastSessionRefresh = entity.getLastSessionRefresh(); + return lastSessionRefresh != null ? TimeAdapter.fromLongWithTimeInSecondsToIntegerWithTimeInSeconds(lastSessionRefresh) : 0; } @Override public void setLastSessionRefresh(int seconds) { - entity.setLastSessionRefresh(seconds); + entity.setLastSessionRefresh(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(seconds)); } @Override @@ -214,8 +216,8 @@ public abstract class MapUserSessionAdapter extends AbstractUserSessionModel { entity.setBrokerUserId(brokerUserId); int currentTime = Time.currentTime(); - entity.setStarted(currentTime); - entity.setLastSessionRefresh(currentTime); + entity.setStarted(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(currentTime)); + entity.setLastSessionRefresh(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(currentTime)); entity.setState(null); diff --git a/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionEntity.java b/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionEntity.java index 65fc3b1d553..cff6025cabf 100644 --- a/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionEntity.java +++ b/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionEntity.java @@ -34,7 +34,7 @@ import java.util.Map; @DeepCloner.Root public interface MapUserSessionEntity extends AbstractEntity, UpdatableEntity { - public abstract class AbstractUserSessionEntity extends UpdatableEntity.Impl implements MapUserSessionEntity { + abstract class AbstractUserSessionEntity extends UpdatableEntity.Impl implements MapUserSessionEntity { private String id; @@ -75,12 +75,11 @@ public interface MapUserSessionEntity extends AbstractEntity, UpdatableEntity { Boolean isRememberMe(); void setRememberMe(Boolean rememberMe); - Integer getStarted(); - void setStarted(Integer started); + Long getStarted(); + void setStarted(Long started); - Integer getLastSessionRefresh(); - - void setLastSessionRefresh(Integer lastSessionRefresh); + Long getLastSessionRefresh(); + void setLastSessionRefresh(Long lastSessionRefresh); Long getExpiration(); void setExpiration(Long expiration); diff --git a/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionProvider.java b/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionProvider.java index 1b99a39d09f..389b1375bab 100644 --- a/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionProvider.java +++ b/model/map/src/main/java/org/keycloak/models/map/userSession/MapUserSessionProvider.java @@ -27,6 +27,7 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; import org.keycloak.models.UserSessionProvider; +import org.keycloak.models.map.common.TimeAdapter; import org.keycloak.models.map.storage.MapKeycloakTransaction; import org.keycloak.models.map.storage.MapStorage; import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator; @@ -81,7 +82,7 @@ public class MapUserSessionProvider implements UserSessionProvider { private Function userEntityToAdapterFunc(RealmModel realm) { // Clone entity before returning back, to avoid giving away a reference to the live object to the caller return (origEntity) -> { - long expiration = origEntity.getExpiration() != null ? origEntity.getExpiration() : 0l; + long expiration = origEntity.getExpiration() != null ? origEntity.getExpiration() : 0L; if (expiration <= Time.currentTime()) { if (Objects.equals(origEntity.getPersistenceState(), TRANSIENT)) { transientUserSessions.remove(origEntity.getId()); @@ -97,7 +98,7 @@ public class MapUserSessionProvider implements UserSessionProvider { @Override public void setLastSessionRefresh(int lastSessionRefresh) { - entity.setLastSessionRefresh(lastSessionRefresh); + entity.setLastSessionRefresh(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(lastSessionRefresh)); // whenever the lastSessionRefresh is changed recompute the expiration time setUserSessionExpiration(entity, realm); } @@ -111,7 +112,7 @@ public class MapUserSessionProvider implements UserSessionProvider { UserSessionModel userSession) { // Clone entity before returning back, to avoid giving away a reference to the live object to the caller return origEntity -> { - long expiration = origEntity.getExpiration() != null ? origEntity.getExpiration() : 0l; + long expiration = origEntity.getExpiration() != null ? origEntity.getExpiration() : 0L; if (expiration <= Time.currentTime()) { userSession.removeAuthenticatedClientSessions(Arrays.asList(origEntity.getClientId())); clientSessionTx.delete(origEntity.getId()); @@ -127,7 +128,7 @@ public class MapUserSessionProvider implements UserSessionProvider { @Override public void setTimestamp(int timestamp) { - entity.setTimestamp(timestamp); + entity.setTimestamp(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(timestamp)); // whenever the timestamp is changed recompute the expiration time setClientSessionExpiration(entity, realm, client); } @@ -424,8 +425,8 @@ public class MapUserSessionProvider implements UserSessionProvider { userSession.setNote(CORRESPONDING_SESSION_ID, offlineUserSession.getId()); int currentTime = Time.currentTime(); - offlineUserSession.setStarted(currentTime); - offlineUserSession.setLastSessionRefresh(currentTime); + offlineUserSession.setStarted(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(currentTime)); + offlineUserSession.setLastSessionRefresh(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(currentTime)); setUserSessionExpiration(offlineUserSession, userSession.getRealm()); return userEntityToAdapterFunc(userSession.getRealm()).apply(offlineUserSession); @@ -467,7 +468,7 @@ public class MapUserSessionProvider implements UserSessionProvider { MapAuthenticatedClientSessionEntity clientSessionEntity = createAuthenticatedClientSessionInstance(clientSession, offlineUserSession, true); int currentTime = Time.currentTime(); clientSessionEntity.setNote(AuthenticatedClientSessionModel.STARTED_AT_NOTE, String.valueOf(currentTime)); - clientSessionEntity.setTimestamp(currentTime); + clientSessionEntity.setTimestamp(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(currentTime)); setClientSessionExpiration(clientSessionEntity, clientSession.getRealm(), clientSession.getClient()); clientSessionEntity = clientSessionTx.create(clientSessionEntity); @@ -631,8 +632,8 @@ public class MapUserSessionProvider implements UserSessionProvider { entity.setNotes(new ConcurrentHashMap<>(userSession.getNotes())); entity.setNote(CORRESPONDING_SESSION_ID, userSession.getId()); entity.setState(userSession.getState()); - entity.setStarted(userSession.getStarted()); - entity.setLastSessionRefresh(userSession.getLastSessionRefresh()); + entity.setStarted(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(userSession.getStarted())); + entity.setLastSessionRefresh(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(userSession.getLastSessionRefresh())); return entity; } @@ -647,7 +648,7 @@ public class MapUserSessionProvider implements UserSessionProvider { entity.setNotes(new ConcurrentHashMap<>(clientSession.getNotes())); entity.setRedirectUri(clientSession.getRedirectUri()); - entity.setTimestamp(clientSession.getTimestamp()); + entity.setTimestamp(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(clientSession.getTimestamp())); return entity; } @@ -666,7 +667,7 @@ public class MapUserSessionProvider implements UserSessionProvider { userSessionEntity.setBrokerSessionId(brokerSessionId); userSessionEntity.setBrokerUserId(brokerUserId); userSessionEntity.setOffline(offline); - userSessionEntity.setStarted(Time.currentTime()); + userSessionEntity.setStarted(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(Time.currentTime())); userSessionEntity.setLastSessionRefresh(userSessionEntity.getStarted()); return userSessionEntity; } @@ -679,7 +680,7 @@ public class MapUserSessionProvider implements UserSessionProvider { clientSessionEntity.setRealmId(realmId); clientSessionEntity.setClientId(clientId); clientSessionEntity.setOffline(offline); - clientSessionEntity.setTimestamp(Time.currentTime()); + clientSessionEntity.setTimestamp(TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(Time.currentTime())); return clientSessionEntity; } diff --git a/model/map/src/main/java/org/keycloak/models/map/userSession/SessionExpiration.java b/model/map/src/main/java/org/keycloak/models/map/userSession/SessionExpiration.java index ac7f1ed367c..de32267ed59 100644 --- a/model/map/src/main/java/org/keycloak/models/map/userSession/SessionExpiration.java +++ b/model/map/src/main/java/org/keycloak/models/map/userSession/SessionExpiration.java @@ -27,7 +27,7 @@ import org.keycloak.protocol.oidc.OIDCConfigAttributes; public class SessionExpiration { public static void setClientSessionExpiration(MapAuthenticatedClientSessionEntity entity, RealmModel realm, ClientModel client) { - long timestamp = entity.getTimestamp() != null ? entity.getTimestamp() : 0l; + long timestamp = entity.getTimestamp() != null ? entity.getTimestamp() : 0L; if (Boolean.TRUE.equals(entity.isOffline())) { long sessionExpires = timestamp + realm.getOfflineSessionIdleTimeout(); if (realm.isOfflineSessionMaxLifespanEnabled()) { @@ -101,8 +101,8 @@ public class SessionExpiration { } public static void setUserSessionExpiration(MapUserSessionEntity entity, RealmModel realm) { - int started = entity.getStarted() != null ? entity.getStarted() : 0; - long lastSessionRefresh = entity.getLastSessionRefresh() != null ? entity.getLastSessionRefresh() : 0l; + long started = entity.getStarted() != null ? entity.getStarted() : 0L; + long lastSessionRefresh = entity.getLastSessionRefresh() != null ? entity.getLastSessionRefresh() : 0L; if (Boolean.TRUE.equals(entity.isOffline())) { long sessionExpires = lastSessionRefresh + realm.getOfflineSessionIdleTimeout(); if (realm.isOfflineSessionMaxLifespanEnabled()) { @@ -127,7 +127,7 @@ public class SessionExpiration { entity.setExpiration(Math.min(expiration, sessionExpires)); } else { - long sessionExpires = (long) started + long sessionExpires = started + (Boolean.TRUE.equals(entity.isRememberMe()) && realm.getSsoSessionMaxLifespanRememberMe() > 0 ? realm.getSsoSessionMaxLifespanRememberMe() : realm.getSsoSessionMaxLifespan()); diff --git a/model/map/src/test/java/org/keycloak/models/map/common/TimeAdapterTest.java b/model/map/src/test/java/org/keycloak/models/map/common/TimeAdapterTest.java new file mode 100644 index 00000000000..d37e82fe44b --- /dev/null +++ b/model/map/src/test/java/org/keycloak/models/map/common/TimeAdapterTest.java @@ -0,0 +1,43 @@ +/* + * Copyright 2022. 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.map.common; + +import org.junit.Assert; +import org.junit.Test; + +/** + * @author Alexander Schwartz + */ +public class TimeAdapterTest { + + @Test + public void shouldConvertIntegersToLongs() { + Assert.assertEquals(0, TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(0)); + Assert.assertEquals(1, TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(1)); + Assert.assertEquals(Integer.MAX_VALUE, TimeAdapter.fromIntegerWithTimeInSecondsToLongWithTimeAsInSeconds(Integer.MAX_VALUE)); + } + + @Test + public void shouldConvertLongsToIntegersSafely() { + Assert.assertEquals(0, TimeAdapter.fromLongWithTimeInSecondsToIntegerWithTimeInSeconds((long) 0)); + Assert.assertEquals(1, TimeAdapter.fromLongWithTimeInSecondsToIntegerWithTimeInSeconds((long) 1)); + Assert.assertEquals(Integer.MAX_VALUE, TimeAdapter.fromLongWithTimeInSecondsToIntegerWithTimeInSeconds((long) Integer.MAX_VALUE)); + Assert.assertEquals(Integer.MAX_VALUE, TimeAdapter.fromLongWithTimeInSecondsToIntegerWithTimeInSeconds(Long.MAX_VALUE)); + } + +} \ No newline at end of file