KEYCLOAK-14145 OIDC support for Client "offline" session lifespan
This commit is contained in:
parent
82cfb8e821
commit
f03ee2ec98
19 changed files with 413 additions and 12 deletions
|
@ -52,6 +52,8 @@ public class RealmRepresentation {
|
||||||
protected Integer offlineSessionMaxLifespan;
|
protected Integer offlineSessionMaxLifespan;
|
||||||
protected Integer clientSessionIdleTimeout;
|
protected Integer clientSessionIdleTimeout;
|
||||||
protected Integer clientSessionMaxLifespan;
|
protected Integer clientSessionMaxLifespan;
|
||||||
|
protected Integer clientOfflineSessionIdleTimeout;
|
||||||
|
protected Integer clientOfflineSessionMaxLifespan;
|
||||||
protected Integer accessCodeLifespan;
|
protected Integer accessCodeLifespan;
|
||||||
protected Integer accessCodeLifespanUserAction;
|
protected Integer accessCodeLifespanUserAction;
|
||||||
protected Integer accessCodeLifespanLogin;
|
protected Integer accessCodeLifespanLogin;
|
||||||
|
@ -387,6 +389,22 @@ public class RealmRepresentation {
|
||||||
this.clientSessionMaxLifespan = clientSessionMaxLifespan;
|
this.clientSessionMaxLifespan = clientSessionMaxLifespan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer getClientOfflineSessionIdleTimeout() {
|
||||||
|
return clientOfflineSessionIdleTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientOfflineSessionIdleTimeout(Integer clientOfflineSessionIdleTimeout) {
|
||||||
|
this.clientOfflineSessionIdleTimeout = clientOfflineSessionIdleTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getClientOfflineSessionMaxLifespan() {
|
||||||
|
return clientOfflineSessionMaxLifespan;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientOfflineSessionMaxLifespan(Integer clientOfflineSessionMaxLifespan) {
|
||||||
|
this.clientOfflineSessionMaxLifespan = clientOfflineSessionMaxLifespan;
|
||||||
|
}
|
||||||
|
|
||||||
public List<ScopeMappingRepresentation> getScopeMappings() {
|
public List<ScopeMappingRepresentation> getScopeMappings() {
|
||||||
return scopeMappings;
|
return scopeMappings;
|
||||||
}
|
}
|
||||||
|
|
|
@ -506,6 +506,32 @@ public class RealmAdapter implements CachedRealmModel {
|
||||||
updated.setClientSessionMaxLifespan(seconds);
|
updated.setClientSessionMaxLifespan(seconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getClientOfflineSessionIdleTimeout() {
|
||||||
|
if (isUpdated())
|
||||||
|
return updated.getClientOfflineSessionIdleTimeout();
|
||||||
|
return cached.getClientOfflineSessionIdleTimeout();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setClientOfflineSessionIdleTimeout(int seconds) {
|
||||||
|
getDelegateForUpdate();
|
||||||
|
updated.setClientOfflineSessionIdleTimeout(seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getClientOfflineSessionMaxLifespan() {
|
||||||
|
if (isUpdated())
|
||||||
|
return updated.getClientOfflineSessionMaxLifespan();
|
||||||
|
return cached.getClientOfflineSessionMaxLifespan();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setClientOfflineSessionMaxLifespan(int seconds) {
|
||||||
|
getDelegateForUpdate();
|
||||||
|
updated.setClientOfflineSessionMaxLifespan(seconds);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getAccessTokenLifespan() {
|
public int getAccessTokenLifespan() {
|
||||||
if (isUpdated()) return updated.getAccessTokenLifespan();
|
if (isUpdated()) return updated.getAccessTokenLifespan();
|
||||||
|
|
|
@ -88,6 +88,8 @@ public class CachedRealm extends AbstractExtendableRevisioned {
|
||||||
protected int offlineSessionMaxLifespan;
|
protected int offlineSessionMaxLifespan;
|
||||||
protected int clientSessionIdleTimeout;
|
protected int clientSessionIdleTimeout;
|
||||||
protected int clientSessionMaxLifespan;
|
protected int clientSessionMaxLifespan;
|
||||||
|
protected int clientOfflineSessionIdleTimeout;
|
||||||
|
protected int clientOfflineSessionMaxLifespan;
|
||||||
protected int accessTokenLifespan;
|
protected int accessTokenLifespan;
|
||||||
protected int accessTokenLifespanForImplicitFlow;
|
protected int accessTokenLifespanForImplicitFlow;
|
||||||
protected int accessCodeLifespan;
|
protected int accessCodeLifespan;
|
||||||
|
@ -201,6 +203,8 @@ public class CachedRealm extends AbstractExtendableRevisioned {
|
||||||
offlineSessionMaxLifespan = model.getOfflineSessionMaxLifespan();
|
offlineSessionMaxLifespan = model.getOfflineSessionMaxLifespan();
|
||||||
clientSessionIdleTimeout = model.getClientSessionIdleTimeout();
|
clientSessionIdleTimeout = model.getClientSessionIdleTimeout();
|
||||||
clientSessionMaxLifespan = model.getClientSessionMaxLifespan();
|
clientSessionMaxLifespan = model.getClientSessionMaxLifespan();
|
||||||
|
clientOfflineSessionIdleTimeout = model.getClientOfflineSessionIdleTimeout();
|
||||||
|
clientOfflineSessionMaxLifespan = model.getClientOfflineSessionMaxLifespan();
|
||||||
accessTokenLifespan = model.getAccessTokenLifespan();
|
accessTokenLifespan = model.getAccessTokenLifespan();
|
||||||
accessTokenLifespanForImplicitFlow = model.getAccessTokenLifespanForImplicitFlow();
|
accessTokenLifespanForImplicitFlow = model.getAccessTokenLifespanForImplicitFlow();
|
||||||
accessCodeLifespan = model.getAccessCodeLifespan();
|
accessCodeLifespan = model.getAccessCodeLifespan();
|
||||||
|
@ -459,6 +463,14 @@ public class CachedRealm extends AbstractExtendableRevisioned {
|
||||||
return clientSessionMaxLifespan;
|
return clientSessionMaxLifespan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getClientOfflineSessionIdleTimeout() {
|
||||||
|
return clientOfflineSessionIdleTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getClientOfflineSessionMaxLifespan() {
|
||||||
|
return clientOfflineSessionMaxLifespan;
|
||||||
|
}
|
||||||
|
|
||||||
public int getAccessTokenLifespan() {
|
public int getAccessTokenLifespan() {
|
||||||
return accessTokenLifespan;
|
return accessTokenLifespan;
|
||||||
}
|
}
|
||||||
|
|
|
@ -543,6 +543,26 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
|
||||||
setAttribute(RealmAttributes.CLIENT_SESSION_MAX_LIFESPAN, seconds);
|
setAttribute(RealmAttributes.CLIENT_SESSION_MAX_LIFESPAN, seconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getClientOfflineSessionIdleTimeout() {
|
||||||
|
return getAttribute(RealmAttributes.CLIENT_OFFLINE_SESSION_IDLE_TIMEOUT, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setClientOfflineSessionIdleTimeout(int seconds) {
|
||||||
|
setAttribute(RealmAttributes.CLIENT_OFFLINE_SESSION_IDLE_TIMEOUT, seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getClientOfflineSessionMaxLifespan() {
|
||||||
|
return getAttribute(RealmAttributes.CLIENT_OFFLINE_SESSION_MAX_LIFESPAN, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setClientOfflineSessionMaxLifespan(int seconds) {
|
||||||
|
setAttribute(RealmAttributes.CLIENT_OFFLINE_SESSION_MAX_LIFESPAN, seconds);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getAccessCodeLifespan() {
|
public int getAccessCodeLifespan() {
|
||||||
return realm.getAccessCodeLifespan();
|
return realm.getAccessCodeLifespan();
|
||||||
|
|
|
@ -36,6 +36,8 @@ public interface RealmAttributes {
|
||||||
String OFFLINE_SESSION_MAX_LIFESPAN = "offlineSessionMaxLifespan";
|
String OFFLINE_SESSION_MAX_LIFESPAN = "offlineSessionMaxLifespan";
|
||||||
String CLIENT_SESSION_IDLE_TIMEOUT = "clientSessionIdleTimeout";
|
String CLIENT_SESSION_IDLE_TIMEOUT = "clientSessionIdleTimeout";
|
||||||
String CLIENT_SESSION_MAX_LIFESPAN = "clientSessionMaxLifespan";
|
String CLIENT_SESSION_MAX_LIFESPAN = "clientSessionMaxLifespan";
|
||||||
|
String CLIENT_OFFLINE_SESSION_IDLE_TIMEOUT = "clientOfflineSessionIdleTimeout";
|
||||||
|
String CLIENT_OFFLINE_SESSION_MAX_LIFESPAN = "clientOfflineSessionMaxLifespan";
|
||||||
String WEBAUTHN_POLICY_RP_ENTITY_NAME = "webAuthnPolicyRpEntityName";
|
String WEBAUTHN_POLICY_RP_ENTITY_NAME = "webAuthnPolicyRpEntityName";
|
||||||
String WEBAUTHN_POLICY_SIGNATURE_ALGORITHMS = "webAuthnPolicySignatureAlgorithms";
|
String WEBAUTHN_POLICY_SIGNATURE_ALGORITHMS = "webAuthnPolicySignatureAlgorithms";
|
||||||
|
|
||||||
|
|
|
@ -366,6 +366,8 @@ public class ModelToRepresentation {
|
||||||
rep.setOfflineSessionMaxLifespan(realm.getOfflineSessionMaxLifespan());
|
rep.setOfflineSessionMaxLifespan(realm.getOfflineSessionMaxLifespan());
|
||||||
rep.setClientSessionIdleTimeout(realm.getClientSessionIdleTimeout());
|
rep.setClientSessionIdleTimeout(realm.getClientSessionIdleTimeout());
|
||||||
rep.setClientSessionMaxLifespan(realm.getClientSessionMaxLifespan());
|
rep.setClientSessionMaxLifespan(realm.getClientSessionMaxLifespan());
|
||||||
|
rep.setClientOfflineSessionIdleTimeout(realm.getClientOfflineSessionIdleTimeout());
|
||||||
|
rep.setClientOfflineSessionMaxLifespan(realm.getClientOfflineSessionMaxLifespan());
|
||||||
rep.setAccessCodeLifespan(realm.getAccessCodeLifespan());
|
rep.setAccessCodeLifespan(realm.getAccessCodeLifespan());
|
||||||
rep.setAccessCodeLifespanUserAction(realm.getAccessCodeLifespanUserAction());
|
rep.setAccessCodeLifespanUserAction(realm.getAccessCodeLifespanUserAction());
|
||||||
rep.setAccessCodeLifespanLogin(realm.getAccessCodeLifespanLogin());
|
rep.setAccessCodeLifespanLogin(realm.getAccessCodeLifespanLogin());
|
||||||
|
|
|
@ -225,6 +225,11 @@ public class RepresentationToModel {
|
||||||
if (rep.getClientSessionMaxLifespan() != null)
|
if (rep.getClientSessionMaxLifespan() != null)
|
||||||
newRealm.setClientSessionMaxLifespan(rep.getClientSessionMaxLifespan());
|
newRealm.setClientSessionMaxLifespan(rep.getClientSessionMaxLifespan());
|
||||||
|
|
||||||
|
if (rep.getClientOfflineSessionIdleTimeout() != null)
|
||||||
|
newRealm.setClientOfflineSessionIdleTimeout(rep.getClientOfflineSessionIdleTimeout());
|
||||||
|
if (rep.getClientOfflineSessionMaxLifespan() != null)
|
||||||
|
newRealm.setClientOfflineSessionMaxLifespan(rep.getClientOfflineSessionMaxLifespan());
|
||||||
|
|
||||||
if (rep.getAccessCodeLifespan() != null) newRealm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
|
if (rep.getAccessCodeLifespan() != null) newRealm.setAccessCodeLifespan(rep.getAccessCodeLifespan());
|
||||||
else newRealm.setAccessCodeLifespan(60);
|
else newRealm.setAccessCodeLifespan(60);
|
||||||
|
|
||||||
|
@ -1097,6 +1102,10 @@ public class RepresentationToModel {
|
||||||
realm.setClientSessionIdleTimeout(rep.getClientSessionIdleTimeout());
|
realm.setClientSessionIdleTimeout(rep.getClientSessionIdleTimeout());
|
||||||
if (rep.getClientSessionMaxLifespan() != null)
|
if (rep.getClientSessionMaxLifespan() != null)
|
||||||
realm.setClientSessionMaxLifespan(rep.getClientSessionMaxLifespan());
|
realm.setClientSessionMaxLifespan(rep.getClientSessionMaxLifespan());
|
||||||
|
if (rep.getClientOfflineSessionIdleTimeout() != null)
|
||||||
|
realm.setClientOfflineSessionIdleTimeout(rep.getClientOfflineSessionIdleTimeout());
|
||||||
|
if (rep.getClientOfflineSessionMaxLifespan() != null)
|
||||||
|
realm.setClientOfflineSessionMaxLifespan(rep.getClientOfflineSessionMaxLifespan());
|
||||||
if (rep.getRequiredCredentials() != null) {
|
if (rep.getRequiredCredentials() != null) {
|
||||||
realm.updateRequiredCredentials(rep.getRequiredCredentials());
|
realm.updateRequiredCredentials(rep.getRequiredCredentials());
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,6 +202,12 @@ public interface RealmModel extends RoleContainerModel {
|
||||||
int getClientSessionMaxLifespan();
|
int getClientSessionMaxLifespan();
|
||||||
void setClientSessionMaxLifespan(int seconds);
|
void setClientSessionMaxLifespan(int seconds);
|
||||||
|
|
||||||
|
int getClientOfflineSessionIdleTimeout();
|
||||||
|
void setClientOfflineSessionIdleTimeout(int seconds);
|
||||||
|
|
||||||
|
int getClientOfflineSessionMaxLifespan();
|
||||||
|
void setClientOfflineSessionMaxLifespan(int seconds);
|
||||||
|
|
||||||
void setAccessTokenLifespan(int seconds);
|
void setAccessTokenLifespan(int seconds);
|
||||||
|
|
||||||
int getAccessTokenLifespanForImplicitFlow();
|
int getAccessTokenLifespanForImplicitFlow();
|
||||||
|
|
|
@ -46,6 +46,8 @@ public final class OIDCConfigAttributes {
|
||||||
public static final String ACCESS_TOKEN_LIFESPAN = "access.token.lifespan";
|
public static final String ACCESS_TOKEN_LIFESPAN = "access.token.lifespan";
|
||||||
public static final String CLIENT_SESSION_IDLE_TIMEOUT = "client.session.idle.timeout";
|
public static final String CLIENT_SESSION_IDLE_TIMEOUT = "client.session.idle.timeout";
|
||||||
public static final String CLIENT_SESSION_MAX_LIFESPAN = "client.session.max.lifespan";
|
public static final String CLIENT_SESSION_MAX_LIFESPAN = "client.session.max.lifespan";
|
||||||
|
public static final String CLIENT_OFFLINE_SESSION_IDLE_TIMEOUT = "client.offline.session.idle.timeout";
|
||||||
|
public static final String CLIENT_OFFLINE_SESSION_MAX_LIFESPAN = "client.offline.session.max.lifespan";
|
||||||
public static final String PKCE_CODE_CHALLENGE_METHOD = "pkce.code.challenge.method";
|
public static final String PKCE_CODE_CHALLENGE_METHOD = "pkce.code.challenge.method";
|
||||||
|
|
||||||
public static final String TOKEN_ENDPOINT_AUTH_SIGNING_ALG = "token.endpoint.auth.signing.alg";
|
public static final String TOKEN_ENDPOINT_AUTH_SIGNING_ALG = "token.endpoint.auth.signing.alg";
|
||||||
|
|
|
@ -689,6 +689,21 @@ public class TokenManager {
|
||||||
if (realm.isOfflineSessionMaxLifespanEnabled()) {
|
if (realm.isOfflineSessionMaxLifespanEnabled()) {
|
||||||
int sessionExpires = userSession.getStarted() + realm.getOfflineSessionMaxLifespan();
|
int sessionExpires = userSession.getStarted() + realm.getOfflineSessionMaxLifespan();
|
||||||
expiration = expiration <= sessionExpires ? expiration : sessionExpires;
|
expiration = expiration <= sessionExpires ? expiration : sessionExpires;
|
||||||
|
|
||||||
|
int clientOfflineSessionMaxLifespan;
|
||||||
|
String clientOfflineSessionMaxLifespanPerClient = client
|
||||||
|
.getAttribute(OIDCConfigAttributes.CLIENT_OFFLINE_SESSION_MAX_LIFESPAN);
|
||||||
|
if (clientOfflineSessionMaxLifespanPerClient != null
|
||||||
|
&& !clientOfflineSessionMaxLifespanPerClient.trim().isEmpty()) {
|
||||||
|
clientOfflineSessionMaxLifespan = Integer.parseInt(clientOfflineSessionMaxLifespanPerClient);
|
||||||
|
} else {
|
||||||
|
clientOfflineSessionMaxLifespan = realm.getClientOfflineSessionMaxLifespan();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clientOfflineSessionMaxLifespan > 0) {
|
||||||
|
int clientOfflineSessionExpiration = userSession.getStarted() + clientOfflineSessionMaxLifespan;
|
||||||
|
return expiration < clientOfflineSessionExpiration ? expiration : clientOfflineSessionExpiration;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int sessionExpires = userSession.getStarted()
|
int sessionExpires = userSession.getStarted()
|
||||||
|
@ -696,7 +711,6 @@ public class TokenManager {
|
||||||
? realm.getSsoSessionMaxLifespanRememberMe()
|
? realm.getSsoSessionMaxLifespanRememberMe()
|
||||||
: realm.getSsoSessionMaxLifespan());
|
: realm.getSsoSessionMaxLifespan());
|
||||||
expiration = expiration <= sessionExpires ? expiration : sessionExpires;
|
expiration = expiration <= sessionExpires ? expiration : sessionExpires;
|
||||||
}
|
|
||||||
|
|
||||||
int clientSessionMaxLifespan;
|
int clientSessionMaxLifespan;
|
||||||
String clientSessionMaxLifespanPerClient = client.getAttribute(OIDCConfigAttributes.CLIENT_SESSION_MAX_LIFESPAN);
|
String clientSessionMaxLifespanPerClient = client.getAttribute(OIDCConfigAttributes.CLIENT_SESSION_MAX_LIFESPAN);
|
||||||
|
@ -710,6 +724,7 @@ public class TokenManager {
|
||||||
int clientSessionExpiration = userSession.getStarted() + clientSessionMaxLifespan;
|
int clientSessionExpiration = userSession.getStarted() + clientSessionMaxLifespan;
|
||||||
return expiration < clientSessionExpiration ? expiration : clientSessionExpiration;
|
return expiration < clientSessionExpiration ? expiration : clientSessionExpiration;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return expiration;
|
return expiration;
|
||||||
}
|
}
|
||||||
|
@ -842,9 +857,41 @@ public class TokenManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getOfflineExpiration() {
|
private int getOfflineExpiration() {
|
||||||
int expiration = Time.currentTime() + realm.getOfflineSessionIdleTimeout();
|
|
||||||
int sessionExpires = userSession.getStarted() + realm.getOfflineSessionMaxLifespan();
|
int sessionExpires = userSession.getStarted() + realm.getOfflineSessionMaxLifespan();
|
||||||
|
|
||||||
|
int clientOfflineSessionMaxLifespan;
|
||||||
|
String clientOfflineSessionMaxLifespanPerClient = client
|
||||||
|
.getAttribute(OIDCConfigAttributes.CLIENT_OFFLINE_SESSION_MAX_LIFESPAN);
|
||||||
|
if (clientOfflineSessionMaxLifespanPerClient != null
|
||||||
|
&& !clientOfflineSessionMaxLifespanPerClient.trim().isEmpty()) {
|
||||||
|
clientOfflineSessionMaxLifespan = Integer.parseInt(clientOfflineSessionMaxLifespanPerClient);
|
||||||
|
} else {
|
||||||
|
clientOfflineSessionMaxLifespan = realm.getClientOfflineSessionMaxLifespan();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clientOfflineSessionMaxLifespan > 0) {
|
||||||
|
int clientOfflineSessionMaxExpiration = userSession.getStarted() + clientOfflineSessionMaxLifespan;
|
||||||
|
sessionExpires = sessionExpires < clientOfflineSessionMaxExpiration ? sessionExpires
|
||||||
|
: clientOfflineSessionMaxExpiration;
|
||||||
|
}
|
||||||
|
|
||||||
|
int expiration = Time.currentTime() + realm.getOfflineSessionIdleTimeout();
|
||||||
|
|
||||||
|
int clientOfflineSessionIdleTimeout;
|
||||||
|
String clientOfflineSessionIdleTimeoutPerClient = client
|
||||||
|
.getAttribute(OIDCConfigAttributes.CLIENT_OFFLINE_SESSION_IDLE_TIMEOUT);
|
||||||
|
if (clientOfflineSessionIdleTimeoutPerClient != null
|
||||||
|
&& !clientOfflineSessionIdleTimeoutPerClient.trim().isEmpty()) {
|
||||||
|
clientOfflineSessionIdleTimeout = Integer.parseInt(clientOfflineSessionIdleTimeoutPerClient);
|
||||||
|
} else {
|
||||||
|
clientOfflineSessionIdleTimeout = realm.getClientOfflineSessionIdleTimeout();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clientOfflineSessionIdleTimeout > 0) {
|
||||||
|
int clientOfflineSessionIdleExpiration = Time.currentTime() + clientOfflineSessionIdleTimeout;
|
||||||
|
expiration = expiration < clientOfflineSessionIdleExpiration ? expiration : clientOfflineSessionIdleExpiration;
|
||||||
|
}
|
||||||
|
|
||||||
return expiration <= sessionExpires ? expiration : sessionExpires;
|
return expiration <= sessionExpires ? expiration : sessionExpires;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -624,6 +624,10 @@ public class RealmTest extends AbstractAdminTest {
|
||||||
Assert.assertEquals(realm.getClientSessionIdleTimeout(), storedRealm.getClientSessionIdleTimeout());
|
Assert.assertEquals(realm.getClientSessionIdleTimeout(), storedRealm.getClientSessionIdleTimeout());
|
||||||
if (realm.getClientSessionMaxLifespan() != null)
|
if (realm.getClientSessionMaxLifespan() != null)
|
||||||
Assert.assertEquals(realm.getClientSessionMaxLifespan(), storedRealm.getClientSessionMaxLifespan());
|
Assert.assertEquals(realm.getClientSessionMaxLifespan(), storedRealm.getClientSessionMaxLifespan());
|
||||||
|
if (realm.getClientOfflineSessionIdleTimeout() != null)
|
||||||
|
Assert.assertEquals(realm.getClientOfflineSessionIdleTimeout(), storedRealm.getClientOfflineSessionIdleTimeout());
|
||||||
|
if (realm.getClientOfflineSessionMaxLifespan() != null)
|
||||||
|
Assert.assertEquals(realm.getClientOfflineSessionMaxLifespan(), storedRealm.getClientOfflineSessionMaxLifespan());
|
||||||
if (realm.getRequiredCredentials() != null) {
|
if (realm.getRequiredCredentials() != null) {
|
||||||
assertNotNull(storedRealm.getRequiredCredentials());
|
assertNotNull(storedRealm.getRequiredCredentials());
|
||||||
for (String cred : realm.getRequiredCredentials()) {
|
for (String cred : realm.getRequiredCredentials()) {
|
||||||
|
|
|
@ -1162,6 +1162,53 @@ public class AccessTokenTest extends AbstractKeycloakTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClientOfflineSessionMaxLifespan() throws Exception {
|
||||||
|
ClientResource client = ApiUtil.findClientByClientId(adminClient.realm("test"), "test-app");
|
||||||
|
ClientRepresentation clientRepresentation = client.toRepresentation();
|
||||||
|
|
||||||
|
RealmResource realm = adminClient.realm("test");
|
||||||
|
RealmRepresentation rep = realm.toRepresentation();
|
||||||
|
int accessTokenLifespan = rep.getAccessTokenLifespan();
|
||||||
|
Boolean originalOfflineSessionMaxLifespanEnabled = rep.getOfflineSessionMaxLifespanEnabled();
|
||||||
|
Integer originalClientOfflineSessionMaxLifespan = rep.getClientOfflineSessionMaxLifespan();
|
||||||
|
|
||||||
|
try {
|
||||||
|
rep.setOfflineSessionMaxLifespanEnabled(true);
|
||||||
|
realm.update(rep);
|
||||||
|
|
||||||
|
oauth.scope(OAuth2Constants.OFFLINE_ACCESS);
|
||||||
|
oauth.doLogin("test-user@localhost", "password");
|
||||||
|
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||||
|
OAuthClient.AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
|
||||||
|
assertEquals(200, response.getStatusCode());
|
||||||
|
assertExpiration(response.getExpiresIn(), accessTokenLifespan);
|
||||||
|
|
||||||
|
rep.setClientOfflineSessionMaxLifespan(accessTokenLifespan - 100);
|
||||||
|
realm.update(rep);
|
||||||
|
|
||||||
|
String refreshToken = response.getRefreshToken();
|
||||||
|
response = oauth.doRefreshTokenRequest(refreshToken, "password");
|
||||||
|
assertEquals(200, response.getStatusCode());
|
||||||
|
assertExpiration(response.getExpiresIn(), accessTokenLifespan - 100);
|
||||||
|
|
||||||
|
clientRepresentation.getAttributes().put(OIDCConfigAttributes.CLIENT_OFFLINE_SESSION_MAX_LIFESPAN,
|
||||||
|
Integer.toString(accessTokenLifespan - 200));
|
||||||
|
client.update(clientRepresentation);
|
||||||
|
|
||||||
|
refreshToken = response.getRefreshToken();
|
||||||
|
response = oauth.doRefreshTokenRequest(refreshToken, "password");
|
||||||
|
assertEquals(200, response.getStatusCode());
|
||||||
|
assertExpiration(response.getExpiresIn(), accessTokenLifespan - 200);
|
||||||
|
} finally {
|
||||||
|
rep.setOfflineSessionMaxLifespanEnabled(originalOfflineSessionMaxLifespanEnabled);
|
||||||
|
rep.setClientOfflineSessionMaxLifespan(originalClientOfflineSessionMaxLifespan);
|
||||||
|
realm.update(rep);
|
||||||
|
clientRepresentation.getAttributes().put(OIDCConfigAttributes.CLIENT_OFFLINE_SESSION_MAX_LIFESPAN, null);
|
||||||
|
client.update(clientRepresentation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void accessTokenRequest_ClientPS384_RealmRS256() throws Exception {
|
public void accessTokenRequest_ClientPS384_RealmRS256() throws Exception {
|
||||||
conductAccessTokenRequest(Algorithm.HS256, Algorithm.PS384, Algorithm.RS256);
|
conductAccessTokenRequest(Algorithm.HS256, Algorithm.PS384, Algorithm.RS256);
|
||||||
|
|
|
@ -39,6 +39,7 @@ import org.keycloak.models.AdminRoles;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.models.utils.SessionTimeoutHelper;
|
import org.keycloak.models.utils.SessionTimeoutHelper;
|
||||||
|
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.representations.RefreshToken;
|
import org.keycloak.representations.RefreshToken;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
|
@ -78,6 +79,7 @@ import static org.junit.Assert.assertNotEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.keycloak.testsuite.Assert.assertExpiration;
|
||||||
import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
|
import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
|
||||||
import static org.keycloak.testsuite.admin.ApiUtil.findRealmRoleByName;
|
import static org.keycloak.testsuite.admin.ApiUtil.findRealmRoleByName;
|
||||||
import static org.keycloak.testsuite.admin.ApiUtil.findUserByUsername;
|
import static org.keycloak.testsuite.admin.ApiUtil.findUserByUsername;
|
||||||
|
@ -881,4 +883,104 @@ public class OfflineTokenTest extends AbstractKeycloakTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClientOfflineSessionMaxLifespan() throws Exception {
|
||||||
|
ClientResource client = ApiUtil.findClientByClientId(adminClient.realm("test"), "offline-client");
|
||||||
|
ClientRepresentation clientRepresentation = client.toRepresentation();
|
||||||
|
|
||||||
|
RealmResource realm = adminClient.realm("test");
|
||||||
|
RealmRepresentation rep = realm.toRepresentation();
|
||||||
|
Boolean originalOfflineSessionMaxLifespanEnabled = rep.getOfflineSessionMaxLifespanEnabled();
|
||||||
|
Integer originalOfflineSessionMaxLifespan = rep.getOfflineSessionMaxLifespan();
|
||||||
|
int offlineSessionMaxLifespan = rep.getOfflineSessionIdleTimeout() - 100;
|
||||||
|
Integer originalClientOfflineSessionMaxLifespan = rep.getClientOfflineSessionMaxLifespan();
|
||||||
|
|
||||||
|
try {
|
||||||
|
rep.setOfflineSessionMaxLifespanEnabled(true);
|
||||||
|
rep.setOfflineSessionMaxLifespan(offlineSessionMaxLifespan);
|
||||||
|
realm.update(rep);
|
||||||
|
|
||||||
|
oauth.scope(OAuth2Constants.OFFLINE_ACCESS);
|
||||||
|
oauth.clientId("offline-client");
|
||||||
|
oauth.redirectUri(offlineClientAppUri);
|
||||||
|
oauth.doLogin("test-user@localhost", "password");
|
||||||
|
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||||
|
OAuthClient.AccessTokenResponse response = oauth.doAccessTokenRequest(code, "secret1");
|
||||||
|
assertEquals(200, response.getStatusCode());
|
||||||
|
assertExpiration(response.getRefreshExpiresIn(), offlineSessionMaxLifespan);
|
||||||
|
|
||||||
|
rep.setClientOfflineSessionMaxLifespan(offlineSessionMaxLifespan - 100);
|
||||||
|
realm.update(rep);
|
||||||
|
|
||||||
|
String refreshToken = response.getRefreshToken();
|
||||||
|
response = oauth.doRefreshTokenRequest(refreshToken, "secret1");
|
||||||
|
assertEquals(200, response.getStatusCode());
|
||||||
|
assertExpiration(response.getRefreshExpiresIn(), offlineSessionMaxLifespan - 100);
|
||||||
|
|
||||||
|
clientRepresentation.getAttributes().put(OIDCConfigAttributes.CLIENT_OFFLINE_SESSION_MAX_LIFESPAN,
|
||||||
|
Integer.toString(offlineSessionMaxLifespan - 200));
|
||||||
|
client.update(clientRepresentation);
|
||||||
|
|
||||||
|
refreshToken = response.getRefreshToken();
|
||||||
|
response = oauth.doRefreshTokenRequest(refreshToken, "secret1");
|
||||||
|
assertEquals(200, response.getStatusCode());
|
||||||
|
assertExpiration(response.getRefreshExpiresIn(), offlineSessionMaxLifespan - 200);
|
||||||
|
} finally {
|
||||||
|
rep.setOfflineSessionMaxLifespanEnabled(originalOfflineSessionMaxLifespanEnabled);
|
||||||
|
rep.setOfflineSessionMaxLifespan(originalOfflineSessionMaxLifespan);
|
||||||
|
rep.setClientOfflineSessionMaxLifespan(originalClientOfflineSessionMaxLifespan);
|
||||||
|
realm.update(rep);
|
||||||
|
clientRepresentation.getAttributes().put(OIDCConfigAttributes.CLIENT_OFFLINE_SESSION_MAX_LIFESPAN, null);
|
||||||
|
client.update(clientRepresentation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClientOfflineSessionIdleTimeout() throws Exception {
|
||||||
|
ClientResource client = ApiUtil.findClientByClientId(adminClient.realm("test"), "offline-client");
|
||||||
|
ClientRepresentation clientRepresentation = client.toRepresentation();
|
||||||
|
|
||||||
|
RealmResource realm = adminClient.realm("test");
|
||||||
|
RealmRepresentation rep = realm.toRepresentation();
|
||||||
|
Boolean originalOfflineSessionMaxLifespanEnabled = rep.getOfflineSessionMaxLifespanEnabled();
|
||||||
|
int offlineSessionIdleTimeout = rep.getOfflineSessionIdleTimeout();
|
||||||
|
Integer originalClientOfflineSessionIdleTimeout = rep.getClientOfflineSessionIdleTimeout();
|
||||||
|
|
||||||
|
try {
|
||||||
|
rep.setOfflineSessionMaxLifespanEnabled(true);
|
||||||
|
realm.update(rep);
|
||||||
|
|
||||||
|
oauth.scope(OAuth2Constants.OFFLINE_ACCESS);
|
||||||
|
oauth.clientId("offline-client");
|
||||||
|
oauth.redirectUri(offlineClientAppUri);
|
||||||
|
oauth.doLogin("test-user@localhost", "password");
|
||||||
|
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||||
|
OAuthClient.AccessTokenResponse response = oauth.doAccessTokenRequest(code, "secret1");
|
||||||
|
assertEquals(200, response.getStatusCode());
|
||||||
|
assertExpiration(response.getRefreshExpiresIn(), offlineSessionIdleTimeout);
|
||||||
|
|
||||||
|
rep.setClientOfflineSessionIdleTimeout(offlineSessionIdleTimeout - 100);
|
||||||
|
realm.update(rep);
|
||||||
|
|
||||||
|
String refreshToken = response.getRefreshToken();
|
||||||
|
response = oauth.doRefreshTokenRequest(refreshToken, "secret1");
|
||||||
|
assertEquals(200, response.getStatusCode());
|
||||||
|
assertExpiration(response.getRefreshExpiresIn(), offlineSessionIdleTimeout - 100);
|
||||||
|
|
||||||
|
clientRepresentation.getAttributes().put(OIDCConfigAttributes.CLIENT_OFFLINE_SESSION_IDLE_TIMEOUT,
|
||||||
|
Integer.toString(offlineSessionIdleTimeout - 200));
|
||||||
|
client.update(clientRepresentation);
|
||||||
|
|
||||||
|
refreshToken = response.getRefreshToken();
|
||||||
|
response = oauth.doRefreshTokenRequest(refreshToken, "secret1");
|
||||||
|
assertEquals(200, response.getStatusCode());
|
||||||
|
assertExpiration(response.getRefreshExpiresIn(), offlineSessionIdleTimeout - 200);
|
||||||
|
} finally {
|
||||||
|
rep.setOfflineSessionMaxLifespanEnabled(originalOfflineSessionMaxLifespanEnabled);
|
||||||
|
rep.setClientOfflineSessionIdleTimeout(originalClientOfflineSessionIdleTimeout);
|
||||||
|
realm.update(rep);
|
||||||
|
clientRepresentation.getAttributes().put(OIDCConfigAttributes.CLIENT_OFFLINE_SESSION_IDLE_TIMEOUT, null);
|
||||||
|
client.update(clientRepresentation);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -282,4 +282,14 @@ public class RealmBuilder {
|
||||||
rep.setClientSessionMaxLifespan(clientSessionMaxLifespan);
|
rep.setClientSessionMaxLifespan(clientSessionMaxLifespan);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RealmBuilder clientOfflineSessionIdleTimeout(int clientOfflineSessionIdleTimeout) {
|
||||||
|
rep.setClientOfflineSessionIdleTimeout(clientOfflineSessionIdleTimeout);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RealmBuilder clientOfflineSessionMaxLifespan(int clientOfflineSessionMaxLifespan) {
|
||||||
|
rep.setClientOfflineSessionMaxLifespan(clientOfflineSessionMaxLifespan);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,6 +132,10 @@ client-session-idle=Client Session Idle
|
||||||
client-session-idle.tooltip=Time a client session is allowed to be idle before it expires. Tokens are invalidated when a client session is expired. If not set it uses the standard SSO Session Idle value.
|
client-session-idle.tooltip=Time a client session is allowed to be idle before it expires. Tokens are invalidated when a client session is expired. If not set it uses the standard SSO Session Idle value.
|
||||||
client-session-max=Client Session Max
|
client-session-max=Client Session Max
|
||||||
client-session-max.tooltip=Max time before a client session is expired. Tokens are invalidated when a client session is expired. If not set, it uses the standard SSO Session Max value.
|
client-session-max.tooltip=Max time before a client session is expired. Tokens are invalidated when a client session is expired. If not set, it uses the standard SSO Session Max value.
|
||||||
|
client-offline-session-idle=Client Offline Session Idle
|
||||||
|
client-offline-session-idle.tooltip=Time a client offline session is allowed to be idle before it expires. Offline tokens are invalidated when a client offline session is expired. If not set it uses the Offline Session Idle value.
|
||||||
|
client-offline-session-max=Client Offline Session Max
|
||||||
|
client-offline-session-max.tooltip=Max time before a client offline session is expired. Offline tokens are invalidated when a client offline session is expired. If not set, it uses the Offline Session Max value.
|
||||||
access-token-lifespan=Access Token Lifespan
|
access-token-lifespan=Access Token Lifespan
|
||||||
access-token-lifespan.tooltip=Max time before an access token is expired. This value is recommended to be short relative to the SSO timeout.
|
access-token-lifespan.tooltip=Max time before an access token is expired. This value is recommended to be short relative to the SSO timeout.
|
||||||
access-token-lifespan-for-implicit-flow=Access Token Lifespan For Implicit Flow
|
access-token-lifespan-for-implicit-flow=Access Token Lifespan For Implicit Flow
|
||||||
|
|
|
@ -1114,6 +1114,8 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, flows, $ro
|
||||||
$scope.samlAssertionLifespan = TimeUnit2.asUnit(client.attributes['saml.assertion.lifespan']);
|
$scope.samlAssertionLifespan = TimeUnit2.asUnit(client.attributes['saml.assertion.lifespan']);
|
||||||
$scope.clientSessionIdleTimeout = TimeUnit2.asUnit(client.attributes['client.session.idle.timeout']);
|
$scope.clientSessionIdleTimeout = TimeUnit2.asUnit(client.attributes['client.session.idle.timeout']);
|
||||||
$scope.clientSessionMaxLifespan = TimeUnit2.asUnit(client.attributes['client.session.max.lifespan']);
|
$scope.clientSessionMaxLifespan = TimeUnit2.asUnit(client.attributes['client.session.max.lifespan']);
|
||||||
|
$scope.clientOfflineSessionIdleTimeout = TimeUnit2.asUnit(client.attributes['client.offline.session.idle.timeout']);
|
||||||
|
$scope.clientOfflineSessionMaxLifespan = TimeUnit2.asUnit(client.attributes['client.offline.session.max.lifespan']);
|
||||||
|
|
||||||
if(client.origin) {
|
if(client.origin) {
|
||||||
if ($scope.access.viewRealm) {
|
if ($scope.access.viewRealm) {
|
||||||
|
@ -1464,6 +1466,22 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, flows, $ro
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$scope.updateClientOfflineSessionIdleTimeout = function() {
|
||||||
|
if ($scope.clientOfflineSessionIdleTimeout.time) {
|
||||||
|
$scope.clientEdit.attributes['client.offline.session.idle.timeout'] = $scope.clientOfflineSessionIdleTimeout.toSeconds();
|
||||||
|
} else {
|
||||||
|
$scope.clientEdit.attributes['client.offline.session.idle.timeout'] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.updateClientOfflineSessionMaxLifespan = function() {
|
||||||
|
if ($scope.clientOfflineSessionMaxLifespan.time) {
|
||||||
|
$scope.clientEdit.attributes['client.offline.session.max.lifespan'] = $scope.clientOfflineSessionMaxLifespan.toSeconds();
|
||||||
|
} else {
|
||||||
|
$scope.clientEdit.attributes['client.offline.session.max.lifespan'] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function configureAuthorizationServices() {
|
function configureAuthorizationServices() {
|
||||||
if ($scope.clientEdit.authorizationServicesEnabled) {
|
if ($scope.clientEdit.authorizationServicesEnabled) {
|
||||||
if ($scope.accessType == 'public') {
|
if ($scope.accessType == 'public') {
|
||||||
|
|
|
@ -1162,6 +1162,8 @@ module.controller('RealmTokenDetailCtrl', function($scope, Realm, realm, $http,
|
||||||
$scope.realm.offlineSessionMaxLifespan = TimeUnit2.asUnit(realm.offlineSessionMaxLifespan);
|
$scope.realm.offlineSessionMaxLifespan = TimeUnit2.asUnit(realm.offlineSessionMaxLifespan);
|
||||||
$scope.realm.clientSessionIdleTimeout = TimeUnit2.asUnit(realm.clientSessionIdleTimeout);
|
$scope.realm.clientSessionIdleTimeout = TimeUnit2.asUnit(realm.clientSessionIdleTimeout);
|
||||||
$scope.realm.clientSessionMaxLifespan = TimeUnit2.asUnit(realm.clientSessionMaxLifespan);
|
$scope.realm.clientSessionMaxLifespan = TimeUnit2.asUnit(realm.clientSessionMaxLifespan);
|
||||||
|
$scope.realm.clientOfflineSessionIdleTimeout = TimeUnit2.asUnit(realm.clientOfflineSessionIdleTimeout);
|
||||||
|
$scope.realm.clientOfflineSessionMaxLifespan = TimeUnit2.asUnit(realm.clientOfflineSessionMaxLifespan);
|
||||||
$scope.realm.accessCodeLifespan = TimeUnit2.asUnit(realm.accessCodeLifespan);
|
$scope.realm.accessCodeLifespan = TimeUnit2.asUnit(realm.accessCodeLifespan);
|
||||||
$scope.realm.accessCodeLifespanLogin = TimeUnit2.asUnit(realm.accessCodeLifespanLogin);
|
$scope.realm.accessCodeLifespanLogin = TimeUnit2.asUnit(realm.accessCodeLifespanLogin);
|
||||||
$scope.realm.accessCodeLifespanUserAction = TimeUnit2.asUnit(realm.accessCodeLifespanUserAction);
|
$scope.realm.accessCodeLifespanUserAction = TimeUnit2.asUnit(realm.accessCodeLifespanUserAction);
|
||||||
|
@ -1219,6 +1221,8 @@ module.controller('RealmTokenDetailCtrl', function($scope, Realm, realm, $http,
|
||||||
$scope.realm.offlineSessionMaxLifespan = $scope.realm.offlineSessionMaxLifespan.toSeconds();
|
$scope.realm.offlineSessionMaxLifespan = $scope.realm.offlineSessionMaxLifespan.toSeconds();
|
||||||
$scope.realm.clientSessionIdleTimeout = $scope.realm.clientSessionIdleTimeout.toSeconds();
|
$scope.realm.clientSessionIdleTimeout = $scope.realm.clientSessionIdleTimeout.toSeconds();
|
||||||
$scope.realm.clientSessionMaxLifespan = $scope.realm.clientSessionMaxLifespan.toSeconds();
|
$scope.realm.clientSessionMaxLifespan = $scope.realm.clientSessionMaxLifespan.toSeconds();
|
||||||
|
$scope.realm.clientOfflineSessionIdleTimeout = $scope.realm.clientOfflineSessionIdleTimeout.toSeconds();
|
||||||
|
$scope.realm.clientOfflineSessionMaxLifespan = $scope.realm.clientOfflineSessionMaxLifespan.toSeconds();
|
||||||
$scope.realm.accessCodeLifespan = $scope.realm.accessCodeLifespan.toSeconds();
|
$scope.realm.accessCodeLifespan = $scope.realm.accessCodeLifespan.toSeconds();
|
||||||
$scope.realm.accessCodeLifespanUserAction = $scope.realm.accessCodeLifespanUserAction.toSeconds();
|
$scope.realm.accessCodeLifespanUserAction = $scope.realm.accessCodeLifespanUserAction.toSeconds();
|
||||||
$scope.realm.accessCodeLifespanLogin = $scope.realm.accessCodeLifespanLogin.toSeconds();
|
$scope.realm.accessCodeLifespanLogin = $scope.realm.accessCodeLifespanLogin.toSeconds();
|
||||||
|
|
|
@ -579,6 +579,42 @@
|
||||||
<kc-tooltip>{{:: 'client-session-max.tooltip' | translate}}</kc-tooltip>
|
<kc-tooltip>{{:: 'client-session-max.tooltip' | translate}}</kc-tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" data-ng-show="protocol == 'openid-connect'">
|
||||||
|
<label class="col-md-2 control-label" for="clientOfflineSessionIdleTimeout">{{::
|
||||||
|
'client-offline-session-idle' | translate}}</label>
|
||||||
|
<div class="col-md-6 time-selector">
|
||||||
|
<input class="form-control" type="number" min="0" max="31536000"
|
||||||
|
data-ng-model="clientOfflineSessionIdleTimeout.time" id="clientOfflineSessionIdleTimeout"
|
||||||
|
name="clientOfflineSessionIdleTimeout" data-ng-change="updateClientOfflineSessionIdleTimeout()" /> <select
|
||||||
|
class="form-control" name="clientOfflineSessionIdleTimeoutUnit"
|
||||||
|
data-ng-model="clientOfflineSessionIdleTimeout.unit"
|
||||||
|
data-ng-change="updateClientOfflineSessionIdleTimeout()">
|
||||||
|
<option value="Minutes">{{:: 'minutes' | translate}}</option>
|
||||||
|
<option value="Hours">{{:: 'hours' | translate}}</option>
|
||||||
|
<option value="Days">{{:: 'days' | translate}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>{{:: 'client-offline-session-idle.tooltip' | translate}}</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" data-ng-show="protocol == 'openid-connect'">
|
||||||
|
<label class="col-md-2 control-label" for="clientOfflineSessionMaxLifespan">{{::
|
||||||
|
'client-offline-session-max' | translate}}</label>
|
||||||
|
<div class="col-md-6 time-selector">
|
||||||
|
<input class="form-control" type="number" min="0" max="31536000"
|
||||||
|
data-ng-model="clientOfflineSessionMaxLifespan.time" id="clientOfflineSessionMaxLifespan"
|
||||||
|
name="clientOfflineSessionMaxLifespan" data-ng-change="updateClientOfflineSessionMaxLifespan()" /> <select
|
||||||
|
class="form-control" name="clientOfflineSessionMaxLifespanUnit"
|
||||||
|
data-ng-model="clientOfflineSessionMaxLifespan.unit"
|
||||||
|
data-ng-change="updateClientOfflineSessionMaxLifespan()">
|
||||||
|
<option value="Minutes">{{:: 'minutes' | translate}}</option>
|
||||||
|
<option value="Hours">{{:: 'hours' | translate}}</option>
|
||||||
|
<option value="Days">{{:: 'days' | translate}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>{{:: 'client-offline-session-max.tooltip' | translate}}</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group clearfix block" data-ng-show="protocol == 'openid-connect'">
|
<div class="form-group clearfix block" data-ng-show="protocol == 'openid-connect'">
|
||||||
<label class="col-md-2 control-label" for="tlsClientCertificateBoundAccessTokens">{{:: 'tls-client-certificate-bound-access-tokens' | translate}}</label>
|
<label class="col-md-2 control-label" for="tlsClientCertificateBoundAccessTokens">{{:: 'tls-client-certificate-bound-access-tokens' | translate}}</label>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
|
|
|
@ -145,6 +145,38 @@
|
||||||
<kc-tooltip>{{:: 'offline-session-max.tooltip' | translate}}</kc-tooltip>
|
<kc-tooltip>{{:: 'offline-session-max.tooltip' | translate}}</kc-tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" data-ng-show="realm.offlineSessionMaxLifespanEnabled">
|
||||||
|
<label class="col-md-2 control-label" for="clientOfflineSessionIdleTimeout">{{::
|
||||||
|
'client-offline-session-idle' | translate}}</label>
|
||||||
|
<div class="col-md-6 time-selector">
|
||||||
|
<input class="form-control" type="number" required min="0" max="31536000"
|
||||||
|
data-ng-model="realm.clientOfflineSessionIdleTimeout.time" id="clientOfflineSessionIdleTimeout"
|
||||||
|
name="clientOfflineSessionIdleTimeout" /> <select class="form-control"
|
||||||
|
name="clientOfflineSessionIdleTimeoutUnit" data-ng-model="realm.clientOfflineSessionIdleTimeout.unit">
|
||||||
|
<option value="Minutes">{{:: 'minutes' | translate}}</option>
|
||||||
|
<option value="Hours">{{:: 'hours' | translate}}</option>
|
||||||
|
<option value="Days">{{:: 'days' | translate}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>{{:: 'client-offline-session-idle.tooltip' | translate}}</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" data-ng-show="realm.offlineSessionMaxLifespanEnabled">
|
||||||
|
<label class="col-md-2 control-label" for="clientOfflineSessionMaxLifespan">{{::
|
||||||
|
'client-offline-session-max' | translate}}</label>
|
||||||
|
<div class="col-md-6 time-selector">
|
||||||
|
<input class="form-control" type="number" required min="0" max="31536000"
|
||||||
|
data-ng-model="realm.clientOfflineSessionMaxLifespan.time" id="clientOfflineSessionMaxLifespan"
|
||||||
|
name="clientOfflineSessionMaxLifespan" /> <select class="form-control"
|
||||||
|
name="clientOfflineSessionMaxLifespanUnit" data-ng-model="realm.clientOfflineSessionMaxLifespan.unit">
|
||||||
|
<option value="Minutes">{{:: 'minutes' | translate}}</option>
|
||||||
|
<option value="Hours">{{:: 'hours' | translate}}</option>
|
||||||
|
<option value="Days">{{:: 'days' | translate}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>{{:: 'client-offline-session-max.tooltip' | translate}}</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-md-2 control-label" for="clientSessionIdleTimeout">{{:: 'client-session-idle' | translate}}</label>
|
<label class="col-md-2 control-label" for="clientSessionIdleTimeout">{{:: 'client-session-idle' | translate}}</label>
|
||||||
<div class="col-md-6 time-selector">
|
<div class="col-md-6 time-selector">
|
||||||
|
|
Loading…
Reference in a new issue