예제 #1
0
 public ChaiUser getProxiedChaiUser(final UserIdentity userIdentity)
     throws PwmUnrecoverableException {
   try {
     final ChaiProvider proxiedProvider = getProxyChaiProvider(userIdentity.getLdapProfileID());
     return ChaiFactory.createChaiUser(userIdentity.getUserDN(), proxiedProvider);
   } catch (ChaiUnavailableException e) {
     throw PwmUnrecoverableException.fromChaiException(e);
   }
 }
예제 #2
0
 private ChaiProvider makeProxyProvider()
     throws ChaiUnavailableException, PwmUnrecoverableException {
   final LdapProfile profile =
       pwmApplication.getConfig().getLdapProfiles().get(userIdentity.getLdapProfileID());
   final String proxyDN = profile.readSettingAsString(PwmSetting.LDAP_PROXY_USER_DN);
   final PasswordData proxyPassword =
       profile.readSettingAsPassword(PwmSetting.LDAP_PROXY_USER_PASSWORD);
   return LdapOperationsHelper.createChaiProvider(
       sessionLabel, profile, pwmApplication.getConfig(), proxyDN, proxyPassword);
 }
예제 #3
0
  private PasswordData setTempUserPassword()
      throws ChaiUnavailableException, ImpossiblePasswordPolicyException,
          PwmUnrecoverableException {

    final boolean configAlwaysUseProxy =
        pwmApplication.getConfig().readSettingAsBoolean(PwmSetting.AD_USE_PROXY_FOR_FORGOTTEN);

    final ChaiProvider chaiProvider =
        pwmApplication.getProxyChaiProvider(userIdentity.getLdapProfileID());
    final ChaiUser chaiUser = ChaiFactory.createChaiUser(userIdentity.getUserDN(), chaiProvider);

    // try setting a random password on the account to authenticate.
    if (!configAlwaysUseProxy && requestedAuthType == AuthenticationType.AUTH_FROM_PUBLIC_MODULE) {
      log(PwmLogLevel.DEBUG, "attempting to set temporary random password");

      PwmPasswordPolicy passwordPolicy =
          PasswordUtility.readPasswordPolicyForUser(
              pwmApplication, sessionLabel, userIdentity, chaiUser, PwmConstants.DEFAULT_LOCALE);

      // create random password for user
      RandomPasswordGenerator.RandomGeneratorConfig randomGeneratorConfig =
          new RandomPasswordGenerator.RandomGeneratorConfig();
      randomGeneratorConfig.setSeedlistPhrases(RandomPasswordGenerator.DEFAULT_SEED_PHRASES);
      randomGeneratorConfig.setPasswordPolicy(passwordPolicy);

      final PasswordData currentPass =
          RandomPasswordGenerator.createRandomPassword(
              sessionLabel, randomGeneratorConfig, pwmApplication);

      try {
        final String oracleDS_PrePasswordAllowChangeTime =
            oraclePreTemporaryPwHandler(chaiProvider, chaiUser);

        // write the random password for the user.
        chaiUser.setPassword(currentPass.getStringValue());

        oraclePostTemporaryPwHandler(chaiProvider, chaiUser, oracleDS_PrePasswordAllowChangeTime);

        log(
            PwmLogLevel.INFO,
            "user "
                + userIdentity
                + " password has been set to random value to use for user authentication");
      } catch (ChaiOperationException e) {
        final String errorStr =
            "error setting random password for user " + userIdentity + " " + e.getMessage();
        log(PwmLogLevel.ERROR, errorStr);
        throw new PwmUnrecoverableException(
            new ErrorInformation(PwmError.ERROR_BAD_SESSION_PASSWORD, errorStr));
      }

      return currentPass;
    }
    return null;
  }
예제 #4
0
  private static Date determinePwdLastModified(
      final PwmApplication pwmApplication,
      final SessionLabel sessionLabel,
      final ChaiUser theUser,
      final UserIdentity userIdentity)
      throws ChaiUnavailableException, PwmUnrecoverableException {
    // fetch last password modification time from pwm last update attribute operation
    try {
      final Date chaiReadDate = theUser.readPasswordModificationDate();
      if (chaiReadDate != null) {
        LOGGER.trace(
            sessionLabel,
            "read last user password change timestamp (via chai) as: "
                + PwmConstants.DEFAULT_DATETIME_FORMAT.format(chaiReadDate));
        return chaiReadDate;
      }
    } catch (ChaiOperationException e) {
      LOGGER.error(
          sessionLabel,
          "unexpected error reading password last modified timestamp: " + e.getMessage());
    }

    final LdapProfile ldapProfile =
        pwmApplication.getConfig().getLdapProfiles().get(userIdentity.getLdapProfileID());
    final String pwmLastSetAttr =
        ldapProfile.readSettingAsString(PwmSetting.PASSWORD_LAST_UPDATE_ATTRIBUTE);
    if (pwmLastSetAttr != null && pwmLastSetAttr.length() > 0) {
      try {
        final Date pwmPwdLastModified = theUser.readDateAttribute(pwmLastSetAttr);
        LOGGER.trace(
            sessionLabel,
            "read pwmPasswordChangeTime as: "
                + (pwmPwdLastModified == null
                    ? "n/a"
                    : PwmConstants.DEFAULT_DATETIME_FORMAT.format(pwmPwdLastModified)));
        return pwmPwdLastModified;
      } catch (ChaiOperationException e) {
        LOGGER.error(
            sessionLabel,
            "error parsing password last modified PWM password value for user "
                + theUser.getEntryDN()
                + "; error: "
                + e.getMessage());
      }
    }

    LOGGER.debug(sessionLabel, "unable to determine time of user's last password modification");
    return null;
  }
예제 #5
0
 public static Map<String, Date> readIndividualReplicaLastPasswordTimes(
     final PwmApplication pwmApplication,
     final SessionLabel sessionLabel,
     final UserIdentity userIdentity)
     throws PwmUnrecoverableException {
   final Map<String, Date> returnValue = new LinkedHashMap<>();
   final ChaiProvider chaiProvider =
       pwmApplication.getProxyChaiProvider(userIdentity.getLdapProfileID());
   final Collection<ChaiConfiguration> perReplicaConfigs =
       ChaiUtility.splitConfigurationPerReplica(
           chaiProvider.getChaiConfiguration(),
           Collections.singletonMap(ChaiSetting.FAILOVER_CONNECT_RETRIES, "1"));
   for (final ChaiConfiguration loopConfiguration : perReplicaConfigs) {
     final String loopReplicaUrl = loopConfiguration.getSetting(ChaiSetting.BIND_DN);
     ChaiProvider loopProvider = null;
     try {
       loopProvider = ChaiProviderFactory.createProvider(loopConfiguration);
       final Date lastModifiedDate =
           determinePwdLastModified(pwmApplication, sessionLabel, userIdentity);
       returnValue.put(loopReplicaUrl, lastModifiedDate);
     } catch (ChaiUnavailableException e) {
       LOGGER.error(sessionLabel, "unreachable server during replica password sync check");
       e.printStackTrace();
     } finally {
       if (loopProvider != null) {
         try {
           loopProvider.close();
         } catch (Exception e) {
           final String errorMsg =
               "error closing loopProvider to "
                   + loopReplicaUrl
                   + " while checking individual password sync status";
           LOGGER.error(sessionLabel, errorMsg);
         }
       }
     }
   }
   return returnValue;
 }
예제 #6
0
  private PasswordData learnUserPassword()
      throws ChaiUnavailableException, PwmUnrecoverableException {
    log(PwmLogLevel.TRACE, "beginning auth processes for user with unknown password");

    if (userIdentity == null
        || userIdentity.getUserDN() == null
        || userIdentity.getUserDN().length() < 1) {
      throw new NullPointerException("invalid user (null)");
    }

    final ChaiProvider chaiProvider =
        pwmApplication.getProxyChaiProvider(userIdentity.getLdapProfileID());
    final ChaiUser chaiUser = ChaiFactory.createChaiUser(userIdentity.getUserDN(), chaiProvider);

    // use chai (nmas) to retrieve user password
    if (pwmApplication.getConfig().readSettingAsBoolean(PwmSetting.EDIRECTORY_READ_USER_PWD)) {
      String currentPass = null;
      try {
        final String readPassword = chaiUser.readPassword();
        if (readPassword != null && readPassword.length() > 0) {
          currentPass = readPassword;
          log(
              PwmLogLevel.DEBUG,
              "successfully retrieved user's current password from ldap, now conducting standard authentication");
        }
      } catch (Exception e) {
        log(PwmLogLevel.ERROR, "unable to retrieve user password from ldap: " + e.getMessage());
      }

      // actually do the authentication since we have user pw.
      if (currentPass != null && currentPass.length() > 0) {
        return new PasswordData(currentPass);
      }
    } else {
      log(PwmLogLevel.TRACE, "skipping attempt to read user password, option disabled");
    }
    return null;
  }
예제 #7
0
  private boolean updateCachedRecordFromLdap(
      final UserIdentity userIdentity,
      final UserInfoBean userInfoBean,
      final UserCacheService.StorageKey storageKey)
      throws ChaiUnavailableException, PwmUnrecoverableException, LocalDBException {
    final UserCacheRecord userCacheRecord = userCacheService.readStorageKey(storageKey);
    TimeDuration cacheAge = null;
    if (userCacheRecord != null && userCacheRecord.getCacheTimestamp() != null) {
      cacheAge = TimeDuration.fromCurrent(userCacheRecord.getCacheTimestamp());
    }

    boolean updateCache = false;
    if (userInfoBean != null) {
      updateCache = true;
    } else {
      if (cacheAge == null) {
        LOGGER.trace(
            PwmConstants.REPORTING_SESSION_LABEL,
            "stored cache for "
                + userIdentity
                + " is missing cache storage timestamp, will update");
        updateCache = true;
      } else if (cacheAge.isLongerThan(settings.getMinCacheAge())) {
        LOGGER.trace(
            PwmConstants.REPORTING_SESSION_LABEL,
            "stored cache for "
                + userIdentity
                + " is "
                + cacheAge.asCompactString()
                + " old, will update");
        updateCache = true;
      }
    }

    if (updateCache) {
      if (userCacheRecord != null) {
        if (summaryData != null
            && summaryData.getEpoch() != null
            && summaryData.getEpoch().equals(userCacheRecord.getSummaryEpoch())) {
          summaryData.remove(userCacheRecord);
        }
      }
      final UserInfoBean newUserBean;
      if (userInfoBean != null) {
        newUserBean = userInfoBean;
      } else {
        newUserBean = new UserInfoBean();
        final UserStatusReader.Settings readerSettings = new UserStatusReader.Settings();
        readerSettings.setSkipReportUpdate(true);
        final ChaiProvider chaiProvider =
            pwmApplication.getProxyChaiProvider(userIdentity.getLdapProfileID());
        final UserStatusReader userStatusReader =
            new UserStatusReader(
                pwmApplication, PwmConstants.REPORTING_SESSION_LABEL, readerSettings);
        userStatusReader.populateUserInfoBean(
            newUserBean, PwmConstants.DEFAULT_LOCALE, userIdentity, chaiProvider);
      }
      final UserCacheRecord newUserCacheRecord = userCacheService.updateUserCache(newUserBean);

      if (summaryData != null && summaryData.getEpoch() != null && newUserCacheRecord != null) {
        if (!summaryData.getEpoch().equals(newUserCacheRecord.getSummaryEpoch())) {
          newUserCacheRecord.setSummaryEpoch(summaryData.getEpoch());
          userCacheService.store(newUserCacheRecord);
        }
        summaryData.update(newUserCacheRecord);
      }
    }

    return updateCache;
  }
예제 #8
0
  private AuthenticationResult authenticateUserImpl(final PasswordData password)
      throws ChaiUnavailableException, PwmUnrecoverableException, PwmOperationalException {
    if (startTime == null) {
      startTime = new Date();
    }

    log(
        PwmLogLevel.DEBUG,
        "preparing to authenticate user using authenticationType="
            + this.requestedAuthType
            + " using strategy "
            + this.strategy);

    final StatisticsManager statisticsManager = pwmApplication.getStatisticsManager();
    final IntruderManager intruderManager = pwmApplication.getIntruderManager();
    intruderManager.convenience().checkUserIdentity(userIdentity);
    intruderManager.check(RecordType.ADDRESS, sessionLabel.getSrcAddress());

    boolean allowBindAsUser = true;
    if (strategy == AuthenticationStrategy.ADMIN_PROXY) {
      allowBindAsUser = false;
    }

    if (allowBindAsUser) {
      try {
        testCredentials(userIdentity, password);
      } catch (PwmOperationalException e) {
        boolean permitAuthDespiteError = false;
        final ChaiProvider.DIRECTORY_VENDOR vendor =
            pwmApplication
                .getProxyChaiProvider(userIdentity.getLdapProfileID())
                .getDirectoryVendor();
        if (PwmError.PASSWORD_NEW_PASSWORD_REQUIRED == e.getError()) {
          if (vendor == ChaiProvider.DIRECTORY_VENDOR.MICROSOFT_ACTIVE_DIRECTORY) {
            if (pwmApplication
                .getConfig()
                .readSettingAsBoolean(PwmSetting.AD_ALLOW_AUTH_REQUIRE_NEW_PWD)) {
              log(
                  PwmLogLevel.INFO,
                  "auth bind failed, but will allow login due to 'must change password on next login AD error', error: "
                      + e.getErrorInformation().toDebugStr());
              allowBindAsUser = false;
              permitAuthDespiteError = true;
            }
          } else if (vendor == ChaiProvider.DIRECTORY_VENDOR.ORACLE_DS) {
            if (pwmApplication
                .getConfig()
                .readSettingAsBoolean(PwmSetting.ORACLE_DS_ALLOW_AUTH_REQUIRE_NEW_PWD)) {
              log(
                  PwmLogLevel.INFO,
                  "auth bind failed, but will allow login due to 'pwdReset' user attribute, error: "
                      + e.getErrorInformation().toDebugStr());
              allowBindAsUser = false;
              permitAuthDespiteError = true;
            }
          }
        } else if (PwmError.PASSWORD_EXPIRED
            == e.getError()) { // handle ad case where password is expired
          if (vendor == ChaiProvider.DIRECTORY_VENDOR.MICROSOFT_ACTIVE_DIRECTORY) {
            if (pwmApplication
                .getConfig()
                .readSettingAsBoolean(PwmSetting.AD_ALLOW_AUTH_REQUIRE_NEW_PWD)) {
              if (!pwmApplication
                  .getConfig()
                  .readSettingAsBoolean(PwmSetting.AD_ALLOW_AUTH_EXPIRED)) {
                throw e;
              }
              log(
                  PwmLogLevel.INFO,
                  "auth bind failed, but will allow login due to 'password expired AD error', error: "
                      + e.getErrorInformation().toDebugStr());
              allowBindAsUser = false;
              permitAuthDespiteError = true;
            }
          }
        }

        if (!permitAuthDespiteError) { // auth failed, presumably due to wrong password.
          statisticsManager.incrementValue(Statistic.AUTHENTICATION_FAILURES);
          throw e;
        }
      }
    } else {
      // verify user is not account disabled
      AuthenticationUtility.checkIfUserEligibleToAuthentication(pwmApplication, userIdentity);
    }

    statisticsManager.incrementValue(Statistic.AUTHENTICATIONS);
    statisticsManager.updateEps(Statistic.EpsType.AUTHENTICATION, 1);
    statisticsManager.updateAverageValue(
        Statistic.AVG_AUTHENTICATION_TIME,
        TimeDuration.fromCurrent(startTime).getTotalMilliseconds());

    final AuthenticationType returnAuthType;
    if (!allowBindAsUser) {
      returnAuthType = AuthenticationType.AUTH_BIND_INHIBIT;
    } else {
      if (requestedAuthType == null) {
        returnAuthType = AuthenticationType.AUTHENTICATED;
      } else {
        if (requestedAuthType == AuthenticationType.AUTH_WITHOUT_PASSWORD) {
          returnAuthType = AuthenticationType.AUTHENTICATED;
        } else if (requestedAuthType == AuthenticationType.AUTH_FROM_PUBLIC_MODULE) {
          returnAuthType = AuthenticationType.AUTH_FROM_PUBLIC_MODULE;
        } else {
          returnAuthType = requestedAuthType;
        }
      }
    }

    final boolean useProxy = determineIfLdapProxyNeeded(returnAuthType, password);
    final ChaiProvider returnProvider = useProxy ? makeProxyProvider() : userProvider;
    final AuthenticationResult authenticationResult =
        new AuthenticationResult(returnProvider, returnAuthType, password);

    final StringBuilder debugMsg = new StringBuilder();
    debugMsg.append("successful ldap authentication for ").append(userIdentity);
    debugMsg.append(" (").append(TimeDuration.fromCurrent(startTime).asCompactString()).append(")");
    debugMsg.append(" type: ").append(returnAuthType).append(", using strategy ").append(strategy);
    debugMsg.append(", using proxy connection: ").append(useProxy);
    debugMsg
        .append(", returning bind dn: ")
        .append(
            returnProvider == null
                ? "none"
                : returnProvider.getChaiConfiguration().getSetting(ChaiSetting.BIND_DN));
    log(PwmLogLevel.INFO, debugMsg);
    pwmApplication
        .getAuditManager()
        .submit(
            pwmApplication
                .getAuditManager()
                .createUserAuditRecord(
                    AuditEvent.AUTHENTICATE,
                    this.userIdentity,
                    makeAuditLogMessage(returnAuthType),
                    sessionLabel.getSrcAddress(),
                    sessionLabel.getSrcHostname()));

    return authenticationResult;
  }