jrivard 10 éve
szülő
commit
17d1d47694
29 módosított fájl, 733 hozzáadás és 362 törlés
  1. 6 2
      pwm/servlet/src/password/pwm/AppProperty.java
  2. 5 1
      pwm/servlet/src/password/pwm/AppProperty.properties
  3. 22 0
      pwm/servlet/src/password/pwm/RecoveryVerificationMethod.java
  4. 63 0
      pwm/servlet/src/password/pwm/bean/PublicUserInfoBean.java
  5. 34 0
      pwm/servlet/src/password/pwm/bean/RemoteVerificationRequestBean.java
  6. 45 0
      pwm/servlet/src/password/pwm/bean/RemoteVerificationResponseBean.java
  7. 3 1
      pwm/servlet/src/password/pwm/config/FormUtility.java
  8. 14 4
      pwm/servlet/src/password/pwm/config/PwmSetting.java
  9. 3 0
      pwm/servlet/src/password/pwm/config/PwmSetting.xml
  10. 14 10
      pwm/servlet/src/password/pwm/config/StoredConfiguration.java
  11. 9 0
      pwm/servlet/src/password/pwm/http/bean/ForgottenPasswordBean.java
  12. 1 1
      pwm/servlet/src/password/pwm/http/client/PwmHttpClient.java
  13. 11 1
      pwm/servlet/src/password/pwm/http/filter/SessionFilter.java
  14. 5 2
      pwm/servlet/src/password/pwm/http/servlet/ChangePasswordServlet.java
  15. 42 6
      pwm/servlet/src/password/pwm/http/servlet/ConfigManagerServlet.java
  16. 165 11
      pwm/servlet/src/password/pwm/http/servlet/ForgottenPasswordServlet.java
  17. 3 3
      pwm/servlet/src/password/pwm/http/servlet/NewUserServlet.java
  18. 9 0
      pwm/servlet/src/password/pwm/i18n/Config.properties
  19. 0 0
      pwm/servlet/src/password/pwm/i18n/ConfigEditor.properties
  20. 153 148
      pwm/servlet/src/password/pwm/i18n/Error_zh.properties
  21. 107 96
      pwm/servlet/src/password/pwm/i18n/Message_zh.properties
  22. 3 3
      pwm/servlet/src/password/pwm/util/PwmPasswordRuleValidator.java
  23. 3 3
      pwm/servlet/src/password/pwm/util/macro/ExternalRestMacro.java
  24. 2 1
      pwm/servlet/src/password/pwm/util/operations/OtpService.java
  25. 3 3
      pwm/servlet/src/password/pwm/ws/client/rest/RestTokenDataClient.java
  26. 3 62
      pwm/servlet/src/password/pwm/ws/server/rest/RestStatusServer.java
  27. 1 1
      pwm/servlet/web/WEB-INF/jsp/forgottenpassword-remote.jsp
  28. 2 1
      pwm/servlet/web/public/resources/js/configeditor-settings.js
  29. 2 2
      pwm/servlet/web/public/resources/js/peoplesearch.js

+ 6 - 2
pwm/servlet/src/password/pwm/AppProperty.java

@@ -34,6 +34,7 @@ public enum AppProperty {
     CACHE_ENABLE                                    ("cache.enable"),
     CACHE_MEMORY_MAX_ITEMS                          ("cache.memory.maxItems"),
     CACHE_PWRULECHECK_LIFETIME_MS                   ("cache.pwRuleCheckLifetimeMS"),
+    CACHE_FORM_UNIQUE_VALUE_LIFETIME_MS             ("cache.uniqueFormValueLifetimeMS"),
     CLIENT_ACTIVITY_MAX_EPS_RATE                    ("client.ajax.activityMaxEpsRate"),
     CLIENT_AJAX_PW_WAIT_CHECK_SECONDS               ("client.ajax.changePasswordWaitCheckSeconds"),
     CLIENT_AJAX_TYPING_TIMEOUT                      ("client.ajax.typingTimeout"),
@@ -52,6 +53,8 @@ public enum AppProperty {
     CONFIG_EDITOR_QUERY_FILTER_TEST_LIMIT           ("configEditor.queryFilter.testLimit"),
     CONFIG_EDITOR_IDLE_TIMEOUT                      ("configEditor.idleTimeoutSeconds"),
     CONFIG_GUIDE_IDLE_TIMEOUT                       ("configGuide.idleTimeoutSeconds"),
+    CONFIG_MANAGER_ZIPDEBUG_MAXLOGLINES             ("configManager.zipDebug.maxLogLines"),
+    CONFIG_MANAGER_ZIPDEBUG_MAXLOGSECONDS           ("configManager.zipDebug.maxLogSeconds"),
     FORM_EMAIL_REGEX                                ("form.email.regexTest"),
     HTTP_RESOURCES_MAX_CACHE_ITEMS                  ("http.resources.maxCacheItems"),
     HTTP_RESOURCES_MAX_CACHE_BYTES                  ("http.resources.maxCacheBytes"),
@@ -81,7 +84,7 @@ public enum AppProperty {
     HTTP_PARAM_NAME_THEME                           ("http.parameter.theme"),
     HTTP_PARAM_NAME_LOCALE                          ("http.parameter.locale"),
     HTTP_PARAM_NAME_PASSWORD_EXPIRED                ("http.parameter.passwordExpired"),
-    HTTP_PARAM_NAME_SSO_ENABLE("http.parameter.ssoBypass"),
+    HTTP_PARAM_NAME_SSO_ENABLE                      ("http.parameter.ssoBypass"),
     HTTP_PARAM_MAX_READ_LENGTH                      ("http.parameter.maxReadLength"),
     HTTP_PARAM_OAUTH_ACCESS_TOKEN                   ("http.parameter.oauth.accessToken"),
     HTTP_PARAM_OAUTH_ATTRIBUTES                     ("http.parameter.oauth.attributes"),
@@ -104,7 +107,7 @@ public enum AppProperty {
     MACRO_LDAP_ATTR_CHAR_MAX_LENGTH                 ("macro.ldapAttr.maxLength"),
     NAAF_ID                                         ("naaf.id"),
     NAAF_SECRET                                     ("naaf.secret"),
-    NAAF_SALT_LENGTH                                ("naaf.salf.length"),
+    NAAF_SALT_LENGTH                                ("naaf.salt.length"),
 
     
     /** Time intruder records exist in the intruder table before being deleted. */
@@ -152,6 +155,7 @@ public enum AppProperty {
     
     TOTP_INTERVAL                                   ("otp.totp.intervalSeconds"),
     OTP_TOKEN_LENGTH                                ("otp.token.length"),
+    OTP_SALT_CHARLENGTH                             ("otp.salt.charLength"),
     OTP_RECOVERY_TOKEN_MACRO                        ("otp.recovery.macro"),
     OTP_RECOVERY_HASH_COUNT                         ("otp.recoveryHash.iterations"),
     OTP_RECOVERY_HASH_METHOD                        ("otp.recoveryHash.method"),

+ 5 - 1
pwm/servlet/src/password/pwm/AppProperty.properties

@@ -31,6 +31,7 @@ backup.localdb.count=10
 cache.enable=true
 cache.memory.maxItems=100
 cache.pwRuleCheckLifetimeMS=30000
+cache.uniqueFormValueLifetimeMS=30000
 client.ajax.activityMaxEpsRate=100
 client.ajax.changePasswordWaitCheckSeconds=3
 client.ajax.typingTimeout=20000
@@ -49,6 +50,8 @@ config.newuser.passwordPolicyCacheMS=3600000
 configEditor.queryFilter.testLimit=1000
 configEditor.idleTimeoutSeconds=900
 configGuide.idleTimeoutSeconds=3600
+configManager.zipDebug.maxLogLines=100000
+configManager.zipDebug.maxLogSeconds=30
 form.email.regexTest=^[_+a-zA-Z0-9-]+(\\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*$
 health.minimumCheckIntervalSeconds=60
 health.certificate.warnSeconds=2592000
@@ -121,7 +124,7 @@ macro.randomChar.maxLength=100
 macro.ldapAttr.maxLength=100
 naaf.id=41414141414141414141414141414141
 naaf.secret=876543210
-naaf.salf.length=30
+naaf.salt.length=30
 logging.devOutput.enable=false
 logging.pattern=%d{yyyy-MM-dd'T'HH:mm:ss'Z'}, %-5p, %c{2}, %m%n
 logging.file.maxSize=20MB
@@ -140,6 +143,7 @@ otp.totp.pastIntervals=1
 otp.totp.futureIntervals=1
 otp.totp.intervalSeconds=30
 otp.token.length=6
+otp.salt.charLength=32
 otp.recovery.macro=@RandomChar:8:0123456789@
 otp.recoveryHash.iterations=1000
 otp.recoveryHash.method=SHA1

+ 22 - 0
pwm/servlet/src/password/pwm/RecoveryVerificationMethod.java

@@ -5,6 +5,7 @@ import password.pwm.bean.UserInfoBean;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmUnrecoverableException;
 
+import java.io.Serializable;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -21,6 +22,27 @@ public interface RecoveryVerificationMethod {
         String getIdentifier();
     }
 
+    class UserPromptBean implements Serializable, UserPrompt {
+        private String displayPrompt;
+        private String identifier;
+
+        public String getDisplayPrompt() {
+            return displayPrompt;
+        }
+
+        public void setDisplayPrompt(String displayPrompt) {
+            this.displayPrompt = displayPrompt;
+        }
+
+        public String getIdentifier() {
+            return identifier;
+        }
+
+        public void setIdentifier(String identifier) {
+            this.identifier = identifier;
+        }
+    }
+
     public List<UserPrompt> getCurrentPrompts() throws PwmUnrecoverableException;
 
     public String getCurrentDisplayInstructions();

+ 63 - 0
pwm/servlet/src/password/pwm/bean/PublicUserInfoBean.java

@@ -0,0 +1,63 @@
+package password.pwm.bean;
+
+import password.pwm.config.Configuration;
+import password.pwm.config.profile.PwmPasswordRule;
+import password.pwm.http.tag.PasswordRequirementsTag;
+
+import java.io.Serializable;
+import java.util.*;
+
+public class PublicUserInfoBean implements Serializable {
+    public String userDN;
+    public String ldapProfile;
+    public String userID;
+    public String userEmailAddress;
+    public Date passwordExpirationTime;
+    public Date passwordLastModifiedTime;
+    public boolean requiresNewPassword;
+    public boolean requiresResponseConfig;
+    public boolean requiresUpdateProfile;
+    public boolean requiresInteraction;
+
+    public PasswordStatus passwordStatus;
+    public Map<String, String> passwordPolicy;
+    public List<String> passwordRules;
+    public Map<String, String> attributes;
+
+    public static PublicUserInfoBean fromUserInfoBean(final UserInfoBean userInfoBean, final Configuration config, final Locale locale) {
+        final PublicUserInfoBean publicUserInfoBean = new PublicUserInfoBean();
+        publicUserInfoBean.userDN = (userInfoBean.getUserIdentity() == null) ? "" : userInfoBean.getUserIdentity().getUserDN();
+        publicUserInfoBean.ldapProfile = (userInfoBean.getUserIdentity() == null) ? "" : userInfoBean.getUserIdentity().getLdapProfileID();
+        publicUserInfoBean.userID = userInfoBean.getUsername();
+        publicUserInfoBean.userEmailAddress = userInfoBean.getUserEmailAddress();
+        publicUserInfoBean.passwordExpirationTime = userInfoBean.getPasswordExpirationTime();
+        publicUserInfoBean.passwordLastModifiedTime = userInfoBean.getPasswordLastModifiedTime();
+        publicUserInfoBean.passwordStatus = userInfoBean.getPasswordState();
+
+        publicUserInfoBean.requiresNewPassword = userInfoBean.isRequiresNewPassword();
+        publicUserInfoBean.requiresResponseConfig = userInfoBean.isRequiresResponseConfig();
+        publicUserInfoBean.requiresUpdateProfile = userInfoBean.isRequiresResponseConfig();
+        publicUserInfoBean.requiresInteraction = userInfoBean.isRequiresNewPassword()
+                || userInfoBean.isRequiresResponseConfig()
+                || userInfoBean.isRequiresUpdateProfile()
+                || userInfoBean.getPasswordState().isWarnPeriod();
+
+
+        publicUserInfoBean.passwordPolicy = new HashMap<>();
+        for (final PwmPasswordRule rule : PwmPasswordRule.values()) {
+            publicUserInfoBean.passwordPolicy.put(rule.name(), userInfoBean.getPasswordPolicy().getValue(rule));
+        }
+
+        publicUserInfoBean.passwordRules = PasswordRequirementsTag.getPasswordRequirementsStrings(
+                userInfoBean.getPasswordPolicy(),
+                config,
+                locale
+        );
+
+        if (userInfoBean.getCachedAttributeValues() != null && !userInfoBean.getCachedAttributeValues().isEmpty()) {
+            publicUserInfoBean.attributes = Collections.unmodifiableMap(userInfoBean.getCachedAttributeValues());
+        }
+
+        return publicUserInfoBean;
+    }
+}

+ 34 - 0
pwm/servlet/src/password/pwm/bean/RemoteVerificationRequestBean.java

@@ -0,0 +1,34 @@
+package password.pwm.bean;
+
+import java.io.Serializable;
+import java.util.Map;
+
+public class RemoteVerificationRequestBean implements Serializable {
+    private String responseSessionID;
+    private PublicUserInfoBean userInfo;
+    private Map<String, String> userResponses;
+
+    public String getResponseSessionID() {
+        return responseSessionID;
+    }
+
+    public void setResponseSessionID(String responseSessionID) {
+        this.responseSessionID = responseSessionID;
+    }
+
+    public PublicUserInfoBean getUserInfo() {
+        return userInfo;
+    }
+
+    public void setUserInfo(PublicUserInfoBean userInfo) {
+        this.userInfo = userInfo;
+    }
+
+    public Map<String, String> getUserResponses() {
+        return userResponses;
+    }
+
+    public void setUserResponses(Map<String, String> userResponses) {
+        this.userResponses = userResponses;
+    }
+}

+ 45 - 0
pwm/servlet/src/password/pwm/bean/RemoteVerificationResponseBean.java

@@ -0,0 +1,45 @@
+package password.pwm.bean;
+
+import password.pwm.RecoveryVerificationMethod;
+
+import java.io.Serializable;
+import java.util.List;
+
+public class RemoteVerificationResponseBean implements Serializable {
+    private String displayInstructions;
+    private RecoveryVerificationMethod.VerificationState verificationState;
+    private List<RecoveryVerificationMethod.UserPromptBean> userPrompts;
+    private String errorMessage;
+
+    public String getDisplayInstructions() {
+        return displayInstructions;
+    }
+
+    public void setDisplayInstructions(String displayInstructions) {
+        this.displayInstructions = displayInstructions;
+    }
+
+    public RecoveryVerificationMethod.VerificationState getVerificationState() {
+        return verificationState;
+    }
+
+    public void setVerificationState(RecoveryVerificationMethod.VerificationState verificationState) {
+        this.verificationState = verificationState;
+    }
+
+    public List<RecoveryVerificationMethod.UserPromptBean> getUserPrompts() {
+        return userPrompts;
+    }
+
+    public void setUserPrompts(List<RecoveryVerificationMethod.UserPromptBean> userPrompts) {
+        this.userPrompts = userPrompts;
+    }
+
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    public void setErrorMessage(String errorMessage) {
+        this.errorMessage = errorMessage;
+    }
+}

+ 3 - 1
pwm/servlet/src/password/pwm/config/FormUtility.java

@@ -27,6 +27,7 @@ import com.novell.ldapchai.exception.ChaiException;
 import com.novell.ldapchai.exception.ChaiOperationException;
 import com.novell.ldapchai.exception.ChaiUnavailableException;
 import com.novell.ldapchai.util.SearchHelper;
+import password.pwm.AppProperty;
 import password.pwm.PwmApplication;
 import password.pwm.Validator;
 import password.pwm.bean.SessionLabel;
@@ -215,7 +216,8 @@ public class FormUtility {
         searchConfiguration.setFilter(filter.toString());
 
         int resultSearchSizeLimit = 1 + (excludeDN == null ? 0 : excludeDN.size());
-        final CachePolicy cachePolicy = CachePolicy.makePolicyWithExpirationMS(30 * 1000);
+        final long cacheLifetimeMS = Long.parseLong(pwmApplication.getConfig().readAppProperty(AppProperty.CACHE_FORM_UNIQUE_VALUE_LIFETIME_MS));
+        final CachePolicy cachePolicy = CachePolicy.makePolicyWithExpirationMS(cacheLifetimeMS);
 
         try {
             final UserSearchEngine userSearchEngine = new UserSearchEngine(pwmApplication, SessionLabel.SYSTEM_LABEL);

+ 14 - 4
pwm/servlet/src/password/pwm/config/PwmSetting.java

@@ -1002,6 +1002,8 @@ public enum PwmSetting {
             "external.pwcheck.urls", PwmSettingSyntax.STRING, PwmSettingCategory.REST_CLIENT),
     EXTERNAL_MACROS_REST_URLS(
             "external.macros.urls", PwmSettingSyntax.STRING_ARRAY, PwmSettingCategory.REST_CLIENT),
+    EXTERNAL_MACROS_REMOTE_RESPONSES_URL(
+            "external.remoteResponses.url", PwmSettingSyntax.STRING, PwmSettingCategory.REST_CLIENT),
     CACHED_USER_ATTRIBUTES(
             "webservice.userAttributes", PwmSettingSyntax.STRING_ARRAY, PwmSettingCategory.REST_CLIENT),
 
@@ -1160,14 +1162,22 @@ public enum PwmSetting {
 
     public String getLabel(final Locale locale) {
         final String key = "Setting_Label_" + this.getKey();
-        return LocaleHelper.getLocalizedMessage(locale, key, null, ConfigEditor.class);
+        try {
+            return LocaleHelper.getLocalizedMessage(locale, key, null, ConfigEditor.class);
+        } catch (MissingResourceException e) {
+            return "MISSING_SETTING_LABEL-" + key;
+        }
     }
 
     public String getDescription(final Locale locale) {
         final String key = "Setting_Description_" + this.getKey();
-        final String storedText = LocaleHelper.getLocalizedMessage(locale, key, null, ConfigEditor.class);
-        final MacroMachine macroMachine = MacroMachine.forStatic();
-        return macroMachine.expandMacros(storedText);
+        try {
+            final String storedText = LocaleHelper.getLocalizedMessage(locale, key, null, ConfigEditor.class);
+            final MacroMachine macroMachine = MacroMachine.forStatic();
+            return macroMachine.expandMacros(storedText);
+        } catch (MissingResourceException e) {
+            return "MISSING_DESCRIPTION_LABEL-" + key;
+        }
     }
 
     public String getPlaceholder(final Locale locale) {

+ 3 - 0
pwm/servlet/src/password/pwm/config/PwmSetting.xml

@@ -2994,6 +2994,9 @@
     <setting key="external.macros.urls" level="2">
         <default />
     </setting>
+    <setting key="external.remoteResponses.url" level="2">
+        <default />
+    </setting>
     <setting key="external.destToken.urls" level="2">
         <default />
     </setting>

+ 14 - 10
pwm/servlet/src/password/pwm/config/StoredConfiguration.java

@@ -393,6 +393,16 @@ public class StoredConfiguration implements Serializable {
         return setting.getKey() + "=" + storedValue.toDebugString(false, null);
     }
 
+    public Map<String,String> getModifiedSettingDebugValues(final Locale locale, final boolean prettyPrint) {
+        final Map<String,String> returnObj = new LinkedHashMap<>();
+        for (SettingValueRecord record : this.modifiedSettings()) {
+            final String label = record.getSetting().toMenuLocationDebug(record.getProfile(),locale);
+            final String value = record.getStoredValue().toDebugString(true, locale);
+            returnObj.put(label,value);
+        }
+        return returnObj;
+    }
+
     List<SettingValueRecord> modifiedSettings() {
         final List<SettingValueRecord> returnObj = new ArrayList<>();
         domModifyLock.readLock().lock();
@@ -505,13 +515,8 @@ public class StoredConfiguration implements Serializable {
         final List<String> errorStrings = new ArrayList<>();
 
         for (final PwmSetting loopSetting : PwmSetting.values()) {
-            final StringBuilder errorPrefix = new StringBuilder();
-            errorPrefix.append(loopSetting.getCategory().getLabel(PwmConstants.DEFAULT_LOCALE));
-            errorPrefix.append("-");
-            errorPrefix.append(loopSetting.getLabel(PwmConstants.DEFAULT_LOCALE));
 
             if (loopSetting.getCategory().hasProfiles()) {
-                errorPrefix.append("-");
                 for (final String profile : profilesForSetting(loopSetting)) {
                     final String errorAppend = profile;
                     final StoredValue loopValue = readSetting(loopSetting,profile);
@@ -519,23 +524,22 @@ public class StoredConfiguration implements Serializable {
                     try {
                         final List<String> errors = loopValue.validateValue(loopSetting);
                         for (final String loopError : errors) {
-                            errorStrings.add(errorPrefix + errorAppend + " " + loopError);
+                            errorStrings.add(loopSetting.toMenuLocationDebug(profile,PwmConstants.DEFAULT_LOCALE) + errorAppend + " " + loopError);
                         }
                     } catch (Exception e) {
-                        LOGGER.error("unexpected error during validate value for " + errorPrefix + errorAppend + ", error: " + e.getMessage(),e);
+                        LOGGER.error("unexpected error during validate value for " + loopSetting.toMenuLocationDebug(profile,PwmConstants.DEFAULT_LOCALE) + errorAppend + ", error: " + e.getMessage(),e);
                     }
                 }
             } else {
-                errorPrefix.append(" ");
                 final StoredValue loopValue = readSetting(loopSetting);
 
                 try {
                     final List<String> errors = loopValue.validateValue(loopSetting);
                     for (final String loopError : errors) {
-                        errorStrings.add(errorPrefix + loopError);
+                        errorStrings.add(loopSetting.toMenuLocationDebug(null,PwmConstants.DEFAULT_LOCALE) + loopError);
                     }
                 } catch (Exception e) {
-                    LOGGER.error("unexpected error during validate value for " + errorPrefix + ", error: " + e.getMessage(),e);
+                    LOGGER.error("unexpected error during validate value for " + loopSetting.toMenuLocationDebug(null,PwmConstants.DEFAULT_LOCALE) + ", error: " + e.getMessage(),e);
                 }
             }
         }

+ 9 - 0
pwm/servlet/src/password/pwm/http/bean/ForgottenPasswordBean.java

@@ -129,6 +129,7 @@ public class ForgottenPasswordBean implements PwmSessionBean {
         private RecoveryVerificationMethods inProgressVerificationMethod;
 
         private transient RecoveryVerificationMethod naafRecoveryMethod;
+        private transient RecoveryVerificationMethod remoteRecoveryMethod;
 
         public Set<RecoveryVerificationMethods> getSatisfiedMethods() {
             return satisfiedMethods;
@@ -189,6 +190,14 @@ public class ForgottenPasswordBean implements PwmSessionBean {
         public RecoveryVerificationMethod getNaafRecoveryMethod() {
             return naafRecoveryMethod;
         }
+
+        public RecoveryVerificationMethod getRemoteRecoveryMethod() {
+            return remoteRecoveryMethod;
+        }
+
+        public void setRemoteRecoveryMethod(RecoveryVerificationMethod remoteRecoveryMethod) {
+            this.remoteRecoveryMethod = remoteRecoveryMethod;
+        }
     }
 
     public static class RecoveryFlags implements Serializable {

+ 1 - 1
pwm/servlet/src/password/pwm/http/client/PwmHttpClient.java

@@ -137,7 +137,7 @@ public class PwmHttpClient {
         }
     }
 
-    public PwmHttpClientResponse makeRequestImpl(final PwmHttpClientRequest clientRequest)
+    PwmHttpClientResponse makeRequestImpl(final PwmHttpClientRequest clientRequest)
             throws IOException, URISyntaxException, PwmUnrecoverableException {
         final Date startTime = new Date();
         final int counter = classCounter++;

+ 11 - 1
pwm/servlet/src/password/pwm/http/filter/SessionFilter.java

@@ -88,7 +88,17 @@ public class SessionFilter extends AbstractPwmFilter {
             LOGGER.trace(pwmRequest.getPwmSession(), "IO exception during servlet processing: " + e.getMessage());
             throw new ServletException(e);
         } catch (Throwable e) {
-            LOGGER.warn(pwmRequest.getPwmSession(), "unhandled exception " + e.getMessage(), e);
+            if (e instanceof ServletException
+                    && e.getCause() != null
+                    && e.getCause() instanceof NoClassDefFoundError
+                    && e.getCause().getMessage() != null
+                    && e.getCause().getMessage().contains("JaxbAnnotationIntrospector")
+                    ) {
+                LOGGER.debug("ignoring JaxbAnnotationIntrospector NoClassDefFoundError: " + e.getMessage()); // this is a jersey 1.18 bug that occurs once per execution
+            } else {
+                LOGGER.warn(pwmRequest.getPwmSession(), "unhandled exception " + e.getMessage(), e);
+            }
+
             throw new ServletException(e);
         }
     }

+ 5 - 2
pwm/servlet/src/password/pwm/http/servlet/ChangePasswordServlet.java

@@ -375,8 +375,11 @@ public class ChangePasswordServlet extends PwmServlet {
         if (pwmSession.getUserInfoBean().getPasswordState().isWarnPeriod()) {
             if (!pwmRequest.getPwmSession().getSessionStateBean().isSkippedRequireNewPassword()) {
                 if (!changePasswordBean.isWarnPassed()) {
-                    pwmRequest.forwardToJsp(PwmConstants.JSP_URL.PASSWORD_WARN);
-                    return;
+                    if (pwmRequest.getPwmSession().getLoginInfoBean().getAuthenticationType() != AuthenticationType.AUTH_FROM_PUBLIC_MODULE) {
+                        LOGGER.trace(pwmRequest, "pasword expiration is within password warn period, forwarding user to warning page");
+                        pwmRequest.forwardToJsp(PwmConstants.JSP_URL.PASSWORD_WARN);
+                        return;
+                    }
                 }
             }
         }

+ 42 - 6
pwm/servlet/src/password/pwm/http/servlet/ConfigManagerServlet.java

@@ -636,7 +636,8 @@ public class ConfigManagerServlet extends PwmServlet {
 
     private static final List<Class<? extends DebugItemGenerator>> DEBUG_ZIP_ITEM_GENERATORS  = Collections.unmodifiableList(Arrays.asList(
             ConfigurationFileItemGenerator.class,
-            ConfigurationDebugItemGenerator.class,
+            ConfigurationDebugJsonItemGenerator.class,
+            ConfigurationDebugTextItemGenerator.class,
             AboutItemGenerator.class,
             EnvironmentItemGenerator.class,
             AuditDebugItemGenerator.class,
@@ -658,10 +659,10 @@ public class ConfigManagerServlet extends PwmServlet {
         ) throws Exception;
     }
 
-    static class ConfigurationDebugItemGenerator implements DebugItemGenerator {
+    static class ConfigurationDebugJsonItemGenerator implements DebugItemGenerator {
         @Override
         public String getFilename() {
-            return "configuration-debug.txt";
+            return "configuration-debug.json";
         }
 
         @Override
@@ -674,6 +675,40 @@ public class ConfigManagerServlet extends PwmServlet {
         }
     }
 
+    static class ConfigurationDebugTextItemGenerator implements DebugItemGenerator {
+        @Override
+        public String getFilename() {
+            return "configuration-debug.txt";
+        }
+
+        @Override
+        public void outputItem(PwmApplication pwmApplication, PwmRequest pwmRequest, OutputStream outputStream) throws Exception
+        {
+            final StoredConfiguration storedConfiguration = readCurrentConfiguration(pwmRequest);
+            storedConfiguration.resetAllPasswordValues("value removed from " + PwmConstants.PWM_APP_NAME + "-Support configuration export");
+
+            final StringWriter writer = new StringWriter();
+            writer.write("Configuration Debug Output for "
+                    + PwmConstants.PWM_APP_NAME + " "
+                    + PwmConstants.SERVLET_VERSION + "\n");
+            writer.write("Timestamp: " + PwmConstants.DEFAULT_DATETIME_FORMAT.format(storedConfiguration.modifyTime()) + "\n");
+            writer.write("This file is encoded using " + PwmConstants.DEFAULT_CHARSET.displayName() + "\n");
+
+            writer.write("\n");
+            final Map<String,String> modifiedSettings = storedConfiguration.getModifiedSettingDebugValues(PwmConstants.DEFAULT_LOCALE, true);
+            for (final String key : modifiedSettings.keySet()) {
+                final String value = modifiedSettings.get(key);
+                writer.write(">> Setting > " + key);
+                writer.write("\n");
+                writer.write(value);
+                writer.write("\n");
+                writer.write("\n");
+            }
+
+            outputStream.write(writer.toString().getBytes(PwmConstants.DEFAULT_CHARSET));
+        }
+    }
+
     static class ConfigurationFileItemGenerator implements DebugItemGenerator {
         @Override
         public String getFilename() {
@@ -886,14 +921,14 @@ public class ConfigManagerServlet extends PwmServlet {
                 final OutputStream outputStream
         ) throws Exception {
 
-            final int maxCount = 100 * 1000;
-            final int maxSeconds = 30 * 1000;
+            final int maxCount = Integer.parseInt(pwmRequest.getConfig().readAppProperty(AppProperty.CONFIG_MANAGER_ZIPDEBUG_MAXLOGLINES));
+            final int maxSeconds = Integer.parseInt(pwmRequest.getConfig().readAppProperty(AppProperty.CONFIG_MANAGER_ZIPDEBUG_MAXLOGSECONDS));
             final LocalDBLogger.SearchParameters searchParameters = new LocalDBLogger.SearchParameters(
                     PwmLogLevel.TRACE,
                     maxCount,
                     null,
                     null,
-                    maxSeconds,
+                    (maxSeconds * 1000),
                     null
             );
             final LocalDBLogger.SearchResults searchResults = pwmApplication.getLocalDBLogger().readStoredEvents(
@@ -908,6 +943,7 @@ public class ConfigManagerServlet extends PwmServlet {
                     outputStream.flush();
                 }
             }
+            LOGGER.trace("output " + counter + " lines to " + this.getFilename());
         }
     }
 }

+ 165 - 11
pwm/servlet/src/password/pwm/http/servlet/ForgottenPasswordServlet.java

@@ -48,6 +48,9 @@ import password.pwm.http.HttpMethod;
 import password.pwm.http.PwmRequest;
 import password.pwm.http.PwmSession;
 import password.pwm.http.bean.ForgottenPasswordBean;
+import password.pwm.http.client.PwmHttpClient;
+import password.pwm.http.client.PwmHttpClientRequest;
+import password.pwm.http.client.PwmHttpClientResponse;
 import password.pwm.http.filter.AuthenticationFilter;
 import password.pwm.i18n.Message;
 import password.pwm.ldap.LdapUserDataReader;
@@ -59,10 +62,7 @@ import password.pwm.ldap.auth.AuthenticationUtility;
 import password.pwm.ldap.auth.SessionAuthenticator;
 import password.pwm.token.TokenPayload;
 import password.pwm.token.TokenService;
-import password.pwm.util.JsonUtil;
-import password.pwm.util.PasswordData;
-import password.pwm.util.PostChangePasswordAction;
-import password.pwm.util.RandomPasswordGenerator;
+import password.pwm.util.*;
 import password.pwm.util.intruder.RecordType;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.macro.MacroMachine;
@@ -105,6 +105,7 @@ public class ForgottenPasswordServlet extends PwmServlet {
         tokenChoice(HttpMethod.POST),
         verificationChoice(HttpMethod.POST),
         enterNaafResponse(HttpMethod.POST),
+        enterRemoteResponse(HttpMethod.POST),
 
         ;
 
@@ -210,6 +211,10 @@ public class ForgottenPasswordServlet extends PwmServlet {
                     this.processEnterNaaf(pwmRequest);
                     break;
 
+                case enterRemoteResponse:
+                    this.processEnterRemote(pwmRequest);
+                    break;
+
             }
         } else {
             pwmRequest.getPwmSession().clearForgottenPasswordBean();
@@ -457,6 +462,45 @@ public class ForgottenPasswordServlet extends PwmServlet {
         }
     }
 
+    private void processEnterRemote(final PwmRequest pwmRequest)
+            throws PwmUnrecoverableException, IOException, ServletException
+    {
+        final String PREFIX = "remote-";
+        final ForgottenPasswordBean forgottenPasswordBean = pwmRequest.getPwmSession().getForgottenPasswordBean();
+        final RecoveryVerificationMethod remoteRecoveryMethod = forgottenPasswordBean.getProgress().getRemoteRecoveryMethod();
+
+        final Map<String,String> remoteResponses = new LinkedHashMap<>();
+        {
+            final Map<String,String> inputMap = pwmRequest.readParametersAsMap();
+            for (final String name : inputMap.keySet()) {
+                if (name != null && name.startsWith(PREFIX)) {
+                    final String strippedName = name.substring(PREFIX.length(), name.length());
+                    final String value = inputMap.get(name);
+                    remoteResponses.put(strippedName, value);
+                }
+            }
+        }
+
+        final ErrorInformation errorInformation = remoteRecoveryMethod.respondToPrompts(remoteResponses);
+
+        if (remoteRecoveryMethod.getVerificationState() == RecoveryVerificationMethod.VerificationState.COMPLETE) {
+            forgottenPasswordBean.getProgress().getSatisfiedMethods().add(RecoveryVerificationMethods.REMOTE_RESPONSES);
+        }
+
+        if (remoteRecoveryMethod.getVerificationState() == RecoveryVerificationMethod.VerificationState.FAILED) {
+            forgottenPasswordBean.getProgress().setNaafRecoveryMethod(null);
+            pwmRequest.respondWithError(errorInformation,true);
+            handleUserVerificationBadAttempt(pwmRequest, forgottenPasswordBean, errorInformation);
+            LOGGER.debug(pwmRequest, "unsuccessful remote response verification input: " + errorInformation.toDebugStr());
+            return;
+        }
+
+        if (errorInformation != null) {
+            pwmRequest.setResponseError(errorInformation);
+            handleUserVerificationBadAttempt(pwmRequest, forgottenPasswordBean, errorInformation);
+        }
+    }
+
     private void processEnterOtpToken(final PwmRequest pwmRequest)
             throws IOException, ServletException, PwmUnrecoverableException, ChaiUnavailableException
     {
@@ -620,6 +664,10 @@ public class ForgottenPasswordServlet extends PwmServlet {
                     + "progress=" + JsonUtil.serialize(progress));
         }
 
+        if (forgottenPasswordProfile == null) {
+            throw new PwmUnrecoverableException(new ErrorInformation(PwmError.ERROR_NO_PROFILE_ASSIGNED));
+        }
+
 
         // check for previous authentication
         if (recoveryFlags.getRequiredAuthMethods().contains(RecoveryVerificationMethods.PREVIOUS_AUTH) || recoveryFlags.getOptionalAuthMethods().contains(RecoveryVerificationMethods.PREVIOUS_AUTH)) {
@@ -1411,7 +1459,32 @@ public class ForgottenPasswordServlet extends PwmServlet {
             }
             break;
 
-            case NAAF:
+            case REMOTE_RESPONSES: {
+                final RecoveryVerificationMethod remoteMethod;
+                if (forgottenPasswordBean.getProgress().getRemoteRecoveryMethod() == null) {
+                    remoteMethod = new RemoteVerificationMethod();
+                    remoteMethod.init(
+                            pwmRequest.getPwmApplication(),
+                            forgottenPasswordBean.getUserInfo(),
+                            pwmRequest.getSessionLabel(),
+                            pwmRequest.getLocale()
+                    );
+                    forgottenPasswordBean.getProgress().setRemoteRecoveryMethod(remoteMethod);
+                } else {
+                    remoteMethod = forgottenPasswordBean.getProgress().getRemoteRecoveryMethod();
+                }
+
+                final List<RecoveryVerificationMethod.UserPrompt> prompts = remoteMethod.getCurrentPrompts();
+                final String displayInstructions = remoteMethod.getCurrentDisplayInstructions();
+
+                pwmRequest.setAttribute(PwmConstants.REQUEST_ATTR.ForgottenPasswordPrompts, new ArrayList<>(prompts));
+                pwmRequest.setAttribute(PwmConstants.REQUEST_ATTR.ForgottenPasswordInstructions, displayInstructions);
+                pwmRequest.forwardToJsp(PwmConstants.JSP_URL.RECOVER_PASSWORD_REMOTE);
+            }
+            break;
+
+
+            case NAAF: {
                 final RecoveryVerificationMethod naafMethod;
                 if (forgottenPasswordBean.getProgress().getNaafRecoveryMethod() == null) {
                     naafMethod = new PwmNAAFVerificationMethod();
@@ -1432,8 +1505,8 @@ public class ForgottenPasswordServlet extends PwmServlet {
                 pwmRequest.setAttribute(PwmConstants.REQUEST_ATTR.ForgottenPasswordPrompts, new ArrayList<>(prompts));
                 pwmRequest.setAttribute(PwmConstants.REQUEST_ATTR.ForgottenPasswordInstructions, displayInstructions);
                 pwmRequest.forwardToJsp(PwmConstants.JSP_URL.RECOVER_PASSWORD_NAAF);
-
-                break;
+            }
+            break;
 
             default:
                 throw new UnsupportedOperationException("unexpected method during forward: " + method.toString());
@@ -1471,32 +1544,113 @@ public class ForgottenPasswordServlet extends PwmServlet {
         pwmRequest.forwardToJsp(PwmConstants.JSP_URL.RECOVER_PASSWORD_SEARCH);
     }
 
-    static class Na implements RecoveryVerificationMethod {
+    public static class RemoteVerificationMethod implements RecoveryVerificationMethod {
+
+        private String remoteSesionID = PwmRandom.getInstance().randomUUID().toString();
+
+        private RemoteVerificationResponseBean lastResponse;
+        private PwmHttpClient pwmHttpClient;
+        private PwmApplication pwmApplication;
+
+        private UserInfoBean userInfoBean;
+        private SessionLabel sessionLabel;
+        private Locale locale;
+        private String url;
+
         @Override
         public List<UserPrompt> getCurrentPrompts() throws PwmUnrecoverableException {
-            return null;
+            if (lastResponse == null || lastResponse.getUserPrompts() == null) {
+                return null;
+            }
+
+            final List<UserPrompt> returnObj = new ArrayList<>();
+            for (final UserPromptBean userPromptBean : lastResponse.getUserPrompts()) {
+                returnObj.add(userPromptBean);
+            }
+            return returnObj;
         }
 
         @Override
         public String getCurrentDisplayInstructions() {
-            return null;
+            return lastResponse == null
+                    ? ""
+                    : lastResponse.getDisplayInstructions();
         }
 
         @Override
         public ErrorInformation respondToPrompts(Map<String, String> answers) throws PwmUnrecoverableException {
+            sendRemoteRequest(answers);
+            if (lastResponse != null) {
+                final String errorMsg = lastResponse.getErrorMessage();
+                if (errorMsg != null && !errorMsg.isEmpty()) {
+                    return new ErrorInformation(PwmError.ERROR_REMOTE_ERROR_VALUE,errorMsg);
+                }
+            }
             return null;
         }
 
         @Override
         public VerificationState getVerificationState() {
-            return null;
+            return lastResponse == null
+                    ? VerificationState.INPROGRESS
+                    : lastResponse.getVerificationState();
         }
 
         @Override
         public void init(PwmApplication pwmApplication, UserInfoBean userInfoBean, SessionLabel sessionLabel, Locale locale) throws PwmUnrecoverableException {
+            pwmHttpClient = new PwmHttpClient(pwmApplication, sessionLabel);
+            this.userInfoBean = userInfoBean;
+            this.sessionLabel = sessionLabel;
+            this.locale = locale;
+            this.pwmApplication = pwmApplication;
+            this.url = pwmApplication.getConfig().readSettingAsString(PwmSetting.EXTERNAL_MACROS_REMOTE_RESPONSES_URL);
+
+            if (url == null || url.isEmpty()) {
+                final String errorMsg = PwmSetting.EXTERNAL_MACROS_REMOTE_RESPONSES_URL.toMenuLocationDebug(null,PwmConstants.DEFAULT_LOCALE)
+                        + " must be configured for remote responses";
+                final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_INVALID_CONFIG,errorMsg);
+                LOGGER.error(sessionLabel,errorInformation);
+                throw new PwmUnrecoverableException(errorInformation);
+            }
 
+            sendRemoteRequest(null);
+        }
+
+        private void sendRemoteRequest(final Map<String,String> userResponses) throws PwmUnrecoverableException {
+            lastResponse = null;
+
+            final Map<String,String> headers = new LinkedHashMap<>();
+            headers.put(PwmConstants.HttpHeader.Content_Type.getHttpName(), PwmConstants.ContentTypeValue.json.getHeaderValue());
+            headers.put(PwmConstants.HttpHeader.Accept_Language.getHttpName(), locale.toLanguageTag());
+
+            RemoteVerificationRequestBean remoteVerificationRequestBean = new RemoteVerificationRequestBean();
+            remoteVerificationRequestBean.setResponseSessionID(this.remoteSesionID);
+            remoteVerificationRequestBean.setUserInfo(PublicUserInfoBean.fromUserInfoBean(userInfoBean, pwmApplication.getConfig(), locale));
+            remoteVerificationRequestBean.setUserResponses(userResponses);
+
+            PwmHttpClientRequest pwmHttpClientRequest = new PwmHttpClientRequest(
+                    HttpMethod.POST,
+                    url,
+                    JsonUtil.serialize(remoteVerificationRequestBean),
+                    headers
+            );
+
+            try {
+                final PwmHttpClientResponse response = pwmHttpClient.makeRequest(pwmHttpClientRequest);
+                final String responseBodyStr = response.getBody();
+                this.lastResponse = JsonUtil.deserialize(responseBodyStr, RemoteVerificationResponseBean.class);
+            } catch (PwmException e) {
+                LOGGER.error(sessionLabel,e.getErrorInformation());
+                throw new PwmUnrecoverableException(e.getErrorInformation());
+            } catch (Exception e) {
+                final String errorMsg = "error reading remote responses web service response: " + e.getMessage();
+                final ErrorInformation errorInformation = new ErrorInformation(PwmError.ERROR_SERVICE_NOT_AVAILABLE,errorMsg);
+                LOGGER.error(sessionLabel,errorInformation);
+                throw new PwmUnrecoverableException(errorInformation);
+            }
         }
     }
+
 }
 
 

+ 3 - 3
pwm/servlet/src/password/pwm/http/servlet/NewUserServlet.java

@@ -851,7 +851,9 @@ public class NewUserServlet extends PwmServlet {
             break;
 
             case EMAIL: {
-                final String toAddress = tokenPayloadMap.get(config.readSettingAsString(PwmSetting.EMAIL_USER_MAIL_ATTRIBUTE));
+                final EmailItemBean configuredEmailSetting = config.readSettingAsEmail(
+                        PwmSetting.EMAIL_NEWUSER_VERIFICATION, pwmSession.getSessionStateBean().getLocale());
+                final String toAddress = macroMachine.expandMacros(configuredEmailSetting.getTo());
 
                 final RestTokenDataClient.TokenDestinationData inputTokenDestData = new RestTokenDataClient.TokenDestinationData(
                         toAddress, null, null);
@@ -881,8 +883,6 @@ public class NewUserServlet extends PwmServlet {
                 newUserBean.setVerificationPhase(NewUserBean.NewUserVerificationPhase.EMAIL);
                 newUserBean.setTokenDisplayText(outputDestTokenData.getDisplayValue());
 
-                final EmailItemBean configuredEmailSetting = config.readSettingAsEmail(
-                        PwmSetting.EMAIL_NEWUSER_VERIFICATION, pwmSession.getSessionStateBean().getLocale());
                 final EmailItemBean emailItemBean = new EmailItemBean(
                         outputDestTokenData.getEmail(),
                         configuredEmailSetting.getFrom(),

+ 9 - 0
pwm/servlet/src/password/pwm/i18n/Config.properties

@@ -139,3 +139,12 @@ Tooltip_FormOptions_Regex=Apply a regular expression pattern to the value.  The
 Tooltip_FormOptions_RegexError=Error message to show when the regular expression pattern is not matched.
 Tooltip_FormOptions_Placeholder=Placeholder text to display in the form field with the field is not populated with a value.
 Tooltip_FormOptions_Javascript=Javascript to be added to the browser.
+VerificationMethodDetail_PREVIOUS_AUTH=This method is passed when a user has previously authenticated using their browser.  There is no user interaction or display associated with this method.
+VerificationMethodDetail_ATTRIBUTES=User will be prompted for LDAP attribute values defined by the setting @PwmSettingReference:challenge.requiredAttributes@
+VerificationMethodDetail_CHALLENGE_RESPONSES=Challenge/Response questions and answers.
+VerificationMethodDetail_TOKEN=An Email and/or SMS token is sent to the user for validation.  See @PwmSettingReference:challenge.token.sendMethod@.
+VerificationMethodDetail_OTP=TOTP authentication.  Referred to on user screens as "Mobile App Authentication".
+VerificationMethodDetail_REMOTE_RESPONSES=Utilize a configured web service for user response verification.   See @PwmSettingReference:external.remoteResponses.url@.
+VerificationMethodDetail_NAAF=NetIQ Advanced Authentication Framework
+
+

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
pwm/servlet/src/password/pwm/i18n/ConfigEditor.properties


+ 153 - 148
pwm/servlet/src/password/pwm/i18n/Error_zh.properties

@@ -1,148 +1,153 @@
-#
-# Password Management Servlets (PWM)
-# http://code.google.com/p/pwm/
-#
-# Copyright (c) 2006-2009 Novell, Inc.
-# Copyright (c) 2009-2014 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
-#
-
-EventLog_ActivateUser=\u6fc0\u6d3b\u7528\u6237
-EventLog_Authenticate=\u8ba4\u8bc1
-EventLog_ChangePassword=\u4fee\u6539\u5bc6\u7801
-EventLog_CreateUser=\u521b\u5efa\u8d26\u6237
-EventLog_FatalEvent=\u4e25\u91cd\u4e8b\u4ef6
-EventLog_HelpdeskAction=\u670d\u52a1\u53f0\u52a8\u4f5c
-EventLog_HelpdeskClearOtpSecret=\u670d\u52a1\u53f0\u6d88\u9664 OTP \u673a\u5bc6
-EventLog_HelpdeskClearResponses=\u670d\u52a1\u53f0\u6e05\u9664\u5e94\u7b54
-EventLog_HelpdeskSetPassword=\u670d\u52a1\u53f0\u8bbe\u7f6e\u5bc6\u7801
-EventLog_HelpdeskUnlockPassword=\u670d\u52a1\u53f0\u89e3\u9501\u5bc6\u7801
-EventLog_IntruderLockout=\u5165\u4fb5\u8005\u9501\u5b9a
-EventLog_ModifyConfiguration=\u914d\u7f6e\u5df2\u4fee\u6539
-EventLog_RecoverPassword=\u6062\u590d\u5fd8\u8bb0\u7684\u5bc6\u7801
-EventLog_SetupResponses=\u8bbe\u7f6e\u5bc6\u7801\u5e94\u7b54
-EventLog_Shutdown=\u5173\u95ed\u5e94\u7528\u7a0b\u5e8f
-EventLog_Startup=\u542f\u52a8\u5e94\u7528\u7a0b\u5e8f
-EventLog_TokenClaimed=\u4ee4\u724c\u6388\u6743
-EventLog_TokenIssued=\u5df2\u7b7e\u53d1\u7684\u4ee4\u724c
-EventLog_UpdateProfile=\u66f4\u65b0\u5c5e\u6027
-Eventlog_SetupOtpSecret=\u8bbe\u7f6e OTP \u673a\u5bc6
-Requirement_ADComplexity=\u5fc5\u987b\u6709\u81f3\u5c11\u4e09\u79cd\u7c7b\u578b\u7684\u4e0b\u5217\u5b57\u7b26\uff1a<ul> <li>\u5927\u5199\u5b57\u6bcd\uff08A-Z\uff09</li> <li>\u5c0f\u5199\u5b57\u6bcd\uff08a-z\uff09</ li> <li>\u6570\u5b57\uff080-9\uff09</ li><li>\u7b26\u53f7\uff08\uff01\uff0c\uff03\uff0c$\u7b49\uff09</li></ul>
-Requirement_AllowNumeric=\u4e0d\u5f97\u5305\u62ec\u4efb\u4f55\u6570\u5b57\u5b57\u7b26\u3002
-Requirement_AllowSpecial=\u4e0d\u5f97\u5305\u62ec\u4efb\u4f55 (\u975e\u5b57\u6bcd\u6216\u8005\u975e\u6570\u5b57)\u5b57\u7b26\u3002
-Requirement_CaseSensitive=\u5bc6\u7801\u533a\u5206\u5927\u5c0f\u5199\u3002
-Requirement_DisAllowedAttributes=\u4e0d\u80fd\u5305\u62ec\u60a8\u7684\u59d3\u540d\u6216\u7528\u6237\u540d\u7684\u4e00\u90e8\u5206\u3002
-Requirement_DisAllowedValues=\u4e0d\u5f97\u5305\u62ec\u4efb\u4f55\u4ee5\u4e0b\u7684\u503c\uff1a: %1%
-Requirement_FirstNumeric=\u7b2c\u4e00\u4e2a\u5b57\u7b26\u4e0d\u80fd\u4e3a\u6570\u5b57\u3002
-Requirement_FirstSpecial=\u7b2c\u4e00\u4e2a\u5b57\u7b26\u4e0d\u80fd\u4e3a(\u975e\u5b57\u6bcd\u6216\u8005\u975e\u6570\u5b57)\u5b57\u7b26\u3002
-Requirement_LastNumeric=\u6700\u540e\u4e00\u4e2a\u5b57\u7b26\u4e0d\u80fd\u4e3a\u6570\u5b57\u3002
-Requirement_LastSpecial=\u6700\u540e\u4e00\u4e2a\u5b57\u7b26\u4e0d\u80fd\u4e3a(\u975e\u5b57\u6bcd\u6216\u8005\u975e\u6570\u5b57\u5b57\u7b26)\u3002
-Requirement_MaxAlpha=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u5b57\u6bcd\u3002
-Requirement_MaxAlphaPlural=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u5b57\u6bcd\u3002
-Requirement_MaxLength=\u5fc5\u987b\u4e0d\u8d85\u8fc7 %1% \u4e2a\u5b57\u8282\u957f\u5ea6\u3002
-Requirement_MaxLengthPlural=\u5fc5\u987b\u4e0d\u8d85\u8fc7 %1% \u4e2a\u5b57\u8282\u957f\u5ea6\u3002
-Requirement_MaxLower=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u5c0f\u5199\u5b57\u6bcd\u3002
-Requirement_MaxLowerPlural=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u5c0f\u5199\u5b57\u6bcd\u3002
-Requirement_MaxNumeric=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u6570\u5b57\u3002
-Requirement_MaxNumericPlural=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u6570\u5b57\u3002
-Requirement_MaxRepeat=\u4efb\u4f55\u5b57\u7b26\u4e0d\u5f97\u91cd\u590d\u8d85\u8fc7 %1% \u6b21\u3002
-Requirement_MaxRepeatPlural=\u4efb\u4f55\u5b57\u7b26\u4e0d\u5f97\u91cd\u590d\u8d85\u8fc7 %1% \u6b21\u3002
-Requirement_MaxSeqRepeat=\u4efb\u4f55\u76f8\u540c\u7684\u5b57\u7b26\u6392\u5217\u987a\u5e8f\u4e0d\u5f97\u91cd\u590d\u8d85\u8fc7 %1% \u6b21\u3002
-Requirement_MaxSeqRepeatPlural=\u4efb\u4f55\u76f8\u540c\u7684\u5b57\u7b26\u6392\u5217\u987a\u5e8f\u4e0d\u5f97\u91cd\u590d\u8d85\u8fc7 %1% \u6b21\u3002
-Requirement_MaxSpecial=\u4e0d\u80fd\u5305\u62ec\u591a\u4e8e%1% \u4e2a(\u975e\u5b57\u6bcd\u6216\u8005\u975e\u6570\u5b57)\u5b57\u7b26\u3002
-Requirement_MaxSpecialPlural=\u4e0d\u80fd\u5305\u62ec\u591a\u4e8e%1% \u4e2a(\u975e\u5b57\u6bcd\u6216\u8005\u975e\u6570\u5b57)\u5b57\u7b26\u3002
-Requirement_MaxUpper=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u5927\u5199\u5b57\u6bcd\u3002
-Requirement_MaxUpperPlural=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u5927\u5199\u5b57\u6bcd\u3002
-Requirement_MinAlpha=\u5fc5\u987b\u81f3\u5c11\u5305\u62ec %1% \u4e2a\u5b57\u6bcd\u3002
-Requirement_MinAlphaPlural=\u5fc5\u987b\u81f3\u5c11\u5305\u62ec %1% \u4e2a\u5b57\u6bcd\u3002
-Requirement_MinLength=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u5b57\u8282\u957f\u5ea6\u3002
-Requirement_MinLengthPlural=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u5b57\u8282\u957f\u5ea6\u3002
-Requirement_MinLower=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u5c0f\u5199\u5b57\u6bcd\u3002
-Requirement_MinLowerPlural=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u5c0f\u5199\u5b57\u6bcd\u3002
-Requirement_MinNumeric=\u5fc5\u987b\u81f3\u5c11\u5305\u62ec %1% \u4e2a\u6570\u5b57\u3002
-Requirement_MinNumericPlural=\u5fc5\u987b\u81f3\u5c11\u5305\u62ec %1% \u4e2a\u6570\u5b57\u3002
-Requirement_MinSpecial=\u5fc5\u987b\u6709\u81f3\u5c11 %1% \u4e2a (\u975e\u5b57\u6bcd\u6216\u8005\u975e\u6570\u5b57)\u5b57\u7b26\u3002
-Requirement_MinSpecialPlural=\u5fc5\u987b\u6709\u81f3\u5c11 %1% \u4e2a (\u975e\u5b57\u6bcd\u6216\u8005\u975e\u6570\u5b57)\u5b57\u7b26\u3002
-Requirement_MinUnique=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u72ec\u7279\u5b57\u7b26\u3002
-Requirement_MinUniquePlural=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u72ec\u7279\u5b57\u7b26\u3002
-Requirement_MinUpper=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u5927\u5199\u5b57\u6bcd\u3002
-Requirement_MinUpperPlural=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u5927\u5199\u5b57\u6bcd\u3002
-Requirement_MinimumFrequency=\u662f\u53ef\u4ee5\u66f4\u6539\u7684\uff0c\u4f46\u662f\u81f3\u5c11\u8981\u95f4\u9694%1%\u3002
-Requirement_NotCaseSensitive=\u5bc6\u7801\u4e0d\u533a\u5206\u5927\u5c0f\u5199\u3002
-Requirement_OldChar=\u4e0d\u5f97\u6709\u8d85\u8fc7 %1% \u4e2a\u65e7\u5bc6\u7801\u6240\u4f7f\u7528\u7684\u5b57\u7b26\u3002
-Requirement_OldCharPlural=\u4e0d\u5f97\u6709\u8d85\u8fc7 %1% \u4e2a\u65e7\u5bc6\u7801\u6240\u4f7f\u7528\u7684\u5b57\u7b26\u3002
-Requirement_RequiredChars=\u5fc5\u987b\u81f3\u5c11\u5305\u62ec\u5404\u4e00\u4e2a\u4ee5\u4e0b\u7684\u5b57\u7b26\uff1a
-Requirement_UniqueRequired=\u65b0\u7684\u5bc6\u7801\u53ef\u80fd\u5c1a\u672a\u4f7f\u7528\u8fc7\u3002
-Requirement_WordList=\u4e0d\u5f97\u5305\u62ec\u4e00\u4e2a\uf5e38\u7528\u8bcd\u6216\u8005\u5e38\u7528\u7684\u5b57\u7b26\u987a\u5e8f\u6392\u5217\u3002
-Rule_ADComplexity=AD Complexity
-Rule_AllowFirstCharNumeric=Allow First Character Numeric
-Rule_AllowFirstCharSpecial=Allow First Character Special
-Rule_AllowLastCharNumeric=Allow Last Character Numeric
-Rule_AllowLastCharSpecial=Allow Last Character Special
-Rule_AllowNumeric=Allow Numeric
-Rule_AllowSpecial=Allow Special
-Rule_CaseSensitive=Case Sensitive
-Rule_ChallengeResponseEnabled=Challenge Response Enabled
-Rule_ChangeMessage=Change Message
-Rule_DisallowCurrent=Disallow Current
-Rule_DisallowedAttributes=Disallowed Attributes
-Rule_DisallowedValues=Disallowed Values
-Rule_EnableWordlist=Enable Wordlist
-Rule_EnforceAtLogin=Enforce At Login
-Rule_ExpirationInterval=Expiration Interval
-Rule_MaximumAlpha=Maximum Alpha
-Rule_MaximumLength=Maximum Length
-Rule_MaximumLowerCase=Maximum Lower Case
-Rule_MaximumNonAlpha=Maximum Non-Alpha
-Rule_MaximumNumeric=Maximum Numeric
-Rule_MaximumOldChars=Maximum Old Characters
-Rule_MaximumRepeat=Maximum Repeat
-Rule_MaximumSequentialRepeat=Maximum Sequential Repeat
-Rule_MaximumSpecial=Maximum Special
-Rule_MaximumUnique=Maximum Unique
-Rule_MaximumUpperCase=Maximum Upper Case
-Rule_MinimumAlpha=Minimum Alpha
-Rule_MinimumLength=Minimum Length
-Rule_MinimumLifetime=Minimum Lifetime
-Rule_MinimumLowerCase=Minimum Lower Case
-Rule_MinimumNonAlpha=Minimum Non-Alpha
-Rule_MinimumNumeric=Minimum Numeric
-Rule_MinimumSpecial=Minimum Special
-Rule_MinimumStrength=Minimum Strength
-Rule_MinimumUnique=Minimum Unique
-Rule_MinimumUpperCase=Minimum Upper Case
-Rule_PolicyEnabled=Policy Enabled
-Rule_RegExMatch=Regular Expression Match
-Rule_RegExNoMatch=Regular Expression No Match
-Rule_UniqueRequired=Unique Required
-Success_Action=\u5df2\u7ecf\u6210\u529f\u5b8c\u6210 %1%.
-Success_ActivateUser=\u4f60\u7684\u7528\u6237\u5e10\u6237\u6210\u529f\u88ab\u6fc0\u6d3b\u3002\u8bf7\u786e\u4fdd\u5b8c\u6210\u8fd9\u4e00\u7a0b\u5e8f\uff0c\u5426\u5219\u4f60\u5c06\u65e0\u6cd5\u8fdb\u5165\u4f60\u7684\u65b0\u5e10\u6237\u3002
-Success_ClearResponse=\u60a8\u7684\u673a\u5bc6\u95ee\u9898\u548c\u7b54\u6848\u5df2\u6210\u529f\u88ab\u79fb\u9664.
-Success_ConfigFileUpload=\u914d\u7f6e\u6587\u4ef6\u5df2\u6210\u529f\u4e0a\u4f20\u3002
-Success_CreateGuest=\u65b0\u8bbf\u5ba2\u5e10\u6237\u5df2\u6210\u529f\u521b\u5efa\u3002\u5982\u679c\u5df2\u8f93\u5165\u7535\u5b50\u90ae\u4ef6\u5730\u5740\uff0c\u8bbf\u5ba2\u7528\u6237\u5c06\u6536\u5230\u901a\u77e5\u3002\u8bbf\u5ba2\u5e10\u6237\uff0c\u53ef\u80fd\u8fd8\u9700\u8981\u6fc0\u6d3b\u3002
-Success_CreateUser=\u4f60\u7684\u65b0\u7528\u6237\u5e10\u6237\u521b\u5efa\u6210\u529f\u3002\u8bf7\u786e\u4fdd\u7ee7\u7eed\u6267\u884c\u6709\u5173\u7a0b\u5e8f\uff0c\u5426\u5219\u4f60\u5c06\u65e0\u6cd5\u8fdb\u5165\u4f60\u7684\u65b0\u5e10\u6237\u3002
-Success_ForgottenUsername=\u60a8\u7684\u7528\u6237\u540d\u662f %1%\u3002\u8bf7\u8bb0\u5f55\u4f60\u7684\u7528\u6237\u540d\u4ee5\u4f9b\u5c06\u6765\u4f7f\u7528\u3002
-Success_NewUserForm=\u51c6\u5907\u8981\u521b\u5efa\u60a8\u7684\u5e10\u6237\u3002\u51c6\u5907\u597d\u65f6\u8bf7\u7ee7\u7eed\u3002
-Success_PasswordChange=\u60a8\u7684\u5bc6\u7801\u5df2\u7ecf\u66f4\u6539\u6210\u529f\u3002<br/> <b>\u6ce8\u610f\uff01</b> \u60a8\u7684\u5bc6\u7801\u5df2\u7ecf\u4e0d\u518d\u4e0e Windows \u5de5\u4f5c\u7ad9\u7684\u4e00\u81f4\u3002\u8981\u66f4\u6539\u60a8\u7684\u5de5\u4f5c\u7ad9\u5bc6\u7801\uff0c\u8bf7\u6309 CTRL-ALT-DEL \u5e76\u9009\u62e9\u66f4\u6539\u5bc6\u7801\u3002
-Success_PasswordReset=\u5df2\u6210\u529f\u4e3a%1%\u8bbe\u7f6e\u5bc6\u7801\u3002
-Success_PasswordSend=\u5df2\u5c06\u60a8\u7684\u65b0\u5bc6\u7801\u4f20\u9001%1%\u3002\u8bf7\u5173\u95ed\u6b64\u7a97\u53e3\uff0c\u7136\u540e\u4f7f\u7528\u60a8\u7684\u65b0\u5bc6\u7801\u767b\u9646\u3002
-Success_ResponsesMeetRules=\u60a8\u7684\u5e94\u7b54\u6ee1\u8db3\u8981\u6c42\u3002\u8bf7\u70b9\u51fb\u4fdd\u5b58\u5e94\u7b54\u3002
-Success_SetupResponse=\u5df2\u6210\u529f\u4fdd\u5b58\u60a8\u7684\u673a\u5bc6\u95ee\u9898\u548c\u7b54\u6848\u3002\u5982\u679c\u4f60\u5fd8\u8bb0\u4f60\u7684\u5bc6\u7801\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528\u8fd9\u4e9b\u95ee\u9898\u7684\u7b54\u6848\u91cd\u8bbe\u5bc6\u7801\u3002
-Success_Unknown=\u6210\u529f\u5b8c\u6210\u64cd\u4f5c\u3002
-Success_UnlockAccount=\u60a8\u7684\u5e10\u6237\u5df2\u88ab\u9501\u5b9a\u3002
-Success_UpdateForm=\u53ef\u4ee5\u5f00\u59cb\u66f4\u65b0\u60a8\u7684\u8bbe\u5b9a\u3002\u51c6\u5907\u597d\u662f\u8bf7\u7ee7\u7eed\u3002
-Success_UpdateGuest=\u6765\u5bbe\u5e10\u6237\u5df2\u6210\u529f\u66f4\u65b0\u3002\u5982\u679c\u5df2\u8f93\u5165\u7535\u5b50\u90ae\u4ef6\u5730\u5740\uff0c\u6765\u5bbe\u7528\u6237\u5c06\u6536\u5230\u901a\u77e5\u3002
-Success_UpdateProfile=\u60a8\u7684\u7528\u6237\u4fe1\u606f\u5df2\u6210\u529f\u66f4\u65b0\u3002
+#
+# Password Management Servlets (PWM)
+# http://code.google.com/p/pwm/
+#
+# Copyright (c) 2006-2009 Novell, Inc.
+# Copyright (c) 2009-2014 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
+#
+
+ Error_AccountDisabled=\u8d26\u6237\u4e0d\u53ef\u7528.
+ Error_AccountExpired=\u8d26\u6237\u5df2\u8fc7\u671f.
+ Error_ActivateUserNoQueryMatch=\u4f60\u7684\u7528\u6237\u5e10\u6237\u4e0d\u5177\u6709\u88ab\u6fc0\u6d3b\u7684\u8d44\u683c
+ Error_Activation=\u4f7f\u7528\u60a8\u6240\u63d0\u4f9b\u7684\u4fe1\u606f\uff0c\u65e0\u6cd5\u6fc0\u6d3b\u60a8\u7684\u5e10\u6237\u3002\u8bf7\u518d\u8bd5\u4e00\u6b21\u3002
+ Error_ActivationValidationFailed=\u4e00\u4e2a\u6216\u591a\u4e2a\u503c\u4e0d\u6b63\u786e\u3002
+ Error_Activation_Failure=\u6fc0\u6d3b\u60a8\u7684\u5e10\u6237\u65f6\u53d1\u751f\u9519\u8bef\u3002\u8bf7\u4e0e\u7ba1\u7406\u5458\u8054\u7cfb\u3002
+ Error_AddressIntruder=\u5df2\u7ecf\u8d85\u8fc7IP\u5730\u5740\u7684\u6700\u591a\u5141\u8bb8\u5c1d\u8bd5\u767b\u9646\u6b21\u6570\u3002\u8bf7\u7a0d\u540e\u518d\u8bd5.
+ Error_App_Unavailable=\u65e0\u6cd5\u4f7f\u7528\u6216\u8005\u6b63\u5728\u91cd\u542f\u8be5\u5e94\u7528\u7a0b\u5e8f\u3002\u82e5\u6b64\u9519\u8bef\u91cd\u590d\u53d1\u751f\uff0c\u8bf7\u60a8\u8054\u7cfb\u670d\u52a1\u53f0\u3002
+ Error_AttrIntruder=\u60a8\u7684\u641c\u7d22\u6b21\u6570\u5df2\u8d85\u8fc7\u4e0a\u9650\uff0c\u8bf7\u7a0d\u540e\u518d\u8bd5\u3002
+ Error_AuditWrite=\u65e0\u6cd5\u5199\u5165\u5ba1\u67e5\u8bb0\u5f55.
+ Error_AuthenticationRequired=\u9700\u8981\u5bf9\u8eab\u4efd\u8fdb\u884c\u9274\u522b
+ Error_BadCaptchaResponse=\u9a8c\u8bc1\u7801\u4e0d\u6b63\u786e\uff0c\u8bf7\u518d\u8bd5\u4e00\u6b21\u3002
+ Error_BadCurrentPassword=\u5f53\u524d\u5bc6\u7801\u4e0d\u6b63\u786e\uff0c\u8bf7\u518d\u8bd5\u4e00\u6b21\u3002
+ Error_BadSession=\u60a8\u7684\u6d4f\u89c8\u5668\u65e0\u6cd5\u5efa\u7acb\u4e00\u4e2a\u4f1a\u8bdd\u3002\u8bf7\u5173\u95ed\u6d4f\u89c8\u5668\u5e76\u518d\u6b21\u5c1d\u8bd5\u3002
+ Error_BadSessionPassword=\u65e0\u6cd5\u5efa\u7acb\u4f1a\u8bdd\u5bc6\u7801\u3002
+ Error_CantMatchUser=\u6ca1\u6709\u627e\u5230\u7528\u6237\u540d
+ Error_CaptchaAPIError=\u9a8c\u8bc1\u9a8c\u8bc1\u7801\u5e94\u7b54\u65f6\u53d1\u751f\u9519\u8bef\u3002\u8bf7\u5173\u95ed\u60a8\u7684\u6d4f\u89c8\u5668\uff0c\u7136\u540e\u518d\u8bd5\u4e00\u6b21\u3002\u5982\u679c\u8fd9\u4e2a\u9519\u8bef\u53cd\u590d\u51fa\u73b0\uff0c\u8bf7\u8054\u7cfb\u670d\u52a1\u53f0\u3002
+ Error_CertificateError=\u53d1\u751f\u8bc1\u4e66\u9519\u8bef: %1%.
+ Error_ChallengeInResponse=\u95ee\u9898 "%1%"\u7684\u56de\u7b54\u4e0d\u80fd\u5305\u542b\u95ee\u9898\u672c\u8eab\u7684\u6587\u5b57\u3002
+ Error_Challenge_Duplicate=\u6bcf\u4e00\u4e2a\u95ee\u9898\u90fd\u5fc5\u987b\u662f\u552f\u4e00\u7684\u3002
+ Error_Clearing_Responses=\u6e05\u7406\u5e94\u7b54\u95ee\u9898\u7684\u8fc7\u7a0b\u4e2d\u53d1\u751f\u9519\u8bef\u3002\u8bf7\u4e0e\u7ba1\u7406\u5458\u8054\u7cfb\u3002
+ Error_Closing=\u64cd\u4f5c\u65e0\u6cd5\u5b8c\u6210\uff0c\u56e0\u4e3aPWM\u88ab\u5173\u505c\u3002
+ Error_ConfigFormatError=\u914d\u7f6e\u683c\u5f0f\u9519\u8bef\uff1a%1%\u3002
+ Error_ConfigLdapFailure=\u65e0\u6cd5\u8fde\u63a5\u5230LDAP\u76ee\u5f55\u670d\u52a1\u5668\uff1a%1%
+ Error_ConfigLdapSuccess=\u6210\u529f\u8fde\u63a5\u5230LDAP\u76ee\u5f55\u670d\u52a1\u5668
+ Error_ConfigSaveSuccess=\u914d\u7f6e\u4fdd\u5b58\u6210\u529f\u3002 \u5df2\u63d0\u4ea4PWM\u91cd\u65b0\u542f\u52a8\u8bf7\u6c42\u3002\u91cd\u65b0\u542f\u52a8\u65f6\uff0cPWM\u53ef\u80fd\u4e0d\u53ef\u7528\u3002\u5982\u679c\u91cd\u65b0\u542f\u52a8\u8bf7\u6c42\u5931\u8d25\uff0c\u60a8\u53ef\u80fd\u9700\u8981\u624b\u52a8\u91cd\u65b0\u542f\u52a8PWM\u3002
+ Error_ConfigUploadFailure=\u6587\u4ef6\u4e0a\u4f20\u5931\u8d25\uff1a%1%
+ Error_ConfigUploadSuccess=\u6587\u4ef6\u4e0a\u4f20\u6210\u529f
+ Error_DB_Unavailable=\u6570\u636e\u5e93\u4e0d\u53ef\u7528\u3002\u5982\u679c\u8fd9\u4e2a\u9519\u8bef\u53cd\u590d\u51fa\u73b0\uff0c\u8bf7\u8054\u7cfb\u60a8\u7684\u670d\u52a1\u53f0\u3002
+ Error_DirectoryUnavailable=\u65e0\u6cd5\u4f7f\u7528\u76ee\u5f55
+ Error_FieldBadConfirm=%1% \u680f\u76ee\u4e0d\u7b26
+ Error_FieldDuplicate=%1% \u5df2\u7ecf\u88ab\u4f7f\u7528
+ Error_FieldInvalidEmail=%1%\u4e0d\u662f\u4e00\u4e2a\u6709\u6548\u7684\u7535\u90ae\u4fe1\u7bb1
+ Error_FieldNotANumber=%1% \u5fc5\u987b\u662f\u6570\u5b57
+ Error_FieldRegexNoMatch=%1% \u4e0d\u662f\u6b63\u786e\u7684\u683c\u5f0f
+ Error_FieldRequired=\u9700\u8981%1%
+ Error_FieldTooLong=%1% \u592a\u957f\u4e86
+ Error_FieldTooShort=%1%\u592a\u77ed\u4e86
+ Error_HTTP_404=\u60a8\u8bf7\u6c42\u7684\u9875\u9762\u65e0\u6cd5\u627e\u5230\u3002
+ Error_IncorrectRequestSequence=\u5df2\u68c0\u6d4b\u5230\u4f7f\u7528\u540e\u9000\u6309\u94ae\u6216\u5b58\u5728\u591a\u4e2a\u6d4f\u89c8\u5668\u4f1a\u8bdd\u3002\u8bf7\u5173\u95ed\u6240\u6709\u7684\u6d4f\u89c8\u5668\uff0c\u7136\u540e\u518d\u8bd5\u4e00\u6b21\u3002
+ Error_InvalidConfig=PWM\u914d\u7f6e\u65e0\u6548\u6216\u635f\u574f\u3002\u8bf7\u66f4\u6b63\u9519\u8bef\uff0c\u6216\u5220\u9664\u914d\u7f6e\u6587\u4ef6\u3002
+ Error_InvalidFormID=\u60a8\u7684\u6d4f\u89c8\u5668\u4f1a\u8bdd\u65e0\u6548\u6216\u5df2\u8fc7\u671f\u3002\u8bf7\u5173\u95ed\u6d4f\u89c8\u5668\uff0c\u7136\u540e\u518d\u8bd5\u4e00\u6b21\u3002
+ Error_InvalidSecurityKey=PWM\u5b89\u5168\u5bc6\u94a5\u4e22\u5931\u6216\u65e0\u6548\u3002
+ Error_LdapIntruder=\u60a8\u7684\u7528\u6237\u540d\u5df2\u7ecf\u8d85\u8fc7\u767b\u9646\u5c1d\u8bd5\u6b21\u6570\u4e0a\u9650\u3002\u8bf7\u7a0d\u540e\u518d\u8bd5\u3002
+ Error_LocalDB_Unavailable=PWMDB\u6570\u636e\u5e93\u4e0d\u53ef\u7528\u3002\u5982\u679c\u8fd9\u4e2a\u9519\u8bef\u53cd\u590d\u51fa\u73b0\uff0c\u8bf7\u8054\u7cfb\u60a8\u7684\u670d\u52a1\u53f0\u3002
+ Error_MissingParameter=\u672a\u8f93\u5165\u8981\u6c42\u7684\u53c2\u6570
+ Error_MissingRandomResponse=\u8bf7\u952e\u5165\u4e00\u4e2a\u989d\u5916\u7684\u968f\u673a\u5e94\u7b54\u3002
+ Error_MissingRequiredResponse=\u8bf7\u952e\u5165\u6240\u6709\u5fc5\u8981\u7684\u5e94\u7b54\u3002
+ Error_Missing_Challenge_Text=\u7f3a\u5c11\u7528\u6237\u8f93\u5165\u7684\u95ee\u9898\u7684\u5185\u5bb9\u3002
+ Error_Missing_GUID=\u6211\u4eec\u65e0\u6cd5\u4e3a\u7528\u6237\u627e\u5230\u4e00\u4e2aGUID\u3002\u8bf7\u4e0e\u7ba1\u7406\u5458\u8054\u7cfb\u3002
+ Error_Multi_Username=\u591a\u4e2a\u7528\u6237\u5339\u914d\u7ed9\u5b9a\u7684\u7528\u6237\u540d "%1%". \u8bf7\u7f29\u5c0f\u60a8\u7684\u641c\u7d22\u8303\u56f4.
+ Error_NewUser_Failure=\u521b\u5efa\u65b0\u7528\u6237\u5e10\u6237\u65f6\u53d1\u751f\u9519\u8bef\u3002\u8bf7\u4e0e\u7ba1\u7406\u5458\u8054\u7cfb\u3002
+ Error_NoChallenges=\u672a\u914d\u7f6e\u9274\u522b\u95ee\u9898
+ Error_NoLdapConnection=\u6240\u9700\u76ee\u5f55\u7684\u8fde\u63a5\u4e0d\u53ef\u7528.
+ Error_NoOtpConfiguration=\u4e3a\u8bbe\u5b9a\u4e00\u6b21\u6027\u5bc6\u7801.
+ Error_OAuthError=\u53d1\u751f\u4f7f\u7528 OAuth \u8ba4\u8bc1\u534f\u8bae\u9519\u8bef\uff0c\u8bf7\u7a0d\u540e\u518d\u8bd5\u3002
+ Error_Orig_Admin_Only=\u4ec5\u539f\u59cb\u7ba1\u7406\u5458\u53ef\u4ee5\u6267\u884c\u6b64\u5185\u5bb9
+ Error_PasswordRequired=\u9700\u8981\u5bc6\u7801\u624d\u80fd\u6267\u884c\u6b64\u64cd\u4f5c
+ Error_ReportingError=\u62a5\u8868\u751f\u6210\u8fc7\u7a0b\u4e2d\u53d1\u751f\u9519\u8bef
+ Error_Response_Duplicate=\u95ee\u9898\u201c%1%\u201d\u7684\u5e94\u7b54\u4e0d\u80fd\u4f5c\u4e3a\u540c\u6837\u4f5c\u4e3a\u53e6\u4e00\u4e2a\u95ee\u9898\u7684\u5e94\u7b54\u3002
+ Error_Response_NoResponse=\u7528\u6237\u540d\u65e0\u6548\u6216\u4e0d\u5177\u6709\u5bf9\u5e94\u7684\u5e94\u7b54\u3002
+ Error_Response_TooLong=\u201c\u95ee\u9898\u201d%1%\u7684\u5e94\u7b54\u592a\u957f
+ Error_Response_TooShort=\u201c\u95ee\u9898\u201d%1%\u7684\u5e94\u7b54\u592a\u77ed
+ Error_Response_Wordlist=\u95ee\u9898\u7684\u5e94\u7b54\u201c%1%\u201d\u592a\u5e38\u7528
+ Error_SecureRequestRequired=\u4e0d\u5141\u8bb8\u4f7f\u7528\u975e\u5b89\u5168\uff08HTTP\uff09\u8fde\u63a5\u5230\u8fd9\u4e2a\u7cfb\u7edf\u3002\u8bf7\u518d\u6b21\u5c1d\u8bd5\u4f7f\u7528\u5b89\u5168\uff08HTTPS\uff09\u8fde\u63a5\u3002
+ Error_SecurityViolation=\u53d1\u751f\u5b89\u5168\u8fdd\u89c4\uff0c\u8bf7\u7a0d\u540e\u518d\u8bd5\u3002
+ Error_ServiceNotAvailable=\u672a\u80fd\u63d0\u4f9b\u670d\u52a1
+ Error_ServiceUnreachable=\u65e0\u6cd5\u4f7f\u7528\u5fc5\u8981\u7684\u670d\u52a1\uff0c\u8bf7\u7a0d\u540e\u518d\u8bd5\u3002
+ Error_SessionIntruder=\u5df2\u7ecf\u8d85\u8fc7\u672c\u65f6\u6bb5\u7684\u6700\u591a\u5141\u8bb8\u5c1d\u8bd5\u767b\u9646\u6b21\u6570\u3002
+ Error_SyslogWriteError=\u5199\u5165 syslog \u670d\u52a1\u5668 '%1%'\u53d1\u751f\u9519\u8bef, \u9519\u8bef: %2%
+ Error_TokenDestIntruder=\u5df2\u8d85\u8fc7\u5c1d\u8bd5\u4e0a\u9650\uff0c\u8bf7\u7a0d\u540e\u518d\u8bd5.
+ Error_TokenExpired=\u60a8\u6240\u8f93\u5165\u7684\u4ee4\u724c\u8fc7\u671f\uff0c\u4e0d\u518d\u6709\u6548\u3002\u8bf7\u518d\u8bd5\u4e00\u6b21\u3002
+ Error_TokenIncorrect=\u4e0d\u6b63\u786e\u7684\u4ee3\u7801\uff0c\u8bf7\u518d\u8bd5\u4e00\u6b21\u3002
+ Error_TokenMissingContact=\u60a8\u7684\u5e10\u6237\u6682\u6ca1\u6709\u4efb\u4f55\u8054\u7edc\u4fe1\u606f\u3002\u8bf7\u4e0e\u7ba1\u7406\u5458\u8054\u7cfb\u3002
+ Error_TooManyThreads=\u8d85\u8fc7\u6700\u5927\u7ebf\u7a0b\u6570\u9650\u5236\uff0c\u8bf7\u7a0d\u540e\u518d\u8bd5\u3002
+ Error_TrialViolation=\u5df2\u8d85\u51fa\u4f7f\u7528\u9650\u5236\u3002
+ Error_Unauthorized=\u60a8\u6ca1\u6709\u6743\u9650\u6267\u884c\u8bf7\u6c42\u7684\u64cd\u4f5c\u3002
+ Error_Unknown=\u672a\u77e5\u7c7b\u578b\u9519\u8bef\u3002\u5982\u679c\u6b64\u7c7b\u9519\u8bef\u91cd\u590d\u53d1\u751f\uff0c\u8bf7\u60a8\u8054\u7cfb\u670d\u52a1\u53f0\u3002
+ Error_Unlock_Failure=\u89e3\u9501\u60a8\u7684\u5e10\u6237\u65f6\u53d1\u751f\u9519\u8bef\u3002\u8bf7\u4e0e\u7ba1\u7406\u5458\u8054\u7cfb\u3002
+ Error_UnreachableCloudService=PWM\u4e91\u670d\u52a1\u4e0d\u80fd\u8bbf\u95ee\u3002
+ Error_Update_Attrs_Failure=\u4fdd\u5b58\u60a8\u7684\u4e2a\u4eba\u8d44\u6599\u65f6\u53d1\u751f\u9519\u8bef\u3002\u8bf7\u4e0e\u7ba1\u7406\u5458\u8054\u7cfb\u3002
+ Error_UserAuthenticated=\u60a8\u5df2\u901a\u8fc7\u9a8c\u8bc1\u3002
+ Error_UserIntruder=\u5df2\u7ecf\u8d85\u8fc7\u4f60\u7528\u6237\u8eab\u4efd\u53f7\u7801\u7684\u6700\u591a\u5141\u8bb8\u5c1d\u8bd5\u767b\u9646\u6b21\u6570\u3002\u8bf7\u7a0d\u540e\u518d\u8bd5\u3002
+ Error_UserMisMatch=\u8eab\u5206\u9274\u522b\u9519\u8bef\uff0c\u8bf7\u5173\u95ed\u4f60\u7684\u6d4f\u89c8\u7a97\u53e3
+ Error_Writing_Otp_Secret=\u5b58\u50a8 OTP \u673a\u5bc6\u662f\u53d1\u751f\u9519\u8bef\u3002\u8bf7\u60a8\u8054\u7cfb\u7ba1\u7406\u5458\u3002
+ Error_Writing_Responses=\u4fdd\u5b58\u60a8\u7684\u5e94\u7b54\u95ee\u9898\u8fc7\u7a0b\u4e2d\u51fa\u73b0\u9519\u8bef\u3002\u8bf7\u4e0e\u7ba1\u7406\u5458\u8054\u7cfb
+ Error_WrongOtpToken=\u4e00\u6b21\u6027\u5bc6\u7801\u4e0d\u6b63\u786e\u3002
+ Error_WrongPassword=\u7528\u6237\u540d\u6216\u8005\u5bc6\u7801\u65e0\u6548
+ Error_WrongResponse=\u4e00\u4e2a\u6216\u591a\u4e2a\u5e94\u7b54\u662f\u4e0d\u6b63\u786e\u7684\u3002\u8bf7\u518d\u8bd5\u4e00\u6b21\u3002
+ Password_BadOldPassword=\u65e7\u5bc6\u7801\u9519\u8bef
+ Password_BadPassword=\u65b0\u5bc6\u7801\u4e0d\u7b26\u5408\u89c4\u5219
+ Password_CustomError=\u65b0\u5bc6\u7801\u4e0d\u7b26\u5408\u89c4\u5219
+ Password_DoesNotMatch=\u5bc6\u7801\u4e0d\u7b26
+ Password_Expired=\u5bc6\u7801\u5df2\u8fc7\u671f
+ Password_FirstIsNumeric=\u7b2c\u4e00\u4e2a\u5b57\u7b26\u4e0d\u80fd\u4e3a\u6570\u5b57
+ Password_FirstIsSpecial=\u7b2c\u4e00\u4e2a\u5b57\u7b26\u4e0d\u80fd\u4e3a\u7b26\u53f7\uff08\u975e\u5b57\u6bcd\u6570\u5b57\uff09
+ Password_HistoryFull=\u65b0\u5bc6\u7801\u8fdb\u7a0b\u5df2\u6ee1
+ Password_InWordlist=\u65b0\u5bc6\u7801\u592a\u5e38\u89c1
+ Password_InvalidChar=\u65b0\u5bc6\u7801\u5305\u542b\u65e0\u6548\u5b57\u7b26
+ Password_LastIsNumeric=\u6700\u540e\u4e00\u4e2a\u5b57\u7b26\u4e0d\u80fd\u4e3a\u6570\u5b57
+ Password_LastIsSpecial=\u6700\u540e\u4e00\u4e2a\u5b57\u7b26\u4e0d\u80fd\u662f\u7b26\u53f7\uff08\u975e\u5b57\u6bcd\u6570\u5b57\uff09
+ Password_MeetsRules=\u5df2\u63a5\u53d7\u65b0\u5bc6\u7801\uff0c\u8bf7\u70b9\u51fb"\u66f4\u6539\u5bc6\u7801"
+ Password_Missing=\u5bc6\u7801\u4e22\u5931
+ Password_MissingConfirm=\u5bc6\u7801\u7b26\u5408\u8981\u6c42\uff0c\u8bf7\u8f93\u5165\u786e\u8ba4\u5bc6\u7801
+ Password_NewPasswordRequired=\u60a8\u9700\u8981\u65b0\u5bc6\u7801\u624d\u80fd\u7ee7\u7eed.
+ Password_NotEnoughAlpha=\u65b0\u7684\u5bc6\u7801\u6240\u9700\u5b57\u7b26\u4e0d\u591f\u3002
+ Password_NotEnoughLower=\u65b0\u7684\u5bc6\u7801\u6ca1\u6709\u8db3\u591f\u7684\u5c0f\u5199\u5b57\u6bcd
+ Password_NotEnoughNonAlpha=\u65b0\u7684\u5bc6\u7801\u6ca1\u6709\u8db3\u591f\u7684\u975e\u5b57\u6bcd\u5b57\u7b26
+ Password_NotEnoughNum=\u65b0\u7684\u5bc6\u7801\u6ca1\u6709\u8db3\u591f\u7684\u6570\u5b57
+ Password_NotEnoughSpecial=\u65b0\u7684\u5bc6\u7801\u6ca1\u6709\u8db3\u591f\u7684\u7b26\u53f7\uff08\u975e\u5b57\u6bcd\u6570\u5b57\uff09
+ Password_NotEnoughUnique=\u65b0\u7684\u5bc6\u7801\u6ca1\u6709\u8db3\u591f\u7684\u552f\u4e00\u5b57\u7b26
+ Password_NotEnoughUpper=\u65b0\u7684\u5bc6\u7801\u6ca1\u6709\u8db3\u591f\u7684\u5927\u5199\u5b57\u6bcd
+ Password_PreviouslyUsed=\u65b0\u7684\u5bc6\u7801\u4e4b\u524d\u5df2\u4f7f\u7528\u8fc7
+ Password_RequiredMissing=\u65b0\u7684\u5bc6\u7801\u7f3a\u5c11\u5fc5\u8981\u7684\u5b57\u7b26
+ Password_SameAsAttr=\u65b0\u7684\u5bc6\u7801\u592a\u660e\u663e
+ Password_SameAsOld=\u65b0\u7684\u5bc6\u7801\u4e0e\u5f53\u9762\u5bc6\u7801\u76f8\u540c
+ Password_TooLong=\u65b0\u7684\u5bc6\u7801\u592a\u957f
+ Password_TooManyAlpha=\u65b0\u7684\u5bc6\u7801\u5305\u542b\u592a\u591a\u5b57\u6bcd
+ Password_TooManyLower=\u65b0\u7684\u5bc6\u7801\u5305\u542b\u592a\u591a\u5c0f\u5199\u5b57\u6bcd
+ Password_TooManyNonAlpha=\u65b0\u7684\u5bc6\u7801\u542b\u6709\u592a\u591a\u7684\u975e\u5b57\u6bcd\u5b57\u7b26
+ Password_TooManyNonAlphaSpecial=\u65b0\u7684\u5bc6\u7801\u542b\u6709\u592a\u591a\u7684\u7b26\u53f7\uff08\u975e\u5b57\u6bcd\u6570\u5b57\uff09\u5b57\u7b26
+ Password_TooManyNumeric=\u65b0\u7684\u5bc6\u7801\u5305\u542b\u592a\u591a\u6570\u5b57
+ Password_TooManyOldChars=\u65b0\u7684\u5bc6\u7801\u5305\u542b\u592a\u591a\u65e7\u5bc6\u7801\u7684\u5b57\u7b26
+ Password_TooManyRepeat=\u65b0\u7684\u5bc6\u7801\u5305\u542b\u592a\u591a\u91cd\u590d\u5b57\u7b26
+ Password_TooManySpecial=\u65b0\u7684\u5bc6\u7801\u6709\u592a\u591a\u7684\u7279\u6b8a\uff08\u975e\u5b57\u6bcd\u6216\u6570\u5b57\uff09\u5b57\u7b26
+ Password_TooManyUpper=\u65b0\u5bc6\u7801\u6709\u592a\u591a\u5927\u5199\u5b57\u6bcd
+ Password_TooShort=\u65b0\u5bc6\u7801\u592a\u77ed
+ Password_TooSoon=\u8ddd\u79bb\u4e0a\u6b21\u66f4\u6539\u5bc6\u7801\u6240\u7ecf\u8fc7\u7684\u65f6\u95f4\u8fc7\u77ed\u3002
+ Password_TooWeak=\u5bc6\u7801\u8fc7\u4e8e\u7b80\u5355\u3002\u5c1d\u8bd5\u6dfb\u52a0\u66f4\u591a\u7684\u6570\u5b57\uff0c\u7b26\u53f7\u6216\u6df7\u5408\u5927\u5c0f\u5199\u5b57\u6bcd\u3002
+ Password_UnknownValidation=\u65b0\u5bc6\u7801\u4e0d\u7b26\u5408\u8981\u6c42\u3002\u8bf7\u5c1d\u8bd5\u4f7f\u7528\u4e0d\u540c\u7684\u5bc6\u7801\u3002
+ Password_UsingDisallowedValue=\u65b0\u5bc6\u7801\u4e2d\u4f7f\u7528\u4e86\u4e0d\u5141\u8bb8\u7684\u5b57\u7b26\u3002

+ 107 - 96
pwm/servlet/src/password/pwm/i18n/Message_zh.properties

@@ -1,96 +1,107 @@
-#
-# Password Management Servlets (PWM)
-# http://code.google.com/p/pwm/
-#
-# Copyright (c) 2006-2009 Novell, Inc.
-# Copyright (c) 2009-2014 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
-#
-
-EventLog_ActivateUser=\u6fc0\u6d3b\u7528\u6237
-EventLog_ChangePassword=\u4fee\u6539\u5bc6\u7801
-EventLog_HelpdeskClearResponses=\u670d\u52a1\u53f0\u6e05\u9664\u5e94\u7b54
-EventLog_HelpdeskSetPassword=\u670d\u52a1\u53f0\u8bbe\u7f6e\u5bc6\u7801
-EventLog_HelpdeskUnlockPassword=\u670d\u52a1\u53f0\u89e3\u9501\u5bc6\u7801
-EventLog_IntruderLockout=\u5165\u4fb5\u8005\u9501\u5b9a
-EventLog_RecoverPassword=\u6062\u590d\u5fd8\u8bb0\u7684\u5bc6\u7801
-EventLog_SetupHints=\u8bbe\u7f6e\u5bc6\u7801\u63d0\u793a
-EventLog_SetupResponses=\u8bbe\u7f6e\u5bc6\u7801\u5e94\u7b54
-EventLog_UpdateAttributes=\u66f4\u65b0\u5c5e\u6027
-EventLog_UpdateProfile=\u66f4\u65b0\u5c5e\u6027
-Requirement_ADComplexity=\u5fc5\u987b\u6709\u81f3\u5c11\u4e09\u79cd\u7c7b\u578b\u7684\u4e0b\u5217\u5b57\u7b26\uff1a<ul> <li>\u5927\u5199\u5b57\u6bcd\uff08A-Z\uff09</li> <li>\u5c0f\u5199\u5b57\u6bcd\uff08a-z\uff09</ li> <li>\u6570\u5b57\uff080-9\uff09</ li><li>\u7b26\u53f7\uff08\uff01\uff0c\uff03\uff0c$\u7b49\uff09</li></ul>
-Requirement_AllowNumeric=\u4e0d\u5f97\u5305\u62ec\u4efb\u4f55\u6570\u5b57\u5b57\u7b26\u3002
-Requirement_AllowSpecial=\u4e0d\u5f97\u5305\u62ec\u4efb\u4f55 (\u975e\u5b57\u6bcd\u6216\u8005\u975e\u6570\u5b57)\u5b57\u7b26\u3002
-Requirement_CaseSensitive=\u5bc6\u7801\u533a\u5206\u5927\u5c0f\u5199\u3002
-Requirement_DisAllowedAttributes=\u4e0d\u80fd\u5305\u62ec\u60a8\u7684\u59d3\u540d\u6216\u7528\u6237\u540d\u7684\u4e00\u90e8\u5206\u3002
-Requirement_DisAllowedValues=\u4e0d\u5f97\u5305\u62ec\u4efb\u4f55\u4ee5\u4e0b\u7684\u503c\uff1a: %1%
-Requirement_FirstNumeric=\u7b2c\u4e00\u4e2a\u5b57\u7b26\u4e0d\u80fd\u4e3a\u6570\u5b57\u3002
-Requirement_FirstSpecial=\u7b2c\u4e00\u4e2a\u5b57\u7b26\u4e0d\u80fd\u4e3a(\u975e\u5b57\u6bcd\u6216\u8005\u975e\u6570\u5b57)\u5b57\u7b26\u3002
-Requirement_LastNumeric=\u6700\u540e\u4e00\u4e2a\u5b57\u7b26\u4e0d\u80fd\u4e3a\u6570\u5b57\u3002
-Requirement_LastSpecial=\u6700\u540e\u4e00\u4e2a\u5b57\u7b26\u4e0d\u80fd\u4e3a(\u975e\u5b57\u6bcd\u6216\u8005\u975e\u6570\u5b57)\u5b57\u7b26)\u3002
-Requirement_MaxAlpha=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u5b57\u6bcd\u3002
-Requirement_MaxAlphaPlural=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u5b57\u6bcd\u3002
-Requirement_MaxLength=\u5fc5\u987b\u4e0d\u8d85\u8fc7 %1% \u4e2a\u5b57\u8282\u957f\u5ea6\u3002
-Requirement_MaxLengthPlural=\u5fc5\u987b\u4e0d\u8d85\u8fc7 %1% \u4e2a\u5b57\u8282\u957f\u5ea6\u3002
-Requirement_MaxLower=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u5c0f\u5199\u5b57\u6bcd\u3002
-Requirement_MaxLowerPlural=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u5c0f\u5199\u5b57\u6bcd\u3002
-Requirement_MaxNumeric=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u6570\u5b57\u3002
-Requirement_MaxNumericPlural=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u6570\u5b57\u3002
-Requirement_MaxRepeat=\u4efb\u4f55\u5b57\u7b26\u4e0d\u5f97\u91cd\u590d\u8d85\u8fc7 %1% \u6b21\u3002
-Requirement_MaxRepeatPlural=\u4efb\u4f55\u5b57\u7b26\u4e0d\u5f97\u91cd\u590d\u8d85\u8fc7 %1% \u6b21\u3002
-Requirement_MaxSeqRepeat=\u4efb\u4f55\u76f8\u540c\u7684\u5b57\u7b26\u6392\u5217\u987a\u5e8f\u4e0d\u5f97\u91cd\u590d\u8d85\u8fc7 %1% \u6b21\u3002
-Requirement_MaxSeqRepeatPlural=\u4efb\u4f55\u76f8\u540c\u7684\u5b57\u7b26\u6392\u5217\u987a\u5e8f\u4e0d\u5f97\u91cd\u590d\u8d85\u8fc7 %1% \u6b21\u3002
-Requirement_MaxSpecial=\u4e0d\u80fd\u5305\u62ec\u591a\u4e8e%1% \u4e2a(\u975e\u5b57\u6bcd\u6216\u8005\u975e\u6570\u5b57)\u5b57\u7b26\u3002
-Requirement_MaxSpecialPlural=\u4e0d\u80fd\u5305\u62ec\u591a\u4e8e%1% \u4e2a(\u975e\u5b57\u6bcd\u6216\u8005\u975e\u6570\u5b57)\u5b57\u7b26\u3002
-Requirement_MaxUpper=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u5927\u5199\u5b57\u6bcd\u3002
-Requirement_MaxUpperPlural=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u5927\u5199\u5b57\u6bcd\u3002
-Requirement_MinAlpha=\u5fc5\u987b\u81f3\u5c11\u5305\u62ec %1% \u4e2a\u5b57\u6bcd\u3002
-Requirement_MinAlphaPlural=\u5fc5\u987b\u81f3\u5c11\u5305\u62ec %1% \u4e2a\u5b57\u6bcd\u3002
-Requirement_MinimumFrequency=\u662f\u53ef\u4ee5\u66f4\u6539\u7684\uff0c\u4f46\u662f\u81f3\u5c11\u8981\u95f4\u9694%1%\u3002
-Requirement_MinLength=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u5b57\u8282\u957f\u5ea6\u3002
-Requirement_MinLengthPlural=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u5b57\u8282\u957f\u5ea6\u3002
-Requirement_MinLower=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u5c0f\u5199\u5b57\u6bcd\u3002
-Requirement_MinLowerPlural=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u5c0f\u5199\u5b57\u6bcd\u3002
-Requirement_MinNumeric=\u5fc5\u987b\u81f3\u5c11\u5305\u62ec %1% \u4e2a\u6570\u5b57\u3002
-Requirement_MinNumericPlural=\u5fc5\u987b\u81f3\u5c11\u5305\u62ec %1% \u4e2a\u6570\u5b57\u3002
-Requirement_MinSpecial=\u5fc5\u987b\u6709\u81f3\u5c11 %1% \u4e2a (\u975e\u5b57\u6bcd\u6216\u8005\u975e\u6570\u5b57)\u5b57\u7b26\u3002
-Requirement_MinSpecialPlural=\u5fc5\u987b\u6709\u81f3\u5c11 %1% \u4e2a (\u975e\u5b57\u6bcd\u6216\u8005\u975e\u6570\u5b57)\u5b57\u7b26\u3002
-Requirement_MinUnique=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u72ec\u7279\u5b57\u7b26\u3002
-Requirement_MinUniquePlural=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u72ec\u7279\u5b57\u7b26\u3002
-Requirement_MinUpper=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u5927\u5199\u5b57\u6bcd\u3002
-Requirement_MinUpperPlural=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u5927\u5199\u5b57\u6bcd\u3002
-Requirement_NotCaseSensitive=\u5bc6\u7801\u4e0d\u533a\u5206\u5927\u5c0f\u5199\u3002
-Requirement_OldChar=\u4e0d\u5f97\u6709\u8d85\u8fc7 %1% \u4e2a\u65e7\u5bc6\u7801\u6240\u4f7f\u7528\u7684\u5b57\u7b26\u3002
-Requirement_OldCharPlural=\u4e0d\u5f97\u6709\u8d85\u8fc7 %1% \u4e2a\u65e7\u5bc6\u7801\u6240\u4f7f\u7528\u7684\u5b57\u7b26\u3002
-Requirement_RequiredChars=\u5fc5\u987b\u81f3\u5c11\u5305\u62ec\u5404\u4e00\u4e2a\u4ee5\u4e0b\u7684\u5b57\u7b26\uff1a
-Requirement_UniqueRequired=\u65b0\u7684\u5bc6\u7801\u53ef\u80fd\u5c1a\u672a\u4f7f\u7528\u8fc7\u3002
-Requirement_WordList=\u4e0d\u5f97\u5305\u62ec\u4e00\u4e2a\u5e38\u7528\u8bcd\u6216\u8005\u5e38\u7528\u7684\u5b57\u7b26\u987a\u5e8f\u6392\u5217\u3002
-Success_ActivateUser=\u4f60\u7684\u7528\u6237\u5e10\u6237\u6210\u529f\u88ab\u6fc0\u6d3b\u3002\u8bf7\u786e\u4fdd\u5b8c\u6210\u8fd9\u4e00\u7a0b\u5e8f\uff0c\u5426\u5219\u4f60\u5c06\u65e0\u6cd5\u8fdb\u5165\u4f60\u7684\u65b0\u5e10\u6237\u3002
-Success_ConfigFileUpload=\u914d\u7f6e\u6587\u4ef6\u5df2\u6210\u529f\u4e0a\u4f20\u3002
-Success_CreateGuest=\u65b0\u6765\u5bbe\u5e10\u6237\u5df2\u6210\u529f\u521b\u5efa\u3002\u5982\u679c\u5df2\u8f93\u5165\u7535\u5b50\u90ae\u4ef6\u5730\u5740\uff0c\u6765\u5bbe\u7528\u6237\u5c06\u6536\u5230\u901a\u77e5\u3002\u6765\u5bbe\u5e10\u6237\uff0c\u53ef\u80fd\u8fd8\u9700\u8981\u6fc0\u6d3b\u3002
-Success_CreateUser=\u4f60\u7684\u65b0\u7528\u6237\u5e10\u6237\u521b\u5efa\u6210\u529f\u3002\u8bf7\u786e\u4fdd\u7ee7\u7eed\u6267\u884c\u6709\u5173\u7a0b\u5e8f\uff0c\u5426\u5219\u4f60\u5c06\u65e0\u6cd5\u8fdb\u5165\u4f60\u7684\u65b0\u5e10\u6237\u3002
-Success_ForgottenUsername=\u60a8\u7684\u7528\u6237\u540d\u662f %1%\u3002\u8bf7\u8bb0\u5f55\u4f60\u7684\u7528\u6237\u540d\u4ee5\u4f9b\u5c06\u6765\u4f7f\u7528\u3002
-Success_NewUserForm=\u51c6\u5907\u8981\u521b\u5efa\u60a8\u7684\u5e10\u6237\u3002\u51c6\u5907\u597d\u65f6\u8bf7\u7ee7\u7eed\u3002
-Success_PasswordChange=\u60a8\u7684\u5bc6\u7801\u5df2\u7ecf\u66f4\u6539\u6210\u529f\u3002<br/> <b>\u6ce8\u610f\uff01</b> \u60a8\u7684\u5bc6\u7801\u5df2\u7ecf\u4e0d\u518d\u4e0e Windows \u5de5\u4f5c\u7ad9\u7684\u4e00\u81f4\u3002\u8981\u66f4\u6539\u60a8\u7684\u5de5\u4f5c\u7ad9\u5bc6\u7801\uff0c\u8bf7\u6309 CTRL-ALT-DEL \u5e76\u9009\u62e9\u66f4\u6539\u5bc6\u7801\u3002
-Success_PasswordReset=\u5df2\u6210\u529f\u4e3a%1%\u8bbe\u7f6e\u5bc6\u7801\u3002
-Success_ResponsesMeetRules=\u60a8\u7684\u5e94\u7b54\u6ee1\u8db3\u8981\u6c42\u3002\u8bf7\u70b9\u51fb\u4fdd\u5b58\u5e94\u7b54\u3002
-Success_SetupHint=\u4f60\u7684\u79d8\u5bc6\u95ee\u9898\u4e0e\u7b54\u6848\u8bbe\u7f6e\u6210\u529f\u3002
-Success_SetupResponse=\u5df2\u6210\u529f\u4fdd\u5b58\u60a8\u7684\u673a\u5bc6\u95ee\u9898\u548c\u7b54\u6848\u3002\u5982\u679c\u4f60\u5fd8\u8bb0\u4f60\u7684\u5bc6\u7801\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528\u8fd9\u4e9b\u95ee\u9898\u7684\u7b54\u6848\u91cd\u8bbe\u5bc6\u7801\u3002
-Success_Unknown=\u6210\u529f\u5b8c\u6210\u64cd\u4f5c\u3002
-Success_UnlockAccount=\u60a8\u7684\u5e10\u6237\u5df2\u88ab\u9501\u5b9a\u3002
-Success_UpdateAttributes=\u4f60\u7684\u7528\u6237\u8d44\u6599\u5df2\u7ecf\u6210\u529f\u88ab\u66f4\u65b0\u3002
-Success_UpdateGuest=\u6765\u5bbe\u5e10\u6237\u5df2\u6210\u529f\u66f4\u65b0\u3002\u5982\u679c\u5df2\u8f93\u5165\u7535\u5b50\u90ae\u4ef6\u5730\u5740\uff0c\u6765\u5bbe\u7528\u6237\u5c06\u6536\u5230\u901a\u77e5\u3002
-Success_UpdateProfile=\u60a8\u7684\u7528\u6237\u4fe1\u606f\u5df2\u6210\u529f\u66f4\u65b0\u3002
+#
+# Password Management Servlets (PWM)
+# http://code.google.com/p/pwm/
+#
+# Copyright (c) 2006-2009 Novell, Inc.
+# Copyright (c) 2009-2014 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
+#
+
+EventLog_ActivateUser=\u6fc0\u6d3b\u7528\u6237
+EventLog_Authenticate=\u8ba4\u8bc1
+EventLog_ChangePassword=\u4fee\u6539\u5bc6\u7801
+EventLog_CreateUser=\u521b\u5efa\u8d26\u6237
+EventLog_FatalEvent=\u4e25\u91cd\u4e8b\u4ef6
+EventLog_HelpdeskAction=\u670d\u52a1\u53f0\u52a8\u4f5c
+EventLog_HelpdeskClearOtpSecret=\u670d\u52a1\u53f0\u6d88\u9664 OTP \u673a\u5bc6
+EventLog_HelpdeskClearResponses=\u670d\u52a1\u53f0\u6e05\u9664\u5e94\u7b54
+EventLog_HelpdeskSetPassword=\u670d\u52a1\u53f0\u8bbe\u7f6e\u5bc6\u7801
+EventLog_HelpdeskUnlockPassword=\u670d\u52a1\u53f0\u89e3\u9501\u5bc6\u7801
+EventLog_IntruderLockout=\u5165\u4fb5\u8005\u9501\u5b9a
+EventLog_ModifyConfiguration=\u914d\u7f6e\u5df2\u4fee\u6539
+EventLog_RecoverPassword=\u6062\u590d\u5fd8\u8bb0\u7684\u5bc6\u7801
+EventLog_SetupResponses=\u8bbe\u7f6e\u5bc6\u7801\u5e94\u7b54
+EventLog_Shutdown=\u5173\u95ed\u5e94\u7528\u7a0b\u5e8f
+EventLog_Startup=\u542f\u52a8\u5e94\u7528\u7a0b\u5e8f
+EventLog_TokenClaimed=\u4ee4\u724c\u6388\u6743
+EventLog_TokenIssued=\u5df2\u7b7e\u53d1\u7684\u4ee4\u724c
+EventLog_UpdateProfile=\u66f4\u65b0\u5c5e\u6027
+Eventlog_SetupOtpSecret=\u8bbe\u7f6e OTP \u673a\u5bc6
+Requirement_ADComplexity=\u5fc5\u987b\u6709\u81f3\u5c11\u4e09\u79cd\u7c7b\u578b\u7684\u4e0b\u5217\u5b57\u7b26\uff1a<ul> <li>\u5927\u5199\u5b57\u6bcd\uff08A-Z\uff09</li> <li>\u5c0f\u5199\u5b57\u6bcd\uff08a-z\uff09</ li> <li>\u6570\u5b57\uff080-9\uff09</ li><li>\u7b26\u53f7\uff08\uff01\uff0c\uff03\uff0c$\u7b49\uff09</li></ul>
+Requirement_AllowNumeric=\u4e0d\u5f97\u5305\u62ec\u4efb\u4f55\u6570\u5b57\u5b57\u7b26\u3002
+Requirement_AllowSpecial=\u4e0d\u5f97\u5305\u62ec\u4efb\u4f55 (\u975e\u5b57\u6bcd\u6216\u8005\u975e\u6570\u5b57)\u5b57\u7b26\u3002
+Requirement_CaseSensitive=\u5bc6\u7801\u533a\u5206\u5927\u5c0f\u5199\u3002
+Requirement_DisAllowedAttributes=\u4e0d\u80fd\u5305\u62ec\u60a8\u7684\u59d3\u540d\u6216\u7528\u6237\u540d\u7684\u4e00\u90e8\u5206\u3002
+Requirement_DisAllowedValues=\u4e0d\u5f97\u5305\u62ec\u4efb\u4f55\u4ee5\u4e0b\u7684\u503c\uff1a: %1%
+Requirement_FirstNumeric=\u7b2c\u4e00\u4e2a\u5b57\u7b26\u4e0d\u80fd\u4e3a\u6570\u5b57\u3002
+Requirement_FirstSpecial=\u7b2c\u4e00\u4e2a\u5b57\u7b26\u4e0d\u80fd\u4e3a(\u975e\u5b57\u6bcd\u6216\u8005\u975e\u6570\u5b57)\u5b57\u7b26\u3002
+Requirement_LastNumeric=\u6700\u540e\u4e00\u4e2a\u5b57\u7b26\u4e0d\u80fd\u4e3a\u6570\u5b57\u3002
+Requirement_LastSpecial=\u6700\u540e\u4e00\u4e2a\u5b57\u7b26\u4e0d\u80fd\u4e3a(\u975e\u5b57\u6bcd\u6216\u8005\u975e\u6570\u5b57\u5b57\u7b26)\u3002
+Requirement_MaxAlpha=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u5b57\u6bcd\u3002
+Requirement_MaxAlphaPlural=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u5b57\u6bcd\u3002
+Requirement_MaxLength=\u5fc5\u987b\u4e0d\u8d85\u8fc7 %1% \u4e2a\u5b57\u8282\u957f\u5ea6\u3002
+Requirement_MaxLengthPlural=\u5fc5\u987b\u4e0d\u8d85\u8fc7 %1% \u4e2a\u5b57\u8282\u957f\u5ea6\u3002
+Requirement_MaxLower=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u5c0f\u5199\u5b57\u6bcd\u3002
+Requirement_MaxLowerPlural=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u5c0f\u5199\u5b57\u6bcd\u3002
+Requirement_MaxNumeric=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u6570\u5b57\u3002
+Requirement_MaxNumericPlural=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u6570\u5b57\u3002
+Requirement_MaxRepeat=\u4efb\u4f55\u5b57\u7b26\u4e0d\u5f97\u91cd\u590d\u8d85\u8fc7 %1% \u6b21\u3002
+Requirement_MaxRepeatPlural=\u4efb\u4f55\u5b57\u7b26\u4e0d\u5f97\u91cd\u590d\u8d85\u8fc7 %1% \u6b21\u3002
+Requirement_MaxSeqRepeat=\u4efb\u4f55\u76f8\u540c\u7684\u5b57\u7b26\u6392\u5217\u987a\u5e8f\u4e0d\u5f97\u91cd\u590d\u8d85\u8fc7 %1% \u6b21\u3002
+Requirement_MaxSeqRepeatPlural=\u4efb\u4f55\u76f8\u540c\u7684\u5b57\u7b26\u6392\u5217\u987a\u5e8f\u4e0d\u5f97\u91cd\u590d\u8d85\u8fc7 %1% \u6b21\u3002
+Requirement_MaxSpecial=\u4e0d\u80fd\u5305\u62ec\u591a\u4e8e%1% \u4e2a(\u975e\u5b57\u6bcd\u6216\u8005\u975e\u6570\u5b57)\u5b57\u7b26\u3002
+Requirement_MaxSpecialPlural=\u4e0d\u80fd\u5305\u62ec\u591a\u4e8e%1% \u4e2a(\u975e\u5b57\u6bcd\u6216\u8005\u975e\u6570\u5b57)\u5b57\u7b26\u3002
+Requirement_MaxUpper=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u5927\u5199\u5b57\u6bcd\u3002
+Requirement_MaxUpperPlural=\u4e0d\u80fd\u5305\u62ec\u8d85\u8fc7 %1% \u4e2a\u5927\u5199\u5b57\u6bcd\u3002
+Requirement_MinAlpha=\u5fc5\u987b\u81f3\u5c11\u5305\u62ec %1% \u4e2a\u5b57\u6bcd\u3002
+Requirement_MinAlphaPlural=\u5fc5\u987b\u81f3\u5c11\u5305\u62ec %1% \u4e2a\u5b57\u6bcd\u3002
+Requirement_MinLength=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u5b57\u8282\u957f\u5ea6\u3002
+Requirement_MinLengthPlural=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u5b57\u8282\u957f\u5ea6\u3002
+Requirement_MinLower=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u5c0f\u5199\u5b57\u6bcd\u3002
+Requirement_MinLowerPlural=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u5c0f\u5199\u5b57\u6bcd\u3002
+Requirement_MinNumeric=\u5fc5\u987b\u81f3\u5c11\u5305\u62ec %1% \u4e2a\u6570\u5b57\u3002
+Requirement_MinNumericPlural=\u5fc5\u987b\u81f3\u5c11\u5305\u62ec %1% \u4e2a\u6570\u5b57\u3002
+Requirement_MinSpecial=\u5fc5\u987b\u6709\u81f3\u5c11 %1% \u4e2a (\u975e\u5b57\u6bcd\u6216\u8005\u975e\u6570\u5b57)\u5b57\u7b26\u3002
+Requirement_MinSpecialPlural=\u5fc5\u987b\u6709\u81f3\u5c11 %1% \u4e2a (\u975e\u5b57\u6bcd\u6216\u8005\u975e\u6570\u5b57)\u5b57\u7b26\u3002
+Requirement_MinUnique=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u72ec\u7279\u5b57\u7b26\u3002
+Requirement_MinUniquePlural=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u72ec\u7279\u5b57\u7b26\u3002
+Requirement_MinUpper=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u5927\u5199\u5b57\u6bcd\u3002
+Requirement_MinUpperPlural=\u5fc5\u987b\u81f3\u5c11\u6709 %1% \u4e2a\u5927\u5199\u5b57\u6bcd\u3002
+Requirement_MinimumFrequency=\u662f\u53ef\u4ee5\u66f4\u6539\u7684\uff0c\u4f46\u662f\u81f3\u5c11\u8981\u95f4\u9694%1%\u3002
+Requirement_NotCaseSensitive=\u5bc6\u7801\u4e0d\u533a\u5206\u5927\u5c0f\u5199\u3002
+Requirement_OldChar=\u4e0d\u5f97\u6709\u8d85\u8fc7 %1% \u4e2a\u65e7\u5bc6\u7801\u6240\u4f7f\u7528\u7684\u5b57\u7b26\u3002
+Requirement_OldCharPlural=\u4e0d\u5f97\u6709\u8d85\u8fc7 %1% \u4e2a\u65e7\u5bc6\u7801\u6240\u4f7f\u7528\u7684\u5b57\u7b26\u3002
+Requirement_RequiredChars=\u5fc5\u987b\u81f3\u5c11\u5305\u62ec\u5404\u4e00\u4e2a\u4ee5\u4e0b\u7684\u5b57\u7b26\uff1a
+Requirement_UniqueRequired=\u65b0\u7684\u5bc6\u7801\u53ef\u80fd\u5c1a\u672a\u4f7f\u7528\u8fc7\u3002
+Requirement_WordList=\u4e0d\u5f97\u5305\u62ec\u4e00\u4e2a\u5e38\u7528\u8bcd\u6216\u8005\u5e38\u7528\u7684\u5b57\u7b26\u987a\u5e8f\u6392\u5217\u3002
+Success_Action=\u5df2\u7ecf\u6210\u529f\u5b8c\u6210 %1%.
+Success_ActivateUser=\u4f60\u7684\u7528\u6237\u5e10\u6237\u6210\u529f\u88ab\u6fc0\u6d3b\u3002\u8bf7\u786e\u4fdd\u5b8c\u6210\u8fd9\u4e00\u7a0b\u5e8f\uff0c\u5426\u5219\u4f60\u5c06\u65e0\u6cd5\u8fdb\u5165\u4f60\u7684\u65b0\u5e10\u6237\u3002
+Success_ClearResponse=\u60a8\u7684\u673a\u5bc6\u95ee\u9898\u548c\u7b54\u6848\u5df2\u6210\u529f\u88ab\u79fb\u9664.
+Success_ConfigFileUpload=\u914d\u7f6e\u6587\u4ef6\u5df2\u6210\u529f\u4e0a\u4f20\u3002
+Success_CreateGuest=\u65b0\u8bbf\u5ba2\u5e10\u6237\u5df2\u6210\u529f\u521b\u5efa\u3002\u5982\u679c\u5df2\u8f93\u5165\u7535\u5b50\u90ae\u4ef6\u5730\u5740\uff0c\u8bbf\u5ba2\u7528\u6237\u5c06\u6536\u5230\u901a\u77e5\u3002\u8bbf\u5ba2\u5e10\u6237\uff0c\u53ef\u80fd\u8fd8\u9700\u8981\u6fc0\u6d3b\u3002
+Success_CreateUser=\u4f60\u7684\u65b0\u7528\u6237\u5e10\u6237\u521b\u5efa\u6210\u529f\u3002\u8bf7\u786e\u4fdd\u7ee7\u7eed\u6267\u884c\u6709\u5173\u7a0b\u5e8f\uff0c\u5426\u5219\u4f60\u5c06\u65e0\u6cd5\u8fdb\u5165\u4f60\u7684\u65b0\u5e10\u6237\u3002
+Success_ForgottenUsername=\u60a8\u7684\u7528\u6237\u540d\u662f %1%\u3002\u8bf7\u8bb0\u5f55\u4f60\u7684\u7528\u6237\u540d\u4ee5\u4f9b\u5c06\u6765\u4f7f\u7528\u3002
+Success_NewUserForm=\u51c6\u5907\u8981\u521b\u5efa\u60a8\u7684\u5e10\u6237\u3002\u51c6\u5907\u597d\u65f6\u8bf7\u7ee7\u7eed\u3002
+Success_PasswordChange=\u60a8\u7684\u5bc6\u7801\u5df2\u7ecf\u66f4\u6539\u6210\u529f\u3002<br/> <b>\u6ce8\u610f\uff01</b> \u60a8\u7684\u5bc6\u7801\u5df2\u7ecf\u4e0d\u518d\u4e0e Windows \u5de5\u4f5c\u7ad9\u7684\u4e00\u81f4\u3002\u8981\u66f4\u6539\u60a8\u7684\u5de5\u4f5c\u7ad9\u5bc6\u7801\uff0c\u8bf7\u6309 CTRL-ALT-DEL \u5e76\u9009\u62e9\u66f4\u6539\u5bc6\u7801\u3002
+Success_PasswordReset=\u5df2\u6210\u529f\u4e3a%1%\u8bbe\u7f6e\u5bc6\u7801\u3002
+Success_PasswordSend=\u5df2\u5c06\u60a8\u7684\u65b0\u5bc6\u7801\u4f20\u9001%1%\u3002\u8bf7\u5173\u95ed\u6b64\u7a97\u53e3\uff0c\u7136\u540e\u4f7f\u7528\u60a8\u7684\u65b0\u5bc6\u7801\u767b\u9646\u3002
+Success_ResponsesMeetRules=\u60a8\u7684\u5e94\u7b54\u6ee1\u8db3\u8981\u6c42\u3002\u8bf7\u70b9\u51fb\u4fdd\u5b58\u5e94\u7b54\u3002
+Success_SetupResponse=\u5df2\u6210\u529f\u4fdd\u5b58\u60a8\u7684\u673a\u5bc6\u95ee\u9898\u548c\u7b54\u6848\u3002\u5982\u679c\u4f60\u5fd8\u8bb0\u4f60\u7684\u5bc6\u7801\uff0c\u60a8\u53ef\u4ee5\u4f7f\u7528\u8fd9\u4e9b\u95ee\u9898\u7684\u7b54\u6848\u91cd\u8bbe\u5bc6\u7801\u3002
+Success_Unknown=\u6210\u529f\u5b8c\u6210\u64cd\u4f5c\u3002
+Success_UnlockAccount=\u60a8\u7684\u5e10\u6237\u5df2\u88ab\u9501\u5b9a\u3002
+Success_UpdateForm=\u53ef\u4ee5\u5f00\u59cb\u66f4\u65b0\u60a8\u7684\u8bbe\u5b9a\u3002\u51c6\u5907\u597d\u662f\u8bf7\u7ee7\u7eed\u3002
+Success_UpdateGuest=\u6765\u5bbe\u5e10\u6237\u5df2\u6210\u529f\u66f4\u65b0\u3002\u5982\u679c\u5df2\u8f93\u5165\u7535\u5b50\u90ae\u4ef6\u5730\u5740\uff0c\u6765\u5bbe\u7528\u6237\u5c06\u6536\u5230\u901a\u77e5\u3002
+Success_UpdateProfile=\u60a8\u7684\u7528\u6237\u4fe1\u606f\u5df2\u6210\u529f\u66f4\u65b0\u3002

+ 3 - 3
pwm/servlet/src/password/pwm/util/PwmPasswordRuleValidator.java

@@ -31,6 +31,7 @@ import password.pwm.AppProperty;
 import password.pwm.PwmApplication;
 import password.pwm.PwmConstants;
 import password.pwm.PwmService;
+import password.pwm.bean.PublicUserInfoBean;
 import password.pwm.bean.UserInfoBean;
 import password.pwm.config.Configuration;
 import password.pwm.config.PwmSetting;
@@ -42,7 +43,6 @@ import password.pwm.util.logging.PwmLogger;
 import password.pwm.util.operations.PasswordUtility;
 import password.pwm.util.stats.Statistic;
 import password.pwm.ws.client.rest.RestClientHelper;
-import password.pwm.ws.server.rest.RestStatusServer;
 
 import java.util.*;
 import java.util.regex.Pattern;
@@ -536,8 +536,8 @@ public class PwmPasswordRuleValidator {
             sendData.put("policy",policyData);
         }
         if (uiBean != null) {
-            final RestStatusServer.JsonStatusData jsonStatusData = RestStatusServer.JsonStatusData.fromUserInfoBean(uiBean, pwmApplication.getConfig(), locale);
-            sendData.put("userInfo", jsonStatusData);
+            final PublicUserInfoBean publicUserInfoBean = PublicUserInfoBean.fromUserInfoBean(uiBean, pwmApplication.getConfig(), locale);
+            sendData.put("userInfo", publicUserInfoBean);
         }
 
         final String jsonRequestBody = JsonUtil.serializeMap(sendData);

+ 3 - 3
pwm/servlet/src/password/pwm/util/macro/ExternalRestMacro.java

@@ -25,12 +25,12 @@ package password.pwm.util.macro;
 import com.google.gson.reflect.TypeToken;
 import password.pwm.PwmApplication;
 import password.pwm.PwmConstants;
+import password.pwm.bean.PublicUserInfoBean;
 import password.pwm.bean.UserInfoBean;
 import password.pwm.error.PwmException;
 import password.pwm.util.JsonUtil;
 import password.pwm.util.logging.PwmLogger;
 import password.pwm.ws.client.rest.RestClientHelper;
-import password.pwm.ws.server.rest.RestStatusServer;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -69,8 +69,8 @@ class ExternalRestMacro extends AbstractMacro {
         final String inputString = matchValue.substring(11,matchValue.length() -1);
         final Map<String,Object> sendData = new HashMap<>();
         if (userInfoBean != null) {
-            final RestStatusServer.JsonStatusData jsonStatusData = RestStatusServer.JsonStatusData.fromUserInfoBean(userInfoBean,pwmApplication.getConfig(), PwmConstants.DEFAULT_LOCALE);
-            sendData.put("userInfo",jsonStatusData);
+            final PublicUserInfoBean publicUserInfoBean = PublicUserInfoBean.fromUserInfoBean(userInfoBean, pwmApplication.getConfig(), PwmConstants.DEFAULT_LOCALE);
+            sendData.put("userInfo", publicUserInfoBean);
         }
         sendData.put("input",inputString);
 

+ 2 - 1
pwm/servlet/src/password/pwm/util/operations/OtpService.java

@@ -173,7 +173,8 @@ public class OtpService implements PwmService {
             final OTPUserRecord.RecoveryInfo recoveryInfo = new OTPUserRecord.RecoveryInfo();
             if (settings.getOtpStorageFormat().supportsHashedRecoveryCodes()) {
                 LOGGER.trace(sessionLabel, "hashing the recovery codes");
-                recoveryInfo.setSalt(PwmRandom.getInstance().alphaNumericString(32));
+                final int saltCharLength = Integer.parseInt(pwmApplication.getConfig().readAppProperty(AppProperty.OTP_SALT_CHARLENGTH));
+                recoveryInfo.setSalt(PwmRandom.getInstance().alphaNumericString(saltCharLength));
                 recoveryInfo.setHashCount(settings.getRecoveryHashIterations());
                 recoveryInfo.setHashMethod(settings.getRecoveryHashMethod());
             } else {

+ 3 - 3
pwm/servlet/src/password/pwm/ws/client/rest/RestTokenDataClient.java

@@ -25,6 +25,7 @@ package password.pwm.ws.client.rest;
 import com.novell.ldapchai.exception.ChaiUnavailableException;
 import password.pwm.PwmApplication;
 import password.pwm.PwmConstants;
+import password.pwm.bean.PublicUserInfoBean;
 import password.pwm.bean.SessionLabel;
 import password.pwm.bean.UserIdentity;
 import password.pwm.bean.UserInfoBean;
@@ -36,7 +37,6 @@ import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.ldap.UserStatusReader;
 import password.pwm.util.JsonUtil;
 import password.pwm.util.logging.PwmLogger;
-import password.pwm.ws.server.rest.RestStatusServer;
 
 import java.io.Serializable;
 import java.util.LinkedHashMap;
@@ -108,8 +108,8 @@ public class RestTokenDataClient implements RestClient {
                     userIdentity
             );
 
-            final RestStatusServer.JsonStatusData jsonStatusData = RestStatusServer.JsonStatusData.fromUserInfoBean(userInfoBean,pwmApplication.getConfig(), PwmConstants.DEFAULT_LOCALE);
-            sendData.put(RestClient.DATA_KEY_USERINFO, jsonStatusData);
+            final PublicUserInfoBean publicUserInfoBean = PublicUserInfoBean.fromUserInfoBean(userInfoBean, pwmApplication.getConfig(), PwmConstants.DEFAULT_LOCALE);
+            sendData.put(RestClient.DATA_KEY_USERINFO, publicUserInfoBean);
         }
 
 

+ 3 - 62
pwm/servlet/src/password/pwm/ws/server/rest/RestStatusServer.java

@@ -23,15 +23,12 @@
 package password.pwm.ws.server.rest;
 
 import password.pwm.PwmService;
-import password.pwm.bean.PasswordStatus;
+import password.pwm.bean.PublicUserInfoBean;
 import password.pwm.bean.UserInfoBean;
-import password.pwm.config.Configuration;
-import password.pwm.config.profile.PwmPasswordRule;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmException;
 import password.pwm.error.PwmUnrecoverableException;
-import password.pwm.http.tag.PasswordRequirementsTag;
 import password.pwm.ldap.UserStatusReader;
 import password.pwm.util.JsonUtil;
 import password.pwm.util.TimeDuration;
@@ -49,69 +46,13 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-import java.io.Serializable;
 import java.net.URISyntaxException;
-import java.util.*;
+import java.util.Date;
 
 @Path("/status")
 public class RestStatusServer extends AbstractRestServer {
     public static final PwmLogger LOGGER = PwmLogger.forClass(RestStatusServer.class);
 
-    public static class JsonStatusData implements Serializable {
-        public String userDN;
-        public String ldapProfile;
-        public String userID;
-        public String userEmailAddress;
-        public Date passwordExpirationTime;
-        public Date passwordLastModifiedTime;
-        public boolean requiresNewPassword;
-        public boolean requiresResponseConfig;
-        public boolean requiresUpdateProfile;
-        public boolean requiresInteraction;
-
-        public PasswordStatus passwordStatus;
-        public Map<String,String> passwordPolicy;
-        public List<String> passwordRules;
-        public Map<String,String> attributes;
-
-        public static JsonStatusData fromUserInfoBean(final UserInfoBean userInfoBean, final Configuration config, final Locale locale) {
-            final JsonStatusData jsonStatusData = new JsonStatusData();
-            jsonStatusData.userDN = (userInfoBean.getUserIdentity() == null) ? "" : userInfoBean.getUserIdentity().getUserDN();
-            jsonStatusData.ldapProfile = (userInfoBean.getUserIdentity() == null) ? "" : userInfoBean.getUserIdentity().getLdapProfileID();
-            jsonStatusData.userID = userInfoBean.getUsername();
-            jsonStatusData.userEmailAddress = userInfoBean.getUserEmailAddress();
-            jsonStatusData.passwordExpirationTime = userInfoBean.getPasswordExpirationTime();
-            jsonStatusData.passwordLastModifiedTime = userInfoBean.getPasswordLastModifiedTime();
-            jsonStatusData.passwordStatus = userInfoBean.getPasswordState();
-
-            jsonStatusData.requiresNewPassword = userInfoBean.isRequiresNewPassword();
-            jsonStatusData.requiresResponseConfig = userInfoBean.isRequiresResponseConfig();
-            jsonStatusData.requiresUpdateProfile = userInfoBean.isRequiresResponseConfig();
-            jsonStatusData.requiresInteraction = userInfoBean.isRequiresNewPassword()
-                    || userInfoBean.isRequiresResponseConfig()
-                    || userInfoBean.isRequiresUpdateProfile()
-                    || userInfoBean.getPasswordState().isWarnPeriod();
-
-
-            jsonStatusData.passwordPolicy = new HashMap<>();
-            for (final PwmPasswordRule rule : PwmPasswordRule.values()) {
-                jsonStatusData.passwordPolicy.put(rule.name(),userInfoBean.getPasswordPolicy().getValue(rule));
-            }
-
-            jsonStatusData.passwordRules = PasswordRequirementsTag.getPasswordRequirementsStrings(
-                    userInfoBean.getPasswordPolicy(),
-                    config,
-                    locale
-            );
-
-            if (userInfoBean.getCachedAttributeValues() != null && !userInfoBean.getCachedAttributeValues().isEmpty()) {
-                jsonStatusData.attributes = Collections.unmodifiableMap(userInfoBean.getCachedAttributeValues());
-            }
-
-            return jsonStatusData;
-        }
-    }
-
     @GET
     @Produces(MediaType.TEXT_HTML)
     public javax.ws.rs.core.Response doHtmlRedirect() throws URISyntaxException {
@@ -150,7 +91,7 @@ public class RestStatusServer extends AbstractRestServer {
                 userInfoBean = restRequestBean.getPwmSession().getUserInfoBean();
             }
             final RestResultBean restResultBean = new RestResultBean();
-            restResultBean.setData(JsonStatusData.fromUserInfoBean(
+            restResultBean.setData(PublicUserInfoBean.fromUserInfoBean(
                     userInfoBean,
                     restRequestBean.getPwmApplication().getConfig(),
                     restRequestBean.getPwmSession().getSessionStateBean().getLocale()

+ 1 - 1
pwm/servlet/web/WEB-INF/jsp/forgottenpassword-remote.jsp

@@ -61,7 +61,7 @@
                 <% } %>
                 <%@ include file="/WEB-INF/jsp/fragment/button-reset.jsp" %>
                 <%@ include file="/WEB-INF/jsp/fragment/forgottenpassword-cancel.jsp" %>
-                <input type="hidden" id="processAction" name="processAction" value="enterNaafResponse"/>
+                <input type="hidden" id="processAction" name="processAction" value="<%=ForgottenPasswordServlet.ForgottenPasswordAction.enterRemoteResponse%>"/>
                 <input type="hidden" id="pwmFormID" name="pwmFormID" value="<pwm:FormID/>"/>
             </div>
         </form>

+ 2 - 1
pwm/servlet/web/public/resources/js/configeditor-settings.js

@@ -2668,7 +2668,8 @@ VerificationMethodHandler.draw = function(settingKey) {
     for (var method in settingOptions) {
         var id = settingKey + '-' + method;
         var label = settingOptions[method];
-        htmlBody += '<tr><td>' + label + '</td><td><input id="input-range-' + id + '" type="range" min="0" max="2" value="0"/></td>';
+        var title = PWM_CONFIG.showString('VerificationMethodDetail_' + method);
+        htmlBody += '<tr><td title="' + title + '"><span style="cursor:pointer")">' + label + '</span></td><td><input id="input-range-' + id + '" type="range" min="0" max="2" value="0"/></td>';
         htmlBody += '<td><span id="label-' + id +'"></span></td></tr>';
     }
     htmlBody += '</table>';

+ 2 - 2
pwm/servlet/web/public/resources/js/peoplesearch.js

@@ -102,7 +102,7 @@ PWM_PS.convertDetailResultToHtml = function(data) {
     }
     htmlBody += '</div>'; //3
     if (data['hasOrgChart']) {
-        htmlBody += '<div class="icon-peoplesearch-orgChart" id="icon-peoplesearch-orgChart"></div>';
+        htmlBody += '<div class="icon-peoplesearch-orgChart" id="icon-peoplesearch-orgChart" title="' + PWM_MAIN.showString('Title_OrgChart') + '"></div>';
     }
     htmlBody += '</div>';
 
@@ -138,7 +138,7 @@ PWM_PS.convertDetailResultToHtml = function(data) {
             }
             if (attributeData['searchable'] == true) {
                 var likeSearchID = 'link-' + attributeData['name'] + '-' + '-likeUserSearch';
-                htmlBody += '<span id="' + likeSearchID + '" class="icon-likeUserSearch btn-icon fa fa-search"></span>';
+                htmlBody += '<span id="' + likeSearchID + '" class="icon-likeUserSearch btn-icon fa fa-search" title="' + PWM_MAIN.showString('Button_Search') + '"></span>';
             }
             htmlBody += '</div></td>'
         })(iter);

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott