have a factory like approach for profile contexts
This commit is contained in:
parent
21cfa54d4d
commit
802a670cc5
13 changed files with 61 additions and 64 deletions
|
@ -26,6 +26,5 @@ public interface UserProfileContext {
|
|||
|
||||
boolean isCreate();
|
||||
UserUpdateEvent getUpdateEvent();
|
||||
UserProfile getCurrent();
|
||||
UserProfile getUpdated();
|
||||
UserProfile getCurrentProfile();
|
||||
}
|
||||
|
|
|
@ -25,6 +25,6 @@ import org.keycloak.userprofile.validation.UserProfileValidationResult;
|
|||
*/
|
||||
public interface UserProfileProvider extends Provider {
|
||||
|
||||
UserProfileValidationResult validate(UserProfileContext updateContext);
|
||||
UserProfileValidationResult validate(UserProfileContext updateContext, UserProfile updatedProfile);
|
||||
|
||||
}
|
||||
|
|
|
@ -37,9 +37,8 @@ import org.keycloak.services.resources.AttributeFormDataProcessor;
|
|||
import org.keycloak.services.validation.Validation;
|
||||
import org.keycloak.userprofile.LegacyUserProfileProviderFactory;
|
||||
import org.keycloak.userprofile.UserProfileProvider;
|
||||
import org.keycloak.userprofile.profile.representations.AttributeUserProfile;
|
||||
import org.keycloak.userprofile.profile.DefaultUserProfileContext;
|
||||
import org.keycloak.userprofile.profile.representations.IdpUserProfile;
|
||||
import org.keycloak.userprofile.profile.representations.AttributeUserProfile;
|
||||
import org.keycloak.userprofile.utils.UserProfileUpdateHelper;
|
||||
import org.keycloak.userprofile.validation.UserProfileValidationResult;
|
||||
import org.keycloak.userprofile.validation.UserUpdateEvent;
|
||||
|
@ -112,9 +111,7 @@ public class IdpReviewProfileAuthenticator extends AbstractIdpAuthenticator {
|
|||
String oldEmail = userCtx.getEmail();
|
||||
String newEmail = updatedProfile.getFirstAttribute(UserModel.EMAIL);
|
||||
|
||||
DefaultUserProfileContext updateContext =
|
||||
new DefaultUserProfileContext(UserUpdateEvent.IdpReview, new IdpUserProfile(userCtx), updatedProfile);
|
||||
UserProfileValidationResult result = profileProvider.validate(updateContext);
|
||||
UserProfileValidationResult result = profileProvider.validate(DefaultUserProfileContext.forIdpReview(userCtx), updatedProfile);
|
||||
List<FormMessage> errors = Validation.getFormErrorsFromValidation(result);
|
||||
|
||||
if (errors != null && !errors.isEmpty()) {
|
||||
|
|
|
@ -72,9 +72,8 @@ public class RegistrationProfile implements FormAction, FormActionFactory {
|
|||
UserProfileProvider userProfile = context.getSession().getProvider(UserProfileProvider.class, LegacyUserProfileProviderFactory.PROVIDER_ID);
|
||||
|
||||
context.getEvent().detail(Details.REGISTER_METHOD, "form");
|
||||
DefaultUserProfileContext updateContext = new DefaultUserProfileContext(UserUpdateEvent.RegistrationProfile, updatedProfile);
|
||||
|
||||
UserProfileValidationResult result = userProfile.validate(updateContext);
|
||||
UserProfileValidationResult result = userProfile.validate(DefaultUserProfileContext.forRegistrationProfile(), updatedProfile);
|
||||
List<FormMessage> errors = Validation.getFormErrorsFromValidation(result);
|
||||
|
||||
if (errors.size() > 0) {
|
||||
|
@ -98,10 +97,7 @@ public class RegistrationProfile implements FormAction, FormActionFactory {
|
|||
public void success(FormContext context) {
|
||||
UserModel user = context.getUser();
|
||||
AttributeUserProfile updatedProfile = AttributeFormDataProcessor.toUserProfile(context.getHttpRequest().getDecodedFormParameters());
|
||||
|
||||
DefaultUserProfileContext updateContext =
|
||||
new DefaultUserProfileContext(UserUpdateEvent.RegistrationProfile, new UserModelUserProfile(user), updatedProfile);
|
||||
UserProfileUpdateHelper.update(updateContext.getUpdateEvent(), context.getSession(), user, updatedProfile, false);
|
||||
UserProfileUpdateHelper.update(UserUpdateEvent.RegistrationProfile, context.getSession(), user, updatedProfile, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -82,8 +82,7 @@ public class RegistrationUserCreation implements FormAction, FormActionFactory {
|
|||
UserProfileProvider profileProvider = context.getSession().getProvider(UserProfileProvider.class, LegacyUserProfileProviderFactory.PROVIDER_ID);
|
||||
|
||||
context.getEvent().detail(Details.REGISTER_METHOD, "form");
|
||||
DefaultUserProfileContext updateContext = new DefaultUserProfileContext(UserUpdateEvent.RegistrationUserCreation, newProfile);
|
||||
UserProfileValidationResult result = profileProvider.validate(updateContext);
|
||||
UserProfileValidationResult result = profileProvider.validate(DefaultUserProfileContext.forRegistrationUserCreation(), newProfile);
|
||||
|
||||
List<FormMessage> errors = Validation.getFormErrorsFromValidation(result);
|
||||
if (context.getRealm().isRegistrationEmailAsUsername()) {
|
||||
|
@ -128,10 +127,7 @@ public class RegistrationUserCreation implements FormAction, FormActionFactory {
|
|||
|
||||
UserModel user = context.getSession().users().addUser(context.getRealm(), username);
|
||||
user.setEnabled(true);
|
||||
|
||||
DefaultUserProfileContext updateContext =
|
||||
new DefaultUserProfileContext(UserUpdateEvent.RegistrationUserCreation, new UserModelUserProfile(user), updatedProfile);
|
||||
UserProfileUpdateHelper.update(updateContext.getUpdateEvent(), context.getSession(), user, updatedProfile, false);
|
||||
UserProfileUpdateHelper.update(UserUpdateEvent.RegistrationUserCreation, context.getSession(), user, updatedProfile, false);
|
||||
|
||||
context.getAuthenticationSession().setClientNote(OIDCLoginProtocol.LOGIN_HINT_PARAM, username);
|
||||
|
||||
|
|
|
@ -80,9 +80,7 @@ public class UpdateProfile implements RequiredActionProvider, RequiredActionFact
|
|||
String newEmail = updatedProfile.getFirstAttribute(UserModel.EMAIL);
|
||||
|
||||
UserProfileProvider userProfile = context.getSession().getProvider(UserProfileProvider.class, LegacyUserProfileProviderFactory.PROVIDER_ID);
|
||||
DefaultUserProfileContext updateContext =
|
||||
new DefaultUserProfileContext(UserUpdateEvent.UpdateProfile, new UserModelUserProfile(user), updatedProfile);
|
||||
UserProfileValidationResult result = userProfile.validate(updateContext);
|
||||
UserProfileValidationResult result = userProfile.validate(DefaultUserProfileContext.forUpdateProfile(user),updatedProfile);
|
||||
List<FormMessage> errors = Validation.getFormErrorsFromValidation(result);
|
||||
|
||||
if (errors != null && !errors.isEmpty()) {
|
||||
|
|
|
@ -369,10 +369,8 @@ public class AccountFormService extends AbstractSecuredLocalService {
|
|||
event.event(EventType.UPDATE_PROFILE).client(auth.getClient()).user(auth.getUser());
|
||||
|
||||
UserProfileProvider profileProvider = session.getProvider(UserProfileProvider.class, LegacyUserProfileProviderFactory.PROVIDER_ID);
|
||||
DefaultUserProfileContext updateContext =
|
||||
new DefaultUserProfileContext(UserUpdateEvent.Account, new UserModelUserProfile(user), updatedProfile);
|
||||
|
||||
UserProfileValidationResult result = profileProvider.validate(updateContext);
|
||||
UserProfileValidationResult result = profileProvider.validate(DefaultUserProfileContext.forAccountService(user), updatedProfile);
|
||||
List<FormMessage> errors = Validation.getFormErrorsFromValidation(result);
|
||||
|
||||
if (!errors.isEmpty()) {
|
||||
|
|
|
@ -48,11 +48,11 @@ import org.keycloak.services.util.ResolveRelative;
|
|||
import org.keycloak.storage.ReadOnlyException;
|
||||
import org.keycloak.theme.Theme;
|
||||
import org.keycloak.userprofile.LegacyUserProfileProviderFactory;
|
||||
import org.keycloak.userprofile.UserProfile;
|
||||
import org.keycloak.userprofile.UserProfileProvider;
|
||||
import org.keycloak.userprofile.utils.UserProfileUpdateHelper;
|
||||
import org.keycloak.userprofile.profile.representations.AccountUserRepresentationUserProfile;
|
||||
import org.keycloak.userprofile.profile.DefaultUserProfileContext;
|
||||
import org.keycloak.userprofile.profile.representations.UserModelUserProfile;
|
||||
import org.keycloak.userprofile.validation.UserProfileValidationResult;
|
||||
import org.keycloak.userprofile.validation.UserUpdateEvent;
|
||||
|
||||
|
@ -175,11 +175,9 @@ public class AccountRestService {
|
|||
|
||||
event.event(EventType.UPDATE_PROFILE).client(auth.getClient()).user(auth.getUser());
|
||||
|
||||
UserProfile updatedUser = new AccountUserRepresentationUserProfile(rep);
|
||||
UserProfileProvider profileProvider = session.getProvider(UserProfileProvider.class, LegacyUserProfileProviderFactory.PROVIDER_ID);
|
||||
AccountUserRepresentationUserProfile updatedUser = new AccountUserRepresentationUserProfile(rep);
|
||||
DefaultUserProfileContext updateContext =
|
||||
new DefaultUserProfileContext(UserUpdateEvent.Account, new UserModelUserProfile(user), updatedUser);
|
||||
UserProfileValidationResult result = profileProvider.validate(updateContext);
|
||||
UserProfileValidationResult result = profileProvider.validate(DefaultUserProfileContext.forAccountService(user), updatedUser);
|
||||
|
||||
if (result.hasFailureOfErrorType(Messages.READ_ONLY_USERNAME))
|
||||
return ErrorResponse.error(Messages.READ_ONLY_USERNAME, Response.Status.BAD_REQUEST);
|
||||
|
|
|
@ -44,7 +44,7 @@ public class LegacyUserProfileProvider implements UserProfileProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public UserProfileValidationResult validate(UserProfileContext updateContext) {
|
||||
public UserProfileValidationResult validate(UserProfileContext updateContext, UserProfile updatedProfile) {
|
||||
RealmModel realm = this.session.getContext().getRealm();
|
||||
|
||||
ValidationChainBuilder builder = ValidationChainBuilder.builder();
|
||||
|
@ -64,7 +64,7 @@ public class LegacyUserProfileProvider implements UserProfileProvider {
|
|||
addUserCreationValidators(builder);
|
||||
break;
|
||||
}
|
||||
return new UserProfileValidationResult(builder.build().validate(updateContext));
|
||||
return new UserProfileValidationResult(builder.build().validate(updateContext,updatedProfile));
|
||||
}
|
||||
|
||||
private void addUserCreationValidators(ValidationChainBuilder builder) {
|
||||
|
|
|
@ -17,8 +17,14 @@
|
|||
|
||||
package org.keycloak.userprofile.profile;
|
||||
|
||||
import org.keycloak.authentication.authenticators.broker.util.SerializedBrokeredIdentityContext;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.userprofile.UserProfile;
|
||||
import org.keycloak.userprofile.UserProfileContext;
|
||||
import org.keycloak.userprofile.profile.representations.IdpUserProfile;
|
||||
import org.keycloak.userprofile.profile.representations.UserModelUserProfile;
|
||||
import org.keycloak.userprofile.profile.representations.UserRepresentationUserProfile;
|
||||
import org.keycloak.userprofile.validation.UserUpdateEvent;
|
||||
|
||||
/**
|
||||
|
@ -27,23 +33,37 @@ import org.keycloak.userprofile.validation.UserUpdateEvent;
|
|||
public class DefaultUserProfileContext implements UserProfileContext {
|
||||
private boolean isCreated;
|
||||
private UserProfile currentUserProfile;
|
||||
private UserProfile updatedUserProfile;
|
||||
private UserUpdateEvent userUpdateEvent;
|
||||
|
||||
public DefaultUserProfileContext(UserUpdateEvent userUpdateEvent, UserProfile updatedUserProfile) {
|
||||
private DefaultUserProfileContext(UserUpdateEvent userUpdateEvent, UserProfile currentUserProfile) {
|
||||
this.userUpdateEvent = userUpdateEvent;
|
||||
this.isCreated = false;
|
||||
this.currentUserProfile = null;
|
||||
this.updatedUserProfile = updatedUserProfile;
|
||||
}
|
||||
|
||||
public DefaultUserProfileContext(UserUpdateEvent userUpdateEvent, UserProfile currentUserProfile, UserProfile updatedUserProfile) {
|
||||
this.userUpdateEvent = userUpdateEvent;
|
||||
this.isCreated = true;
|
||||
this.currentUserProfile = currentUserProfile;
|
||||
this.updatedUserProfile = updatedUserProfile;
|
||||
}
|
||||
|
||||
public static DefaultUserProfileContext forIdpReview(SerializedBrokeredIdentityContext currentUser) {
|
||||
return new DefaultUserProfileContext(UserUpdateEvent.IdpReview, new IdpUserProfile(currentUser));
|
||||
}
|
||||
|
||||
public static DefaultUserProfileContext forUpdateProfile(UserModel currentUser) {
|
||||
return new DefaultUserProfileContext(UserUpdateEvent.UpdateProfile, new UserModelUserProfile(currentUser));
|
||||
}
|
||||
|
||||
public static DefaultUserProfileContext forAccountService(UserModel currentUser) {
|
||||
return new DefaultUserProfileContext(UserUpdateEvent.Account, new UserModelUserProfile(currentUser));
|
||||
}
|
||||
|
||||
public static DefaultUserProfileContext forRegistrationUserCreation() {
|
||||
return new DefaultUserProfileContext(UserUpdateEvent.RegistrationUserCreation, null);
|
||||
}
|
||||
|
||||
public static DefaultUserProfileContext forRegistrationProfile() {
|
||||
return new DefaultUserProfileContext(UserUpdateEvent.RegistrationProfile, null);
|
||||
}
|
||||
|
||||
public static DefaultUserProfileContext forUserResource(UserRepresentation rep) {
|
||||
return new DefaultUserProfileContext(UserUpdateEvent.UserResource, new UserRepresentationUserProfile(rep));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreate() {
|
||||
|
@ -51,15 +71,10 @@ public class DefaultUserProfileContext implements UserProfileContext {
|
|||
}
|
||||
|
||||
@Override
|
||||
public UserProfile getCurrent() {
|
||||
public UserProfile getCurrentProfile() {
|
||||
return currentUserProfile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserProfile getUpdated() {
|
||||
return updatedUserProfile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserUpdateEvent getUpdateEvent(){
|
||||
return userUpdateEvent;
|
||||
|
|
|
@ -41,16 +41,16 @@ public class StaticValidators {
|
|||
|
||||
public static BiFunction<String, UserProfileContext, Boolean> userNameExists(KeycloakSession session) {
|
||||
return (value, context) ->
|
||||
!(context.getCurrent() != null
|
||||
&& !value.equals(context.getCurrent().getFirstAttribute(UserModel.USERNAME))
|
||||
!(context.getCurrentProfile() != null
|
||||
&& !value.equals(context.getCurrentProfile().getFirstAttribute(UserModel.USERNAME))
|
||||
&& session.users().getUserByUsername(value, session.getContext().getRealm()) != null);
|
||||
}
|
||||
|
||||
public static BiFunction<String, UserProfileContext, Boolean> isUserMutable(RealmModel realm) {
|
||||
return (value, context) ->
|
||||
!(!realm.isEditUsernameAllowed()
|
||||
&& context.getCurrent() != null
|
||||
&& !value.equals(context.getCurrent().getFirstAttribute(UserModel.USERNAME))
|
||||
&& context.getCurrentProfile() != null
|
||||
&& !value.equals(context.getCurrentProfile().getFirstAttribute(UserModel.USERNAME))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@ public class StaticValidators {
|
|||
RealmModel realm = session.getContext().getRealm();
|
||||
if (!realm.isDuplicateEmailsAllowed()) {
|
||||
UserModel userByEmail = session.users().getUserByEmail(value, realm);
|
||||
return !(realm.isRegistrationEmailAsUsername() && userByEmail != null && context.getCurrent() != null && !userByEmail.getId().equals(context.getCurrent().getId()));
|
||||
return !(realm.isRegistrationEmailAsUsername() && userByEmail != null && context.getCurrentProfile() != null && !userByEmail.getId().equals(context.getCurrentProfile().getId()));
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
@ -77,7 +77,7 @@ public class StaticValidators {
|
|||
if (!realm.isDuplicateEmailsAllowed()) {
|
||||
UserModel userByEmail = session.users().getUserByEmail(value, realm);
|
||||
// check for duplicated email
|
||||
return !(userByEmail != null && (context.getCurrent() == null || !userByEmail.getId().equals(context.getCurrent().getId())));
|
||||
return !(userByEmail != null && (context.getCurrentProfile() == null || !userByEmail.getId().equals(context.getCurrentProfile().getId())));
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package org.keycloak.userprofile.validation;
|
||||
|
||||
import org.keycloak.userprofile.UserProfile;
|
||||
import org.keycloak.userprofile.UserProfileContext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -32,17 +33,17 @@ public class ValidationChain {
|
|||
this.attributeValidators = attributeValidators;
|
||||
}
|
||||
|
||||
public List<AttributeValidationResult> validate(UserProfileContext updateContext) {
|
||||
public List<AttributeValidationResult> validate(UserProfileContext updateContext, UserProfile updatedProfile) {
|
||||
List<AttributeValidationResult> overallResults = new ArrayList<>();
|
||||
for (AttributeValidator attribute : attributeValidators) {
|
||||
List<ValidationResult> validationResults = new ArrayList<>();
|
||||
|
||||
String attributeKey = attribute.attributeKey;
|
||||
String attributeValue = updateContext.getUpdated().getFirstAttribute(attributeKey);
|
||||
String attributeValue = updatedProfile.getFirstAttribute(attributeKey);
|
||||
boolean attributeChanged = false;
|
||||
|
||||
if (attributeValue != null) {
|
||||
attributeChanged = updateContext.getCurrent() != null && !attributeValue.equals(updateContext.getCurrent().getFirstAttribute(attributeKey));
|
||||
attributeChanged = updateContext.getCurrentProfile() != null && !attributeValue.equals(updateContext.getCurrentProfile().getFirstAttribute(attributeKey));
|
||||
for (Validator validator : attribute.validators) {
|
||||
validationResults.add(new ValidationResult(validator.function.apply(attributeValue, updateContext), validator.errorType));
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ public class ValidationChainTest {
|
|||
ValidationChain testchain;
|
||||
UserProfile user;
|
||||
DefaultUserProfileContext updateContext;
|
||||
UserRepresentation rep = new UserRepresentation();
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
@ -27,7 +28,6 @@ public class ValidationChainTest {
|
|||
.addAttributeValidator().forAttribute("firstName")
|
||||
.addValidationFunction("FIRST_NAME_FIELD_ERRORKEY", (value, updateUserProfileContext) -> true).build();
|
||||
|
||||
UserRepresentation rep = new UserRepresentation();
|
||||
//default user content
|
||||
rep.singleAttribute(UserModel.FIRST_NAME, "firstName");
|
||||
rep.singleAttribute(UserModel.LAST_NAME, "lastName");
|
||||
|
@ -35,15 +35,14 @@ public class ValidationChainTest {
|
|||
rep.singleAttribute("FAKE_FIELD", "content");
|
||||
rep.singleAttribute("NULLABLE_FIELD", null);
|
||||
|
||||
user = new UserRepresentationUserProfile(rep);
|
||||
updateContext = new DefaultUserProfileContext(UserUpdateEvent.Account,null, user);
|
||||
updateContext = DefaultUserProfileContext.forRegistrationProfile();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validate() {
|
||||
testchain = builder.build();
|
||||
UserProfileValidationResult results = new UserProfileValidationResult(testchain.validate(updateContext));
|
||||
UserProfileValidationResult results = new UserProfileValidationResult(testchain.validate(updateContext, new UserRepresentationUserProfile(rep)));
|
||||
Assert.assertEquals(true, results.hasFailureOfErrorType("FAKE_FIELD_ERRORKEY"));
|
||||
Assert.assertEquals(false, results.hasFailureOfErrorType("FIRST_NAME_FIELD_ERRORKEY"));
|
||||
Assert.assertEquals(true, results.getValidationResults().stream().filter(o -> o.getField().equals("firstName")).collect(Collectors.toList()).get(0).isValid());
|
||||
|
@ -58,7 +57,7 @@ public class ValidationChainTest {
|
|||
.addAttributeValidator().forAttribute("FAKE_FIELD")
|
||||
.addValidationFunction("FAKE_FIELD_ERRORKEY_2", (value, updateUserProfileContext) -> false).build().build();
|
||||
|
||||
UserProfileValidationResult results = new UserProfileValidationResult(testchain.validate(updateContext));
|
||||
UserProfileValidationResult results = new UserProfileValidationResult(testchain.validate(updateContext, new UserRepresentationUserProfile(rep)));
|
||||
Assert.assertEquals(true, results.hasFailureOfErrorType("FAKE_FIELD_ERRORKEY_1"));
|
||||
Assert.assertEquals(true, results.hasFailureOfErrorType("FAKE_FIELD_ERRORKEY_2"));
|
||||
Assert.assertEquals(true, results.getValidationResults().stream().filter(o -> o.getField().equals("firstName")).collect(Collectors.toList()).get(0).isValid());
|
||||
|
@ -68,7 +67,7 @@ public class ValidationChainTest {
|
|||
|
||||
@Test
|
||||
public void emptyChain() {
|
||||
UserProfileValidationResult results = new UserProfileValidationResult(ValidationChainBuilder.builder().build().validate(updateContext));
|
||||
UserProfileValidationResult results = new UserProfileValidationResult(ValidationChainBuilder.builder().build().validate(updateContext,new UserRepresentationUserProfile(rep) ));
|
||||
Assert.assertEquals(Collections.emptyList(), results.getValidationResults());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue