/* * Password Management Servlets (PWM) * http://www.pwm-project.org * * Copyright (c) 2006-2009 Novell, Inc. * Copyright (c) 2009-2017 The PWM Project * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package password.pwm.http.servlet; import com.novell.ldapchai.ChaiUser; import com.novell.ldapchai.exception.ChaiException; import com.novell.ldapchai.exception.ChaiUnavailableException; import password.pwm.PwmApplication; import password.pwm.PwmConstants; import password.pwm.bean.EmailItemBean; import password.pwm.bean.UserIdentity; import password.pwm.config.ActionConfiguration; import password.pwm.config.Configuration; import password.pwm.config.PwmSetting; import password.pwm.config.profile.DeleteAccountProfile; import password.pwm.config.profile.ProfileType; import password.pwm.error.ErrorInformation; import password.pwm.error.PwmError; import password.pwm.error.PwmOperationalException; import password.pwm.error.PwmUnrecoverableException; import password.pwm.http.HttpMethod; import password.pwm.http.JspUrl; import password.pwm.http.ProcessStatus; import password.pwm.http.PwmRequest; import password.pwm.http.PwmRequestAttribute; import password.pwm.http.bean.DeleteAccountBean; import password.pwm.svc.event.AuditEvent; import password.pwm.svc.event.AuditRecord; import password.pwm.svc.event.AuditRecordFactory; import password.pwm.util.logging.PwmLogger; import password.pwm.util.macro.MacroMachine; import password.pwm.util.operations.ActionExecutor; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Locale; @WebServlet( name="SelfDeleteServlet", urlPatterns={ PwmConstants.URL_PREFIX_PRIVATE + "/delete", PwmConstants.URL_PREFIX_PRIVATE + "/DeleteAccount" } ) public class DeleteAccountServlet extends ControlledPwmServlet { private static final PwmLogger LOGGER = PwmLogger.forClass(DeleteAccountServlet.class); public enum DeleteAccountAction implements AbstractPwmServlet.ProcessAction { agree(HttpMethod.POST), delete(HttpMethod.POST), reset(HttpMethod.POST), ; private final HttpMethod method; DeleteAccountAction(final HttpMethod method) { this.method = method; } public Collection<HttpMethod> permittedMethods() { return Collections.singletonList(method); } } @Override public Class<? extends ProcessAction> getProcessActionsClass() { return DeleteAccountAction.class; } private DeleteAccountProfile getProfile(final PwmRequest pwmRequest) { return pwmRequest.getPwmSession().getSessionManager().getSelfDeleteProfile(pwmRequest.getPwmApplication()); } private DeleteAccountBean getBean(final PwmRequest pwmRequest) throws PwmUnrecoverableException { return pwmRequest.getPwmApplication().getSessionStateService().getBean(pwmRequest, DeleteAccountBean.class); } @Override public ProcessStatus preProcessCheck(final PwmRequest pwmRequest) throws PwmUnrecoverableException, IOException, ServletException { final PwmApplication pwmApplication = pwmRequest.getPwmApplication(); final DeleteAccountProfile deleteAccountProfile = getProfile(pwmRequest); if (!pwmApplication.getConfig().readSettingAsBoolean(PwmSetting.DELETE_ACCOUNT_ENABLE)) { throw new PwmUnrecoverableException(new ErrorInformation( PwmError.ERROR_SERVICE_NOT_AVAILABLE, "Setting " + PwmSetting.DELETE_ACCOUNT_ENABLE.toMenuLocationDebug(null,null) + " is not enabled.") ); } if (deleteAccountProfile == null) { throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_NO_PROFILE_ASSIGNED)); } return ProcessStatus.Continue; } @Override protected void nextStep(final PwmRequest pwmRequest) throws PwmUnrecoverableException, IOException, ChaiUnavailableException, ServletException { final DeleteAccountProfile profile = getProfile(pwmRequest); final DeleteAccountBean bean = getBean(pwmRequest); final String selfDeleteAgreementText = profile.readSettingAsLocalizedString( PwmSetting.DELETE_ACCOUNT_AGREEMENT, pwmRequest.getPwmSession().getSessionStateBean().getLocale() ); if (selfDeleteAgreementText != null && !selfDeleteAgreementText.trim().isEmpty()) { if (!bean.isAgreementPassed()) { final MacroMachine macroMachine = pwmRequest.getPwmSession().getSessionManager().getMacroMachine(pwmRequest.getPwmApplication()); final String expandedText = macroMachine.expandMacros(selfDeleteAgreementText); pwmRequest.setAttribute(PwmRequestAttribute.AgreementText, expandedText); pwmRequest.forwardToJsp(JspUrl.SELF_DELETE_AGREE); return; } } pwmRequest.forwardToJsp(JspUrl.SELF_DELETE_CONFIRM); } @ActionHandler(action = "reset") private ProcessStatus handleResetRequest( final PwmRequest pwmRequest ) throws ServletException, IOException, PwmUnrecoverableException, ChaiUnavailableException { pwmRequest.getPwmApplication().getSessionStateService().clearBean(pwmRequest, DeleteAccountBean.class); pwmRequest.sendRedirectToContinue(); return ProcessStatus.Halt; } @ActionHandler(action = "agree") private ProcessStatus handleAgreeRequest( final PwmRequest pwmRequest ) throws ServletException, IOException, PwmUnrecoverableException, ChaiUnavailableException { LOGGER.debug(pwmRequest, "user accepted agreement"); final DeleteAccountBean deleteAccountBean = getBean(pwmRequest); if (!deleteAccountBean.isAgreementPassed()) { deleteAccountBean.setAgreementPassed(true); final AuditRecord auditRecord = new AuditRecordFactory(pwmRequest).createUserAuditRecord( AuditEvent.AGREEMENT_PASSED, pwmRequest.getUserInfoIfLoggedIn(), pwmRequest.getSessionLabel(), ProfileType.DeleteAccount.toString() ); pwmRequest.getPwmApplication().getAuditManager().submit(auditRecord); } return ProcessStatus.Continue; } @ActionHandler(action = "delete") private ProcessStatus handleDeleteRequest( final PwmRequest pwmRequest ) throws ServletException, IOException, PwmUnrecoverableException, ChaiUnavailableException { final PwmApplication pwmApplication = pwmRequest.getPwmApplication(); final DeleteAccountProfile deleteAccountProfile = getProfile(pwmRequest); final UserIdentity userIdentity = pwmRequest.getUserInfoIfLoggedIn(); { // execute configured actions final List<ActionConfiguration> actions = deleteAccountProfile.readSettingAsAction(PwmSetting.DELETE_ACCOUNT_ACTIONS); if (actions != null && !actions.isEmpty()) { LOGGER.debug(pwmRequest, "executing configured actions to user " + userIdentity); final ActionExecutor actionExecutor = new ActionExecutor.ActionExecutorSettings(pwmApplication, userIdentity) .setExpandPwmMacros(true) .setMacroMachine(pwmRequest.getPwmSession().getSessionManager().getMacroMachine(pwmApplication)) .createActionExecutor(); try { actionExecutor.executeActions(actions, pwmRequest.getPwmSession()); } catch (PwmOperationalException e) { LOGGER.error("error during user delete action execution: ", e); throw new PwmUnrecoverableException(e.getErrorInformation(),e.getCause()); } } } // send notification sendProfileUpdateEmailNotice(pwmRequest); // mark the event log pwmApplication.getAuditManager().submit(AuditEvent.DELETE_ACCOUNT, pwmRequest.getPwmSession().getUserInfoBean(), pwmRequest.getPwmSession()); final String nextUrl = deleteAccountProfile.readSettingAsString(PwmSetting.DELETE_ACCOUNT_NEXT_URL); if (nextUrl != null && !nextUrl.isEmpty()) { final MacroMachine macroMachine = pwmRequest.getPwmSession().getSessionManager().getMacroMachine(pwmApplication); final String macroedUrl = macroMachine.expandMacros(nextUrl); LOGGER.debug(pwmRequest, "settinging forward url to post-delete next url: " + macroedUrl); pwmRequest.getPwmSession().getSessionStateBean().setForwardURL(macroedUrl); } // perform ldap entry delete. if (deleteAccountProfile.readSettingAsBoolean(PwmSetting.DELETE_ACCOUNT_DELETE_USER_ENTRY)) { final ChaiUser chaiUser = pwmApplication.getProxiedChaiUser(pwmRequest.getUserInfoIfLoggedIn()); try { chaiUser.getChaiProvider().deleteEntry(chaiUser.getEntryDN()); } catch (ChaiException e) { final PwmUnrecoverableException pwmException = PwmUnrecoverableException.fromChaiException(e); LOGGER.error("error during user delete", pwmException); throw pwmException; } } // clear the delete bean pwmApplication.getSessionStateService().clearBean(pwmRequest, DeleteAccountBean.class); // delete finished, so logout and redirect. pwmRequest.getPwmSession().unauthenticateUser(pwmRequest); pwmRequest.sendRedirectToContinue(); return ProcessStatus.Halt; } private static void sendProfileUpdateEmailNotice( final PwmRequest pwmRequest ) throws PwmUnrecoverableException, ChaiUnavailableException { final Configuration config = pwmRequest.getConfig(); final Locale locale = pwmRequest.getLocale(); final EmailItemBean configuredEmailSetting = config.readSettingAsEmail(PwmSetting.EMAIL_DELETEACCOUNT, locale); if (configuredEmailSetting == null) { LOGGER.debug(pwmRequest, "skipping delete account notice email for '" + pwmRequest.getUserInfoIfLoggedIn() + "' no email configured"); return; } pwmRequest.getPwmApplication().getEmailQueue().submitEmail( configuredEmailSetting, pwmRequest.getPwmSession().getUserInfoBean(), pwmRequest.getPwmSession().getSessionManager().getMacroMachine(pwmRequest.getPwmApplication()) ); } }