Example #1
0
  private static ErrorInformation sendNewPasswordEmail(
      final UserInfoBean userInfoBean,
      final PwmApplication pwmApplication,
      final MacroMachine macroMachine,
      final PasswordData newPassword,
      final String toAddress,
      final Locale userLocale)
      throws PwmOperationalException, PwmUnrecoverableException {
    final Configuration config = pwmApplication.getConfig();
    final EmailItemBean configuredEmailSetting =
        config.readSettingAsEmail(PwmSetting.EMAIL_SENDPASSWORD, userLocale);

    if (configuredEmailSetting == null) {
      final String errorMsg = "send password email contents are not configured";
      return new ErrorInformation(PwmError.ERROR_UNKNOWN, errorMsg);
    }

    final EmailItemBean emailItemBean =
        new EmailItemBean(
            configuredEmailSetting.getTo(),
            configuredEmailSetting.getFrom(),
            configuredEmailSetting.getSubject(),
            configuredEmailSetting.getBodyPlain().replace("%TOKEN%", newPassword.getStringValue()),
            configuredEmailSetting.getBodyHtml().replace("%TOKEN%", newPassword.getStringValue()));
    pwmApplication.getEmailQueue().submitEmail(emailItemBean, userInfoBean, macroMachine);

    LOGGER.debug(
        "new password email to "
            + userInfoBean.getUserIdentity()
            + " added to send queue for "
            + toAddress);
    return null;
  }
Example #2
0
  private static ErrorInformation sendNewPasswordSms(
      final UserInfoBean userInfoBean,
      final PwmApplication pwmApplication,
      final MacroMachine macroMachine,
      final PasswordData newPassword,
      final String toNumber,
      final Locale userLocale)
      throws PwmOperationalException, PwmUnrecoverableException {
    final Configuration config = pwmApplication.getConfig();
    String message =
        config.readSettingAsLocalizedString(PwmSetting.SMS_CHALLENGE_NEW_PASSWORD_TEXT, userLocale);

    if (toNumber == null || toNumber.length() < 1) {
      final String errorMsg =
          String.format(
              "unable to send new password email for '%s'; no SMS number available in ldap",
              userInfoBean.getUserIdentity());
      return new ErrorInformation(PwmError.ERROR_UNKNOWN, errorMsg);
    }

    message = message.replace("%TOKEN%", newPassword.getStringValue());

    pwmApplication.sendSmsUsingQueue(new SmsItemBean(toNumber, message), macroMachine);
    LOGGER.debug(String.format("password SMS added to send queue for %s", toNumber));
    return null;
  }
Example #3
0
  private static void sendChangePasswordHelpdeskEmailNotice(
      final PwmSession pwmSession,
      final PwmApplication pwmApplication,
      final UserInfoBean userInfoBean)
      throws PwmUnrecoverableException {
    final Configuration config = pwmApplication.getConfig();
    final Locale locale = pwmSession.getSessionStateBean().getLocale();
    final EmailItemBean configuredEmailSetting =
        config.readSettingAsEmail(PwmSetting.EMAIL_CHANGEPASSWORD_HELPDESK, locale);

    if (configuredEmailSetting == null) {
      LOGGER.debug(
          pwmSession,
          "skipping send change password email for '"
              + pwmSession.getUserInfoBean().getUserIdentity()
              + "' no email configured");
      return;
    }

    final MacroMachine macroMachine =
        userInfoBean == null
            ? null
            : new MacroMachine(
                pwmApplication,
                pwmSession.getLabel(),
                userInfoBean,
                null,
                LdapUserDataReader.appProxiedReader(
                    pwmApplication, userInfoBean.getUserIdentity()));

    pwmApplication.getEmailQueue().submitEmail(configuredEmailSetting, userInfoBean, macroMachine);
  }
Example #4
0
  public static PasswordCheckInfo checkEnteredPassword(
      final PwmApplication pwmApplication,
      final Locale locale,
      final ChaiUser user,
      final UserInfoBean userInfoBean,
      final LoginInfoBean loginInfoBean,
      final PasswordData password,
      final PasswordData confirmPassword)
      throws PwmUnrecoverableException, ChaiUnavailableException {
    if (userInfoBean == null) {
      throw new NullPointerException("userInfoBean cannot be null");
    }

    boolean pass = false;
    String userMessage = "";
    int errorCode = 0;

    final boolean passwordIsCaseSensitive =
        userInfoBean.getPasswordPolicy() == null
            || userInfoBean
                .getPasswordPolicy()
                .getRuleHelper()
                .readBooleanValue(PwmPasswordRule.CaseSensitive);
    final CachePolicy cachePolicy;
    {
      final long cacheLifetimeMS =
          Long.parseLong(
              pwmApplication
                  .getConfig()
                  .readAppProperty(AppProperty.CACHE_PWRULECHECK_LIFETIME_MS));
      cachePolicy = CachePolicy.makePolicyWithExpirationMS(cacheLifetimeMS);
    }

    if (password == null) {
      userMessage =
          new ErrorInformation(PwmError.PASSWORD_MISSING)
              .toUserStr(locale, pwmApplication.getConfig());
    } else {
      final CacheService cacheService = pwmApplication.getCacheService();
      final CacheKey cacheKey =
          user != null && userInfoBean.getUserIdentity() != null
              ? CacheKey.makeCacheKey(
                  PasswordUtility.class,
                  userInfoBean.getUserIdentity(),
                  user.getEntryDN() + ":" + password.hash())
              : null;
      if (pwmApplication.getConfig().isDevDebugMode()) {
        LOGGER.trace("generated cacheKey for password check request: " + cacheKey);
      }
      try {
        if (cacheService != null && cacheKey != null) {
          final String cachedValue = cacheService.get(cacheKey);
          if (cachedValue != null) {
            if (NEGATIVE_CACHE_HIT.equals(cachedValue)) {
              pass = true;
            } else {
              LOGGER.trace("cache hit!");
              final ErrorInformation errorInformation =
                  JsonUtil.deserialize(cachedValue, ErrorInformation.class);
              throw new PwmDataValidationException(errorInformation);
            }
          }
        }
        if (!pass) {
          final PwmPasswordRuleValidator pwmPasswordRuleValidator =
              new PwmPasswordRuleValidator(
                  pwmApplication, userInfoBean.getPasswordPolicy(), locale);
          final PasswordData oldPassword =
              loginInfoBean == null ? null : loginInfoBean.getUserCurrentPassword();
          pwmPasswordRuleValidator.testPassword(password, oldPassword, userInfoBean, user);
          pass = true;
          if (cacheService != null && cacheKey != null) {
            cacheService.put(cacheKey, cachePolicy, NEGATIVE_CACHE_HIT);
          }
        }
      } catch (PwmDataValidationException e) {
        errorCode = e.getError().getErrorCode();
        userMessage = e.getErrorInformation().toUserStr(locale, pwmApplication.getConfig());
        pass = false;
        if (cacheService != null && cacheKey != null) {
          final String jsonPayload = JsonUtil.serialize(e.getErrorInformation());
          cacheService.put(cacheKey, cachePolicy, jsonPayload);
        }
      }
    }

    final PasswordCheckInfo.MATCH_STATUS matchStatus =
        figureMatchStatus(passwordIsCaseSensitive, password, confirmPassword);
    if (pass) {
      switch (matchStatus) {
        case EMPTY:
          userMessage =
              new ErrorInformation(PwmError.PASSWORD_MISSING_CONFIRM)
                  .toUserStr(locale, pwmApplication.getConfig());
          break;
        case MATCH:
          userMessage =
              new ErrorInformation(PwmError.PASSWORD_MEETS_RULES)
                  .toUserStr(locale, pwmApplication.getConfig());
          break;
        case NO_MATCH:
          userMessage =
              new ErrorInformation(PwmError.PASSWORD_DOESNOTMATCH)
                  .toUserStr(locale, pwmApplication.getConfig());
          break;
        default:
          userMessage = "";
      }
    }

    final int strength = judgePasswordStrength(password == null ? null : password.getStringValue());
    return new PasswordCheckInfo(userMessage, pass, strength, matchStatus, errorCode);
  }
Example #5
0
  /**
   * This is the entry point under which all password changes are managed. The following is the
   * general procedure when this method is invoked.
   *
   * <ul>
   *   <li>password is checked against PWM password requirement
   *   <li>ldap password set is attempted<br>
   *       <br>
   *       if successful:
   *       <ul>
   *         <li>uiBean is updated with old and new passwords
   *         <li>uiBean's password expire flag is set to false
   *         <li>any configured external methods are invoked
   *         <li>user email notification is sent
   *         <li>return true
   *       </ul>
   *       <br>
   *       if unsuccessful
   *       <ul>
   *         <li>ssBean is updated with appropriate error
   *         <li>return false
   *       </ul>
   * </ul>
   *
   * @param newPassword the new password that is being set.
   * @param pwmSession beanmanager for config and user info lookup
   * @throws com.novell.ldapchai.exception.ChaiUnavailableException if the ldap directory is not
   *     unavailable
   * @throws password.pwm.error.PwmUnrecoverableException if user is not authenticated
   */
  public static void setActorPassword(
      final PwmSession pwmSession,
      final PwmApplication pwmApplication,
      final PasswordData newPassword)
      throws ChaiUnavailableException, PwmUnrecoverableException, PwmOperationalException {
    final UserInfoBean uiBean = pwmSession.getUserInfoBean();

    if (!pwmSession
        .getSessionManager()
        .checkPermission(pwmApplication, Permission.CHANGE_PASSWORD)) {
      final String errorMsg =
          "attempt to setActorPassword, but user does not have password change permission";
      final ErrorInformation errorInformation =
          new ErrorInformation(PwmError.ERROR_UNAUTHORIZED, errorMsg);
      throw new PwmOperationalException(errorInformation);
    }

    // double check to make sure password meets PWM rule requirements.  This should
    // have been done before setActorPassword() is invoked, so it should be redundant
    // but we do it just in case.
    try {
      final PwmPasswordRuleValidator pwmPasswordRuleValidator =
          new PwmPasswordRuleValidator(pwmApplication, uiBean.getPasswordPolicy());
      pwmPasswordRuleValidator.testPassword(
          newPassword, null, uiBean, pwmSession.getSessionManager().getActor(pwmApplication));
    } catch (PwmDataValidationException e) {
      final String errorMsg =
          "attempt to setActorPassword, but password does not pass local policy validator";
      final ErrorInformation errorInformation =
          new ErrorInformation(e.getErrorInformation().getError(), errorMsg);
      throw new PwmOperationalException(errorInformation);
    }

    // retrieve the user's old password from the userInfoBean in the session
    final PasswordData oldPassword = pwmSession.getLoginInfoBean().getUserCurrentPassword();

    boolean setPasswordWithoutOld = false;
    if (oldPassword == null) {
      if (pwmSession
              .getSessionManager()
              .getActor(pwmApplication)
              .getChaiProvider()
              .getDirectoryVendor()
          == ChaiProvider.DIRECTORY_VENDOR.MICROSOFT_ACTIVE_DIRECTORY) {
        setPasswordWithoutOld = true;
      }
    }

    if (!setPasswordWithoutOld) {
      // Check to make sure we actually have an old password
      if (oldPassword == null) {
        final String errorMsg = "cannot set password for user, old password is not available";
        final ErrorInformation errorInformation =
            new ErrorInformation(PwmError.ERROR_WRONGPASSWORD, errorMsg);
        throw new PwmOperationalException(errorInformation);
      }
    }

    try {
      final ChaiProvider provider = pwmSession.getSessionManager().getChaiProvider();
      final ChaiUser theUser =
          ChaiFactory.createChaiUser(
              pwmSession.getUserInfoBean().getUserIdentity().getUserDN(), provider);
      final boolean boundAsSelf =
          theUser
              .getEntryDN()
              .equals(provider.getChaiConfiguration().getSetting(ChaiSetting.BIND_DN));
      LOGGER.trace(
          pwmSession,
          "preparing to setActorPassword for '"
              + theUser.getEntryDN()
              + "', bindAsSelf="
              + boundAsSelf
              + ", authType="
              + pwmSession.getLoginInfoBean().getType());
      if (setPasswordWithoutOld) {
        theUser.setPassword(newPassword.getStringValue(), true);
      } else {
        theUser.changePassword(oldPassword.getStringValue(), newPassword.getStringValue());
      }
    } catch (ChaiPasswordPolicyException e) {
      final String errorMsg =
          "error setting password for user '" + uiBean.getUserIdentity() + "'' " + e.toString();
      final PwmError pwmError = PwmError.forChaiError(e.getErrorCode());
      final ErrorInformation error =
          new ErrorInformation(
              pwmError == null ? PwmError.PASSWORD_UNKNOWN_VALIDATION : pwmError, errorMsg);
      throw new PwmOperationalException(error);
    } catch (ChaiOperationException e) {
      final String errorMsg =
          "error setting password for user '" + uiBean.getUserIdentity() + "'' " + e.getMessage();
      final PwmError pwmError =
          PwmError.forChaiError(e.getErrorCode()) == null
              ? PwmError.ERROR_UNKNOWN
              : PwmError.forChaiError(e.getErrorCode());
      final ErrorInformation error = new ErrorInformation(pwmError, errorMsg);
      throw new PwmOperationalException(error);
    }

    // at this point the password has been changed, so log it.
    LOGGER.info(
        pwmSession, "user '" + uiBean.getUserIdentity() + "' successfully changed password");

    // update the session state bean's password modified flag
    pwmSession.getSessionStateBean().setPasswordModified(true);

    // update the login info bean with the user's new password
    pwmSession.getLoginInfoBean().setUserCurrentPassword(newPassword);

    // close any outstanding ldap connections (since they cache the old password)
    pwmSession
        .getSessionManager()
        .updateUserPassword(pwmApplication, uiBean.getUserIdentity(), newPassword);

    // clear the "requires new password flag"
    uiBean.setRequiresNewPassword(false);

    // mark the auth type as authenticatePd now that we have the user's natural password.
    pwmSession.getLoginInfoBean().setType(AuthenticationType.AUTHENTICATED);

    // update the uibean's "password expired flag".
    final UserStatusReader userStatusReader =
        new UserStatusReader(pwmApplication, pwmSession.getLabel());
    uiBean.setPasswordState(
        userStatusReader.readPasswordStatus(
            pwmSession.getSessionManager().getActor(pwmApplication),
            uiBean.getPasswordPolicy(),
            uiBean,
            newPassword));

    // create a proxy user object for pwm to update/read the user.
    final ChaiUser proxiedUser = pwmSession.getSessionManager().getActor(pwmApplication);

    // update statistics
    {
      pwmApplication.getStatisticsManager().incrementValue(Statistic.PASSWORD_CHANGES);
      pwmApplication.getStatisticsManager().updateEps(Statistic.EpsType.PASSWORD_CHANGES, 1);
      final int passwordStrength =
          PasswordUtility.judgePasswordStrength(newPassword.getStringValue());
      pwmApplication
          .getStatisticsManager()
          .updateAverageValue(Statistic.AVG_PASSWORD_STRENGTH, passwordStrength);
    }

    // add the old password to the global history list (if the old password is known)
    if (oldPassword != null
        && pwmApplication
            .getConfig()
            .readSettingAsBoolean(PwmSetting.PASSWORD_SHAREDHISTORY_ENABLE)) {
      pwmApplication.getSharedHistoryManager().addWord(pwmSession, oldPassword.getStringValue());
    }

    // invoke post password change actions
    invokePostChangePasswordActions(pwmSession, newPassword.getStringValue());

    { // execute configured actions
      LOGGER.debug(pwmSession, "executing configured actions to user " + proxiedUser.getEntryDN());
      final List<ActionConfiguration> configValues =
          pwmApplication
              .getConfig()
              .readSettingAsAction(PwmSetting.CHANGE_PASSWORD_WRITE_ATTRIBUTES);
      if (configValues != null && !configValues.isEmpty()) {
        final LoginInfoBean clonedLoginInfoBean =
            JsonUtil.cloneUsingJson(pwmSession.getLoginInfoBean(), LoginInfoBean.class);
        clonedLoginInfoBean.setUserCurrentPassword(newPassword);

        final MacroMachine macroMachine =
            new MacroMachine(
                pwmApplication,
                pwmSession.getLabel(),
                pwmSession.getUserInfoBean(),
                clonedLoginInfoBean,
                pwmSession.getSessionManager().getUserDataReader(pwmApplication));

        final ActionExecutor actionExecutor =
            new ActionExecutor.ActionExecutorSettings(pwmApplication, uiBean.getUserIdentity())
                .setMacroMachine(macroMachine)
                .setExpandPwmMacros(true)
                .createActionExecutor();
        actionExecutor.executeActions(configValues, pwmSession);
      }
    }

    // update the current last password update field in ldap
    LdapOperationsHelper.updateLastPasswordUpdateAttribute(
        pwmApplication, pwmSession.getLabel(), uiBean.getUserIdentity());
  }
Example #6
-1
  public static String sendNewPassword(
      final UserInfoBean userInfoBean,
      final PwmApplication pwmApplication,
      final MacroMachine macroMachine,
      final PasswordData newPassword,
      final Locale userLocale,
      final MessageSendMethod messageSendMethod)
      throws PwmOperationalException, PwmUnrecoverableException {
    final String emailAddress = userInfoBean.getUserEmailAddress();
    final String smsNumber = userInfoBean.getUserSmsNumber();
    String returnToAddress = emailAddress;

    ErrorInformation error = null;
    switch (messageSendMethod) {
      case BOTH:
        // Send both email and SMS, success if one of both succeeds
        final ErrorInformation err1 =
            sendNewPasswordEmail(
                userInfoBean, pwmApplication, macroMachine, newPassword, emailAddress, userLocale);
        final ErrorInformation err2 =
            sendNewPasswordSms(
                userInfoBean, pwmApplication, macroMachine, newPassword, smsNumber, userLocale);
        if (err1 != null) {
          error = err1;
          returnToAddress = smsNumber;
        } else if (err2 != null) {
          error = err2;
        }
        break;
      case EMAILFIRST:
        // Send email first, try SMS if email is not available
        error =
            sendNewPasswordEmail(
                userInfoBean, pwmApplication, macroMachine, newPassword, emailAddress, userLocale);
        if (error != null) {
          error =
              sendNewPasswordSms(
                  userInfoBean, pwmApplication, macroMachine, newPassword, smsNumber, userLocale);
          returnToAddress = smsNumber;
        }
        break;
      case SMSFIRST:
        // Send SMS first, try email if SMS is not available
        error =
            sendNewPasswordSms(
                userInfoBean, pwmApplication, macroMachine, newPassword, smsNumber, userLocale);
        if (error != null) {
          error =
              sendNewPasswordEmail(
                  userInfoBean,
                  pwmApplication,
                  macroMachine,
                  newPassword,
                  emailAddress,
                  userLocale);
        } else {
          returnToAddress = smsNumber;
        }
        break;
      case SMSONLY:
        // Only try SMS
        error =
            sendNewPasswordSms(
                userInfoBean, pwmApplication, macroMachine, newPassword, smsNumber, userLocale);
        returnToAddress = smsNumber;
        break;
      case EMAILONLY:
      default:
        // Only try email
        error =
            sendNewPasswordEmail(
                userInfoBean, pwmApplication, macroMachine, newPassword, emailAddress, userLocale);
        break;
    }
    if (error != null) {
      throw new PwmOperationalException(error);
    }
    return returnToAddress;
  }