package com.evolveum.midpoint.web.page.login; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang.Validate; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.markup.html.AjaxLink; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.request.mapper.parameter.PageParameters; import org.apache.wicket.util.string.StringValue; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.SecurityContextHolder; import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils; import com.evolveum.midpoint.model.api.context.NonceAuthenticationContext; import com.evolveum.midpoint.prism.delta.ContainerDelta; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.schema.constants.ObjectTypes; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.result.OperationResultStatus; import com.evolveum.midpoint.schema.util.ObjectTypeUtil; import com.evolveum.midpoint.security.api.ConnectionEnvironment; import com.evolveum.midpoint.security.api.MidPointPrincipal; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.Producer; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.web.application.PageDescriptor; import com.evolveum.midpoint.web.application.Url; import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType; import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsType; import com.evolveum.midpoint.xml.ns._public.common.common_3.NonceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; //CONFIRMATION_LINK = "http://localhost:8080/midpoint/confirm/registration/"; @PageDescriptor(urls = {@Url(mountUrl = SchemaConstants.REGISTRATION_CONFIRAMTION_PREFIX)}) public class PageRegistrationConfirmation extends PageRegistrationBase { private static final Trace LOGGER = TraceManager.getTrace(PageRegistrationConfirmation.class); private static final String DOT_CLASS = PageRegistrationConfirmation.class.getName() + "."; private static final String ID_LABEL_SUCCESS = "successLabel"; private static final String ID_LABEL_ERROR = "errorLabel"; private static final String ID_LINK_LOGIN = "linkToLogin"; private static final String ID_SUCCESS_PANEL = "successPanel"; private static final String ID_ERROR_PANEL = "errorPanel"; private static final String OPERATION_ASSIGN_DEFAULT_ROLES = DOT_CLASS + ".assignDefaultRoles"; private static final String OPERATION_FINISH_REGISTRATION = DOT_CLASS + "finishRegistration"; private static final long serialVersionUID = 1L; public PageRegistrationConfirmation() { super(); init(null); } public PageRegistrationConfirmation(PageParameters params) { super(); init(params); } private void init(final PageParameters pageParameters) { PageParameters params = pageParameters; if (params == null) { params = getPageParameters(); } OperationResult result = new OperationResult(OPERATION_FINISH_REGISTRATION); if (params == null) { LOGGER.error("Confirmation link is not valid. No credentials provided in it"); String msg = createStringResource("PageSelfRegistration.invalid.registration.link").getString(); getSession().error(createStringResource(msg)); result.recordFatalError(msg); initLayout(result); return; } StringValue userNameValue = params.get(SchemaConstants.USER_ID); Validate.notEmpty(userNameValue.toString()); StringValue tokenValue = params.get(SchemaConstants.TOKEN); Validate.notEmpty(tokenValue.toString()); UserType userType = checkUserCredentials(userNameValue.toString(), tokenValue.toString(), result); if (userType == null) { initLayout(result); return; } result = assignDefaultRoles(userType.getOid()); if (result.getStatus() == OperationResultStatus.FATAL_ERROR) { LOGGER.error("Failed to assign default roles, {}", result.getMessage()); initLayout(result); return; } final NonceType nonceClone = userType.getCredentials().getNonce().clone(); result = removeNonce(userType.getOid(), nonceClone); result = assignAdditionalRoleIfPresent(userType.getOid(), nonceClone, result); initLayout(result); } private UsernamePasswordAuthenticationToken authenticateUser(String username, String nonce, OperationResult result){ ConnectionEnvironment connEnv = new ConnectionEnvironment(); connEnv.setChannel(SchemaConstants.CHANNEL_GUI_SELF_REGISTRATION_URI); try { return getAuthenticationEvaluator().authenticate(connEnv, new NonceAuthenticationContext( username, nonce, getSelfRegistrationConfiguration().getNoncePolicy())); } catch (AuthenticationException ex) { getSession() .error(getString(ex.getMessage())); result.recordFatalError("Failed to validate user"); LoggingUtils.logException(LOGGER, ex.getMessage(), ex); return null; } catch (Exception ex) { getSession() .error(createStringResource("PageRegistrationConfirmation.authnetication.failed").getString()); LoggingUtils.logException(LOGGER, "Failed to confirm registration", ex); return null; } } private UserType checkUserCredentials(String username, String nonce, OperationResult result){ ConnectionEnvironment connEnv = new ConnectionEnvironment(); connEnv.setChannel(SchemaConstants.CHANNEL_GUI_SELF_REGISTRATION_URI); try { return getAuthenticationEvaluator().checkCredentials(connEnv, new NonceAuthenticationContext( username, nonce, getSelfRegistrationConfiguration().getNoncePolicy())); } catch (AuthenticationException ex) { getSession() .error(getString(ex.getMessage())); result.recordFatalError("Failed to validate user"); LoggingUtils.logException(LOGGER, ex.getMessage(), ex); return null; } catch (Exception ex) { getSession() .error(createStringResource("PageRegistrationConfirmation.authnetication.failed").getString()); LoggingUtils.logException(LOGGER, "Failed to confirm registration", ex); return null; } } private OperationResult assignDefaultRoles(final String userOid){ List<ContainerDelta<AssignmentType>> assignments = new ArrayList<>(); for (ObjectReferenceType defaultRole : getSelfRegistrationConfiguration().getDefaultRoles()) { AssignmentType assignment = new AssignmentType(); assignment.setTargetRef(defaultRole); try { getPrismContext().adopt(assignment); assignments.add(ContainerDelta.createModificationAdd(UserType.F_ASSIGNMENT, UserType.class, getPrismContext(), assignment)); } catch (SchemaException e) { //nothing to do } } final ObjectDelta<UserType> delta = ObjectDelta.createModifyDelta(userOid, assignments, UserType.class, getPrismContext()); return runPrivileged(new Producer<OperationResult>() { @Override public OperationResult run() { OperationResult result = new OperationResult(OPERATION_ASSIGN_DEFAULT_ROLES); Task task = createAnonymousTask(OPERATION_ASSIGN_DEFAULT_ROLES); WebModelServiceUtils.save(delta, result, task, PageRegistrationConfirmation.this); result.computeStatusIfUnknown(); return result; } }); } private OperationResult removeNonce(final String userOid, final NonceType nonce){ return runPrivileged(new Producer<OperationResult>() { @Override public OperationResult run() { OperationResult result = new OperationResult("assignDefaultRoles"); Task task = createAnonymousTask("assignDefaultRoles"); ObjectDelta<UserType> userAssignmentsDelta; try { userAssignmentsDelta = ObjectDelta.createModificationDeleteContainer(UserType.class, userOid, new ItemPath(UserType.F_CREDENTIALS, CredentialsType.F_NONCE), getPrismContext(), nonce); userAssignmentsDelta.addModificationReplaceProperty(UserType.F_LIFECYCLE_STATE, SchemaConstants.LIFECYCLE_ACTIVE); } catch (SchemaException e) { result.recordFatalError("Could not create delta"); LOGGER.error("Could not prepare delta for removing nonce and lyfecycle state {}", e.getMessage()); return result; } WebModelServiceUtils.save(userAssignmentsDelta, result, task, PageRegistrationConfirmation.this); result.computeStatusIfUnknown(); return result; } }); } private OperationResult assignAdditionalRoleIfPresent(String userOid, NonceType nonceType, OperationResult result){ // SecurityContextHolder.getContext().setAuthentication(token); return runPrivileged(new Producer<OperationResult>() { @Override public OperationResult run() { List<ItemDelta> userDeltas = new ArrayList<>(); if (nonceType.getName() != null) { Task task = createAnonymousTask(OPERATION_FINISH_REGISTRATION); ObjectDelta<UserType> assignRoleDelta = null; try { AssignmentType assignment = new AssignmentType(); assignment.setTargetRef( ObjectTypeUtil.createObjectRef(nonceType.getName(), ObjectTypes.ABSTRACT_ROLE)); getPrismContext().adopt(assignment); userDeltas.add((ItemDelta) ContainerDelta.createModificationAdd(UserType.F_ASSIGNMENT, UserType.class, getPrismContext(), assignment)); assignRoleDelta = ObjectDelta.createModifyDelta(userOid, userDeltas, UserType.class, getPrismContext()); assignRoleDelta.setPrismContext(getPrismContext()); } catch (SchemaException e) { result.recordFatalError("Could not create delta"); return result; } WebModelServiceUtils.save(assignRoleDelta, result, task, PageRegistrationConfirmation.this); result.computeStatusIfUnknown(); } return result; } }); // SecurityContextHolder.getContext().setAuthentication(null); } private void initLayout(final OperationResult result) { WebMarkupContainer successPanel = new WebMarkupContainer(ID_SUCCESS_PANEL); add(successPanel); successPanel.add(new VisibleEnableBehaviour() { private static final long serialVersionUID = 1L; @Override public boolean isVisible() { return result.getStatus() != OperationResultStatus.FATAL_ERROR; } @Override public boolean isEnabled() { return result.getStatus() != OperationResultStatus.FATAL_ERROR; } }); Label successMessage = new Label(ID_LABEL_SUCCESS, createStringResource("PageRegistrationConfirmation.confirmation.successful")); successPanel.add(successMessage); AjaxLink<String> continueToLogin = new AjaxLink<String>(ID_LINK_LOGIN) { private static final long serialVersionUID = 1L; @Override public void onClick(AjaxRequestTarget target) { setResponsePage(PageLogin.class); } }; successPanel.add(continueToLogin); WebMarkupContainer errorPanel = new WebMarkupContainer(ID_ERROR_PANEL); add(errorPanel); errorPanel.add(new VisibleEnableBehaviour() { private static final long serialVersionUID = 1L; @Override public boolean isEnabled() { return result.getStatus() == OperationResultStatus.FATAL_ERROR; } @Override public boolean isVisible() { return result.getStatus() == OperationResultStatus.FATAL_ERROR; } }); Label errorMessage = new Label(ID_LABEL_ERROR, createStringResource("PageRegistrationConfirmation.confirmation.error")); errorPanel.add(errorMessage); } @Override protected void createBreadcrumb() { // don't create breadcrumb for registration confirmation page } }