/*
* 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.ChaiFactory;
import com.novell.ldapchai.ChaiUser;
import com.novell.ldapchai.exception.ChaiOperationException;
import com.novell.ldapchai.exception.ChaiUnavailableException;
import com.novell.ldapchai.exception.ImpossiblePasswordPolicyException;
import password.pwm.PwmApplication;
import password.pwm.PwmConstants;
import password.pwm.bean.EmailItemBean;
import password.pwm.bean.LocalSessionStateBean;
import password.pwm.bean.SmsItemBean;
import password.pwm.bean.UserIdentity;
import password.pwm.bean.UserInfoBean;
import password.pwm.config.ActionConfiguration;
import password.pwm.config.Configuration;
import password.pwm.config.FormConfiguration;
import password.pwm.config.FormUtility;
import password.pwm.config.PwmSetting;
import password.pwm.config.UserPermission;
import password.pwm.config.option.MessageSendMethod;
import password.pwm.config.profile.LdapProfile;
import password.pwm.error.ErrorInformation;
import password.pwm.error.PwmDataValidationException;
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.PwmRequest;
import password.pwm.http.PwmSession;
import password.pwm.http.bean.ActivateUserBean;
import password.pwm.i18n.Message;
import password.pwm.ldap.LdapPermissionTester;
import password.pwm.ldap.LdapUserDataReader;
import password.pwm.ldap.search.SearchConfiguration;
import password.pwm.ldap.UserDataReader;
import password.pwm.ldap.search.UserSearchEngine;
import password.pwm.ldap.auth.AuthenticationType;
import password.pwm.ldap.auth.PwmAuthenticationSource;
import password.pwm.ldap.auth.SessionAuthenticator;
import password.pwm.svc.event.AuditEvent;
import password.pwm.svc.event.AuditRecord;
import password.pwm.svc.event.AuditRecordFactory;
import password.pwm.svc.stats.Statistic;
import password.pwm.svc.token.TokenPayload;
import password.pwm.svc.token.TokenService;
import password.pwm.svc.token.TokenType;
import password.pwm.util.CaptchaUtility;
import password.pwm.util.PostChangePasswordAction;
import password.pwm.util.java.JavaHelper;
import password.pwm.util.logging.PwmLogger;
import password.pwm.util.macro.MacroMachine;
import password.pwm.util.operations.ActionExecutor;
import password.pwm.util.operations.PasswordUtility;
import password.pwm.ws.client.rest.RestTokenDataClient;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
import java.time.Instant;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
/**
* User interaction servlet for creating new users (self registration)
*
* @author Jason D. Rivard
*/
@WebServlet(
name="ActivateUserServlet",
urlPatterns = {
PwmConstants.URL_PREFIX_PUBLIC + "/activate",
PwmConstants.URL_PREFIX_PUBLIC + "/activate/*",
PwmConstants.URL_PREFIX_PUBLIC + "/ActivateUser",
PwmConstants.URL_PREFIX_PUBLIC + "/ActivateUser/*",
}
)
public class ActivateUserServlet extends AbstractPwmServlet {
// ------------------------------ FIELDS ------------------------------
private static final PwmLogger LOGGER = PwmLogger.forClass(ActivateUserServlet.class);
public enum ActivateUserAction implements AbstractPwmServlet.ProcessAction {
activate(HttpMethod.POST),
enterCode(HttpMethod.POST, HttpMethod.GET),
reset(HttpMethod.POST),
agree(HttpMethod.POST),
;
private final Collection<HttpMethod> method;
ActivateUserAction(final HttpMethod... method)
{
this.method = Collections.unmodifiableList(Arrays.asList(method));
}
public Collection<HttpMethod> permittedMethods()
{
return method;
}
}
protected ActivateUserAction readProcessAction(final PwmRequest request)
throws PwmUnrecoverableException
{
try {
return ActivateUserAction.valueOf(request.readParameterAsString(PwmConstants.PARAM_ACTION_REQUEST));
} catch (IllegalArgumentException e) {
return null;
}
}
protected void processAction(final PwmRequest pwmRequest)
throws ServletException, ChaiUnavailableException, IOException, PwmUnrecoverableException
{
//Fetch the session state bean.
final PwmSession pwmSession = pwmRequest.getPwmSession();
final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
final Configuration config = pwmApplication.getConfig();
final ActivateUserBean activateUserBean = pwmApplication.getSessionStateService().getBean(pwmRequest, ActivateUserBean.class);
if (!config.readSettingAsBoolean(PwmSetting.ACTIVATE_USER_ENABLE)) {
final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_SERVICE_NOT_AVAILABLE,"activate user is not enabled");
pwmRequest.respondWithError(errorInformation);
return;
}
if (pwmSession.isAuthenticated()) {
final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_USERAUTHENTICATED);
pwmRequest.respondWithError(errorInformation);
return;
}
final ActivateUserAction action = readProcessAction(pwmRequest);
// convert a url command like /pwm/public/NewUserServlet/12321321 to redirect with a process action.
if (action == null) {
if (pwmRequest.convertURLtokenCommand()) {
return;
}
} else {
switch (action) {
case activate:
handleActivationRequest(pwmRequest);
break;
case enterCode:
handleEnterTokenCode(pwmRequest);
break;
case reset:
pwmApplication.getSessionStateService().clearBean(pwmRequest, ActivateUserBean.class);
forwardToActivateUserForm(pwmRequest);
return;
case agree:
handleAgreeRequest(pwmRequest, activateUserBean);
advanceToNextStage(pwmRequest);
break;
default:
JavaHelper.unhandledSwitchStatement(action);
}
}
if (!pwmRequest.getPwmResponse().isCommitted()) {
this.advanceToNextStage(pwmRequest);
}
}
public void handleActivationRequest(final PwmRequest pwmRequest)
throws PwmUnrecoverableException, ChaiUnavailableException, IOException, ServletException
{
final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
final PwmSession pwmSession = pwmRequest.getPwmSession();
final Configuration config = pwmApplication.getConfig();
final LocalSessionStateBean ssBean = pwmSession.getSessionStateBean();
if (!CaptchaUtility.verifyReCaptcha(pwmRequest)) {
final ErrorInformation errorInfo = new ErrorInformation(PwmError.ERROR_BAD_CAPTCHA_RESPONSE);
LOGGER.debug(pwmRequest, errorInfo);
setLastError(pwmRequest, errorInfo);
return;
}
pwmApplication.getSessionStateService().clearBean(pwmRequest, ActivateUserBean.class);
final List<FormConfiguration> configuredActivationForm = config.readSettingAsForm(PwmSetting.ACTIVATE_USER_FORM);
Map<FormConfiguration,String> formValues = new HashMap<>();
try {
//read the values from the request
formValues = FormUtility.readFormValuesFromRequest(pwmRequest, configuredActivationForm,
ssBean.getLocale());
// check for intruders
pwmApplication.getIntruderManager().convenience().checkAttributes(formValues);
// read the context attr
final String contextParam = pwmRequest.readParameterAsString(PwmConstants.PARAM_CONTEXT);
// read the profile attr
final String ldapProfile = pwmRequest.readParameterAsString(PwmConstants.PARAM_LDAP_PROFILE);
// see if the values meet the configured form requirements.
FormUtility.validateFormValues(config, formValues, ssBean.getLocale());
final String searchFilter = figureLdapSearchFilter(pwmRequest);
// read an ldap user object based on the params
final UserIdentity userIdentity;
{
final UserSearchEngine userSearchEngine = pwmApplication.getUserSearchEngine();
final SearchConfiguration searchConfiguration = SearchConfiguration.builder()
.contexts(Collections.singletonList(contextParam))
.filter(searchFilter)
.formValues(formValues)
.ldapProfile(ldapProfile)
.build();
userIdentity = userSearchEngine.performSingleUserSearch(searchConfiguration, pwmRequest.getSessionLabel());
}
validateParamsAgainstLDAP(pwmRequest, formValues, userIdentity);
final List<UserPermission> userPermissions = config.readSettingAsUserPermission(PwmSetting.ACTIVATE_USER_QUERY_MATCH);
if (!LdapPermissionTester.testUserPermissions(pwmApplication, pwmSession.getLabel(), userIdentity, userPermissions)) {
final String errorMsg = "user " + userIdentity + " attempted activation, but does not match query string";
final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_ACTIVATE_NO_PERMISSION, errorMsg);
pwmApplication.getIntruderManager().convenience().markUserIdentity(userIdentity, pwmSession);
pwmApplication.getIntruderManager().convenience().markAddressAndSession(pwmSession);
throw new PwmUnrecoverableException(errorInformation);
}
final ActivateUserBean activateUserBean = pwmApplication.getSessionStateService().getBean(pwmRequest, ActivateUserBean.class);
activateUserBean.setUserIdentity(userIdentity);
activateUserBean.setFormValidated(true);
pwmApplication.getIntruderManager().convenience().clearAttributes(formValues);
pwmApplication.getIntruderManager().convenience().clearAddressAndSession(pwmSession);
} catch (PwmOperationalException e) {
pwmApplication.getIntruderManager().convenience().markAttributes(formValues, pwmSession);
pwmApplication.getIntruderManager().convenience().markAddressAndSession(pwmSession);
setLastError(pwmRequest, e.getErrorInformation());
LOGGER.debug(pwmSession.getLabel(),e.getErrorInformation().toDebugStr());
}
// redirect user to change password screen.
advanceToNextStage(pwmRequest);
}
private void handleAgreeRequest(
final PwmRequest pwmRequest,
final ActivateUserBean activateUserBean
)
throws ServletException, IOException, PwmUnrecoverableException, ChaiUnavailableException
{
LOGGER.debug(pwmRequest, "user accepted agreement");
if (!activateUserBean.isAgreementPassed()) {
activateUserBean.setAgreementPassed(true);
final AuditRecord auditRecord = new AuditRecordFactory(pwmRequest).createUserAuditRecord(
AuditEvent.AGREEMENT_PASSED,
pwmRequest.getUserInfoIfLoggedIn(),
pwmRequest.getSessionLabel(),
"ActivateUser"
);
pwmRequest.getPwmApplication().getAuditManager().submit(auditRecord);
}
}
private void advanceToNextStage(final PwmRequest pwmRequest)
throws PwmUnrecoverableException, IOException, ServletException, ChaiUnavailableException
{
final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
final PwmSession pwmSession = pwmRequest.getPwmSession();
final Configuration config = pwmApplication.getConfig();
final ActivateUserBean activateUserBean = pwmApplication.getSessionStateService().getBean(pwmRequest, ActivateUserBean.class);
if (!activateUserBean.isFormValidated() || activateUserBean.getUserIdentity() == null) {
forwardToActivateUserForm(pwmRequest);
return;
}
final boolean tokenRequired = MessageSendMethod.NONE != MessageSendMethod.valueOf(config.readSettingAsString(PwmSetting.ACTIVATE_TOKEN_SEND_METHOD));
if (tokenRequired) {
if (!activateUserBean.isTokenIssued()) {
try {
final Locale locale = pwmSession.getSessionStateBean().getLocale();
initializeToken(pwmRequest, locale, activateUserBean.getUserIdentity());
} catch (PwmOperationalException e) {
setLastError(pwmRequest, e.getErrorInformation());
forwardToActivateUserForm(pwmRequest);
return;
}
}
if (!activateUserBean.isTokenPassed()) {
pwmRequest.forwardToJsp(JspUrl.ACTIVATE_USER_ENTER_CODE);
return;
}
}
final String agreementText = config.readSettingAsLocalizedString(
PwmSetting.ACTIVATE_AGREEMENT_MESSAGE,
pwmSession.getSessionStateBean().getLocale()
);
if (agreementText != null && agreementText.length() > 0 && !activateUserBean.isAgreementPassed()) {
if (activateUserBean.getAgreementText() == null) {
final MacroMachine macroMachine = MacroMachine.forUser(pwmRequest, activateUserBean.getUserIdentity());
final String expandedText = macroMachine.expandMacros(agreementText);
activateUserBean.setAgreementText(expandedText);
}
pwmRequest.forwardToJsp(JspUrl.ACTIVATE_USER_AGREEMENT);
return;
}
try {
activateUser(pwmRequest, activateUserBean.getUserIdentity());
pwmRequest.getPwmResponse().forwardToSuccessPage(Message.Success_ActivateUser);
} catch (PwmOperationalException e) {
LOGGER.debug(pwmRequest, e.getErrorInformation());
pwmApplication.getIntruderManager().convenience().markUserIdentity(activateUserBean.getUserIdentity(),pwmSession);
pwmApplication.getIntruderManager().convenience().markAddressAndSession(pwmSession);
pwmRequest.respondWithError(e.getErrorInformation());
}
}
public void activateUser(
final PwmRequest pwmRequest,
final UserIdentity userIdentity
)
throws ChaiUnavailableException, PwmUnrecoverableException, PwmOperationalException
{
final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
final PwmSession pwmSession = pwmRequest.getPwmSession();
final Configuration config = pwmApplication.getConfig();
final ChaiUser theUser = pwmApplication.getProxiedChaiUser(userIdentity);
if (config.readSettingAsBoolean(PwmSetting.ACTIVATE_USER_UNLOCK)) {
try {
theUser.unlockPassword();
} catch (ChaiOperationException e) {
final String errorMsg = "error unlocking user " + userIdentity + ": " + e.getMessage();
final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_ACTIVATION_FAILURE, errorMsg);
throw new PwmOperationalException(errorInformation);
}
}
try {
{ // execute configured actions
LOGGER.debug(pwmSession.getLabel(), "executing configured pre-actions to user " + theUser.getEntryDN());
final List<ActionConfiguration> configValues = config.readSettingAsAction(PwmSetting.ACTIVATE_USER_PRE_WRITE_ATTRIBUTES);
if (configValues != null && !configValues.isEmpty()) {
final MacroMachine macroMachine = MacroMachine.forUser(pwmRequest, userIdentity);
final ActionExecutor actionExecutor = new ActionExecutor.ActionExecutorSettings(pwmApplication, userIdentity)
.setExpandPwmMacros(true)
.setMacroMachine(macroMachine)
.createActionExecutor();
actionExecutor.executeActions(configValues, pwmSession);
}
}
//authenticate the pwm session
final SessionAuthenticator sessionAuthenticator = new SessionAuthenticator(pwmApplication, pwmSession, PwmAuthenticationSource.USER_ACTIVATION);
sessionAuthenticator.authUserWithUnknownPassword(userIdentity,AuthenticationType.AUTH_FROM_PUBLIC_MODULE);
//ensure a change password is triggered
pwmSession.getLoginInfoBean().setType(AuthenticationType.AUTH_FROM_PUBLIC_MODULE);
pwmSession.getLoginInfoBean().getAuthFlags().add(AuthenticationType.AUTH_FROM_PUBLIC_MODULE);
pwmSession.getUserInfoBean().setRequiresNewPassword(true);
// mark the event log
pwmApplication.getAuditManager().submit(AuditEvent.ACTIVATE_USER, pwmSession.getUserInfoBean(), pwmSession);
// update the stats bean
pwmApplication.getStatisticsManager().incrementValue(Statistic.ACTIVATED_USERS);
// send email or sms
sendPostActivationNotice(pwmRequest);
// setup post-change attributes
final PostChangePasswordAction postAction = new PostChangePasswordAction() {
public String getLabel() {
return "ActivateUser write attributes";
}
public boolean doAction(final PwmSession pwmSession, final String newPassword)
throws PwmUnrecoverableException {
try {
{ // execute configured actions
LOGGER.debug(pwmSession.getLabel(), "executing post-activate configured actions to user " + userIdentity.toDisplayString());
final MacroMachine macroMachine = pwmSession.getSessionManager().getMacroMachine(pwmApplication);
final List<ActionConfiguration> configValues = pwmApplication.getConfig().readSettingAsAction(PwmSetting.ACTIVATE_USER_POST_WRITE_ATTRIBUTES);
final ActionExecutor actionExecutor = new ActionExecutor.ActionExecutorSettings(pwmApplication, userIdentity)
.setExpandPwmMacros(true)
.setMacroMachine(macroMachine)
.createActionExecutor();
actionExecutor.executeActions(configValues, pwmSession);
}
} catch (PwmOperationalException e) {
final ErrorInformation info = new ErrorInformation(PwmError.ERROR_ACTIVATION_FAILURE, e.getErrorInformation().getDetailedErrorMsg(), e.getErrorInformation().getFieldValues());
final PwmUnrecoverableException newException = new PwmUnrecoverableException(info);
newException.initCause(e);
throw newException;
} catch (ChaiUnavailableException e) {
final String errorMsg = "unable to reach ldap server while writing post-activate attributes: " + e.getMessage();
final ErrorInformation info = new ErrorInformation(PwmError.ERROR_ACTIVATION_FAILURE, errorMsg);
final PwmUnrecoverableException newException = new PwmUnrecoverableException(info);
newException.initCause(e);
throw newException;
}
return true;
}
};
pwmSession.getUserSessionDataCacheBean().addPostChangePasswordActions("activateUserWriteAttributes", postAction);
} catch (ImpossiblePasswordPolicyException e) {
final ErrorInformation info = new ErrorInformation(PwmError.ERROR_UNKNOWN, "unexpected ImpossiblePasswordPolicyException error while activating user");
LOGGER.warn(pwmSession, info, e);
throw new PwmOperationalException(info);
}
}
protected static void validateParamsAgainstLDAP(
final PwmRequest pwmRequest,
final Map<FormConfiguration, String> formValues,
final UserIdentity userIdentity
)
throws ChaiUnavailableException, PwmDataValidationException, PwmUnrecoverableException
{
final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
final PwmSession pwmSession = pwmRequest.getPwmSession();
final String searchFilter = figureLdapSearchFilter(pwmRequest);
final ChaiUser chaiUser = ChaiFactory.createChaiUser(userIdentity.getUserDN(), pwmApplication.getProxyChaiProvider(userIdentity.getLdapProfileID()));
for (final FormConfiguration formItem : formValues.keySet()) {
final String attrName = formItem.getName();
final String tokenizedAttrName = "%" + attrName + "%";
if (searchFilter.contains(tokenizedAttrName)) {
LOGGER.trace(pwmSession, "skipping validation of ldap value for '" + attrName + "' because it is in search filter");
} else {
final String value = formValues.get(formItem);
try {
if (!chaiUser.compareStringAttribute(attrName, value)) {
final String errorMsg = "incorrect value for '" + attrName + "'";
final ErrorInformation errorInfo = new ErrorInformation(PwmError.ERROR_ACTIVATION_VALIDATIONFAIL, errorMsg, new String[]{attrName});
LOGGER.debug(pwmSession.getLabel(), errorInfo.toDebugStr());
throw new PwmDataValidationException(errorInfo);
}
LOGGER.trace(pwmSession.getLabel(), "successful validation of ldap value for '" + attrName + "'");
} catch (ChaiOperationException e) {
LOGGER.error(pwmSession.getLabel(), "error during param validation of '" + attrName + "', error: " + e.getMessage());
throw new PwmDataValidationException(new ErrorInformation(PwmError.ERROR_ACTIVATION_VALIDATIONFAIL, "ldap error testing value for '" + attrName + "'", new String[]{attrName}));
}
}
}
}
private void sendPostActivationNotice(
final PwmRequest pwmRequest
)
throws PwmUnrecoverableException, ChaiUnavailableException
{
final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
final PwmSession pwmSession = pwmRequest.getPwmSession();
final Configuration config = pwmApplication.getConfig();
final UserInfoBean userInfoBean = pwmSession.getUserInfoBean();
final MessageSendMethod pref = MessageSendMethod.valueOf(config.readSettingAsString(PwmSetting.ACTIVATE_TOKEN_SEND_METHOD));
final boolean success;
switch (pref) {
case BOTH:
// Send both email and SMS, success if one of both succeeds
final boolean suc1 = sendPostActivationEmail(pwmRequest);
final boolean suc2 = sendPostActivationSms(pwmRequest);
success = suc1 || suc2;
break;
case EMAILFIRST:
// Send email first, try SMS if email is not available
success = sendPostActivationEmail(pwmRequest) || sendPostActivationSms(pwmRequest);
break;
case SMSFIRST:
// Send SMS first, try email if SMS is not available
success = sendPostActivationSms(pwmRequest) || sendPostActivationEmail(pwmRequest);
break;
case SMSONLY:
// Only try SMS
success = sendPostActivationSms(pwmRequest);
break;
case EMAILONLY:
default:
// Only try email
success = sendPostActivationEmail(pwmRequest);
break;
}
if (!success) {
LOGGER.warn(pwmSession, "skipping send activation message for '" + userInfoBean.getUserIdentity() + "' no email or SMS number configured");
}
}
private boolean sendPostActivationEmail(
final PwmRequest pwmRequest
)
throws PwmUnrecoverableException, ChaiUnavailableException
{
final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
final PwmSession pwmSession = pwmRequest.getPwmSession();
final UserInfoBean userInfoBean = pwmSession.getUserInfoBean();
final Configuration config = pwmApplication.getConfig();
final Locale locale = pwmSession.getSessionStateBean().getLocale();
final EmailItemBean configuredEmailSetting = config.readSettingAsEmail(PwmSetting.EMAIL_ACTIVATION, locale);
if (configuredEmailSetting == null) {
LOGGER.debug(pwmSession, "skipping send activation email for '" + userInfoBean.getUserIdentity() + "' no email configured");
return false;
}
pwmApplication.getEmailQueue().submitEmail(
configuredEmailSetting,
pwmSession.getUserInfoBean(),
pwmSession.getSessionManager().getMacroMachine(pwmApplication)
);
return true;
}
private Boolean sendPostActivationSms(final PwmRequest pwmRequest)
throws PwmUnrecoverableException, ChaiUnavailableException
{
final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
final PwmSession pwmSession = pwmRequest.getPwmSession();
final Configuration config = pwmApplication.getConfig();
final UserInfoBean userInfoBean = pwmSession.getUserInfoBean();
final UserDataReader userDataReader = pwmSession.getSessionManager().getUserDataReader(pwmApplication);
final Locale locale = pwmSession.getSessionStateBean().getLocale();
final LdapProfile ldapProfile = userInfoBean.getUserIdentity().getLdapProfile(config);
final String message = config.readSettingAsLocalizedString(PwmSetting.SMS_ACTIVATION_TEXT, locale);
final String toSmsNumber;
try {
toSmsNumber = userDataReader.readStringAttribute(ldapProfile.readSettingAsString(PwmSetting.SMS_USER_PHONE_ATTRIBUTE));
} catch (Exception e) {
LOGGER.debug(pwmSession.getLabel(), "error reading SMS attribute from user '" + pwmSession.getUserInfoBean().getUserIdentity() + "': " + e.getMessage());
return false;
}
if (toSmsNumber == null || toSmsNumber.length() < 1) {
LOGGER.debug(pwmSession.getLabel(), "skipping send activation SMS for '" + pwmSession.getUserInfoBean().getUserIdentity() + "' no SMS number configured");
return false;
}
final SmsItemBean smsItem = new SmsItemBean(toSmsNumber, message);
pwmApplication.sendSmsUsingQueue(smsItem, pwmSession.getSessionManager().getMacroMachine(pwmApplication));
return true;
}
public static void initializeToken(
final PwmRequest pwmRequest,
final Locale locale,
final UserIdentity userIdentity
)
throws PwmUnrecoverableException, PwmOperationalException, ChaiUnavailableException
{
final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
final PwmSession pwmSession = pwmRequest.getPwmSession();
final ActivateUserBean activateUserBean = pwmApplication.getSessionStateService().getBean(pwmRequest, ActivateUserBean.class);
final Configuration config = pwmApplication.getConfig();
final RestTokenDataClient.TokenDestinationData inputTokenDestData;
{
final UserDataReader dataReader = LdapUserDataReader.appProxiedReader(pwmApplication, userIdentity);
final String toAddress;
{
final EmailItemBean emailItemBean = config.readSettingAsEmail(PwmSetting.EMAIL_ACTIVATION_VERIFICATION, locale);
final MacroMachine macroMachine = MacroMachine.forUser(pwmRequest, userIdentity);
toAddress = macroMachine.expandMacros(emailItemBean.getTo());
}
final String toSmsNumber;
try {
final LdapProfile ldapProfile = userIdentity.getLdapProfile(config);
toSmsNumber = dataReader.readStringAttribute(ldapProfile.readSettingAsString(PwmSetting.SMS_USER_PHONE_ATTRIBUTE));
} catch (Exception e) {
final String errorMsg = "unable to read user SMS attribute due to ldap error, unable to send token: " + e.getMessage();
final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_ACTIVATION_FAILURE, errorMsg);
LOGGER.error(pwmSession.getLabel(), errorInformation);
throw new PwmOperationalException(errorInformation);
}
inputTokenDestData = new RestTokenDataClient.TokenDestinationData(toAddress,toSmsNumber,null);
}
final RestTokenDataClient restTokenDataClient = new RestTokenDataClient(pwmApplication);
final RestTokenDataClient.TokenDestinationData outputDestTokenData = restTokenDataClient.figureDestTokenDisplayString(
pwmSession.getLabel(),
inputTokenDestData,
activateUserBean.getUserIdentity(),
pwmSession.getSessionStateBean().getLocale());
final Set<String> destinationValues = new HashSet<>();
if (outputDestTokenData.getEmail() != null) {
destinationValues.add(outputDestTokenData.getEmail());
}
if (outputDestTokenData.getSms() != null) {
destinationValues.add(outputDestTokenData.getSms());
}
final Map<String,String> tokenMapData = new HashMap<>();
try {
final Instant userLastPasswordChange = PasswordUtility.determinePwdLastModified(
pwmApplication,
pwmSession.getLabel(),
activateUserBean.getUserIdentity());
if (userLastPasswordChange != null) {
tokenMapData.put(PwmConstants.TOKEN_KEY_PWD_CHG_DATE, JavaHelper.toIsoDate(userLastPasswordChange));
}
} catch (ChaiUnavailableException e) {
LOGGER.error(pwmSession.getLabel(), "unexpected error reading user's last password change time");
}
final String tokenKey;
final TokenPayload tokenPayload;
try {
tokenPayload = pwmApplication.getTokenService().createTokenPayload(TokenType.ACTIVATION, tokenMapData, userIdentity, destinationValues);
tokenKey = pwmApplication.getTokenService().generateNewToken(tokenPayload, pwmRequest.getSessionLabel());
} catch (PwmOperationalException e) {
throw new PwmUnrecoverableException(e.getErrorInformation());
}
sendToken(pwmRequest, userIdentity, locale, outputDestTokenData.getEmail(), outputDestTokenData.getSms(), tokenKey);
activateUserBean.setTokenDisplayText(outputDestTokenData.getDisplayValue());
activateUserBean.setTokenIssued(true);
}
private void handleEnterTokenCode(
final PwmRequest pwmRequest
)
throws ChaiUnavailableException, PwmUnrecoverableException, IOException, ServletException
{
final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
final PwmSession pwmSession = pwmRequest.getPwmSession();
final ActivateUserBean activateUserBean = pwmApplication.getSessionStateService().getBean(pwmRequest, ActivateUserBean.class);
final String userEnteredCode = pwmRequest.readParameterAsString(PwmConstants.PARAM_TOKEN);
ErrorInformation errorInformation = null;
try {
final TokenPayload tokenPayload = pwmApplication.getTokenService().processUserEnteredCode(
pwmSession,
activateUserBean.getUserIdentity(),
TokenType.ACTIVATION,
userEnteredCode
);
if (tokenPayload != null) {
activateUserBean.setUserIdentity(tokenPayload.getUserIdentity());
activateUserBean.setTokenPassed(true);
activateUserBean.setFormValidated(true);
}
} catch (PwmOperationalException e) {
final String errorMsg = "token incorrect: " + e.getMessage();
errorInformation = new ErrorInformation(PwmError.ERROR_TOKEN_INCORRECT,errorMsg);
}
if (!activateUserBean.isTokenPassed()) {
if (errorInformation == null) {
errorInformation = new ErrorInformation(PwmError.ERROR_TOKEN_INCORRECT);
}
LOGGER.debug(pwmSession.getLabel(), errorInformation.toDebugStr());
setLastError(pwmRequest, errorInformation);
}
this.advanceToNextStage(pwmRequest);
}
private static void sendToken(
final PwmRequest pwmRequest,
final UserIdentity userIdentity,
final Locale userLocale,
final String toAddress,
final String toSmsNumber,
final String tokenKey
)
throws PwmUnrecoverableException, ChaiUnavailableException
{
final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
final Configuration config = pwmApplication.getConfig();
final MessageSendMethod pref = MessageSendMethod.valueOf(config.readSettingAsString(PwmSetting.ACTIVATE_TOKEN_SEND_METHOD));
final EmailItemBean emailItemBean = config.readSettingAsEmail(PwmSetting.EMAIL_ACTIVATION_VERIFICATION, userLocale);
final String smsMessage = config.readSettingAsLocalizedString(PwmSetting.SMS_ACTIVATION_VERIFICATION_TEXT, userLocale);
final MacroMachine macroMachine = MacroMachine.forUser(pwmRequest, userIdentity);
TokenService.TokenSender.sendToken(
pwmApplication,
null,
macroMachine,
emailItemBean,
pref,
toAddress,
toSmsNumber,
smsMessage,
tokenKey
);
}
private static String figureLdapSearchFilter(final PwmRequest pwmRequest)
throws PwmUnrecoverableException
{
final PwmApplication pwmApplication = pwmRequest.getPwmApplication();
final Configuration config = pwmApplication.getConfig();
final List<FormConfiguration> configuredActivationForm = config.readSettingAsForm(PwmSetting.ACTIVATE_USER_FORM);
final String configuredSearchFilter = config.readSettingAsString(PwmSetting.ACTIVATE_USER_SEARCH_FILTER);
final String searchFilter;
if (configuredSearchFilter == null || configuredSearchFilter.isEmpty()) {
searchFilter = FormUtility.ldapSearchFilterForForm(pwmApplication,configuredActivationForm);
LOGGER.trace(pwmRequest,"auto generated search filter based on activation form: " + searchFilter);
} else {
searchFilter = configuredSearchFilter;
}
return searchFilter;
}
private static void forwardToActivateUserForm(final PwmRequest pwmRequest)
throws ServletException, PwmUnrecoverableException, IOException
{
pwmRequest.addFormInfoToRequestAttr(PwmSetting.ACTIVATE_USER_FORM,false,false);
pwmRequest.forwardToJsp(JspUrl.ACTIVATE_USER);
}
}