Add TRANSIENT_USERS feature flag

This commit is contained in:
Hynek Mlnarik 2023-10-20 14:02:07 +02:00 committed by Hynek Mlnařík
parent d59ceb17e9
commit c036980c37
24 changed files with 79 additions and 59 deletions

View file

@ -95,6 +95,8 @@ public class Profile {
LINKEDIN_OAUTH("LinkedIn Social Identity Provider based on OAuth", Type.DEPRECATED),
DEVICE_FLOW("OAuth 2.0 Device Authorization Grant", Type.DEFAULT),
TRANSIENT_USERS("Transient users for brokering", Type.PREVIEW),
;
private final Type type;

View file

@ -71,6 +71,7 @@ public class ProfileTest {
Assert.assertEquals(Profile.ProfileName.DEFAULT, profile.getName());
Set<Profile.Feature> disabledFeatures = new HashSet<>(Arrays.asList(
Profile.Feature.TRANSIENT_USERS,
Profile.Feature.DPOP,
Profile.Feature.FIPS,
Profile.Feature.ACCOUNT3,
@ -92,7 +93,7 @@ public class ProfileTest {
disabledFeatures.add(Profile.Feature.KERBEROS);
}
assertEquals(profile.getDisabledFeatures(), disabledFeatures);
assertEquals(profile.getPreviewFeatures(), Profile.Feature.ACCOUNT3, Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ, Profile.Feature.RECOVERY_CODES, Profile.Feature.SCRIPTS, Profile.Feature.TOKEN_EXCHANGE, Profile.Feature.DECLARATIVE_USER_PROFILE, Profile.Feature.CLIENT_SECRET_ROTATION, Profile.Feature.UPDATE_EMAIL, Profile.Feature.DPOP);
assertEquals(profile.getPreviewFeatures(), Profile.Feature.ACCOUNT3, Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ, Profile.Feature.RECOVERY_CODES, Profile.Feature.SCRIPTS, Profile.Feature.TOKEN_EXCHANGE, Profile.Feature.DECLARATIVE_USER_PROFILE, Profile.Feature.CLIENT_SECRET_ROTATION, Profile.Feature.UPDATE_EMAIL, Profile.Feature.DPOP, Profile.Feature.TRANSIENT_USERS);
}
@Test

View file

@ -15,6 +15,7 @@ import { HelpItem } from "ui-shared";
import { adminClient } from "../../admin-client";
import { useFetch } from "../../utils/useFetch";
import useIsFeatureEnabled, { Feature } from "../../utils/useIsFeatureEnabled";
import type { FieldProps } from "../component/FormGroupField";
import { FormGroupField } from "../component/FormGroupField";
import { SwitchField } from "../component/SwitchField";
@ -106,12 +107,14 @@ export const AdvancedSettings = ({ isOIDC, isSAML }: AdvancedSettingsProps) => {
defaultValue: "false",
});
const claimFilterRequired = filteredByClaim === "true";
const transientSessions = useWatch({
const isFeatureEnabled = useIsFeatureEnabled();
const isTransientUsersEnabled = isFeatureEnabled(Feature.TransientUsers);
const transientUsers = useWatch({
control,
name: "config.doNotStoreUsers",
defaultValue: "false",
});
const syncModeAvailable = transientSessions === "false";
const syncModeAvailable = transientUsers === "false";
return (
<>
{!isOIDC && !isSAML && (
@ -238,28 +241,30 @@ export const AdvancedSettings = ({ isOIDC, isSAML }: AdvancedSettingsProps) => {
defaultValue=""
/>
<FormGroupField label="doNotStoreUsers">
<Controller
name="config.doNotStoreUsers"
defaultValue="false"
control={control}
render={({ field }) => (
<Switch
id="doNotStoreUsers"
label={t("on")}
labelOff={t("off")}
isChecked={field.value === "true"}
onChange={(value) => {
field.onChange(value.toString());
// if field is checked, set sync mode to import
if (value) {
setValue("config.syncMode", "IMPORT");
}
}}
/>
)}
/>
</FormGroupField>
{isTransientUsersEnabled && (
<FormGroupField label="doNotStoreUsers">
<Controller
name="config.doNotStoreUsers"
defaultValue="false"
control={control}
render={({ field }) => (
<Switch
id="doNotStoreUsers"
label={t("on")}
labelOff={t("off")}
isChecked={field.value === "true"}
onChange={(value) => {
field.onChange(value.toString());
// if field is checked, set sync mode to import
if (value) {
setValue("config.syncMode", "IMPORT");
}
}}
/>
)}
/>
</FormGroupField>
)}
{syncModeAvailable && (
<FormGroup
className="pf-u-pb-3xl"

View file

@ -8,6 +8,7 @@ export enum Feature {
DynamicScopes = "DYNAMIC_SCOPES",
DPoP = "DPOP",
DeviceFlow = "DEVICE_FLOW",
TransientUsers = "TRANSIENT_USERS",
}
export default function useIsFeatureEnabled() {

View file

@ -17,6 +17,8 @@
package org.keycloak.models.sessions.infinispan;
import org.keycloak.common.Profile;
import org.keycloak.common.Profile.Feature;
import java.util.Collections;
import java.util.concurrent.ConcurrentHashMap;
import java.util.HashSet;
@ -289,7 +291,7 @@ public class AuthenticationSessionAdapter implements AuthenticationSessionModel
return null;
}
if (getUserSessionNotes().containsKey(SESSION_NOTE_LIGHTWEIGHT_USER)) {
if (Profile.isFeatureEnabled(Feature.TRANSIENT_USERS) && getUserSessionNotes().containsKey(SESSION_NOTE_LIGHTWEIGHT_USER)) {
LightweightUserAdapter cachedUser = session.getAttribute("authSession.user." + parent.getId(), LightweightUserAdapter.class);
if (cachedUser != null) {

View file

@ -25,6 +25,8 @@ import org.infinispan.context.Flag;
import org.infinispan.stream.CacheCollectors;
import org.jboss.logging.Logger;
import org.keycloak.cluster.ClusterProvider;
import org.keycloak.common.Profile;
import org.keycloak.common.Profile.Feature;
import org.keycloak.common.util.Retry;
import org.keycloak.common.util.Time;
import org.keycloak.models.AuthenticatedClientSessionModel;
@ -752,7 +754,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
UserSessionAdapter wrap(RealmModel realm, UserSessionEntity entity, boolean offline) {
UserModel user = null;
if (entity.getNotes().containsKey(SESSION_NOTE_LIGHTWEIGHT_USER)) {
if (Profile.isFeatureEnabled(Feature.TRANSIENT_USERS) && entity.getNotes().containsKey(SESSION_NOTE_LIGHTWEIGHT_USER)) {
LightweightUserAdapter lua = LightweightUserAdapter.fromString(session, realm, entity.getNotes().get(SESSION_NOTE_LIGHTWEIGHT_USER));
final UserSessionAdapter us = wrap(realm, entity, offline, lua);
lua.setUpdateHandler(lua1 -> {

View file

@ -28,7 +28,7 @@ import static org.keycloak.quarkus.runtime.cli.command.AbstractStartCommand.OPTI
@LegacyStore
public class FeaturesDistTest {
private static final String PREVIEW_FEATURES_EXPECTED_LOG = "Preview features enabled: account3, admin-fine-grained-authz, client-secret-rotation, declarative-user-profile, dpop, recovery-codes, scripts, token-exchange, update-email";
private static final String PREVIEW_FEATURES_EXPECTED_LOG = "Preview features enabled: account3, admin-fine-grained-authz, client-secret-rotation, declarative-user-profile, dpop, recovery-codes, scripts, token-exchange, transient-users, update-email";
@Test
public void testEnableOnBuild(KeycloakDistribution dist) {

View file

@ -50,7 +50,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
--features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api,
account2, account3, admin-api, admin-fine-grained-authz, admin2,
@ -58,7 +58,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
HTTP/TLS:

View file

@ -50,7 +50,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
--features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api,
account2, account3, admin-api, admin-fine-grained-authz, admin2,
@ -58,7 +58,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
HTTP/TLS:

View file

@ -61,7 +61,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
--features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api,
account2, account3, admin-api, admin-fine-grained-authz, admin2,
@ -69,7 +69,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
Config:

View file

@ -124,7 +124,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
--features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api,
account2, account3, admin-api, admin-fine-grained-authz, admin2,
@ -132,7 +132,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
Config:

View file

@ -61,7 +61,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
--features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api,
account2, account3, admin-api, admin-fine-grained-authz, admin2,
@ -69,7 +69,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
Config:

View file

@ -124,7 +124,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
--features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api,
account2, account3, admin-api, admin-fine-grained-authz, admin2,
@ -132,7 +132,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
Config:

View file

@ -77,7 +77,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
--features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api,
account2, account3, admin-api, admin-fine-grained-authz, admin2,
@ -85,7 +85,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
Hostname:

View file

@ -75,7 +75,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
--features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api,
account2, account3, admin-api, admin-fine-grained-authz, admin2,
@ -83,7 +83,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
Hostname:

View file

@ -140,7 +140,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
--features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api,
account2, account3, admin-api, admin-fine-grained-authz, admin2,
@ -148,7 +148,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
Hostname:

View file

@ -138,7 +138,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
--features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api,
account2, account3, admin-api, admin-fine-grained-authz, admin2,
@ -146,7 +146,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
Hostname:

View file

@ -78,7 +78,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
--features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api,
account2, account3, admin-api, admin-fine-grained-authz, admin2,
@ -86,7 +86,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
Hostname:

View file

@ -76,7 +76,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
--features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api,
account2, account3, admin-api, admin-fine-grained-authz, admin2,
@ -84,7 +84,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
Hostname:

View file

@ -141,7 +141,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
--features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api,
account2, account3, admin-api, admin-fine-grained-authz, admin2,
@ -149,7 +149,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
Hostname:

View file

@ -139,7 +139,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
--features-disabled <feature>
Disables a set of one or more features. Possible values are: account-api,
account2, account3, admin-api, admin-fine-grained-authz, admin2,
@ -147,7 +147,7 @@ Feature:
declarative-user-profile, device-flow, docker, dpop, dynamic-scopes, fips,
impersonation, js-adapter, kerberos, linkedin-oauth, map-storage, par,
preview, recovery-codes, scripts, step-up-authentication, token-exchange,
update-email, web-authn.
transient-users, update-email, web-authn.
Hostname:

View file

@ -16,6 +16,8 @@
*/
package org.keycloak.models.light;
import org.keycloak.common.Profile;
import org.keycloak.common.Profile.Feature;
import org.keycloak.common.util.Base64;
import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
@ -61,11 +63,11 @@ public class LightweightUserAdapter extends AbstractInMemoryUserAdapter {
public static final String ID_PREFIX = "lightweight-";
public static boolean isLightweightUser(UserModel user) {
return user instanceof LightweightUserAdapter;
return Profile.isFeatureEnabled(Feature.TRANSIENT_USERS) && user instanceof LightweightUserAdapter;
}
public static boolean isLightweightUser(String id) {
return id != null && id.startsWith(ID_PREFIX);
return Profile.isFeatureEnabled(Feature.TRANSIENT_USERS) && id != null && id.startsWith(ID_PREFIX);
}
public static String getLightweightUserId(String id) {

View file

@ -16,6 +16,8 @@
*/
package org.keycloak.models;
import org.keycloak.common.Profile;
import org.keycloak.common.Profile.Feature;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
@ -266,7 +268,7 @@ public class IdentityProviderModel implements Serializable {
* @return
*/
public boolean isTransientUsers() {
return Boolean.valueOf(getConfig().get(DO_NOT_STORE_USERS));
return Profile.isFeatureEnabled(Feature.TRANSIENT_USERS) && Boolean.valueOf(getConfig().get(DO_NOT_STORE_USERS));
}
/**

View file

@ -20,6 +20,7 @@ import org.keycloak.broker.oidc.mappers.UserAttributeMapper;
import org.keycloak.broker.provider.ConfigConstants;
import org.keycloak.broker.provider.HardcodedRoleMapper;
import org.keycloak.broker.provider.util.SimpleHttp;
import org.keycloak.common.Profile;
import org.keycloak.crypto.Algorithm;
import org.keycloak.events.Details;
import org.keycloak.events.Errors;
@ -50,6 +51,7 @@ import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
import org.keycloak.testsuite.updaters.Creator;
import org.keycloak.testsuite.util.AccountHelper;
import org.keycloak.testsuite.util.OAuthClient;
@ -92,6 +94,7 @@ import static org.keycloak.testsuite.broker.KcOidcBrokerConfiguration.CONSUMER_B
/**
* Final class as it's not intended to be overriden. Feel free to remove "final" if you really know what you are doing.
*/
@EnableFeature(value = Profile.Feature.TRANSIENT_USERS, skipRestart = true)
public final class KcOidcBrokerTransientSessionsTest extends AbstractAdvancedBrokerTest {
private final static String USER_ATTRIBUTE_NAME = "user-attribute";
private final static String USER_ATTRIBUTE_VALUE = "attribute-value";