UpdateProfileServlet.java 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. /*
  2. * Password Management Servlets (PWM)
  3. * http://www.pwm-project.org
  4. *
  5. * Copyright (c) 2006-2009 Novell, Inc.
  6. * Copyright (c) 2009-2016 The PWM Project
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  21. */
  22. package password.pwm.http.servlet;
  23. import com.novell.ldapchai.ChaiUser;
  24. import com.novell.ldapchai.exception.ChaiException;
  25. import com.novell.ldapchai.exception.ChaiUnavailableException;
  26. import password.pwm.PwmApplication;
  27. import password.pwm.PwmConstants;
  28. import password.pwm.bean.EmailItemBean;
  29. import password.pwm.bean.TokenVerificationProgress;
  30. import password.pwm.bean.UserIdentity;
  31. import password.pwm.bean.UserInfoBean;
  32. import password.pwm.config.ActionConfiguration;
  33. import password.pwm.config.Configuration;
  34. import password.pwm.config.FormConfiguration;
  35. import password.pwm.config.FormUtility;
  36. import password.pwm.config.PwmSetting;
  37. import password.pwm.config.option.TokenStorageMethod;
  38. import password.pwm.config.profile.LdapProfile;
  39. import password.pwm.config.profile.UpdateAttributesProfile;
  40. import password.pwm.error.ErrorInformation;
  41. import password.pwm.error.PwmDataValidationException;
  42. import password.pwm.error.PwmError;
  43. import password.pwm.error.PwmException;
  44. import password.pwm.error.PwmOperationalException;
  45. import password.pwm.error.PwmUnrecoverableException;
  46. import password.pwm.http.HttpMethod;
  47. import password.pwm.http.JspUrl;
  48. import password.pwm.http.ProcessStatus;
  49. import password.pwm.http.PwmRequest;
  50. import password.pwm.http.PwmSession;
  51. import password.pwm.http.bean.UpdateProfileBean;
  52. import password.pwm.i18n.Message;
  53. import password.pwm.ldap.LdapOperationsHelper;
  54. import password.pwm.ldap.UserDataReader;
  55. import password.pwm.ldap.UserStatusReader;
  56. import password.pwm.svc.event.AuditEvent;
  57. import password.pwm.svc.event.AuditRecord;
  58. import password.pwm.svc.event.AuditRecordFactory;
  59. import password.pwm.svc.stats.Statistic;
  60. import password.pwm.svc.token.TokenPayload;
  61. import password.pwm.svc.token.TokenService;
  62. import password.pwm.svc.token.TokenType;
  63. import password.pwm.util.logging.PwmLogger;
  64. import password.pwm.util.macro.MacroMachine;
  65. import password.pwm.util.operations.ActionExecutor;
  66. import password.pwm.ws.server.RestResultBean;
  67. import javax.servlet.ServletException;
  68. import javax.servlet.annotation.WebServlet;
  69. import java.io.IOException;
  70. import java.util.Collection;
  71. import java.util.Collections;
  72. import java.util.HashSet;
  73. import java.util.LinkedHashMap;
  74. import java.util.List;
  75. import java.util.Locale;
  76. import java.util.Map;
  77. import java.util.Set;
  78. /**
  79. * User interaction servlet for updating user attributes
  80. *
  81. * @author Jason D. Rivard
  82. */
  83. @WebServlet(
  84. name="UpdateProfileServlet",
  85. urlPatterns = {
  86. PwmConstants.URL_PREFIX_PRIVATE + "/updateprofile",
  87. PwmConstants.URL_PREFIX_PRIVATE + "/UpdateProfile"
  88. }
  89. )
  90. public class UpdateProfileServlet extends ControlledPwmServlet {
  91. private static final PwmLogger LOGGER = PwmLogger.forClass(UpdateProfileServlet.class);
  92. public enum UpdateProfileAction implements AbstractPwmServlet.ProcessAction {
  93. updateProfile(HttpMethod.POST),
  94. agree(HttpMethod.POST),
  95. confirm(HttpMethod.POST),
  96. unConfirm(HttpMethod.POST),
  97. validate(HttpMethod.POST),
  98. enterCode(HttpMethod.POST),
  99. ;
  100. private final HttpMethod method;
  101. UpdateProfileAction(final HttpMethod method)
  102. {
  103. this.method = method;
  104. }
  105. public Collection<HttpMethod> permittedMethods()
  106. {
  107. return Collections.singletonList(method);
  108. }
  109. }
  110. @Override
  111. public Class<? extends ProcessAction> getProcessActionsClass() {
  112. return UpdateProfileAction.class;
  113. }
  114. private static UpdateAttributesProfile getProfile(final PwmRequest pwmRequest) {
  115. return pwmRequest.getPwmSession().getSessionManager().getUpdateAttributeProfile(pwmRequest.getPwmApplication());
  116. }
  117. private static UpdateProfileBean getBean(final PwmRequest pwmRequest) throws PwmUnrecoverableException {
  118. return pwmRequest.getPwmApplication().getSessionStateService().getBean(pwmRequest, UpdateProfileBean.class);
  119. }
  120. @ActionHandler(action = "enterCode")
  121. ProcessStatus handleEnterCodeRequest(
  122. final PwmRequest pwmRequest
  123. )
  124. throws PwmUnrecoverableException, IOException, ServletException, ChaiUnavailableException
  125. {
  126. final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
  127. final UpdateProfileBean updateProfileBean = getBean(pwmRequest);
  128. final PwmSession pwmSession = pwmRequest.getPwmSession();
  129. final String userEnteredCode = pwmRequest.readParameterAsString(PwmConstants.PARAM_TOKEN);
  130. boolean tokenPassed = false;
  131. ErrorInformation errorInformation = null;
  132. try {
  133. final TokenPayload tokenPayload = pwmApplication.getTokenService().processUserEnteredCode(
  134. pwmSession,
  135. pwmRequest.getUserInfoIfLoggedIn(),
  136. null,
  137. userEnteredCode
  138. );
  139. if (tokenPayload != null) {
  140. if (TokenType.UPDATE_EMAIL.matchesName(tokenPayload.getName())) {
  141. LOGGER.debug(pwmRequest, "email token passed");
  142. updateProfileBean.getTokenVerificationProgress().getPassedTokens().add(TokenVerificationProgress.TokenChannel.EMAIL);
  143. updateProfileBean.getTokenVerificationProgress().getIssuedTokens().add(TokenVerificationProgress.TokenChannel.EMAIL);
  144. updateProfileBean.getTokenVerificationProgress().setPhase(null);
  145. tokenPassed = true;
  146. } else if (TokenType.UPDATE_SMS.matchesName(tokenPayload.getName())) {
  147. LOGGER.debug(pwmRequest, "SMS token passed");
  148. updateProfileBean.getTokenVerificationProgress().getPassedTokens().add(TokenVerificationProgress.TokenChannel.SMS);
  149. updateProfileBean.getTokenVerificationProgress().getIssuedTokens().add(TokenVerificationProgress.TokenChannel.SMS);
  150. updateProfileBean.getTokenVerificationProgress().setPhase(null);
  151. tokenPassed = true;
  152. } else {
  153. final String errorMsg = "token name/type is not recognized: " + tokenPayload.getName();
  154. errorInformation = new ErrorInformation(PwmError.ERROR_TOKEN_INCORRECT,errorMsg);
  155. }
  156. }
  157. } catch (PwmOperationalException e) {
  158. final String errorMsg = "token incorrect: " + e.getMessage();
  159. errorInformation = new ErrorInformation(PwmError.ERROR_TOKEN_INCORRECT, errorMsg);
  160. }
  161. if (!tokenPassed) {
  162. if (errorInformation == null) {
  163. errorInformation = new ErrorInformation(PwmError.ERROR_TOKEN_INCORRECT);
  164. }
  165. LOGGER.debug(pwmSession, errorInformation.toDebugStr());
  166. setLastError(pwmRequest, errorInformation);
  167. }
  168. return ProcessStatus.Continue;
  169. }
  170. @ActionHandler(action = "validate")
  171. ProcessStatus restValidateForm(
  172. final PwmRequest pwmRequest
  173. )
  174. throws IOException, ServletException, PwmUnrecoverableException, ChaiUnavailableException
  175. {
  176. final UpdateProfileBean updateProfileBean = getBean(pwmRequest);
  177. final UpdateAttributesProfile updateAttributesProfile = getProfile(pwmRequest);
  178. boolean success = true;
  179. String userMessage = Message.getLocalizedMessage(pwmRequest.getLocale(), Message.Success_UpdateForm, pwmRequest.getConfig());
  180. try {
  181. // read in the responses from the request
  182. final Map<FormConfiguration,String> formValues = readFromJsonRequest(pwmRequest, updateAttributesProfile, updateProfileBean);
  183. // verify form meets the form requirements
  184. verifyFormAttributes(pwmRequest, formValues, true);
  185. updateProfileBean.getFormData().putAll(FormUtility.asStringMap(formValues));
  186. } catch (PwmOperationalException e) {
  187. success = false;
  188. userMessage = e.getErrorInformation().toUserStr(pwmRequest.getPwmSession(), pwmRequest.getPwmApplication());
  189. }
  190. final LinkedHashMap<String, String> outputMap = new LinkedHashMap<>();
  191. outputMap.put("version", "1");
  192. outputMap.put("message", userMessage);
  193. outputMap.put("success", String.valueOf(success));
  194. pwmRequest.outputJsonResult(new RestResultBean(outputMap));
  195. return ProcessStatus.Halt;
  196. }
  197. @ActionHandler(action = "unConfirm")
  198. ProcessStatus handleUnconfirm(
  199. final PwmRequest pwmRequest
  200. )
  201. throws PwmUnrecoverableException
  202. {
  203. final UpdateProfileBean updateProfileBean = getBean(pwmRequest);
  204. updateProfileBean.setFormSubmitted(false);
  205. updateProfileBean.setConfirmationPassed(false);
  206. updateProfileBean.clearTokenVerificationProgress();
  207. return ProcessStatus.Continue;
  208. }
  209. @ActionHandler(action = "agree")
  210. ProcessStatus handleAgreeRequest(final PwmRequest pwmRequest)
  211. throws ServletException, IOException, PwmUnrecoverableException, ChaiUnavailableException
  212. {
  213. LOGGER.debug(pwmRequest, "user accepted agreement");
  214. final UpdateProfileBean updateProfileBean = getBean(pwmRequest);
  215. if (!updateProfileBean.isAgreementPassed()) {
  216. updateProfileBean.setAgreementPassed(true);
  217. final AuditRecord auditRecord = new AuditRecordFactory(pwmRequest).createUserAuditRecord(
  218. AuditEvent.AGREEMENT_PASSED,
  219. pwmRequest.getUserInfoIfLoggedIn(),
  220. pwmRequest.getSessionLabel(),
  221. "UpdateProfile"
  222. );
  223. pwmRequest.getPwmApplication().getAuditManager().submit(auditRecord);
  224. }
  225. return ProcessStatus.Continue;
  226. }
  227. @ActionHandler(action = "confirm")
  228. ProcessStatus handleConfirmRequest(final PwmRequest pwmRequest)
  229. throws PwmUnrecoverableException
  230. {
  231. final UpdateProfileBean updateProfileBean = getBean(pwmRequest);
  232. updateProfileBean.setConfirmationPassed(true);
  233. return ProcessStatus.Continue;
  234. }
  235. @ActionHandler(action = "updateProfile")
  236. ProcessStatus handleUpdateRequest(
  237. final PwmRequest pwmRequest
  238. )
  239. throws PwmUnrecoverableException, ChaiUnavailableException, IOException, ServletException
  240. {
  241. final UpdateProfileBean updateProfileBean = getBean(pwmRequest);
  242. final UpdateAttributesProfile updateAttributesProfile = getProfile(pwmRequest);
  243. try {
  244. readFormParametersFromRequest(pwmRequest, updateAttributesProfile, updateProfileBean);
  245. } catch (PwmOperationalException e) {
  246. LOGGER.error(pwmRequest, e.getMessage());
  247. setLastError(pwmRequest, e.getErrorInformation());
  248. }
  249. updateProfileBean.setFormSubmitted(true);
  250. return ProcessStatus.Continue;
  251. }
  252. protected void nextStep(
  253. final PwmRequest pwmRequest)
  254. throws IOException, ServletException, PwmUnrecoverableException, ChaiUnavailableException
  255. {
  256. final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
  257. final UpdateProfileBean updateProfileBean = getBean(pwmRequest);
  258. final UpdateAttributesProfile updateAttributesProfile = getProfile(pwmRequest);
  259. final PwmSession pwmSession = pwmRequest.getPwmSession();
  260. final String updateProfileAgreementText = updateAttributesProfile.readSettingAsLocalizedString(
  261. PwmSetting.UPDATE_PROFILE_AGREEMENT_MESSAGE,
  262. pwmSession.getSessionStateBean().getLocale()
  263. );
  264. if (updateProfileAgreementText != null && updateProfileAgreementText.length() > 0) {
  265. if (!updateProfileBean.isAgreementPassed()) {
  266. final MacroMachine macroMachine = pwmRequest.getPwmSession().getSessionManager().getMacroMachine(pwmRequest.getPwmApplication());
  267. final String expandedText = macroMachine.expandMacros(updateProfileAgreementText);
  268. pwmRequest.setAttribute(PwmRequest.Attribute.AgreementText, expandedText);
  269. pwmRequest.forwardToJsp(JspUrl.UPDATE_ATTRIBUTES_AGREEMENT);
  270. return;
  271. }
  272. }
  273. //make sure there is form data in the bean.
  274. if (!updateProfileBean.isFormLdapLoaded()) {
  275. updateProfileBean.getFormData().clear();
  276. updateProfileBean.getFormData().putAll((formDataFromLdap(pwmRequest, updateAttributesProfile)));
  277. updateProfileBean.setFormLdapLoaded(true);
  278. forwardToForm(pwmRequest, updateAttributesProfile, updateProfileBean);
  279. return;
  280. }
  281. if (!updateProfileBean.isFormSubmitted()) {
  282. forwardToForm(pwmRequest, updateAttributesProfile, updateProfileBean);
  283. return;
  284. }
  285. // validate the form data.
  286. try {
  287. // verify form meets the form requirements
  288. final List<FormConfiguration> formFields = updateAttributesProfile.readSettingAsForm(PwmSetting.UPDATE_PROFILE_FORM);
  289. final Map<FormConfiguration, String> formValues = FormUtility.readFormValuesFromMap(updateProfileBean.getFormData(), formFields, pwmRequest.getLocale());
  290. verifyFormAttributes(pwmRequest, formValues, true);
  291. } catch (PwmException e) {
  292. LOGGER.error(pwmSession, e.getMessage());
  293. setLastError(pwmRequest, e.getErrorInformation());
  294. forwardToForm(pwmRequest, updateAttributesProfile, updateProfileBean);
  295. return;
  296. }
  297. final boolean requireConfirmation = updateAttributesProfile.readSettingAsBoolean(PwmSetting.UPDATE_PROFILE_SHOW_CONFIRMATION);
  298. if (requireConfirmation && !updateProfileBean.isConfirmationPassed()) {
  299. forwardToConfirmForm(pwmRequest, updateAttributesProfile, updateProfileBean);
  300. return;
  301. }
  302. final Set<TokenVerificationProgress.TokenChannel> requiredVerifications = determineTokenPhaseRequired(pwmRequest, updateProfileBean, updateAttributesProfile);
  303. if (requiredVerifications != null) {
  304. for (final TokenVerificationProgress.TokenChannel tokenChannel : requiredVerifications) {
  305. if (requiredVerifications.contains(tokenChannel)) {
  306. if (!updateProfileBean.getTokenVerificationProgress().getIssuedTokens().contains(tokenChannel)) {
  307. initializeToken(pwmRequest, updateProfileBean, tokenChannel);
  308. }
  309. if (!updateProfileBean.getTokenVerificationProgress().getPassedTokens().contains(tokenChannel)) {
  310. updateProfileBean.getTokenVerificationProgress().setPhase(tokenChannel);
  311. pwmRequest.forwardToJsp(JspUrl.UPDATE_ATTRIBUTES_ENTER_CODE);
  312. return;
  313. }
  314. }
  315. }
  316. }
  317. try {
  318. // write the form values
  319. final ChaiUser theUser = pwmSession.getSessionManager().getActor(pwmApplication);
  320. doProfileUpdate(pwmRequest, updateProfileBean.getFormData(), theUser);
  321. pwmRequest.getPwmResponse().forwardToSuccessPage(Message.Success_UpdateProfile);
  322. return;
  323. } catch (PwmException e) {
  324. LOGGER.error(pwmSession, e.getMessage());
  325. setLastError(pwmRequest, e.getErrorInformation());
  326. } catch (ChaiException e) {
  327. final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_UPDATE_ATTRS_FAILURE,e.toString());
  328. LOGGER.error(pwmSession, errorInformation.toDebugStr());
  329. setLastError(pwmRequest, errorInformation);
  330. }
  331. forwardToForm(pwmRequest, updateAttributesProfile, updateProfileBean);
  332. }
  333. @Override
  334. public ProcessStatus preProcessCheck(final PwmRequest pwmRequest) throws PwmUnrecoverableException, IOException, ServletException {
  335. if (!pwmRequest.getPwmApplication().getConfig().readSettingAsBoolean(PwmSetting.UPDATE_PROFILE_ENABLE)) {
  336. pwmRequest.respondWithError(new ErrorInformation(PwmError.ERROR_SERVICE_NOT_AVAILABLE, "Setting " + PwmSetting.UPDATE_PROFILE_ENABLE.toMenuLocationDebug(null,null) + " is not enabled."));
  337. return ProcessStatus.Halt;
  338. }
  339. final UpdateAttributesProfile updateAttributesProfile = getProfile(pwmRequest);
  340. if (updateAttributesProfile == null) {
  341. pwmRequest.respondWithError(new ErrorInformation(PwmError.ERROR_NO_PROFILE_ASSIGNED));
  342. return ProcessStatus.Halt;
  343. }
  344. return ProcessStatus.Continue;
  345. }
  346. final Map<FormConfiguration,String> readFormParametersFromRequest(
  347. final PwmRequest pwmRequest,
  348. final UpdateAttributesProfile updateAttributesProfile,
  349. final UpdateProfileBean updateProfileBean
  350. )
  351. throws PwmUnrecoverableException, PwmDataValidationException, ChaiUnavailableException
  352. {
  353. final List<FormConfiguration> formFields = updateAttributesProfile.readSettingAsForm(PwmSetting.UPDATE_PROFILE_FORM);
  354. //read the values from the request
  355. final Map<FormConfiguration,String> formValueMap = FormUtility.readFormValuesFromRequest(pwmRequest, formFields, pwmRequest.getLocale());
  356. updateProfileBean.getFormData().clear();
  357. updateProfileBean.getFormData().putAll(FormUtility.asStringMap(formValueMap));
  358. return formValueMap;
  359. }
  360. static Map<FormConfiguration,String> readFromJsonRequest(
  361. final PwmRequest pwmRequest,
  362. final UpdateAttributesProfile updateAttributesProfile,
  363. final UpdateProfileBean updateProfileBean
  364. )
  365. throws PwmDataValidationException, PwmUnrecoverableException, IOException
  366. {
  367. final List<FormConfiguration> formFields = updateAttributesProfile.readSettingAsForm(PwmSetting.UPDATE_PROFILE_FORM);
  368. final Map<FormConfiguration,String> formValueMap = FormUtility.readFormValuesFromMap(pwmRequest.readBodyAsJsonStringMap(), formFields, pwmRequest.getLocale());
  369. updateProfileBean.getFormData().clear();
  370. updateProfileBean.getFormData().putAll(FormUtility.asStringMap(formValueMap));
  371. return formValueMap;
  372. }
  373. public static void doProfileUpdate(
  374. final PwmRequest pwmRequest,
  375. final Map<String,String> formValues,
  376. final ChaiUser theUser
  377. )
  378. throws PwmUnrecoverableException, ChaiUnavailableException, PwmOperationalException
  379. {
  380. final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
  381. final PwmSession pwmSession = pwmRequest.getPwmSession();
  382. final UserInfoBean uiBean = pwmRequest.getPwmSession().getUserInfoBean();
  383. final UpdateAttributesProfile updateAttributesProfile = pwmRequest.getPwmSession().getSessionManager().getUpdateAttributeProfile(pwmApplication);
  384. final List<FormConfiguration> formFields = updateAttributesProfile.readSettingAsForm(PwmSetting.UPDATE_PROFILE_FORM);
  385. final Map<FormConfiguration, String> formMap = FormUtility.readFormValuesFromMap(formValues, formFields, pwmRequest.getLocale());
  386. // verify form meets the form requirements (may be redundant, but shouldn't hurt)
  387. verifyFormAttributes(pwmRequest, formMap, false);
  388. // write values.
  389. LOGGER.info("updating profile for " + pwmRequest.getPwmSession().getUserInfoBean().getUserIdentity());
  390. pwmRequest.getPwmSession().getSessionManager().getChaiProvider();
  391. LdapOperationsHelper.writeFormValuesToLdap(pwmRequest.getPwmApplication(), pwmRequest.getPwmSession(), theUser, formMap, false);
  392. final UserIdentity userIdentity = uiBean.getUserIdentity();
  393. // re-populate the uiBean because we have changed some values.
  394. final UserStatusReader userStatusReader = new UserStatusReader(pwmRequest.getPwmApplication(), pwmRequest.getSessionLabel());
  395. userStatusReader.populateActorUserInfoBean(
  396. pwmRequest.getPwmSession(),
  397. userIdentity
  398. );
  399. // clear cached read attributes.
  400. pwmRequest.getPwmSession().getSessionManager().clearUserDataReader();
  401. { // execute configured actions
  402. final List<ActionConfiguration> actions = updateAttributesProfile.readSettingAsAction(PwmSetting.UPDATE_PROFILE_WRITE_ATTRIBUTES);
  403. if (actions != null && !actions.isEmpty()) {
  404. LOGGER.debug(pwmRequest, "executing configured actions to user " + userIdentity);
  405. final ActionExecutor actionExecutor = new ActionExecutor.ActionExecutorSettings(pwmApplication, userIdentity)
  406. .setExpandPwmMacros(true)
  407. .setMacroMachine(pwmSession.getSessionManager().getMacroMachine(pwmApplication))
  408. .createActionExecutor();
  409. actionExecutor.executeActions(actions, pwmSession);
  410. }
  411. }
  412. sendProfileUpdateEmailNotice(pwmSession,pwmApplication);
  413. // mark the event log
  414. pwmApplication.getAuditManager().submit(AuditEvent.UPDATE_PROFILE, pwmSession.getUserInfoBean(), pwmSession);
  415. // mark the uiBean so we user isn't recycled to the update profile page by the CommandServlet
  416. uiBean.setRequiresUpdateProfile(false);
  417. // clear out the updateProfileBean
  418. pwmApplication.getSessionStateService().clearBean(pwmRequest, UpdateProfileBean.class);
  419. // success, so forward to success page
  420. pwmApplication.getStatisticsManager().incrementValue(Statistic.UPDATE_ATTRIBUTES);
  421. }
  422. private static void verifyFormAttributes(
  423. final PwmRequest pwmRequest,
  424. final Map<FormConfiguration, String> formValues,
  425. final boolean allowResultCaching
  426. )
  427. throws PwmOperationalException, PwmUnrecoverableException
  428. {
  429. final Locale userLocale = pwmRequest.getLocale();
  430. // see if the values meet form requirements.
  431. FormUtility.validateFormValues(pwmRequest.getConfig(), formValues, userLocale);
  432. // check unique fields against ldap
  433. FormUtility.validateFormValueUniqueness(
  434. pwmRequest.getPwmApplication(),
  435. formValues,
  436. userLocale,
  437. Collections.singletonList(pwmRequest.getPwmSession().getUserInfoBean().getUserIdentity()),
  438. allowResultCaching
  439. );
  440. }
  441. private static void sendProfileUpdateEmailNotice(
  442. final PwmSession pwmSession,
  443. final PwmApplication pwmApplication
  444. )
  445. throws PwmUnrecoverableException, ChaiUnavailableException {
  446. final Configuration config = pwmApplication.getConfig();
  447. final Locale locale = pwmSession.getSessionStateBean().getLocale();
  448. final EmailItemBean configuredEmailSetting = config.readSettingAsEmail(PwmSetting.EMAIL_UPDATEPROFILE, locale);
  449. if (configuredEmailSetting == null) {
  450. LOGGER.debug(pwmSession, "skipping send profile update email for '" + pwmSession.getUserInfoBean().getUserIdentity() + "' no email configured");
  451. return;
  452. }
  453. pwmApplication.getEmailQueue().submitEmail(
  454. configuredEmailSetting,
  455. pwmSession.getUserInfoBean(),
  456. pwmSession.getSessionManager().getMacroMachine(pwmApplication)
  457. );
  458. }
  459. private static void forwardToForm(final PwmRequest pwmRequest, final UpdateAttributesProfile updateAttributesProfile, final UpdateProfileBean updateProfileBean)
  460. throws ServletException, PwmUnrecoverableException, IOException
  461. {
  462. final List<FormConfiguration> form = updateAttributesProfile.readSettingAsForm(PwmSetting.UPDATE_PROFILE_FORM);
  463. final Map<FormConfiguration,String> formValueMap = formMapFromBean(updateAttributesProfile, updateProfileBean);
  464. pwmRequest.addFormInfoToRequestAttr(form, formValueMap, false, false);
  465. pwmRequest.forwardToJsp(JspUrl.UPDATE_ATTRIBUTES);
  466. }
  467. private static void forwardToConfirmForm(final PwmRequest pwmRequest, final UpdateAttributesProfile updateAttributesProfile, final UpdateProfileBean updateProfileBean)
  468. throws ServletException, PwmUnrecoverableException, IOException
  469. {
  470. final List<FormConfiguration> form = updateAttributesProfile.readSettingAsForm(PwmSetting.UPDATE_PROFILE_FORM);
  471. final Map<FormConfiguration,String> formValueMap = formMapFromBean(updateAttributesProfile, updateProfileBean);
  472. pwmRequest.addFormInfoToRequestAttr(form, formValueMap, true, false);
  473. pwmRequest.forwardToJsp(JspUrl.UPDATE_ATTRIBUTES_CONFIRM);
  474. }
  475. private static Map<FormConfiguration, String> formMapFromBean(final UpdateAttributesProfile updateAttributesProfile, final UpdateProfileBean updateProfileBean) throws PwmUnrecoverableException {
  476. final List<FormConfiguration> form = updateAttributesProfile.readSettingAsForm(PwmSetting.UPDATE_PROFILE_FORM);
  477. final Map<FormConfiguration, String> formValueMap = new LinkedHashMap<>();
  478. for (final FormConfiguration formConfiguration : form) {
  479. formValueMap.put(
  480. formConfiguration,
  481. updateProfileBean.getFormData().keySet().contains(formConfiguration.getName())
  482. ? updateProfileBean.getFormData().get(formConfiguration.getName())
  483. : ""
  484. );
  485. }
  486. return formValueMap;
  487. }
  488. private static Map<String,String> formDataFromLdap(final PwmRequest pwmRequest, final UpdateAttributesProfile updateAttributesProfile)
  489. throws PwmUnrecoverableException
  490. {
  491. final UserDataReader userDataReader = pwmRequest.getPwmSession().getSessionManager().getUserDataReader(pwmRequest.getPwmApplication());
  492. final List<FormConfiguration> formFields = updateAttributesProfile.readSettingAsForm(PwmSetting.UPDATE_PROFILE_FORM);
  493. final Map<FormConfiguration, String> formMap = new LinkedHashMap<>();
  494. FormUtility.populateFormMapFromLdap(formFields, pwmRequest.getSessionLabel(), formMap, userDataReader);
  495. return FormUtility.asStringMap(formMap);
  496. }
  497. private static Set<TokenVerificationProgress.TokenChannel> determineTokenPhaseRequired(
  498. final PwmRequest pwmRequest,
  499. final UpdateProfileBean updateProfileBean,
  500. final UpdateAttributesProfile updateAttributesProfile
  501. )
  502. throws PwmUnrecoverableException
  503. {
  504. final Set<TokenVerificationProgress.TokenChannel> returnObj = new HashSet<>();
  505. final LdapProfile ldapProfile = pwmRequest.getUserInfoIfLoggedIn().getLdapProfile(pwmRequest.getConfig());
  506. final Map<String,String> userFormData = updateProfileBean.getFormData();
  507. Map<String,String> ldapData = null;
  508. if (updateAttributesProfile.readSettingAsBoolean(PwmSetting.UPDATE_PROFILE_EMAIL_VERIFICATION)) {
  509. final String emailAddressAttribute = ldapProfile.readSettingAsString(PwmSetting.EMAIL_USER_MAIL_ATTRIBUTE);
  510. if (userFormData.containsKey(emailAddressAttribute)) {
  511. ldapData = formDataFromLdap(pwmRequest, updateAttributesProfile);
  512. if (userFormData.get(emailAddressAttribute) != null && !userFormData.get(emailAddressAttribute).equalsIgnoreCase(ldapData.get(emailAddressAttribute))) {
  513. returnObj.add(TokenVerificationProgress.TokenChannel.EMAIL);
  514. }
  515. } else {
  516. LOGGER.warn(pwmRequest, "email verification enabled, but email attribute '" + emailAddressAttribute + "' is not in update form");
  517. }
  518. }
  519. if (updateAttributesProfile.readSettingAsBoolean(PwmSetting.UPDATE_PROFILE_SMS_VERIFICATION)) {
  520. final String phoneNumberAttribute = ldapProfile.readSettingAsString(PwmSetting.SMS_USER_PHONE_ATTRIBUTE);
  521. if (userFormData.containsKey(phoneNumberAttribute)) {
  522. if (ldapData == null) {
  523. ldapData = formDataFromLdap(pwmRequest, updateAttributesProfile);
  524. }
  525. if (userFormData.get(phoneNumberAttribute) != null && !userFormData.get(phoneNumberAttribute).equalsIgnoreCase(ldapData.get(phoneNumberAttribute))) {
  526. returnObj.add(TokenVerificationProgress.TokenChannel.SMS);
  527. }
  528. } else {
  529. LOGGER.warn(pwmRequest, "sms verification enabled, but phone attribute '" + phoneNumberAttribute + "' is not in update form");
  530. }
  531. }
  532. return returnObj;
  533. }
  534. private void initializeToken(
  535. final PwmRequest pwmRequest,
  536. final UpdateProfileBean updateProfileBean,
  537. final TokenVerificationProgress.TokenChannel tokenType
  538. )
  539. throws PwmUnrecoverableException
  540. {
  541. final PwmSession pwmSession = pwmRequest.getPwmSession();
  542. final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
  543. if (pwmApplication.getConfig().getTokenStorageMethod() == TokenStorageMethod.STORE_LDAP) {
  544. throw new PwmUnrecoverableException(new ErrorInformation(PwmError.CONFIG_FORMAT_ERROR,null,new String[]{
  545. "cannot generate new user tokens when storage type is configured as STORE_LDAP.",
  546. }));
  547. }
  548. final MacroMachine macroMachine = pwmRequest.getPwmSession().getSessionManager().getMacroMachine(pwmApplication);
  549. final Configuration config = pwmApplication.getConfig();
  550. final LdapProfile ldapProfile = pwmRequest.getUserInfoIfLoggedIn().getLdapProfile(pwmRequest.getConfig());
  551. switch (tokenType) {
  552. case SMS: {
  553. final String telephoneNumberAttribute = ldapProfile.readSettingAsString(PwmSetting.SMS_USER_PHONE_ATTRIBUTE);
  554. final String toNum = updateProfileBean.getFormData().get(telephoneNumberAttribute);
  555. final String tokenKey;
  556. try {
  557. final TokenPayload tokenPayload = pwmApplication.getTokenService().createTokenPayload(
  558. TokenType.UPDATE_SMS,
  559. Collections.emptyMap(),
  560. pwmRequest.getUserInfoIfLoggedIn(),
  561. Collections.singleton(toNum)
  562. );
  563. tokenKey = pwmApplication.getTokenService().generateNewToken(tokenPayload,
  564. pwmRequest.getSessionLabel());
  565. } catch (PwmOperationalException e) {
  566. throw new PwmUnrecoverableException(e.getErrorInformation());
  567. }
  568. final String message = config.readSettingAsLocalizedString(PwmSetting.SMS_UPDATE_PROFILE_TOKEN_TEXT,
  569. pwmSession.getSessionStateBean().getLocale());
  570. try {
  571. TokenService.TokenSender.sendSmsToken(pwmApplication, null, macroMachine, toNum, message, tokenKey);
  572. } catch (Exception e) {
  573. throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_UNKNOWN));
  574. }
  575. updateProfileBean.getTokenVerificationProgress().getIssuedTokens().add(TokenVerificationProgress.TokenChannel.SMS);
  576. updateProfileBean.getTokenVerificationProgress().setTokenDisplayText(toNum);
  577. updateProfileBean.getTokenVerificationProgress().setPhase(TokenVerificationProgress.TokenChannel.SMS);
  578. }
  579. break;
  580. case EMAIL: {
  581. final EmailItemBean configuredEmailSetting = config.readSettingAsEmail(
  582. PwmSetting.EMAIL_UPDATEPROFILE_VERIFICATION,
  583. pwmRequest.getLocale()
  584. );
  585. final String emailAddressAttribute = ldapProfile.readSettingAsString(PwmSetting.EMAIL_USER_MAIL_ATTRIBUTE);
  586. final String toAddress = updateProfileBean.getFormData().get(emailAddressAttribute);
  587. final String tokenKey;
  588. try {
  589. final TokenPayload tokenPayload = pwmApplication.getTokenService().createTokenPayload(
  590. TokenType.UPDATE_EMAIL,
  591. Collections.<String,String>emptyMap(),
  592. pwmRequest.getUserInfoIfLoggedIn(),
  593. Collections.singleton(toAddress)
  594. );
  595. tokenKey = pwmApplication.getTokenService().generateNewToken(tokenPayload,
  596. pwmRequest.getSessionLabel());
  597. } catch (PwmOperationalException e) {
  598. throw new PwmUnrecoverableException(e.getErrorInformation());
  599. }
  600. updateProfileBean.getTokenVerificationProgress().getIssuedTokens().add(TokenVerificationProgress.TokenChannel.EMAIL);
  601. updateProfileBean.getTokenVerificationProgress().setPhase(TokenVerificationProgress.TokenChannel.EMAIL);
  602. updateProfileBean.getTokenVerificationProgress().setTokenDisplayText(toAddress);
  603. final EmailItemBean emailItemBean = new EmailItemBean(
  604. toAddress,
  605. configuredEmailSetting.getFrom(),
  606. configuredEmailSetting.getSubject(),
  607. configuredEmailSetting.getBodyPlain().replace("%TOKEN%", tokenKey),
  608. configuredEmailSetting.getBodyHtml().replace("%TOKEN%", tokenKey));
  609. try {
  610. TokenService.TokenSender.sendEmailToken(pwmApplication, null, macroMachine, emailItemBean,
  611. toAddress, tokenKey);
  612. } catch (Exception e) {
  613. throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_UNKNOWN));
  614. }
  615. }
  616. break;
  617. default:
  618. LOGGER.error("Unimplemented token purpose: " + tokenType);
  619. updateProfileBean.getTokenVerificationProgress().setPhase(null);
  620. }
  621. }
  622. }