From 48c322edeaa2b346f1e4c6c2239d4bf47b7910f2 Mon Sep 17 00:00:00 2001 From: Katarina Valalikova Date: Tue, 25 Oct 2016 11:51:29 +0200 Subject: [PATCH] added captcha to registration page..small improivements for user registration notifier --- .../login/PageRegistrationConfirmation.java | 43 ++++- .../web/page/login/PageSelfRegistration.html | 14 ++ .../web/page/login/PageSelfRegistration.java | 153 +++++++++++++++--- .../localization/Midpoint.properties | 2 + .../notifiers/UserRegistrationNotifier.java | 61 ++++++- 5 files changed, 236 insertions(+), 37 deletions(-) diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/login/PageRegistrationConfirmation.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/login/PageRegistrationConfirmation.java index 29ba93c6612..183ac63d7bc 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/login/PageRegistrationConfirmation.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/login/PageRegistrationConfirmation.java @@ -8,10 +8,13 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.request.mapper.parameter.PageParameters; import org.apache.wicket.util.string.StringValue; +import org.w3c.tools.codec.Base64Decoder; +import org.w3c.tools.codec.Base64Encoder; import com.evolveum.midpoint.gui.api.page.PageBase; import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils; import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.crypto.EncryptionException; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.schema.constants.ObjectTypes; import com.evolveum.midpoint.schema.result.OperationResult; @@ -25,10 +28,10 @@ import com.evolveum.midpoint.web.util.MidPointPageParametersEncoder; import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; +import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; -//"http://localhost:8080/midpoint/confirm/registrationid=" + newUser.getOid() -//+ "/token=" + userType.getCostCenter() + "/roleId=00000000-0000-0000-0000-000000000008"; +//CONFIRMATION_LINK = "http://localhost:8080/midpoint/confirm/registration/"; @PageDescriptor(url = "/confirm", encoder = MidPointPageParametersEncoder.class) public class PageRegistrationConfirmation extends PageBase { @@ -59,6 +62,33 @@ private void init(final PageParameters pageParameters){ OperationResult result = runPrivileged(new Producer() { + /* + * private String createConfirmationLink(UserType userType){ + StringBuilder confirmLinkBuilder = new StringBuilder(CONFIRMATION_LINK); + + StringBuilder suffixBuilder = new StringBuilder("registrationId"); + suffixBuilder.append(userType.getOid()).append("/token/").append(userType.getCostCenter()).append("/roleId/00000000-0000-0000-0000-000000000008"); + String suffix = suffixBuilder.toString(); + Base64Encoder base64Encoder = new Base64Encoder(suffix); + String encoded = base64Encoder.processString(); + + String urlSuffix; + try { + ProtectedStringType protectedString = prismContext.getDefaultProtector().encryptString(encoded); + urlSuffix = new String(protectedString.getEncryptedDataType().getCipherData().getCipherValue()); + } catch (EncryptionException e) { + urlSuffix = encoded; + } + + confirmLinkBuilder.append(urlSuffix); + return confirmLinkBuilder.toString(); + + }(non-Javadoc) + * @see + * + com.evolveum.midpoint.util.Producer#run() + */ + @Override public OperationResult run() { @@ -66,7 +96,14 @@ public OperationResult run() { if (params == null) { params = getPageParameters(); } - StringValue userOidValue = params.get("registrationid"); +// StringValue registrationLink = params.get("registration"); +// Validate.notEmpty(registrationLink.toString()); +// +// String encoded = registrationLink.toString(); +// Base64Decoder decoder = new Base64Decoder(encoded); +// String decoded = decoder.processString(); + + StringValue userOidValue = params.get("registrationId"); Validate.notEmpty(userOidValue.toString()); StringValue tokenValue = params.get("token"); Validate.notEmpty(tokenValue.toString()); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/login/PageSelfRegistration.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/login/PageSelfRegistration.html index 18c66d9bd3a..20746299329 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/login/PageSelfRegistration.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/login/PageSelfRegistration.html @@ -86,6 +86,20 @@ + + +

+ +

+

+ +

+ + + + + +
diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/login/PageSelfRegistration.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/login/PageSelfRegistration.java index c2607c86523..991e98a574d 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/login/PageSelfRegistration.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/login/PageSelfRegistration.java @@ -5,14 +5,21 @@ import java.util.Iterator; import java.util.List; +import org.apache.wicket.RestartResponseException; import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.markup.html.AjaxLink; +import org.apache.wicket.extensions.markup.html.captcha.CaptchaImageResource; +import org.apache.wicket.markup.ComponentTag; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.basic.MultiLineLabel; +import org.apache.wicket.markup.html.form.RequiredTextField; +import org.apache.wicket.markup.html.image.Image; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.PropertyModel; import com.evolveum.midpoint.web.component.form.Form; +import com.evolveum.midpoint.common.policy.StringPolicyUtils; import com.evolveum.midpoint.common.policy.ValuePolicyGenerator; import com.evolveum.midpoint.gui.api.component.autocomplete.AutoCompleteTextPanel; import com.evolveum.midpoint.gui.api.component.password.PasswordPanel; @@ -42,8 +49,10 @@ import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; import com.evolveum.midpoint.web.page.admin.configuration.component.EmptyOnBlurAjaxFormUpdatingBehaviour; import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.LimitationsType; import com.evolveum.midpoint.xml.ns._public.common.common_3.OrgType; import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.StringPolicyType; import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemConfigurationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemObjectsType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; @@ -51,13 +60,12 @@ import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; - //"http://localhost:8080/midpoint/confirm/registrationid=" + newUser.getOid() //+ "/token=" + userType.getCostCenter() + "/roleId=00000000-0000-0000-0000-000000000008"; @PageDescriptor(url = "/registration") public class PageSelfRegistration extends PageBase { - - private static final String DOT_CLASS = PageSelfRegistration.class.getName() + "."; + + private static final String DOT_CLASS = PageSelfRegistration.class.getName() + "."; private static final String ID_MAIN_FORM = "mainForm"; private static final String ID_FIRST_NAME = "firstName"; @@ -67,20 +75,26 @@ public class PageSelfRegistration extends PageBase { private static final String ID_PASSWORD = "password"; private static final String ID_SUBMIT_REGISTRATION = "submitRegistration"; private static final String ID_REGISTRATION_SUBMITED = "registrationInfo"; + private static final String ID_IMAGE = "image"; + private static final String ID_CHANGE_LINK = "changeLink"; + private static final String ID_USER_TEXT = "text"; private static final String OPERATION_SAVE_USER = DOT_CLASS + "saveUser"; private static final String OPERATION_LOAD_ORGANIZATIONS = DOT_CLASS + "loadOrganization"; private static final long serialVersionUID = 1L; - IModel userModel; - boolean submited = false; + private IModel userModel; + + private boolean submited = false; + String randomString = null; + String captchaString = null; public PageSelfRegistration() { final UserType user = createUser(); - userModel = new LoadableModel() { + userModel = new LoadableModel(true) { private static final long serialVersionUID = 1L; @Override @@ -175,22 +189,89 @@ public Iterator getIterator(String input) { password.getBaseFormComponent().add(new EmptyOnBlurAjaxFormUpdatingBehaviour()); mainForm.add(password); + final CaptchaImageResource captcha = new CaptchaImageResource(); + OperationResult result = new OperationResult("generateRandomString"); + + StringPolicyType sp = StringPolicyUtils.normalize(new StringPolicyType()); + LimitationsType limits = new LimitationsType(); + limits.setMinLength(8); + limits.setMaxLength(12); + limits.setMinUniqueChars(6); + sp.setLimitations(limits); + + randomString = ValuePolicyGenerator.generate(sp, 8, result); + captcha.getChallengeIdModel().setObject(randomString); + + final Image captchaImage = new Image(ID_IMAGE, captcha); + captchaImage.setOutputMarkupId(true); + mainForm.add(captchaImage); + + AjaxLink changeCaptchaLink = new AjaxLink(ID_CHANGE_LINK) { + private static final long serialVersionUID = 1L; + + @Override + public void onClick(AjaxRequestTarget target) { + updateCaptcha(captcha, target); + } + }; + mainForm.add(changeCaptchaLink); + + RequiredTextField userText = new RequiredTextField(ID_USER_TEXT, new PropertyModel(PageSelfRegistration.this, "captchaString"), String.class) { + + private static final long serialVersionUID = 1L; + + @Override + protected final void onComponentTag(final ComponentTag tag) { + super.onComponentTag(tag); + tag.put("value", ""); + } + + }; +// userText.add(new EmptyOnBlurAjaxFormUpdatingBehaviour(){ +// +// @Override +// protected void onUpdate(AjaxRequestTarget target) { +// PageSelfRegistration.this.captchaString = (String) getDefaultModelObject(); +// } +// }); + userText.setOutputMarkupId(true); + + mainForm.add(userText); + + AjaxSubmitButton register = new AjaxSubmitButton(ID_SUBMIT_REGISTRATION) { private static final long serialVersionUID = 1L; protected void onSubmit(AjaxRequestTarget target, org.apache.wicket.markup.html.form.Form form) { - saveUser(target); + + if (randomString == null || captchaString == null || !randomString.equals(captchaString)) + { + getSession().error(createStringResource("PageSelfRegistration.captcha.validation.failed").getString()); + new RestartResponseException(PageSelfRegistration.class); + } + else + { + saveUser(target); + } + captcha.invalidate(); + target.add(getFeedbackPanel()); + target.add(PageSelfRegistration.this); + } }; + mainForm.add(register); - MultiLineLabel label = new MultiLineLabel(ID_REGISTRATION_SUBMITED, createStringResource("PageSelfRegistration.registration.confirm.message")); + MultiLineLabel label = new MultiLineLabel(ID_REGISTRATION_SUBMITED, + createStringResource("PageSelfRegistration.registration.confirm.message")); add(label); label.add(new VisibleEnableBehaviour() { + private static final long serialVersionUID = 1L; + @Override public boolean isVisible() { return submited; @@ -236,6 +317,13 @@ public List run() { }); } + + private void updateCaptcha(CaptchaImageResource captcha, AjaxRequestTarget target) { + + captcha.invalidate(); + Image captchaImage = (Image) get(createComponentPath(ID_MAIN_FORM, ID_IMAGE)); + target.add(captchaImage); + } private void saveUser(AjaxRequestTarget target) { OperationResult result = runPrivileged(new Producer() { @@ -247,44 +335,57 @@ public OperationResult run() { if (organization != null) { userType.getOrganization().add(new PolyStringType(organization)); } - + Task task = createAnonymousTask(OPERATION_SAVE_USER); task.setChannel(SchemaConstants.CHANNEL_GUI_REGISTRATION_URI); OperationResult result = new OperationResult(OPERATION_SAVE_USER); - - PrismObject systemConfig = WebModelServiceUtils.loadObject(SystemConfigurationType.class, SystemObjectsType.SYSTEM_CONFIGURATION.value(), PageSelfRegistration.this, task, result); - + + PrismObject systemConfig = WebModelServiceUtils.loadObject( + SystemConfigurationType.class, SystemObjectsType.SYSTEM_CONFIGURATION.value(), + PageSelfRegistration.this, task, result); + String token = null; ValuePolicyType policy = null; - if (systemConfig.asObjectable().getGlobalPasswordPolicyRef() != null) { - PrismObject valuePolicy = WebModelServiceUtils.loadObject(ValuePolicyType.class, systemConfig.asObjectable().getGlobalPasswordPolicyRef().getOid(), PageSelfRegistration.this, task, result); + if (systemConfig.asObjectable().getGlobalPasswordPolicyRef() != null) { + PrismObject valuePolicy = WebModelServiceUtils.loadObject( + ValuePolicyType.class, + systemConfig.asObjectable().getGlobalPasswordPolicyRef().getOid(), + PageSelfRegistration.this, task, result); policy = valuePolicy.asObjectable(); } - - token = ValuePolicyGenerator.generate(policy != null ? policy.getStringPolicy() : null, 24, result); + + token = ValuePolicyGenerator.generate(policy != null ? policy.getStringPolicy() : null, 24, + result); userType.setCostCenter(token); - - ObjectDelta userDelta= ObjectDelta.createAddDelta(userType.asPrismObject()); + + try { + getPrismContext().adopt(userType); + } catch (SchemaException e) { + // nothing to do, try without it + } + + ObjectDelta userDelta = ObjectDelta.createAddDelta(userType.asPrismObject()); userDelta.setPrismContext(getPrismContext()); - + WebModelServiceUtils.save(userDelta, result, task, PageSelfRegistration.this); return result; } - + }); - + result.computeStatus(); - + if (result.getStatus() == OperationResultStatus.SUCCESS) { submited = true; - success(createStringResource("PageSelfRegistration.registration.success").getString()); + getSession().success(createStringResource("PageSelfRegistration.registration.success").getString()); } else { - error(createStringResource("PageSelfRegistration.registration.error", result.getMessage()).getString()); + getSession().error(createStringResource("PageSelfRegistration.registration.error", result.getMessage()) + .getString()); + new RestartResponseException(PageSelfRegistration.class); } - target.add(getFeedbackPanel()); - target.add(this); + } private String getOrganization() { diff --git a/gui/admin-gui/src/main/resources/localization/Midpoint.properties b/gui/admin-gui/src/main/resources/localization/Midpoint.properties index 95411477e25..8647df8c91b 100644 --- a/gui/admin-gui/src/main/resources/localization/Midpoint.properties +++ b/gui/admin-gui/src/main/resources/localization/Midpoint.properties @@ -3405,3 +3405,5 @@ PageRegistrationConfirmation.continueToLogin=Continue to login page PageRegistrationConfirmation.confirmation.successful=Confirmation successful PageSelfRegistration.title=Registration PageRegistrationConfirmation.title=Confirm registration +PageSelfRegistration.reload=Reload +PageSelfRegistration.captcha.validation.failed=CAPTCHA validation failed, try again diff --git a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/UserRegistrationNotifier.java b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/UserRegistrationNotifier.java index eed70a0ea64..947fceab65c 100644 --- a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/UserRegistrationNotifier.java +++ b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/UserRegistrationNotifier.java @@ -16,7 +16,9 @@ package com.evolveum.midpoint.notifications.impl.notifiers; +import com.evolveum.midpoint.common.crypto.CryptoUtil; import com.evolveum.midpoint.model.api.expr.MidpointFunctions; +import com.evolveum.midpoint.model.common.expression.ExpressionVariables; import com.evolveum.midpoint.notifications.api.events.Event; import com.evolveum.midpoint.notifications.api.events.ModelEvent; import com.evolveum.midpoint.notifications.impl.NotificationFuctionsImpl; @@ -35,9 +37,13 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.UserPasswordNotifierType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserRegistrationNotifierType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; +import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; +import org.apache.commons.codec.digest.Crypt; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import org.w3c.tools.codec.Base64Decoder; +import org.w3c.tools.codec.Base64Encoder; import javax.annotation.PostConstruct; @@ -57,6 +63,8 @@ public class UserRegistrationNotifier extends GeneralNotifier { @Autowired private NotificationFuctionsImpl notificationsUtil; + + private static String CONFIRMATION_LINK = "http://localhost:8080/midpoint/confirm/"; @PostConstruct public void init() { @@ -108,13 +116,7 @@ protected String getSubject(Event event, GeneralNotifierType generalNotifierType @Override protected String getBody(Event event, GeneralNotifierType generalNotifierType, String transport, Task task, OperationResult result) { - ModelEvent modelEvent = (ModelEvent) event; - List> deltas = modelEvent.getFocusDeltas(); - PrismObject newUser = modelEvent.getFocusContext().getObjectNew(); - UserType userType = newUser.asObjectable(); - - String confirmationLink = "http://localhost:8080/midpoint/confirm/registrationid/" + newUser.getOid() - + "/token/" + userType.getCostCenter() + "/roleId/00000000-0000-0000-0000-000000000008"; + UserType userType = getUser(event); String plainTextPassword = "IhopeYouRememberYourPassword"; try { @@ -127,7 +129,7 @@ protected String getBody(Event event, GeneralNotifierType generalNotifierType, S messageBuilder.append(userType.getGivenName()).append(",\n") .append("your account was successfully created. To activate your account click on the following confiramtion link. ") .append("\n") - .append(confirmationLink) + .append(createConfirmationLink(userType)) .append("\n\n") .append("After your account is activated, use following credentials to log in: \n") .append("username: ") @@ -138,6 +140,49 @@ protected String getBody(Event event, GeneralNotifierType generalNotifierType, S return messageBuilder.toString(); } + private String createConfirmationLink(UserType userType){ + StringBuilder confirmLinkBuilder = new StringBuilder(CONFIRMATION_LINK); + + StringBuilder suffixBuilder = new StringBuilder("registrationId/"); + suffixBuilder.append(userType.getOid()).append("/token/").append(userType.getCostCenter()).append("/roleId/00000000-0000-0000-0000-000000000008"); + String suffix = suffixBuilder.toString(); +// Base64Encoder base64Encoder = new Base64Encoder(suffix); +// String encoded = base64Encoder.processString(); + +// String urlSuffix; +// try { +// ProtectedStringType protectedString = prismContext.getDefaultProtector().encryptString(encoded); +// urlSuffix = new String(protectedString.getEncryptedDataType().getCipherData().getCipherValue()); +// } catch (EncryptionException e) { +// String urlSuffix = encoded; +// } + + confirmLinkBuilder.append(suffix); + return confirmLinkBuilder.toString(); + + } + + private UserType getUser(Event event){ + ModelEvent modelEvent = (ModelEvent) event; + List> deltas = modelEvent.getFocusDeltas(); + PrismObject newUser = modelEvent.getFocusContext().getObjectNew(); + UserType userType = newUser.asObjectable(); + return userType; + } + + @Override + protected String getBodyFromExpression(Event event, GeneralNotifierType generalNotifierType, + ExpressionVariables variables, Task task, OperationResult result) { + UserType userType = getUser(event); + + String body = super.getBodyFromExpression(event, generalNotifierType, variables, task, result); + if (body != null ) { + return body + "\n" + createConfirmationLink(userType); + } + + return body; + } + @Override protected Trace getLogger() { return LOGGER;