Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
mederly committed May 24, 2023
2 parents b62a2ca + 1088735 commit 52ea165
Show file tree
Hide file tree
Showing 16 changed files with 401 additions and 132 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,17 @@
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.RequiredTextField;
import org.apache.wicket.markup.html.image.Image;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.model.Model;

import com.evolveum.midpoint.gui.api.component.BasePanel;
import com.evolveum.midpoint.gui.api.page.PageBase;
import com.evolveum.midpoint.web.component.message.FeedbackAlerts;

public class CaptchaPanel extends BasePanel<Void> {

private static final long serialVersionUID = 1L;

private static final String CAPTCHA_TEXT_ID = "text";
private static final String CAPTCHA_IMAGE_ID = "image";
/**
* The text provided by the user.
*/
Expand All @@ -49,7 +50,7 @@ public CaptchaPanel(String id, PageAdminLTE pageBase) {
add(feedback);

captchaImageResource = createCaptchaImageResource();
final Image captchaImage = new Image("image", captchaImageResource);
final Image captchaImage = new Image(CAPTCHA_IMAGE_ID, captchaImageResource);
captchaImage.setOutputMarkupId(true);
add(captchaImage);

Expand All @@ -69,8 +70,7 @@ public void onClick(AjaxRequestTarget target) {
add(new Label("textDescriptionLabel",
pageBase.createStringResource("CaptchaPanel.textDescriptionLabel")));

add(new RequiredTextField<String>("text",
new PropertyModel<>(CaptchaPanel.this, "captchaText"), String.class) {
add(new RequiredTextField<String>(CAPTCHA_TEXT_ID, Model.of()) {
private static final long serialVersionUID = 1L;

@Override
Expand Down Expand Up @@ -104,7 +104,8 @@ static String randomString() {
}

public String getCaptchaText() {
return captchaText;
RequiredTextField<String> captchaField = (RequiredTextField) get(CAPTCHA_TEXT_ID);
return captchaField.getInput();
}

public String getRandomText() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,9 @@
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.web.component.AjaxButton;
import com.evolveum.midpoint.web.component.AjaxSubmitButton;
import com.evolveum.midpoint.web.component.form.MidpointForm;
import com.evolveum.midpoint.web.component.prism.DynamicFormPanel;
import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;

Expand Down Expand Up @@ -118,7 +116,6 @@ private void doRegistration(AjaxRequestTarget target) {
if (!validateCaptcha(target)) {
return;
}

submitRegistration(target);
isSubmitted = true;
}
Expand All @@ -132,7 +129,7 @@ private boolean validateCaptcha(AjaxRequestTarget target) {
}

CaptchaPanel captcha = getCaptcha();
if (captcha.getRandomText() == null) {
if (captcha.getRandomText() == null || captcha.getCaptchaText() == null) {
String message = createStringResource("PageSelfRegistration.captcha.validation.failed")
.getString();
LOGGER.error(message);
Expand All @@ -142,16 +139,14 @@ private boolean validateCaptcha(AjaxRequestTarget target) {
return false;
}

if (captcha.getCaptchaText() != null && captcha.getRandomText() != null) {
if (!captcha.getCaptchaText().equals(captcha.getRandomText())) {
String message = createStringResource("PageSelfRegistration.captcha.validation.failed")
.getString();
LOGGER.error(message);
getSession().error(message);
updateCaptcha(target);
target.add(getFeedbackPanel());
return false;
}
if (!captcha.getCaptchaText().equals(captcha.getRandomText())) {
String message = createStringResource("PageSelfRegistration.captcha.validation.failed")
.getString();
LOGGER.error(message);
getSession().error(message);
updateCaptcha(target);
target.add(getFeedbackPanel());
return false;
}
LOGGER.trace("CAPTCHA Validation OK");
return true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* Copyright (C) 2010-2023 Evolveum and contributors
*
* This work is dual-licensed under the Apache License 2.0
* and European Union Public License. See LICENSE file for details.
*/
package com.evolveum.midpoint.gui.impl.page.login;

import com.evolveum.midpoint.authentication.api.authorization.AuthorizationAction;
import com.evolveum.midpoint.authentication.api.authorization.PageDescriptor;
import com.evolveum.midpoint.authentication.api.authorization.Url;
import com.evolveum.midpoint.authentication.api.util.AuthenticationModuleNameConstants;
import com.evolveum.midpoint.gui.api.model.LoadableModel;
import com.evolveum.midpoint.prism.delta.DeltaFactory;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.SecurityPolicyUtil;
import com.evolveum.midpoint.security.api.AuthorizationConstants;
import com.evolveum.midpoint.security.api.SecurityUtil;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.exception.*;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import org.apache.wicket.model.IModel;

@PageDescriptor(urls = { @Url(mountUrl = "/invitation", matchUrlForSecurity = "/invitation") },
action = {
@AuthorizationAction(actionUri = AuthorizationConstants.AUTZ_UI_INVITATION_URL) },
authModule = AuthenticationModuleNameConstants.MAIL_NONCE)
public class PageInvitation extends PageSelfRegistration {

private static final long serialVersionUID = 1L;

private static final Trace LOGGER = TraceManager.getTrace(PageInvitation.class);

private static final String DOT_CLASS = PageInvitation.class.getName() + ".";

public PageInvitation() {
super();
}

@Override
protected UserType instantiateUser() {
return (UserType) getPrincipalFocus();
}

@Override
protected ObjectDelta<UserType> prepareUserDelta(Task task, OperationResult result) throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException {
LOGGER.trace("Preparing user MODIFY delta (preregistered user registration)");
ObjectDelta<UserType> delta;
if (!isCustomFormDefined()) {
delta = getPrismContext().deltaFactory().object().createEmptyModifyDelta(UserType.class,
userModel.getObject().getOid());
if (getSelfRegistrationConfiguration().getInitialLifecycleState() != null) {
delta.addModificationReplaceProperty(UserType.F_LIFECYCLE_STATE,
getSelfRegistrationConfiguration().getInitialLifecycleState());
}
delta.addModificationReplaceProperty(SchemaConstants.PATH_PASSWORD_VALUE, createPassword().getValue());
} else {
delta = getDynamicFormPanel().getObjectDelta();
}

delta.addModificationReplaceContainer(SchemaConstants.PATH_NONCE,
createNonce(getNonceCredentialsPolicy(), task, result).asPrismContainerValue());
LOGGER.trace("Going to register user with modifications {}", delta);
return delta;
}

private NonceCredentialsPolicyType getNonceCredentialsPolicy() {
SecurityPolicyType securityPolicy = resolveSecurityPolicy();
if (securityPolicy == null) {
return null;
}
String invitationSequenceIdentifier = SecurityUtil.getInvitationSequenceIdentifier(securityPolicy);
AuthenticationSequenceType invitationSequence = SecurityPolicyUtil.findSequenceByIdentifier(securityPolicy, invitationSequenceIdentifier);
if (invitationSequence == null || invitationSequence.getModule().isEmpty()) {
return null;
}
String moduleIdentifier = invitationSequence.getModule().get(0).getIdentifier();
if (moduleIdentifier == null) {
return null;
}
MailNonceAuthenticationModuleType nonceModule = securityPolicy
.getAuthentication()
.getModules()
.getMailNonce()
.stream()
.filter(m -> moduleIdentifier.equals(m.getIdentifier()))
.findFirst()
.orElse(null);
if (nonceModule == null) {
return null;
}
String credentialName = nonceModule.getCredentialName();
if (credentialName == null) {
return null;
}
return securityPolicy
.getCredentials()
.getNonce()
.stream()
.filter(n -> credentialName.equals(n.getName()))
.findFirst()
.orElse(null);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ private void initPostAuthenticationConfiguration() {

}

private SecurityPolicyType resolveSecurityPolicy() {
protected SecurityPolicyType resolveSecurityPolicy() {
SecurityPolicyType securityPolicy = runPrivileged((Producer<SecurityPolicyType>) () -> {

Task task = createAnonymousTask(OPERATION_GET_SECURITY_POLICY);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,79 +70,25 @@ public class PageSelfRegistration extends PageAbstractFlow {
private static final String ID_COMPONENT_FEEDBACK = "componentFeedback";
private static final String ID_STATIC_FORM = "staticForm";

private static final String PARAM_USER_OID = "user";
protected IModel<UserType> userModel;

private IModel<UserType> userModel;

public PageSelfRegistration(PageParameters pageParameters) {
super(pageParameters);
}

private String getOidFromParams(PageParameters pageParameters) {
if (pageParameters == null) {
return null;
}

StringValue oidValue = pageParameters.get(PARAM_USER_OID);
if (oidValue != null && isNotAdministrator(oidValue.toString())) {
return oidValue.toString();
}

return null;
}

private boolean isNotAdministrator(String userOid) {
return !SystemObjectsType.USER_ADMINISTRATOR.value().equals(userOid);
public PageSelfRegistration() {
super(null);
}

@Override
public void initializeModel() {
final String userOid = getOidFromParams(pageParameters);

userModel = new LoadableModel<>(false) {
private static final long serialVersionUID = 1L;

@Override
protected UserType load() {
return createUserModel(userOid);
return instantiateUser();
}
};
}

private UserType createUserModel(String userOid) {
if (userOid == null) {
LOGGER.trace("Registration process for new user started");
return instantiateUser();
}

PrismObject<UserType> result = runPrivileged(new Producer<>() {

private static final long serialVersionUID = 1L;

@Override
public PrismObject<UserType> run() {
LOGGER.trace("Loading preregistered user with oid {}.", userOid);
Task task = createAnonymousTask(OPERATION_LOAD_USER);
OperationResult result = new OperationResult(OPERATION_LOAD_USER);
PrismObject<UserType> user = WebModelServiceUtils.loadObject(UserType.class, userOid,
PageSelfRegistration.this, task, result);
result.computeStatus();
return user;
}

});

if (result == null) {
LOGGER.error("Failed to load preregistered user");
getSession().error(
createStringResource("PageSelfRegistration.invalid.registration.link").getString());
throw new RestartResponseException(PageLogin.class);
}

return result.asObjectable();
}

private UserType instantiateUser() {
protected UserType instantiateUser() {
PrismObjectDefinition<UserType> userDef = getUserDefinition();
PrismObject<UserType> user;
try {
Expand Down Expand Up @@ -212,19 +158,7 @@ private void initInputProperties(FeedbackPanel feedback, String placeholderKey,
input.getBaseFormComponent().add(new EmptyOnBlurAjaxFormUpdatingBehaviour());
input.getBaseFormComponent().setRequired(true);
feedback.setFilter(new ContainerFeedbackMessageFilter(input.getBaseFormComponent()));

input.add(new VisibleEnableBehaviour() {

private static final long serialVersionUID = 1L;

@Override
public boolean isEnabled() {
return getOidFromParams(getPageParameters()) == null;
}

});
input.setRenderBodyOnly(true);

}

private void createPasswordPanel(WebMarkupContainer staticRegistrationForm) {
Expand Down Expand Up @@ -334,35 +268,12 @@ private void saveUser(OperationResult result) {
}
}

private ObjectDelta<UserType> prepareUserDelta(Task task, OperationResult result) throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException {
if (getOidFromParams(getPageParameters()) == null) {
LOGGER.trace("Preparing user ADD delta (new user registration)");
UserType userType = prepareUserToSave(task, result);
ObjectDelta<UserType> userDelta = DeltaFactory.Object.createAddDelta(userType.asPrismObject());
LOGGER.trace("Going to register user {}", userDelta);
return userDelta;
} else {
LOGGER.trace("Preparing user MODIFY delta (preregistered user registration)");
ObjectDelta<UserType> delta;
if (!isCustomFormDefined()) {
delta = getPrismContext().deltaFactory().object().createEmptyModifyDelta(UserType.class,
getOidFromParams(getPageParameters()));
if (getSelfRegistrationConfiguration().getInitialLifecycleState() != null) {
delta.addModificationReplaceProperty(UserType.F_LIFECYCLE_STATE,
getSelfRegistrationConfiguration().getInitialLifecycleState());
}
delta.addModificationReplaceProperty(SchemaConstants.PATH_PASSWORD_VALUE, createPassword().getValue());
} else {
delta = getDynamicFormPanel().getObjectDelta();
}

delta.addModificationReplaceContainer(SchemaConstants.PATH_NONCE,
createNonce(getSelfRegistrationConfiguration().getNoncePolicy(), task, result)
.asPrismContainerValue());
LOGGER.trace("Going to register user with modifications {}", delta);
return delta;

}
protected ObjectDelta<UserType> prepareUserDelta(Task task, OperationResult result) throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException {
LOGGER.trace("Preparing user ADD delta (new user registration)");
UserType userType = prepareUserToSave(task, result);
ObjectDelta<UserType> userDelta = DeltaFactory.Object.createAddDelta(userType.asPrismObject());
LOGGER.trace("Going to register user {}", userDelta);
return userDelta;
}

private UserType prepareUserToSave(Task task, OperationResult result) throws ExpressionEvaluationException, SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException {
Expand Down Expand Up @@ -419,7 +330,7 @@ private UserType prepareUserToSave(Task task, OperationResult result) throws Exp

}

private NonceType createNonce(NonceCredentialsPolicyType noncePolicy, Task task, OperationResult result) throws ExpressionEvaluationException, SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException {
protected NonceType createNonce(NonceCredentialsPolicyType noncePolicy, Task task, OperationResult result) throws ExpressionEvaluationException, SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException {
ProtectedStringType nonceCredentials = new ProtectedStringType();
nonceCredentials.setClearValue(generateNonce(noncePolicy, task, result));

Expand Down Expand Up @@ -447,7 +358,7 @@ private CredentialsType getCredentials(UserType user) {
return credentials;
}

private PasswordType createPassword() {
protected PasswordType createPassword() {
PasswordType password = new PasswordType();
ProtectedStringType protectedString = new ProtectedStringType();
protectedString.setClearValue(getPassword());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,9 @@ public abstract class SchemaConstants {
public static final QName CHANNEL_SELF_REGISTRATION_QNAME = new QName(NS_CHANNEL, "selfRegistration");
public static final String CHANNEL_SELF_REGISTRATION_URI = qNameToUri(CHANNEL_SELF_REGISTRATION_QNAME);

public static final QName CHANNEL_INVITATION_QNAME = new QName(NS_CHANNEL, "invitation");
public static final String CHANNEL_INVITATION_URI = qNameToUri(CHANNEL_INVITATION_QNAME);

// Channel for self-service part of the user interface. These are the pages when user is changing his own data.
// E.g. update of his own profile and password change are considered to be self-service.
public static final QName CHANNEL_SELF_SERVICE_QNAME = new QName(NS_CHANNEL, "selfService");
Expand Down

0 comments on commit 52ea165

Please sign in to comment.