mirror of
https://github.com/keycloak/keycloak.git
synced 2026-05-28 04:13:22 -04:00
Merge db303d4220 into 94dcc24a8d
This commit is contained in:
commit
eda6e8636e
16 changed files with 183 additions and 16 deletions
|
|
@ -38,6 +38,7 @@ import org.keycloak.sessions.AuthenticationSessionModel;
|
|||
public interface LoginFormsProvider extends Provider {
|
||||
|
||||
String UPDATE_PROFILE_CONTEXT_ATTR = "updateProfileCtx";
|
||||
String TERMS_ACCEPTANCE_REQUIRED = "termsAcceptanceRequired";
|
||||
|
||||
String IDENTITY_PROVIDER_BROKER_CONTEXT = "identityProviderBrokerCtx";
|
||||
|
||||
|
|
|
|||
|
|
@ -544,6 +544,7 @@ public class DefaultAuthenticationFlows {
|
|||
reviewProfileConfig.setAlias(IDP_REVIEW_PROFILE_CONFIG_ALIAS);
|
||||
Map<String, String> config = new HashMap<>();
|
||||
config.put("update.profile.on.first.login", IdentityProviderRepresentation.UPFLM_MISSING);
|
||||
config.put("terms_and_conditions", "false");
|
||||
reviewProfileConfig.setConfig(config);
|
||||
reviewProfileConfig = realm.addAuthenticatorConfig(reviewProfileConfig);
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,21 @@ public interface UserProfileProvider extends Provider {
|
|||
*/
|
||||
UserProfile create(UserProfileContext context, Map<String, ?> attributes);
|
||||
|
||||
/**
|
||||
* <p>Creates a new {@link UserProfile} instance for a given {@code context} and {@code attributes} for update purposes.
|
||||
*
|
||||
* <p>Instances created from this method are going to run validations and updates based on the given {@code user}. This
|
||||
* might be useful when updating an existing user.
|
||||
*
|
||||
* @param context the context
|
||||
* @param attributes the attributes to associate with the instance returned from this method
|
||||
* @param user the user to eventually update with the given {@code attributes}
|
||||
* @param terms if terms and condition required action user attribute neeed to be saved
|
||||
*
|
||||
* @return the user profile instance
|
||||
*/
|
||||
UserProfile create(UserProfileContext context, Map<String, ?> attributes, UserModel user, boolean terms);
|
||||
|
||||
/**
|
||||
* <p>Creates a new {@link UserProfile} instance for a given {@code context} and {@code attributes} for update purposes.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package org.keycloak.authentication.authenticators.broker;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
|
@ -28,8 +29,10 @@ import jakarta.ws.rs.core.Response;
|
|||
|
||||
import org.keycloak.authentication.AuthenticationFlowContext;
|
||||
import org.keycloak.authentication.authenticators.broker.util.SerializedBrokeredIdentityContext;
|
||||
import org.keycloak.authentication.requiredactions.TermsAndConditions;
|
||||
import org.keycloak.broker.provider.AbstractIdentityProvider;
|
||||
import org.keycloak.broker.provider.BrokeredIdentityContext;
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.EventBuilder;
|
||||
import org.keycloak.events.EventType;
|
||||
|
|
@ -56,7 +59,8 @@ import org.jboss.logging.Logger;
|
|||
public class IdpReviewProfileAuthenticator extends AbstractIdpAuthenticator {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(IdpReviewProfileAuthenticator.class);
|
||||
|
||||
private static final String TERMS_FIELD ="termsAccepted";
|
||||
private boolean enabledRequiredAction= false;
|
||||
@Override
|
||||
public boolean requiresUser() {
|
||||
return false;
|
||||
|
|
@ -65,14 +69,20 @@ public class IdpReviewProfileAuthenticator extends AbstractIdpAuthenticator {
|
|||
@Override
|
||||
protected void authenticateImpl(AuthenticationFlowContext context, SerializedBrokeredIdentityContext userCtx, BrokeredIdentityContext brokerContext) {
|
||||
IdentityProviderModel idpConfig = brokerContext.getIdpConfig();
|
||||
enabledRequiredAction = context.getRealm().getRequiredActionProviderByAlias(UserModel.RequiredAction.TERMS_AND_CONDITIONS.name()).isEnabled() && Boolean.valueOf(context.getAuthenticatorConfig().getConfig().get(IdpReviewProfileAuthenticatorFactory.TERMS_AND_CONDITIONS));
|
||||
boolean updateProfile = requiresUpdateProfilePage(context.getAuthenticatorConfig(), context, userCtx);
|
||||
|
||||
if (requiresUpdateProfilePage(context, userCtx, brokerContext)) {
|
||||
if ( enabledRequiredAction || updateProfile) {
|
||||
|
||||
// set up form only if
|
||||
// 1. terms and conditions is enabled and terms and condition configuration is true
|
||||
// 2. based on UPDATE_PROFILE_ON_FIRST_LOGIN value and IdP release data
|
||||
logger.debugf("Identity provider '%s' requires update profile action for broker user '%s'.", idpConfig.getAlias(), userCtx.getUsername());
|
||||
|
||||
// No formData for first render. The profile is rendered from userCtx
|
||||
Response challengeResponse = context.form()
|
||||
.setAttribute(LoginFormsProvider.UPDATE_PROFILE_CONTEXT_ATTR, userCtx)
|
||||
.setAttribute(LoginFormsProvider.TERMS_ACCEPTANCE_REQUIRED, enabledRequiredAction)
|
||||
.setFormData(null)
|
||||
.createUpdateProfilePage();
|
||||
context.challenge(challengeResponse);
|
||||
|
|
@ -82,14 +92,12 @@ public class IdpReviewProfileAuthenticator extends AbstractIdpAuthenticator {
|
|||
}
|
||||
}
|
||||
|
||||
protected boolean requiresUpdateProfilePage(AuthenticationFlowContext context, SerializedBrokeredIdentityContext userCtx, BrokeredIdentityContext brokerContext) {
|
||||
String enforceUpdateProfile = context.getAuthenticationSession().getAuthNote(ENFORCE_UPDATE_PROFILE);
|
||||
if (Boolean.parseBoolean(enforceUpdateProfile)) {
|
||||
protected boolean requiresUpdateProfilePage(AuthenticatorConfigModel authenticatorConfig, AuthenticationFlowContext context, SerializedBrokeredIdentityContext userCtx) {
|
||||
if (Boolean.parseBoolean(context.getAuthenticationSession().getAuthNote(ENFORCE_UPDATE_PROFILE))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String updateProfileFirstLogin;
|
||||
AuthenticatorConfigModel authenticatorConfig = context.getAuthenticatorConfig();
|
||||
if (authenticatorConfig == null || !authenticatorConfig.getConfig().containsKey(IdpReviewProfileAuthenticatorFactory.UPDATE_PROFILE_ON_FIRST_LOGIN)) {
|
||||
updateProfileFirstLogin = IdentityProviderRepresentation.UPFLM_MISSING;
|
||||
} else {
|
||||
|
|
@ -114,6 +122,19 @@ public class IdpReviewProfileAuthenticator extends AbstractIdpAuthenticator {
|
|||
EventBuilder event = context.getEvent();
|
||||
event.event(EventType.UPDATE_PROFILE).detail(Details.CONTEXT, UserProfileContext.IDP_REVIEW.name());
|
||||
MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
|
||||
|
||||
if (enabledRequiredAction && ! formData.containsKey(TERMS_FIELD)) {
|
||||
Response challengeForTerms = context.form()
|
||||
.setErrors(Collections.singletonList(new FormMessage(TERMS_FIELD, "termsAcceptanceRequired")))
|
||||
.setAttribute(LoginFormsProvider.UPDATE_PROFILE_CONTEXT_ATTR, userCtx)
|
||||
.setAttribute(LoginFormsProvider.TERMS_ACCEPTANCE_REQUIRED, enabledRequiredAction)
|
||||
.setFormData(formData)
|
||||
.createUpdateProfilePage();
|
||||
|
||||
context.challenge(challengeForTerms);
|
||||
|
||||
return;
|
||||
}
|
||||
UserModelDelegate updatedProfile = new UserModelDelegate(null) {
|
||||
|
||||
@Override
|
||||
|
|
@ -205,7 +226,13 @@ public class IdpReviewProfileAuthenticator extends AbstractIdpAuthenticator {
|
|||
UserProfileProvider profileProvider = context.getSession().getProvider(UserProfileProvider.class);
|
||||
Map<String, List<String>> attributes = new HashMap<>(formData);
|
||||
attributes.putIfAbsent(UserModel.USERNAME, Collections.singletonList(updatedProfile.getUsername()));
|
||||
UserProfile profile = profileProvider.create(UserProfileContext.IDP_REVIEW, attributes, updatedProfile);
|
||||
if (attributes.containsKey(TERMS_FIELD)) {
|
||||
//if form contains terms and condition remove this field and add TermsAndConditions.USER_ATTRIBUTE
|
||||
attributes.remove(TERMS_FIELD);
|
||||
attributes.put(TermsAndConditions.USER_ATTRIBUTE, Arrays.asList(Integer.toString(Time.currentTime())));
|
||||
}
|
||||
|
||||
UserProfile profile = profileProvider.create(UserProfileContext.IDP_REVIEW, attributes, updatedProfile, formData.containsKey(TERMS_FIELD));
|
||||
|
||||
try {
|
||||
profile.update((attributeName, userModel, oldValue) -> {
|
||||
|
|
@ -231,6 +258,7 @@ public class IdpReviewProfileAuthenticator extends AbstractIdpAuthenticator {
|
|||
Response challenge = context.form()
|
||||
.setErrors(errors)
|
||||
.setAttribute(LoginFormsProvider.UPDATE_PROFILE_CONTEXT_ATTR, userCtx)
|
||||
.setAttribute(LoginFormsProvider.TERMS_ACCEPTANCE_REQUIRED, enabledRequiredAction)
|
||||
.setFormData(formData)
|
||||
.createUpdateProfilePage();
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ public class IdpReviewProfileAuthenticatorFactory implements AuthenticatorFactor
|
|||
static IdpReviewProfileAuthenticator SINGLETON = new IdpReviewProfileAuthenticator();
|
||||
|
||||
public static final String UPDATE_PROFILE_ON_FIRST_LOGIN = "update.profile.on.first.login";
|
||||
public static final String TERMS_AND_CONDITIONS = "terms_and_conditions";
|
||||
|
||||
@Override
|
||||
public Authenticator create(KeycloakSession session) {
|
||||
|
|
@ -110,7 +111,13 @@ public class IdpReviewProfileAuthenticatorFactory implements AuthenticatorFactor
|
|||
+ " page for reviewing profile will be displayed and user can review and update his profile. Value 'off' means that page won't be displayed."
|
||||
+ " Value 'missing' means that page is displayed just when some required attribute is missing (wasn't downloaded from identity provider). Value 'missing' is the default one."
|
||||
+ " WARN: In case that user clicks 'Review profile info' on link duplications page, the update page will be always displayed. You would need to disable this authenticator to never display the page.");
|
||||
|
||||
configProperties.add(property);
|
||||
property = new ProviderConfigProperty();
|
||||
property.setName(TERMS_AND_CONDITIONS);
|
||||
property.setLabel("Accept Terms and Conditions");
|
||||
property.setType(ProviderConfigProperty.BOOLEAN_TYPE);
|
||||
property.setHelpText("Enable this option to require users to accept terms and conditions before their profile is recorded."
|
||||
+ "This ensures compliance with data regulation frameworks like GDPR on first login. You also need to enable the 'Terms and Conditions' Required action for this to take effect.");
|
||||
configProperties.add(property);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,8 +30,10 @@ import java.util.Set;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.keycloak.authentication.requiredactions.TermsAndConditions;
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientScopeModel;
|
||||
|
|
@ -50,6 +52,7 @@ import org.keycloak.userprofile.config.UPConfigUtils;
|
|||
import org.keycloak.userprofile.validator.AttributeRequiredByMetadataValidator;
|
||||
import org.keycloak.userprofile.validator.ImmutableAttributeValidator;
|
||||
import org.keycloak.userprofile.validator.MultiValueValidator;
|
||||
import org.keycloak.userprofile.validator.ReadOnlyAttributeUnchangedValidator;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
import org.keycloak.validate.AbstractSimpleValidator;
|
||||
import org.keycloak.validate.ValidatorConfig;
|
||||
|
|
@ -127,6 +130,33 @@ public class DeclarativeUserProfileProvider implements UserProfileProvider {
|
|||
return createUserProfile(context, attributes, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserProfile create(UserProfileContext context, Map<String, ?> attributes, UserModel user, boolean terms) {
|
||||
return terms ? createUserProfileWithTerms(context, attributes, user) : createUserProfile(context, attributes, user);
|
||||
}
|
||||
|
||||
private UserProfile createUserProfileWithTerms(UserProfileContext context, Map<String, ?> attributes, UserModel user) {
|
||||
UserProfileMetadata defaultMetadata = contextualMetadataRegistry.get(context);
|
||||
|
||||
if (defaultMetadata == null) {
|
||||
// some contexts (and their metadata) are available enabled when the corresponding feature is enabled
|
||||
throw new RuntimeException("No metadata is bound to the " + context + " context");
|
||||
}
|
||||
|
||||
UserProfileMetadata metadata = configureUserProfile(defaultMetadata, session);
|
||||
List<AttributeValidatorMetadata> readonlyValidators = new ArrayList<>();
|
||||
readonlyValidators.add(createReadOnlyAttributeUnchangedValidator(DeclarativeUserProfileProviderFactory.readOnlyAttributesPattern));
|
||||
metadata.addAttribute(TermsAndConditions.USER_ATTRIBUTE, 1000, readonlyValidators);
|
||||
Attributes profileAttributes = createAttributes(context, attributes, user, metadata);
|
||||
return new DefaultUserProfile(metadata, profileAttributes, createUserFactory(), user, session);
|
||||
}
|
||||
|
||||
private AttributeValidatorMetadata createReadOnlyAttributeUnchangedValidator(Pattern pattern) {
|
||||
return new AttributeValidatorMetadata(ReadOnlyAttributeUnchangedValidator.ID,
|
||||
ValidatorConfig.builder().config(ReadOnlyAttributeUnchangedValidator.CFG_PATTERN, pattern)
|
||||
.build());
|
||||
}
|
||||
|
||||
private UserProfile createUserProfile(UserProfileContext context, Map<String, ?> attributes, UserModel user) {
|
||||
UserProfileMetadata defaultMetadata = contextualMetadataRegistry.get(context);
|
||||
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ public class DeclarativeUserProfileProviderFactory implements UserProfileProvide
|
|||
*/
|
||||
private static final String[] DEFAULT_READ_ONLY_ATTRIBUTES = { "KERBEROS_PRINCIPAL", "LDAP_ID", "LDAP_ENTRY_DN", "CREATED_TIMESTAMP", "createTimestamp", "modifyTimestamp", "userCertificate", "saml.persistent.name.id.for.*", "ENABLED", "EMAIL_VERIFIED", "disabledReason", UserModel.EMAIL_PENDING };
|
||||
private static final String[] DEFAULT_ADMIN_READ_ONLY_ATTRIBUTES = { "KERBEROS_PRINCIPAL", "LDAP_ID", "LDAP_ENTRY_DN", "CREATED_TIMESTAMP", "createTimestamp", "modifyTimestamp" };
|
||||
private static final Pattern readOnlyAttributesPattern = getRegexPatternString(DEFAULT_READ_ONLY_ATTRIBUTES);
|
||||
public static final Pattern readOnlyAttributesPattern = getRegexPatternString(DEFAULT_READ_ONLY_ATTRIBUTES);
|
||||
private static final Pattern adminReadOnlyAttributesPattern = getRegexPatternString(DEFAULT_ADMIN_READ_ONLY_ATTRIBUTES);
|
||||
private static final String ANNOTATION_SCIM_SCHEMA_ATTRIBUTE = "kc.scim.schema.attribute";
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ public class InitialFlowsTest extends AbstractAuthenticationTest {
|
|||
private HashMap<String, AuthenticatorConfigRepresentation> expectedConfigs = new HashMap<>();
|
||||
|
||||
{
|
||||
expectedConfigs.put("idp-review-profile", newConfig("review profile config", new String[]{"update.profile.on.first.login", "missing"}));
|
||||
expectedConfigs.put("idp-review-profile", newConfig("review profile config", new String[]{"update.profile.on.first.login", "missing","terms_and_conditions","false"}));
|
||||
expectedConfigs.put("idp-create-user-if-unique", newConfig("create unique user config", new String[]{"require.password.update.after.registration", "false"}));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@ public class UpdateAccountInformationPage extends LanguageComboboxAwarePage {
|
|||
@FindBy(name = "department")
|
||||
private WebElement departmentInput;
|
||||
|
||||
@FindBy(name = "termsAccepted")
|
||||
private WebElement termsAccepted;
|
||||
|
||||
@FindBy(css = "input[type=\"submit\"]")
|
||||
private WebElement submitButton;
|
||||
|
||||
|
|
@ -46,6 +49,26 @@ public class UpdateAccountInformationPage extends LanguageComboboxAwarePage {
|
|||
clickLink(submitButton);
|
||||
}
|
||||
|
||||
public void acceptTerms(String userName,
|
||||
String email,
|
||||
String firstName,
|
||||
String lastName) {
|
||||
usernameInput.clear();
|
||||
usernameInput.sendKeys(userName);
|
||||
|
||||
emailInput.clear();
|
||||
emailInput.sendKeys(email);
|
||||
|
||||
firstNameInput.clear();
|
||||
firstNameInput.sendKeys(firstName);
|
||||
|
||||
lastNameInput.clear();
|
||||
lastNameInput.sendKeys(lastName);
|
||||
termsAccepted.click();
|
||||
|
||||
clickLink(submitButton);
|
||||
}
|
||||
|
||||
public void updateAccountInformation(String userName,
|
||||
String email,
|
||||
String firstName,
|
||||
|
|
|
|||
|
|
@ -212,6 +212,7 @@ public abstract class AbstractBrokerTest extends AbstractInitializedBaseBrokerTe
|
|||
} else if (execution.getAlias() != null && execution.getAlias().equals(IDP_REVIEW_PROFILE_CONFIG_ALIAS)) {
|
||||
AuthenticatorConfigRepresentation config = flows.getAuthenticatorConfig(execution.getAuthenticationConfig());
|
||||
config.getConfig().put("update.profile.on.first.login", IdentityProviderRepresentation.UPFLM_ON);
|
||||
config.getConfig().put("terms_and_conditions", "false");
|
||||
flows.updateAuthenticatorConfig(config.getId(), config);
|
||||
}
|
||||
}
|
||||
|
|
@ -223,6 +224,7 @@ public abstract class AbstractBrokerTest extends AbstractInitializedBaseBrokerTe
|
|||
} else if (execution.getAlias() != null && execution.getAlias().equals(IDP_REVIEW_PROFILE_CONFIG_ALIAS)) {
|
||||
AuthenticatorConfigRepresentation config = flows.getAuthenticatorConfig(execution.getAuthenticationConfig());
|
||||
config.getConfig().put("update.profile.on.first.login", IdentityProviderRepresentation.UPFLM_MISSING);
|
||||
config.getConfig().put("terms_and_conditions", "false");
|
||||
flows.updateAuthenticatorConfig(config.getId(), config);
|
||||
}
|
||||
}
|
||||
|
|
@ -253,10 +255,24 @@ public abstract class AbstractBrokerTest extends AbstractInitializedBaseBrokerTe
|
|||
} else if (execution.getAlias() != null && execution.getAlias().equals(IDP_REVIEW_PROFILE_CONFIG_ALIAS)) {
|
||||
AuthenticatorConfigRepresentation config = flows.getAuthenticatorConfig(execution.getAuthenticationConfig());
|
||||
config.getConfig().put("update.profile.on.first.login", IdentityProviderRepresentation.UPFLM_OFF);
|
||||
config.getConfig().put("terms_and_conditions", "false");
|
||||
flows.updateAuthenticatorConfig(config.getId(), config);
|
||||
}
|
||||
}
|
||||
|
||||
static void makeTermsAndCondionRequiredInLogin(AuthenticationExecutionInfoRepresentation execution, AuthenticationManagementResource flows) {
|
||||
if (execution.getProviderId() != null && execution.getProviderId().equals(IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID)) {
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED.name());
|
||||
flows.updateExecutions(DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_FLOW, execution);
|
||||
} else if (execution.getAlias() != null && execution.getAlias().equals(IDP_REVIEW_PROFILE_CONFIG_ALIAS)) {
|
||||
AuthenticatorConfigRepresentation config = flows.getAuthenticatorConfig(execution.getAuthenticationConfig());
|
||||
config.getConfig().put("update.profile.on.first.login", IdentityProviderRepresentation.UPFLM_ON);
|
||||
config.getConfig().put("terms_and_conditions", "true");
|
||||
flows.updateAuthenticatorConfig(config.getId(), config);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void disableExistingUser(AuthenticationExecutionInfoRepresentation execution, AuthenticationManagementResource flows) {
|
||||
if (execution.getProviderId() != null && (execution.getProviderId().equals(IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID) || execution.getProviderId().equals(IdpConfirmLinkAuthenticatorFactory.PROVIDER_ID))) {
|
||||
execution.setRequirement(AuthenticationExecutionModel.Requirement.DISABLED.name());
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
package org.keycloak.testsuite.broker;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
|
||||
import org.keycloak.admin.client.resource.AuthenticationManagementResource;
|
||||
import org.keycloak.admin.client.resource.IdentityProviderResource;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
|
|
@ -693,6 +695,29 @@ public abstract class AbstractFirstBrokerLoginTest extends AbstractInitializedBa
|
|||
assertEquals("User with username consumer already exists. Please login to account management to link the account.", errorPage.getError());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserExistsFirstBrokerLoginFlowUpdateProfileOnAndTermsAccepted() {
|
||||
createUser("consumer");
|
||||
|
||||
updateExecutionsAndEnableTermsAndCondition(AbstractBrokerTest::makeTermsAndCondionRequiredInLogin);
|
||||
|
||||
oauth.clientId("broker-app");
|
||||
loginPage.open(bc.consumerRealmName());
|
||||
|
||||
logInWithBroker(bc);
|
||||
|
||||
Assert.assertTrue(updateAccountInformationPage.isCurrent());
|
||||
Assert.assertTrue("We must be on correct realm right now",
|
||||
driver.getCurrentUrl().contains("/auth/realms/" + bc.consumerRealmName() + "/"));
|
||||
|
||||
log.debug("Updating info on updateAccount page");
|
||||
updateAccountInformationPage.acceptTerms("consumer", "consumer-user@redhat.com", "FirstName", "LastName");
|
||||
|
||||
waitForPage(driver, "we are sorry...", false);
|
||||
assertEquals("User with username consumer already exists. Please login to account management to link the account.", errorPage.getError());
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Refers to in old test suite: org.keycloak.testsuite.broker.AbstractFirstBrokerLoginTest#testRegistrationWithPasswordUpdateRequired
|
||||
|
|
@ -1720,4 +1745,9 @@ public abstract class AbstractFirstBrokerLoginTest extends AbstractInitializedBa
|
|||
|
||||
return () -> toggleRegistrationAllowed(realmName, genuineValue);
|
||||
}
|
||||
|
||||
private void updateExecutionsAndEnableTermsAndCondition(BiConsumer<AuthenticationExecutionInfoRepresentation, AuthenticationManagementResource> action) {
|
||||
updateExecutions(action);
|
||||
changeRequiredAction(true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,8 +21,10 @@ import java.util.function.BiConsumer;
|
|||
import org.keycloak.admin.client.resource.AuthenticationManagementResource;
|
||||
import org.keycloak.admin.client.resource.IdentityProviderResource;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.authentication.requiredactions.TermsAndConditions;
|
||||
import org.keycloak.models.utils.DefaultAuthenticationFlows;
|
||||
import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
|
||||
import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
|
||||
import org.junit.Before;
|
||||
|
|
@ -65,6 +67,16 @@ public abstract class AbstractInitializedBaseBrokerTest extends AbstractBaseBrok
|
|||
addClientsToProviderAndConsumer();
|
||||
|
||||
testContext.setInitialized(true);
|
||||
changeRequiredAction(false);
|
||||
|
||||
}
|
||||
|
||||
protected void changeRequiredAction(boolean enabled) {
|
||||
AuthenticationManagementResource flows = adminClient.realm(bc.consumerRealmName()).flows();
|
||||
RequiredActionProviderRepresentation rep = flows.getRequiredAction(TermsAndConditions.PROVIDER_ID);
|
||||
rep.setEnabled(enabled);
|
||||
flows.updateRequiredAction(TermsAndConditions.PROVIDER_ID, rep);
|
||||
|
||||
}
|
||||
|
||||
protected void updateExecutions(BiConsumer<AuthenticationExecutionInfoRepresentation, AuthenticationManagementResource> action) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<#import "template.ftl" as layout>
|
||||
<#import "user-profile-commons.ftl" as userProfileCommons>
|
||||
<#import "register-commons.ftl" as registerCommons>
|
||||
<@layout.registrationLayout displayMessage=messagesPerField.exists('global') displayRequiredFields=true; section>
|
||||
<#if section = "header">
|
||||
${msg("loginIdpReviewProfileTitle")}
|
||||
|
|
@ -7,6 +8,7 @@
|
|||
<form id="kc-idp-review-profile-form" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
|
||||
|
||||
<@userProfileCommons.userProfileFormFields/>
|
||||
<@registerCommons.termsAcceptance/>
|
||||
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<#import "template.ftl" as layout>
|
||||
<#import "user-profile-commons.ftl" as userProfileCommons>
|
||||
<#import "register-commons.ftl" as registerCommons>
|
||||
<@layout.registrationLayout displayMessage=messagesPerField.exists('global') displayRequiredFields=true; section>
|
||||
<#if section = "header">
|
||||
${msg("loginProfileTitle")}
|
||||
|
|
@ -7,10 +8,11 @@
|
|||
<form id="kc-update-profile-form" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
|
||||
|
||||
<@userProfileCommons.userProfileFormFields/>
|
||||
|
||||
<@registerCommons.termsAcceptance/>
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
|
||||
<div class="${properties.kcFormOptionsWrapperClass!}">
|
||||
|
||||
<div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
|
||||
<div class="${properties.kcFormOptionsWrapperClass!}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -25,4 +27,4 @@
|
|||
</div>
|
||||
</form>
|
||||
</#if>
|
||||
</@layout.registrationLayout>
|
||||
</@layout.registrationLayout>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<#macro termsAcceptance>
|
||||
<#if termsAcceptanceRequired??>
|
||||
<#if termsAcceptanceRequired!false>
|
||||
<div class="form-group">
|
||||
<div class="${properties.kcInputWrapperClass!}">
|
||||
${msg("termsTitle")}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<#macro termsAcceptance>
|
||||
<#if termsAcceptanceRequired??>
|
||||
<#if termsAcceptanceRequired!false>
|
||||
<div class="form-group">
|
||||
<div class="${properties.kcInputWrapperClass!}">
|
||||
${msg("termsTitle")}
|
||||
|
|
|
|||
Loading…
Reference in a new issue